Crash Adding New LUA Function

Discussions on development of both the EQ2Emulator LUA Script Engine and Script specifications

Moderator: Team Members

Post Reply
User avatar
Scatman
Retired
Posts: 1688
Joined: Wed Apr 16, 2008 5:44 am
EQ2Emu Server: Scatman's Word
Characters: Scatman
Location: New Jersey

Crash Adding New LUA Function

Post by Scatman » Wed Dec 10, 2008 10:47 am

LE, I added the following LUA spell:

Code: Select all

Index: LuaFunctions.cpp
===================================================================
--- LuaFunctions.cpp	(revision 175)
+++ LuaFunctions.cpp	(working copy)
@@ -102,6 +102,16 @@
 	return 0;
 }
 
+int EQ2Emu_lua_KillSpawn(lua_State* state) {
+	Spawn* dead = lua_interface->GetSpawn(state);
+	Spawn* killer = lua_interface->GetSpawn(state, 2);
+
+	if (dead && dead->GetZone())
+		dead->GetZone()->KillSpawn(dead, killer);
+
+	return 0;
+}
+
 int EQ2Emu_lua_KillSpawnByDistance(lua_State* state){
 	Spawn* spawn = lua_interface->GetSpawn(state);
 	float max_distance = lua_interface->GetFloatValue(state, 2);
Index: LuaFunctions.h
===================================================================
--- LuaFunctions.h	(revision 175)
+++ LuaFunctions.h	(working copy)
@@ -65,6 +65,7 @@
 int EQ2Emu_lua_GetLootCoin(lua_State* state);
 int EQ2Emu_lua_GetSpawn(lua_State* state);
 int EQ2Emu_lua_SpawnSet(lua_State* state);
+int EQ2Emu_lua_KillSpawn(lua_State* state);
 int EQ2Emu_lua_KillSpawnByDistance(lua_State* state);
 int EQ2Emu_lua_SpawnSetByDistance(lua_State* state);
 int EQ2Emu_lua_SetRequiredQuest(lua_State* state);
Index: LuaInterface.cpp
===================================================================
--- LuaInterface.cpp	(revision 175)
+++ LuaInterface.cpp	(working copy)
@@ -447,6 +447,7 @@
 	lua_register(state, "StartConversation", EQ2Emu_lua_StartConversation);
 	lua_register(state, "SpawnSet", EQ2Emu_lua_SpawnSet);
 	lua_register(state, "SpawnSetByDistance", EQ2Emu_lua_SpawnSetByDistance);
+	lua_register(state, "KillSpawn", EQ2Emu_lua_KillSpawn);
 	lua_register(state, "KillSpawnByDistance", EQ2Emu_lua_KillSpawnByDistance);
 
 	lua_register(state, "SetRequiredQuest", EQ2Emu_lua_SetRequiredQuest);
Sorry, Fileshare wouldn't let me upload a file then let you view it, you had to download it to view it. We tested a script out last night that used KillSpawn() and it all worked except we get a crash at the end. John sent this:

Code: Select all

>   EQ2WorldDebug.exe!operator delete(void * pUserData=0xdddddddd)  Line 52 + 0x3 bytes   C++
    EQ2WorldDebug.exe!Timer::`scalar deleting destructor'()  + 0x25 bytes   C++
    EQ2WorldDebug.exe!ZoneServer::CheckSpawnScriptTimers()  Line 1755 + 0x35 bytes   C++
    EQ2WorldDebug.exe!ZoneServer::Process()  Line 653   C++
    EQ2WorldDebug.exe!ZoneLoop(void * tmp=0x06f48540)  Line 2504 + 0x8 bytes   C++
    EQ2WorldDebug.exe!_callthreadstart()  Line 293 + 0xf bytes   C
    EQ2WorldDebug.exe!_threadstart(void * ptd=0x06f49110)  Line 277   C
    kernel32.dll!77e64829()    
    [Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]    
I tried to look up what was going on but couldn't, for the life of me, figure out what was wrong. I tried searching the error and people on forums said this error is usually some kind of warning but it's clearly a crash. :P

LethalEncounter
Team: Zombie
Posts: 2717
Joined: Wed Jul 25, 2007 10:10 pm

Post by LethalEncounter » Wed Dec 10, 2008 3:39 pm

Could you also paste your script that was causing it to crash? It looks like the timer wasn't getting initialized correctly or was destroyed twice, just need to find out how.

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Post by John Adams » Wed Dec 10, 2008 4:33 pm

I think this is what you're asking for:
spawnscript:

Code: Select all

function spawn(NPC) 
   --uncomment to require quest 
   --SetRequiredQuest(NPC, 31, 2)
end 
function destroy_totem(NPC, Player)
   KillSpawn(NPC, Player)
end 
function enable_command_icon(NPC, Player) 
   SpawnSet(NPC, "show_command_icon", "1") 
end 
spell:

Code: Select all

function cast(Caster, Target) 
   KillSpawn = GetSpawn(Target, 2530197)
   AddTimer(Target, 1000, "destroy_totem")
   SpawnSet(Target, "destroy_totem", "0") 
   SpawnSet(Target, "show_command_icon", "0") 
end 
Last edited by John Adams on Wed Dec 10, 2008 4:43 pm, edited 1 time in total.

User avatar
Scatman
Retired
Posts: 1688
Joined: Wed Apr 16, 2008 5:44 am
EQ2Emu Server: Scatman's Word
Characters: Scatman
Location: New Jersey

Post by Scatman » Wed Dec 10, 2008 4:41 pm

Note, you'll want to change the SpawnScript that calls KillSpawn from KillSpawn(Player, NPC) to KillSpawn(NPC, Player). I changed the order the parameters are taken to be consistent with everything else.

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Post by John Adams » Wed Dec 10, 2008 4:45 pm

Ok Scat, I changed the posted script as you suggested. Please edit or repost whatever else you may see wrong so LE has accurate info.

LethalEncounter
Team: Zombie
Posts: 2717
Joined: Wed Jul 25, 2007 10:10 pm

Post by LethalEncounter » Wed Dec 10, 2008 4:53 pm

John Adams wrote:I think this is what you're asking for:
spawnscript:

Code: Select all

function spawn(NPC) 
   --uncomment to require quest 
   --SetRequiredQuest(NPC, 31, 2)
end 
function destroy_totem(NPC, Player)
   KillSpawn(NPC, Player)
end 
function enable_command_icon(NPC, Player) 
   SpawnSet(NPC, "show_command_icon", "1") 
end 
spell:

Code: Select all

function cast(Caster, Target) 
   KillSpawn = GetSpawn(Target, 2530197)
   AddTimer(Target, 1000, "destroy_totem")
   SpawnSet(Target, "destroy_totem", "0") 
   SpawnSet(Target, "show_command_icon", "0") 
end 

One thing I see right away is:

Code: Select all

SpawnSet(Target, "destroy_totem", "0")
That is invalid as the second argument is the parameter you would give /spawn set and there isn't a /spawn set destroy_totem option :)

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Post by John Adams » Wed Dec 10, 2008 5:33 pm

LE, let me tell ya what we're really after here. KillSpawn() was a necessary add only because we can certainly see needing to kill something remotely :) But I think what we're after with these totems is the ability to "despawn" it after the [destroy totem] command is executed. I believe in live, when you destroy these totems, the player performs a Kick, the totem poofs, and the quest gets updated.
What I do not remember is if there is some other animation that happens - does the totem crumble? fall over? or just vanish? The latter will work for us immediately.
In the end, Despawn() might be the best solution here. I will go try and find the world-crashing bug so at least you can plug that hole, whether the param is right or not, I suppose we shouldn't crash. :)
Edit: here's the crash with the dev svn code:

Code: Select all

>	EQ2WorldDebug.exe!operator delete(void * pUserData=0xdddddddd)  Line 52 + 0x3 bytes	C++
 	EQ2WorldDebug.exe!Timer::`scalar deleting destructor'()  + 0x25 bytes	C++
 	EQ2WorldDebug.exe!ZoneServer::CheckSpawnScriptTimers()  Line 1755 + 0x35 bytes	C++
 	EQ2WorldDebug.exe!ZoneServer::Process()  Line 653	C++
 	EQ2WorldDebug.exe!ZoneLoop(void * tmp=0x083ff860)  Line 2503 + 0x8 bytes	C++
 	EQ2WorldDebug.exe!_callthreadstart()  Line 293 + 0xf bytes	C
 	EQ2WorldDebug.exe!_threadstart(void * ptd=0x08848098)  Line 277	C
 	kernel32.dll!77e64829() 	
 	[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]	

User avatar
Scatman
Retired
Posts: 1688
Joined: Wed Apr 16, 2008 5:44 am
EQ2Emu Server: Scatman's Word
Characters: Scatman
Location: New Jersey

Post by Scatman » Wed Dec 10, 2008 6:04 pm

After kicking the totem, you immediately get the update. The totem stays there, untargettable for about 4 seconds then just poofs, no other animation. This is exactly what happens when you /kill the totem, quest updates immediately (using a kill update quest function) after kicking it, totem sits there for a few seconds, then poofs. So killing it would be just as good too I think, otherwise we'd have to figure out how to update the quest if we just de-spawned it?

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Post by John Adams » Wed Dec 10, 2008 6:06 pm

If there is a delay, just like /kill, then perhaps that's what SOE does. I just assumed it would leave me mystified as the player as to why I just destroyed something that is still lingering around =)
I haven't ran that quest in 6 mos, so it's probably just my foggy memory at play. I'll take Scats word over mine anyday.
(though a Despawn() function would still be nice :p)

LethalEncounter
Team: Zombie
Posts: 2717
Joined: Wed Jul 25, 2007 10:10 pm

Post by LethalEncounter » Wed Dec 10, 2008 6:07 pm

OK, I see the problem. Your timer was killing the same spawn that the timer was based on. When a spawn dies it automatically deletes any timers associated it, so when it died it deleted the timer and when your timer finished it tried to delete itself (again). I fixed the code and I'll also add a despawn function. I just finished that quest on live a couple of days ago but I can't remember if they just disappeared or if they did something else first.

LethalEncounter
Team: Zombie
Posts: 2717
Joined: Wed Jul 25, 2007 10:10 pm

Post by LethalEncounter » Wed Dec 10, 2008 6:14 pm

BTW if might make it a little more clear if your

Code: Select all

function destroy_totem(NPC, Player)
   KillSpawn(NPC, Player)
end
was

Code: Select all

function destroy_totem(Dead, Killer)
   KillSpawn(Dead, Killer)
end
instead. It performs the same but might give you less headaches when trying to debug something. Feel free to do it as you like, just a thought :) Oh and if you want to use the second parameter to KillSpawn you will need to specify the second spawn in your AddTimer LUA call. It is is 5th parameter in the AddTimer function:

Code: Select all

AddTimer(Spawn, time, function, max count, Spawn)

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Post by John Adams » Wed Dec 10, 2008 6:17 pm

I'm diggin the whole Dead, Killer thing... adds mystique to our development personas... ;)

LethalEncounter
Team: Zombie
Posts: 2717
Joined: Wed Jul 25, 2007 10:10 pm

Post by LethalEncounter » Wed Dec 10, 2008 6:30 pm

heh, btw note that I am adding a few optional parameters:

Code: Select all

KillSpawn(Dead (Spawn), Killer (Spawn), send death packet (0 or 1))
KillSpawnByDistance(Killer (Spawn), distance around (float), include players (0 or 1), send death packets (0 or 1))
Examples:
KillSpawn(NPC, Player, 0) -- player kills NPC but doesnt send death packet or no message in their chat
KillSpawnByDistance(NPC, 10, 1, 1) -- kills everything around the NPC including players, also sends death messages for everything killed
Remember that NPC == Spawn, Player == Spawn, and any name you substitute in place of Spawn is still a Spawn.

LethalEncounter
Team: Zombie
Posts: 2717
Joined: Wed Jul 25, 2007 10:10 pm

Post by LethalEncounter » Wed Dec 10, 2008 6:43 pm

OK, I also added Despawn(Spawn, delay). Delay is optional and will be immediate if you leave it off.

User avatar
John Adams
Retired
Posts: 9684
Joined: Thu Jul 26, 2007 6:27 am
EQ2Emu Server: EQ2Emulator Test Center
Characters: John
Location: Arizona
Contact:

Post by John Adams » Wed Dec 10, 2008 6:45 pm

Right on, thanks LE!

Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests