diff options
31 files changed, 617 insertions, 97 deletions
diff --git a/MCServer/Plugins/Core/README.md b/MCServer/Plugins/Core/README.md index d840459a0..418c23b87 100644 --- a/MCServer/Plugins/Core/README.md +++ b/MCServer/Plugins/Core/README.md @@ -1,23 +1,70 @@ -Core Plugin (Forked) -=========== - -A fork of MCServer's Core plugin. - -**New Features:** -* Simplified commands, such as 'gotoworld' -> 'portal' -* Simplified and combined LUA files, such as 'listworlds.lua & gotoworld.lua' -> 'worlds-portal.lua' -* Fixed 'tp' command not working due to typography errors -* Fixed 'arithmetic on nil value' on startup due to inactivation of world limiter -* Massive overhaul / redesign of webadmin GUI interface. - * Added jQuery transition effect - * Completely redesigned CSS - * Added new logo - * Made HTML5 compliant -* Beautified 'help' menu -* Rewrite of death messages - fixed strange grammar and edited to more faithfully reflect Vanilla -* Added 'unban' console command - -**How to Use** - -Simply copy all LUA files into Plugins/Core (delete existing files first, except banned.ini and whitelist.ini!) -Then, copy webadmin to MCServer root directory (delete existing directory first!) +MCServer Core Plugin +==================== + +The Core plugin for MCServer provides the default utility commands and also a lot of WebAdmin goodness. + +Commands +-------- + + * /back + * /ban + * /downfall + * /give + * /gm + * /groups + * /help + * /i + * /item + * /kick + * /locate + * /me + * /motd + * /plugins + * /portal + * /rank + * /regen + * /reload + * /save-all + * /spawn + * /stop + * /time + * /top + * /tp + * /tpa + * /tpaccept + * /unban + * /viewdistance + * /worlds + +**Also, console commands:** + + * ban + * banlist + * getversion + * help + * list + * listgroups + * numchunks + * players + * rank + * reload + * say + * setversion + * unban + * unload + +Contributors +------------ + +FakeTruth +xoft +tigerw +bearbin +tonibm19 + +(If you want your name here, please submit a PR after you've done your contributions.) + +How to Use +---------- + +Core should be installed in MCServer by default. diff --git a/MCServer/Plugins/Core/console.lua b/MCServer/Plugins/Core/console.lua index 59a60ae62..8fd548612 100644 --- a/MCServer/Plugins/Core/console.lua +++ b/MCServer/Plugins/Core/console.lua @@ -5,21 +5,22 @@ function InitConsoleCommands() -- Please keep the list alpha-sorted PluginMgr:BindConsoleCommand("ban", HandleConsoleBan, " ~ Bans a player by name"); - PluginMgr:BindConsoleCommand("unban", HandleConsoleUnban, " ~ Unbans a player by name"); - PluginMgr:BindConsoleCommand("banlist", HandleConsoleBanList, " - Lists all players banned by name"); PluginMgr:BindConsoleCommand("banlist ips", HandleConsoleBanList, " - Lists all players banned by IP"); + PluginMgr:BindConsoleCommand("banlist", HandleConsoleBanList, " - Lists all players banned by name"); + PluginMgr:BindConsoleCommand("getversion", HandleConsoleVersion, " - Gets server version reported to 1.4+ clients"); PluginMgr:BindConsoleCommand("help", HandleConsoleHelp, " - Lists all commands"); PluginMgr:BindConsoleCommand("list", HandleConsoleList, " - Lists all players in a machine-readable format"); PluginMgr:BindConsoleCommand("listgroups", HandleConsoleListGroups, " - Shows a list of all the groups"); PluginMgr:BindConsoleCommand("numchunks", HandleConsoleNumChunks, " - Shows number of chunks currently loaded"); PluginMgr:BindConsoleCommand("players", HandleConsolePlayers, " - Lists all connected players"); - PluginMgr:BindConsoleCommand("getversion", HandleConsoleVersion, " - Gets server version reported to 1.4+ clients"); - PluginMgr:BindConsoleCommand("setversion", HandleConsoleVersion, " ~ Sets server version reported to 1.4+ clients"); PluginMgr:BindConsoleCommand("rank", HandleConsoleRank, " ~ Add a player to a group"); PluginMgr:BindConsoleCommand("reload", HandleConsoleReload, " - Reloads all plugins"); PluginMgr:BindConsoleCommand("save-all", HandleConsoleSaveAll, " - Saves all chunks"); PluginMgr:BindConsoleCommand("say", HandleConsoleSay, " - Sends a chat message to all players"); + PluginMgr:BindConsoleCommand("setversion", HandleConsoleVersion, " ~ Sets server version reported to 1.4+ clients"); + PluginMgr:BindConsoleCommand("unban", HandleConsoleUnban, " ~ Unbans a player by name"); PluginMgr:BindConsoleCommand("unload", HandleConsoleUnload, " - Unloads all unused chunks"); + end function HandleConsoleBan(Split) diff --git a/MCServer/Plugins/Core/give.lua b/MCServer/Plugins/Core/give.lua index d1c7ae59f..ba3a1eb41 100644 --- a/MCServer/Plugins/Core/give.lua +++ b/MCServer/Plugins/Core/give.lua @@ -1,39 +1,65 @@ function HandleGiveCommand(Split, Player) - if ((#Split ~= 2) and (#Split ~=3)) then - Player:SendMessage(cChatColor.Yellow .. "[INFO] " .. cChatColor.White .. "Usage: /give [ItemType/Name:Dmg] <Amount>" ); - return true; + + -- Make sure there are a correct number of arguments. + if #Split ~= 3 and #Split ~= 4 and #Split ~= 5 then + Player:SendMessage( cChatColor.Yellow .. "[INFO] " .. cChatColor.White .. "Usage: /give <player> <item> [amount] [meta]" ) + return true end - local Item = cItem(); - local FoundItem = StringToItem(Split[2], Item); - - if not(IsValidItem(Item.m_ItemType)) then -- StringToItem does not check if item is valid + -- Get the item from the arguments and check it's valid. + local Item = cItem() + if #Split == 5 then + local FoundItem = StringToItem(Split[3] .. ":" .. Split[5], Item) + else + local FoundItem = StringToItem(Split[3], Item) + end + if not IsValidItem(Item.m_ItemType) then -- StringToItem does not check if item is valid FoundItem = false end - if not(FoundItem) then + if not FoundItem then Player:SendMessage(cChatColor.Rose .. "[INFO] " .. cChatColor.White .. "Invalid item id or name!" ) return true end - local ItemAmount = 1; - if (#Split == 3) then - ItemAmount = tonumber(Split[3]); - if ((ItemAmount == nil) or (ItemAmount < 1) or (ItemAmount > 512)) then - Player:SendMessage(cChatColor.Rose .. "[INFO] " .. cChatColor.White .. "Invalid amount!" ); - return true; + -- Work out how many items the user wants. + local ItemAmount = 1 + if #Split > 3 then + ItemAmount = tonumber(Split[4]) + if ItemAmount == nil or ItemAmount < 1 or ItemAmount > 512 then + Player:SendMessage(cChatColor.Rose .. "[INFO] " .. cChatColor.White .. "Invalid amount!" ) + return true end end - Item.m_ItemCount = ItemAmount; + Item.m_ItemCount = ItemAmount - local ItemsGiven = Player:GetInventory():AddItem(Item); - if (ItemsGiven == ItemAmount) then - Player:SendMessage(cChatColor.Green .. "[INFO] " .. cChatColor.White .. "There you go!" ); - LOG("Gave " .. Player:GetName() .. " " .. Item.m_ItemCount .. " times " .. Item.m_ItemType .. ":" .. Item.m_ItemDamage); - else - Player:SendMessage(cChatColor.Rose .. "[INFO] " .. cChatColor.White .. "Not enough space in inventory, only gave " .. ItemsGiven); - LOG("Player " .. Player:GetName() .. " asked for " .. Item.m_ItemCount .. " times " .. Item.m_ItemType .. ":" .. Item.m_ItemDamage ..", but only could fit " .. ItemsGiven); + -- Get the playername from the split. + local playerName = Split[2] + + local function giveItems(newPlayer) + local ItemsGiven = newPlayer:GetInventory():AddItem(Item) + if ItemsGiven == ItemAmount then + newPlayer:SendMessage(cChatColor.Green .. "[INFO] " .. cChatColor.White .. "You were given " .. Item.m_ItemCount .. " of " .. Item.m_ItemType .. "." ) + if not newPlayer == Player then + Player:SendMessage(cChatColor.Green .. "[INFO] " .. cChatColor.White .. "Items given!" ) + end + LOG("Gave " .. newPlayer:GetName() .. " " .. Item.m_ItemCount .. " times " .. Item.m_ItemType .. ":" .. Item.m_ItemDamage) + else + Player:SendMessage( cChatColor.Rose .. "[INFO] " .. cChatColor.White .. "Not enough space in inventory, only gave " .. ItemsGiven) + LOG( "Player " .. Player:GetName() .. " asked for " .. Item.m_ItemCount .. " times " .. Item.m_ItemType .. ":" .. Item.m_ItemDamage ..", but only could fit " .. ItemsGiven ) + end + return true + end + + -- Finally give the items to the player. + itemStatus = cRoot:Get():FindAndDoWithPlayer(playerName, giveItems) + + -- Check to make sure that giving items was successful. + if not itemStatus then + Player:SendMessage( cChatColor.Rose .. "[INFO] " .. cChatColor.White .. "There was no player that matched your query.") end - return true; -end
\ No newline at end of file + + return true + +end diff --git a/MCServer/Plugins/Core/item.lua b/MCServer/Plugins/Core/item.lua new file mode 100644 index 000000000..b665e5208 --- /dev/null +++ b/MCServer/Plugins/Core/item.lua @@ -0,0 +1,24 @@ +function HandleItemCommand(Split, Player) + + if ((#Split ~= 2) and (#Split ~=3)) then + Player:SendMessage(cChatColor.Yellow .. "[INFO] " .. cChatColor.White .. "Usage: /i <item>[:meta] [amount]" ) + return true + end + + itemSplit = StringSplit(Split[2], ":") + + newSplit[1] = "/give" + newSplit[2] = Player:GetName() + newSplit[3] = itemSplit[1] + if Split[3] ~= nil then + newSplit[4] = Split[3] + else + newSplit[4] = 1 + end + if itemSplit[2] ~= nil then + newSplit[5] = itemSplit[2] + end + + HandleGiveCommand(newSplit, Player) + return true +end
\ No newline at end of file diff --git a/MCServer/Plugins/Core/main.lua b/MCServer/Plugins/Core/main.lua index 3fd9c6585..9c476a48c 100644 --- a/MCServer/Plugins/Core/main.lua +++ b/MCServer/Plugins/Core/main.lua @@ -29,12 +29,16 @@ function Initialize(Plugin) --BIND COMMANDS PluginManager:BindCommand("/back", "core.back", HandleBackCommand, " - Return to your last position"); PluginManager:BindCommand("/ban", "core.ban", HandleBanCommand, " ~ Ban a player"); - PluginManager:BindCommand("/give", "core.give", HandleGiveCommand, " ~ Give yourself an item"); + PluginManager:BindCommand("/downfall", "core.downfall", HandleDownfallCommand, " - Toggles the weather"); + PluginManager:BindCommand("/give", "core.give", HandleGiveCommand, " ~ Give someone an item"); PluginManager:BindCommand("/gm", "core.changegm", HandleChangeGMCommand, " ~ Change your gamemode"); + PluginManager:BindCommand("/groups", "core.groups", HandleGroupsCommand, " - Shows a list of all the groups"); PluginManager:BindCommand("/help", "core.help", HandleHelpCommand, " ~ Show available commands"); + PluginManager:BindCommand("/i", "core.give", HandleItemCommand, "") + PluginManager:BindCommand("/item", "core.give", HandleItemCommand, " - Give yourself an item.") PluginManager:BindCommand("/kick", "core.kick", HandleKickCommand, " ~ Kick a player"); - PluginManager:BindCommand("/groups", "core.groups", HandleGroupsCommand, " - Shows a list of all the groups"); PluginManager:BindCommand("/locate", "core.locate", HandleLocateCommand, " - Show your current server coordinates"); + PluginManager:BindCommand("/me", "core.me", HandleMeCommand, " ~ Tell what you are doing"); PluginManager:BindCommand("/motd", "core.motd", HandleMOTDCommand, " - Show message of the day"); PluginManager:BindCommand("/plugins", "core.plugins", HandlePluginsCommand, " - Show list of plugins"); PluginManager:BindCommand("/portal", "core.portal", HandlePortalCommand, " ~ Move to a different world"); @@ -45,8 +49,6 @@ function Initialize(Plugin) PluginManager:BindCommand("/spawn", "core.spawn", HandleSpawnCommand, " - Return to the spawn"); PluginManager:BindCommand("/stop", "core.stop", HandleStopCommand, " - Stops the server"); PluginManager:BindCommand("/time", "core.time", HandleTimeCommand, " ~ Sets the time of day"); - PluginManager:BindCommand("/downfall", "core.downfall", HandleDownfallCommand, " - Toggles the weather"); - PluginManager:BindCommand("/me", "core.me", HandleMeCommand, " ~ Tell what you are doing"); PluginManager:BindCommand("/top", "core.top", HandleTopCommand, " - Teleport yourself to the top most block"); PluginManager:BindCommand("/tp", "core.teleport", HandleTPCommand, " ~ Teleport yourself to a player"); PluginManager:BindCommand("/tpa", "core.teleport", HandleTPACommand, " ~ Ask to teleport yourself to a player"); diff --git a/MCServer/Plugins/Core/time.lua b/MCServer/Plugins/Core/time.lua index b5d3c991a..fd2816f23 100644 --- a/MCServer/Plugins/Core/time.lua +++ b/MCServer/Plugins/Core/time.lua @@ -9,7 +9,7 @@ function HandleTimeCommand( Split, Player ) Server:SendMessage(cChatColor.Green .. "[INFO] " .. cChatColor.White .. "Time was set to daytime" ) elseif( string.upper( Split[2] ) == "NIGHT") then Player:GetWorld():SetTimeOfDay( 12000 + 1000 ) - Server:SendMessage(cChatColor.Green .. "[INFO] " .. cChatColor.White .. "Time was set to nighttime" ) + Server:SendMessage(cChatColor.Green .. "[INFO] " .. cChatColor.White .. "Time was set to night time" ) elseif( string.upper(Split[2]) == "SET" ) and ( tonumber(Split[3]) ~= nil) then Player:GetWorld():SetTimeOfDay( tonumber(Split[3]) ) Server:SendMessage(cChatColor.Green .. "[INFO] " .. cChatColor.White .. "Time was set to " .. Split[3] ) @@ -20,4 +20,4 @@ function HandleTimeCommand( Split, Player ) Player:SendMessage(cChatColor.Yellow .. "[INFO] " .. cChatColor.White .. "Usage: /time [Day/Night/Set/Add]" ) end return true -end
\ No newline at end of file +end diff --git a/MCServer/Plugins/HookNotify/HookNotify.lua b/MCServer/Plugins/HookNotify/HookNotify.lua index 09759451d..6badc63e7 100644 --- a/MCServer/Plugins/HookNotify/HookNotify.lua +++ b/MCServer/Plugins/HookNotify/HookNotify.lua @@ -45,6 +45,10 @@ function Initialize(Plugin) PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_USING_ITEM); PluginManager:AddHook(Plugin, cPluginManager.HOOK_POST_CRAFTING); PluginManager:AddHook(Plugin, cPluginManager.HOOK_PRE_CRAFTING); + PluginManager:AddHook(Plugin, cPluginManager.HOOK_SPAWNED_ENTITY); + PluginManager:AddHook(Plugin, cPluginManager.HOOK_SPAWNED_MONSTER); + PluginManager:AddHook(Plugin, cPluginManager.HOOK_SPAWNING_ENTITY); + PluginManager:AddHook(Plugin, cPluginManager.HOOK_SPAWNING_MONSTER); PluginManager:AddHook(Plugin, cPluginManager.HOOK_TAKE_DAMAGE); PluginManager:AddHook(Plugin, cPluginManager.HOOK_UPDATED_SIGN); PluginManager:AddHook(Plugin, cPluginManager.HOOK_UPDATING_SIGN); @@ -358,6 +362,38 @@ end +function OnSpawnedEntity(...) + LogHook("OnSpawnedEntity", unpack(arg)); +end + + + + + +function OnSpawnedMonster(...) + LogHook("OnSpawnedMonster", unpack(arg)); +end + + + + + +function OnSpawningEntity(...) + LogHook("OnSpawningEntity", unpack(arg)); +end + + + + + +function OnSpawningMonster(...) + LogHook("OnSpawningMonster", unpack(arg)); +end + + + + + function OnUpdatedSign(...) LogHook("OnUpdatedSign", unpack(arg)); end diff --git a/source/AllToLua.pkg b/source/AllToLua.pkg index cd22aba0a..360901ecb 100644 --- a/source/AllToLua.pkg +++ b/source/AllToLua.pkg @@ -59,6 +59,7 @@ $cfile "Generating/ChunkDesc.h" $cfile "CraftingRecipes.h" $cfile "UI/Window.h" $cfile "LuaWindow.h" +$cfile "Mobs/Monster.h" diff --git a/source/Bindings.cpp b/source/Bindings.cpp index fd953e29d..653c01f7f 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/07/13 12:06:03. +** Generated automatically by tolua++-1.0.92 on 08/08/13 09:04:23. */ #ifndef __cplusplus @@ -59,6 +59,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S); #include "CraftingRecipes.h" #include "UI/Window.h" #include "LuaWindow.h" +#include "Mobs/Monster.h" /* function to release collected object via destructor */ #ifdef __cplusplus @@ -203,6 +204,7 @@ static void tolua_reg_types (lua_State* tolua_S) { tolua_usertype(tolua_S,"TakeDamageInfo"); tolua_usertype(tolua_S,"cPlugin_NewLua"); + tolua_usertype(tolua_S,"cMonster"); tolua_usertype(tolua_S,"cCraftingGrid"); tolua_usertype(tolua_S,"cCraftingRecipe"); tolua_usertype(tolua_S,"cPlugin"); @@ -8256,10 +8258,11 @@ static int tolua_AllToLua_cPlayer_Initialize00(lua_State* tolua_S) if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Initialize'", NULL); #endif { - self->Initialize(a_World); + bool tolua_ret = (bool) self->Initialize(a_World); + tolua_pushboolean(tolua_S,(bool)tolua_ret); } } - return 0; + return 1; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'Initialize'.",&tolua_err); @@ -10087,12 +10090,15 @@ static int tolua_AllToLua_cPlayer_SetSprint00(lua_State* tolua_S) class Lua__cPlayer : public cPlayer, public ToluaBase { public: - void Initialize( cWorld* a_World) { + bool Initialize( cWorld* a_World) { if (push_method("Initialize", tolua_AllToLua_cPlayer_Initialize00)) { tolua_pushusertype(lua_state, (void*)a_World, "cWorld"); - ToluaBase::dbcall(lua_state, 2, 0); + ToluaBase::dbcall(lua_state, 2, 1); + bool tolua_ret = ( bool )tolua_toboolean(lua_state, -1, 0); + lua_pop(lua_state, 1); + return tolua_ret; } else { - return ( void ) cPlayer:: Initialize(a_World); + return ( bool ) cPlayer:: Initialize(a_World); }; }; void MoveTo( const Vector3d& a_NewPos) { @@ -10296,8 +10302,8 @@ public: }; }; - void cPlayer__Initialize( cWorld* a_World) { - return ( void )cPlayer::Initialize(a_World); + bool cPlayer__Initialize( cWorld* a_World) { + return ( bool )cPlayer::Initialize(a_World); }; void cPlayer__MoveTo( const Vector3d& a_NewPos) { return ( void )cPlayer::MoveTo(a_NewPos); @@ -10415,10 +10421,11 @@ static int tolua_AllToLua_Lua__cPlayer_cPlayer__Initialize00(lua_State* tolua_S) if (!self) tolua_error(tolua_S,"invalid 'self' in function 'cPlayer__Initialize'", NULL); #endif { - self->cPlayer__Initialize(a_World); + bool tolua_ret = (bool) self->cPlayer__Initialize(a_World); + tolua_pushboolean(tolua_S,(bool)tolua_ret); } } - return 0; + return 1; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'cPlayer__Initialize'.",&tolua_err); @@ -29527,6 +29534,10 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"HOOK_PLAYER_USING_ITEM",cPluginManager::HOOK_PLAYER_USING_ITEM); tolua_constant(tolua_S,"HOOK_POST_CRAFTING",cPluginManager::HOOK_POST_CRAFTING); tolua_constant(tolua_S,"HOOK_PRE_CRAFTING",cPluginManager::HOOK_PRE_CRAFTING); + tolua_constant(tolua_S,"HOOK_SPAWNED_ENTITY",cPluginManager::HOOK_SPAWNED_ENTITY); + tolua_constant(tolua_S,"HOOK_SPAWNED_MONSTER",cPluginManager::HOOK_SPAWNED_MONSTER); + tolua_constant(tolua_S,"HOOK_SPAWNING_ENTITY",cPluginManager::HOOK_SPAWNING_ENTITY); + tolua_constant(tolua_S,"HOOK_SPAWNING_MONSTER",cPluginManager::HOOK_SPAWNING_MONSTER); tolua_constant(tolua_S,"HOOK_TAKE_DAMAGE",cPluginManager::HOOK_TAKE_DAMAGE); tolua_constant(tolua_S,"HOOK_TICK",cPluginManager::HOOK_TICK); tolua_constant(tolua_S,"HOOK_UPDATED_SIGN",cPluginManager::HOOK_UPDATED_SIGN); @@ -30341,6 +30352,9 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetContents",tolua_AllToLua_cLuaWindow_GetContents00); tolua_variable(tolua_S,"__cItemGrid__cListener__",tolua_get_cLuaWindow___cItemGrid__cListener__,NULL); tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cMonster","cMonster","cPawn",NULL); + tolua_beginmodule(tolua_S,"cMonster"); + tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cLineBlockTracer","cLineBlockTracer","",NULL); tolua_beginmodule(tolua_S,"cLineBlockTracer"); tolua_endmodule(tolua_S); diff --git a/source/Bindings.h b/source/Bindings.h index a5654c062..b53029f08 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/07/13 12:06:04. +** Generated automatically by tolua++-1.0.92 on 08/08/13 09:04:23. */ /* Exported function */ diff --git a/source/Entity.cpp b/source/Entity.cpp index 2c822d0cc..8afdfdb95 100644 --- a/source/Entity.cpp +++ b/source/Entity.cpp @@ -129,14 +129,22 @@ const char * cEntity::GetParentClass(void) const -void cEntity::Initialize(cWorld * a_World) +bool cEntity::Initialize(cWorld * a_World) { + if (cPluginManager::Get()->CallHookSpawningEntity(*a_World, *this)) + { + return false; + } + LOGD("Initializing entity #%d (%s) at {%.02f, %.02f, %.02f}", m_UniqueID, GetClass(), m_Pos.x, m_Pos.y, m_Pos.z ); m_IsInitialized = true; m_World = a_World; m_World->AddEntity(this); + + cPluginManager::Get()->CallHookSpawnedEntity(*a_World, *this); + return true; } diff --git a/source/Entity.h b/source/Entity.h index bd66df5f5..c9d26e1a1 100644 --- a/source/Entity.h +++ b/source/Entity.h @@ -107,7 +107,8 @@ public: cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); virtual ~cEntity(); - virtual void Initialize(cWorld * a_World); + /// Spawns the entity in the world; returns true if spawned, false if not (plugin disallowed) + virtual bool Initialize(cWorld * a_World); // tolua_begin diff --git a/source/FallingBlock.cpp b/source/FallingBlock.cpp index 5dc99c771..05766ae01 100644 --- a/source/FallingBlock.cpp +++ b/source/FallingBlock.cpp @@ -22,10 +22,14 @@ cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_Block -void cFallingBlock::Initialize(cWorld * a_World) +bool cFallingBlock::Initialize(cWorld * a_World) { - super::Initialize(a_World); - a_World->BroadcastSpawnEntity(*this); + if (super::Initialize(a_World)) + { + a_World->BroadcastSpawnEntity(*this); + return true; + } + return false; } diff --git a/source/FallingBlock.h b/source/FallingBlock.h index 887ae6268..492931fa3 100644 --- a/source/FallingBlock.h +++ b/source/FallingBlock.h @@ -30,7 +30,7 @@ public: NIBBLETYPE GetBlockMeta(void) const { return m_BlockMeta; } // cEntity overrides: - virtual void Initialize(cWorld * a_World) override; + virtual bool Initialize(cWorld * a_World) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; diff --git a/source/LuaState.cpp b/source/LuaState.cpp index 664ba8147..d4beb249b 100644 --- a/source/LuaState.cpp +++ b/source/LuaState.cpp @@ -396,6 +396,19 @@ void cLuaState::PushObject(cEntity * a_Entity) +void cLuaState::PushObject(cMonster * a_Monster) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushusertype(m_LuaState, a_Monster, "cMonster"); + m_NumCurrentFunctionArgs += 1; +} + + + + + void cLuaState::PushObject(cItem * a_Item) { ASSERT(IsValid()); diff --git a/source/LuaState.h b/source/LuaState.h index 6820f1777..15dbdbc0e 100644 --- a/source/LuaState.h +++ b/source/LuaState.h @@ -36,6 +36,7 @@ extern "C" class cWorld; class cPlayer; class cEntity; +class cMonster; class cItem; class cItems; class cClientHandle; @@ -145,6 +146,7 @@ public: void PushObject(cWorld * a_World); void PushObject(cPlayer * a_Player); void PushObject(cEntity * a_Entity); + void PushObject(cMonster * a_Monster); void PushObject(cItem * a_Item); void PushObject(cItems * a_Items); void PushObject(cClientHandle * a_ClientHandle); diff --git a/source/Minecart.cpp b/source/Minecart.cpp index bae56d582..cffa1b6e0 100644 --- a/source/Minecart.cpp +++ b/source/Minecart.cpp @@ -22,10 +22,14 @@ cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) : -void cMinecart::Initialize(cWorld * a_World) +bool cMinecart::Initialize(cWorld * a_World) { - super::Initialize(a_World); - a_World->BroadcastSpawnEntity(*this); + if (super::Initialize(a_World)) + { + a_World->BroadcastSpawnEntity(*this); + return true; + } + return false; } diff --git a/source/Minecart.h b/source/Minecart.h index b7b4c2b04..e205a4963 100644 --- a/source/Minecart.h +++ b/source/Minecart.h @@ -33,7 +33,7 @@ public: } ; // cEntity overrides: - virtual void Initialize(cWorld * a_World) override; + virtual bool Initialize(cWorld * a_World) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; diff --git a/source/Pickup.cpp b/source/Pickup.cpp index 36322bcfb..217af969c 100644 --- a/source/Pickup.cpp +++ b/source/Pickup.cpp @@ -41,10 +41,14 @@ cPickup::cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem -void cPickup::Initialize(cWorld * a_World) +bool cPickup::Initialize(cWorld * a_World) { - super::Initialize(a_World); - a_World->BroadcastSpawnEntity(*this); + if (super::Initialize(a_World)) + { + a_World->BroadcastSpawnEntity(*this); + return true; + } + return false; } diff --git a/source/Pickup.h b/source/Pickup.h index f37618d2d..dcdc02137 100644 --- a/source/Pickup.h +++ b/source/Pickup.h @@ -26,7 +26,7 @@ public: cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem & a_Item, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f); // tolua_export - virtual void Initialize(cWorld * a_World) override; + virtual bool Initialize(cWorld * a_World) override; cItem & GetItem(void) {return m_Item; } // tolua_export const cItem & GetItem(void) const {return m_Item; } diff --git a/source/Player.cpp b/source/Player.cpp index bbf39f789..fb752ed87 100644 --- a/source/Player.cpp +++ b/source/Player.cpp @@ -40,6 +40,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_IP("") , m_LastBlockActionTime( 0 ) , m_LastBlockActionCnt( 0 ) + , m_AirLevel( MAX_AIR_LEVEL ) + , m_AirTickTimer( DROWNING_TICKS ) , m_bVisible( true ) , m_LastGroundHeight( 0 ) , m_bTouchGround( false ) @@ -121,10 +123,14 @@ cPlayer::~cPlayer(void) -void cPlayer::Initialize(cWorld * a_World) +bool cPlayer::Initialize(cWorld * a_World) { - super::Initialize(a_World); - GetWorld()->AddPlayer(this); + if (super::Initialize(a_World)) + { + GetWorld()->AddPlayer(this); + return true; + } + return false; } @@ -174,6 +180,10 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) } super::Tick(a_Dt, a_Chunk); + + //handle air drowning stuff + HandleAir(a_Chunk); + if (m_bDirtyPosition) { // Apply food exhaustion from movement: @@ -1196,7 +1206,7 @@ bool cPlayer::LoadFromDisk() } m_Health = root.get("health", 0).asInt(); - + m_AirLevel = root.get("air", MAX_AIR_LEVEL).asInt(); m_FoodLevel = root.get("food", MAX_FOOD_LEVEL).asInt(); m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble(); m_FoodTickTimer = root.get("foodTickTimer", 0).asInt(); @@ -1242,6 +1252,7 @@ bool cPlayer::SaveToDisk() root["rotation"] = JSON_PlayerRotation; root["inventory"] = JSON_Inventory; root["health"] = m_Health; + root["air"] = m_AirLevel; root["food"] = m_FoodLevel; root["foodSaturation"] = m_FoodSaturationLevel; root["foodTickTimer"] = m_FoodTickTimer; @@ -1309,7 +1320,42 @@ void cPlayer::UseEquippedItem() } +void cPlayer::HandleAir(cChunk & a_Chunk) +{ + // Ref.: http://www.minecraftwiki.net/wiki/Chunk_format + // see if the player is /submerged/ water (block above is water) + // Get the type of block the player's standing in: + BLOCKTYPE BlockIn; + int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width; + int RelY = (int)floor(m_LastPosY + 1.1); + int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width; + // Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk + VERIFY(a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn)); + if (IsBlockWater(BlockIn)) + { + // either reduce air level or damage player + if(m_AirLevel < 1) + { + if(m_AirTickTimer < 1) + { + // damage player + TakeDamage(dtDrowning, NULL, 1, 1, 0); + // reset timer + m_AirTickTimer = DROWNING_TICKS; + }else{ + m_AirTickTimer -= 1; + } + }else{ + // reduce air supply + m_AirLevel -= 1; + } + }else{ + // set the air back to maximum + m_AirLevel = MAX_AIR_LEVEL; + m_AirTickTimer = DROWNING_TICKS; + } +} void cPlayer::HandleFood(void) diff --git a/source/Player.h b/source/Player.h index eea8c1596..542656b5a 100644 --- a/source/Player.h +++ b/source/Player.h @@ -29,6 +29,8 @@ public: MAX_HEALTH = 20, MAX_FOOD_LEVEL = 20, EATING_TICKS = 30, ///< Number of ticks it takes to eat an item + MAX_AIR_LEVEL = 300, + DROWNING_TICKS = 10, //number of ticks per heart of damage } ; // tolua_end @@ -38,7 +40,7 @@ public: cPlayer(cClientHandle * a_Client, const AString & a_PlayerName); virtual ~cPlayer(); - virtual void Initialize(cWorld * a_World); // tolua_export + virtual bool Initialize(cWorld * a_World); // tolua_export virtual void SpawnOn(cClientHandle & a_Client) override; @@ -160,6 +162,8 @@ public: int GetFoodTickTimer (void) const { return m_FoodTickTimer; } double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; } int GetFoodPoisonedTicksRemaining(void) const { return m_FoodPoisonedTicksRemaining; } + + int GetAirLevel (void) const { return m_AirLevel; } /// Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); } @@ -267,6 +271,11 @@ protected: std::string m_PlayerName; std::string m_LoadedWorldName; + /// Player's air level (for swimming) + int m_AirLevel; + /// used to time ticks between damage taken via drowning/suffocation + int m_AirTickTimer; + bool m_bVisible; // Food-related variables: @@ -329,7 +338,6 @@ protected: /// The world tick in which eating will be finished. -1 if not eating Int64 m_EatingFinishTick; - virtual void Destroyed(void); /// Filters out damage for creative mode @@ -338,6 +346,9 @@ protected: /// Called in each tick to handle food-related processing void HandleFood(void); + /// Called in each tick to handle air-related processing i.e. drowning + void HandleAir(cChunk & a_Chunk); + /// Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block) void ApplyFoodExhaustionFromMovement(cChunk & a_Chunk); } ; // tolua_export diff --git a/source/Plugin.cpp b/source/Plugin.cpp index 20943b916..76110321a 100644 --- a/source/Plugin.cpp +++ b/source/Plugin.cpp @@ -5,6 +5,7 @@ #include "Player.h" #include "World.h" #include "CommandOutput.h" +#include "Mobs/Monster.h" @@ -478,6 +479,50 @@ bool cPlugin::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Gr +bool cPlugin::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity) +{ + UNUSED(a_World); + UNUSED(a_Entity); + return false; +} + + + + + +bool cPlugin::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster) +{ + UNUSED(a_World); + UNUSED(a_Monster); + return false; +} + + + + + +bool cPlugin::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity) +{ + UNUSED(a_World); + UNUSED(a_Entity); + return false; +} + + + + + +bool cPlugin::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster) +{ + UNUSED(a_World); + UNUSED(a_Monster); + return false; +} + + + + + bool cPlugin::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TakeDamageInfo) { UNUSED(a_Receiver); diff --git a/source/Plugin.h b/source/Plugin.h index 0f68273ee..f3d7a1c56 100644 --- a/source/Plugin.h +++ b/source/Plugin.h @@ -80,6 +80,10 @@ public: virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ); virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); + virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity); + virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster); + virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity); + virtual bool OnSpawningMonster (cWorld & a_World, cMonster & a_Monster); virtual bool OnTakeDamage (cEntity & a_Receiver, TakeDamageInfo & a_TakeDamageInfo); virtual bool OnUpdatedSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player); virtual bool OnUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player); diff --git a/source/PluginManager.cpp b/source/PluginManager.cpp index 16b4056f4..5a81cccbc 100644 --- a/source/PluginManager.cpp +++ b/source/PluginManager.cpp @@ -888,6 +888,88 @@ bool cPluginManager::CallHookPreCrafting(const cPlayer * a_Player, const cCrafti +bool cPluginManager::CallHookSpawnedEntity(cWorld & a_World, cEntity & a_Entity) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNED_ENTITY); + if (Plugins == m_Hooks.end()) + { + return false; + } + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnSpawnedEntity(a_World, a_Entity)) + { + return true; + } + } + return false; +} + + + + +bool cPluginManager::CallHookSpawnedMonster(cWorld & a_World, cMonster & a_Monster) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNED_MONSTER); + if (Plugins == m_Hooks.end()) + { + return false; + } + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnSpawnedMonster(a_World, a_Monster)) + { + return true; + } + } + return false; +} + + + + +bool cPluginManager::CallHookSpawningEntity(cWorld & a_World, cEntity & a_Entity) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNING_ENTITY); + if (Plugins == m_Hooks.end()) + { + return false; + } + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnSpawningEntity(a_World, a_Entity)) + { + return true; + } + } + return false; +} + + + + + +bool cPluginManager::CallHookSpawningMonster(cWorld & a_World, cMonster & a_Monster) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNING_MONSTER); + if (Plugins == m_Hooks.end()) + { + return false; + } + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + if ((*itr)->OnSpawningMonster(a_World, a_Monster)) + { + return true; + } + } + return false; +} + + + + + bool cPluginManager::CallHookTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI) { HookMap::iterator Plugins = m_Hooks.find(HOOK_TAKE_DAMAGE); diff --git a/source/PluginManager.h b/source/PluginManager.h index 26bd34dc5..6c3fa81fe 100644 --- a/source/PluginManager.h +++ b/source/PluginManager.h @@ -15,9 +15,12 @@ class cWorld; // fwd: ChunkDesc.h class cChunkDesc; -// fwd: Entityes/Entity.h +// fwd: Entities/Entity.h class cEntity; +// fwd: Mobs/Monster.h +class cMonster; + // fwd: Player.h class cPlayer; @@ -82,6 +85,10 @@ public: // tolua_export HOOK_PLAYER_USING_ITEM, HOOK_POST_CRAFTING, HOOK_PRE_CRAFTING, + HOOK_SPAWNED_ENTITY, + HOOK_SPAWNED_MONSTER, + HOOK_SPAWNING_ENTITY, + HOOK_SPAWNING_MONSTER, HOOK_TAKE_DAMAGE, HOOK_TICK, HOOK_UPDATED_SIGN, @@ -116,8 +123,9 @@ public: // tolua_export void ReloadPlugins(); // tolua_export void AddHook( cPlugin* a_Plugin, PluginHook a_Hook ); // tolua_export - unsigned int GetNumPlugins() const; // tolua_export - + unsigned int GetNumPlugins() const; // tolua_export + + // Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort bool CallHookBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups); bool CallHookChat (cPlayer * a_Player, AString & a_Message); bool CallHookChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ); @@ -151,6 +159,10 @@ public: // tolua_export bool CallHookPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ); bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); + bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity); + bool CallHookSpawnedMonster (cWorld & a_World, cMonster & a_Monster); + bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity); + bool CallHookSpawningMonster (cWorld & a_World, cMonster & a_Monster); bool CallHookTakeDamage (cEntity & a_Receiver, TakeDamageInfo & a_TDI); bool CallHookUpdatedSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player); bool CallHookUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player); diff --git a/source/Plugin_NewLua.cpp b/source/Plugin_NewLua.cpp index 704bb3a95..a85d5aae9 100644 --- a/source/Plugin_NewLua.cpp +++ b/source/Plugin_NewLua.cpp @@ -1102,6 +1102,117 @@ bool cPlugin_NewLua::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid +bool cPlugin_NewLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity) +{ + cCSLock Lock(m_CriticalSection); + const char * FnName = GetHookFnName(cPluginManager::HOOK_SPAWNED_ENTITY); + ASSERT(FnName != NULL); + if (!m_LuaState.PushFunction(FnName)) + { + return false; + } + + m_LuaState.PushObject(&a_World); + m_LuaState.PushObject(&a_Entity); + + if (!m_LuaState.CallFunction(1)) + { + return false; + } + + bool bRetVal = (tolua_toboolean(m_LuaState, -1, 0) > 0); + lua_pop(m_LuaState, 1); + return bRetVal; +} + + + + + +bool cPlugin_NewLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster) +{ + cCSLock Lock(m_CriticalSection); + const char * FnName = GetHookFnName(cPluginManager::HOOK_SPAWNED_MONSTER); + ASSERT(FnName != NULL); + if (!m_LuaState.PushFunction(FnName)) + { + return false; + } + + m_LuaState.PushObject(&a_World); + m_LuaState.PushObject(&a_Monster); + + if (!m_LuaState.CallFunction(1)) + { + return false; + } + + bool bRetVal = (tolua_toboolean(m_LuaState, -1, 0) > 0); + lua_pop(m_LuaState, 1); + return bRetVal; + return false; +} + + + + + +bool cPlugin_NewLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity) +{ + cCSLock Lock(m_CriticalSection); + const char * FnName = GetHookFnName(cPluginManager::HOOK_SPAWNING_ENTITY); + ASSERT(FnName != NULL); + if (!m_LuaState.PushFunction(FnName)) + { + return false; + } + + m_LuaState.PushObject(&a_World); + m_LuaState.PushObject(&a_Entity); + + if (!m_LuaState.CallFunction(1)) + { + return false; + } + + bool bRetVal = (tolua_toboolean(m_LuaState, -1, 0) > 0); + lua_pop(m_LuaState, 1); + return bRetVal; + return false; +} + + + + + +bool cPlugin_NewLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster) +{ + cCSLock Lock(m_CriticalSection); + const char * FnName = GetHookFnName(cPluginManager::HOOK_SPAWNING_MONSTER); + ASSERT(FnName != NULL); + if (!m_LuaState.PushFunction(FnName)) + { + return false; + } + + m_LuaState.PushObject(&a_World); + m_LuaState.PushObject(&a_Monster); + + if (!m_LuaState.CallFunction(1)) + { + return false; + } + + bool bRetVal = (tolua_toboolean(m_LuaState, -1, 0) > 0); + lua_pop(m_LuaState, 1); + return bRetVal; + return false; +} + + + + + bool cPlugin_NewLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI) { cCSLock Lock(m_CriticalSection); @@ -1482,6 +1593,10 @@ const char * cPlugin_NewLua::GetHookFnName(cPluginManager::PluginHook a_Hook) case cPluginManager::HOOK_PLAYER_USING_ITEM: return "OnPlayerUsingItem"; case cPluginManager::HOOK_POST_CRAFTING: return "OnPostCrafting"; case cPluginManager::HOOK_PRE_CRAFTING: return "OnPreCrafting"; + case cPluginManager::HOOK_SPAWNED_ENTITY: return "OnSpawnedEntity"; + case cPluginManager::HOOK_SPAWNED_MONSTER: return "OnSpawnedMonster"; + case cPluginManager::HOOK_SPAWNING_ENTITY: return "OnSpawningEntity"; + case cPluginManager::HOOK_SPAWNING_MONSTER: return "OnSpawningMonster"; case cPluginManager::HOOK_TAKE_DAMAGE: return "OnTakeDamage"; case cPluginManager::HOOK_TICK: return "OnTick"; case cPluginManager::HOOK_UPDATED_SIGN: return "OnUpdatedSign"; diff --git a/source/Plugin_NewLua.h b/source/Plugin_NewLua.h index d31a62601..ba66a9047 100644 --- a/source/Plugin_NewLua.h +++ b/source/Plugin_NewLua.h @@ -68,6 +68,10 @@ public: virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; + virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override; + virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) override; + virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override; + virtual bool OnSpawningMonster (cWorld & a_World, cMonster & a_Monster) override; virtual bool OnTakeDamage (cEntity & a_Receiver, TakeDamageInfo & a_TakeDamageInfo) override; virtual bool OnUpdatedSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player) override; virtual bool OnUpdatingSign (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4, cPlayer * a_Player) override; diff --git a/source/TNTEntity.cpp b/source/TNTEntity.cpp index e431464b3..25e8f19ce 100644 --- a/source/TNTEntity.cpp +++ b/source/TNTEntity.cpp @@ -29,10 +29,14 @@ cTNTEntity::cTNTEntity(const Vector3d & a_Pos, float a_FuseTimeInSec) : -void cTNTEntity::Initialize(cWorld * a_World) +bool cTNTEntity::Initialize(cWorld * a_World) { - super::Initialize(a_World); - a_World->BroadcastSpawnEntity(*this); + if (super::Initialize(a_World)) + { + a_World->BroadcastSpawnEntity(*this); + return true; + } + return false; } diff --git a/source/TNTEntity.h b/source/TNTEntity.h index 5dbfd2d43..a8487b66f 100644 --- a/source/TNTEntity.h +++ b/source/TNTEntity.h @@ -20,7 +20,7 @@ public: cTNTEntity(const Vector3d & a_Pos, float a_FuseTimeInSec); // cEntity overrides: - virtual void Initialize(cWorld * a_World) override; + virtual bool Initialize(cWorld * a_World) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; diff --git a/source/World.cpp b/source/World.cpp index 699767d5e..6a83da489 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -2414,14 +2414,24 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, int a_EntityTy default: { - LOGWARNING("cWorld::SpawnMob(): Unhandled entity type: %d. Not spawning.", a_EntityType); + LOGWARNING("%s: Unhandled entity type: %d. Not spawning.", __FUNCTION__, a_EntityType); return -1; } } Monster->SetPosition(a_PosX, a_PosY, a_PosZ); Monster->SetHealth(Monster->GetMaxHealth()); - Monster->Initialize(this); + if (cPluginManager::Get()->CallHookSpawningMonster(*this, *Monster)) + { + delete Monster; + return -1; + } + if (!Monster->Initialize(this)) + { + delete Monster; + return -1; + } BroadcastSpawnEntity(*Monster); + cPluginManager::Get()->CallHookSpawnedMonster(*this, *Monster); return Monster->GetUniqueID(); } |