Disallow particle lifetime management in some contexts

Namely, in Create and ChangeType callbacks, which are themselves called by such lifetime management functions. Lifetime management includes explicit actions via partCreate and partKill, but also implicit ones such as changing the type property or changing x or y properties to values that move the particle beyond the edges and causes it to be killed.
This commit is contained in:
Tamás Bálint Misius
2025-05-06 21:31:55 +02:00
parent f65c4ee4e1
commit 3adf6ef91c
5 changed files with 27 additions and 8 deletions

View File

@@ -13,6 +13,7 @@ enum EventTraits : uint32_t
eventTraitInterfaceGraphics = UINT32_C(0x00000010),
eventTraitConstSim = UINT32_C(0x00000020),
eventTraitConstTools = UINT32_C(0x00000040),
eventTraitMonopartAccess = UINT32_C(0x00000080),
};
constexpr EventTraits operator |(EventTraits lhs, EventTraits rhs)
{

View File

@@ -225,11 +225,13 @@ static void luaCreateWrapper(ELEMENT_CREATE_FUNC_ARGS)
lua_pushinteger(lsi->L, y);
lua_pushinteger(lsi->L, t);
lua_pushinteger(lsi->L, v);
if (tpt_lua_pcall(lsi->L, 5, 0, 0, eventTraitSimRng))
lsi->monopartAccessPartID = i;
if (tpt_lua_pcall(lsi->L, 5, 0, 0, eventTraitSimRng | eventTraitMonopartAccess))
{
lsi->Log(CommandInterface::LogError, "In create func: " + LuaGetError());
lua_pop(lsi->L, 1);
}
lsi->monopartAccessPartID = -1;
}
}
@@ -283,11 +285,13 @@ static void luaChangeTypeWrapper(ELEMENT_CHANGETYPE_FUNC_ARGS)
lua_pushinteger(lsi->L, y);
lua_pushinteger(lsi->L, from);
lua_pushinteger(lsi->L, to);
if (tpt_lua_pcall(lsi->L, 5, 0, 0, eventTraitSimRng))
lsi->monopartAccessPartID = i;
if (tpt_lua_pcall(lsi->L, 5, 0, 0, eventTraitSimRng | eventTraitMonopartAccess))
{
lsi->Log(CommandInterface::LogError, "In change type: " + LuaGetError());
lua_pop(lsi->L, 1);
}
lsi->monopartAccessPartID = -1;
}
}

View File

@@ -319,10 +319,12 @@ void LuaSetParticleProperty(lua_State *L, int particleID, StructProperty propert
auto *sim = lsi->sim;
if (property.Name == "type")
{
lsi->AssertMonopartAccessEvent(-1);
sim->part_change_type(particleID, int(sim->parts[particleID].x+0.5f), int(sim->parts[particleID].y+0.5f), luaL_checkinteger(L, 3));
}
else if (property.Name == "x" || property.Name == "y")
{
lsi->AssertMonopartAccessEvent(-1);
float val = luaL_checknumber(L, 3);
float x = sim->parts[particleID].x;
float y = sim->parts[particleID].y;
@@ -332,6 +334,7 @@ void LuaSetParticleProperty(lua_State *L, int particleID, StructProperty propert
}
else
{
lsi->AssertMonopartAccessEvent(particleID);
LuaSetProperty(L, property, propertyAddress, 3);
}
}
@@ -917,3 +920,12 @@ void LuaScriptInterface::AssertMutableToolsEvent()
luaL_error(L, "this functionality is restricted to mutable tool events");
}
}
void LuaScriptInterface::AssertMonopartAccessEvent(int partID)
{
AssertMutableSimEvent();
if ((eventTraits & eventTraitMonopartAccess) && monopartAccessPartID != partID)
{
luaL_error(L, "particle management is restricted to ID %i", monopartAccessPartID);
}
}

View File

@@ -129,6 +129,7 @@ public:
int textInputRefcount = 0;
long unsigned int luaExecutionStart = 0;
int monopartAccessPartID = -1;
private:
std::vector<std::list<LuaSmartRef>> gameControllerEventHandlers; // must come after luaState
@@ -154,6 +155,7 @@ public:
void AssertInterfaceEvent();
void AssertMutableSimEvent();
void AssertMutableToolsEvent();
void AssertMonopartAccessEvent(int partID);
friend class CommandInterface;
};

View File

@@ -312,7 +312,7 @@ static int partNeighbors(lua_State *L)
static int partChangeType(lua_State *L)
{
auto *lsi = GetLSI();
lsi->AssertMutableSimEvent();
lsi->AssertMonopartAccessEvent(-1);
int partIndex = lua_tointeger(L, 1);
if(partIndex < 0 || partIndex >= NPART || !lsi->sim->parts[partIndex].type)
return 0;
@@ -323,7 +323,7 @@ static int partChangeType(lua_State *L)
static int partCreate(lua_State *L)
{
auto *lsi = GetLSI();
lsi->AssertMutableSimEvent();
lsi->AssertMonopartAccessEvent(-1);
int newID = lua_tointeger(L, 1);
if (newID >= NPART || newID < -3)
{
@@ -386,6 +386,7 @@ static int partPosition(lua_State *L)
{
if(argCount == 1)
{
lsi->AssertMonopartAccessEvent(-1);
lua_pushnil(L);
lua_pushnil(L);
return 2;
@@ -396,7 +397,7 @@ static int partPosition(lua_State *L)
if (argCount == 3)
{
lsi->AssertMutableSimEvent();
lsi->AssertMonopartAccessEvent(-1);
float x = sim->parts[particleID].x;
float y = sim->parts[particleID].y;
sim->move(particleID, (int)(x + 0.5f), (int)(y + 0.5f), lua_tonumber(L, 2), lua_tonumber(L, 3));
@@ -422,7 +423,7 @@ static int partProperty(lua_State *L)
{
if (argCount == 3)
{
lsi->AssertMutableSimEvent();
lsi->AssertMonopartAccessEvent(-1);
return 0;
}
lua_pushnil(L);
@@ -466,7 +467,6 @@ static int partProperty(lua_State *L)
if (argCount == 3)
{
lsi->AssertMutableSimEvent();
LuaSetParticleProperty(L, particleID, *prop, propertyAddress, 3);
return 0;
}
@@ -477,7 +477,7 @@ static int partProperty(lua_State *L)
static int partKill(lua_State *L)
{
auto *lsi = GetLSI();
lsi->AssertMutableSimEvent();
lsi->AssertMonopartAccessEvent(-1);
if(lua_gettop(L)==2)
lsi->sim->delete_part(lua_tointeger(L, 1), lua_tointeger(L, 2));
else