Themabewertung:
  • 1 Bewertung(en) - 5 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Reverse Engineering der NLT II
So, ich konnte jetzt die fehlenden Werte (siehe Tabelle meines vorherigen Beitrags) des Unbekannten Blockes in der .3DM durch Beobachtung im Spiel entschlüsseln:
  • Ersteinmal gibt es genau 2 verschiedene Beleuchtungsarten: "L"(Lichter) und "F"(Fackeln). Die Art wird durch die 3. Position im Namen mitgeteilt, wobei wenige Lichter hiervon abweichen und mit dem Präfix "Light" beginnen.

  • In U1 steht die maximale Leuchtkraft, wobei die vorkommende 63 volle Helligkeit, die 44 eine mittlere Helligkeit, und 17 eine sehr sehr geringe Leuchtkraft darstellen. Siehe die .TAB Dateien im Beitrag #257, dort erstreckt sich der komplett schwarze Bereich relativ weit rein.

  • Lichter beleuchten, ohne zu flackern. Dabei wird die Beleuchtung mit steigendem Abstand schwächer.
    Für Abstände =< U2 ist die Beleuchtung immer U1, dh. für dieses Licht maximal.
    Für Abstände >= U3 ist die Beleuchtung 0.
    In den Abständen [U2, U3] wird die Leuchtkraft linear auf den Bereich [U1, 0] gemappt.
    Beleuchtungen addieren sich (zB. Kaminfeuer + Stabzauber) bis maximal 63.

  • Fackeln funktionieren genau wie Licht (linearer Abfall), haben darüber hinaus aber noch die Eigenschaft, dass diese flackern.
    Ich vermute, dass in zufälligen Zeiträumen überall ein kleiner konstanter Wert abgezogen wird.

  • Die Lichtquellen des Spielers (Stabzauber, Flim Flam, Fackeln, etc.) funktionieren wie Fackeln, dh. flackern. Hier stehen die maximale Leuchtstärke (U1) sowie innerer und äußerer Radius (U2, U3) vermutlich in der .EXE. Die Werte zu approximieren ginge auch, aber wahrscheinlich nur mit aufwendigen Tests und Pixelzählerei

  • Für den Wert den ich Light? getauft habe gilt: Aus Light? == 1 folgt immer U2==U3==0, dh. das Licht ist aus.

Damit sollte der bisher Unbekannte Datenblock vollständig geklärt sein, bis auf die Daten des deaktivierten Lichtes in STAR02
Zitieren
Ersteinmal das, was mir auf der Zunge brennt:
Ich weiß wo in der Riva.exe die Probenwürfe stattfinden  :jippie: Zumindest einige. Aber ich ahne, wie man alle finden könnte.
Was ich nicht weiß ist, ob uns das einem Logger näher bringt, oder ob mein Ergebnis vielleicht für den ein oder anderen Minutenarbeit gewesen wäre, und schon bekannt?
Das einzige was ich gerade machen kann, ist die Würfel zu zinken, aber leider nicht anzuschauen, bzw. auszugeben .. (also welcher Wurf á la aWb + c eigentlich gedacht war)

Ich, als kompletter DOS und Assembler-Noob, würde als nächstes hergehen, und versuchen, entsprechende Stellen so umzuschreiben, dass sie
a) noch funktionieren, und ich
b) auch irgendeine Ausgabe bekomme. Vielleicht kann man leicht an irgendeine Adresse schreiben, die man mittels DosBox auslesen kann.
Oder irgendwie neue Funktionen ans Ende der .exe schreiben, die man hoffentlich auch irgendwie erreichen kann, und die mir entsprechende Daten auf die Platte schreiben.

Wahrscheinlich liegt hier mit das Hauptproblem. Wollte aber trotzdem mal in die Runde fragen, ob jemand eine Idee hat, wie man hier am besten weiter machen könnte? :think:

EDIT: Jetzt frisch ausgeschlafen, denke ich, dass ich das hinbekomme. Kompiliere gerade die DosBox, und wenn ich das richtig sehe, kann ich dort einfach den Instruction Pointer (IP) prüfen,
ob er gerade an den spannenden Stellen im Code ist, und dann die interessanten Register/Stack - Werte ausgeben. Damit sollte ich zumindest erstmal alle Würfe bekommen (dh. welcher Würfel mit welchem Ergebnis).
Als nächsten Schritt finde ich dann bestimmt in der Nähe die Stellen, an denen das Ergebnis je nach Probe mit den Charakterwerten verglichen wird, und kann auch das ausgeben.
Damit sollten wir hoffentlich bald auch für Riva einen Proben-Logger haben.



Der eigentliche Grund, wieso ich gerade in die .Exe schaue, ist, dass dort fast alles hart "geskripted" ist. Also was passiert, wenn man auf Feld X der Karte kommt, welcher Ausgang zu welchem Eingang führt, etc.
Daten zu letzterem habe ich schon (und ausschließlich) in der .Exe gefunden, die aber so komisch verstreut liegen, dass mir das ohne Codeverständnis leider nichts bringt.
Und die restlichen Daten aus der RIVA.ALF (also v.a. die jeweils anders kodierten .DAT Dateien), sehen leider nicht vielversprechend aus.
Also zumindest in einem Überflug konnte ich dort nichts spannendes mehr finden.
Das heißt, ich muss wohl mehr Assembler lernen..
Zitieren
Mich wundert das nicht so. Bei Schick war es auch schon so, dass viel von der Logik einfach in der EXE im Code festgelegt wurde. Die Idee mit dem DosBOX-Monitor halte ich daher für ziemlich gut.
Zitieren
(13.03.2023, 19:07)cmfrydos schrieb: Der eigentliche Grund, wieso ich gerade in die .Exe schaue, ist, dass dort fast alles hart "geskripted" ist. Also was passiert, wenn man auf Feld X der Karte kommt, welcher Ausgang zu welchem Eingang führt, etc.
Daten zu letzterem habe ich schon (und ausschließlich) in der .Exe gefunden, die aber so komisch verstreut liegen, dass mir das ohne Codeverständnis leider nichts bringt.
Und die restlichen Daten aus der RIVA.ALF (also v.a. die jeweils anders kodierten .DAT Dateien), sehen leider nicht vielversprechend aus.
Also zumindest in einem Überflug konnte ich dort nichts spannendes mehr finden.
Das heißt, ich muss wohl mehr Assembler lernen..
Wie schaust du rein? Gidhra oder IDA?

Hast du schon viele Funktionszuordnungen gefunden?
Zitieren
(18.03.2023, 12:30)Shihan schrieb: Wie schaust du rein? Gidhra oder IDA?

Hast du schon viele Funktionszuordnungen gefunden?

Ich habe den Code über das Watcom Disassembly Tool (https://github.com/fonic/wcdatool) bekommen, und ersteinmal darin gesucht. Als ich dann fündig wurde, und quasi einen Kristallkeim (in Form der Zufallsfunktion) hatte,
bin ich mehr auf den DosBox-Staging Debugger umgestiegen, und hangel mich da anhand von Rücksprungadressen und Breakpoints durch den Code, um mehr interessantes zu finden.

Bisher konnte ich etwa 20 Funktionen verstehen, vielleicht 30, wenn man so etwas wie Bildschirmschoner und wahrscheinlich, weil in anderem Codesegment, DOS-Renderschleife mitzählt,
die ich nur identifizieren konnte, aber mich ersteinmal nicht interessieren ;D.
Das repräsentiert, wenns man großzügig schätzt, vielleicht 30 der 4083 Funktionen, und etwa 500 der 44109 Funktionsaufrufen.
Hauptsächlich verstanden habe ich bisher nur 3 Würfelfunktionen, 4 Probenfunktionen(und unterfunktionen), 9 EW/TW/ZW Getter/Setter/Adder und eine GebeIndexVonElementInListe Funktion ;)

Fürs Auge hier mal ein schon stark eingedampfter Jump&Call Graph mit über 100tsd Kanten und 50tsd Knoten (Sprungstellen), wobei die blauen Kanten Funktionsaufrufe sind, und die schwarzen alle bedingten Sprünge respräsentieren.

   
Meine gefundenen Funktionen sind noch nichtmal in einem größerem Cluster, also in Richtung eines Riva-BrightEyes wäre das leider nur ein Tropfen auf heißem Stein..
Zitieren
(13.03.2023, 19:07)cmfrydos schrieb: Ersteinmal das, was mir auf der Zunge brennt:
Ich weiß wo in der Riva.exe die Probenwürfe stattfinden  :jippie: Zumindest einige. Aber ich ahne, wie man alle finden könnte.
Was ich nicht weiß ist, ob uns das einem Logger näher bringt, oder ob mein Ergebnis vielleicht für den ein oder anderen Minutenarbeit gewesen wäre, und schon bekannt?

Auch wenn ich mit meinen dürftigen IT-Kenntnissen leider keine Hilfe zu diesem Projekt beisteuern kann, wollte ich nur kurz zum Ausdruck bringen, wie sehr ich mich freue, dass es offensichtlich schon Fortschritte auf dem langen Weg zum Riva-Logger gibt! Das wäre echt der Hammer, wenn dieser eines Tages einmal Wirklichkeit werden sollte!!!  :jippie: :jippie: :thx:
Zitieren
(19.03.2023, 13:28)Tiefhusen schrieb: Auch wenn ich mit meinen dürftigen IT-Kenntnissen leider keine Hilfe zu diesem Projekt beisteuern kann, wollte ich nur kurz zum Ausdruck bringen, wie sehr ich mich freue, dass es offensichtlich schon Fortschritte auf dem langen Weg zum Riva-Logger gibt! Das wäre echt der Hammer, wenn dieser eines Tages einmal Wirklichkeit werden sollte!!!  :jippie: :jippie: :thx:





Das ist er schon :D . Ich warte gerade nur noch ab, ob ich vielleicht noch etwas an der Geschwindigkeit, und der Bedienungsfreundlichkeit schrauben kann.

Habe den Logger in einen eigenen Thread verlagert: https://www.crystals-dsa-foren.de/showth...p?tid=6059

Wenn da ein Kenner Ideen und Vorschläge zu beisteuern kann, würde ich mich freuen.






Ich bin gerade ziemlich happy, weil das was ich mir gerade in den Kopf gesetzt habe, wohl leichter ist, wie gedacht.

Hier ein paar Teaser. Wer mit weniger Infos errät, an was ich gerade arbeite, kriegt einen :toast: .



Zitieren
https://www.crystals-dsa-foren.de/showth...#pid132612 :
Shihan schrieb:Man kann den "Beleuchtungsmechanismus" von Riva gut sehen, besonders beim 2. Bild: Die Entfernung gibt einfach eine Helligkeitszunahme an. Das war's auch schon an Shading. Bei den Gräbern kann man das gut erkennen. Es ist noch nichtmal Gouraud-Shading, sonst könnte man die Kanten sehen. Nix, nur Helligkeit. Sehr lustig.


Mich verwirrt das Shading. Wenn man sich genau umguckt, kann man uA. Gouraud erkennen, aber eben noch mehr.
Leider ist dein Bild offline, daher kenne ich das dortige Setting nicht.

Die Lichtquelle der Gruppe kann ich noch einigermaßen erklären. Am Tag lüftet diese den Nebel, bei Nacht erhellt es die Karte. Das spielt nur Distanz eine Rolle.
Habe ich in meiner 3D Engine mit einer Depth-Map realisiert.

Kompliziert wird es z.B bei den auf den Karten platzierten Fackeln. Meine Verwirrung lässt sich am Leichtesten anhand von Bildern erklären.
Erst einmal ein Wireframe, damit man eine Idee bekommt, wo die Polygone liegen. Ich habe die Ecken der hier interessanten Flächen mal farblich markiert.
   
So, und als nächstes dann wie es im Original aussieht. Nicht wundern, ich habe hier das Zeichnen von Billboard"ähnlichem", wie z.B Animationen deaktiviert,
deshalb sieht man hier die Flamme nicht. Der aktuelle Held trägt keine Lichtquelle (wobei die Gruppe von sich aus auch immer etwas strahlt, aber sollte hier keinen Effekt haben).
Die grobe Position des Lichtes habe ich mal markiert.
   
Ich kann mir das nur erkären, wenn die Beleuchtung aus der Summe zweier verschiedener Algorithmen basiert.

a) Ganz deutlich sieht man eine Art kugelförmige Aura um das Zentrum der Lichtquelle. Ich verstehe nur nicht, was hier benutzt wurde. Ich würde ShadowMaps nehmen, aber gab es das schon 1997? Oder ist das einfach Per-Pixel Lighting?
b) Wenn man das Wireframe kennt, sieht man zusätzlich Per-Vertex Lighting, also wohl Gouraud-Shading. Es fällt nämlich auf, dass hinter der Lichtquelle kein Vertex ist, und es dort auch unerwartet (bzw. nach Per-Vertex dann doch erwartet) dunkel ist. Das Licht strömt vielmehr von den Ecken der Wand auf die Fackel zu. Man sieht sogar recht deutlich die Kante zwischen den beiden Wandpolygonen (Aufgrund der unterschiedlichen Distanz zu den entsprechenden Vertices). Das wohl auch ein Gouraud-Algorithmus in der .exe steckt, lässt sich auch daran sehen, dass "Gouraud" in einem String der .exe vorkommt. 

Das Resultat der Beleuchtung ist ganz klar ein Mix aus Beidem - da man beides sieht. Ich habe nur keine handfeste Idee, wie der 'Halo' realisiert wurde. Ich kenne mich dafür mit den verschiedenen Shading Algorithmen nicht genug aus. Und warum wurde Gouraud überhaupt mit in die Gleichung eingebracht? Reines Per-Pixel Lighting (wenn es das denn ist), sollte dem Mix ja überlegen sein.

Normalen spielen übrigends auch eine Rolle. Hier mal die Feuerstelle aus der ersten Ebene des Magierturms. Dass die linke Wand hier leuchtet, kann man ignorieren, dort ist einfach eine weitere Lichtquelle.
Aber die Wand vor einem liegt ganz klar im Schatten der Feuerstelle.
   

@Shihan, ich glaube du kennst dich mit der Thematik besser aus. Bestätigungen, oder Erklärungen würden mir sehr helfen. Natürlich auch von anderen.
Würde das Licht in meiner Engine gerne so nah wie möglich zum Original implementieren.

Edit: Zum Halo Effekt habe ich eine Idee. Man bestimmt den Schnittpunkt der an die Leuchtquelle angelegten Normale mit dem zu einer Ebene erweiterten Face. Ich weiß gar nicht, ob man per-Face Informationen an den Pixel-Shader weitergeben kann, sonst macht man es notfalls für alle drei Vertices, wobei jeweils das selbe herauskommt. Anhand des Schnittpunktes, der Position des Pixels, und ggbfs. der Größe des Face, kann im Pixelshader der Halo-Glow erzeugt werden. Gibt man noch mit, ob der Schnittpunkt vor, oder hinter der Lichtquelle liegt, kann man bestimmen, ob das Face im Schatten liegt. Dieses Procedere macht man für jede Lichtquelle, den Spieler eingeschlossen.
Keine Ahnung, ob das der echte Algorithmus ist. Aber der sollte ziemlich nah an den Effekt im Spiel herankommen.
Zitieren
(18.03.2023, 16:47)cmfrydos schrieb: Ich habe den Code über das Watcom Disassembly Tool (https://github.com/fonic/wcdatool) bekommen [..]
Cool, das hatte ich nicht auf dem Schirm. Muss ich mir auch mal ansehen. Ghidra ist zwar der Knaller, hat aber bei so altem Zeugs schonmal Schwierigkeiten. Die Kenntnisse über Watcom-Compiler und deren Calling Convention musste ich Ghidra erst beibringen. Danach kam aber ziemlich viel gutes Zeug raus.


(18.03.2023, 16:47)cmfrydos schrieb: Bisher konnte ich etwa 20 Funktionen verstehen, vielleicht 30, wenn man so etwas wie Bildschirmschoner und wahrscheinlich, weil in anderem Codesegment, DOS-Renderschleife mitzählt, die ich nur identifizieren konnte, aber mich ersteinmal nicht interessieren ;D.
Das repräsentiert, wenns man großzügig schätzt, vielleicht 30 der 4083 Funktionen, und etwa 500 der 44109 Funktionsaufrufen.
Hauptsächlich verstanden habe ich bisher nur 3 Würfelfunktionen, 4 Probenfunktionen(und unterfunktionen), 9 EW/TW/ZW Getter/Setter/Adder und eine GebeIndexVonElementInListe Funktion ;)

Wäre es möglich, dass Du mir Deine Asm-Listings und Infos mal zukommen lässt? Dann würde ich die mit meinen Erkenntnissen zusammenbringen und in mein Wiki posten (nebst Deinen neuen Entdeckungen im 3DM). Das würde bestimmt auch Deinen Aktivitäten im Proben-Logger-Thread helfen :)

Stand heute habe ich eine handvoll Funktionen ganz sicher identifiziert. Dazu gehören viele C-Library-Funktionen und ein paar aus der Watcom-Runtime. Viele weitere kann ich dank der Debug-Ausgaben, die noch drin versteckt sind, zumindest mal einzelnen Code-Files zuordnen. Dazu gehören Funktionen aus:

Die Anzahl der Funktionen ist eine Untergrenze. Vermutlich bekommen viele dieser Dateien am Ende noch mehr Funktionen zugeordet. Habe das etwas konservativ geschätzt.

Es gibt noch mehr Verweise auf CPP-Dateien, aber die konnte ich noch keinen Funktionen zuordnen. Insgesamt hab ich ca. 1400 Funktionen mit Namen versehen können. Die Angaben sind allerdings nicht in Stein gemeißelt, weil das Python-Skript dafür stark heuristisch vorgegangen ist. Aber die Richtung sollte stimmen und könnte helfen.

Überlege mir aktuell, wie man das so dokumentieren kann, dass es lesbar bleibt und Du schnell die Funktionen mit Deinen Asm-Listings und dem Dosbox-Debugger übereinander bringen kannst.



(21.03.2023, 09:56)cmfrydos schrieb: @Shihan, ich glaube du kennst dich mit der Thematik besser aus. Bestätigungen, oder Erklärungen würden mir sehr helfen. Natürlich auch von anderen.
Würde das Licht in meiner Engine gerne so nah wie möglich zum Original implementieren.

Deine Ausführungen passen für mich. Was Du mit diesem Halo-Effekt meinst, spukte auch schon vor meinem inneren Auge herum.

Würde auch denken, dass Gouraud-Shading die Grundlage ist. Das hat den Vorteil, dass man nur die 3-4 Vertices berechnen muss und den Rest im Polygon einfach interpolieren kann. Deshalb glaube ich nicht, dass es Per-Pixel-Shading ist, weil man dabei für jedes identifizierte Pixel ("fragment") diese Berechnungen machen müsste. Das würde in einem Software-Renderer dieses Alters wohl nicht schnell genug laufen. Per-Pixel hat ja erst richtig an Bedeutung gewonnen, als die Graphikkarten zur parallelen Fragment-Auswertung in der Lage waren.

Und ja, um die Face-Infos an den Pixel-Shader zu bringen, geht man den Weg über den Vertex-Shader. Da muss man sich auch keine Sorgen machen, dass die redundanten Informationen Probleme bereiten... die Hardware lacht darüber :D
Zitieren
(25.03.2023, 12:43)Shihan schrieb:
(18.03.2023, 16:47)cmfrydos schrieb: Ich habe den Code über das Watcom Disassembly Tool (https://github.com/fonic/wcdatool) bekommen [..]
Cool, das hatte ich nicht auf dem Schirm. Muss ich mir auch mal ansehen. Ghidra ist zwar der Knaller, hat aber bei so altem Zeugs schonmal Schwierigkeiten. 

Das Tool war der erste Google-Treffer auf meine Suche nach einem Watcom Disassembler. Wie gesagt, Assembler ist für mich Neuland. "Unter" C habe ich mich bisher nicht getraut. Daher kenne ich z.B. Ghidra gar nicht, aber sollte es mir wohl auch mal anschauen.
Da ich wirklich noch nicht viel von der Materie verstehe, frage ich lieber noch einmal nach, was genau du von mir gerne haben möchtest. :shy:
Ich erklimme leider gerade noch "Mount Stupid"..

[Bild: 512px-Dunning%E2%80%93Kruger_Effekt.svg.png]

(25.03.2023, 12:43)Shihan schrieb: Wäre es möglich, dass Du mir Deine Asm-Listings und Infos mal zukommen lässt? Dann würde ich die mit meinen Erkenntnissen zusammenbringen und in mein Wiki posten (nebst Deinen neuen Entdeckungen im 3DM). Das würde bestimmt auch Deinen Aktivitäten im Proben-Logger-Thread helfen :)

Was genau sind Asm-Listings? Meinst du damit die gesamte Ausgabe des wcdatools? (wenn ja, lieber von riva de oder en?)

An Infos daneben habe ich eine Liste mit HEX-Suchstrings, mit den gefundenen Adressen in der V1.01UK und der deutschen V1.12.
Jeweils noch mit einem Kommentar mit in etwa der Funktion an dieser Stelle. Die HEX-Suchstrings solltest du auch in deiner Disassembly finden.
Die Liste wird dann auch im Logger stecken, den ich die nächsten Wochen hier noch veröffentliche, kann sie dir aber schon mal zukommen lassen.
Ich habe auch einige "Daten"-Adressen, die aber wahrscheinlich nur für die englische Version gelten, und die ich noch nicht auf die Daten bzw. generierten Variablennamen in der Disassembly mappen konnte. Ich weiß nicht, ob dir das hilft? Ich habe darüber auch noch ein (leider noch nicht 100% korrektes) .py Skript, um mir aus den .asm einen Graphen zu erzeugen, und dort z.B Reachability abzufragen. Aber das ist halt auf die Ausgabe des wcdatools zugeschnitten.

(25.03.2023, 12:43)Shihan schrieb: Stand heute habe ich eine handvoll Funktionen ganz sicher identifiziert. Dazu gehören viele C-Library-Funktionen und ein paar aus der Watcom-Runtime. Viele weitere kann ich dank der Debug-Ausgaben, die noch drin versteckt sind, zumindest mal einzelnen Code-Files zuordnen. Dazu gehören Funktionen aus:

Die Anzahl der Funktionen ist eine Untergrenze. Vermutlich bekommen viele dieser Dateien am Ende noch mehr Funktionen zugeordet. Habe das etwas konservativ geschätzt.

Es gibt noch mehr Verweise auf CPP-Dateien, aber die konnte ich noch keinen Funktionen zuordnen. Insgesamt hab ich ca. 1400 Funktionen mit Namen versehen können. Die Angaben sind allerdings nicht in Stein gemeißelt, weil das Python-Skript dafür stark heuristisch vorgegangen ist. Aber die Richtung sollte stimmen und könnte helfen.

Oh, Wow, das hört sich ja fantastisch an! Keine Ahnung, wie du das geschafft hast - Ich habe da selbst nur immer mal wieder ein paar Strings im Hexeditor gesehen, konnte damit aber gar nichts anfangen.. ZB. die Informationen zu den Dungeon-Verknüpfungen, welcher Ausgang zu welchem Eingang führt, stand inmitten von .cpp Dateien (also den String Verweisen darauf). Deine Zuordnung könnte mir tatsächlich einiges erleichtern, da es meinen Suchraum stark einschränkt.
Wenn man aus den Startpositionen der Funktionen einen eindeutigen Suchstring generieren könnte, kann ich das direkt im Debugger anzeigen lassen. Nur so als Idee, um da unsere Ergebnisse abzugleichen. Das mit den Suchstrings funktioniert aber nicht überall. Vorallem bei weiten Sprüngen, oder Variablenreferenzierungen gibt es da doch einen Unterschied zwischen den Riva Versionen, und meiner disassembly. Aber in 2 von 3 Fällen hat es bisher geklappt. Optimalerweise würde man da dann mit einer RegEx suchen, bei denen die uneindeutigen Adressen Wildcards sind.

(25.03.2023, 12:43)Shihan schrieb: Deine Ausführungen passen für mich. Was Du mit diesem Halo-Effekt meinst, spukte auch schon vor meinem inneren Auge herum. [...]

Danke für deine Einschätzung, damit habe ich das Vertrauen, dass bei meinem Shader etwas sinnvolles bei rauskommen könnte :)
Wirklich vielen, vielen Dank für deine Hilfe! Hier ist es etwas still geworden, und die meisten Experten hier schauen nur noch alle paar Monate oder Jahre vorbei. Ich habe das Gefühl, ich bin hier über 10 Jahre zu spät, andererseits dann aber doch froh, dass es an Riva noch zu arbeiten gibt.
Zitieren
Ganz kurz, bevor ich näher auf Deinen Text eingehe:
Wie sieht bei Dir die Ausgabe vom wcdatool aus? Bei mir kommen da eine Reihe von Dateien raus, aber es schafft z.B. nicht, die ASMs noch aufzuteilen.

Das habe ich als Ergebnis:

Code:
| 158620615 Mar 25 15:56 RIVA.EXE_disasm_data_all.txt
|  11410114 Mar 25 15:56 RIVA.EXE_disasm_data_fixups.txt
|  11034014 Mar 25 15:56 RIVA.EXE_disasm_data_globals.txt
|        0 Mar 25 15:56 RIVA.EXE_disasm_data_modules.txt
| 131057471 Mar 25 15:56 RIVA.EXE_disasm_data_objects.txt
|  1630208 Mar 25 15:56 RIVA.EXE_disasm_object_1_data_binary.bin
|      152 Mar 25 15:56 RIVA.EXE_disasm_object_1_disassembly_data_map.txt
|  33857902 Mar 25 15:56 RIVA.EXE_disasm_object_1_disassembly_formatted.asm
|  24923552 Mar 25 15:56 RIVA.EXE_disasm_object_1_disassembly_plain.asm
|  10190489 Mar 25 15:56 RIVA.EXE_disasm_object_1_disassembly_structure.txt
|    228672 Mar 25 15:56 RIVA.EXE_disasm_object_2_data_binary.bin
|  1793956 Mar 25 15:56 RIVA.EXE_disasm_object_2_disassembly_data_map.txt
|  17495051 Mar 25 15:56 RIVA.EXE_disasm_object_2_disassembly_formatted.asm
|  16400991 Mar 25 15:56 RIVA.EXE_disasm_object_2_disassembly_plain.asm
|  2621219 Mar 25 15:56 RIVA.EXE_disasm_object_2_disassembly_structure.txt
|    485135 Mar 25 15:55 RIVA.EXE_fixup_data_binary.bin
| 118633617 Mar 25 15:55 RIVA.EXE_fixup_data_decoded.txt
|      4096 Mar 25 15:56 RIVA.EXE_modules/
|  2245095 Mar 25 15:55 RIVA.EXE_split_dos4g_payload.exe
|    232804 Mar 25 15:55 RIVA.EXE_split_dos4g_stub.exe
|  2233687 Mar 25 15:55 RIVA.EXE_split_linear_executable_payload.bin
|    11408 Mar 25 15:55 RIVA.EXE_split_linear_executable_stub.exe
|  12358784 Mar 25 15:55 RIVA.EXE_wdump_output_parsed.txt
|  12736879 Mar 25 15:55 RIVA.EXE_wdump_output_plain.txt
|    269398 Mar 25 15:56 RIVA.EXE_zzz_log.txt
|        2 Mar 25 15:32 ___output_files_will_be_created_here___

Wenn Du damit arbeitest, dann zieh ich den Hut! Selbst die "..._formatted.asm" sind super unübersichtlich. Respekt, dass Du da überhaupt was findest.

Allerdings bin ich nicht sicher, ob man das Ergebnis nicht noch schöner hinkriegt. Habe das jetzt unter Win10 mit WSL gemacht...
Zitieren
(25.03.2023, 16:11)Shihan schrieb: Ganz kurz, bevor ich näher auf Deinen Text eingehe:
Wie sieht bei Dir die Ausgabe vom wcdatool aus? Bei mir kommen da eine Reihe von Dateien raus, aber es schafft z.B. nicht, die ASMs noch aufzuteilen.

Ja, genau damit arbeite ich. Hauptsächlich mit der object1_formatted. Ich finde mich darin nur mittels Notepad++ und Strg-f zurecht. Und halt ein paar .py Skripte um da automatisiert zu suchen, oder es etwas umzuformatieren.
Aber das zeigt ziemlich gut, dass ich da mit meinem Können und Wissen zu Reverse-Enginieering ziemlich am Anfang stehe..

Ergänzung: Also ich hatte mich da entschieden, (Open) Watcom direkt auf Windows zu installieren, und das Python Skript statt über die .sh, direkt auszuführen. Aber ich vermute mal stark, dass da das selbe bei rauskommt. Der Code ist durchsäht mir Branches (wie object_1_branch_21994: ), und ich sehe neben der Adresse den binären Befehl als HexCode und den entsprechenden Assembler-Befehl. An einigen Stellen steht "; Bad code", die aber gottseidank bisher noch nicht relevant waren.
Zitieren
(25.03.2023, 16:00)cmfrydos schrieb: Das Tool war der erste Google-Treffer auf meine Suche nach einem Watcom Disassembler. Wie gesagt, Assembler ist für mich Neuland. "Unter" C habe ich mich bisher nicht getraut. Daher kenne ich z.B. Ghidra gar nicht, aber sollte es mir wohl auch mal anschauen.
Ghidra stolpert ab und an über das Disassembly (keine Ahnung, welchen Ansatz die nutzen). Das Problem ist ja generell, dass man das richtige, echte Disassembly eigentlich erst zur Laufzeit bekommt, weil dann bei Sprüngen und Pointer-Aktionen die notwendigen Register-Inhalte gesetzt sind. Alles andere ist eigentlich kluges Raten.

Wie dem auch sei, im Großen und Ganzen passt der Code. Das Schöne ist, dass man durch den Code browsen kann. Z.B. einem Call folgen, schauen, an welchen Stellen auf eine Adresse geschrieben oder von ihr gelesen wird, etc.
Und es gibt auch die Möglichkeit, eine Konvertierung in eine mögliche C-Funktion zu machen. Die ist meistens ziemlich chaotisch und kompiliert garantiert nicht, aber Dinge wie if oder while kann man dann schon erkennen.

   

Lohnt sich also schon, da mal einzusteigen ;)


(25.03.2023, 16:00)cmfrydos schrieb: Da ich wirklich noch nicht viel von der Materie verstehe, frage ich lieber noch einmal nach, was genau du von mir gerne haben möchtest. :shy:
Ich erklimme leider gerade noch "Mount Stupid"..
Mount Stupid ist völlig ok. Da stand ich auch drauf und dachte, ich hätte die Welt verstanden :D


(25.03.2023, 16:00)cmfrydos schrieb: Was genau sind Asm-Listings? Meinst du damit die gesamte Ausgabe des wcdatools? (wenn ja, lieber von riva de oder en?)
Jep, aber wie es scheint, gibt es da echt nur diese riesige ASM-Dateien...


(25.03.2023, 16:00)cmfrydos schrieb: An Infos daneben habe ich eine Liste mit HEX-Suchstrings, mit den gefundenen Adressen in der V1.01UK und der deutschen V1.12.
Jeweils noch mit einem Kommentar mit in etwa der Funktion an dieser Stelle. Die HEX-Suchstrings solltest du auch in deiner Disassembly finden.
Jep, das ist z.B. einer der großen Vorteile von Ghidra, weil es genau diese definierten Strings schon sammelt und dann auch sucht, wo sie im Code referenziert werden. Das hilft unglaublich!


(25.03.2023, 16:00)cmfrydos schrieb: Oh, Wow, das hört sich ja fantastisch an! Keine Ahnung, wie du das geschafft hast - Ich habe da selbst nur immer mal wieder ein paar Strings im Hexeditor gesehen, konnte damit aber gar nichts anfangen.. ZB. die Informationen zu den Dungeon-Verknüpfungen, welcher Ausgang zu welchem Eingang führt, stand inmitten von .cpp Dateien (also den String Verweisen darauf). Deine Zuordnung könnte mir tatsächlich einiges erleichtern, da es meinen Suchraum stark einschränkt.
Wenn man aus den Startpositionen der Funktionen einen eindeutigen Suchstring generieren könnte, kann ich das direkt im Debugger anzeigen lassen. Nur so als Idee, um da unsere Ergebnisse abzugleichen. Das mit den Suchstrings funktioniert aber nicht überall. Vorallem bei weiten Sprüngen, oder Variablenreferenzierungen gibt es da doch einen Unterschied zwischen den Riva Versionen, und meiner disassembly. Aber in 2 von 3 Fällen hat es bisher geklappt. Optimalerweise würde man da dann mit einer RegEx suchen, bei denen die uneindeutigen Adressen Wildcards sind.
Mal sehen, wie ich das aufbereite. In Ghidra kann man mit Python viel machen. Also werde ich wohl einfach einen sinnvollen Export bauen. Könnte aber ein paar Tage bauen, bis ich da was brauchbares habe...


(25.03.2023, 16:00)cmfrydos schrieb: Danke für deine Einschätzung, damit habe ich das Vertrauen, dass bei meinem Shader etwas sinnvolles bei rauskommen könnte :)
Wirklich vielen, vielen Dank für deine Hilfe! Hier ist es etwas still geworden, und die meisten Experten hier schauen nur noch alle paar Monate oder Jahre vorbei. Ich habe das Gefühl, ich bin hier über 10 Jahre zu spät, andererseits dann aber doch froh, dass es an Riva noch zu arbeiten gibt.
Jederzeit und sehr gerne! :)
Finde es großartig, dass Du hier eingestiegen bist und jetzt so viele gute Erkenntnisse gewonnen hast. Das hat mich motiviert, auch nochmal mehr einzusteigen.
Zitieren
(25.03.2023, 16:36)Shihan schrieb:
(25.03.2023, 16:00)cmfrydos schrieb: Das Tool war der erste Google-Treffer auf meine Suche nach einem Watcom Disassembler. Wie gesagt, Assembler ist für mich Neuland. "Unter" C habe ich mich bisher nicht getraut. Daher kenne ich z.B. Ghidra gar nicht, aber sollte es mir wohl auch mal anschauen.

Ghidra stolpert ab und an über das Disassembly (keine Ahnung, welchen Ansatz die nutzen). Das Problem ist ja generell, dass man das richtige, echte Disassembly eigentlich erst zur Laufzeit bekommt, weil dann bei Sprüngen und Pointer-Aktionen die notwendigen Register-Inhalte gesetzt sind. Alles andere ist eigentlich kluges Raten.



Wie dem auch sei, im Großen und Ganzen passt der Code. Das Schöne ist, dass man durch den Code browsen kann. Z.B. einem Call folgen, schauen, an welchen Stellen auf eine Adresse geschrieben oder von ihr gelesen wird, etc.

Und es gibt auch die Möglichkeit, eine Konvertierung in eine mögliche C-Funktion zu machen. Die ist meistens ziemlich chaotisch und kompiliert garantiert nicht, aber Dinge wie if oder while kann man dann schon erkennen.




Lohnt sich also schon, da mal einzusteigen ;)

Das sieht mal nach einer guten IDRE E aus ;D
Bisher mache ich das alles manuell. Schaue ich mir bald auf jeden Fall mal an. Wenn das mindestens genauso gut geht wie mit Notepad++ steige ich wahrscheinlich dann um.

Wäre schon cool, wenn man da irgendwie eine gemeinsame "Datenbasis" aufbauen könnte, und parallel über Git dran arbeiten kann. Also ähnlich wie bei BrightEyes, aber ersteinmal nur zur Analyse. Aber ich weiß noch nicht, ob das mit Ghidra gut geht. Auch das öffentliche Teilen der Disassembly halte ich für (rechtlich) schwierig, kann man daraus doch in Theorie die .exe rekonstruieren. Das Henne sich das getraut hat..

Da du jetzt den gleichen Output wie ich hast, brauche ich das nicht mehr teilen. Ich will dich nicht bremsen da ein Export Skript zu schreiben, aber vielleicht geht es leichter, wenn ich bei mir dann auch Ghidra einrichte.

Naja, also im Folgenden meine in den letzten Wochen gesammelten Adressen. Zum Automatisierten Parsen müsste man die unterschiedlichen Sektionen nochmal auseinandernehmen.
Zu den Adressen möchte ich noch erwähnen, dass es sich hierbei um bessere Abfangpunkte handelt, und nicht den Beginn einer Funktion. Z.T können mehrere Abfangpunkte in einer Funktion liegen, und manchmal muss man mehr als einmal abfangen, um zB. alle Infos zu einer Probe zu sammeln. Welche Register und Stackwerte wo genau spannend sind, ist denke ich hier erstmal nicht wichtig, und habe ich ausgelassen.

Was ich gerade noch suche ist (vielleicht mehr als Notizzettel für mich, oder für Interessierte ;D ):
- Stelle an der Texte abgefragt werden. Komme ich wahrscheinlich schnell per Unterbrechung während einer Anzeige ran
- Aktueller Screen / State. Wurde mindestens z.T. auch als Stack gelöst (zB. der Speicherdialog über der 3D Welt). Entweder brauche ich eine Liste der aktuellen States, oder muss die Übergangsfunktion(en) finden und abgreifen (also zB. 3DWelt, Innerhalb eines Hauses, Im Dialog, Kampf, "Inventar", Gegenstandsverteiler, Abspielen von Video, Einstellungen, ...)
- Evtl. wo der größere SVGA Screenbuffer liegt (finde ich wahrscheinlich auch in der DosBox)
- In welchem Dungeon man sich befindet. Falls dort Aktionen ausgeführt werden, bekomme ich das schon mit, aber habe noch nicht die Variable und die Funktion zum Wechseln gefunden.
- Wann ein neuer Track abgespielt wird

Und, ganz wichtig, nochmal zurück zum Datei-Format Reverse-Engineering: Woher kommen bitte die %S().() Dateien in Temp? (z.B. %SBO1.BO1)
Da steht drin, welche Objekte der Welt über welchen Schlüssel (meistens die O.Nummer) verändert werden können. Wird entweder von der .exe generiert, oder steht noch versteckt in einem .ALF Archiv

(25.03.2023, 16:36)Shihan schrieb: Finde es großartig, dass Du hier eingestiegen bist und jetzt so viele gute Erkenntnisse gewonnen hast. Das hat mich motiviert, auch nochmal mehr einzusteigen.

Freue mich, dass wir da zusammen dran arbeiten. :bigsmile:
Nur nach deinem Pacing. Habe gerade noch Semesterferien, werde in ein paar Wochen dann auch nicht mehr täglich dran arbeiten können.
Zitieren
Ein kurzes Videoupdate zum 4k Viewer:

Riva 4K Game Integration

Gestern größere Fortschritte gemacht, dass ich aktuellen Stand und noch zu behebende Bugs einmal festhalten wollte.

Es geht im Eilgalopp durch die Stadt, die Kanalisation, das Rivaner Umland und die Zwergenbinge.


Edit: @Shihan
Nachdem jetzt noch einige Codestellen dazukamen, zu denen es keinen versionsübergreifend eindeutigen Suchstring gibt,
habe ich mich entschieden, statt Suchstrings jetzt doch reguläre Ausdrücke zu verwenden. Alternative wäre gewesen, kurz davor oder danach eine Stelle zu suchen, zu denen es einen Suchstring gibt, und die echte Stelle dann noch mittels Offset anzugeben, aber die Bytezählerei war mir zu aufwendig.

Hier die weiteren Codestellen. Uneindeutige Bytes habe ich mit '.' markiert, dh. ein '.' kann zum Beispiel "0F" matchen. Ich hoffe das kann man auch irgendwie mittels Skript in Ghidra finden.

Und noch zu den Speicheradressen in der deutschen Version:
Hatte leider noch keine Zeit mir Ghidra näher anzuschauen, aber versuche es diese Woche noch.
Was mir noch (weniger) Lustiges aufgefallen ist: Sowohl der Code im DosBox Debugger als auch seltener der aus dem WCDATool stimmen an manchen Stellen nicht. Es werden die Bytessequenzen nicht richtig zerlegt, dh. nicht an den eigentlichen Befehlsgrenzen. Hier hilft dann nur Kreuzlesen, meistens erkennt man aber ganz gut, wenn die Abfolge und Art der Befehle keinen Sinn ergibt. Bin gespannt, wie sich Ghidra da schlägt. Meintest du das mit "Ghidra stolpert ab und an über das Disassembly"? Da ist es vielleicht ganz gut, mehrere Disassemblies zu haben.
Zitieren
Wenn ich mir Dein Video ansehe, muss ich sagen: WAHNSINN!
Hast ja richtig Fortschritte gemacht, weit über das hinaus, was ich damals geschafft habe. Super Sache!


(28.03.2023, 18:12)cmfrydos schrieb: Hatte leider noch keine Zeit mir Ghidra näher anzuschauen, aber versuche es diese Woche noch.
Was mir noch (weniger) Lustiges aufgefallen ist: Sowohl der Code im DosBox Debugger als auch seltener der aus dem WCDATool stimmen an manchen Stellen nicht. Es werden die Bytessequenzen nicht richtig zerlegt, dh. nicht an den eigentlichen Befehlsgrenzen. Hier hilft dann nur Kreuzlesen, meistens erkennt man aber ganz gut, wenn die Abfolge und Art der Befehle keinen Sinn ergibt. Bin gespannt, wie sich Ghidra da schlägt. Meintest du das mit "Ghidra stolpert ab und an über das Disassembly"? Da ist es vielleicht ganz gut, mehrere Disassemblies zu haben.
Genau das meinte ich. Am treffsichersten ist der Debugger der Dosbox, aber nur, wenn man step-by-step durchgegeht. Ghidra und das wcdatool machen statische Analyse, die nicht immer richtig sein muss. Wenn man aber alles zusammen nimmt, dann bekommt man schon den richtigen Eindruck, hoffe ich :D


(28.03.2023, 18:12)cmfrydos schrieb: Nachdem jetzt noch einige Codestellen dazukamen, zu denen es keinen versionsübergreifend eindeutigen Suchstring gibt,
habe ich mich entschieden, statt Suchstrings jetzt doch reguläre Ausdrücke zu verwenden. Alternative wäre gewesen, kurz davor oder danach eine Stelle zu suchen, zu denen es einen Suchstring gibt, und die echte Stelle dann noch mittels Offset anzugeben, aber die Bytezählerei war mir zu aufwendig.
Ich versuche die Tage mal, mittels Python-Skript diese Stellen im Ghidra-Disassembly zu finden.
Aktuell bin ich aber mental wieder etwas schlechter dran, daher wird es noch einige Zeit dauern, bis ich was Neues habe.
Zitieren
Gibt es da ein Skalierungs- oder Auflösungsproblem oder täuscht mich meine Erinnerung so sehr? :think:

Die Gebäude in Riva kommen mir alle einen Tick zu schmal vor, vor allem die Lagerhäuser wirken komisch. Aber es ist auch schon sehr lange her, dass ich Riva zuletzt hab laufen lassen. ^^"

Coole Sache auf jeden Fall! :ok:
Die der Götter Gunst verloren,
sind verfallen einer Macht -
Die sie führt zu fernen Toren,
und durch sie in ew'ge Nacht.
Zitieren
(30.03.2023, 18:33)Alpha Zen schrieb: Gibt es da ein Skalierungs- oder Auflösungsproblem oder täuscht mich meine Erinnerung so sehr? :think:

Die Gebäude in Riva kommen mir alle einen Tick zu schmal vor, vor allem die Lagerhäuser wirken komisch. Aber es ist auch schon sehr lange her, dass ich Riva zuletzt hab laufen lassen. ^^"

Coole Sache auf jeden Fall! :ok:

Vielen Dank für den Hinweis, damit hast du vollkommen Recht!
Mir ist das vor ein paar Wochen auch schon aufgefallen, dass das optisch irgendwie nicht hinkommt,
aber habe es nicht direkt untersucht, und es fiel mir seitdem nicht mehr auf.
(Selektive Wahrnehmung und so ;D)
Da ist es super, dass wir hier noch ein paar mehr Augen im Forum haben.

Mein Renderer behandelt X, Y und Z Koordinaten identisch. Das heißt es wird unverzerrt genauso gezeichnet, wie es in den Daten steht.

Beispielhaft betrachten wir im Folgenden eine der Seiten der Lagerhäuser. Folgende Koordinaten dazu stehen in den 3D Daten:
Eckpunkte P1(-75216792, -448) und P2(-66076204, 8824943) =>Breite 9140588, Höhe 8825391, Verhältnis Breite/Höhe: 1,036

Hier wie es der neue Renderer darstellt:
[Bild: attachment.php?aid=6196]
Breite 988, Höhe 949, Verhältnis Breite/Höhe: 1,041

Und hier wie es in der DosBox aussieht: (mit rechteckigen Pixeln, siehe unten)
[Bild: attachment.php?aid=6197]
Breite 1333, Höhe 979, Verhältnis Breite/Höhe: 1,373

Ich habe das selbe noch mit der vorderen Seite des Lagerhauses gemacht, und kam zu einem ähnlichen Ergebniss, dass mein Renderer Dinge im Schnitt etwa um den Faktor 1,3 zu hoch malt.

Folglich muss der Renderer des originalen Spieles die Y-Koordinaten stauchen, tatsächlich sogar in etwa um den Faktor 1,56 , denn, die Pixel, wie sie in der Dosbox dargestellt werden, sind um den Faktor 1,2 in der Höhe gestreckt. Vielleicht ist das euch schon mal aufgefallen dass die Pixel dort nicht quadratisch sind. Die Auflösung des Spiels ist eigentlich 16:10 (320x200), aber fast alle der damaligen Monitore waren 4:3, was dazu führt, dass man entweder oben und unten einen schwarzen Balken hat, oder das Spiel in die Höhe gestreckt wird.
Hier noch einen interessanten Artikel dazu, der unter anderem dieses Problem thematisiert: http://nerdlypleasures.blogspot.com/2013...bm-pc.html
Man kann etwas runter scrollen, interessant wird es kurz bevor die ersten Bilder mit Kreisen gezeigt werden.
Der Kern ist: Es gab Spiele, die grafisch darauf designed wurden, im gestreckten Modus gespielt zu werden, und andere, die nur mit schwarzem Balken oben und unten richtig aussahen.

Die Frage ist, wie ist das bei Riva?
Ich finde, dass beides gut aussieht, tendiere bei der 3D Grafik aber eher zu den rechteckigen, dh. gestreckten Pixeln.

Was denkt ihr, dass richtig ist? Quadratische, oder Rechteckige Pixel?

Hier zum Vergleich mal ein Let's Play, dass in 16:10 aufgenommen wurde, dh. mit quadratischen Pixeln.
https://youtu.be/u4YkeQaUQRQ?t=819

Bei Minute 13:40 ist interessant zu beobachten, wie die Travia-Geweihte im Video deutlich zu breit wirkt, im darauffolgenden Dialog aber 'richtig' aussieht.
Vielleicht wurde bei der Entwicklung von Riva auch einfach kein einheitlicher Ansatz verwendet :lol:


Angehängte Dateien Thumbnail(s)
       
Zitieren
Hatte das Spiel nicht nur eine DOS-Exe, sondern auch eine für Win32 bzw. Windows 95 in SVGA? Könnte sogar sein, dass es dann ein leicht unterschiedliches Seitenverhältnis hatte.
Zitieren
Meine mich auch zu erinnern, dass Riva bei mir in 640x480 lief. Ob das aber die "korrekte" Auflösung ist, weiß ich nicht. ^^

Es ist zumindest die Optik, die sich mir eingebrannt hat. :)
Die der Götter Gunst verloren,
sind verfallen einer Macht -
Die sie führt zu fernen Toren,
und durch sie in ew'ge Nacht.
Zitieren




Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste