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

 

Seite 2 von 2 « Erste 12
Ergebnis 21 bis 29 von 29
  1. Beiträge anzeigen #21 Zitieren
    Auserwählte Avatar von Strontzine
    Registriert seit
    May 2017
    Ort
    Yns Avallach
    Beiträge
    6.224
     
    Strontzine ist offline

    Kirides

    z.B. könnte ein neuer Mod-Entwickler sich die *.VDF anschauen und so sehen wie eine eigene Schadensberechnung, Prüfung auf bestimmte Waffen und Gegner aussieht und diese in etwas größeres einbauen.
    Ich handhabe das so wie bei "GameStar". Vor- und Nachteile bedenkend.
    Aber für Mod-Entwickler : Okay!!

    Gruss

  2. Beiträge anzeigen #22 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Kirides Beitrag anzeigen
    Update



    • Patch ist nun eine einzige multilinguale *.VDF (DE, EN, PL, RU)
    • safety check für den Fall das ein Angreifer nicht extiert, oder kein NPC ist (attackerPtr = 0)
    • Mehrere safety-checks für den Fall das eine Mod etwas ändert
    • Prüfung ob "Orks" im spiel existieren (anhand einiger Konstanten)
    Das sieht sehr gut aus. Wenn du magst, habe ich wieder ein paar Anmerkungen.
    • Die polnische Lokalisierung scheint inkorrekt. Überprüfe: Öffne die Datei Localization.d mit Kodierung Windows 1250, dann kommt bei mir "Bro? jednor?czna (+15% obra?e? zadawanych orkom)" raus.

    • Lokalisierung wird nur getan, wenn initialisiert wird. Das ist finde ich sehr gut. Dabei solltest du vielleicht Ninja_BetterOrcSlayer_TextBonusDamage als leeren String initialisieren (und beim Lokalisieren erst die englische Übersetzung einfügen), damit die Beschreibung dort nicht trotz Nicht-Initialisierung steht. Dazu musst du dann natürlich einfach nur einen Else-Block in Ninja_BetterOrcSlayer_GuessLocalization für englisch anlegen.

    • Eine kleine Sache zur Initialisierung: Die ist etwas zu über kompliziert und du kannst sie um einiges vereinfachen. Im Moment wird die Initialisierung zum Damageskript bei jedem Spielstart und -laden und Levelwechsel aufgerufen. Sie wird aber nur einmal benötigt. Ebenso wird auch die Existenz der Orks in der Mod jedes mal neu überprüft, auch wenn du isCompatible schon bestimmt hast. Im Grunde braucht alles nur ein einziges Mal initialisiert werden. Außerdem brauchst du die Menu-Initialisierung nicht wirklich. Ich würde die beiden Initialisierungsfunktionen reduzieren zu einer.
      Code:
      func void Ninja_BetterOrcSlayer_Init() {
          const int once = 0;
          if (!once) { // Only once per entire session
              MEM_InitAll();
              if (Ninja_BetterOrcSlayer_ShouldInit()) { // Only initialize if Orcs are detected
                  // Initialize custom Damage
                  Ninja_BetterOrcSlayer_LocalizeTexts();
                  Ninja_BetterOrcSlayer_InitDamage();
      
                  MEM_Info("BetterOrcSlayer initialized");
              };
              once = 1;
          };
      };

    • Eine kleine Anmerkung zu Daedalus: Verknüpfte (&& oder ||) If-Abfragen werden alle ausgewertet (übrigens von hinten nach vorne, aber hier ist wichtig: alle), so dass Konstrukte wie
      Code:
      if(!attackerptr || !Hlp_Is_oCNpc(attackerptr))
      äquivalent ist zu
      Code:
      var int a; a = !attackerptr;
      var int b; b = !Hlp_Is_oCNpc(attackerptr)
      
      if (a || b)
      Hier ist das nicht weiter gefährlich, aber in folgendem Ansatz wird Ninja_BetterOrcSlayer_IsGuildOrc mit null aufgerufen, trotz dem victimNpc.guild null ist.
      Code:
      if (!victimNpc.guild || !Ninja_BetterOrcSlayer_IsGuildOrc(victimNpc.guild))
      Um If-Abfragen in Daedalus sequentiell abzuarbeiten, führt kein Weg herum um
      Code:
      // Only if guild is valid / Enemy is an Orc
      if (victimNpc.guild) {
          if (Ninja_BetterOrcSlayer_IsGuildOrc(victimNpc.guild)) {
              dmg = (dmg * 115) / 100; // 15% Bonus dmg
          };
      };
      
      return dmg;

      Zum vorherigen Beispiel: Weil der Pointer auch innerhalb von Hlp_Is_oCNpc gegen null abgeglichen wird, kannst du die Abfrage hier einfach reduzieren zu
      Code:
      if (!Hlp_Is_oCNpc(attackerptr))



    PS:Na wo kommen denn die Flaggen her? ;)
    Geändert von mud-freak (16.12.2019 um 19:33 Uhr)

  3. Beiträge anzeigen #23 Zitieren
    Ritter Avatar von Kirides
    Registriert seit
    Jul 2009
    Ort
    Norddeutschland
    Beiträge
    1.780
     
    Kirides ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    Das sieht sehr gut aus. Wenn du magst, habe ich wieder ein paar Anmerkungen.
    Die polnische Lokalisierung scheint inkorrekt. Überprüfe: Öffne die Datei Localization.d mit Kodierung ISO 8859-16, dann kommt bei mir "Bro? jednor?czna (+15% obra?e? zadawanych orkom)" raus.
    Prüfe ich nochmal

    Zitat Zitat von mud-freak Beitrag anzeigen
    Lokalisierung wird nur getan, wenn initialisiert wird. Das ist finde ich sehr gut. Dabei solltest du vielleicht Ninja_BetterOrcSlayer_TextBonusDamage als leeren String initialisieren (und beim Lokalisieren erst die englische Übersetzung einfügen), damit die Beschreibung dort nicht trotz Nicht-Initialisierung steht. Dazu musst du dann natürlich einfach nur einen Else-Block in Ninja_BetterOrcSlayer_GuessLocalization für englisch anlegen.


    Eine kleine Sache zur Initialisierung: Die ist etwas zu über kompliziert und du kannst sie um einiges vereinfachen. Im Moment wird die Initialisierung zum Damageskript bei jedem Spielstart und -laden und Levelwechsel aufgerufen. Sie wird aber nur einmal benötigt. Ebenso wird auch die Existenz der Orks in der Mod jedes mal neu überprüft, auch wenn du isCompatible schon bestimmt hast. Im Grunde braucht alles nur ein einziges Mal initialisiert werden. Außerdem brauchst du die Menu-Initialisierung nicht wirklich. Ich würde die beiden Initialisierungsfunktionen reduzieren zu einer.
    Code:
    func void Ninja_BetterOrcSlayer_Init() {
        const int once = 0;
        if (!once) { // Only once per entire session
            MEM_InitAll();
            if (Ninja_BetterOrcSlayer_ShouldInit()) { // Only initialize if Orcs are detected
                // Initialize custom Damage
                Ninja_BetterOrcSlayer_LocalizeTexts();
                Ninja_BetterOrcSlayer_InitDamage();
    
                MEM_Info("BetterOrcSlayer initialized");
            };
            once = 1;
        };
    };
    Mist habe das englisch vergessen beim umbauen.
    Ich könnte schwören, dass die Lokalisierung nicht geklappt hat, wenn ich diese in die Patch_Name_Init() gepackt habe (hat immer den standard "Englisch" genommen) - prüfe ich nochmal gegen.


    ja - klar, im nachhinein macht es sinn, ein Hook wird ja nicht einfach so entfernt (zumindest sollte man das denken).


    Zitat Zitat von mud-freak Beitrag anzeigen
    Eine kleine Anmerkung zu Daedalus: Verknüpfte (&& oder ||) If-Abfragen werden alle ausgewertet (übrigens von hinten nach vorne, aber hier ist wichtig: alle), so dass Konstrukte wie
    Code:
    if(!attackerptr || !Hlp_Is_oCNpc(attackerptr))
    äquivalent ist zu
    Code:
    var int a; a = !attackerptr;
    var int b; b = !Hlp_Is_oCNpc(attackerptr)
    
    if (a || b)
    Oh man ...

    Zitat Zitat von mud-freak Beitrag anzeigen
    [...]
    Hier ist das nicht weiter gefährlich, aber in folgendem Ansatz wird Ninja_BetterOrcSlayer_IsGuildOrc mit null aufgerufen, trotz dem victimNpc.guild null ist.
    Code:
    if (!victimNpc.guild || !Ninja_BetterOrcSlayer_IsGuildOrc(victimNpc.guild))
    Um If-Abfragen in Daedalus sequentiell abzuarbeiten, führt kein Weg herum um
    Code:
    // Only if guild isvalid / Enemy is an Orc
    if (victimNpc.guild) {
        if (Ninja_BetterOrcSlayer_IsGuildOrc(victimNpc.guild)) {
            dmg = (dmg * 115) / 100; // 15% Bonus dmg
        };
    };
    
    return dmg;
    doch (bin einer der chaoten die versuchen in den lesefluss möglichst wenig branching einzubauen)
    Ja - sollte praktisch das gleiche sein, nur umgekehrt - außer Daedalus macht hier auch komische sachen...

    Code:
    // no guild / guild is invalid
    if (!victimNpc.guild) { return dmg; };
    // Enemy is not an Orc
    if (!Ninja_BetterOrcSlayer_IsGuildOrc(victimNpc.guild)) { return dmg; };
    
    // If we're here, we are the player who uses the OrcSlayer against an orc
    dmg = (dmg * 115) / 100; // 15% Bonus dmg
    return dmg;
    Zitat Zitat von mud-freak Beitrag anzeigen
    Zum vorherigen Beispiel: Weil der Pointer auch innerhalb von Hlp_Is_oCNpc gegen null abgeglichen wird, kannst du die Abfrage hier einfach reduzieren zu
    Code:
    if (!Hlp_Is_oCNpc(attackerptr))
    Da durchforste ich jede LeGo View-Methode aber schaue nicht einmal in die Hlp_Is_oCNpc

    Zitat Zitat von mud-freak Beitrag anzeigen
    PS:Na wo kommen denn die Flaggen her?
    ... aus dem internet :duh: - genauer aus den posts vom lieben @mud-freak

  4. Beiträge anzeigen #24 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Kirides Beitrag anzeigen
    Ich könnte schwören, dass die Lokalisierung nicht geklappt hat, wenn ich diese in die Patch_Name_Init() gepackt habe
    Das kann ich gerade nicht versprechen. Es kann gut sein, dass das Ersetzen der Stringkonstanten in Instanzen vor dem Erstellen der Items passieren muss (sehr wahrscheinlich). Ich hatte das alles mal im Rahmen des FirstMageKit ausprobiert, die ganzen Patches habe ich ca. vor einem Jahr erstellt (auch wenn sie jetzt erst veröffentlicht wurden).

    Wenn es nicht über die Content-Init-Funktion funktioniert, kannst du den gesamten Code aus meinem Post stattdessen in den Menü-Init-Funktion stecken und die Content-Init-Funktion dann weg lassen.



    PS:
    Zitat Zitat von Kirides Beitrag anzeigen
    Ja - sollte praktisch das gleiche sein, nur umgekehrt - außer Daedalus macht hier auch komische sachen...
    Ja, ich hatte mich mal beim Erstellen von GFA sehr auf Performance (Mikro-Optimierungen) fokussiert. Meine Lösung wäre minimal schneller.


    Zitat Zitat von Kirides Beitrag anzeigen
    (flaggen geklaut von unserem lieben @mud-freak ;) )
    Hahah, die Bemerkung kannst du gern auch wieder rausnehmen :D
    Geändert von mud-freak (29.11.2019 um 08:45 Uhr)

  5. Beiträge anzeigen #25 Zitieren
    Ritter Avatar von Kirides
    Registriert seit
    Jul 2009
    Ort
    Norddeutschland
    Beiträge
    1.780
     
    Kirides ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    Das kann ich gerade nicht versprechen. Es kann gut sein, dass das Ersetzen der Stringkonstanten in Instanzen vor dem Erstellen der Items passieren muss (sehr wahrscheinlich). Ich hatte das alles mal im Rahmen des FirstMageKit ausprobiert, die ganzen Patches habe ich ca. vor einem Jahr erstellt (auch wenn sie jetzt erst veröffentlicht wurden).

    Wenn es nicht über die Content-Init-Funktion funktioniert, kannst du den gesamten Code aus meinem Post stattdessen in den Menü-Init-Funktion stecken und die Content-Init-Funktion dann weg lassen.
    Zitat Zitat von mir aus der Vergangenheit
    Daran habe ich auch gedacht, aber als ich im zSpy die ganzen Ninja_PATCH_Menu - Aufrufe gesehen habe, habe ich das doch im Ninja_PATCH_Init gelassen.
    dödel - das sollte keinen unterschied machen, weil die aufrufe ja eh passieren und praktisch ein noop sind durch die abfrage des "once". Sondern eher besser sein, weil der Init dann gar nicht existiert und nicht aufgerufen werden muss.


    Zitat Zitat von mud-freak Beitrag anzeigen
    PS:

    Ja, ich hatte mich mal beim Erstellen von GFA sehr auf Performance (Mikro-Optimierungen) fokussiert. Meine Lösung wäre minimal schneller.
    Sind das wirklich so viel mehr cmp und jmp zwischen den beiden ?
    Hmm, wobei, es wird, denke ich mal, für jeden return ein neues label angelegt, welches den funktionsaufruf vergrößert, was sich wiederum schlechter auf den CPU Cache auswirken lassen kann.
    Ich gehe hierbei davon aus, dass die daedalus engine nicht "intelligent" ist und nicht merkt, dass sich der wert der Variable "dmg" während der ganzen abragen nicht ändert.


    Zitat Zitat von mud-freak Beitrag anzeigen
    Hahah, die Bemerkung kannst du gern auch wieder rausnehmen
    Ach wo, ich find's gut
    Geändert von Kirides (29.11.2019 um 10:18 Uhr)

  6. Beiträge anzeigen #26 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Kirides Beitrag anzeigen
    das sollte keinen unterschied machen, weil die aufrufe ja eh passieren und praktisch ein noop sind durch die abfrage des "once". Sondern eher besser sein, weil der Init dann gar nicht existiert und nicht aufgerufen werden muss.
    Achtung, Daedalus ist eine interpretierte und keine kompilierte Sprache. Daedalus liegt Gothic nicht als Compiler-Instruktionen, sondern als Bytecode vor. Das ist also nicht einfach eine noop-Instruktion. Bis eine Daedalus-Funktion aus der Engine überhaupt aufgerufen wird (wie hier der Fall), werden einige Instruktionen durchlaufen. Wichtig ist aber, dass das überhaupt nicht ausschlaggebend ist!

    Wenn also die Lokalisierung wirklich in beiden Init-Funktionen funktioniert, empfehle ich lieber die Content-Init-Funktion zu nutzen. Die wird weit-aus seltener aufgerufen und ist auch für etwaige Interessierte im Quelltext nicht so verwirrend. Schließlich stellt dein Patch nichts am Menü an.


    Zitat Zitat von Kirides Beitrag anzeigen
    Sind das wirklich so viel mehr cmp und jmp zwischen den beiden ?
    Hmm, wobei, es wird, denke ich mal, für jeden return ein neues label angelegt, welches den funktionsaufruf vergrößert, was sich wiederum schlechter auf den CPU Cache auswirken lassen kann.
    Ich gehe hierbei davon aus, dass die daedalus engine nicht "intelligent" ist und nicht merkt, dass sich der wert der Variable "dmg" während der ganzen abragen nicht ändert.
    Da ist um einiges mehr als ein paar Compiler-Instruktionen zwischen. Daedalus läuft in einer VM, sodass der einzelne Daedalus-Befehle (bzw. deren Bytecode) zur Laufzeit interpretiert werden. Deshalb ist Daedalus auch so "langsam" (was in dem Skriptingkontext nicht weiter auffällt oder schlimm ist). Optimierungen gibt es also auch keine, der Code wird ausgeführt wie er geschrieben wurde.


    Wie auch immer, ist das alles nicht wichtig. Das macht keinen Unterschied. Das war nur so eine Bemerkung am Rand bzgl. meiner Mikro-Optimierungen. In GFA war das notwendig, weil ich an kritischen Adressen Daedaluscode hab ausführen lassen. Da sollten wir nicht weiter drüber reden; Je weiter man sich darin verbeißt, desto unleserlicher wird der Code. Von daher ist es gut, dass du bei deiner Variante bleiben willst.

  7. Beiträge anzeigen #27 Zitieren
    Ritter Avatar von Kirides
    Registriert seit
    Jul 2009
    Ort
    Norddeutschland
    Beiträge
    1.780
     
    Kirides ist offline
    Zitat Zitat von mud-freak Beitrag anzeigen
    Achtung, Daedalus ist eine interpretierte und keine kompilierte Sprache. Daedalus liegt Gothic nicht als Compiler-Instruktionen, sondern als Bytecode vor. Das ist also nicht einfach eine noop-Instruktion. Bis eine Daedalus-Funktion aus der Engine überhaupt aufgerufen wird (wie hier der Fall), werden einige Instruktionen durchlaufen. Wichtig ist aber, dass das überhaupt nicht ausschlaggebend ist!

    Wenn also die Lokalisierung wirklich in beiden Init-Funktionen funktioniert, empfehle ich lieber die Content-Init-Funktion zu nutzen. Die wird weit-aus seltener aufgerufen und ist auch für etwaige Interessierte im Quelltext nicht so verwirrend. Schließlich stellt dein Patch nichts am Menü an.
    Natürlich ist es nie ein richtiger "noop" aber ein Laufzeitinterpreter sollte doch in der lage zu sein eine expression auszuwerten und einen betroffenen Block nicht weiter zu interpretieren sondern lediglich die Tokens durchgehen bis der betroffene Block vorbei ist.

    Ich würde von einem Laufzeitinterpreter mindestens folgendes erwarten

    Grün: wird als daedalus sprache interpretiert und ausgewertet. (performance einbuße regulär)
    Rot: wird lediglich als start/end-token der betroffenen expression gewertet (performance einbuße für merken des starts und mitzählen bis das end-token erreicht wurde)
    Grau: wird wie ein kommentar behandelt / nicht als code interpretiert und ausgewertet. (performance einbuße minimal)
    Code:
    done = TRUE;
    if (!done) {
    
    done = TRUE;
    
    };
    Zitat Zitat von mud-freak Beitrag anzeigen
    Da ist um einiges mehr als ein paar Compiler-Instruktionen zwischen. Daedalus läuft in einer VM, sodass der einzelne Daedalus-Befehle (bzw. deren Bytecode) zur Laufzeit interpretiert werden. Deshalb ist Daedalus auch so "langsam" (was in dem Skriptingkontext nicht weiter auffällt oder schlimm ist). Optimierungen gibt es also auch keine, der Code wird ausgeführt wie er geschrieben wurde.


    Wie auch immer, ist das alles nicht wichtig. Das macht keinen Unterschied. Das war nur so eine Bemerkung am Rand bzgl. meiner Mikro-Optimierungen. In GFA war das notwendig, weil ich an kritischen Adressen Daedaluscode hab ausführen lassen. Da sollten wir nicht weiter drüber reden; Je weiter man sich darin verbeißt, desto unleserlicher wird der Code. Von daher ist es gut, dass du bei deiner Variante bleiben willst.
    ich verstehe das Daedalus durch das interpretieren des bytecode langsamer wird (mehr bytes = mehr interpretationsdauer)

    Aber bevor man jetzt zu tief in die details geht - wie du bereits sagst - fürs Scripten ist egal, außer man hookt sich in lebenswichtige Engine Funktionen und zwingt die Engine von hochperformantem kompiliertem code auf daedalus zurückzuspringen.

  8. Beiträge anzeigen #28 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Zitat Zitat von Kirides Beitrag anzeigen
    Natürlich ist es nie ein richtiger "noop" aber ein Laufzeitinterpreter sollte doch in der lage zu sein eine expression auszuwerten und einen betroffenen Block nicht weiter zu interpretieren sondern lediglich die Tokens durchgehen bis der betroffene Block vorbei ist.

    Ich würde von einem Laufzeitinterpreter mindestens folgendes erwarten

    Grün: wird als daedalus sprache interpretiert und ausgewertet. (performance einbuße regulär)
    Rot: wird lediglich als start/end-token der betroffenen expression gewertet (performance einbuße für merken des starts und mitzählen bis das end-token erreicht wurde)
    Grau: wird wie ein kommentar behandelt / nicht als code interpretiert und ausgewertet. (performance einbuße minimal)
    Code:
    done = TRUE;
    if (!done) {
    
    done = TRUE;
    
    };
    Gothic wertet einfach nur Tokens aus (mit Hilfe eines Datenstacks) und springt bei If-Abfragen und Funktionsaufrufen im Codestack. Falls dich das mehr interessiert, kann ich diesen Post empfehlen. Sektenspinner hat da mal eine kompakte Erklärung zu geschrieben.

  9. Beiträge anzeigen #29 Zitieren
    Ehrengarde Avatar von mud-freak
    Registriert seit
    Dec 2005
    Beiträge
    2.199
     
    mud-freak ist offline
    Ich habe einen Fehler bei einem Verbesserungsvorschlag gemacht. Die If-Abfrage in deiner Funktion Ninja_BetterOrcSlayer_GetSymbolValue sollte so aussehen:
    Code:
    if (MEM_FindParserSymbol(symbolName) != -1)
    Das solltest du zusammen mit den ausstehenden Änderungen noch unbedingt einbauen, ansonsten ist diese Abfrage ineffektiv.

Seite 2 von 2 « Erste 12

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