Common API

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • Common API

      Geschätzte Transport Fever Spieler und Entwickler.

      Hiermit präsentiere ich euch mein Mod API Schnittstelle nun auch offiziell in einem eigenen Thema.

      Die Mod bietet die Grundlage übergreifende Nutzung von Spielelemente wie Gleise, Brücken, Strassen in anderen Mods zu nutzen.

      Es ist zwar über sogenannte „modifer“ möglich das Laden von Gleisen, Strassen und Brücken zu beobachten, dies hat aber den Nachteil das jedes Mod seine eigenen Funktionen dafür mitbringen musste. Des weiteren musste öfters eine Reihenfolge eingehalten werden oder eine Konfigurationsdatei geändert werden. Gerade bei mehrere Spielstände gibt es dann vielleicht Probleme. UG hat leider versäumt dafür geeignete Schnittstellen anzubieten.

      Was macht also Common API?

      Für Spieler:

      Sobald Ihr die Common API lädt, können Mod Autoren euch eine Auswahlliste mit allen Mod Gleisen, Brücken, Straßen anbieten.
      Des weiteren gibt es eine Liste mit allen Mods und deren Namen in der stdout.txt. Sinnvoll bei Steam Workshop Mods, die sonst nur als eine Nummer angezeigt werden.

      Beispiel: Ihr fügt einen Spielstand ein neues Schmalspurgleis hinzu. Habt Ihr einen Bahnhof der CommonAPI nutzt, könnt Ihr diesen neuen Gleistyp einfach nutzen.

      Hierfür müssen Gleise, Brücken und Straßen nicht angepasst werden, auch keine Änderungen an Konfigurationsdateien sind nötig.

      Technisch gesehen:
      Während des Laden eines Spielstandes werden intern die genutzten Moddateien ermittelt, diese werden vorgeladen und die Mod Autoren können dann Ihre Konstruktionen (Depots, Bahnhöfe) anpassen.

      Für Entwickler von Mods:

      Common API bietet Schnittstellen um herauszufinden welche anderen Gleistypen, Straßen, Brücken oder Tunnel noch geladen wurden. Dazu gibt es noch Funktionen um zum Beispiel die Daten per Name abzufragen, bzw. einer Liste. Warum also nicht selber einen Modifer benutzen?

      Jedes Mod hat dann eine andere Auswahlliste. Sollte eure Konstruktion vor einem anderen Mod geladen sein, hab Ihr keine Möglichkeit dessen Anzeigenamen herauszufinden, oder die Anzahl der Typen. Mit der Common API bleiben auch die ID Zuordnungen generell stabil. Darüber hinaus kümmert es sich bei der UI Erstellung auch darum, das die Modgleis Namen richtig übersetzt werden.

      Brücken, Straßen, Gleise:
      Bitte vergibt für eure Gleise, Strassen, Brücken eindeutige Namen, es ist sehr unschön wenn zig Gleise den gleichen Namen beinhalten – Standard Gleis - , außerdem ist X mal Stahlbrücke auch kein Vergnügen.

      Möchtet Ihr lieber einen sehr langen Namen nutzen ist dies auch kein Problem,
      Ihr könnt zusätzlich für die CommonAPI einen „shortUIName“ definieren,
      dieser wird dann in der Common API UI genutzt.

      Konstruktionen:
      Die API Beschreibung findet Ihr in doc Ordner der CommonAPI

      Ob die API verfügbar ist, könnt Ihr einfach herausfinden,
      CommonAPI darf nicht per require geladen werden, sobald der Nutzer es lädt ist commonapi global definiert.

      if (commonapi ~= nil) then

      end


      Auch weiteren Module kann man einfach abfragen:
      if (commonapi ~= nil and commonapi.uiparameter ~= nil) then

      end

      Wenn ein Modul nicht geladen werden kann, gibt es nil zurück.

      Ihr könnt die Präsenz der CommonAPI zwar in der runfn der mods.lua testen, aber Funktionen bezüglich der Daten zu den Mods oder UI Funktionen stehen euch dort noch nicht zur Verfügung! Diese sind erst während des Ladens einer Konstruktion nutzbar.

      Steam
      Eine Steam Veröffentlichung ist natürlich auch geplant sobald die API stabilisiert ist.


      VorabVersion
      In der Webdisk: Common API

      Wenn Ihr weitere Fragen zur Entwicklung, Nutzung habt, so könnt Ihr diese hier gerne hier zum besten geben ;)

      Links:
      Webdisk: Common API
      Zur Geschichte der Common API: Mod API Diskussion (weiterführung aus dem Beta News Beitrag)

      Neuste Informationen:

      MacOS
      Ich suche Nutzer mit MacOS, bitte meldet euch! MacOS ist nicht getestet.

      Fahrplan nächste Version:

      Zeitabhängige Anzeige von Typen (yearFrom, yearTo): Fertig.
      Einfache Erstellung von UI Parametern. Einfach die vorhandenen Parameter durch replaceParams für die Common API fit machen: In Entwicklung
    • @eis_os, ich möchte Danke sagen für deine tolle und vor allem creative Arbeit als auch für die Bereitstellung der Common API. :thumbup:

      Mich überzeugt diese API, was mich dazu veranlasst hat, dem Schweriner Hauptbahnhof die Unterstützung eben dieser API zu ermöglichen und mit Version 1.12 auch umgesetzt wurde.

      Nochmals Danke und bitte weiter so.

      LG Enno :)
      Auch ein alter Fuchs schaut gern ein Huhn, selbst wenn er's nicht mehr Reißen kann. ^^

      System: Windows 10 Home (64 bit) | AMD Ryzen R7 3700X | 32 GB DDR4 (CMK32GX4M2B3200C16) | Samsung 960 PRO MZ-V6P512BW (M.2 SSD| Palit Geforce GTX 1070 Dual 8 GB GDDR5
    • Hallo, es gibt eine neue Version 20170924:

      Was gibt es also neues:

      • Die erstellten UI Parameter berücksichtigen nun auch die Zeit.
        Dies bedeutet das Gleise, Brücken und co. ohne Namen dargestellt werden, solange Sie eigentlich nicht Aktiv im Spieljahr sind. Auch dieses ist eine Bewusste Entscheidung damit IDs nicht durcheinander geraten.
      • standard.lua und high_speed.lua werden nun intern vertauscht, damit sollte das Upgrade Tool wieder funktionieren. (Bedenkt, wenn es ein Mod Gleis ist, wird dann einfach standard.lua oder high_speed.lua als Gleis genutzt.
      • Weniger "Müll" in der stdout.txt bezüglich preloading.
      • Es können nun einfacher UI Parameter erstellt werden. (uiparameter.modifyTrackCatenary)


      Beispiel zu den einfachen UI Funktion(en):

      Source Code

      1. function data()
      2. local config = {
      3. trackTypes = { "standard.lua", "high_speed.lua" }
      4. }
      5. -- Default (no commonapi, no changes to parameters)
      6. local paramfn = function(params)
      7. return params
      8. end
      9. -- Do we have commonapi loaded?
      10. if (commonapi ~= nil and commonapi.uiparameter ~= nil) then
      11. -- replace paramfn with a function calling commonapi
      12. paramfn = function(params)
      13. -- you can pass all object parameters for TrackCatenarySelector
      14. -- additional a selectionlist to be modifed
      15. commonapi.uiparameter.modifyTrackCatenary(params, {
      16. selectionlist = config.trackTypes
      17. })
      18. return params
      19. end
      20. end
      21. return {
      22. type = "RAIL_DEPOT",
      23. description = {
      24. name = _("Train depot"),
      25. description = _("Used to buy/sell trains.")
      26. },
      27. availability = {
      28. },
      29. params = paramfn({
      30. paramsutil.makeTrackTypeParam(),
      31. paramsutil.makeTrackCatenaryParam(),
      32. }),
      Display All
      Eine Erklärung:

      Die lokale paramfn ändert ggf. die Parameter via commonapi.uiparameter.modifyTrackCatenary.

      Um den Code so wenig wie möglich zu ändern, wird dann einfach die config.trackTypes verändert. (dazu wird die Referenz per selectionlist übergeben)
    • So ganz kann ich dir nicht folgen:
      • Ist jetzt eine zeitliche Selektion nach Spieljahr implementiert (nur Gleise, welche auch. z.B. 2014, verfügbar sind)?
      • Werden im Code-Beispiel nun nur noch Standard- und Hochgeschwindigkeitsgleise zur Auswahl angeboten?
      Auch ein alter Fuchs schaut gern ein Huhn, selbst wenn er's nicht mehr Reißen kann. ^^

      System: Windows 10 Home (64 bit) | AMD Ryzen R7 3700X | 32 GB DDR4 (CMK32GX4M2B3200C16) | Samsung 960 PRO MZ-V6P512BW (M.2 SSD| Palit Geforce GTX 1070 Dual 8 GB GDDR5
    • Hier mal bei den Brückentypen die Zeitabhängigkeit:



      Leider kann man in TPF einen Eintrag der Liste nicht verstecken. (Und die Listen IDs müssen ja stabil sein, also kann man auch nicht einfach Einträge weglassen)

      Zum Beispiel, die config.trackTypes werden durch selectionlist überschrieben:


      commonapi.uiparameter.modifyTrackCatenary(params, {
      selectionlist = config.trackTypes
      })

      Der Aufruf dieser Funktion verursacht grob:
      1. Interne Erstellung eines TrackCatenarySelector mit den optionalen Parametern (grün)
      2. Die Modifikation der config.trackTypes (orange)
      3. Änderung der params (rot)
      4. Rückgabe des Objekts (hier nicht genutzt)


      PS: Kann sein das die Zeitabhängigkeit noch Porbleme macht, deswegen ist es ja noch eine Alpha.

      Nochmalig der Wunsch: Liebe Mac Spieler, wollt Ihr eure Plattform nicht unterstützen, meldet euch doch mal...
    • Die Auswahl mit den Gleisen funktioniert.
      Was mir dabei nicht zusagt ist, dass die "ungültigen" Gleise dennoch angezeigt werden. Dies ist bei Gleisen jedoch nicht nötig, da wir hier eindeutig auf die Namen der lua verweisen.
      Bei den Brücken mag das anders ein, jedoch muss dieses Manko bei den Gleisen nicht berücksichtigt werden.
      Auch ein alter Fuchs schaut gern ein Huhn, selbst wenn er's nicht mehr Reißen kann. ^^

      System: Windows 10 Home (64 bit) | AMD Ryzen R7 3700X | 32 GB DDR4 (CMK32GX4M2B3200C16) | Samsung 960 PRO MZ-V6P512BW (M.2 SSD| Palit Geforce GTX 1070 Dual 8 GB GDDR5
    • UG hat leider keine Möglichkeit die UI Liste so anzuzeigen das Einträge fehlen.

      Und die Zuordnung von GleisID (Position in der values Liste) zu Konstruktion muss fest sein. Wenn man in einer neuen Epoche eine Konstruktion ändert, hat man sonst auf einmal ein anderes Gleis an der ID oder wenn die Liste kleiner wird ist die ID vielleicht auch ungültig.

      Mir gefällt das zurzeit auch nicht, und ich bin für Ideen dankbar.
      Bis dato hab ich aber noch keine. Am besten wäre wenn man 0 als Eintrag angeben könnte, das wäre dann nicht nil und würde bedeuten das man den Button nicht anzeigt.
    • Du hast natürlich recht, die ID sollte erhalten bleiben.

      Noch einige Gedanken dazu:
      • Alle Einträge, deren Endjahr vor 1850 liegt können ausgeblendet werden. Diese sind nie zur Auswahl bestimmt gewesen.
      • Einträge, deren Erscheinungsjahr in der Zukunft liegt können ebenso ausgebendet werden, wenn dies möglich ist.
      • Einmal zur Auswahl mögliche Einträge sollten nicht ausgeblendet oder auf "hidden" gestellt werden. Der Spieler möchte eventuell das uralte Gleis weiterhin am Lokschuppen haben, auch wenn es offiziell nicht mehr verfügbar ist. Da wäre es sinnvoll, so man die Bezeichnung noch sehen könnte.


      Edit:
      Durch die Umsetzung obiger Überlegungen könnte sich natürlich die Liste ändern und somit die ID. Da die Liste aber nicht kleiner sonder wenn dann immer größer würde, wäre dies nach meiner Ansicht das kleinere Übel.
      Der Spieler muss dann halt das erwünschte Gleis noch einmal auswählen. Ich persönlioch würde dies bevorzugen.
      Auch ein alter Fuchs schaut gern ein Huhn, selbst wenn er's nicht mehr Reißen kann. ^^

      System: Windows 10 Home (64 bit) | AMD Ryzen R7 3700X | 32 GB DDR4 (CMK32GX4M2B3200C16) | Samsung 960 PRO MZ-V6P512BW (M.2 SSD| Palit Geforce GTX 1070 Dual 8 GB GDDR5

      The post was edited 1 time, last by EAT1963 ().

    • filter.visibleInUI macht das schon, der Zeitpunkt liegt zurzeit bei kleiner oder gleich 1800. Ich notiere mal 1850 auf meine Todo Liste.

      Ich versuche es über die Zeit weiter zu optimieren, danke für deine Gedanken.

      Ja die Blöcke am Ende der Liste wollte ich weg optimieren sofern ich keine andere Lösung habe.
      Meine interne vorherige Version hat nach yearFrom sortiert, dies führt aber beim hinzufügen oder updaten eines Mods zu einer ID Änderung, dies wollte ich vermeiden.
      Vielleicht ist das aber immer noch das kleinere Übel.

      Ich habe vor eine settings.lua Schnittstelle hinzuzufügen.
      Dann könnte ich die Auswahlvarianten dem Nutzer überlassen. Also, immer alle Typen, der jetzigen Zustand (optimiert) oder nach yearFrom sortiert.
    • eis_os wrote:

      filter.visibleInUI macht das schon, der Zeitpunkt liegt zurzeit bei kleiner oder gleich 1800
      Schon gesehen.
      Da würde ich gerne eine Möglichkeit haben, eigene Filter zu setzen. Z.B. mit einer Art Modifier filter.addVisibleInUIModifier( fnModifier )

      eis_os wrote:

      Vielleicht ist das aber immer noch das kleinere Übel.
      Ich denke schon.
      Auch ein alter Fuchs schaut gern ein Huhn, selbst wenn er's nicht mehr Reißen kann. ^^

      System: Windows 10 Home (64 bit) | AMD Ryzen R7 3700X | 32 GB DDR4 (CMK32GX4M2B3200C16) | Samsung 960 PRO MZ-V6P512BW (M.2 SSD| Palit Geforce GTX 1070 Dual 8 GB GDDR5
    • Du kannst die Filter List komplett während der Erstellung eines UI Objekts setzten, d.h. per filter im Objekt oder später das Objekt manipulieren.

      also local obj = create*({ filters = { komplett neue liste } } )

      (das geht dann auch bei der modify Funktion)

      oder

      local obj = uiparameter.create*()
      obj.filters[#obj.filters+1] = neueFilterFn

      obj:createUIParams(params)

      ...

      Das benutzt das System intern um die Brücken zu filtern.
      Ich kann natürlich auch noch eine schöne addFilter Funktion einbauen, wenn Du magst. ;)
    • Tja, da ist wohl das Verständnis zur Funktionalität der Knackpunkt.

      eis_os wrote:

      local obj = create*({ filters = { komplett neue liste } } )
      Hier zum Beispiel verstehe ich überhaupt nicht, was filters denn nun beinhalten soll. Ich kann ja schlecht schreiben: nimm nur Einträge ab 1955. :D

      eis_os wrote:

      local obj = uiparameter.create*()
      obj.filters[#obj.filters+1] = neueFilterFn

      obj:createUIParams(params)
      Das ist dann schon klarer. In einer eigenen FilterFn bin ich der Herr und weiß, was ich tue....zumindest meistens. :D

      Somit ist eine Art addModifier natürlich hinfällig.
      Auch ein alter Fuchs schaut gern ein Huhn, selbst wenn er's nicht mehr Reißen kann. ^^

      System: Windows 10 Home (64 bit) | AMD Ryzen R7 3700X | 32 GB DDR4 (CMK32GX4M2B3200C16) | Samsung 960 PRO MZ-V6P512BW (M.2 SSD| Palit Geforce GTX 1070 Dual 8 GB GDDR5
    • Die Default Filter sind in commonapi.filter definiert. LDoc macht mich Wahnsinnig um das richtig zu dokumentieren. Das sollte funktionieren:

      local myfilter = function(filename, data)
      local yearFrom = data.yearFrom or 0
      if (yearFrom~= 0 and yearFrom < 1955) then
      return false
      end
      return true
      end

      local obj = createTrackCatenary({
      filters = { commonapi.filter.visibleInUI, myfilter }

      })
    • Wenn ich dich korekt verstanden habe, dann sollte folgende Anpassung in meinen Skripten zum Erfolg führen:

      PHP Source Code

      1. local uiTrackSelector = nil
      2. local function filterTracks ( fileName, data )
      3. local yearFrom = data.yearFrom or 0
      4. if (yearFrom~= 0 and yearFrom < 1955) then
      5. return false
      6. end
      7. return true
      8. end
      9. if (commonapi ~= nil and commonapi.uiparameter ~= nil) then
      10. uiTrackSelector = commonapi.uiparameter.createTrackCatenary(
      11. {
      12. filters = { commonapi.filter.visibleInUI, filterTracks }
      13. }
      14. )
      15. end
      Display All
      Ist das korrekt?
      Auch ein alter Fuchs schaut gern ein Huhn, selbst wenn er's nicht mehr Reißen kann. ^^

      System: Windows 10 Home (64 bit) | AMD Ryzen R7 3700X | 32 GB DDR4 (CMK32GX4M2B3200C16) | Samsung 960 PRO MZ-V6P512BW (M.2 SSD| Palit Geforce GTX 1070 Dual 8 GB GDDR5
    • Ja, oder es gibt eine Bug... (den Code Pfad hab ich so nicht getestet)

      Du kannst auch nach createTrackCatenary schreiben, dann hast Du eine Klammer weniger...
      uiTrackSelector.filters = { commonapi.filter.visibleInUI, filterTracks }

      Die nächste Version wird wohl noch eine addFilter Funktion bekommen, das ist dann übersichtlicher., gerade für die Brücken...
    • Ok. Jetzt kapiere ich was du meinst. Der Groschen fällt aber heute laaaangsam.

      Folgenden Code werde ich bei mir testen. Und ja, so ist es etwas übersichtlicher.

      PHP Source Code

      1. if (options.enable_commonApi and commonapi ~= nil and commonapi.uiparameter ~= nil) then
      2. uiTrackSelector = commonapi.uiparameter.createTrackCatenary()
      3. uiTrackSelector.filters = { commonapi.filter.visibleInUI, filterTracks }
      4. end
      Auch ein alter Fuchs schaut gern ein Huhn, selbst wenn er's nicht mehr Reißen kann. ^^

      System: Windows 10 Home (64 bit) | AMD Ryzen R7 3700X | 32 GB DDR4 (CMK32GX4M2B3200C16) | Samsung 960 PRO MZ-V6P512BW (M.2 SSD| Palit Geforce GTX 1070 Dual 8 GB GDDR5
    • eis_os wrote:

      Mir gefällt das zurzeit auch nicht, und ich bin für Ideen dankbar.
      So als spontane Idee: Könntest du hidden buttons nicht simmulieren, indem du nur so viele buttons hinzufügst und eine Funktion zur Verfügung stellst die das mapping index->id übernehmen kann, abhängig vom aktuellen Spieljahr?
      Ist aber auch nur so eine Idee. Mag sein, dass man da ganz schnell wieder in einer der unzähligen Fallen landet.


      eis_os wrote:

      LDoc macht mich Wahnsinnig um das richtig zu dokumentieren.
      Du meinst die Stellen die du z.B. mit @tparam[opt] object o dokumentierst vermute ich mal?
      Ldoc ist da bockig genug, als dass du da kaum drum herum kommst dieses object als eigenen Typen zu definieren. z.B. in ner eigenen Datei als @classmod
      Dieser Beitrag wurde bereits ∞ mal editiert, zuletzt von Freahk (Vor π Minuten)
    • Ja, wenn man nur beeinflussen könnte oder abspeichern könnte welche ID dann in verschiedenen Jahren gemeint ist.

      Beispiel trackType 1950:
      track1, track2, track3,

      Später 2000:
      track1, track3, track5

      Wenn eine Konstruktion im Jahr 1950 gebaut wurde, mit track3 ist trackType der UI im Savegame = 2, kommt von die C++ Seite.
      Aber im Jahr 2000 ist beim Umbau oder Upgrade der Konstruktion der trackType aus params nun auf track5.

      Leider kann ich da auch nichts ändern, wenn die UI es zulassen würde einen eigenen Integer Wert zu speichern (ein Hash Wert des Gleisnamens) wäre es möglich, diesen wieder zu finden. Dazu wäre aber auch die Beeinflussung der UI nötig.

      Wie gesagt, ich werde wohl 3 Möglichkeiten anbieten: Immer alles anzeigen (erste Version), Verbergen der "falschen" Einträge (jetzige Version), sortiert nach Zeit.
      Bei der dritten Möglichkeit muss man den beim Upgrade leider nachschauen ob die gewählte Einstellung noch stimmt. TTD konnte auch in UI Texten die Farbe ändern, dann könnte ich die falschen Einträge grau darstellen,
      aber all das ist mit TPF nicht möglich und von UG erwarte ich da auch in Zukunft keine Hilfe.

      ldoc:
      Einen eigene Type habe ich ja schon für Einträge definiert, und ldoc gepatcht damit die HTML Referenzen halbwegs stimmen, ich möchte die Doku aber auch nicht mit irgendwelchen Typen verstopfen.
      Das ich alle UI Objekte einzeln Dokumentieren musste ist mir auch ein Dorn im Auge.

      Todoliste:
      settings.lua Routine, werde ich wohl auch als API stellen.
      Sortierung nach Jahren in der UI
      Ein Mod Common API Depot als Ersatz des normalen Depots
      Ein Mod das die normalen Bahnhöfe von UG ändert.
    • Oh,
      die letzten Punkte (Standarddepot und Standardbahnhöfe ändern) hatte ich mir zum Wochenende vorgenommen. Ebenso wollte ich schauen, wie ich eine Auswahl von Mod-Bahnhöfen ändere, ohne diese zu überschreiben.
      Auch ein alter Fuchs schaut gern ein Huhn, selbst wenn er's nicht mehr Reißen kann. ^^

      System: Windows 10 Home (64 bit) | AMD Ryzen R7 3700X | 32 GB DDR4 (CMK32GX4M2B3200C16) | Samsung 960 PRO MZ-V6P512BW (M.2 SSD| Palit Geforce GTX 1070 Dual 8 GB GDDR5
    • Gut das ich meine Todoliste poste :)

      Das Depot habe ich als Beispiel einfach per überschreiben der Con Datei gelöst und in ein Mod gepackt. Das ist theoretisch fertig und sollte keinem weh tun.

      Für Default Bahnhof Mods sollte so aussehen:

      Die paramsutil patchen in der runFn,
      d.h. makeTrainStationParamsCurved (wenn vorhanden) und makeTrainStationParams ruft dann einfach noch ein modifyTrackCatenary auf.

      Die normal erstellten params werden dann einfach überschrieben und die config.trackTypes angepasst.
      Vielleicht noch gewürzt mit einer Sicherheitsabfrage ob die Funktionen auch UG Standard sind bzw. die config.trackTypes nur 2 Einträge hat.

      Mod Bahnhöfe von anderen wollte ich nicht ändern sofern Sie Ihre eigenen Baufunktionen haben, da ich ja hoffe das Sie über kurz oder lang auch die CommonAPI direkt unterstützen.
      Vielleicht wäre es sinnvoll die von Tom erstellten Bahnhofsscripte anzupassen, da diese ja öfters genutzt wurden.

      In Richtung Bahnhöfe habe ich aber noch gar nicht angefangen, erst mal muss ich schauen wie ich den settings.lua umsetze, damit ich das UI Problem kaschieren kann ;)



      -edit-

      Da das Patchen der paramsutil so einfach ist, hab ich mal ein Mod dafür hochgeladen. Und weil ich gerade dabei war, auch noch das Depot.
      Die Erstellung der Screenshots und die Einträge in der Webdisk haben länger gedauert. :D