Portal-Zone Gothic-Zone Gothic II-Zone Gothic 3-Zone Gothic 4-Zone Modifikationen-Zone Download-Zone Foren-Zone RPG-Zone Almanach-Zone Spirit of Gothic

 

Ergebnis 1 bis 12 von 12
  1. Beiträge anzeigen #1 Zitieren
    Provinzheld Avatar von Herobrine
    Registriert seit
    Oct 2012
    Ort
    Minental von Khorinis (Gothic)
    Beiträge
    275
     
    Herobrine ist offline

    Abfragen, welche ZS_POS der PC/ein NPC benutzt

    Hey,

    Ist es irgendwie möglich, abzufragen (mithilfe von Ikarus und LeGo natürlich), an welcher ZS_POS (ZS_POS0/ZS_POS1/etc.) sich der Spielercharakter oder ein NPC beim Benutzen eines Mobs befindet? Ich würde gerne eine von mir erstellte gespiegelte Animation abspielen, falls sich der PC/NPC an ZS_POS1 befindet. Außerdem würde ich, um das zu ermöglichen, auch gerne wissen, wie ich die State-Animationsnamen austauschen kann: Sagen wir mal bei ZS_POS0 soll die Animation T_Baumsaege0_Stand_2_S0 abgespielt werden und bei ZS_POS1 soll die Animation T_Baumsaege1_Stand_2_S0 abgespielt werden.

    MfG,
    Herobrine

  2. Beiträge anzeigen #2 Zitieren
    Knight
    Registriert seit
    Aug 2009
    Ort
    Hessen
    Beiträge
    1.487
     
    Cryp18Struct ist offline
    Du könntest dein mob wahrscheinlich einfach als Bett im spacer setzen.
    Da gibt es jeweils 2 unterschiedliche Animationen, je nach dem aus welcher Richtung man das Teil benutzt(t_BedHigh_Front_Stand_2_S0, t_BedHigh_Back_Stand_2_S0).

    edit: in gothic1 funktioniert die Behandlung von Betten evt. nicht richtig. Deshalb sind da die Betten auch als Tür gesetzt im spacer. Tür sollte auf jeden Fall gehen.
    Geändert von Cryp18Struct (26.02.2020 um 14:10 Uhr)

  3. Beiträge anzeigen #3 Zitieren
    now also in your universe  Avatar von Milky-Way
    Registriert seit
    Jun 2007
    Beiträge
    15.246
     
    Milky-Way ist offline
    Ich glaube, selbst in G2 müssen Betten zur zweiseitigen Benutzung als Tür (oCMobDoor) gesetzt sein -- zumindest hatten sich da meiner Erinnerung nach unsere Tester mal beschwert über Betten, die nur von einer Seite aus gingen.

  4. Beiträge anzeigen #4 Zitieren
    Knight
    Registriert seit
    Aug 2009
    Ort
    Hessen
    Beiträge
    1.487
     
    Cryp18Struct ist offline
    Ich habe es nicht getestet, aber nico behauptet ocMobBed funktioniert in g2:
    https://forum.worldofplayers.de/foru...1#post24734420

  5. Beiträge anzeigen #5 Zitieren
    Provinzheld Avatar von Herobrine
    Registriert seit
    Oct 2012
    Ort
    Minental von Khorinis (Gothic)
    Beiträge
    275
     
    Herobrine ist offline
    Zitat Zitat von Cryp18Struct Beitrag anzeigen
    Du könntest dein mob wahrscheinlich einfach als Bett im spacer setzen.
    Da gibt es jeweils 2 unterschiedliche Animationen, je nach dem aus welcher Richtung man das Teil benutzt(t_BedHigh_Front_Stand_2_S0, t_BedHigh_Back_Stand_2_S0).

    edit: in gothic1 funktioniert die Behandlung von Betten evt. nicht richtig. Deshalb sind da die Betten auch als Tür gesetzt im spacer. Tür sollte auf jeden Fall gehen.
    Ah, an Betten habe ich gar nicht gedacht. Das funktioniert schon mal mit BACK und FRONT. Habe allerdings immer noch ein paar Probleme:

    Ich versuche einen Patch zu erstellen, der Ninja nutzt, der das Visual aller Baumsäge Mobs austauscht (also BAUMSAEGE_1.ASC durch BAUMSAEGE_1.MDS). Ich kann die .ASC nicht einfach ersetzen, weil mein Baumsäge-Mob animiert ist, weswegen ich es durch eine while-Schleife löse. Hierzu nutze ich mudfreaks searchVobs.d Script, welches ein Array nutzt, in das nur oCMobInter gespeichert werden. Bei den oCMobInter wird dann abgefragt, ob dessen Visual "BAUMSAEGE_1.ASC" ist und dann mit mudfreaks VobSetVisual aus seiner insertAnything.d das Model jeweils mit "BAUMSAEGE_1.MDS" ausgetauscht.

    Das klappt soweit. Allerdings weiß ich nicht, wie ich ein oCMobInter in ein oCMobDoor umwandeln kann, um FRONT und BACK zu nutzen. Momentan frage ich Positionen und Rotationen von Mobs ab, die als Visual "BAUMSAEGE_1.ASC" haben, platziere dann an durch die abgefragten Positionen und Rotationen jeweils ein oCMobDoor mit dem Visual "BAUMSAEGE_1.MDS" an dessen Stelle und lösche die oCMobInter mit MEM_DeleteVob. Beim Spielstart ist das kein großes Ding, das funktioniert super. Wenn ich das Spiel allerdings speichere, muss ich das Mob ja wieder ersetzen mit einem oCMobInter mit dem "BAUMSAEGE_1.ASC" Visual, weil sonst beim Entfernen des Patches das Spiel beim Laden des Savegames abschmiert. Beim normalen oCMobInter klappen FRONT und BACK nicht, weswegen ich auch wissen wollte, ob man den AniNamen, der vom Mob genutzt werden soll, irgendwie abändern kann oder die ZS_POS abfragen kann, um dann die Animation, die genutzt werden soll, zu ändern. Das würde dann beim Speichern keine Probleme machen, weil das Austauschen des Visuals keine Probleme macht, das habe ich schon ausprobiert.

    Worum es mir vor allem geht, ist, dass beim Abspeichern das ersetzte Mob nicht gespeichert werden soll. Momentan habe ich die Funktionen "CGameManager_Write_Savegame" und "oCSavegameManager_SetAndWriteSavegame" gehookt. CGameManager_Write_Savegame ruft ein Script zum Ersetzen der BAUMSAEGE_1.MDS mit BAUMSAEGE_1.ASC vor Anfang des Speichern auf, oCSavegameManager_SetAndWriteSavegame ruft nach dem Speichern das Script zum Ersetzen der BAUMSAEGE_1.ASC durch die BAUMSAEGE_1.MDS auf - sodass es, falls der Patch entfernt wird, keine Probleme mehr gibt. Das würde keine Probleme machen, wenn NPCs die Mobs nicht benutzen würden. Wenn sie die Mobs allerdings benutzen, während gespeichert wird, nutzt der NPC noch das Mob, das ersetzt wurde und das Spiel crasht, sobald der NPC das nicht vorhandene Mob nicht mehr benutzt, was heißt: sollte man ihn ansprechen oder schlagen oder sonst irgendetwas machen, was dafür sorgt, dass er aufhört, das Mob zu nutzen, crasht das Spiel. Auch, wenn man aus seiner Reichweite geht, crasht das Spiel. Hierfür hatte ich dann überlegt, dafür zu sorgen, dass der NPC mit AI_StandUp aufhört, das Mob zu nutzen. Das klappt auch mit der searchVobs.d, indem ich alle oCNPC suche, die als NPC_GetDetectedMob("BAUMSAEGE") haben. Aber nur, wenn sie sich im Zustand S1 befinden. In Zwischenzuständen wie S0_2_S1 klappt es nicht, dann warten sie, bis sie S1 erreicht haben und hören dann erst auf, das Mob zu nutzen. Das sorgt auch dafür, dass das Spiel crasht. Da habe ich mir natürlich wieder etwas überlegt: nämlich dafür zu sorgen, dass das Spiel nicht gespeichert werden kann, sollte ein NPC die Zwischenanimationen nutzen. Dafür habe ich dann Sektenspinners EnforceSavingPolicy und mudfreaks Ninja_SavingPolicy genutzt. Sektenspinners EnforceSavingPolicy verträgt sich allerdings nicht mit meinen Savegame Hooks. Nur wenn ich die Quicksave-Sachen rausnehme. Ich habe das Gefühl, dass es einfacher wäre, könnte ich irgendwie einfach nur auf das Savegame mit Daedalus zugreifen und dann nicht zur Laufzeit die Mobs beim Speichern ersetzen, sondern nur für das Savegame, das gespeichert wird. Beim Laden wird mit der Patch_Init dann sowieso das Mob wieder ausgetauscht, aber wenn man den Patch entfernt, handelt es sich wieder um ein oCMobInter mit dem Visual "BAUMSAEGE_1.ASC".

    TL;DR: Gibt es irgendeine Möglichkeit, bestimmte Funktionen wie z.B. MEM_DeleteVob oder MEM_InsertVob nicht für einen Speicherstand zu übernehmen, bzw. nur für einen Speicherstand auszuführen?
    Geändert von Herobrine (29.02.2020 um 14:20 Uhr)

  6. Beiträge anzeigen #6 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Ich frage mich, ob es klappt hier die Archiver-Funktion von zCVob zu hooken und dort den String des Visuals beim Speichern zu ersetzen. Damit sollte das laufende Spiel unberührt bleiben, ich weiß aber nicht aus dem Kopf ob das Spiel laden dann funktioniert.

  7. Beiträge anzeigen #7 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Was zumindest das Ersetzen des Visuals angeht, probier es mal damit. Hier wird sowohl ein anderer Visual-Name (in ReplaceVisualOnSave2) als auch ein anderes zCVisual-Objekt (in ReplaceVisualOnSave1) in den Speicherstand geschrieben. Das hat bei mir mit 3DS Visuals bei simplen zCVobs gut funktioniert. Wenn ich andere Visuals mit 3DS ersetzt habe gab es beim Laden Warnungen. Die Kombination ASC zu MDS bei oCMobInter habe ich nicht ausprobiert. Ich denke es sollte keinerlei Probleme geben. Halte aber trotzdem auf jeden Fall die Augen nach Warnungen im zSpy offen. Die sollte man sicher nicht auf die leichte Schulter nehmen.

    Die Adressen sind für Gothic 2. Moddest du für Gothic 1?
    Code:
    const int dummy_visual = 0;
    const int dummy_visStrPtr = 0;
    
    func void ReplaceVisualOnSave_Init() {
        const int zCVisual__LoadVisual           = 6318800; //0x606AD0
        const int zCVob__ArchivePacked_visual    = 6286598; //0x5FED06
        const int zCVob__ArchivePacked_visualStr = 6286574; //0x5FECEE
    
        HookEngineF(zCVob__ArchivePacked_visual,    8, ReplaceVisualOnSave1);
        HookEngineF(zCVob__ArchivePacked_visualStr, 6, ReplaceVisualOnSave2);
    
        if (!dummy_visual) {
            CALL_zStringPtrParam("BAUMSAEGE_1.ASC");
            CALL_PutRetValTo(_@(dummy_visual));
            CALL__cdecl(zCVisual__LoadVisual);
        };
    
        if (!dummy_visStrPtr) {
            dummy_visStrPtr = _@s("BAUMSAEGE_1.ASC");
        };
    };
    func void ReplaceVisualOnSave1() {
        var zCVob vob; vob = _^(EBP);
        if (vob.visual) {
            var zCObject vis; vis = _^(vob.visual);
            if (Hlp_StrCmp(vis.objectname, "BAUMSAEGE_1.MDS")) {
                ECX = dummy_visual;
            };
        };
    };
    func void ReplaceVisualOnSave2() {
        var zCVob vob; vob = _^(EBP);
        if (vob.visual) {
            var zCObject vis; vis = _^(vob.visual);
            if (Hlp_StrCmp(vis.objectname, "BAUMSAEGE_1.MDS")) {
                ECX = dummy_visStrPtr;
            };
        };
    };
    Eine Idee für das Ersetzen von oCMobDoor nach oCMobInter vor dem Speichern habe ich nicht. Musst du das denn zwingend zurück ersetzen? oCMobDoor erbt von oCMobInter. Könntest du es nicht dann einfach beim oCMobDoor belassen?

  8. Beiträge anzeigen #8 Zitieren
    Provinzheld Avatar von Herobrine
    Registriert seit
    Oct 2012
    Ort
    Minental von Khorinis (Gothic)
    Beiträge
    275
     
    Herobrine ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    Was zumindest das Ersetzen des Visuals angeht, probier es mal damit. Hier wird sowohl ein anderer Visual-Name (in ReplaceVisualOnSave2) als auch ein anderes zCVisual-Objekt (in ReplaceVisualOnSave1) in den Speicherstand geschrieben. Das hat bei mir mit 3DS Visuals bei simplen zCVobs gut funktioniert. Wenn ich andere Visuals mit 3DS ersetzt habe gab es beim Laden Warnungen. Die Kombination ASC zu MDS bei oCMobInter habe ich nicht ausprobiert. Ich denke es sollte keinerlei Probleme geben. Halte aber trotzdem auf jeden Fall die Augen nach Warnungen im zSpy offen. Die sollte man sicher nicht auf die leichte Schulter nehmen.

    Die Adressen sind für Gothic 2. Moddest du für Gothic 1?
    Code:
    const int dummy_visual = 0;
    const int dummy_visStrPtr = 0;
    
    func void ReplaceVisualOnSave_Init() {
        const int zCVisual__LoadVisual           = 6318800; //0x606AD0
        const int zCVob__ArchivePacked_visual    = 6286598; //0x5FED06
        const int zCVob__ArchivePacked_visualStr = 6286574; //0x5FECEE
    
        HookEngineF(zCVob__ArchivePacked_visual,    8, ReplaceVisualOnSave1);
        HookEngineF(zCVob__ArchivePacked_visualStr, 6, ReplaceVisualOnSave2);
    
        if (!dummy_visual) {
            CALL_zStringPtrParam("BAUMSAEGE_1.ASC");
            CALL_PutRetValTo(_@(dummy_visual));
            CALL__cdecl(zCVisual__LoadVisual);
        };
    
        if (!dummy_visStrPtr) {
            dummy_visStrPtr = _@s("BAUMSAEGE_1.ASC");
        };
    };
    func void ReplaceVisualOnSave1() {
        var zCVob vob; vob = _^(EBP);
        if (vob.visual) {
            var zCObject vis; vis = _^(vob.visual);
            if (Hlp_StrCmp(vis.objectname, "BAUMSAEGE_1.MDS")) {
                ECX = dummy_visual;
            };
        };
    };
    func void ReplaceVisualOnSave2() {
        var zCVob vob; vob = _^(EBP);
        if (vob.visual) {
            var zCObject vis; vis = _^(vob.visual);
            if (Hlp_StrCmp(vis.objectname, "BAUMSAEGE_1.MDS")) {
                ECX = dummy_visStrPtr;
            };
        };
    };
    Oh, vielen Dank! Ich modde sowohl für Gothic 2 als auch für Gothic 1. Ausprobieren tue ich das ganze aber mit Gothic 2 momentan. Es soll später auch für Gothic 1 funktionieren, wobei ich mir momentan nicht sicher bin, ob ich außer den Baumsäge-Mobs noch andere Modelle austauschen will und es im originalen Gothic 1 keine Baumsägen gibt. Für Mods, die die Baumsäge mit BAUMSAEGE_1.ASC als Visual einfügen, ist der Patch dann natürlich doch ganz praktisch.

    Wenn der einzige Unterschied die Adressen sind, ist das kein Problem. Die kann ich ja dann mit MEMINT_SwitchG1G2 ganz einfach austauschen.

    Das Austauschen der Visuals bei den Baumsäge-Mobs funktioniert. Wenn ich speichere, dann das Spiel beende, den Patch entferne und lade, haben alle Baumsäge-Mobs die BAUMSÄGE_1.ASC als Visual. Ich musste nur das Script von dir nochmal anpassen und statt dem Vob den Vob Pointer nutzen, um dann mithilfe von F a w k e s Mob_GetVisualName Funktion an den Visual-Namen zu kommen und diesen dann zu vergleichen. vis.objectname hat er bei mir zwar bei Vobs gefunden, aber nicht bei Mobs. Es gibt jetzt nur noch ein Problem, welches ich unten beschreibe.
    Zitat Zitat von mud-freak Beitrag anzeigen
    Eine Idee für das Ersetzen von oCMobDoor nach oCMobInter vor dem Speichern habe ich nicht. Musst du das denn zwingend zurück ersetzen? oCMobDoor erbt von oCMobInter. Könntest du es nicht dann einfach beim oCMobDoor belassen?
    Das Problem ist hierbei FRONT und BACK. Wenn es sich um ein oCMobDoor handelt und keine FRONT oder BACK Animationen vorhanden sind, dann wird keine Animation gefunden und dementsprechend auch keine abgespielt beim Benutzen des Mobs. Habe es ausprobiert. NPCs stehen leider einfach nur still vor den Baumsägen, wenn es sich um ein oCMobDoor handelt und der zSpy sagt mir ziemlich oft, dass die Animation "T_BAUMSAEGE_BACK_STAND_2_S0" nicht gefunden wurde.

  9. Beiträge anzeigen #9 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Ich habe ein bisschen nachgeforscht (hat wieder länger gedauert als ich gedacht hätte). Ähnlich wie beim Visual, ersetze ich die Klasse des Objekts im Speicherstand mit einer anderen (oCMobInter). Das war nicht so einfach, da das Archiving etwas verschachtelt ist und die richtigen Stellen nicht so leicht aufzufinden waren. Auch wird beim Speichern der Klassenbezeichnung deren Prüfsumme mitgespeichert, die beim Laden überprüft wird.

    Der Code unten sollte alles beinhalten (inkl. des Codes für das Visual vom letzten Post). Der Code läuft bereits für G1 und G2 und setzt (außer Ikarus) nichts anderes voraus. Anstatt Fawkes Mob_GetVisualName Funktion, ist im Code eine generelle Variante, die mit allen von zCVob abgeleiteten Klassen funktioniert. (Wegen der Prüfsumme und des Klassennamens ist der Code nicht flexibel für das Tauschen in beliebige Klassen, sondern nur für den Tausch nach oCMobInter.)

    Code:
    /*
     * Get the visual name from any object inheriting from zCVob
     */
    func string OverrideMobDoor_GetVobVisName(var int vobPtr) {
        var zCVob vob; vob = _^(vobPtr); // Caution: No check if valid zCVob
        CALL_RetValIszString();
        CALL__thiscall(vob.visual, MEM_ReadInt(MEM_ReadInt(vob.visual) + /*GetVisualName 0x20*/32));
        return CALL_RetValAszString();
    };
    
    /*
     * Initialization function
     */
    func void OverrideMobDoor_Init() {
        const int zCArchiverGeneric__WriteObject_className_G1  = 5325313; //0x514201
        const int zCArchiverGeneric__WriteObject_className_G2  = 5393841; //0x524DB1
        const int zCArchiverGeneric__WriteObject_archiveObj_G1 = 5325323; //0x51420B
        const int zCArchiverGeneric__WriteObject_archiveObj_G2 = 5393851; //0x524DBB
        const int zCVob__ArchivePacked_visual_G1               = 6109963; //0x5D3B0B
        const int zCVob__ArchivePacked_visual_G2               = 6286598; //0x5FED06
        const int zCVob__ArchivePacked_visualStr_G1            = 6109939; //0x5D3AF3
        const int zCVob__ArchivePacked_visualStr_G2            = 6286574; //0x5FECEE
    
        HookEngineF(MEMINT_SwitchG1G2(zCArchiverGeneric__WriteObject_className_G1,
                                      zCArchiverGeneric__WriteObject_className_G2),  5, OverrideMobDoor_WriteClassName);
        HookEngineF(MEMINT_SwitchG1G2(zCArchiverGeneric__WriteObject_archiveObj_G1,
                                      zCArchiverGeneric__WriteObject_archiveObj_G2), 6, OverrideMobDoor_CallArchiver);
        HookEngineF(MEMINT_SwitchG1G2(zCVob__ArchivePacked_visual_G1,
                                      zCVob__ArchivePacked_visual_G2),               8, OverrideMobDoor_WriteVisual);
        HookEngineF(MEMINT_SwitchG1G2(zCVob__ArchivePacked_visualStr_G1,
                                      zCVob__ArchivePacked_visualStr_G2),            6, OverrideMobDoor_WriteVisName);
    };
    func int OverrideMobDoor_IsNeedle(var int objPtr) {
        if (!Hlp_Is_oCMobDoor(objPtr)) { // Important, because zCArchiverGeneric::WriteObject is called for any zCObject
            return FALSE;
        };
        return Hlp_StrCmp(OverrideMobDoor_GetVobVisName(objPtr), "BAUMSAEGE_1.MDS");
    };
    func void OverrideMobDoor_WriteClassName() {
        if (OverrideMobDoor_IsNeedle(ESI)) {
            MEM_Debug("OverrideMobDoor: Archive as oCMobInter (class name)");
            ECX = STR_toChar("oCMobInter:oCMOB:zCVob"); // Write different class name
            EAX = 35585; // oCMobInter::_GetClassDef()->archiveVersionSum (Same for G1 and G2)
        };
    };
    func void OverrideMobDoor_CallArchiver() {
        if (OverrideMobDoor_IsNeedle(ESI)) {
            MEM_Debug("OverrideMobDoor: Archive as oCMobInter (vtbl)");
            EAX = oCMobInter_vtbl; // Call different archiver (that of oCMobInter)
        };
    };
    func void OverrideMobDoor_WriteVisual() {
        if (OverrideMobDoor_IsNeedle(EBP)) {
            MEM_Debug("OverrideMobDoor: Write different visual");
    
            // Create different visual for game saves - only once and only just now, to be sure it's necessary
            const int dummyVisual = 0;
            if (!dummyVisual) {
                const int zCVisual__LoadVisual_G1 = 6136304; //0x5DA1F0
                const int zCVisual__LoadVisual_G2 = 6318800; //0x606AD0
                CALL_zStringPtrParam("BAUMSAEGE_1.ASC");
                CALL_PutRetValTo(_@(dummyVisual));
                CALL__cdecl(MEMINT_SwitchG1G2(zCVisual__LoadVisual_G1, zCVisual__LoadVisual_G2));
            };
    
            ECX = dummyVisual; // Write different visual
        };
    };
    func void OverrideMobDoor_WriteVisName() {
        if (OverrideMobDoor_IsNeedle(EBP)) {
            MEM_Debug("OverrideMobDoor: Write different visual name");
            ECX = _@s("BAUMSAEGE_1.ASC"); // Write different visual name
        };
    };

    Hier noch ein paar Gedanken zu dem Vorhaben, daraus einen Patch zu machen:
    1. Beim Test unter G1 ist mir aufgefallen, dass die BAUMSAEGE_1.ASC in G1 nicht existiert. Damit es beim Spielen dort nicht zu einem Fehler kommt, habe ich die Erstellung des Dummy-Visuals in die entsprechende Hookfunktion verschoben, damit es nur erstellt wird, wenn es gebraucht wird und folglich existiert.
    2. Beachte die Namenskonventionen für alle Symbole (Ninja_[PatchName]_*), wenn du daraus einen Patch machst. Da der Code hier zugänglich ist, könnte es sein das jemand ihn (angepasst) in seine Mod einbaut und dein Patch dann die Mod dann kaputt macht.
    3. Du hattest erwähnt, dass deine Savegame Hooks sich nicht mit dem EnforceSavingPolicy Skript vertragen. Falls diese Savegame Hooks Teil deines Patch werden sollen, solltest du diese überarbeiten. Ansonsten wird dein Patch einige Mods kaputt machen, die das EnforceSavingPolicy verwenden.

  10. Beiträge anzeigen #10 Zitieren
    Provinzheld Avatar von Herobrine
    Registriert seit
    Oct 2012
    Ort
    Minental von Khorinis (Gothic)
    Beiträge
    275
     
    Herobrine ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    Ich habe ein bisschen nachgeforscht (hat wieder länger gedauert als ich gedacht hätte). Ähnlich wie beim Visual, ersetze ich die Klasse des Objekts im Speicherstand mit einer anderen (oCMobInter). Das war nicht so einfach, da das Archiving etwas verschachtelt ist und die richtigen Stellen nicht so leicht aufzufinden waren. Auch wird beim Speichern der Klassenbezeichnung deren Prüfsumme mitgespeichert, die beim Laden überprüft wird.

    Der Code unten sollte alles beinhalten (inkl. des Codes für das Visual vom letzten Post). Der Code läuft bereits für G1 und G2 und setzt (außer Ikarus) nichts anderes voraus. Anstatt Fawkes Mob_GetVisualName Funktion, ist im Code eine generelle Variante, die mit allen von zCVob abgeleiteten Klassen funktioniert. (Wegen der Prüfsumme und des Klassennamens ist der Code nicht flexibel für das Tauschen in beliebige Klassen, sondern nur für den Tausch nach oCMobInter.)

    Code:
    /*
     * Get the visual name from any object inheriting from zCVob
     */
    func string OverrideMobDoor_GetVobVisName(var int vobPtr) {
        var zCVob vob; vob = _^(vobPtr); // Caution: No check if valid zCVob
        CALL_RetValIszString();
        CALL__thiscall(vob.visual, MEM_ReadInt(MEM_ReadInt(vob.visual) + /*GetVisualName 0x20*/32));
        return CALL_RetValAszString();
    };
    
    /*
     * Initialization function
     */
    func void OverrideMobDoor_Init() {
        const int zCArchiverGeneric__WriteObject_className_G1  = 5325313; //0x514201
        const int zCArchiverGeneric__WriteObject_className_G2  = 5393841; //0x524DB1
        const int zCArchiverGeneric__WriteObject_archiveObj_G1 = 5325323; //0x51420B
        const int zCArchiverGeneric__WriteObject_archiveObj_G2 = 5393851; //0x524DBB
        const int zCVob__ArchivePacked_visual_G1               = 6109963; //0x5D3B0B
        const int zCVob__ArchivePacked_visual_G2               = 6286598; //0x5FED06
        const int zCVob__ArchivePacked_visualStr_G1            = 6109939; //0x5D3AF3
        const int zCVob__ArchivePacked_visualStr_G2            = 6286574; //0x5FECEE
    
        HookEngineF(MEMINT_SwitchG1G2(zCArchiverGeneric__WriteObject_className_G1,
                                      zCArchiverGeneric__WriteObject_className_G2),  5, OverrideMobDoor_WriteClassName);
        HookEngineF(MEMINT_SwitchG1G2(zCArchiverGeneric__WriteObject_archiveObj_G1,
                                      zCArchiverGeneric__WriteObject_archiveObj_G2), 6, OverrideMobDoor_CallArchiver);
        HookEngineF(MEMINT_SwitchG1G2(zCVob__ArchivePacked_visual_G1,
                                      zCVob__ArchivePacked_visual_G2),               8, OverrideMobDoor_WriteVisual);
        HookEngineF(MEMINT_SwitchG1G2(zCVob__ArchivePacked_visualStr_G1,
                                      zCVob__ArchivePacked_visualStr_G2),            6, OverrideMobDoor_WriteVisName);
    };
    func int OverrideMobDoor_IsNeedle(var int objPtr) {
        if (!Hlp_Is_oCMobDoor(objPtr)) { // Important, because zCArchiverGeneric::WriteObject is called for any zCObject
            return FALSE;
        };
        return Hlp_StrCmp(OverrideMobDoor_GetVobVisName(objPtr), "BAUMSAEGE_1.MDS");
    };
    func void OverrideMobDoor_WriteClassName() {
        if (OverrideMobDoor_IsNeedle(ESI)) {
            MEM_Debug("OverrideMobDoor: Archive as oCMobInter (class name)");
            ECX = STR_toChar("oCMobInter:oCMOB:zCVob"); // Write different class name
            EAX = 35585; // oCMobInter::_GetClassDef()->archiveVersionSum (Same for G1 and G2)
        };
    };
    func void OverrideMobDoor_CallArchiver() {
        if (OverrideMobDoor_IsNeedle(ESI)) {
            MEM_Debug("OverrideMobDoor: Archive as oCMobInter (vtbl)");
            EAX = oCMobInter_vtbl; // Call different archiver (that of oCMobInter)
        };
    };
    func void OverrideMobDoor_WriteVisual() {
        if (OverrideMobDoor_IsNeedle(EBP)) {
            MEM_Debug("OverrideMobDoor: Write different visual");
    
            // Create different visual for game saves - only once and only just now, to be sure it's necessary
            const int dummyVisual = 0;
            if (!dummyVisual) {
                const int zCVisual__LoadVisual_G1 = 6136304; //0x5DA1F0
                const int zCVisual__LoadVisual_G2 = 6318800; //0x606AD0
                CALL_zStringPtrParam("BAUMSAEGE_1.ASC");
                CALL_PutRetValTo(_@(dummyVisual));
                CALL__cdecl(MEMINT_SwitchG1G2(zCVisual__LoadVisual_G1, zCVisual__LoadVisual_G2));
            };
    
            ECX = dummyVisual; // Write different visual
        };
    };
    func void OverrideMobDoor_WriteVisName() {
        if (OverrideMobDoor_IsNeedle(EBP)) {
            MEM_Debug("OverrideMobDoor: Write different visual name");
            ECX = _@s("BAUMSAEGE_1.ASC"); // Write different visual name
        };
    };
    Okay, mit dem Code klappt jetzt alles genauso wie ich es haben wollte. Das Austauschen des Visuals macht keine Probleme mehr. Vielen Dank nochmal dafür, dass du dir den Aufwand gemacht hast, das alles rauszusuchen und auszuprobieren.
    Zitat Zitat von mud-freak Beitrag anzeigen
    Hier noch ein paar Gedanken zu dem Vorhaben, daraus einen Patch zu machen:
    1. Beim Test unter G1 ist mir aufgefallen, dass die BAUMSAEGE_1.ASC in G1 nicht existiert. Damit es beim Spielen dort nicht zu einem Fehler kommt, habe ich die Erstellung des Dummy-Visuals in die entsprechende Hookfunktion verschoben, damit es nur erstellt wird, wenn es gebraucht wird und folglich existiert.
    2. Beachte die Namenskonventionen für alle Symbole (Ninja_[PatchName]_*), wenn du daraus einen Patch machst. Da der Code hier zugänglich ist, könnte es sein das jemand ihn (angepasst) in seine Mod einbaut und dein Patch dann die Mod dann kaputt macht.
    3. Du hattest erwähnt, dass deine Savegame Hooks sich nicht mit dem EnforceSavingPolicy Skript vertragen. Falls diese Savegame Hooks Teil deines Patch werden sollen, solltest du diese überarbeiten. Ansonsten wird dein Patch einige Mods kaputt machen, die das EnforceSavingPolicy verwenden.
    Ich hatte am Ende sowieso vor, erstmal alles aufzuräumen, was ich im Patch nicht mehr benötige und dann an alle Symbole ein Ninja_[PatchName]_ dranzuhängen.
    Die Savegame Hooks sind dann auch nicht mehr notwendig dank deines Codes. Hätte jetzt nur noch eine Frage: Kann man auch die useWithItem-Werte oder die anderen Werte wie sceme, conditionFunc, onStateFunc, etc. im Speicherstand ändern? Hatte noch andere Mobs, wo ich das useWithItem geändert hatte, weiß aber nicht, wie genau ich das jetzt im Savegame noch umändern kann.

  11. Beiträge anzeigen #11 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Herobrine Beitrag anzeigen
    Okay, mit dem Code klappt jetzt alles genauso wie ich es haben wollte. Das Austauschen des Visuals macht keine Probleme mehr. Vielen Dank nochmal dafür, dass du dir den Aufwand gemacht hast, das alles rauszusuchen und auszuprobieren.
    Freut mich, dass das alles gut funktioniert. Du kannst noch einmal herum testen, ob das Austauschen der Klasse auch in Spieler-Installationen (anstatt Modkit Installationen) funktioniert. Denn ich hooke nur den "zCArchiverGeneric". Es gibt aber noch "zCArchiverBinSafe" und ich habe noch nicht herausfinden können was der Unterschied ist.


    Zitat Zitat von Herobrine Beitrag anzeigen
    Ich hatte am Ende sowieso vor, erstmal alles aufzuräumen, was ich im Patch nicht mehr benötige und dann an alle Symbole ein Ninja_[PatchName]_ dranzuhängen.
    Die Savegame Hooks sind dann auch nicht mehr notwendig dank deines Codes.
    Um den Patch noch leichter zu machen und um noch mehr Kompatibilität zu sichern, könntest du das Ersetzen von Visual und Klasse auch so in die andere Richtung umsetzen: Beim Unarchivieren (und/oder Erstellen) eines entsprechenden Mobs hooken, um den Tausch durchführen. Dann würdest du dir die ganzen Skripte sparen und (neben besserer Performance) wird alles etwas stabiler, weil Hin- und Hertauschen auf "symmetrische" Weise getan wird.


    Zitat Zitat von Herobrine Beitrag anzeigen
    Hätte jetzt nur noch eine Frage: Kann man auch die useWithItem-Werte oder die anderen Werte wie sceme, conditionFunc, onStateFunc, etc. im Speicherstand ändern? Hatte noch andere Mobs, wo ich das useWithItem geändert hatte, weiß aber nicht, wie genau ich das jetzt im Savegame noch umändern kann.
    Ja das sollte auf die selbe Weise (aber viel einfacher) machbar sein. Das hatte ich schon einmal ein bisschen gemacht. Schau mal in [deineKlasse]::Archiver. Bzw. es ist besser erst in die virtuellen Methoden Tabelle der entsprechenden Klasse zu schauen, denn nicht alle oCMob*-Klassen haben ihren eigenen Archiver. oCMobDoor wird z.B. glaube ich einfach mit dem Archiver von oCMobLockable in den Spielstand geschrieben.
    In den Archiver-Funktionen werden die relevanten Eigenschaften mit samt ihrem Namen als String (z.B. "useWithItem") in das Speicherobject geschrieben. D.h. über diese Strings sieht man in IDA auf einen Blick, wo in der Funktion die gesuchte Eigenschaft abgespeichert wird, um das Schreiben zu hooken.

  12. Beiträge anzeigen #12 Zitieren
    Provinzheld Avatar von Herobrine
    Registriert seit
    Oct 2012
    Ort
    Minental von Khorinis (Gothic)
    Beiträge
    275
     
    Herobrine ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    Freut mich, dass das alles gut funktioniert. Du kannst noch einmal herum testen, ob das Austauschen der Klasse auch in Spieler-Installationen (anstatt Modkit Installationen) funktioniert. Denn ich hooke nur den "zCArchiverGeneric". Es gibt aber noch "zCArchiverBinSafe" und ich habe noch nicht herausfinden können was der Unterschied ist.
    Habe erst gestern ausprobiert, ob es überhaupt in meiner Modkit-Installation funktioniert. Kann nun bestätigen, dass es sowohl in meiner Modkit-Installation als auch in meiner Spielerinstallation funktioniert. Habe es auch schon mit mehreren Mods ausprobiert. Gab bis jetzt noch keine Probleme.
    Zitat Zitat von mud-freak Beitrag anzeigen
    Um den Patch noch leichter zu machen und um noch mehr Kompatibilität zu sichern, könntest du das Ersetzen von Visual und Klasse auch so in die andere Richtung umsetzen: Beim Unarchivieren (und/oder Erstellen) eines entsprechenden Mobs hooken, um den Tausch durchführen. Dann würdest du dir die ganzen Skripte sparen und (neben besserer Performance) wird alles etwas stabiler, weil Hin- und Hertauschen auf "symmetrische" Weise getan wird.
    Bin leider noch kein Assembler-Experte. Habe versucht mich damit auseinanderzusetzen, bin bis jetzt allerdings noch nicht zu einer Lösung gekommen. Eigentlich sollte es sich bei dem meisten um das gleiche handeln, nur in der Unarchive-Variante, oder? Also statt zCVob::ArchivePacked nun zCVob::UnarchivePacked. Und sollte es bei zCArchiverGeneric statt WriteObject ReadObject sein? Nur das zCVob::Unarchive Visual konnte ich ändern, da die Zeilen fast identisch mit denen aus zCVob::Archive waren, den String allerdings nicht, obwohl ich in IDA - denke ich zumindest - die richtige Adresse (0x5FF3C8) gefunden habe. Das Mob sah im Spiel dann natürlich auch nicht anders aus, im zSpy habe ich allerdings Prints diesbezüglich bekommen. Gibt es auch neben Archive und Unarchive etwas, das beim Spielstart für das Visual bzw. die Eigenschaften der Vobs/Mobs zuständig ist? Unarchive wird anscheinend nicht beim Spielstart ausgeführt.

    Zitat Zitat von mud-freak Beitrag anzeigen
    Ja das sollte auf die selbe Weise (aber viel einfacher) machbar sein. Das hatte ich schon einmal ein bisschen gemacht. Schau mal in [deineKlasse]::Archiver. Bzw. es ist besser erst in die virtuellen Methoden Tabelle der entsprechenden Klasse zu schauen, denn nicht alle oCMob*-Klassen haben ihren eigenen Archiver. oCMobDoor wird z.B. glaube ich einfach mit dem Archiver von oCMobLockable in den Spielstand geschrieben.
    In den Archiver-Funktionen werden die relevanten Eigenschaften mit samt ihrem Namen als String (z.B. "useWithItem") in das Speicherobject geschrieben. D.h. über diese Strings sieht man in IDA auf einen Blick, wo in der Funktion die gesuchte Eigenschaft abgespeichert wird, um das Schreiben zu hooken.
    Ja, hat funktioniert. War auch nicht sehr schwer. Hier ist mein Code, falls jemand auch mal Lust hat, Items während des Speicherns/Ladens auszutauschen:
    Code:
    /* 
     * Get the visual name from any object inheriting from zCVob
     */
    func string OverrideMob_GetVobVisName(var int vobPtr) {
        var zCVob vob; vob = _^(vobPtr); // Caution: No check if valid zCVob
        CALL_RetValIszString();
        CALL__thiscall(vob.visual, MEM_ReadInt(MEM_ReadInt(vob.visual) + /*GetVisualName 0x20*/32));
        return CALL_RetValAszString();
    };
    
    /*
     * Initialize function
     */
    func void OverrideMob_Init() {
    
        const int oCMobInter__Archive_WriteUseWithItem_G1           = 6818186; //0x68098A
        const int oCMobInter__Archive_WriteUseWithItem_G2           = 7480154; //0x72235A
        const int oCMobInter__Unarchive_WriteUseWithItem_G1         = 6818349; //0x680A2D
        const int oCMobInter__Unarchive_WriteUseWithItem_G2         = 7480317; //0x7223FD
    
        HookEngineF(MEMINT_SwitchG1G2(oCMobInter__Archive_WriteUseWithItem_G1,
                                      oCMobInter__Archive_WriteUseWithItem_G2),           6, OverrideMob_Archive_WriteUseWithItem);
        HookEngineF(MEMINT_SwitchG1G2(oCMobInter__Unarchive_WriteUseWithItem_G1,
                                      oCMobInter__Unarchive_WriteUseWithItem_G2),         6, OverrideMob_Unarchive_WriteUseWithItem);
    };
    
    /*
     * Check if oCMobInter is BSANVIL_OC.MSB
     */
    func int OverrideMob_IsBSANVIL_OC(var int objPtr){
        if (!Hlp_Is_oCMobInter (objPtr)){
            return FALSE;
        };
        return Hlp_StrCmp(OverrideMob_GetVobVisName(objPtr), "BSANVIL_OC.MDS");
    };
    
    /*
     * Replace useWithItem while saving 
     */
    func void OverrideMob_Archive_WriteUseWithItem(){
        if (OverrideMob_IsBSANVIL_OC(EDI)){
            MEM_Debug("OverrideMob_Archive: replace useWithItem");
            ECX = _@s("ItMiSwordrawhot"); // Write different useWithItem
        };
    };
    
    /*
     * Replace useWithItem while loading 
     */
    func void OverrideMob_Unarchive_WriteUseWithItem(){
        if (OverrideMob_IsBSANVIL_OC(EDI)){
            MEM_Debug("OverrideMob_Unarchive: replace useWithItem");
            ECX = _@s(""); // Write different useWithItem
        };
    
    };
    Geändert von Herobrine (04.03.2020 um 21:12 Uhr)

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
Impressum | Link Us | intern
World of Gothic © by World of Gothic Team
Gothic, Gothic 2 & Gothic 3 are © by Piranha Bytes & Egmont Interactive & JoWooD Productions AG, all rights reserved worldwide