Ultima modifica da un moderatore:
[AWESOME][/AWESOME]Buondì,
giusto l'altro ieri, dopo l'ennesimo crash dovuto al malfunzionamento del garbage collector di Lua 5.0 (è del 2004 o giù di lì, non c'è da meravigliarsi se crasha) ho deciso di fare l'upgrade a Lua 5.3.3 (ultima versione di quest'anno).
Dato che ho altro da sbrigare, arrivo al dunque mostrando anche a voi come poter fare l'upgrade.
La guida sarà divisa in 4 parti: lib. Lua, server c++, makefile, server lua.
La libreria appena scaricata di per se va bene, solo che per ragioni di retrocompatibilità ci conviene fare delle modifiche. Per comodità vi mostrerò gli screen di Winmerge con le differenze evidenziate tra il prima ed il dopo le modifiche. A destra troverete il file prima delle modifiche, a sinistra troverete il file dopo le modifiche, in giallo/giallino è evidenziato il codice aggiunto mentre in nero/grigiastro il codice rimosso.
Vi consiglio di editare/riscrivere il comando "do_priv_guild" presente in "cmd_gm.cpp".
Per compilare i file server dovrete editare il Makefile aggiungendo i nuovi link alla libreria lua sostituendo tutte le ricorrenze della stringa "/liblua/" con "/liblua/install/", successivamente lanciate il comando "gmake clean && gmake dep && gmake tag && gmake".
Dovete sostituire in tutti i file il comando "!=" con il comando "~=" (cosa che dovrebbe fare in automatico il qc).
Rimuovete da tutti i file lua le funzioni deprecate "table.foreach" e "table.foreachi", un modo intelligente per farlo è il seguente
Andate nel file "questlib.lua" e sostituite la funzione
con
Se non ho dimenticato qualcosa dovrebbe essere tutto.
L'upgrade a Lua 5.3 sembra abbastanza stabile, attualmente dopo le ultime modifiche non ho riscontrato alcun crash dovuto al garbage collector e 12 anni di aggiornamenti Lua si fanno sentire nelle nuove perfomance.
Non chiedetemi di farvi un nuovo qc (quest compilator), non lo uso, non mi serve e sono impegnato con altri progetti.
- Edited (23/08/2016) -
Riscritta la funzione CQuestManager::RunState (file questlua.cpp) aggiungendo:
Dato che la funzione "lua_resume" dovrebbe essere usata solo su coroutine "sospese", ho dovuto aggiungere la gestione dei vari casi in cui una coroutine non sia sospesa. Ho aggiornato di conseguenza la funzione "CQuestManager::RunState".
Senza questa patch è possibile far volontariamente crashare l'intero core, quindi l'aggiornamento è critico (se non ho capito male, il bug è presente anche con la versione 5.0 di lua).
Altri progetti? Stiamo sostituendo il motore grafico, passeremo da Granny ad Unreal Engine 4. A tal proposito cerchiamo gente volenterosa che ci aiuti nell'impresa C++ (che verrà pubblicata in questo forum coi dovuti crediti agli sviluppatori).
Commenti: "Riusciremo finalmente a liberarci una volta per tutte dall'incubo degli exporter gr2!!!"
Saluti,
Acqua
giusto l'altro ieri, dopo l'ennesimo crash dovuto al malfunzionamento del garbage collector di Lua 5.0 (è del 2004 o giù di lì, non c'è da meravigliarsi se crasha) ho deciso di fare l'upgrade a Lua 5.3.3 (ultima versione di quest'anno).
Dato che ho altro da sbrigare, arrivo al dunque mostrando anche a voi come poter fare l'upgrade.
La guida sarà divisa in 4 parti: lib. Lua, server c++, makefile, server lua.
P1: Libreria Lua
Link del download ufficiale: https://www.lua.org/download.html
La libreria appena scaricata di per se va bene, solo che per ragioni di retrocompatibilità ci conviene fare delle modifiche. Per comodità vi mostrerò gli screen di Winmerge con le differenze evidenziate tra il prima ed il dopo le modifiche. A destra troverete il file prima delle modifiche, a sinistra troverete il file dopo le modifiche, in giallo/giallino è evidenziato il codice aggiunto mentre in nero/grigiastro il codice rimosso.
- lauxlib.h:
C++:
/* ** Compatibility macros and functions */ LUALIB_API int lua_dofile (lua_State *L, const char *filename); LUALIB_API int lua_dostring (lua_State *L, const char *str); LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t sz, const char *n);
- lauxlib.c: C++:
/* ** {====================================================== ** compatibility code ** ======================================================= */ static void callalert (lua_State *L, int status) { if (status != 0) { lua_getglobal(L, "_ALERT"); if (lua_isfunction(L, -1)) { lua_insert(L, -2); lua_call(L, 1, 0); } else { /* no _ALERT function; print it on stderr */ fprintf(stderr, "%s\n", lua_tostring(L, -2)); lua_pop(L, 2); /* remove error message and _ALERT */ } } } static int aux_do (lua_State *L, int status) { if (status == 0) { /* parse OK? */ status = lua_pcall(L, 0, LUA_MULTRET, 0); /* call main */ } callalert(L, status); return status; } LUALIB_API int lua_dofile (lua_State *L, const char *filename) { return aux_do(L, luaL_loadfile(L, filename)); } LUALIB_API int lua_dobuffer (lua_State *L, const char *buff, size_t size, const char *name) { return aux_do(L, luaL_loadbuffer(L, buff, size, name)); } LUALIB_API int lua_dostring (lua_State *L, const char *str) { return lua_dobuffer(L, str, strlen(str), str); } /* }====================================================== */
- ltablib.c (aggiunta funzione table.getn per mantenere retro-compatibilità): C++:
static int luaB_getn (lua_State *L) { lua_pushnumber(L, (lua_Number)aux_getn(L, 1, TAB_R)); return 1; } /* }====================================================== */ static const luaL_Reg tab_funcs[] = { {"concat", tconcat}, #if defined(LUA_COMPAT_MAXN) {"maxn", maxn}, #endif {"getn", luaB_getn}, // MODDED - backward compatibility {"insert", tinsert}, {"pack", pack}, {"unpack", unpack}, {"remove", tremove}, {"move", tmove}, {"sort", sort}, {NULL, NULL} };
P2: Server C++
Dovete sostituire in tutti i file:
- "luaL_reg" con "luaL_Reg"
- "luaL_getn" con "lua_objlen"
- "lua_tonumber" con "lua_tointeger" (tranne che nella funzione "combine_lua_string" all'interno di questlua.cpp)
- "lua_pushnumber" con "lua_pushinteger"
- questlua.cpp: C++:
L = luaL_newstate(); luaL_openlibs(L); // LUA 5.3
C++:lua_gc(L,LUA_GCCOLLECT,0); // launch the garbage collector lua_gc(L,LUA_GCSTEP,0); // init garbage collector step counter
C++:QuestState CQuestManager::OpenState(const string& quest_name, int state_index) { QuestState qs; qs.args=0; qs.st = state_index; qs.co = lua_newthread(L); qs.ico = luaL_ref(L, LUA_REGISTRYINDEX); return qs; } // // * RunState // // decides script to wait for user input, or finish // bool CQuestManager::RunState(QuestState & qs) { ClearError(); m_CurrentRunningState = &qs; int ret = lua_resume(qs.co, L, qs.args); if (ret == LUA_OK || ret == LUA_YIELD)
C++:void CQuestManager::CloseState(QuestState& qs) { if (qs.co) { qs.co = NULL; luaL_unref(L, LUA_REGISTRYINDEX, qs.ico); lua_gc(L,LUA_GCSTEP,1); // increase garbace collector step counter } }
- questmanager.cpp (importante bugfix della cache degli script lua, veniva usato come indice unico un indirizzo di memoria castato a signed long int da 32 bit anche quando la macchina è a 64 bit e quindi con indirizzi da 64 bit): C++:
lua_getglobal(qs.co, "__codecache"); // stack : __codecache lua_pushinteger(qs.co, (unsigned long long)code); // stack : __codecache (codeptr) lua_rawget(qs.co, -2); // stack : __codecache (compiled-code) if (lua_isnil(qs.co, -1)) // cache miss { // load code to lua, save it to cache and only function remain in stack lua_pop(qs.co, 1); // stack : __codecache luaL_loadbuffer(qs.co, code, code_size, quest_name.c_str()); // stack : __codecache (compiled-code) lua_pushinteger(qs.co, (unsigned long long)code); // stack : __codecache (compiled-code) (codeptr) lua_pushvalue(qs.co, -2); // stack : __codecache (compiled-code) (codeptr) (compiled_code) lua_rawset(qs.co, -4); // stack : __codecache (compiled-code) lua_remove(qs.co, -2); // stack : (compiled-code) } else // cache hit { lua_remove(qs.co, -2); // stack : (compiled-code) }
C++:
#define LUA_COMPAT_5_1
#if !defined(_MSC_VER) && defined(__cplusplus)
extern "C" {
#endif
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <luaconf.h>
#if !defined(_MSC_VER) && defined(__cplusplus)
}
#endif
Vi consiglio di editare/riscrivere il comando "do_priv_guild" presente in "cmd_gm.cpp".
P3: Makefile
Per compilare Lua dovrete entrare nella cartella ./liblua e lanciare il comando "make freebsd && make local".
Per compilare i file server dovrete editare il Makefile aggiungendo i nuovi link alla libreria lua sostituendo tutte le ricorrenze della stringa "/liblua/" con "/liblua/install/", successivamente lanciate il comando "gmake clean && gmake dep && gmake tag && gmake".
P4: Server Lua
Dovete sostituire in tutti i file la funzione "math.mod" con la funzione "math.fmod".
Dovete sostituire in tutti i file il comando "!=" con il comando "~=" (cosa che dovrebbe fare in automatico il qc).
Rimuovete da tutti i file lua le funzioni deprecate "table.foreach" e "table.foreachi", un modo intelligente per farlo è il seguente
Codice:
--Da
table.foreachi(tab,function(index,value) say( "tab["..index.."] = "..value ) end)
--A
for index, value in ipairs(tab) do say( "tab["..index.."] = "..value ) end
--Da
table.foreach(tab,function(key,value) say( "tab['"..key.."'] = "..value ) end)
--A
for key, value in pairs(tab) do say( "tab['"..key.."'] = "..value ) end
Andate nel file "questlib.lua" e sostituite la funzione
Codice:
function select(...)
return q.yield('select', arg)
end
Codice:
function select(...)
return q.yield('select', {...})
end
Se non ho dimenticato qualcosa dovrebbe essere tutto.
L'upgrade a Lua 5.3 sembra abbastanza stabile, attualmente dopo le ultime modifiche non ho riscontrato alcun crash dovuto al garbage collector e 12 anni di aggiornamenti Lua si fanno sentire nelle nuove perfomance.
Non chiedetemi di farvi un nuovo qc (quest compilator), non lo uso, non mi serve e sono impegnato con altri progetti.
- Edited (23/08/2016) -
Riscritta la funzione CQuestManager::RunState (file questlua.cpp) aggiungendo:
- gestione delle coroutine morte
- gestione di eventuali overflow degli argomenti sulla pila lua
Dato che la funzione "lua_resume" dovrebbe essere usata solo su coroutine "sospese", ho dovuto aggiungere la gestione dei vari casi in cui una coroutine non sia sospesa. Ho aggiornato di conseguenza la funzione "CQuestManager::RunState".
Senza questa patch è possibile far volontariamente crashare l'intero core, quindi l'aggiornamento è critico (se non ho capito male, il bug è presente anche con la versione 5.0 di lua).
C++:
bool CQuestManager::RunState(QuestState & qs)
{
ClearError();
m_CurrentRunningState = &qs;
if (!lua_checkstack(qs.co, qs.args))
{
// lua_pop(qs.co, qs.args); /* remove results anyway */
sys_err("LUA_ERROR: too many arguments to resume.");
WriteRunningStateToSyserr();
SetError();
GotoEndState(qs);
return false;
}
switch (lua_status(qs.co))
{
case LUA_OK:
{
lua_Debug ar;
if (lua_getstack(qs.co, 0, &ar) > 0) // normal
{
sys_err("LUA_ERROR: cannot resume non-suspended coroutine.");
WriteRunningStateToSyserr();
SetError();
GotoEndState(qs);
return false;
}
else if (lua_gettop(qs.co) == 0) // dead
{
sys_err("LUA_ERROR: cannot resume dead coroutine.");
WriteRunningStateToSyserr();
SetError();
GotoEndState(qs);
return false;
}
// else is suspended
}
break;
case LUA_YIELD:
break;
default:
{
sys_err("LUA_ERROR: cannot resume dead coroutine.");
WriteRunningStateToSyserr();
SetError();
GotoEndState(qs);
return false;
}
break;
}
int status = lua_resume(qs.co, NULL, qs.args); // resumes only suspended coroutines
if (status != LUA_OK && status != LUA_YIELD)
{
sys_err("LUA_ERROR: %s, %s, %d", lua_tostring(qs.co, 1), lua_tostring(qs.co, -1), status);
WriteRunningStateToSyserr();
SetError();
GotoEndState(qs);
return false;
}
int nres = lua_gettop(qs.co);
if (!lua_checkstack(qs.co, nres + 1))
{
lua_pop(qs.co, nres); /* remove results anyway */
sys_err("LUA_ERROR: too many results to resume %d", status);
WriteRunningStateToSyserr();
SetError();
GotoEndState(qs);
return false;
}
if ( status == LUA_OK && nres == 0) // dead coroutine
{
// end of quest
GotoEndState(qs);
return false;
}
string state = lua_tostring(qs.co, 1);
if ( state == "select" )
{
GotoSelectState(qs);
return true;
}
else if ( state == "wait" )
{
GotoPauseState(qs);
return true;
}
else if ( state == "input" )
{
GotoInputState(qs);
return true;
}
else if ( state == "confirm" )
{
GotoConfirmState(qs);
return true;
}
else if ( state == "select_item" )
{
GotoSelectItemState(qs);
return true;
}
sys_err("LUA_ERROR: unknown state %s", state.c_str());
WriteRunningStateToSyserr();
SetError();
GotoEndState(qs);
return false;
}
Altri progetti? Stiamo sostituendo il motore grafico, passeremo da Granny ad Unreal Engine 4. A tal proposito cerchiamo gente volenterosa che ci aiuti nell'impresa C++ (che verrà pubblicata in questo forum coi dovuti crediti agli sviluppatori).
Commenti: "Riusciremo finalmente a liberarci una volta per tutte dall'incubo degli exporter gr2!!!"
Saluti,
Acqua