Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[LUA][C++] gdb problem z silnikiem gry

Ostatnio zmodyfikowano 2022-10-05 19:52
Autor Wiadomość
dunno
Temat założony przez niniejszego użytkownika
» 2022-10-01 12:29:59
@DejaVu @pekfos
Dzięki za wskazówki.

Zrobiłem tak jak napisałeś tj.
C/C++
void ActionScript::internalAddPositionEx( lua_State * L, const PositionEx & pos )
{
   
#ifdef MUTEXY_FIX
   
std::lock_guard < std::mutex > guard( actionsMutex );
   
#endif  //MUTEXY_FIX
   
lua_newtable( L );
   
setField( L, "z", pos.z );
   
setField( L, "y", pos.y );
   
setField( L, "x", pos.x );
   
setField( L, "stackpos", pos.stackpos );
}

oraz w actions.h pod protected: dodałem
C/C++
#ifdef MUTEXY_FIX
mutable std::mutex actionsMutex;
#endif  //MUTEXY_FIX

to wywala błąd:
actions.cpp: In static member function âstatic void ActionScript::internalAddPositionEx(lua_State*, const PositionEx&)â:
actions.cpp:1175:37: error: invalid use of member âActionScript::actionsMutexâ in static member function
  std::lock_guard <std::mutex> guard(actionsMutex);
                                     ^~~~~~~~~~~~
In file included from player.h:10,
                 from actions.cpp:8:
actions.h:274:21: note: declared here
  mutable std::mutex actionsMutex;
                     ^~~~~~~~~~~~

Próbowałem też innym sposobem tzn.
Zwróciłeś uwage jak są zrobione locki w protocol76.cpp - gdybym tak zrobił analogicznie dla spells.cpp i actions.cpp i creature.cpp miałoby to sens? np.
C/C++
void ActionScript::internalAddPositionEx( lua_State * L, const PositionEx & pos )
{
   
#ifdef MUTEXY_FIX
   
OTSYS_THREAD_LOCK_CLASS lockClass( game->gameLock, "ActionScript::internalAddPositionEx()" );
   
#endif  //MUTEXY_FIX
   
lua_newtable( L );
   
setField( L, "z", pos.z );
   
setField( L, "y", pos.y );
   
setField( L, "x", pos.x );
   
setField( L, "stackpos", pos.stackpos );
}
z tym, że wywala podobny błąd:

actions.cpp: In static member function âstatic void ActionScript::internalAddPositionEx(lua_State*, const PositionEx&)â:
actions.cpp:1175:39: error: invalid use of member âActionScript::gameâ in static member function
     OTSYS_THREAD_LOCK_CLASS lockClass(game->gameLock, "ActionScript::internalAddPositionEx()");
                                       ^~~~
In file included from player.h:10,
                 from actions.cpp:8:
actions.h:274:8: note: declared here
  Game *game;
        ^~~~

Na tyle rozumiem, że problem jest w tym ze jest zadeklarowana jako metoda statyczna tj:
static void internalAddPositionEx( lua_State * L, const PositionEx & pos );

Da się jakoś inaczej obejsć ten problem niz kasujac slowo kluczowe static? Bo jak zmieniam ta metode kasujac słowo static to w ogóle zaczyna się krzaczyć w kilku innych miejscach.
np.

actions.cpp: In static member function âstatic int32_t ActionScript::internalGetPlayerInfo(lua_State*, ePlayerInfo)â:
actions.cpp:1241:31: error: cannot call member function âvoid ActionScript::internalAddPositionEx(lua_State*, const PositionEx&)â without object
    internalAddPositionEx(L,pos);
                               ^
actions.cpp:1246:31: error: cannot call member function âvoid ActionScript::internalAddPositionEx(lua_State*, const PositionEx&)â without object
    internalAddPositionEx(L,pos);

Oczywiście w actions.h mam kilka klas np.
C/C++
class ActionScript;
class Action;

Jeżeli chodzi np. już o Action::executeUse(......)
to zadziałało bez problemu jednym i drugim sposobem np:
C/C++
bool Action::executeUse( Player * player, Item * item, PositionEx & posFrom, PositionEx & posTo )
{
   
#ifdef MUTEXY_FIX
   
OTSYS_THREAD_LOCK_CLASS lockClass( game->gameLock, "Action::executeUse()" );
   
#endif  //MUTEXY_FIX
   

ale tutaj metoda już nie jest oznaczona jako "static"

bool executeUse( Player * player, Item * item, PositionEx & posFrom, PositionEx & posTo );


Także jak sobie poradzić gdy metoda jest oznaczona jako static i chciałbym użyć np.
C/C++
#ifdef MUTEXY_FIX
OTSYS_THREAD_LOCK_CLASS lockClass( game->gameLock, "ActionScript::internalAddPositionEx()" );
#endif  //MUTEXY_FIX
P-179666
pekfos
» 2022-10-01 14:26:26
Mechanika gry wydaje się być z natury jednowątkowa, więc dodawanie tego tego muteksu w tym miejscu nie ma sensu. Trzeba to zrobić w Game, gdzie to już jest zrobione, pytanie tylko czy wszędzie gdzie powinno. W szczególności sprawdź te 10% własnego kodu, którego nie znamy.
P-179667
dunno
Temat założony przez niniejszego użytkownika
» 2022-10-01 17:31:10
@pekfos
. Trzeba to zrobić w Game, gdzie to już jest zrobione, pytanie tylko czy wszędzie gdzie powinno. W szczególności sprawdź te 10% własnego kodu, którego nie znamy.
Bazuje na tym: https://github.com/divinity76/YurOTS/tree/master/ots/source. W zasadzie mam tylko kilka innych dodatkowych funkcji do ktorych dodalem tez locka, wiem ze problem ten wystepował też na tym silniku co wyżej podałem link, a ja właściwie mam ten sam silnik.

w gdb wywalalo ze problem dotyczy m.in. Game::playerUseItemEx, a tam jest lock.

C/C++
bool Game::playerUseItemEx( Player * player, const Position & posFrom, const unsigned char stack_from,
const Position & posTo, const unsigned char stack_to, const uint16_t itemid )
{
   
OTSYS_THREAD_LOCK_CLASS lockClass( gameLock, "Game::playerUseItemEx()" );
   
   
if( player->isRemoved )
       
 return false;
   
   
bool ret = false;
   
   
Position thingpos = getThingMapPos( player, posFrom );
   
Item * item = dynamic_cast < Item * >( getThing( posFrom, stack_from, player ) );
   
   
if( item )
   
{
       
//Runes
       
std::map < uint16_t, Spell * >::iterator sit = spells.getAllRuneSpells()->find( item->getID() );
       
if( sit != spells.getAllRuneSpells()->end() )
       
{
           
if(( abs( thingpos.x - player->pos.x ) > 1 ) ||( abs( thingpos.y - player->pos.y ) > 1 ) )
           
{
               
player->sendCancel( "To far away..." );
               
ret = false;
           
}
           
else
           
{
               
std::string var = std::string( "" );
               
if( player->access >= g_config.ACCESS_PROTECT || sit->second->getMagLv() <= player->maglevel )
               
{
                   
bool success = sit->second->getSpellScript()->castSpell( player, posTo, var );
                   
ret = success;
                   
if( success )
                   
{
                       
autoCloseTrade( item );
                       
item->setItemCharge( std::max(( int32_t ) item->getItemCharge() - 1, 0 ) );
                       
if( item->getItemCharge() == 0 )
                       
{
                           
if( removeThing( player, posFrom, item ) )
                           
{
                               
FreeThing( item );
                           
}
                        }
                    }
                }
               
else
               
{
                   
player->sendCancel( "You don't have the required magic level to use that rune." );
               
}
            }
        }
       
else {
           
actions.UseItemEx( player, posFrom, stack_from, posTo, stack_to, itemid );
           
ret = true;
       
}
    }
   
   
   
return ret;
}

bo rozumiem, ze jakby byl problem z inna funkcja, to gdb raczej by to wskazalo?, a tu ten lock jest. Może one po prostu nie działają prawidłowo?
P-179668
pekfos
» 2022-10-01 17:54:17
bo rozumiem, ze jakby byl problem z inna funkcja, to gdb raczej by to wskazalo?, a tu ten lock jest.
Nie. Problem nie musi dotyczyć tej funkcji i najprawdopodobniej nie dotyczy. Żeby dwa fragmenty kodu nie wykonywały się jednocześnie lock musi być w obu miejscach. Tu jest, więc patrzysz na zły kod. Przynajmniej dopóki rozważamy hipotezę błędnej synchronizacji. Wróć może do core dumpa i zobacz co robiły inne wątki w czasie gdy wywalił się ten jeden, który pokazałeś. Przy odrobinie szczęścia będzie drugi interesujący backtrace.
P-179669
dunno
Temat założony przez niniejszego użytkownika
» 2022-10-01 18:23:03

Żeby dwa fragmenty kodu nie wykonywały się jednocześnie lock musi być w obu miejscach.
No to nie bardzo rozumiem dlaczego w actions.cpp nie ma sensu go dodawać.

Wróć może do core dumpa i zobacz co robiły inne wątki w czasie gdy wywalił się ten jeden, który pokazałeś. Przy odrobinie szczęścia będzie drugi interesujący backtrace.

Właśnie core dumpa nie mam zapisanego - nadpisał mi się przy robieniu restartu silnika gry. Poczekam, aż problem wystąpi ponownie, wtedy rozumiem, ze zrobić coś takiego:
gdb ./otserv core




np. jak mam skrypt lua to on wygląda tak:

function onUse(cid, item, frompos, item2, topos)
-- tutaj zawartość skryptu
end

a właśnie w actions.cpp w oryginlnym executeuse miałem:
C/C++
bool Action::executeUse( Player * player, Item * item, PositionEx & posFrom, PositionEx & posTo )
{
   
//onUse(uidplayer, item1,position1,item2,position2)
   
script->ClearMap();
   
script->_player = player;
   
PositionEx playerpos = player->pos;
   
uint32_t cid = script->AddThingToMap(( Thing * ) player, playerpos );
   
uint32_t itemid1 = script->AddThingToMap( item, posFrom );
   
lua_State * luaState = script->getLuaState();
   
   
lua_pushstring( luaState, "onUse" );
   
lua_gettable( luaState, LUA_GLOBALSINDEX );
   
   
lua_pushnumber( luaState, cid );
   
script->internalAddThing( luaState, item, itemid1 );
   
script->internalAddPositionEx( luaState, posFrom );
   
//std::cout << "posTo" <<  (Position)posTo << " stack" << (int32_t)posTo.stackpos <<std::endl;
   
Thing * thing = script->game->getThing(( Position ) posTo, posTo.stackpos, player );
   
if( thing && posFrom != posTo )
   
{
       
int32_t thingId2 = script->AddThingToMap( thing, posTo );
       
script->internalAddThing( luaState, thing, thingId2 );
       
script->internalAddPositionEx( luaState, posTo );
   
}
   
else
   
{
       
script->internalAddThing( luaState, NULL, 0 );
       
PositionEx posEx;
       
script->internalAddPositionEx( luaState, posEx );
   
}
   
   
lua_pcall( luaState, 5, 1, 0 );
   
   
bool ret =( script->internalGetNumber( luaState ) != 0 );
   
   
return ret;
}
się do tego odwołuje tj
lua_pushstring( luaState, "onUse" );

więc na pewno nie ma sensu w powyższej metodzie dodawać locka?

a w zasadzie wszystko zaczyna się mniej więcej od
C/C++
void Protocol76::parseUseItemEx( NetworkMessage & msg )
{
   
Position pos_from = msg.GetPosition();
   
uint16_t itemid = msg.GetItemId();
   
unsigned char from_stackpos = msg.GetByte();
   
Position pos_to = msg.GetPosition();
   
/*uint16_t tile_id = */
   
msg.GetU16();
   
unsigned char to_stackpos = msg.GetByte();
   
   
game->playerUseItemEx( player, pos_from, from_stackpos, pos_to, to_stackpos, itemid );
   
}
i tutaj tez nie ma locka a dopiero potem idzie do game->playerUseItemEx i dopiero dalej do actions - nie wiem czy da coś dodanie locka w protocol76.cpp od ktorego się to zaczyna?

Jeśli problem się powtórzy - a na pewno się powtórzy prędzej czy później, wszystko zależy od ilości graczy to skopiuje sobie tego core dumpa. I wrzucę co wyszło.
P-179670
pekfos
» 2022-10-01 18:47:23
No to nie bardzo rozumiem dlaczego w actions.cpp nie ma sensu go dodawać.
Cała logika gry powinna być wykonywana przez maksymalnie jeden wątek naraz, z czego wynika że skrypty lua są zawsze wykonywane przez maksymalnie jeden wątek naraz. Jeśli tak nie jest, to masz większy problem, na poziomie całej logiki gry. Lockiem w ActionScript co najwyżej zmniejszysz szanse na wystąpienie problemu, a w najgorszym razie wprowadzisz dodatkowe błędy w działaniu.
P-179671
dunno
Temat założony przez niniejszego użytkownika
» 2022-10-02 14:47:46
Cała logika gry powinna być wykonywana przez maksymalnie jeden wątek naraz, z czego wynika że skrypty lua są zawsze wykonywane przez maksymalnie jeden wątek naraz.
Rozumiem, czyli w takim przypadku jeśli dodałbym locka do każdej metody w game.cpp nieważne czy byłby on niezbędny czy nie - to wtedy miałbym pewność, że locki są wszedzie tam gdzie powinny?
P-179675
pekfos
» 2022-10-03 00:06:16
Nie, bo nie tylko metody Game korzystają z tych pól.
P-179677
1 « 2 » 3
Poprzednia strona Strona 2 z 3 Następna strona