Hallo zusammen!
Einleitung:
Vorab, ich glaube das Thema gehört hier nicht hin, aber an anderen Stellen, wo es mir sinnvoller erscheinen würde, kann ich kein Thema erstellen... Also bei Bedarf, einfach verschieben
.
Wie ja bekannt ist, haben wir (also das SKO-(Team) -- in Klammern, weil ich gehöre ja nicht zum Team) keinen Sourcecode von dem eigentlichen Multiplayer-Kern und daher so gut wie keine Möglichkeit manche neue Funktionen zu implementieren, die tieferen Eingriff in die Engine erfordern würden oder Fehler, wie beispielsweise die Lags, die mit der Laufzeit von Gothic2 skalieren und jedem bekannt sein dürften, zu beheben.
Daher habe ich angefangen einen neuen Kern für den Gothic Multiplayer zu schreiben mit dem Ziel, eines Tages Accrescere ablösen zu können und von da an mehr Möglichkeiten der Fehlerbehebung oder der Erstellung weiterer Funktionen zu haben.
Nur damit es keine Missverständnisse gibt: Ich tue dies in erster Linie für SKO, weil ich den Server gut finde -- Nicht um einen eigenen auf zu machen und hier auf Userfang zu gehen oder ähnliches. Nicht das der Eindruck entsteht.
Genaueres zur Entwicklung:
Es gibt ein hervorragendes Projekt namens
Gothic Untold Chapter, dessen
Sourcecode frei verfügbar ist und mir sehr viel Arbeit bei der Erstellung eines neuen Multiplayerkerns abnimmt. Mainclain, falls du das ließt, ernsthaft: Danke für deinen riesigen Beitrag durch die Offenlegung deines Codes und deine Reverse-Engineering Anstrengungen!
Dieses Projekt dient mir als Basis für den Durchgriff eines externen Programms auf Funktionen innerhalb von Gothic. Zunächst gibt es aber ein paar Design Entscheidungen für die neue Software:
Programmiersprache bzw. Environment:
- Mit dem Gedanken im Hinterkopf, dass der Gothic-Server auf einem Linux-Server und damit unter Wine lauffähig sein sollte, scheidet für mich Visual Studio mit .NET Kern aus. Die Version, die derzeit aktuell wäre (2015 oder neuer) verwendet eine Runtime, die noch nicht vollständig in Wine implementiert ist und daher Probleme verursachen könnte bei der Inbetriebnahme. Weiter ist Gothic Untold Chapter in C# implementiert, was zwar erstmal nicht schlimm ist, aber ein paar Nachteile mit sich bringt bei der Verbindung von Gothic2 mit dem neuen Programmteil. Vom größeren Aufwand abgesehen, einen separaten .NET Kern überhaupt zu starten in einer laufenden Gothic Instanz, muss zusätzlich für jeden Aufruf einer noch so popeligen Funktion innerhalb von Gothic für Gothic ausführbarer Code in den Speicher gelegt werden. Dieser kann dann ausgeführt werden über den Start eines neuen Threads in Gothic. Dies ist zwar möglich, aber doch ein sehr großer Aufwand damit vergleichen, dass auch nativ ausführbarer Code von vorn herein eingeladen werden kann.
Davon abgesehen kann C# unter Linux noch zusätzlich eine unnötige Hürde sein.
Daher habe ich mich für C++ entschieden, da ich mir davon die größtmögliche Performance verspreche (und weniger Aufwand bei Calls, Speicher Lese-Schreiboperationen usw.).
Compiler:
Tatsächlich wäre es vermutlich am einfachsten einen Compiler von Microsoft zu verwenden, da Gothic ziemlich sicher auch mit einem kompiliert wurde. Ich jedoch habe mich für MinGW (mit g++) entschieden unter anderem deshalb, weil ich unter Linux arbeite und MinGW einen anständigen Cross-Compiler anbietet.
Eine Sache wird dadurch komplizierter: Der sogenannte THISCALL. Die Call-Convention des This-calls ist so ziemlich die einzige, die sich etwas unterscheidet zwischen GCC und Msvc. Der This-Pointer liegt bei MinGW auf dem Stack, während Msvc (und damit Gothic) ihn im Register ECX erwartet. Durch die Verwendung eines STDCALLs mit vorherigem Inline-Assembler schafft man es aber, die Adresse ins Register zu schieben und anschließend mittels eines STDCALLs nur noch die benötigten Argumente auf den Stack zu verfrachten vor dem Call.
Architektur:
Nach ziemlich ausgiebiger Sichtung des Codes von Untold Chapter habe ich mich dazu entschieden, die Struktur des Codes weitestgehend beizubehalten. Bei der Übersetzung von C# nach C++ entstehen natürlich Unterschiede, aber die Struktur der Objektorientierung leuchtet ein und ist es daher auch wert so übernommen zu werden, finde ich.
Falls Mainclain ließt: Das einzige was ich noch nicht nachlesen konnte bzw. mir keinen Reim drauf machen konnte sind die Präfixe der Dateinamen... Gemerkt habe ich, dass Dateien mit Präfix oC meisst Spielrelevanten Code enthalten und zC Dateien eher strukturelle Sachen bzw. Supportfunktionen enthalten. Oder von oC Dateien werden Objekte erstellt und zC sind quasi nur die Eltern.. Mhh mal sehen. Behindert mich nicht, aber ich glaube da steckt ein tieferer Sinn dahinter, den ich eigentlich gerne wüsste .
Edit: Mittlerweile hab ich gesehen, dass die Namen aus Gothic selbst kommen. Es lohnt sich auf World of Gothic zum Thema Modden etwas zu stöbern.
Multiplayer-Funktionen:
Dieses "Kapitel" kann erst folgen, wenn der "Kern" soweit übersetzt ist, da es nicht sinnvoll ist Netzwerkfunktionen zu implementieren für Sachen, die man noch nicht steuern kann. Da die Bibliothek RakNet nun unter der BSD-Lizenz verfügbar ist werde ich wahrscheinlich wie GUC und Accrescere auch schon diese Bibliothek für den Netzwerkverkehr benutzen.
Skripting Interface:
Wie ich mitbekommen habe, ist Accrescere so populär und auch für den SKO-Server verwendet worden aufgrund der Anpassbarkeit durch LUA-Skripte. Die glaube ich letzte Api dazu, die noch online zu finden ist, ist glaube ich
diese hier leider mit russischer Beschreibung. Durch die englischen Parameternamen versteht man es aber trotzdem. Diese API wird also zu späterem Zeitpunkt auch implementiert werden, wodurch ein Umstieg von Accrescere auf den neuen Kern einfach möglich sein sollte.
Roadmap:
Funktionales:
- Lade von externen Code in die Zielanwendung (erledigt)
- Normale Calls innerhalb von Gothic II (erledigt)
- This-Calls mit Objektzeigern von Gothic II (implementiert - getestet: RainController erstellt und es schneien lassen - Läuft! x'D)
- Detours / Hooks (erledigt - getestet - Rückgabedaten mittels Stackmanipulation aus Callbackfunktion heraus stehen noch aus, bzw müssen von den jeweiligen Hook-Callbacks implementiert werden.)
- Implementierung Server/Client System mit Kommunikation (nicht gestartet - RakNet geplant)
- Implementierung Lua-Skriptschnittstelle (nicht gestartet - Bibliotheken gesichtet für Export von C Funktionen für Lua und Import von Lua Funktionen für C -- Sollte machbar sein).
Derzeitig in Arbeit:
- Implementierung von allen steuer- und lesbaren Elementen von Gothic (in Arbeit -- Schätzungsweise 30% übersetzt)
Aber mancher wird sich jetzt fragen, wieso schreibt der Typ den Roman hier ?
Eigentlich möchte ich in erster Linie informieren, dass es etwas gibt, das in Arbeit ist und möglicherweise mal zur Verbesserung des Projekts beitragen kann. Zum anderen könnte es ja sein, dass es jemanden gibt, der C++ Erfahrung und x86 Architektur Verständnis hat oder Interesse hat, sich sowas anzuschauen und mitzuhelfen. Das ist möglich -- Ich versioniere mittels eines
Gitlab-Servers . Falls jemand Interesse hat mitzuwirken schreibt doch bitte eine PM an mich, dann kann ich euch einen Gitlab-Konto erstellen, um mitarbeiten zu können.
Soviel dazu. Wollte ich mal gesagt haben.
Ups, der Post ist wohl etwas länger geworden
Ok, ich gebs zu, hab ich vorher gewusst
Grüße
Christian