Code Ausführung ist durcheinader bei Superscalar CPU



  • @D_Key sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    Wenn ich nun eine Combo ausführe (komischerweise passiert das nur bei einer Kombo, dann kommt diese Ausgabe mehrfach und beim Raspberry nur ein mal.

    Das klingt ja nach einem Timing Problem.

    Wie reagiert deine Software wenn du z.B. ein kleines Delay an gewissen Stellen (z.B. bei deinem std::cout << "gameObjectPtr address: "...) einbaust?

    Also z.B. folgendes:

    std::cout << "gameObjectPtr address: " << gameObjectPtr << " this address: " << this << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
    


  • BTW:

    Und seie bitte vorsichtig mit der Verwendung von Pointern, da diese gerne Ärger machen. Ein Beispiel:

    std::vector<int> L{1, 2, 3};
    
    int* P = L[0];
    for (int i = -5; i < 5; i++)
      L.push_back(i);
    std::cout << *P;
    


  • @Quiche-Lorraine sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    Das klingt ja nach einem Timing Problem.

    Das habe ich mir auch schon gedacht, aber ich Blicks nicht was hier passiert. Wenn man gdb nutzen könnte, könnte man mit dem Debugger den Code schrittweise durchgehen.

    Ich habe mal in TU_update eine Ausgabe hinzugefügt auf dem PC als auch auf der PS2:

    void LivingObject::TU_update() // update done at every TU (30fps)
    {
        if(effect->stuck){
                std::cout << "effect->timein: " << signed(effect->timein) << " ptr: " << this << std::endl;
        }
        if (state_update(-6) <= 0)
        {
            frame_force();
        }
        if(effect->timein < 0)
        {
            if(effect->oscillate)
            {
                if(effect->oi == 1)
                {
                    effect->oi = -1;
                }
                else
                {
                    effect->oi = 1;
                }
                enginePtr->set_x_y(uID, engineID, metric->sx + effect->oscillate* effect->oi,metric->sy + metric->sz);
            }
            else if(effect->blink)
            {
                if(effect->bi < 0)
                {
                    effect->bi = 0;
                }
                uint8_t mod = effect->bi%4;
                if(mod == 0 || mod == 1)
                {
                    enginePtr->show_hide(engineID, false);
                }
                else if(mod == 2 || mod == 3)
                {
                    enginePtr->show_hide(engineID, true);
                }
                effect->bi++;
            }
            if(effect->timeout == 0)
            {
                effect->num = -99;
                if(effect->stuck)
                {
                    effect->stuck = false;
                }
                if(effect->oscillate)
                {
                    effect->oscillate = 0;
                    enginePtr->set_x_y(uID, engineID, metric->sx, metric->sy + metric->sz);
                }
                if(effect->blink)
                {
                    effect->blink = false;
                    effect->bi = 0;
                    //todo SHOW()
                }
                if(effect->super)
                {
                    effect->super = false;
                }
            }
            else if(effect->timeout == -1)
            {
                if(effect->dvx)
                {
                    metric->vx = effect->dvx;
                }
                if(effect->dvy != 0)
                {
                    metric->vy = effect->dvy;
                }
                effect->dvx = 0;
                effect->dvy = 0;
            }
            effect->timeout--;
        }
        if(effect->timein < 0 && effect->stuck)
        {
            //struck
        }
        else
        {
            std::cout << "aufgerufen wurde: " << this << std::endl;
            state_update(-5);
        }
        if(health->hp <=0)
        {
            //todo health
        }
    
        if(_itr->arest > 0)
        {
            _itr->arest--;
        }
    }
    

    Der PC Spuckt aus:

    aufruf von: 0x5555561f0470
    aufruf von: 0x5555561f0588
    aufgerufen wurde: 0x5555561f0470
    aufgerufen wurde: 0x5555561f0588
    aufruf von: 0x5555561f0470
    aufruf von: 0x5555561f0588
    aufgerufen wurde: 0x5555561f0470
    gameObjectPtr:0x5555561f0588 thisPtr: 0x5555561f0470
    effect->timein: 0 ptr: 0x5555561f0588
    aufgerufen wurde: 0x5555561f0588
    aufruf von: 0x5555561f0470
    aufruf von: 0x5555561f0588
    aufgerufen wurde: 0x5555561f0470
    effect->timein: -1 ptr: 0x5555561f0588
    aufruf von: 0x5555561f0470
    aufruf von: 0x5555561f0588
    aufgerufen wurde: 0x5555561f0470
    effect->timein: -2 ptr: 0x5555561f0588
    aufruf von: 0x5555561f0470
    aufruf von: 0x5555561f0588
    aufgerufen wurde: 0x5555561f0470
    effect->timein: -3 ptr: 0x5555561f0588
    aufgerufen wurde: 0x5555561f0588
    aufruf von: 0x5555561f0470
    aufruf von: 0x5555561f0588
    aufgerufen wurde: 0x5555561f0470
    aufgerufen wurde: 0x5555561f0588
    aufruf von: 0x5555561f0470
    aufruf von: 0x5555561f0588
    aufgerufen wurde: 0x5555561f0470
    aufgerufen wurde: 0x5555561f0588
    aufruf von: 0x5555561f0470
    aufruf von: 0x5555561f0588
    aufgerufen wurde: 0x5555561f0470
    aufgerufen wurde: 0x5555561f0588
    

    Hier fand der Angriff statt gameObjectPtr:0x5555561f0588 thisPtr: 0x5555561f0470

    Bei der Playstation Sieht man schon, da ist wirr-war:

    aufgerufen wurde: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    aufruf von: 0x317200
    aufgerufen wurde: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    aufruf von: 0x317200
    aufgerufen wurde: 0x317200
    gameObjectPtr address: 0x317530 this address: 0x317200
    aufruf von: 0x317530
    effect.timein: 0 ptr: 0x317530
    aufgerufen wurde: 0x317530
    aufruf von: 0x317200
    aufgerufen wurde: 0x317200
    aufruf von: 0x317530
    effect.timein: -1 ptr: 0x317530
    aufruf von: 0x317200
    aufgerufen wurde: 0x317200
    aufruf von: 0x317530
    effect.timein: -2 ptr: 0x317530
    aufruf von: 0x317200
    aufgerufen wurde: 0x317200
    aufruf von: 0x317530
    effect.timein: -3 ptr: 0x317530
    aufgerufen wurde: 0x317530
    aufruf von: 0x317200
    aufgerufen wurde: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    aufruf von: 0x317200
    aufgerufen wurde: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    aufruf von: 0x317200
    aufgerufen wurde: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    gameObjectPtr address: 0x317200 this address: 0x317530
    aufruf von: 0x317200
    effect.timein: -1 ptr: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    gameObjectPtr address: 0x317200 this address: 0x317530
    aufruf von: 0x317200
    effect.timein: -2 ptr: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    gameObjectPtr address: 0x317200 this address: 0x317530
    aufruf von: 0x317200
    effect.timein: -3 ptr: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    aufruf von: 0x317200
    effect.timein: -4 ptr: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    aufruf von: 0x317200
    effect.timein: -5 ptr: 0x317200
    aufgerufen wurde: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    gameObjectPtr address: 0x317200 this address: 0x317530
    aufruf von: 0x317200
    effect.timein: -1 ptr: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    gameObjectPtr address: 0x317200 this address: 0x317530
    aufruf von: 0x317200
    effect.timein: -2 ptr: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    gameObjectPtr address: 0x317200 this address: 0x317530
    aufruf von: 0x317200
    effect.timein: -3 ptr: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    aufruf von: 0x317200
    effect.timein: -4 ptr: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    aufruf von: 0x317200
    effect.timein: -5 ptr: 0x317200
    aufgerufen wurde: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    aufruf von: 0x317200
    aufgerufen wurde: 0x317200
    aufruf von: 0x317530
    aufgerufen wurde: 0x317530
    

    Beim PC kommt immer zwei mal
    aufruf von: 0x5555561dce00
    aufruf von: 0x5555561dcf18

    Das Macht die Playstation nie.
    Von der Sache her ruft ja TU_update -> Query auf, wenn query läuft pausiert TU update, bzw die schleife die TU_update aufruft.
    Es macht aber den Eindruck alls wenn emit_event noch zu ende läuft, während query läuft. Wie zwei Thread's.
    Was mir auch noch anfällt, Ausgabe beim PC

    @wob sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    Du kannst auch die STL bemühen:
    bool excluded = std::find(exclude.begin(), exclude.end(), go.get()) != exclude.end();

    Es gibt immer 100 Wege die nach Rom führen

    @wob sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    Was ist denn das charakterControllerObject bei dir? Ein festes Array? Ich sehe nur diese 2 Zeilen:
    Das ist ein statisches Array, da landen die Charaktere drinnen, die von einen Menschen gesteuert werden.
    Da man auf der Playstation mehrere Controller anschließen kann.

    Das array ist nur ein Überbleibsel aus meiner verzweifelten such nach dem Bug.
    Da der Fehler erst nach beim Ausführen ein Kombo auf tritt hatte ich ein Problem mit der Controller Klasse vermutet
    Das ist bei der Playstation 2 ,maximal beschissen, denn jede Taste ist eine Anlog Taste, auch X und Viereck.
    Man muss erst mal zwischenspeichern wie weit runter eine Taste gedrückt ist um dann im nächsten Schritt zu erkennen, der Wert hat zu verkleinert ....Taste nicht mehr gedrückt.
    Man hat keine Festen Interrupts wie bei einer Tastatur.

    Ich könnte genau so gut in der emit_event Funktion schauen ob in gameobjekt ein ChildController Pointer ist, wenn ja kann ich auch fetch aufrufen.
    Das spart auch eine schleife😃



  • Was mich wundert, warum gibt die Playstation mehrfach diese Ausgabe aus:

    @D_Key sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    if(!_itr->arest)
    {
    std::cout << "gameObjectPtr address: " << gameObjectPtr << " this address: " << this << std::endl;

    Klar, weil post_interaction schon von falschen Instanz aufgerufen wurde, da ist arest 0
    Aber hier, ist was nicht in Ordung, dass muss ich mal abklären:
    const uint8_t ITR_Len = thisFrame.D->numOfItr;
    for(uint8_t i=0; i<ITR_Len; i++)

    Itr ist bei dem Zweienten Charakter immer 0, weil der macht ja nix und steht nur rum.

    Esseiden, beim aufrufen der hit Funktion überschrieb ich die Adresse der Instanz, Übertrieben gesagt this=... .
    Ich rufe ja hier hit auf: gameObjectPtr->hit_impl(itr, this, &vol))
    hit ist eine Methode von Charakter, daher die virtuelle Funktion:
    In Charakter.h habe ich

    float hit_impl(const Itr *itr, Charakter *thisChar, const Volume *vol) override
        {
            return hit(itr, thisChar, vol);
        }
    

    Wenn ich return hit(itr, this, vol); schreibe, haue ich mich direkt selbst, nicht erst bei einer Combo.
    Wahrscheinlich doch ein vTable Problem oder der Compiler kann mit this nicht umgehen.
    Wer Spaß hat, kann sich noch durch die hit Funktion hangeln, aber das Problem muss schon beiaufrufen, bzw vor dem aufrufen passieren.

    float Charakter::hit(const Itr *itr, Charakter *att,const Volume *vol)
    {
        Charakter *that = this;
        util utility;
        if(!that->itr_vrest_test(att->engineID))
        {
            return false;
        }
        bool accepthit = false;
        bool defended = false;
        float ef_dvx = 0;
        ef_dvy = 0;
        float inj = 0;
    
        auto falldown = [&](){
              if(itr->dvy == 0)
            {
                ef_dvy = GC._default.fall.dvy;
            }
            that->health.fall = 0;
            that->bdyBox.vy = 0;
            const bool _front = (att->bdyBox.x > that->bdyBox.x) == (that->bdyBox.dir == '>');
            if((itr->dvx != 0 && itr->bdefend >= 0) && (_front && itr->dvx < 0 && itr->bdefend >= 60))
            {
                that->setFrame(186,21);
            }
            else if(_front)
            {
                that->setFrame(180,21);
            }
            else if(!_front)
            {
                that->setFrame(186,21);
            }
        };//lambda fall down
    
        auto fall = [&](){
               if(itr->fall != 0)
            {
                health.fall += itr->fall;
            }else{
                health.fall += GC._default.fall.value;
            }
            const uint16_t _fall = health.fall;
            if(that->getState() == 13)
            {
                falldown();
            }
            else if(that->bdyBox.y < 0 || that->bdyBox.vy < 0)
            {
                falldown();
            }
            else if(that->health.hp - inj <= 0)
            {
               falldown();
            }
            else if(_fall > 0 && _fall <= 20)
            {
                that->setFrame(220,20);
            }
            else if(_fall > 20 && _fall <=30)
            {
                that->setFrame(222,20);
            }
            else if(_fall > 30 && _fall <= 40)
            {
                that->setFrame(224,20);
            }
            else if(_fall > 40 && _fall <= 60)
            {
                that->setFrame(226,20);
            }
            else if(GC.fall.KO < _fall)
            {
                falldown();
            }
        };// lambda Fall
    
    
        if(that->getState() == 10) //beeing caught
        {
            if(that->catching && that->catching->_char->caught_cpointhurtable())
            {
                accepthit = true;
                fall();
            }
            if(catching && catching->_char->caught_cpointhurtable() == 0 && catching->_char->engineID != att->engineID)
            {
                // I am unhurtable as defined by catcher,
                // and I am hit by attacker other than catcher
            }
            else
            {
                accepthit = true;
                inj += abs(itr->injury);
                if(itr->injury > 0)
                {
                    that->effect_create(0, GC.effect.duration);
                    int16_t tar;
                    if(itr->vaction != 0)
                    {
                        tar = itr->vaction;
                    }
                    else
                    {
                        tar = (att->bdyBox.x > that->bdyBox.x) == (that->bdyBox.dir == '>') ? that->thisFrame.D->cpoint.fronthurtact : that->thisFrame.D->cpoint.backhurtact;
                    }
                    that->setFrame(tar, 20);
                }
            }
        }
        else if(that->getState() == 14)
        {
            //lying
        }
        else if(that->getState() == 19 && att->getState() == 3000)
        {
            //firerun
            return false;
        }
        else if(itr->kind < 0 || itr->kind == 0 || itr->kind == 4 || itr->kind == 9)  //normal, falling, reflectif shiled
        {
            accepthit = true;
            const bool compen = bdyBox.y == 0 ? 1 : 0;
            const int8_t attdir = att->bdyBox.vx == 0 ? att->dirh() : (att->bdyBox.vx > 0 ? 1 : -1);
            if(itr->dvx != 0)
            {
                ef_dvx =  attdir * (itr->dvx - compen);
            }
            else
            {
                ef_dvx = 0;
            }
            if(itr->dvy != 0)
            {
                ef_dvy = itr->dvy;
            }
            else
            {
                ef_dvy = 0;
            }
            const uint8_t effectnum = itr->effect >= 0 ? itr->effect : GC._default.effect.num;
            if(that->getState() == 13 && effectnum == 30) // frozen characters are immune to effect 30 'weak ice'
            {
                return false;
            }
            if((that->getState() == 18 || that->getState() == 19) && (effectnum == 20 || effectnum == 21)) //burning and firerun characters are immune to effect 20/21 'weak fire'
            {
                return false;
            }
            if(that->getState() == 7 && (att->bdyBox.x > bdyBox.x) == (bdyBox.dir == '>')) // defend ; // attacked in front
            {
                if(itr->injury != 0)
                {
                    inj += GC.defend.injury.factor * itr->injury;
                }
                if(itr->bdefend >= 0)
                {
                    health.bdefend += itr->bdefend;
                }
                if(that->health.bdefend > GC.defend.break_limit)
                {
                    that->setFrame(112,20);
                }
                else
                {
                    that->setFrame(110,20);
                }
                if(ef_dvx)
                {
                    ef_dvx += (ef_dvx > 0 ? -1 : 1) * utility.lookup_abs(GC.defend.absorb, ef_dvx);
                }
                ef_dvy = 0;
                if(that->health.hp - inj <= 0)
                {
                    falldown();
                }
                else
                {
                    defended = true;
                }
            }
            else  //end defend
            {
                //TODO hold obj
                if(itr->injury != 0)
                {
                    inj += itr->injury;
                }
                health.bdefend = 45;
                fall();
            }
            uint8_t vanish = GC.effect.duration - 1;
            switch(getNext())
            {
            case 111:
            {
                vanish = 3;
                break;
            }
            case 112:
            {
                vanish = 4;
                break;
            }
            }
            that->effect_create(effectnum, vanish, ef_dvx, ef_dvy);
            //TODO Posteffec
        }//TODO itr-kind 15 & itr.kind 16
    
    
        if(accepthit)
        {
            that->_itr->attacker = att;
        }
        that->injury(inj);
        if(accepthit)
        {
            return inj;
        }
        else
        {
            return 0;
        }
    }
    

    Das Problem ist ja, das sich beide Chakrakter KO hauen aber nur bei ienr Kombo.
    Das beduet das der Zeiger in der vTabel zum zeitunkt x noch falsch ist.
    Sehe ich das richtg?



  • @D_Key sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    Wenn ich return hit(itr, this, vol); schreibe

    Ich habe das noch mal gecheckt return hit(itr, this, vol); geht auch und macht genau das selbe Problem.
    Bei einer Combo treffe ich mich selbst.

    Es gibt ja bei der Playstation einige Restriktionen die zu beachten sind. Was mir im klassischen C(fast alles auf der Ps2 ist in c geschrieben) aufgefallen ist, dass an jedem struct attribute((packed)) hängt.
    attribute((packed)) geht in c++ nicht, da müsste ich das linker File neu schreiben. Ich bin bei dem Makefile schon fast gestorben😩
    Dann wird sehr viel mit semaphores gearbeitet und mutex wird auch oft verwendet mit und ohne Zusammenhang der Semaphores.

    __sync() habe ich auch schon mal gesehen, das ist auch so ein Speicher voodoo.

    Es gibt zwei potentiell Probleme die ich jetzt Atok sehe. Entweder kann er "this" nicht verarbeiten, aufgrund von aggresiven Optimierungen ( die ich aus habe ).
    Oder er kann die vTable nicht verarbeiten.

    Eine Idee habe ich noch.
    Ich mache die Engine klasse als Basis Klasse für LivingObject.
    Dann kann ich in über eine Virtuelle Funktion alle abgeleiteten Klassen ansprechen.
    Damit ist dann die Engine Klasse teil der vTable.
    Ist aber auch erst mal nur graue Theorie.



  • @D_Key sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    Es gibt ja bei der Playstation einige Restriktionen die zu beachten sind. Was mir im klassischen C(fast alles auf der Ps2 ist in c geschrieben) aufgefallen ist, dass an jedem struct attribute((packed)) hängt.
    attribute((packed)) geht in c++ nicht, da müsste ich das linker File neu schreiben. Ich bin bei dem Makefile schon fast gestorben😩

    Sicher? Ich habe damit zumindest bei GCC bisher keine Probleme gehabt. Da geht's in C++ sogar mit C++11-Attributen: struct [[gnu::packed]] A { ... }. Ist da der C++-Compiler vielleicht ein anderer als der C-Compiler? Oder vielleicht stand das Attribut auch nur an der falschen Stelle? Das gehört nach struct/class. Was gibt's denn da für ne Fehlermeldung?

    Mit nem Linker-Skript hat man soweit ich weiß eh keinen Einfluss auf diese interne Struktur von Objekten. Da kann man nur festlegen, wo die Objekte als ganzes letztendlich hin sollen (im Speicher oder in der Executable).

    Und sorry dass ich mit deinem Hauptproblem auch keinen Geistesblitz habe. Ich weiß nur, dass die PS2 wegen ihrer besonderen Architektur zwar sehr leistungsfähig für ihre Generation, aber eine echte Herausforderung zu programmieren war. Das riecht ein bisschen als müsse man die Hardware schon sehr intim kennen, um da das Problem zu finden 😉



  • @D_Key sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    Normaler weise wird bei einer Kombo if(!_itr->arest) gesetzt und über einen Timer abgebaut

    Was meinst du mit Timer? Interrupt von einem Hardware-Timer?
    Und hast du mehrere Threads laufen?

    bei Superscalar CPU

    Alle modernen CPUs sind superscalar. Man hat bloss aufgehört das Wort zu verwenden, weil es mittlerweile Standard ist. Daran liegt es also schonmal nicht.

    Falls du unions oder verbotene Pointer-casts verwendest (also z.B. nen int* zu nem short* casten und dann dereferenzieren) könntest du versuchen mit -fno-strict-aliasing zu bauen.

    Was man theoretisch auch nicht ausschliessen kann sind Compiler-Bugs. Soweit ich weiss erfordert der MIPS R5900 dass die Instruktionen vom Compiler schon passend "angeordnet" werden, so dass Abhängigkeiten/Ausführungszeiten berücksichtigt wurden. Wenn der Compiler das nicht macht, dann kann es sein dass der generierte Code auf einem Emulator funktioniert, aber auf echter Hardware dann leider nicht.

    Also vielleicht mal nen anderen Compiler versuchen. Mach dich schlau was der "beste" Compiler für PS2 ist.



  • @D_Key sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    Das habe ich mir auch schon gedacht, aber ich Blicks nicht was hier passiert. Wenn man gdb nutzen könnte, könnte man mit dem Debugger den Code schrittweise durchgehen.

    Kann man aber leider nicht, da dies dein Timing komplett stören würde.

    Mein Gedanke zielt in folgende Richtung:

    Du nutzt eine PS2 welche sich vermutlich anders verhält als ein Standard PC. Du sagst dass das Problem bei einem Combo auftritt. Hau mich bitte nicht, aber Spielen ist nicht so mein Ding. Ein Combo war doch eine schnelle Kombination von Tastenkombinationen bzw. Schlägen. In Endeffekt eine schnelle Folge von Tastenevents.

    Von daher wäre es interresant zu wissen welche Events da auftreten. Deswegen würde ich da einen Logger einsetzen um dies genau nachzuverfolgen.

    Folgende Fragen würde ich klären:

    • Wie schnell kommen die Events?
    • Wie lange dauert die Bearbeitung?
    • Wie reagiert deine Eventbehandlung unter Volllast?


  • @Finnegan sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    Sicher?

    Da kommt ganz normal error: 'packed' was not declared in this scope

    @hustbaer sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    Was meinst du mit Timer? Interrupt von einem Hardware-Timer?
    Und hast du mehrere Threads laufen?

    Nein, ich habe keine Threads am laufen.
    Nein ,keine Hardware Timer. Timing über die game loop. arest steht für attack rest. Quasi die Ausdauer.
    Nach einer Kombo wird arest gesetzt (für this, also den attacker) weil Ausdauer verbraucht wurde.

    Da aber post_interaction schon aus dem falschen Kontext her aufgerufen wurde und this schon auf den falchen Speicher zeigt, setzt er arest auch auf den angegriffen Charakter. Daher feuert cout mehrmals.

    Allerdings hat der angegriffene Charakter keine ITR's (Interaktionen) daher darf er hier:

    void Charakter::post_interaction()
    {
        const uint8_t ITR_Len = thisFrame.D->numOfItr;
        for(uint8_t i=0; i<ITR_Len; i++)
        {
    

    Schon gar nicht rein gehen.
    Der erste aufruf von if(attacked(gameObjectPtr->hit_impl(itr, &vol)))
    passt noch
    Danach sind alle Werte von den angegriffenen Charakter auch die der Angreift.

    Was noch passt, die Kobo geht von frame 70 bis Frame 73, danach muss auf frame 0 Gesprungen werden.
    Frame 72 setzt arest.
    Er springt aber nicht auf frame 0 weil zuvor in hit that->setFrame(180,21); aufgerufen wurde. Weil hit auch schon aus dem falschen Kontext aufgerufen wurde weil post_interaktion schon an falscher stelle ist.
    Das heißt beide Charakter bekommen zum Zeitpunkt x that->setFrame(180,21); aufgebrummt.

    Aber warum nur bei einer Combo???????

    @Quiche-Lorraine sagte in Code Ausführung ist durcheinader bei Superscalar CPU:

    Ein Combo war doch eine schnelle Kombination von Tastenkombinationen bzw. Schlägen. In Endeffekt eine schnelle Folge von Tastenevents.

    Ja richtig, eine Combo ist ein folge von Tastenkombinationen, die in der Richtigen zeit eingegeben werden müssen.
    Zum meinem jetzigen Zeitpunk habe ich nur zwei Kobo's: rennen angriff und drei mal Attacke, beides führt zu Frame 70.

    die Kombo wird ausgewertet kurz vor der Transition in Funktion transit:

    void LivingObject::transit()
    {
        if(childController)
        {
            combo_impl();
        }
        if(effect.timein < 0 && effect.stuck)
        {
            //stuck
        }
        else
        {
            //trans;
            trans(this);
        }
        effect.timein--;
        if(effect.timein < 0 && effect.stuck)
        {
            //stuck
        }
        else
        {
            state_update(-9);
        }
    }
    combo_impl(); ist wider eine virtuelle Funktion:
     ```cpp
    void combo_impl() override
        {
            combo_update();
        }
    
    und
    ```cpp
    void Charakter::combo_update()
    {
        uint16_t K = 0;
        if(comboBuffer)
        {
            K = comboBuffer->combo;
        }
    
        if(comboBuffer->combo && comboBuffer->combo == 67) //67 jump-att
        {
            K = 6;
        }
    
        int16_t tar1 = call(this, thisFrame.D->state, -3, K);
        int16_t tar2 = 0;
        if(tar1 <= 0)
        {
           tar2 = generic(this, -3, K);
        }
       call(this,  thisFrame.D->state, -4, 0);
       generic(this, -4, K);
    
        if(comboBuffer->combo && comboBuffer->combo == 67) //67 jump-att
        {
            if(tar1 || tar2)
            {
                comboBuffer->combo = 7;
            }
        }
        else
        {
            if(tar1 > 0 || tar2 > 0 || K == 1 || K == 2 ||  K ==3 || K==4 )
            {
                comboBuffer->combo = 0;
            }
        }
    }
    

    in combo_update wird wiederum generic aufgerufen und generic ruft post_interaction auf.

    int16_t Char_States::generic(Charakter *basePtr,int8_t e, uint16_t K)
    {
        switch(e)
        {
        case -1: //frame
        {
            if(basePtr->thisFrame.D->mp != 0)
            {
                if(mainCharFrames[basePtr->uID][basePtr->thisFrame.PN]->next == basePtr->thisFrame.N)
                {
                    if(basePtr->thisFrame.D->mp < 0)
                    {
                        if(!Engine::getInstance().F6_mode)
                        {
                            basePtr->health.mp += basePtr->thisFrame.D->mp;
                        }
                        basePtr->health.mp_usage -=  basePtr->thisFrame.D->mp;
                        if(basePtr->health.mp < 0)
                        {
                            basePtr->health.mp = 0;
                            basePtr->setFrame(basePtr->thisFrame.D->hit_d);
                        }
                    }
                }
                else
                {
                    const int16_t dmp = basePtr->thisFrame.D->mp % 1000;
                    const int16_t dhp = floor(basePtr->thisFrame.D->mp / 1000) * 10;//frame.d.Mp correct??
                    if(!Engine::getInstance().F6_mode)
                    {
                        basePtr->health.mp -= dmp;
                    }
                    basePtr->health.mp_usage += dmp;
                    basePtr->injury(dhp);
                }
            }
            //todo Opoint();
        }//frame
        break;
        case -5: //TU
        {
            if(!basePtr->state_update(-100))
            {
                basePtr->post_interaction();
            }
            if (basePtr->bdyBox.y == 0 && basePtr->bdyBox.vy == 0 && basePtr->thisFrame.N == 212 && basePtr->thisFrame.PN != 211)
            {
                basePtr->setFrame(999);
            }
            else if (basePtr->bdyBox.y == 0 && basePtr->bdyBox.vy > 0)   // fell onto ground
            {
                int16_t result = basePtr->state_update(-11);
                if (result > 0)
                {
                    basePtr->setFrame(result, 15);
                }
                else
                {
                    basePtr->bdyBox.vy = 0; // set to zero
                    basePtr->linear_friction(
                        utility.lookup_abs(GC.friction.fell, basePtr->bdyBox.vx),
                        utility.lookup_abs(GC.friction.fell, basePtr->bdyBox.vz)
                    );
                }
            }
            else if (basePtr->bdyBox.y + basePtr->bdyBox.vy >= 0 && basePtr->bdyBox.vy > 0)   // predict falling onto the ground
            {
                int16_t result = basePtr->state_update(-12);
                if (result > 0)
                {
                    basePtr->setFrame(result, 15);
                }
                else
                {
                    if (basePtr->getState() == 13)   // frozen
                    {
                        ; // do nothing
                    }
                    else if (basePtr->thisFrame.N == 212)     // jumping
                    {
                        basePtr->setFrame(215, 15); // crouch
                    }
                    else
                    {
                        basePtr->setFrame(219, 15); // crouch2
                    }
                }
            }
            // basePtr->health recover
            // http://lf2.wikia.com/wiki/Health_and_mana
            if (Engine::getInstance().timeT % 12 == 0)
            {
                if (basePtr->health.hp >= 0 && basePtr->health.hp < basePtr->health.hp_bound)
                {
                    basePtr->health.hp++;
                }
            }
    
            if (basePtr->health.hp >= 0 && basePtr->effect.heal && basePtr->effect.heal > 0)
            {
                if (Engine::getInstance().timeT % unsigned(basePtr->heal_speed) == 0)
                {
                    if (basePtr->health.hp + basePtr->heal_speed  <= basePtr->health.hp_bound)
                    {
                        basePtr->health.hp +=  basePtr->heal_speed;
                    }
                    basePtr->effect.heal -=  basePtr->heal_speed;
                }
            }
            if (Engine::getInstance().timeT % 3 == 0)
            {
                if (basePtr->health.mp < basePtr->health.mp_full)
                {
                    basePtr->health.mp += 1 + floor((basePtr->health.hp_full - (basePtr->health.hp < basePtr->health.hp_full ? basePtr->health.hp : basePtr->health.hp_full)) / 100);
                }
            }
            // recovery
            if (basePtr->health.fall > 0)
            {
                basePtr->health.fall += GC.recover.fall;
            }
            if (basePtr->health.bdefend > 0)
            {
                basePtr->health.bdefend += GC.recover.bdefend;
            }
            basePtr->comboBuffer->timeout--;
            if(basePtr->comboBuffer->timeout == 0)
            {
                if(K == 5 || K == 6  || K == 7 || K == 11 || K == 22 )
                {
                    basePtr->comboBuffer->combo = 0;
                }
            }
    
        }//TU
        break;
        case -9 : //transit
        {
            basePtr->dynamics();
        }
        break;
        }
        return 0;
    }//generic
    

    Die gesamte state machine umfasst über 100 states. das ist ein Riesen Baum an switch und if's.
    In der generic Funktion wird auch Energie hinzugefügt basePtr->health.hp += basePtr->heal_speed;
    wie zuvoor erwähnt wirkt sich eien ineraktion auf beide Charaktere aus.

    Villeicht gibt es auch ein Problem mit Mehrfachvererbung
    class Charakter : public LivingObject, protected Char_States. Weil, health ist ein struct in LivingObject.



  • Ich fange bald an zu weinen...
    Ich finde das Problem einfach nicht 😡 😤

    Die Engine klasse als Basisklasse für alle LivingObjects einzurichten geht nicht, da verhedder ich mich in Zirkulären Abhängigkeiten.

    Zudem ist es tatsächlich so, das die "falling Frames" ein itr tag haben
    Das heißt, er geht auch für den Gegner Charakter hier rein:

    void Charakter::post_interaction()
    {
        const uint8_t ITR_Len = thisFrame.D->numOfItr;
        for(uint8_t i=0; i<ITR_Len; i++)
        {
    

    itr_arest_update(itr); wird korrekt gesetzt trotzdem spuckt die Playstaion bzw pcsx2 mehrmals:
    std::cout << "gameObjectPtr address: " << gameObjectPtr << " this address: " << this << std::endl;
    aus.

    Der Verdacht verhärtet sich, das es was mit dem Controller zu tun haben muss.
    Die combo wird ausgewertet in combo_update(). hier wird auch nochmals generic aufgerufen, was auch post_interaktion aufruft.

    if(tar1 <= 0)
       {
          tar2 = generic(this, -3, K);
       }
      call(this,  thisFrame.D->state, -4, 0);
      generic(this, -4, K);
    

    Allerdings mit dem event -4 oder -3. Post Interaktion ist event -5
    Nicht das er in genric eventuell eine break; Anweisung überspringt.

    Es gibt nur zwei Sachen die unterschiedlich sind vom PC zu Playstation.Der PC rendert via SDL2 und die Playstation via GS und der PC hat als Eingabegerät eine Tastatur, die Playstation eine Controller.

    Ich begreife nicht wie der Controller, die events beeinflussen könnte.
    Der Combodecoder erkennt die Eingaben egal ob Tastatur oder Controller und wenn eine Combo erkannt wurde wird sie an die Charakter Instanz übergebenen. Dafür gebe ich den Zeiger der Charakter Instanz an den Combodecoder
    Der Zeiger aber auch nur dann übergeben, wenn es sich um eine Charakter Instanz handelt die von einer Person gesteuert wird.



  • Nochmal: ich denke es ist durchaus möglich dass der Compiler schuld ist.


Anmelden zum Antworten