Allow scripting of instances w/ persistent data

Some fixes for TC and changes overall

Pass map object to hook via function arguments

The map object is no longer stored inside the instance data table.

Fix mistake in base64 decoder

It was failing whenever it encountered a '=' character, which is
completely valid.

Make ElunaInstanceAI::Load always load something

When it failed to load data, it was leaving nothing on the stack. Since
subsequent code expected Load to always load something, this was causing
issues.

Now, when Load fails to load anything, it just leaves a new empty table on
the stack.

Also: the error messages for Load have been improved.

Modify lua-marshal to allow saving of functions/userdata.

Some additional code was needed to save functions due to the inclusion of
a reference to _ENV within their upvalues (since Lua 5.2).

During encoding, a placeholder is left where the _ENV reference would be.
During decoding, a reference to the current _G is swapped with the
placeholder.

Make ElunaInstanceAI::Load re-initialize if data failed to load.

Also improve error messages by not including the raw data.

Improve storage format of upvalues

Instead of storing the upvalues by name, store by index. A wrapper is
still used in case the upvalue is nil, to prevent holes in the upvalues table.

A special field in the upvalues table, "E", is used to store the index of
the _ENV reference (if there was one). A reference to the current globals
table is set as the upvalue upon decoding.

Remove wrapping from upvalue storing, instead save amount of upvalues
This commit is contained in:
Patman64
2015-01-18 21:53:50 -05:00
committed by Rochet2
parent d57ca139b7
commit 31470c2cf7
14 changed files with 1564 additions and 25 deletions

View File

@@ -499,7 +499,7 @@ namespace LuaGlobalFunctions
static int RegisterEntryHelper(Eluna* E, lua_State* L, int regtype)
{
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
uint32 id = Eluna::CHECKVAL<uint32>(L, 1);
uint32 ev = Eluna::CHECKVAL<uint32>(L, 2);
luaL_checktype(L, 3, LUA_TFUNCTION);
uint32 shots = Eluna::CHECKVAL<uint32>(L, 4, 0);
@@ -507,7 +507,7 @@ namespace LuaGlobalFunctions
lua_pushvalue(L, 3);
int functionRef = luaL_ref(L, LUA_REGISTRYINDEX);
if (functionRef >= 0)
return E->Register(L, regtype, entry, 0, 0, ev, functionRef, shots);
return E->Register(L, regtype, id, 0, 0, ev, functionRef, shots);
else
luaL_argerror(L, 3, "unable to make a ref to function");
return 0;
@@ -923,6 +923,60 @@ namespace LuaGlobalFunctions
return RegisterEntryHelper(E, L, Hooks::REGTYPE_ITEM_GOSSIP);
}
/**
* Registers a [Map] event handler for all instance of a [Map].
*
* <pre>
* enum InstanceEvents
* {
* INSTANCE_EVENT_ON_INITIALIZE = 1, // (event, instance_data, map)
* INSTANCE_EVENT_ON_LOAD = 2, // (event, instance_data, map)
* INSTANCE_EVENT_ON_UPDATE = 3, // (event, instance_data, map, diff)
* INSTANCE_EVENT_ON_PLAYER_ENTER = 4, // (event, instance_data, map, player)
* INSTANCE_EVENT_ON_CREATURE_CREATE = 5, // (event, instance_data, map, creature)
* INSTANCE_EVENT_ON_GAMEOBJECT_CREATE = 6, // (event, instance_data, map, go)
* INSTANCE_EVENT_ON_CHECK_ENCOUNTER_IN_PROGRESS = 7, // (event, instance_data, map)
* INSTANCE_EVENT_COUNT
* };
* </pre>
*
* @param uint32 map_id : ID of a [Map]
* @param uint32 event : [Map] event ID, refer to MapEvents above
* @param function function : function to register
* @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function"
*/
int RegisterMapEvent(Eluna* E, lua_State* L)
{
return RegisterEntryHelper(E, L, Hooks::REGTYPE_MAP);
}
/**
* Registers a [Map] event handler for one instance of a [Map].
*
* <pre>
* enum InstanceEvents
* {
* INSTANCE_EVENT_ON_INITIALIZE = 1, // (event, instance_data, map)
* INSTANCE_EVENT_ON_LOAD = 2, // (event, instance_data, map)
* INSTANCE_EVENT_ON_UPDATE = 3, // (event, instance_data, map, diff)
* INSTANCE_EVENT_ON_PLAYER_ENTER = 4, // (event, instance_data, map, player)
* INSTANCE_EVENT_ON_CREATURE_CREATE = 5, // (event, instance_data, map, creature)
* INSTANCE_EVENT_ON_GAMEOBJECT_CREATE = 6, // (event, instance_data, map, go)
* INSTANCE_EVENT_ON_CHECK_ENCOUNTER_IN_PROGRESS = 7, // (event, instance_data, map)
* INSTANCE_EVENT_COUNT
* };
* </pre>
*
* @param uint32 instance_id : ID of an instance of a [Map]
* @param uint32 event : [Map] event ID, refer to MapEvents above
* @param function function : function to register
* @param uint32 shots = 0 : the number of times the function will be called, 0 means "always call this function"
*/
int RegisterInstanceEvent(Eluna* E, lua_State* L)
{
return RegisterEntryHelper(E, L, Hooks::REGTYPE_INSTANCE);
}
/**
* Registers a [Player] gossip event handler.
*
@@ -2898,5 +2952,71 @@ namespace LuaGlobalFunctions
}
return 0;
}
/**
* Unbinds event handlers for either all of a non-instanced [Map]'s events, or one type of event.
*
* If `event_type` is `nil`, all the non-instanced [Map]'s event handlers are cleared.
*
* Otherwise, only event handlers for `event_type` are cleared.
*
* @proto (map_id)
* @proto (map_id, event_type)
* @param uint32 map_id : the ID of a [Map]
* @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterPlayerGossipEvent]
*/
int ClearMapEvents(Eluna* E, lua_State* L)
{
typedef EntryKey<Hooks::InstanceEvents> Key;
if (lua_isnoneornil(L, 2))
{
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
for (uint32 i = 1; i < Hooks::INSTANCE_EVENT_COUNT; ++i)
E->MapEventBindings->Clear(Key((Hooks::InstanceEvents)i, entry));
}
else
{
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2);
E->MapEventBindings->Clear(Key((Hooks::InstanceEvents)event_type, entry));
}
return 0;
}
/**
* Unbinds event handlers for either all of an instanced [Map]'s events, or one type of event.
*
* If `event_type` is `nil`, all the instanced [Map]'s event handlers are cleared.
*
* Otherwise, only event handlers for `event_type` are cleared.
*
* @proto (instance_id)
* @proto (instance_id, event_type)
* @param uint32 entry : the ID of an instance of a [Map]
* @param uint32 event_type : the event whose handlers will be cleared, see [Global:RegisterPlayerGossipEvent]
*/
int ClearInstanceEvents(Eluna* E, lua_State* L)
{
typedef EntryKey<Hooks::InstanceEvents> Key;
if (lua_isnoneornil(L, 2))
{
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
for (uint32 i = 1; i < Hooks::INSTANCE_EVENT_COUNT; ++i)
E->InstanceEventBindings->Clear(Key((Hooks::InstanceEvents)i, entry));
}
else
{
uint32 entry = Eluna::CHECKVAL<uint32>(L, 1);
uint32 event_type = Eluna::CHECKVAL<uint32>(L, 2);
E->InstanceEventBindings->Clear(Key((Hooks::InstanceEvents)event_type, entry));
}
return 0;
}
}
#endif