Skip to content

Commit

Permalink
update Lua interpreter (#582)
Browse files Browse the repository at this point in the history
* update add_param call

* add type: lua_param, LuaParamType

* keep Lua thread ref in registry

* restore current_state after lua_resume

* update the signature of call_coroutine

* select synchro material in main thread

* edit comment

* fix lua_yield nresults

* update lua_resume in 5.3

* use std::exchange
  • Loading branch information
salix5 authored May 31, 2024
1 parent 4e09ea2 commit fb30f1e
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 88 deletions.
8 changes: 4 additions & 4 deletions card.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3282,8 +3282,8 @@ int32 card::is_spsummonable_card() {
pduel->lua->add_param(pduel->game_field->core.reason_effect, PARAM_TYPE_EFFECT);
pduel->lua->add_param(pduel->game_field->core.reason_player, PARAM_TYPE_INT);
pduel->lua->add_param(SUMMON_TYPE_SPECIAL, PARAM_TYPE_INT);
pduel->lua->add_param((void*)0, PARAM_TYPE_INT);
pduel->lua->add_param((void*)0, PARAM_TYPE_INT);
pduel->lua->add_param(0, PARAM_TYPE_INT);
pduel->lua->add_param(0, PARAM_TYPE_INT);
if(!eset[i]->check_value_condition(5))
return FALSE;
}
Expand All @@ -3301,8 +3301,8 @@ int32 card::is_fusion_summonable_card(uint32 summon_type) {
pduel->lua->add_param(pduel->game_field->core.reason_effect, PARAM_TYPE_EFFECT);
pduel->lua->add_param(pduel->game_field->core.reason_player, PARAM_TYPE_INT);
pduel->lua->add_param(summon_type, PARAM_TYPE_INT);
pduel->lua->add_param((void*)0, PARAM_TYPE_INT);
pduel->lua->add_param((void*)0, PARAM_TYPE_INT);
pduel->lua->add_param(0, PARAM_TYPE_INT);
pduel->lua->add_param(0, PARAM_TYPE_INT);
if(!eset[i]->check_value_condition(5))
return FALSE;
}
Expand Down
119 changes: 61 additions & 58 deletions interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

#include <cstring>
#include <utility>
#include "duel.h"
#include "group.h"
#include "card.h"
Expand Down Expand Up @@ -176,68 +177,70 @@ int32 interpreter::load_card_script(uint32 code) {
}
return OPERATION_SUCCESS;
}
void interpreter::add_param(void *param, int32 type, bool front) {
void interpreter::add_param(void* param, LuaParamType type, bool front) {
lua_param p;
p.ptr = param;
if(front)
params.emplace_front(param, type);
params.emplace_front(p, type);
else
params.emplace_back(param, type);
params.emplace_back(p, type);
}
void interpreter::add_param(int32 param, int32 type, bool front) {
void interpreter::add_param(int32 param, LuaParamType type, bool front) {
lua_param p;
p.integer = param;
if(front)
params.emplace_front((void*)(intptr_t)param, type);
params.emplace_front(p, type);
else
params.emplace_back((void*)(intptr_t)param, type);
params.emplace_back(p, type);
}
void interpreter::push_param(lua_State* L, bool is_coroutine) {
int32 pushed = 0;
for (const auto& it : params) {
luaL_checkstack(L, 1, nullptr);
uint32 type = it.second;
auto type = it.second;
switch(type) {
case PARAM_TYPE_INT:
lua_pushinteger(L, (lua_Integer)it.first);
lua_pushinteger(L, it.first.integer);
break;
case PARAM_TYPE_STRING:
lua_pushstring(L, (const char *)it.first);
lua_pushstring(L, (const char*)it.first.ptr);
break;
case PARAM_TYPE_BOOLEAN:
lua_pushboolean(L, (int32)(intptr_t)it.first);
lua_pushboolean(L, it.first.integer);
break;
case PARAM_TYPE_CARD: {
if (it.first)
lua_rawgeti(L, LUA_REGISTRYINDEX, ((card*)it.first)->ref_handle);
if (it.first.ptr)
lua_rawgeti(L, LUA_REGISTRYINDEX, ((card*)it.first.ptr)->ref_handle);
else
lua_pushnil(L);
break;
}
case PARAM_TYPE_EFFECT: {
if (it.first)
lua_rawgeti(L, LUA_REGISTRYINDEX, ((effect*)it.first)->ref_handle);
if (it.first.ptr)
lua_rawgeti(L, LUA_REGISTRYINDEX, ((effect*)it.first.ptr)->ref_handle);
else
lua_pushnil(L);
break;
}
case PARAM_TYPE_GROUP: {
if (it.first)
lua_rawgeti(L, LUA_REGISTRYINDEX, ((group*)it.first)->ref_handle);
if (it.first.ptr)
lua_rawgeti(L, LUA_REGISTRYINDEX, ((group*)it.first.ptr)->ref_handle);
else
lua_pushnil(L);
break;
}
case PARAM_TYPE_FUNCTION: {
function2value(L, (int32)(intptr_t)it.first);
function2value(L, it.first.integer);
break;
}
case PARAM_TYPE_INDEX: {
int32 index = (int32)(intptr_t)it.first;
int32 index = it.first.integer;
if(index > 0)
lua_pushvalue(L, index);
else if(is_coroutine) {
//copy value from current_state to new stack
lua_pushvalue(current_state, index);
int32 ref = luaL_ref(current_state, LUA_REGISTRYINDEX);
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
luaL_unref(current_state, LUA_REGISTRYINDEX, ref);
lua_xmove(current_state, L, 1);
} else {
//the calling function is pushed before the params, so the actual index is: index - pushed -1
lua_pushvalue(L, index - pushed - 1);
Expand Down Expand Up @@ -529,7 +532,7 @@ int32 interpreter::get_function_value(int32 f, uint32 param_count, std::vector<i
}
return is_success;
}
int32 interpreter::call_coroutine(int32 f, uint32 param_count, uint32 * yield_value, uint16 step) {
int32 interpreter::call_coroutine(int32 f, uint32 param_count, int32* yield_value, uint16 step) {
*yield_value = 0;
if (!f) {
sprintf(pduel->strbuffer, "\"CallCoroutine\": attempt to call a null function");
Expand All @@ -547,18 +550,23 @@ int32 interpreter::call_coroutine(int32 f, uint32 param_count, uint32 * yield_va
lua_State* rthread;
if (it == coroutines.end()) {
rthread = lua_newthread(lua_state);
const auto threadref = luaL_ref(lua_state, LUA_REGISTRYINDEX);
function2value(rthread, f);
if(!lua_isfunction(rthread, -1)) {
luaL_unref(lua_state, LUA_REGISTRYINDEX, threadref);
sprintf(pduel->strbuffer, "\"CallCoroutine\": attempt to call an error function");
handle_message(pduel, 1);
params.clear();
return OPERATION_FAIL;
}
++call_depth;
coroutines.emplace(f, rthread);
auto ret = coroutines.emplace(f, std::make_pair(rthread, threadref));
it = ret.first;
} else {
rthread = it->second;
if(step == 0) {
auto threadref = it->second.second;
coroutines.erase(it);
luaL_unref(lua_state, LUA_REGISTRYINDEX, threadref);
sprintf(pduel->strbuffer, "recursive event trigger detected.");
handle_message(pduel, 1);
params.clear();
Expand All @@ -569,49 +577,44 @@ int32 interpreter::call_coroutine(int32 f, uint32 param_count, uint32 * yield_va
}
return OPERATION_FAIL;
}
rthread = it->second.first;
}
push_param(rthread, true);
lua_State* prev_state = current_state;
current_state = rthread;
int32 result = 0, nresults = 0;
{
auto prev_state = std::exchange(current_state, rthread);
#if (LUA_VERSION_NUM >= 504)
int32 nresults;
int32 result = lua_resume(rthread, prev_state, param_count, &nresults);
result = lua_resume(rthread, prev_state, param_count, &nresults);
#else
int32 result = lua_resume(rthread, 0, param_count);
int32 nresults = lua_gettop(rthread);
result = lua_resume(rthread, prev_state, param_count);
nresults = lua_gettop(rthread);
#endif
if (result == LUA_OK) {
coroutines.erase(f);
if(yield_value) {
if(nresults == 0)
*yield_value = 0;
else if(lua_isboolean(rthread, -1))
*yield_value = lua_toboolean(rthread, -1);
else
*yield_value = (uint32)lua_tointeger(rthread, -1);
}
current_state = lua_state;
--call_depth;
if(call_depth == 0) {
pduel->release_script_group();
pduel->restore_assumes();
}
return COROUTINE_FINISH;
} else if (result == LUA_YIELD) {
current_state = prev_state;
}
if (result == LUA_YIELD)
return COROUTINE_YIELD;
} else {
coroutines.erase(f);
if (result != LUA_OK) {
sprintf(pduel->strbuffer, "%s", lua_tostring(rthread, -1));
handle_message(pduel, 1);
lua_pop(rthread, 1);
current_state = lua_state;
--call_depth;
if(call_depth == 0) {
pduel->release_script_group();
pduel->restore_assumes();
}
return COROUTINE_ERROR;
}
else if (yield_value) {
if (nresults == 0)
*yield_value = 0;
else if (lua_isboolean(rthread, -1))
*yield_value = lua_toboolean(rthread, -1);
else
*yield_value = (int32)lua_tointeger(rthread, -1);
}
auto threadref = it->second.second;
coroutines.erase(it);
luaL_unref(lua_state, LUA_REGISTRYINDEX, threadref);
--call_depth;
if (call_depth == 0) {
pduel->release_script_group();
pduel->restore_assumes();
}
return (result == LUA_OK) ? COROUTINE_FINISH : COROUTINE_ERROR;
}
int32 interpreter::clone_function_ref(int32 func_ref) {
luaL_checkstack(current_state, 1, nullptr);
Expand All @@ -628,7 +631,7 @@ void* interpreter::get_ref_object(int32 ref_handler) {
lua_pop(current_state, 1);
return p;
}
//Convert a pointer to a lua value, +1 -0
//push the object onto the stack, +1
void interpreter::card2value(lua_State* L, card* pcard) {
luaL_checkstack(L, 1, nullptr);
if (!pcard || pcard->ref_handle == 0)
Expand Down
36 changes: 21 additions & 15 deletions interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,25 @@ class effect;
class group;
class duel;

enum LuaParamType {
PARAM_TYPE_INT = 0x01,
PARAM_TYPE_STRING = 0x02,
PARAM_TYPE_CARD = 0x04,
PARAM_TYPE_GROUP = 0x08,
PARAM_TYPE_EFFECT = 0x10,
PARAM_TYPE_FUNCTION = 0x20,
PARAM_TYPE_BOOLEAN = 0x40,
PARAM_TYPE_INDEX = 0x80,
};

class interpreter {
public:
using coroutine_map = std::unordered_map<int32, lua_State*>;
using param_list = std::list<std::pair<void*, uint32>>;
union lua_param {
void* ptr;
int32 integer;
};
using coroutine_map = std::unordered_map<int32, std::pair<lua_State*, int32>>;
using param_list = std::list<std::pair<lua_param, LuaParamType>>;

duel* pduel;
char msgbuf[64];
Expand All @@ -48,8 +63,8 @@ class interpreter {

int32 load_script(const char* script_name);
int32 load_card_script(uint32 code);
void add_param(void* param, int32 type, bool front = false);
void add_param(int32 param, int32 type, bool front = false);
void add_param(void* param, LuaParamType type, bool front = false);
void add_param(int32 param, LuaParamType type, bool front = false);
void push_param(lua_State* L, bool is_coroutine = false);
int32 call_function(int32 f, uint32 param_count, int32 ret_count);
int32 call_card_function(card* pcard, const char* f, uint32 param_count, int32 ret_count);
Expand All @@ -59,14 +74,14 @@ class interpreter {
int32 get_operation_value(card* pcard, int32 findex, int32 extraargs);
int32 get_function_value(int32 f, uint32 param_count);
int32 get_function_value(int32 f, uint32 param_count, std::vector<int32>* result);
int32 call_coroutine(int32 f, uint32 param_count, uint32* yield_value, uint16 step);
int32 call_coroutine(int32 f, uint32 param_count, int32* yield_value, uint16 step);
int32 clone_function_ref(int32 func_ref);
void* get_ref_object(int32 ref_handler);

static void card2value(lua_State* L, card* pcard);
static void group2value(lua_State* L, group* pgroup);
static void effect2value(lua_State* L, effect* peffect);
static void function2value(lua_State* L, int32 pointer);
static void function2value(lua_State* L, int32 func_ref);
static int32 get_function_handle(lua_State* L, int32 index);
static duel* get_duel_info(lua_State* L);

Expand All @@ -76,15 +91,6 @@ class interpreter {
}
};

#define PARAM_TYPE_INT 0x01
#define PARAM_TYPE_STRING 0x02
#define PARAM_TYPE_CARD 0x04
#define PARAM_TYPE_GROUP 0x08
#define PARAM_TYPE_EFFECT 0x10
#define PARAM_TYPE_FUNCTION 0x20
#define PARAM_TYPE_BOOLEAN 0x40
#define PARAM_TYPE_INDEX 0x80

#define COROUTINE_FINISH 1
#define COROUTINE_YIELD 2
#define COROUTINE_ERROR 3
Expand Down
6 changes: 4 additions & 2 deletions libduel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3227,7 +3227,8 @@ int32 scriptlib::duel_select_synchro_material(lua_State *L) {
lua_pushvalue(L, 3);
lua_pushvalue(L, 4);
lua_pushvalue(L, 2);
return lua_yield(L, 3);
lua_xmove(L, pduel->lua->lua_state, 3);
return lua_yield(L, 0);
}
int32 scriptlib::duel_check_synchro_material(lua_State *L) {
check_param_count(L, 5);
Expand Down Expand Up @@ -3286,7 +3287,8 @@ int32 scriptlib::duel_select_tuner_material(lua_State *L) {
lua_pushvalue(L, 4);
lua_pushvalue(L, 5);
lua_pushvalue(L, 2);
return lua_yield(L, 3);
lua_xmove(L, pduel->lua->lua_state, 3);
return lua_yield(L, 0);
}
int32 scriptlib::duel_check_tuner_material(lua_State *L) {
check_param_count(L, 6);
Expand Down
12 changes: 6 additions & 6 deletions operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5316,7 +5316,7 @@ int32 field::select_synchro_material(int16 step, uint8 playerid, card* pcard, in
case 1: {
if(returns.ivalue[0] == -1) {
lua_pop(pduel->lua->current_state, 3);
pduel->lua->add_param((void*)0, PARAM_TYPE_GROUP);
pduel->lua->add_param(nullptr, PARAM_TYPE_GROUP);
core.limit_tuner = 0;
return TRUE;
}
Expand Down Expand Up @@ -5683,7 +5683,7 @@ int32 field::select_xyz_material(int16 step, uint8 playerid, uint32 lv, card* sc
}
case 1: {
if(returns.ivalue[0] == -1) {
pduel->lua->add_param((void*)0, PARAM_TYPE_GROUP);
pduel->lua->add_param(nullptr, PARAM_TYPE_GROUP);
return TRUE;
}
int32 pv = 0;
Expand Down Expand Up @@ -5850,7 +5850,7 @@ int32 field::select_xyz_material(int16 step, uint8 playerid, uint32 lv, card* sc
}
case 4: {
if(returns.ivalue[0] == -1) {
pduel->lua->add_param((void*)0, PARAM_TYPE_GROUP);
pduel->lua->add_param(nullptr, PARAM_TYPE_GROUP);
return TRUE;
}
card* pcard = core.select_cards[returns.bvalue[1]];
Expand Down Expand Up @@ -5906,7 +5906,7 @@ int32 field::select_xyz_material(int16 step, uint8 playerid, uint32 lv, card* sc
}
case 6: {
if(returns.ivalue[0] == -1) {
pduel->lua->add_param((void*)0, PARAM_TYPE_GROUP);
pduel->lua->add_param(nullptr, PARAM_TYPE_GROUP);
return TRUE;
}
group* pgroup = pduel->new_group(core.operated_set);
Expand All @@ -5930,7 +5930,7 @@ int32 field::select_xyz_material(int16 step, uint8 playerid, uint32 lv, card* sc
}
case 8: {
if(returns.ivalue[0] == -1) {
pduel->lua->add_param((void*)0, PARAM_TYPE_GROUP);
pduel->lua->add_param(nullptr, PARAM_TYPE_GROUP);
return TRUE;
}
int32 pv = 0;
Expand Down Expand Up @@ -6036,7 +6036,7 @@ int32 field::select_xyz_material(int16 step, uint8 playerid, uint32 lv, card* sc
}
case 22: {
if(returns.ivalue[0] == -1) {
pduel->lua->add_param((void*)0, PARAM_TYPE_GROUP);
pduel->lua->add_param(nullptr, PARAM_TYPE_GROUP);
return TRUE;
}
int32 pv = 0;
Expand Down
Loading

0 comments on commit fb30f1e

Please sign in to comment.