diff options
Diffstat (limited to 'source')
56 files changed, 4012 insertions, 1475 deletions
diff --git a/source/AllToLua.pkg b/source/AllToLua.pkg index 98c58ed0a..8d87be307 100644 --- a/source/AllToLua.pkg +++ b/source/AllToLua.pkg @@ -27,6 +27,8 @@ $cfile "ClientHandle.h" $cfile "Entities/Entity.h" $cfile "Entities/Pawn.h" $cfile "Entities/Player.h" +$cfile "Entities/Pickup.h" +$cfile "Entities/ProjectileEntity.h" $cfile "PluginManager.h" $cfile "Plugin.h" $cfile "PluginLua.h" @@ -45,7 +47,6 @@ $cfile "BlockEntities/DropperEntity.h" $cfile "BlockEntities/FurnaceEntity.h" $cfile "WebAdmin.h" $cfile "WebPlugin.h" -$cfile "Entities/Pickup.h" $cfile "Root.h" $cfile "Vector3f.h" $cfile "Vector3d.h" diff --git a/source/Bindings.cpp b/source/Bindings.cpp index effb9c6ed..d89592bcf 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/19/13 11:57:26. +** Generated automatically by tolua++-1.0.92 on 09/01/13 14:42:04. */ #ifndef __cplusplus @@ -27,6 +27,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S); #include "Entities/Entity.h" #include "Entities/Pawn.h" #include "Entities/Player.h" +#include "Entities/Pickup.h" +#include "Entities/ProjectileEntity.h" #include "PluginManager.h" #include "Plugin.h" #include "PluginLua.h" @@ -45,7 +47,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S); #include "BlockEntities/FurnaceEntity.h" #include "WebAdmin.h" #include "WebPlugin.h" -#include "Entities/Pickup.h" #include "Root.h" #include "Vector3f.h" #include "Vector3d.h" @@ -202,9 +203,14 @@ static int tolua_collect_Vector3d (lua_State* tolua_S) /* function to register type */ static void tolua_reg_types (lua_State* tolua_S) { + tolua_usertype(tolua_S,"cThrownEnderPearlEntity"); tolua_usertype(tolua_S,"TakeDamageInfo"); + tolua_usertype(tolua_S,"cPluginManager"); + tolua_usertype(tolua_S,"cMonster"); + tolua_usertype(tolua_S,"cCraftingGrid"); tolua_usertype(tolua_S,"cCraftingRecipe"); tolua_usertype(tolua_S,"cPlugin"); + tolua_usertype(tolua_S,"cWindow"); tolua_usertype(tolua_S,"cStringMap"); tolua_usertype(tolua_S,"cItemGrid"); tolua_usertype(tolua_S,"cBlockArea"); @@ -212,51 +218,51 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cLuaWindow"); tolua_usertype(tolua_S,"cServer"); tolua_usertype(tolua_S,"cRoot"); - tolua_usertype(tolua_S,"cDropperEntity"); + tolua_usertype(tolua_S,"cCuboid"); tolua_usertype(tolua_S,"std::vector<cIniFile::key>"); - tolua_usertype(tolua_S,"cMonster"); + tolua_usertype(tolua_S,"cGroup"); tolua_usertype(tolua_S,"cPickup"); tolua_usertype(tolua_S,"std::vector<std::string>"); - tolua_usertype(tolua_S,"cWindow"); + tolua_usertype(tolua_S,"cTracer"); tolua_usertype(tolua_S,"cClientHandle"); tolua_usertype(tolua_S,"cChunkDesc"); tolua_usertype(tolua_S,"cFurnaceRecipe"); - tolua_usertype(tolua_S,"cCraftingGrid"); - tolua_usertype(tolua_S,"cChatColor"); - tolua_usertype(tolua_S,"cGroup"); - tolua_usertype(tolua_S,"cTracer"); - tolua_usertype(tolua_S,"cCuboid"); tolua_usertype(tolua_S,"Vector3i"); - tolua_usertype(tolua_S,"cInventory"); + tolua_usertype(tolua_S,"cChatColor"); + tolua_usertype(tolua_S,"cThrownSnowballEntity"); + tolua_usertype(tolua_S,"cWebAdmin"); + tolua_usertype(tolua_S,"cCraftingRecipes"); + tolua_usertype(tolua_S,"cItems"); + tolua_usertype(tolua_S,"cWebPlugin"); tolua_usertype(tolua_S,"cItem"); tolua_usertype(tolua_S,"Vector3f"); - tolua_usertype(tolua_S,"cCraftingRecipes"); + tolua_usertype(tolua_S,"cArrowEntity"); tolua_usertype(tolua_S,"cDropSpenserEntity"); - tolua_usertype(tolua_S,"cWorld"); - tolua_usertype(tolua_S,"cWebPlugin"); + tolua_usertype(tolua_S,"sWebAdminPage"); + tolua_usertype(tolua_S,"HTTPFormData"); tolua_usertype(tolua_S,"cChestEntity"); tolua_usertype(tolua_S,"cDispenserEntity"); - tolua_usertype(tolua_S,"cWebAdmin"); + tolua_usertype(tolua_S,"HTTPRequest"); tolua_usertype(tolua_S,"cBlockEntity"); - tolua_usertype(tolua_S,"cCriticalSection"); + tolua_usertype(tolua_S,"cItemGrid::cListener"); tolua_usertype(tolua_S,"HTTPTemplateRequest"); - tolua_usertype(tolua_S,"sWebAdminPage"); - tolua_usertype(tolua_S,"HTTPRequest"); - tolua_usertype(tolua_S,"HTTPFormData"); tolua_usertype(tolua_S,"cFurnaceEntity"); + tolua_usertype(tolua_S,"cDropperEntity"); + tolua_usertype(tolua_S,"cPluginLua"); + tolua_usertype(tolua_S,"cBlockEntityWithItems"); tolua_usertype(tolua_S,"cLineBlockTracer"); - tolua_usertype(tolua_S,"cPluginManager"); + tolua_usertype(tolua_S,"cCriticalSection"); tolua_usertype(tolua_S,"cIniFile"); - tolua_usertype(tolua_S,"cBlockEntityWithItems"); + tolua_usertype(tolua_S,"cEntity"); tolua_usertype(tolua_S,"cListeners"); tolua_usertype(tolua_S,"cPawn"); - tolua_usertype(tolua_S,"cPlayer"); + tolua_usertype(tolua_S,"cThrownEggEntity"); tolua_usertype(tolua_S,"cGroupManager"); tolua_usertype(tolua_S,"cBlockEntityWindowOwner"); - tolua_usertype(tolua_S,"cEntity"); - tolua_usertype(tolua_S,"cItemGrid::cListener"); - tolua_usertype(tolua_S,"cPluginLua"); - tolua_usertype(tolua_S,"cItems"); + tolua_usertype(tolua_S,"cInventory"); + tolua_usertype(tolua_S,"cProjectileEntity"); + tolua_usertype(tolua_S,"cWorld"); + tolua_usertype(tolua_S,"cPlayer"); tolua_usertype(tolua_S,"Vector3d"); } @@ -3075,6 +3081,182 @@ static int tolua_set_AllToLua_g_BlockOneHitDig(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* get function: g_BlockPistonBreakable */ +#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockPistonBreakable +static int tolua_get_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S) +{ + int tolua_index; +#ifndef TOLUA_RELEASE + { + tolua_Error tolua_err; + if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) + tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + } +#endif + tolua_index = (int)tolua_tonumber(tolua_S,2,0); +#ifndef TOLUA_RELEASE + if (tolua_index<0 || tolua_index>=256) + tolua_error(tolua_S,"array indexing out of range.",NULL); +#endif + tolua_pushboolean(tolua_S,(bool)g_BlockPistonBreakable[tolua_index]); + return 1; +} +#endif //#ifndef TOLUA_DISABLE + +/* set function: g_BlockPistonBreakable */ +#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockPistonBreakable +static int tolua_set_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S) +{ + int tolua_index; +#ifndef TOLUA_RELEASE + { + tolua_Error tolua_err; + if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) + tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + } +#endif + tolua_index = (int)tolua_tonumber(tolua_S,2,0); +#ifndef TOLUA_RELEASE + if (tolua_index<0 || tolua_index>=256) + tolua_error(tolua_S,"array indexing out of range.",NULL); +#endif + g_BlockPistonBreakable[tolua_index] = ((bool) tolua_toboolean(tolua_S,3,0)); + return 0; +} +#endif //#ifndef TOLUA_DISABLE + +/* get function: g_BlockIsSnowable */ +#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSnowable +static int tolua_get_AllToLua_g_BlockIsSnowable(lua_State* tolua_S) +{ + int tolua_index; +#ifndef TOLUA_RELEASE + { + tolua_Error tolua_err; + if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) + tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + } +#endif + tolua_index = (int)tolua_tonumber(tolua_S,2,0); +#ifndef TOLUA_RELEASE + if (tolua_index<0 || tolua_index>=256) + tolua_error(tolua_S,"array indexing out of range.",NULL); +#endif + tolua_pushboolean(tolua_S,(bool)g_BlockIsSnowable[tolua_index]); + return 1; +} +#endif //#ifndef TOLUA_DISABLE + +/* set function: g_BlockIsSnowable */ +#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockIsSnowable +static int tolua_set_AllToLua_g_BlockIsSnowable(lua_State* tolua_S) +{ + int tolua_index; +#ifndef TOLUA_RELEASE + { + tolua_Error tolua_err; + if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) + tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + } +#endif + tolua_index = (int)tolua_tonumber(tolua_S,2,0); +#ifndef TOLUA_RELEASE + if (tolua_index<0 || tolua_index>=256) + tolua_error(tolua_S,"array indexing out of range.",NULL); +#endif + g_BlockIsSnowable[tolua_index] = ((bool) tolua_toboolean(tolua_S,3,0)); + return 0; +} +#endif //#ifndef TOLUA_DISABLE + +/* get function: g_BlockRequiresSpecialTool */ +#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockRequiresSpecialTool +static int tolua_get_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S) +{ + int tolua_index; +#ifndef TOLUA_RELEASE + { + tolua_Error tolua_err; + if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) + tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + } +#endif + tolua_index = (int)tolua_tonumber(tolua_S,2,0); +#ifndef TOLUA_RELEASE + if (tolua_index<0 || tolua_index>=256) + tolua_error(tolua_S,"array indexing out of range.",NULL); +#endif + tolua_pushboolean(tolua_S,(bool)g_BlockRequiresSpecialTool[tolua_index]); + return 1; +} +#endif //#ifndef TOLUA_DISABLE + +/* set function: g_BlockRequiresSpecialTool */ +#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockRequiresSpecialTool +static int tolua_set_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S) +{ + int tolua_index; +#ifndef TOLUA_RELEASE + { + tolua_Error tolua_err; + if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) + tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + } +#endif + tolua_index = (int)tolua_tonumber(tolua_S,2,0); +#ifndef TOLUA_RELEASE + if (tolua_index<0 || tolua_index>=256) + tolua_error(tolua_S,"array indexing out of range.",NULL); +#endif + g_BlockRequiresSpecialTool[tolua_index] = ((bool) tolua_toboolean(tolua_S,3,0)); + return 0; +} +#endif //#ifndef TOLUA_DISABLE + +/* get function: g_BlockIsSolid */ +#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSolid +static int tolua_get_AllToLua_g_BlockIsSolid(lua_State* tolua_S) +{ + int tolua_index; +#ifndef TOLUA_RELEASE + { + tolua_Error tolua_err; + if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) + tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + } +#endif + tolua_index = (int)tolua_tonumber(tolua_S,2,0); +#ifndef TOLUA_RELEASE + if (tolua_index<0 || tolua_index>=256) + tolua_error(tolua_S,"array indexing out of range.",NULL); +#endif + tolua_pushboolean(tolua_S,(bool)g_BlockIsSolid[tolua_index]); + return 1; +} +#endif //#ifndef TOLUA_DISABLE + +/* set function: g_BlockIsSolid */ +#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockIsSolid +static int tolua_set_AllToLua_g_BlockIsSolid(lua_State* tolua_S) +{ + int tolua_index; +#ifndef TOLUA_RELEASE + { + tolua_Error tolua_err; + if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) + tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + } +#endif + tolua_index = (int)tolua_tonumber(tolua_S,2,0); +#ifndef TOLUA_RELEASE + if (tolua_index<0 || tolua_index>=256) + tolua_error(tolua_S,"array indexing out of range.",NULL); +#endif + g_BlockIsSolid[tolua_index] = ((bool) tolua_toboolean(tolua_S,3,0)); + return 0; +} +#endif //#ifndef TOLUA_DISABLE + /* function: ClickActionToString */ #ifndef TOLUA_DISABLE_tolua_AllToLua_ClickActionToString00 static int tolua_AllToLua_ClickActionToString00(lua_State* tolua_S) @@ -7471,6 +7653,92 @@ static int tolua_AllToLua_cPlayer_GetEquippedItem00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: GetThrowStartPos of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetThrowStartPos00 +static int tolua_AllToLua_cPlayer_GetThrowStartPos00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cPlayer",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cPlayer* self = (const cPlayer*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetThrowStartPos'", NULL); +#endif + { + Vector3d tolua_ret = (Vector3d) self->GetThrowStartPos(); + { +#ifdef __cplusplus + void* tolua_obj = Mtolua_new((Vector3d)(tolua_ret)); + tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#else + void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3d)); + tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#endif + } + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetThrowStartPos'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetThrowSpeed of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetThrowSpeed00 +static int tolua_AllToLua_cPlayer_GetThrowSpeed00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cPlayer",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cPlayer* self = (const cPlayer*) tolua_tousertype(tolua_S,1,0); + double a_SpeedCoeff = ((double) tolua_tonumber(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetThrowSpeed'", NULL); +#endif + { + Vector3d tolua_ret = (Vector3d) self->GetThrowSpeed(a_SpeedCoeff); + { +#ifdef __cplusplus + void* tolua_obj = Mtolua_new((Vector3d)(tolua_ret)); + tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#else + void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3d)); + tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#endif + } + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetThrowSpeed'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetGameMode of class cPlayer */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetGameMode00 static int tolua_AllToLua_cPlayer_GetGameMode00(lua_State* tolua_S) @@ -8545,12 +8813,12 @@ static int tolua_AllToLua_cPlayer_SetFoodExhaustionLevel00(lua_State* tolua_S) #endif { cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); - double a_FoodSaturationLevel = ((double) tolua_tonumber(tolua_S,2,0)); + double a_FoodExhaustionLevel = ((double) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetFoodExhaustionLevel'", NULL); #endif { - self->SetFoodExhaustionLevel(a_FoodSaturationLevel); + self->SetFoodExhaustionLevel(a_FoodExhaustionLevel); } } return 0; @@ -9182,6 +9450,513 @@ static int tolua_AllToLua_cPlayer_IsSubmerged00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: new of class cPickup */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_new00 +static int tolua_AllToLua_cPickup_new00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cPickup",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + (tolua_isvaluenil(tolua_S,5,&tolua_err) || !tolua_isusertype(tolua_S,5,"const cItem",0,&tolua_err)) || + !tolua_isnumber(tolua_S,6,1,&tolua_err) || + !tolua_isnumber(tolua_S,7,1,&tolua_err) || + !tolua_isnumber(tolua_S,8,1,&tolua_err) || + !tolua_isnoobj(tolua_S,9,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + int a_MicroPosX = ((int) tolua_tonumber(tolua_S,2,0)); + int a_MicroPosY = ((int) tolua_tonumber(tolua_S,3,0)); + int a_MicroPosZ = ((int) tolua_tonumber(tolua_S,4,0)); + const cItem* a_Item = ((const cItem*) tolua_tousertype(tolua_S,5,0)); + float a_SpeedX = ((float) tolua_tonumber(tolua_S,6,0.f)); + float a_SpeedY = ((float) tolua_tonumber(tolua_S,7,0.f)); + float a_SpeedZ = ((float) tolua_tonumber(tolua_S,8,0.f)); + { + cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_MicroPosX,a_MicroPosY,a_MicroPosZ,*a_Item,a_SpeedX,a_SpeedY,a_SpeedZ)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cPickup"); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: new_local of class cPickup */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_new00_local +static int tolua_AllToLua_cPickup_new00_local(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cPickup",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + (tolua_isvaluenil(tolua_S,5,&tolua_err) || !tolua_isusertype(tolua_S,5,"const cItem",0,&tolua_err)) || + !tolua_isnumber(tolua_S,6,1,&tolua_err) || + !tolua_isnumber(tolua_S,7,1,&tolua_err) || + !tolua_isnumber(tolua_S,8,1,&tolua_err) || + !tolua_isnoobj(tolua_S,9,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + int a_MicroPosX = ((int) tolua_tonumber(tolua_S,2,0)); + int a_MicroPosY = ((int) tolua_tonumber(tolua_S,3,0)); + int a_MicroPosZ = ((int) tolua_tonumber(tolua_S,4,0)); + const cItem* a_Item = ((const cItem*) tolua_tousertype(tolua_S,5,0)); + float a_SpeedX = ((float) tolua_tonumber(tolua_S,6,0.f)); + float a_SpeedY = ((float) tolua_tonumber(tolua_S,7,0.f)); + float a_SpeedZ = ((float) tolua_tonumber(tolua_S,8,0.f)); + { + cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_MicroPosX,a_MicroPosY,a_MicroPosZ,*a_Item,a_SpeedX,a_SpeedY,a_SpeedZ)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cPickup"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetItem of class cPickup */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_GetItem00 +static int tolua_AllToLua_cPickup_GetItem00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cPickup",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cPickup* self = (cPickup*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetItem'", NULL); +#endif + { + cItem& tolua_ret = (cItem&) self->GetItem(); + tolua_pushusertype(tolua_S,(void*)&tolua_ret,"cItem"); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetItem'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: CollectedBy of class cPickup */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_CollectedBy00 +static int tolua_AllToLua_cPickup_CollectedBy00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cPickup",0,&tolua_err) || + !tolua_isusertype(tolua_S,2,"cPlayer",0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cPickup* self = (cPickup*) tolua_tousertype(tolua_S,1,0); + cPlayer* a_Dest = ((cPlayer*) tolua_tousertype(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'CollectedBy'", NULL); +#endif + { + bool tolua_ret = (bool) self->CollectedBy(a_Dest); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'CollectedBy'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetAge of class cPickup */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_GetAge00 +static int tolua_AllToLua_cPickup_GetAge00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cPickup",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cPickup* self = (const cPickup*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetAge'", NULL); +#endif + { + int tolua_ret = (int) self->GetAge(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetAge'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: IsCollected of class cPickup */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_IsCollected00 +static int tolua_AllToLua_cPickup_IsCollected00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cPickup",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cPickup* self = (const cPickup*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsCollected'", NULL); +#endif + { + bool tolua_ret = (bool) self->IsCollected(); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'IsCollected'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetProjectileKind of class cProjectileEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cProjectileEntity_GetProjectileKind00 +static int tolua_AllToLua_cProjectileEntity_GetProjectileKind00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cProjectileEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cProjectileEntity* self = (const cProjectileEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetProjectileKind'", NULL); +#endif + { + cProjectileEntity::eKind tolua_ret = (cProjectileEntity::eKind) self->GetProjectileKind(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetProjectileKind'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetCreator of class cProjectileEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cProjectileEntity_GetCreator00 +static int tolua_AllToLua_cProjectileEntity_GetCreator00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cProjectileEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cProjectileEntity* self = (cProjectileEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetCreator'", NULL); +#endif + { + cEntity* tolua_ret = (cEntity*) self->GetCreator(); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cEntity"); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetCreator'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetMCAClassName of class cProjectileEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cProjectileEntity_GetMCAClassName00 +static int tolua_AllToLua_cProjectileEntity_GetMCAClassName00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cProjectileEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cProjectileEntity* self = (const cProjectileEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetMCAClassName'", NULL); +#endif + { + AString tolua_ret = (AString) self->GetMCAClassName(); + tolua_pushcppstring(tolua_S,(const char*)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetMCAClassName'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: IsInGround of class cProjectileEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cProjectileEntity_IsInGround00 +static int tolua_AllToLua_cProjectileEntity_IsInGround00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cProjectileEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cProjectileEntity* self = (const cProjectileEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsInGround'", NULL); +#endif + { + bool tolua_ret = (bool) self->IsInGround(); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'IsInGround'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetPickupState of class cArrowEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_GetPickupState00 +static int tolua_AllToLua_cArrowEntity_GetPickupState00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cArrowEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cArrowEntity* self = (const cArrowEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPickupState'", NULL); +#endif + { + cArrowEntity::ePickupState tolua_ret = (cArrowEntity::ePickupState) self->GetPickupState(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetPickupState'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: SetPickupState of class cArrowEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_SetPickupState00 +static int tolua_AllToLua_cArrowEntity_SetPickupState00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cArrowEntity",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cArrowEntity* self = (cArrowEntity*) tolua_tousertype(tolua_S,1,0); + cArrowEntity::ePickupState a_PickupState = ((cArrowEntity::ePickupState) (int) tolua_tonumber(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetPickupState'", NULL); +#endif + { + self->SetPickupState(a_PickupState); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'SetPickupState'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetDamageCoeff of class cArrowEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_GetDamageCoeff00 +static int tolua_AllToLua_cArrowEntity_GetDamageCoeff00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cArrowEntity",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cArrowEntity* self = (const cArrowEntity*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetDamageCoeff'", NULL); +#endif + { + double tolua_ret = (double) self->GetDamageCoeff(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetDamageCoeff'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: SetDamageCoeff of class cArrowEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_SetDamageCoeff00 +static int tolua_AllToLua_cArrowEntity_SetDamageCoeff00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cArrowEntity",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cArrowEntity* self = (cArrowEntity*) tolua_tousertype(tolua_S,1,0); + double a_DamageCoeff = ((double) tolua_tonumber(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetDamageCoeff'", NULL); +#endif + { + self->SetDamageCoeff(a_DamageCoeff); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'SetDamageCoeff'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: CanPickup of class cArrowEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_CanPickup00 +static int tolua_AllToLua_cArrowEntity_CanPickup00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cArrowEntity",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const cPlayer",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cArrowEntity* self = (const cArrowEntity*) tolua_tousertype(tolua_S,1,0); + const cPlayer* a_Player = ((const cPlayer*) tolua_tousertype(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'CanPickup'", NULL); +#endif + { + bool tolua_ret = (bool) self->CanPickup(*a_Player); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'CanPickup'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: Get of class cPluginManager */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_Get00 static int tolua_AllToLua_cPluginManager_Get00(lua_State* tolua_S) @@ -9307,41 +10082,6 @@ static int tolua_AllToLua_cPluginManager_ReloadPlugins00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: AddHook of class cPluginManager */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_AddHook00 -static int tolua_AllToLua_cPluginManager_AddHook00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cPluginManager",0,&tolua_err) || - !tolua_isusertype(tolua_S,2,"cPlugin",0,&tolua_err) || - !tolua_isnumber(tolua_S,3,0,&tolua_err) || - !tolua_isnoobj(tolua_S,4,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0); - cPlugin* a_Plugin = ((cPlugin*) tolua_tousertype(tolua_S,2,0)); - cPluginManager::PluginHook a_Hook = ((cPluginManager::PluginHook) (int) tolua_tonumber(tolua_S,3,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'AddHook'", NULL); -#endif - { - self->AddHook(a_Plugin,a_Hook); - } - } - return 0; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'AddHook'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: GetNumPlugins of class cPluginManager */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_GetNumPlugins00 static int tolua_AllToLua_cPluginManager_GetNumPlugins00(lua_State* tolua_S) @@ -10543,6 +11283,95 @@ static int tolua_AllToLua_cWorld_BroadcastChat00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: BroadcastSoundEffect of class cWorld */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_BroadcastSoundEffect00 +static int tolua_AllToLua_cWorld_BroadcastSoundEffect00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) || + !tolua_iscppstring(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnumber(tolua_S,5,0,&tolua_err) || + !tolua_isnumber(tolua_S,6,0,&tolua_err) || + !tolua_isnumber(tolua_S,7,0,&tolua_err) || + !tolua_isusertype(tolua_S,8,"const cClientHandle",1,&tolua_err) || + !tolua_isnoobj(tolua_S,9,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0); + const AString a_SoundName = ((const AString) tolua_tocppstring(tolua_S,2,0)); + int a_SrcX = ((int) tolua_tonumber(tolua_S,3,0)); + int a_SrcY = ((int) tolua_tonumber(tolua_S,4,0)); + int a_SrcZ = ((int) tolua_tonumber(tolua_S,5,0)); + float a_Volume = ((float) tolua_tonumber(tolua_S,6,0)); + float a_Pitch = ((float) tolua_tonumber(tolua_S,7,0)); + const cClientHandle* a_Exclude = ((const cClientHandle*) tolua_tousertype(tolua_S,8,NULL)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'BroadcastSoundEffect'", NULL); +#endif + { + self->BroadcastSoundEffect(a_SoundName,a_SrcX,a_SrcY,a_SrcZ,a_Volume,a_Pitch,a_Exclude); + tolua_pushcppstring(tolua_S,(const char*)a_SoundName); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'BroadcastSoundEffect'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: BroadcastSoundParticleEffect of class cWorld */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_BroadcastSoundParticleEffect00 +static int tolua_AllToLua_cWorld_BroadcastSoundParticleEffect00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnumber(tolua_S,5,0,&tolua_err) || + !tolua_isnumber(tolua_S,6,0,&tolua_err) || + !tolua_isusertype(tolua_S,7,"const cClientHandle",1,&tolua_err) || + !tolua_isnoobj(tolua_S,8,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0); + int a_EffectID = ((int) tolua_tonumber(tolua_S,2,0)); + int a_SrcX = ((int) tolua_tonumber(tolua_S,3,0)); + int a_SrcY = ((int) tolua_tonumber(tolua_S,4,0)); + int a_SrcZ = ((int) tolua_tonumber(tolua_S,5,0)); + int a_Data = ((int) tolua_tonumber(tolua_S,6,0)); + const cClientHandle* a_Exclude = ((const cClientHandle*) tolua_tousertype(tolua_S,7,NULL)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'BroadcastSoundParticleEffect'", NULL); +#endif + { + self->BroadcastSoundParticleEffect(a_EffectID,a_SrcX,a_SrcY,a_SrcZ,a_Data,a_Exclude); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'BroadcastSoundParticleEffect'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: UnloadUnusedChunks of class cWorld */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_UnloadUnusedChunks00 static int tolua_AllToLua_cWorld_UnloadUnusedChunks00(lua_State* tolua_S) @@ -11982,6 +12811,38 @@ static int tolua_AllToLua_cWorld_GetName00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: GetIniFileName of class cWorld */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GetIniFileName00 +static int tolua_AllToLua_cWorld_GetIniFileName00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cWorld",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cWorld* self = (const cWorld*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetIniFileName'", NULL); +#endif + { + const AString tolua_ret = (const AString) self->GetIniFileName(); + tolua_pushcppstring(tolua_S,(const char*)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetIniFileName'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: SaveAllChunks of class cWorld */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_SaveAllChunks00 static int tolua_AllToLua_cWorld_SaveAllChunks00(lua_State* tolua_S) @@ -12555,6 +13416,50 @@ static int tolua_AllToLua_cWorld_SpawnMob00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: CreateProjectile of class cWorld */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_CreateProjectile00 +static int tolua_AllToLua_cWorld_CreateProjectile00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnumber(tolua_S,5,0,&tolua_err) || + !tolua_isusertype(tolua_S,6,"cEntity",0,&tolua_err) || + !tolua_isusertype(tolua_S,7,"const Vector3d",1,&tolua_err) || + !tolua_isnoobj(tolua_S,8,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0); + double a_PosX = ((double) tolua_tonumber(tolua_S,2,0)); + double a_PosY = ((double) tolua_tonumber(tolua_S,3,0)); + double a_PosZ = ((double) tolua_tonumber(tolua_S,4,0)); + cProjectileEntity::eKind a_Kind = ((cProjectileEntity::eKind) (int) tolua_tonumber(tolua_S,5,0)); + cEntity* a_Creator = ((cEntity*) tolua_tousertype(tolua_S,6,0)); + const Vector3d* a_Speed = ((const Vector3d*) tolua_tousertype(tolua_S,7,NULL)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'CreateProjectile'", NULL); +#endif + { + int tolua_ret = (int) self->CreateProjectile(a_PosX,a_PosY,a_PosZ,a_Kind,a_Creator,a_Speed); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'CreateProjectile'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: Clear of class cInventory */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cInventory_Clear00 static int tolua_AllToLua_cInventory_Clear00(lua_State* tolua_S) @@ -17892,221 +18797,6 @@ static int tolua_AllToLua_cWebPlugin_SafeString00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: new of class cPickup */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_new00 -static int tolua_AllToLua_cPickup_new00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertable(tolua_S,1,"cPickup",0,&tolua_err) || - !tolua_isnumber(tolua_S,2,0,&tolua_err) || - !tolua_isnumber(tolua_S,3,0,&tolua_err) || - !tolua_isnumber(tolua_S,4,0,&tolua_err) || - (tolua_isvaluenil(tolua_S,5,&tolua_err) || !tolua_isusertype(tolua_S,5,"const cItem",0,&tolua_err)) || - !tolua_isnumber(tolua_S,6,1,&tolua_err) || - !tolua_isnumber(tolua_S,7,1,&tolua_err) || - !tolua_isnumber(tolua_S,8,1,&tolua_err) || - !tolua_isnoobj(tolua_S,9,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - int a_MicroPosX = ((int) tolua_tonumber(tolua_S,2,0)); - int a_MicroPosY = ((int) tolua_tonumber(tolua_S,3,0)); - int a_MicroPosZ = ((int) tolua_tonumber(tolua_S,4,0)); - const cItem* a_Item = ((const cItem*) tolua_tousertype(tolua_S,5,0)); - float a_SpeedX = ((float) tolua_tonumber(tolua_S,6,0.f)); - float a_SpeedY = ((float) tolua_tonumber(tolua_S,7,0.f)); - float a_SpeedZ = ((float) tolua_tonumber(tolua_S,8,0.f)); - { - cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_MicroPosX,a_MicroPosY,a_MicroPosZ,*a_Item,a_SpeedX,a_SpeedY,a_SpeedZ)); - tolua_pushusertype(tolua_S,(void*)tolua_ret,"cPickup"); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - -/* method: new_local of class cPickup */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_new00_local -static int tolua_AllToLua_cPickup_new00_local(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertable(tolua_S,1,"cPickup",0,&tolua_err) || - !tolua_isnumber(tolua_S,2,0,&tolua_err) || - !tolua_isnumber(tolua_S,3,0,&tolua_err) || - !tolua_isnumber(tolua_S,4,0,&tolua_err) || - (tolua_isvaluenil(tolua_S,5,&tolua_err) || !tolua_isusertype(tolua_S,5,"const cItem",0,&tolua_err)) || - !tolua_isnumber(tolua_S,6,1,&tolua_err) || - !tolua_isnumber(tolua_S,7,1,&tolua_err) || - !tolua_isnumber(tolua_S,8,1,&tolua_err) || - !tolua_isnoobj(tolua_S,9,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - int a_MicroPosX = ((int) tolua_tonumber(tolua_S,2,0)); - int a_MicroPosY = ((int) tolua_tonumber(tolua_S,3,0)); - int a_MicroPosZ = ((int) tolua_tonumber(tolua_S,4,0)); - const cItem* a_Item = ((const cItem*) tolua_tousertype(tolua_S,5,0)); - float a_SpeedX = ((float) tolua_tonumber(tolua_S,6,0.f)); - float a_SpeedY = ((float) tolua_tonumber(tolua_S,7,0.f)); - float a_SpeedZ = ((float) tolua_tonumber(tolua_S,8,0.f)); - { - cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_MicroPosX,a_MicroPosY,a_MicroPosZ,*a_Item,a_SpeedX,a_SpeedY,a_SpeedZ)); - tolua_pushusertype(tolua_S,(void*)tolua_ret,"cPickup"); - tolua_register_gc(tolua_S,lua_gettop(tolua_S)); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - -/* method: GetItem of class cPickup */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_GetItem00 -static int tolua_AllToLua_cPickup_GetItem00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cPickup",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cPickup* self = (cPickup*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetItem'", NULL); -#endif - { - cItem& tolua_ret = (cItem&) self->GetItem(); - tolua_pushusertype(tolua_S,(void*)&tolua_ret,"cItem"); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'GetItem'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - -/* method: CollectedBy of class cPickup */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_CollectedBy00 -static int tolua_AllToLua_cPickup_CollectedBy00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cPickup",0,&tolua_err) || - !tolua_isusertype(tolua_S,2,"cPlayer",0,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cPickup* self = (cPickup*) tolua_tousertype(tolua_S,1,0); - cPlayer* a_Dest = ((cPlayer*) tolua_tousertype(tolua_S,2,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'CollectedBy'", NULL); -#endif - { - bool tolua_ret = (bool) self->CollectedBy(a_Dest); - tolua_pushboolean(tolua_S,(bool)tolua_ret); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'CollectedBy'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - -/* method: GetAge of class cPickup */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_GetAge00 -static int tolua_AllToLua_cPickup_GetAge00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"const cPickup",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - const cPickup* self = (const cPickup*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetAge'", NULL); -#endif - { - int tolua_ret = (int) self->GetAge(); - tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'GetAge'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - -/* method: IsCollected of class cPickup */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_IsCollected00 -static int tolua_AllToLua_cPickup_IsCollected00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"const cPickup",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - const cPickup* self = (const cPickup*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsCollected'", NULL); -#endif - { - bool tolua_ret = (bool) self->IsCollected(); - tolua_pushboolean(tolua_S,(bool)tolua_ret); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'IsCollected'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* get function: m_PrimaryServerVersion of class cRoot */ #ifndef TOLUA_DISABLE_tolua_get_cRoot_m_PrimaryServerVersion static int tolua_get_cRoot_m_PrimaryServerVersion(lua_State* tolua_S) @@ -20404,6 +21094,50 @@ tolua_lerror: } #endif //#ifndef TOLUA_DISABLE +/* method: operator/ of class Vector3d */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_Vector3d__div00 +static int tolua_AllToLua_Vector3d__div00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const Vector3d",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const Vector3d* self = (const Vector3d*) tolua_tousertype(tolua_S,1,0); + const double f = ((const double) tolua_tonumber(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'operator/'", NULL); +#endif + { + Vector3d tolua_ret = (Vector3d) self->operator/(f); + { +#ifdef __cplusplus + void* tolua_obj = Mtolua_new((Vector3d)(tolua_ret)); + tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#else + void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3d)); + tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#endif + } + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function '.div'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* get function: x of class Vector3d */ #ifndef TOLUA_DISABLE_tolua_get_Vector3d_x static int tolua_get_Vector3d_x(lua_State* tolua_S) @@ -27433,6 +28167,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"E_ITEM_WAIT_DISC",E_ITEM_WAIT_DISC); tolua_constant(tolua_S,"E_ITEM_LAST_DISC_PLUS_ONE",E_ITEM_LAST_DISC_PLUS_ONE); tolua_constant(tolua_S,"E_ITEM_LAST_DISC",E_ITEM_LAST_DISC); + tolua_constant(tolua_S,"E_ITEM_LAST",E_ITEM_LAST); tolua_constant(tolua_S,"E_META_CHEST_FACING_ZM",E_META_CHEST_FACING_ZM); tolua_constant(tolua_S,"E_META_CHEST_FACING_ZP",E_META_CHEST_FACING_ZP); tolua_constant(tolua_S,"E_META_CHEST_FACING_XM",E_META_CHEST_FACING_XM); @@ -27691,6 +28426,10 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_array(tolua_S,"g_BlockSpreadLightFalloff",tolua_get_AllToLua_g_BlockSpreadLightFalloff,tolua_set_AllToLua_g_BlockSpreadLightFalloff); tolua_array(tolua_S,"g_BlockTransparent",tolua_get_AllToLua_g_BlockTransparent,tolua_set_AllToLua_g_BlockTransparent); tolua_array(tolua_S,"g_BlockOneHitDig",tolua_get_AllToLua_g_BlockOneHitDig,tolua_set_AllToLua_g_BlockOneHitDig); + tolua_array(tolua_S,"g_BlockPistonBreakable",tolua_get_AllToLua_g_BlockPistonBreakable,tolua_set_AllToLua_g_BlockPistonBreakable); + tolua_array(tolua_S,"g_BlockIsSnowable",tolua_get_AllToLua_g_BlockIsSnowable,tolua_set_AllToLua_g_BlockIsSnowable); + tolua_array(tolua_S,"g_BlockRequiresSpecialTool",tolua_get_AllToLua_g_BlockRequiresSpecialTool,tolua_set_AllToLua_g_BlockRequiresSpecialTool); + tolua_array(tolua_S,"g_BlockIsSolid",tolua_get_AllToLua_g_BlockIsSolid,tolua_set_AllToLua_g_BlockIsSolid); tolua_constant(tolua_S,"BLOCK_FACE_NONE",BLOCK_FACE_NONE); tolua_constant(tolua_S,"BLOCK_FACE_BOTTOM",BLOCK_FACE_BOTTOM); tolua_constant(tolua_S,"BLOCK_FACE_TOP",BLOCK_FACE_TOP); @@ -27842,10 +28581,11 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"etPlayer",cEntity::etPlayer); tolua_constant(tolua_S,"etPickup",cEntity::etPickup); tolua_constant(tolua_S,"etMonster",cEntity::etMonster); - tolua_constant(tolua_S,"etMob",cEntity::etMob); tolua_constant(tolua_S,"etFallingBlock",cEntity::etFallingBlock); tolua_constant(tolua_S,"etMinecart",cEntity::etMinecart); tolua_constant(tolua_S,"etTNT",cEntity::etTNT); + tolua_constant(tolua_S,"etProjectile",cEntity::etProjectile); + tolua_constant(tolua_S,"etMob",cEntity::etMob); tolua_constant(tolua_S,"eEntityType_Entity",cEntity::eEntityType_Entity); tolua_constant(tolua_S,"eEntityType_Player",cEntity::eEntityType_Player); tolua_constant(tolua_S,"eEntityType_Pickup",cEntity::eEntityType_Pickup); @@ -27954,6 +28694,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetStance",tolua_AllToLua_cPlayer_GetStance00); tolua_function(tolua_S,"GetInventory",tolua_AllToLua_cPlayer_GetInventory00); tolua_function(tolua_S,"GetEquippedItem",tolua_AllToLua_cPlayer_GetEquippedItem00); + tolua_function(tolua_S,"GetThrowStartPos",tolua_AllToLua_cPlayer_GetThrowStartPos00); + tolua_function(tolua_S,"GetThrowSpeed",tolua_AllToLua_cPlayer_GetThrowSpeed00); tolua_function(tolua_S,"GetGameMode",tolua_AllToLua_cPlayer_GetGameMode00); tolua_function(tolua_S,"SetGameMode",tolua_AllToLua_cPlayer_SetGameMode00); tolua_function(tolua_S,"IsGameModeCreative",tolua_AllToLua_cPlayer_IsGameModeCreative00); @@ -28007,6 +28749,57 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"IsSwimming",tolua_AllToLua_cPlayer_IsSwimming00); tolua_function(tolua_S,"IsSubmerged",tolua_AllToLua_cPlayer_IsSubmerged00); tolua_endmodule(tolua_S); + #ifdef __cplusplus + tolua_cclass(tolua_S,"cPickup","cPickup","cEntity",tolua_collect_cPickup); + #else + tolua_cclass(tolua_S,"cPickup","cPickup","cEntity",NULL); + #endif + tolua_beginmodule(tolua_S,"cPickup"); + tolua_function(tolua_S,"new",tolua_AllToLua_cPickup_new00); + tolua_function(tolua_S,"new_local",tolua_AllToLua_cPickup_new00_local); + tolua_function(tolua_S,".call",tolua_AllToLua_cPickup_new00_local); + tolua_function(tolua_S,"GetItem",tolua_AllToLua_cPickup_GetItem00); + tolua_function(tolua_S,"CollectedBy",tolua_AllToLua_cPickup_CollectedBy00); + tolua_function(tolua_S,"GetAge",tolua_AllToLua_cPickup_GetAge00); + tolua_function(tolua_S,"IsCollected",tolua_AllToLua_cPickup_IsCollected00); + tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cProjectileEntity","cProjectileEntity","cEntity",NULL); + tolua_beginmodule(tolua_S,"cProjectileEntity"); + tolua_constant(tolua_S,"pkArrow",cProjectileEntity::pkArrow); + tolua_constant(tolua_S,"pkSnowball",cProjectileEntity::pkSnowball); + tolua_constant(tolua_S,"pkEgg",cProjectileEntity::pkEgg); + tolua_constant(tolua_S,"pkGhastFireball",cProjectileEntity::pkGhastFireball); + tolua_constant(tolua_S,"pkFireCharge",cProjectileEntity::pkFireCharge); + tolua_constant(tolua_S,"pkEnderPearl",cProjectileEntity::pkEnderPearl); + tolua_constant(tolua_S,"pkExpBottle",cProjectileEntity::pkExpBottle); + tolua_constant(tolua_S,"pkSplashPotion",cProjectileEntity::pkSplashPotion); + tolua_constant(tolua_S,"pkWitherSkull",cProjectileEntity::pkWitherSkull); + tolua_constant(tolua_S,"pkFishingFloat",cProjectileEntity::pkFishingFloat); + tolua_function(tolua_S,"GetProjectileKind",tolua_AllToLua_cProjectileEntity_GetProjectileKind00); + tolua_function(tolua_S,"GetCreator",tolua_AllToLua_cProjectileEntity_GetCreator00); + tolua_function(tolua_S,"GetMCAClassName",tolua_AllToLua_cProjectileEntity_GetMCAClassName00); + tolua_function(tolua_S,"IsInGround",tolua_AllToLua_cProjectileEntity_IsInGround00); + tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cArrowEntity","cArrowEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cArrowEntity"); + tolua_constant(tolua_S,"psNoPickup",cArrowEntity::psNoPickup); + tolua_constant(tolua_S,"psInSurvivalOrCreative",cArrowEntity::psInSurvivalOrCreative); + tolua_constant(tolua_S,"psInCreative",cArrowEntity::psInCreative); + tolua_function(tolua_S,"GetPickupState",tolua_AllToLua_cArrowEntity_GetPickupState00); + tolua_function(tolua_S,"SetPickupState",tolua_AllToLua_cArrowEntity_SetPickupState00); + tolua_function(tolua_S,"GetDamageCoeff",tolua_AllToLua_cArrowEntity_GetDamageCoeff00); + tolua_function(tolua_S,"SetDamageCoeff",tolua_AllToLua_cArrowEntity_SetDamageCoeff00); + tolua_function(tolua_S,"CanPickup",tolua_AllToLua_cArrowEntity_CanPickup00); + tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cThrownEggEntity","cThrownEggEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cThrownEggEntity"); + tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cThrownEnderPearlEntity","cThrownEnderPearlEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cThrownEnderPearlEntity"); + tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cThrownSnowballEntity","cThrownSnowballEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cThrownSnowballEntity"); + tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cPluginManager","cPluginManager","",NULL); tolua_beginmodule(tolua_S,"cPluginManager"); tolua_constant(tolua_S,"HOOK_BLOCK_TO_PICKUPS",cPluginManager::HOOK_BLOCK_TO_PICKUPS); @@ -28058,11 +28851,12 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"HOOK_WEATHER_CHANGED",cPluginManager::HOOK_WEATHER_CHANGED); tolua_constant(tolua_S,"HOOK_WEATHER_CHANGING",cPluginManager::HOOK_WEATHER_CHANGING); tolua_constant(tolua_S,"HOOK_WORLD_TICK",cPluginManager::HOOK_WORLD_TICK); + tolua_constant(tolua_S,"HOOK_NUM_HOOKS",cPluginManager::HOOK_NUM_HOOKS); + tolua_constant(tolua_S,"HOOK_MAX",cPluginManager::HOOK_MAX); tolua_function(tolua_S,"Get",tolua_AllToLua_cPluginManager_Get00); tolua_function(tolua_S,"GetPlugin",tolua_AllToLua_cPluginManager_GetPlugin00); tolua_function(tolua_S,"FindPlugins",tolua_AllToLua_cPluginManager_FindPlugins00); tolua_function(tolua_S,"ReloadPlugins",tolua_AllToLua_cPluginManager_ReloadPlugins00); - tolua_function(tolua_S,"AddHook",tolua_AllToLua_cPluginManager_AddHook00); tolua_function(tolua_S,"GetNumPlugins",tolua_AllToLua_cPluginManager_GetNumPlugins00); tolua_function(tolua_S,"DisablePlugin",tolua_AllToLua_cPluginManager_DisablePlugin00); tolua_function(tolua_S,"LoadPlugin",tolua_AllToLua_cPluginManager_LoadPlugin00); @@ -28112,6 +28906,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetDimension",tolua_AllToLua_cWorld_GetDimension00); tolua_function(tolua_S,"GetHeight",tolua_AllToLua_cWorld_GetHeight00); tolua_function(tolua_S,"BroadcastChat",tolua_AllToLua_cWorld_BroadcastChat00); + tolua_function(tolua_S,"BroadcastSoundEffect",tolua_AllToLua_cWorld_BroadcastSoundEffect00); + tolua_function(tolua_S,"BroadcastSoundParticleEffect",tolua_AllToLua_cWorld_BroadcastSoundParticleEffect00); tolua_function(tolua_S,"UnloadUnusedChunks",tolua_AllToLua_cWorld_UnloadUnusedChunks00); tolua_function(tolua_S,"RegenerateChunk",tolua_AllToLua_cWorld_RegenerateChunk00); tolua_function(tolua_S,"GenerateChunk",tolua_AllToLua_cWorld_GenerateChunk00); @@ -28150,6 +28946,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GrowSugarcane",tolua_AllToLua_cWorld_GrowSugarcane00); tolua_function(tolua_S,"GetBiomeAt",tolua_AllToLua_cWorld_GetBiomeAt00); tolua_function(tolua_S,"GetName",tolua_AllToLua_cWorld_GetName00); + tolua_function(tolua_S,"GetIniFileName",tolua_AllToLua_cWorld_GetIniFileName00); tolua_function(tolua_S,"SaveAllChunks",tolua_AllToLua_cWorld_SaveAllChunks00); tolua_function(tolua_S,"QueueSaveAllChunks",tolua_AllToLua_cWorld_QueueSaveAllChunks00); tolua_function(tolua_S,"GetNumChunks",tolua_AllToLua_cWorld_GetNumChunks00); @@ -28167,6 +28964,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetMaxCactusHeight",tolua_AllToLua_cWorld_GetMaxCactusHeight00); tolua_function(tolua_S,"IsBlockDirectlyWatered",tolua_AllToLua_cWorld_IsBlockDirectlyWatered00); tolua_function(tolua_S,"SpawnMob",tolua_AllToLua_cWorld_SpawnMob00); + tolua_function(tolua_S,"CreateProjectile",tolua_AllToLua_cWorld_CreateProjectile00); tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cInventory","cInventory","cItemGrid::cListener",NULL); tolua_beginmodule(tolua_S,"cInventory"); @@ -28470,20 +29268,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"HandleWebRequest",tolua_AllToLua_cWebPlugin_HandleWebRequest00); tolua_function(tolua_S,"SafeString",tolua_AllToLua_cWebPlugin_SafeString00); tolua_endmodule(tolua_S); - #ifdef __cplusplus - tolua_cclass(tolua_S,"cPickup","cPickup","cEntity",tolua_collect_cPickup); - #else - tolua_cclass(tolua_S,"cPickup","cPickup","cEntity",NULL); - #endif - tolua_beginmodule(tolua_S,"cPickup"); - tolua_function(tolua_S,"new",tolua_AllToLua_cPickup_new00); - tolua_function(tolua_S,"new_local",tolua_AllToLua_cPickup_new00_local); - tolua_function(tolua_S,".call",tolua_AllToLua_cPickup_new00_local); - tolua_function(tolua_S,"GetItem",tolua_AllToLua_cPickup_GetItem00); - tolua_function(tolua_S,"CollectedBy",tolua_AllToLua_cPickup_CollectedBy00); - tolua_function(tolua_S,"GetAge",tolua_AllToLua_cPickup_GetAge00); - tolua_function(tolua_S,"IsCollected",tolua_AllToLua_cPickup_IsCollected00); - tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cRoot","cRoot","",NULL); tolua_beginmodule(tolua_S,"cRoot"); tolua_variable(tolua_S,"m_PrimaryServerVersion",tolua_get_cRoot_m_PrimaryServerVersion,tolua_set_cRoot_m_PrimaryServerVersion); @@ -28580,6 +29364,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,".sub",tolua_AllToLua_Vector3d__sub01); tolua_function(tolua_S,".mul",tolua_AllToLua_Vector3d__mul00); tolua_function(tolua_S,".mul",tolua_AllToLua_Vector3d__mul01); + tolua_function(tolua_S,".div",tolua_AllToLua_Vector3d__div00); tolua_variable(tolua_S,"x",tolua_get_Vector3d_x,tolua_set_Vector3d_x); tolua_variable(tolua_S,"y",tolua_get_Vector3d_y,tolua_set_Vector3d_y); tolua_variable(tolua_S,"z",tolua_get_Vector3d_z,tolua_set_Vector3d_z); diff --git a/source/Bindings.h b/source/Bindings.h index 4dee7f815..c706c2281 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,8 +1,8 @@ -/* -** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/19/13 11:57:27. -*/ - -/* Exported function */ -TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S); - +/*
+** Lua binding: AllToLua
+** Generated automatically by tolua++-1.0.92 on 09/01/13 14:42:05.
+*/
+
+/* Exported function */
+TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);
+
diff --git a/source/BlockID.h b/source/BlockID.h index b08795fdd..02d2c7193 100644 --- a/source/BlockID.h +++ b/source/BlockID.h @@ -367,7 +367,9 @@ enum ENUM_ITEM_ID // Keep these two as the last values of the disc list, without a number - they will get their correct number assigned automagically by C++ // IsValidItem() depends on this! E_ITEM_LAST_DISC_PLUS_ONE, ///< Useless, really, but needs to be present for the following value - E_ITEM_LAST_DISC = E_ITEM_LAST_DISC_PLUS_ONE - 1 ///< Maximum disc itemtype number used + E_ITEM_LAST_DISC = E_ITEM_LAST_DISC_PLUS_ONE - 1, ///< Maximum disc itemtype number used + + E_ITEM_LAST = E_ITEM_LAST_DISC, ///< Maximum valid ItemType }; diff --git a/source/BlockTracer.h b/source/BlockTracer.h index 6d67f1052..d0a34811d 100644 --- a/source/BlockTracer.h +++ b/source/BlockTracer.h @@ -31,12 +31,12 @@ public: /** Called on each block encountered along the path, including the first block (path start) When this callback returns true, the tracing is aborted. */ - virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; + virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) = 0; /** Called on each block encountered along the path, including the first block (path start), if chunk data is not loaded When this callback returns true, the tracing is aborted. */ - virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) { return false; } + virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) { return false; } /** Called when the path goes out of world, either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height) The coords specify the exact point at which the path exited the world. diff --git a/source/Blocks/BlockCarpet.h b/source/Blocks/BlockCarpet.h index 9ac998131..5eafd8c21 100644 --- a/source/Blocks/BlockCarpet.h +++ b/source/Blocks/BlockCarpet.h @@ -18,8 +18,8 @@ class cBlockCarpetHandler : public cBlockHandler { public: - cBlockCarpetHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + cBlockCarpetHandler(BLOCKTYPE a_BlockType) : + cBlockHandler(a_BlockType) { } diff --git a/source/Blocks/BlockDoubleSlab.h b/source/Blocks/BlockDoubleSlab.h deleted file mode 100644 index ed6ae9a70..000000000 --- a/source/Blocks/BlockDoubleSlab.h +++ /dev/null @@ -1,43 +0,0 @@ - -#pragma once - -#include "BlockHandler.h" -#include "../Items/ItemHandler.h" - - - - - -class cBlockDoubleSlabHandler : - public cBlockHandler -{ -public: - cBlockDoubleSlabHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) - { - } - - - virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override - { - if (m_BlockType == E_BLOCK_DOUBLE_STONE_SLAB) - { - m_BlockType = E_BLOCK_STONE_SLAB; - } - else - { - m_BlockType = E_BLOCK_WOODEN_SLAB; - } - a_Pickups.push_back(cItem(m_BlockType, 2, a_BlockMeta)); - } - - - virtual const char * GetStepSound(void) override - { - return ((m_BlockType == E_BLOCK_DOUBLE_WOODEN_SLAB) || (m_BlockType == E_BLOCK_DOUBLE_WOODEN_SLAB)) ? "step.wood" : "step.stone"; - } -} ; - - - - diff --git a/source/Blocks/BlockHandler.cpp b/source/Blocks/BlockHandler.cpp index 22efa25f5..5134c1103 100644 --- a/source/Blocks/BlockHandler.cpp +++ b/source/Blocks/BlockHandler.cpp @@ -17,7 +17,6 @@ #include "BlockDeadBush.h" #include "BlockDirt.h" #include "BlockDoor.h" -#include "BlockDoubleSlab.h" #include "BlockDropSpenser.h" #include "BlockEnderchest.h" #include "BlockEntity.h" diff --git a/source/Blocks/BlockSlab.h b/source/Blocks/BlockSlab.h index 6caa3a27a..7c1251b28 100644 --- a/source/Blocks/BlockSlab.h +++ b/source/Blocks/BlockSlab.h @@ -1,7 +1,17 @@ +// BlockSlab.h + +// Declares cBlockSlabHandler and cBlockDoubleSlabHandler classes + + + + + #pragma once #include "BlockHandler.h" +#include "../Items/ItemHandler.h" + @@ -30,36 +40,26 @@ public: ) override { a_BlockType = m_BlockType; - BLOCKTYPE Type = (BLOCKTYPE)(a_Player->GetEquippedItem().m_ItemType); + BLOCKTYPE Type = (BLOCKTYPE) (a_Player->GetEquippedItem().m_ItemType); NIBBLETYPE Meta = (NIBBLETYPE)(a_Player->GetEquippedItem().m_ItemDamage & 0x07); - int DoubleType; - if (Type == E_BLOCK_STONE_SLAB) - { - DoubleType = 43; // Make it a double slab (with old type wood) - } - else - { - DoubleType = 125; // Make it a wooden double slab (new type) - } // HandlePlaceBlock wants a cItemHandler pointer thing, so let's give it one - cItemHandler * ItemHandler = cItemHandler::GetItemHandler(DoubleType); + cItemHandler * ItemHandler = cItemHandler::GetItemHandler(GetDoubleSlabType(Type)); - // Check if the block at the coordinates is a slab. Eligibility for combining etc. were processed in ClientHandle - BLOCKTYPE IsSlab; - IsSlab = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - if ((IsSlab == E_BLOCK_STONE_SLAB) || (IsSlab == E_BLOCK_WOODEN_SLAB)) + // Check if the block at the coordinates is a slab. Eligibility for combining has already been processed in ClientHandle + if (IsAnySlabType(a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ))) { - // Special handling for non top/bottom clicks + // Call the function in ClientHandle that places a block when the client sends the packet, + // so that plugins may interfere with the placement. + if ((a_BlockFace == BLOCK_FACE_TOP) || (a_BlockFace == BLOCK_FACE_BOTTOM)) { - // As with previous, call the function in ClientHandle that places a block when the client sends the packet - // This effectively simulates a client placing a double slab, so it goes through plugins etc. so the slabbing can be cancelled + // Top and bottom faces need no parameter modification a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler); } else { - // If player cursor is at top half of block + // The other faces need to distinguish between top and bottom cursor positions if (a_CursorY > 7) { // Edit the call to use BLOCK_FACE_BOTTOM, otherwise it places incorrectly @@ -71,19 +71,23 @@ public: a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_BOTTOM, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler); } } - return false; // Cancel the event because dblslabs were already placed, nothing else needed + return false; // Cancel the event, because dblslabs were already placed, nothing else needed } + // Place the single-slab with correct metas: switch (a_BlockFace) { - // Previous IF condition didn't cancel the event (not a slab at coords), so place slab with correct metas case BLOCK_FACE_TOP: { - a_BlockMeta = Meta & 0x7; break; // Bottom half slab block + // Bottom half slab block + a_BlockMeta = Meta & 0x7; + break; } case BLOCK_FACE_BOTTOM: { - a_BlockMeta = Meta | 0x8; break; // Top half slab block + // Top half slab block + a_BlockMeta = Meta | 0x8; + break; } case BLOCK_FACE_EAST: case BLOCK_FACE_NORTH: @@ -107,8 +111,69 @@ public: virtual const char * GetStepSound(void) override + { + switch (m_BlockType) + { + case E_BLOCK_WOODEN_SLAB: return "step.wood"; + case E_BLOCK_STONE_SLAB: return "step.stone"; + } + ASSERT(!"Unhandled slab type!"); + return ""; + } + + + /// Returns true if the specified blocktype is one of the slabs handled by this handler + static bool IsAnySlabType(BLOCKTYPE a_BlockType) + { + return ((a_BlockType == E_BLOCK_WOODEN_SLAB) || (a_BlockType == E_BLOCK_STONE_SLAB)); + } + + + /// Converts the single-slab blocktype to its equivalent double-slab blocktype + static BLOCKTYPE GetDoubleSlabType(BLOCKTYPE a_SingleSlabBlockType) + { + switch (a_SingleSlabBlockType) + { + case E_BLOCK_STONE_SLAB: return E_BLOCK_DOUBLE_STONE_SLAB; + case E_BLOCK_WOODEN_SLAB: return E_BLOCK_DOUBLE_WOODEN_SLAB; + } + ASSERT(!"Unhandled slab type!"); + return E_BLOCK_AIR; + } + +} ; + + + + + +class cBlockDoubleSlabHandler : + public cBlockHandler +{ +public: + cBlockDoubleSlabHandler(BLOCKTYPE a_BlockType) + : cBlockHandler(a_BlockType) + { + } + + + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + { + if (m_BlockType == E_BLOCK_DOUBLE_STONE_SLAB) + { + m_BlockType = E_BLOCK_STONE_SLAB; + } + else + { + m_BlockType = E_BLOCK_WOODEN_SLAB; + } + a_Pickups.push_back(cItem(m_BlockType, 2, a_BlockMeta)); + } + + + virtual const char * GetStepSound(void) override { - return ((m_BlockType == E_BLOCK_WOODEN_SLAB) || (m_BlockType == E_BLOCK_STONE_SLAB)) ? "step.wood" : "step.stone"; + return ((m_BlockType == E_BLOCK_DOUBLE_WOODEN_SLAB) || (m_BlockType == E_BLOCK_DOUBLE_WOODEN_SLAB)) ? "step.wood" : "step.stone"; } } ; diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index 53aae4dc4..357c07105 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -19,6 +19,7 @@ #include "OSSupport/Timer.h" #include "Items/ItemHandler.h" #include "Blocks/BlockHandler.h" +#include "Blocks/BlockSlab.h" #include "Vector3f.h" #include "Vector3d.h" @@ -51,6 +52,9 @@ static const int MAX_EXPLOSIONS_PER_TICK = 100; /// How many explosions in the recent history are allowed static const int MAX_RUNNING_SUM_EXPLOSIONS = cClientHandle::NUM_CHECK_EXPLOSIONS_TICKS * MAX_EXPLOSIONS_PER_TICK / 8; +/// How many ticks before the socket is closed after the client is destroyed (#31) +static const int TICKS_BEFORE_CLOSE = 20; + @@ -84,6 +88,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) , m_bKeepThreadGoing(true) , m_Ping(1000) , m_PingID(1) + , m_TicksSinceDestruction(0) , m_State(csConnected) , m_LastStreamedChunkX(0x7fffffff) // bogus chunk coords to force streaming upon login , m_LastStreamedChunkZ(0x7fffffff) @@ -111,7 +116,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) cClientHandle::~cClientHandle() { - ASSERT(m_State == csDestroyed); // Has Destroy() been called? + ASSERT(m_State >= csDestroyedWaiting); // Has Destroy() been called? LOGD("Deleting client \"%s\" at %p", GetUsername().c_str(), this); @@ -189,7 +194,7 @@ void cClientHandle::Destroy(void) RemoveFromAllChunks(); m_Player->GetWorld()->RemoveClientFromChunkSender(this); } - m_State = csDestroyed; + m_State = csDestroyedWaiting; } @@ -571,8 +576,8 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch // A plugin doesn't agree with the action. The plugin itself is responsible for handling the consequences (possible inventory mismatch) return; } + ItemHandler->OnItemShoot(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); } - LOGINFO("%s: Status SHOOT not implemented", __FUNCTION__); return; } @@ -785,16 +790,16 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, c BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); - cBlockHandler * Handler = cBlockHandler::GetBlockHandler(BlockType); + cBlockHandler * BlockHandler = cBlockHandler::GetBlockHandler(BlockType); - if (Handler->IsUseable() && !m_Player->IsCrouched()) + if (BlockHandler->IsUseable() && !m_Player->IsCrouched()) { if (PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta)) { // A plugin doesn't agree with using the block, abort return; } - Handler->OnUse(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ); + BlockHandler->OnUse(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ); PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta); return; } @@ -852,25 +857,24 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType); NIBBLETYPE EquippedBlockDamage = (NIBBLETYPE)(m_Player->GetEquippedItem().m_ItemDamage); + if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) + { + // The block is being placed outside the world, ignore this packet altogether (#128) + return; + } + World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta); - // Special slab handler coding + // Special slab handling - placing a slab onto another slab produces a dblslab instead: if ( - // If clicked face top: is slab there in the "bottom" position? - // If clicked face bottom: is the slab there in the "top" position? - // This prevents a dblslab forming below if you click the top face of a "top" slab. - (((a_BlockFace == BLOCK_FACE_TOP) && (ClickedBlockMeta == (EquippedBlockDamage & 0x07))) || ((a_BlockFace == BLOCK_FACE_BOTTOM) && (ClickedBlockMeta == (EquippedBlockDamage | 0x08)))) && - - // Is clicked a slab? This is a SLAB handler, not stone or something! - ((ClickedBlock == E_BLOCK_STONE_SLAB) || (ClickedBlock == E_BLOCK_WOODEN_SLAB)) && - - // Is equipped a some type of slab? - // This prevents a bug where, well, you get a dblslab by placing TNT or something not a slab. - ((EquippedBlock == E_BLOCK_STONE_SLAB) || (EquippedBlock == E_BLOCK_WOODEN_SLAB)) && - - // Is equipped slab type same as the slab in the world? After all, we can't combine different slabs! - ((ClickedBlockMeta & 0x07) == (EquippedBlockDamage & 0x07)) + cBlockSlabHandler::IsAnySlabType(ClickedBlock) && // Is there a slab already? + cBlockSlabHandler::IsAnySlabType(EquippedBlock) && // Is the player placing another slab? + ((ClickedBlockMeta & 0x07) == (EquippedBlockDamage & 0x07)) && // Is it the same slab type? + ( + (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab + (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab ) + ) { // Coordinates at CLICKED block, don't move them anywhere } @@ -881,17 +885,26 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c if (Handler->DoesIgnoreBuildCollision()) { Handler->OnDestroyedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ); - //World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); } - else + + BLOCKTYPE PlaceBlock = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); + if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision()) { AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) + { + // The block is being placed outside the world, ignore this packet altogether (#128) + return; + } + + BLOCKTYPE PlaceBlock = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); + // Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed. // No need to do combinability (dblslab) checks, client will do that here. - if ((World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_STONE_SLAB) || (World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_WOODEN_SLAB)) + if (cBlockSlabHandler::IsAnySlabType(PlaceBlock)) { - //Is a slab, don't do checks and proceed to double-slabbing + // It's a slab, don't do checks and proceed to double-slabbing } else { @@ -899,13 +912,11 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c if ((a_BlockFace == BLOCK_FACE_TOP) && !Handler->DoesAllowBlockOnTop()) { // Resend the old block - // Some times the client still places the block O.o + // Sometimes the client still places the block O.o World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); return; } - - - BLOCKTYPE PlaceBlock = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); + if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision()) { // Tried to place a block *into* another? @@ -915,7 +926,6 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c } } } - // Special slab handler coding end BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; @@ -951,7 +961,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c NewBlock->OnPlacedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta); // Step sound with 0.8f pitch is used as block placement sound - World->BroadcastSoundEffect(NewBlock->GetStepSound(),a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 0.8f); + World->BroadcastSoundEffect(NewBlock->GetStepSound(), a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 0.8f); cRoot::Get()->GetPluginManager()->CallHookPlayerPlacedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta); } @@ -1324,6 +1334,12 @@ void cClientHandle::HandleTabCompletion(const AString & a_Text) void cClientHandle::SendData(const char * a_Data, int a_Size) { + if (m_HasSentDC) + { + // This could crash the client, because they've already unloaded the world etc., and suddenly a wild packet appears (#31) + return; + } + { cCSLock Lock(m_CSOutgoingData); @@ -1438,6 +1454,17 @@ bool cClientHandle::CheckBlockInteractionsRate(void) void cClientHandle::Tick(float a_Dt) { + // Handle clients that are waiting for final close while destroyed: + if (m_State == csDestroyedWaiting) + { + m_TicksSinceDestruction += 1; // This field is misused for the timeout counting + if (m_TicksSinceDestruction > TICKS_BEFORE_CLOSE) + { + m_State = csDestroyed; + } + return; + } + // Process received network data: AString IncomingData; { @@ -1563,6 +1590,16 @@ void cClientHandle::SendChat(const AString & a_Message) void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { + ASSERT(m_Player != NULL); + + if ((m_State == csAuthenticated) || (m_State == csDownloadingWorld)) + { + if ((a_ChunkX == m_Player->GetChunkX()) && (a_ChunkZ == m_Player->GetChunkZ())) + { + m_Protocol->SendPlayerMoveLook(); + } + } + // Check chunks being sent, erase them from m_ChunksToSend: bool Found = false; { diff --git a/source/ClientHandle.h b/source/ClientHandle.h index 65ad35165..761cf25fe 100644 --- a/source/ClientHandle.h +++ b/source/ClientHandle.h @@ -257,6 +257,9 @@ private: int m_LastDigBlockX; int m_LastDigBlockY; int m_LastDigBlockZ; + + /// Used while csDestroyedWaiting for counting the ticks until the connection is closed + int m_TicksSinceDestruction; enum eState { @@ -267,6 +270,7 @@ private: csConfirmingPos, ///< The client has been sent the position packet, waiting for them to repeat the position back csPlaying, ///< Normal gameplay csDestroying, ///< The client is being destroyed, don't queue any more packets / don't add to chunks + csDestroyedWaiting, ///< The client has been destroyed, but is still kept so that the Kick packet is delivered (#31) csDestroyed, ///< The client has been destroyed, the destructor is to be called from the owner thread // TODO: Add Kicking here as well diff --git a/source/Defines.h b/source/Defines.h index 48a7cfb1e..6bc1a18f6 100644 --- a/source/Defines.h +++ b/source/Defines.h @@ -29,6 +29,16 @@ extern bool g_BlockTransparent[]; /// Is a block destroyed after a single hit? extern bool g_BlockOneHitDig[]; +/// Can a piston break this block? +extern bool g_BlockPistonBreakable[256]; + +/// Can this block hold snow atop? +extern bool g_BlockIsSnowable[256]; + +extern bool g_BlockRequiresSpecialTool[256]; + +extern bool g_BlockIsSolid[256]; + diff --git a/source/Entities/Entity.cpp b/source/Entities/Entity.cpp index b9810aabb..56fd36a05 100644 --- a/source/Entities/Entity.cpp +++ b/source/Entities/Entity.cpp @@ -144,6 +144,10 @@ bool cEntity::Initialize(cWorld * a_World) m_World->AddEntity(this); cPluginManager::Get()->CallHookSpawnedEntity(*a_World, *this); + + // Spawn the entity on the clients: + a_World->BroadcastSpawnEntity(*this); + return true; } @@ -477,7 +481,7 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) { // TODO Add collision detection with entities. - a_Dt /= 1000; + a_Dt /= 1000; // Convert from msec to sec Vector3d NextPos = Vector3d(GetPosX(),GetPosY(),GetPosZ()); Vector3d NextSpeed = Vector3d(GetSpeedX(),GetSpeedY(),GetSpeedZ()); int BlockX = (int) floor(NextPos.x); @@ -493,7 +497,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) } // Make sure we got the correct chunk and a valid one. No one ever knows... - cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX,BlockZ); + cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); if (NextChunk != NULL) { int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width); @@ -513,11 +517,12 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) } else { - //Push out entity. + // Push out entity. m_bOnGround = true; NextPos.y += 0.2; - LOGD("Entity #%d (%s) is inside a block at {%d,%d,%d}", - m_UniqueID, GetClass(), BlockX, BlockY, BlockZ); + LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}", + m_UniqueID, GetClass(), BlockX, BlockY, BlockZ + ); } if (!m_bOnGround) @@ -525,16 +530,16 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) float fallspeed; if (IsBlockWater(BlockIn)) { - fallspeed = -3.0f * a_Dt; //Fall slower in water. + fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water. } else if (BlockIn == E_BLOCK_COBWEB) { - NextSpeed.y *= 0.05; //Reduce overall falling speed - fallspeed = 0; //No falling. + NextSpeed.y *= 0.05; // Reduce overall falling speed + fallspeed = 0; // No falling. } else { - //Normal gravity + // Normal gravity fallspeed = m_Gravity * a_Dt; } NextSpeed.y += fallspeed; @@ -548,19 +553,25 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) (BlockBelow != E_BLOCK_ACTIVATOR_RAIL) ) { - //Friction + // Friction if (NextSpeed.SqrLength() > 0.0004f) { - NextSpeed.x *= 0.7f/(1+a_Dt); - if ( fabs(NextSpeed.x) < 0.05 ) NextSpeed.x = 0; - NextSpeed.z *= 0.7f/(1+a_Dt); - if ( fabs(NextSpeed.z) < 0.05 ) NextSpeed.z = 0; + NextSpeed.x *= 0.7f / (1 + a_Dt); + if (fabs(NextSpeed.x) < 0.05) + { + NextSpeed.x = 0; + } + NextSpeed.z *= 0.7f / (1 + a_Dt); + if (fabs(NextSpeed.z) < 0.05) + { + NextSpeed.z = 0; + } } } } - //Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we - //might have different speed modifiers according to terrain. + // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we + // might have different speed modifiers according to terrain. if (BlockIn == E_BLOCK_COBWEB) { NextSpeed.x *= 0.25; @@ -1037,9 +1048,9 @@ void cEntity::SetMass(double a_Mass) } else { - //Make sure that mass is not zero. 1g is the default because we - //have to choose a number. It's perfectly legal to have a mass - //less than 1g as long as is NOT equal or less than zero. + // Make sure that mass is not zero. 1g is the default because we + // have to choose a number. It's perfectly legal to have a mass + // less than 1g as long as is NOT equal or less than zero. m_Mass = 0.001; } } diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h index 119cb2fe5..2d058abae 100644 --- a/source/Entities/Entity.h +++ b/source/Entities/Entity.h @@ -90,12 +90,13 @@ public: etPlayer, etPickup, etMonster, - etMob = etMonster, // DEPRECATED, use etMonster instead! etFallingBlock, etMinecart, etTNT, + etProjectile, // DEPRECATED older constants, left over for compatibility reasons (plugins) + etMob = etMonster, // DEPRECATED, use etMonster instead! eEntityType_Entity = etEntity, eEntityType_Player = etPlayer, eEntityType_Pickup = etPickup, @@ -162,7 +163,7 @@ public: void SetPosY (double a_PosY); void SetPosZ (double a_PosZ); void SetPosition(double a_PosX, double a_PosY, double a_PosZ); - void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x,a_Pos.y,a_Pos.z);} + void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x, a_Pos.y, a_Pos.z); } void SetRot (const Vector3f & a_Rot); void SetRotation(double a_Rotation); void SetPitch (double a_Pitch); @@ -276,9 +277,8 @@ public: /** Descendants override this function to send a command to the specified client to spawn the entity on the client. To spawn on all eligible clients, use cChunkMap::BroadcastSpawnEntity() - Needs to have a default implementation due to Lua bindings. */ - virtual void SpawnOn(cClientHandle & a_Client) {ASSERT(!"SpawnOn() unimplemented!"); } + virtual void SpawnOn(cClientHandle & a_Client) = 0; // tolua_begin diff --git a/source/Entities/FallingBlock.cpp b/source/Entities/FallingBlock.cpp index 237327975..9fcd9ac80 100644 --- a/source/Entities/FallingBlock.cpp +++ b/source/Entities/FallingBlock.cpp @@ -22,20 +22,6 @@ cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_Block -bool cFallingBlock::Initialize(cWorld * a_World) -{ - if (super::Initialize(a_World)) - { - a_World->BroadcastSpawnEntity(*this); - return true; - } - return false; -} - - - - - void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle) { a_ClientHandle.SendSpawnFallingBlock(*this); diff --git a/source/Entities/FallingBlock.h b/source/Entities/FallingBlock.h index 13931f061..5ba9909bb 100644 --- a/source/Entities/FallingBlock.h +++ b/source/Entities/FallingBlock.h @@ -29,7 +29,6 @@ public: NIBBLETYPE GetBlockMeta(void) const { return m_BlockMeta; } // cEntity overrides: - 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/Entities/Minecart.cpp b/source/Entities/Minecart.cpp index 9a92df38e..685067e79 100644 --- a/source/Entities/Minecart.cpp +++ b/source/Entities/Minecart.cpp @@ -26,20 +26,6 @@ cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) : -bool cMinecart::Initialize(cWorld * a_World) -{ - if (super::Initialize(a_World)) - { - a_World->BroadcastSpawnEntity(*this); - return true; - } - return false; -} - - - - - void cMinecart::SpawnOn(cClientHandle & a_ClientHandle) { char SubType = 0; diff --git a/source/Entities/Minecart.h b/source/Entities/Minecart.h index b3386fbc9..f98b02bb5 100644 --- a/source/Entities/Minecart.h +++ b/source/Entities/Minecart.h @@ -35,7 +35,6 @@ public: } ; // cEntity overrides: - virtual bool Initialize(cWorld * a_World) override; virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; void HandleRailPhysics(float a_Dt, cChunk & a_Chunk); diff --git a/source/Entities/Pickup.cpp b/source/Entities/Pickup.cpp index 0417b861d..9b388366a 100644 --- a/source/Entities/Pickup.cpp +++ b/source/Entities/Pickup.cpp @@ -40,20 +40,6 @@ cPickup::cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem -bool cPickup::Initialize(cWorld * a_World) -{ - if (super::Initialize(a_World)) - { - a_World->BroadcastSpawnEntity(*this); - return true; - } - return false; -} - - - - - void cPickup::SpawnOn(cClientHandle & a_Client) { a_Client.SendPickupSpawn(*this); @@ -73,18 +59,19 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk) if (!m_bCollected) { int BlockY = (int) floor(GetPosY()); - if (BlockY < cChunkDef::Height) // Don't do anything except for falling when above the world + if ((BlockY >= 0) && (BlockY < cChunkDef::Height)) // Don't do anything except for falling when outside the world { int BlockX = (int) floor(GetPosX()); int BlockZ = (int) floor(GetPosZ()); - //Position might have changed due to physics. So we have to make sure we have the correct chunk. + // Position might have changed due to physics. So we have to make sure we have the correct chunk. cChunk * CurrentChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); if (CurrentChunk != NULL) // Make sure the chunk is loaded { int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width); int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width); - BLOCKTYPE BlockBelow = CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ); + // If the pickup is on the bottommost block position, make it think the void is made of air: (#131) + BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ); if ( diff --git a/source/Entities/Pickup.h b/source/Entities/Pickup.h index b0323dd92..af6eaf3bb 100644 --- a/source/Entities/Pickup.h +++ b/source/Entities/Pickup.h @@ -26,8 +26,6 @@ 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 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/Entities/Player.cpp b/source/Entities/Player.cpp index 3ccb4ca1d..0943f61ff 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -64,6 +64,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_IsSwimming(false) , m_IsSubmerged(false) , m_EatingFinishTick(-1) + , m_IsChargingBow(false) + , m_BowCharge(0) { LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", a_PlayerName.c_str(), a_Client->GetIPString().c_str(), @@ -200,6 +202,12 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) } } + if (!a_Chunk.IsValid()) + { + // This may happen if the cPlayer is created before the chunks have the chance of being loaded / generated (#83) + return; + } + super::Tick(a_Dt, a_Chunk); // Set player swimming state @@ -207,6 +215,13 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) // Handle air drowning stuff HandleAir(); + + // Handle charging the bow: + if (m_IsChargingBow) + { + m_BowCharge += 1; + LOGD("Player \"%s\" charging bow: %d", m_PlayerName.c_str(), m_BowCharge); + } if (m_bDirtyPosition) { @@ -247,6 +262,41 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) +void cPlayer::StartChargingBow(void) +{ + LOGD("Player \"%s\" started charging their bow", m_PlayerName.c_str()); + m_IsChargingBow = true; + m_BowCharge = 0; +} + + + + + +int cPlayer::FinishChargingBow(void) +{ + LOGD("Player \"%s\" finished charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge); + int res = m_BowCharge; + m_IsChargingBow = false; + m_BowCharge = 0; + return res; +} + + + + + +void cPlayer::CancelChargingBow(void) +{ + LOGD("Player \"%s\" cancelled charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge); + m_IsChargingBow = false; + m_BowCharge = 0; +} + + + + + void cPlayer::SetTouchGround(bool a_bTouchGround) { // If just @@ -807,6 +857,36 @@ void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) +Vector3d cPlayer::GetThrowStartPos(void) const +{ + Vector3d res = GetEyePosition(); + + // Adjust the position to be just outside the player's bounding box: + res.x += 0.16 * cos(GetPitch()); + res.y += -0.1; + res.z += 0.16 * sin(GetPitch()); + + return res; +} + + + + + +Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const +{ + Vector3d res = GetLookVector(); + res.Normalize(); + + // TODO: Add a slight random change (+-0.0075 in each direction) + + return res * a_SpeedCoeff; +} + + + + + void cPlayer::MoveTo( const Vector3d & a_NewPos ) { if ((a_NewPos.y < -990) && (GetPosY() > -100)) diff --git a/source/Entities/Player.h b/source/Entities/Player.h index 5dcce8421..82ff48954 100644 --- a/source/Entities/Player.h +++ b/source/Entities/Player.h @@ -62,6 +62,18 @@ public: /// Returns the currently equipped boots; empty item if none virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); } + + /// Starts charging the equipped bow + void StartChargingBow(void); + + /// Finishes charging the current bow. Returns the number of ticks for which the bow has been charged + int FinishChargingBow(void); + + /// Cancels the current bow charging + void CancelChargingBow(void); + + /// Returns true if the player is currently charging the bow + bool IsChargingBow(void) const { return m_IsChargingBow; } void SetTouchGround( bool a_bTouchGround ); inline void SetStance( const double a_Stance ) { m_Stance = a_Stance; } @@ -78,6 +90,12 @@ public: // tolua_begin + /// Returns the position where projectiles thrown by this player should start, player eye position + adjustment + Vector3d GetThrowStartPos(void) const; + + /// Returns the initial speed vector of a throw, with a 3D length of a_SpeedCoeff. + Vector3d GetThrowSpeed(double a_SpeedCoeff) const; + /// Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable eGameMode GetGameMode(void) const { return m_GameMode; } @@ -351,6 +369,9 @@ protected: /// The world tick in which eating will be finished. -1 if not eating Int64 m_EatingFinishTick; + + bool m_IsChargingBow; + int m_BowCharge; virtual void Destroyed(void); diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp new file mode 100644 index 000000000..91b2c97a8 --- /dev/null +++ b/source/Entities/ProjectileEntity.cpp @@ -0,0 +1,351 @@ + +// ProjectileEntity.cpp + +// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types + +#include "Globals.h" +#include "ProjectileEntity.h" +#include "../ClientHandle.h" +#include "Player.h" +#include "../LineBlockTracer.h" + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cProjectileTracerCallback: + +class cProjectileTracerCallback : + public cBlockTracer::cCallbacks +{ +public: + cProjectileTracerCallback(cProjectileEntity * a_Projectile) : + m_Projectile(a_Projectile) + { + } + +protected: + cProjectileEntity * m_Projectile; + + virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override + { + if (g_BlockIsSolid[a_BlockType]) + { + // The projectile hit a solid block + m_Projectile->OnHitSolidBlock(a_BlockX, a_BlockY, a_BlockZ, a_EntryFace); + return true; + } + + // Convey some special effects from special blocks: + switch (a_BlockType) + { + case E_BLOCK_LAVA: + case E_BLOCK_STATIONARY_LAVA: + { + m_Projectile->StartBurning(30); + break; + } + case E_BLOCK_WATER: + case E_BLOCK_STATIONARY_WATER: + { + m_Projectile->StopBurning(); + break; + } + } // switch (a_BlockType) + + // Continue tracing + return false; + } +} ; + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cProjectileEntity: + +cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height) : + super(etProjectile, a_X, a_Y, a_Z, a_Width, a_Height), + m_ProjectileKind(a_Kind), + m_Creator(a_Creator), + m_IsInGround(false) +{ +} + + + + + +cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height) : + super(etProjectile, a_Pos.x, a_Pos.y, a_Pos.z, a_Width, a_Height), + m_ProjectileKind(a_Kind), + m_Creator(a_Creator), + m_IsInGround(false) +{ + SetSpeed(a_Speed); +} + + + + + +cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed) +{ + Vector3d Speed; + if (a_Speed != NULL) + { + Speed = *a_Speed; + } + + switch (a_Kind) + { + case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed); + case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed); + // TODO: the rest + } + + LOGWARNING("%s: Unknown projectile kind: %d", __FUNCTION__, a_Kind); + return NULL; +} + + + + + +void cProjectileEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +{ + // TODO: Set proper position based on what face was hit + switch (a_BlockFace) + { + case BLOCK_FACE_TOP: SetPosition(0.5 + a_BlockX, 1.0 + a_BlockY, 0.5 + a_BlockZ); break; + case BLOCK_FACE_BOTTOM: SetPosition(0.5 + a_BlockX, a_BlockY, 0.5 + a_BlockZ); break; + case BLOCK_FACE_EAST: SetPosition( a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; + case BLOCK_FACE_WEST: SetPosition(1.0 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; + case BLOCK_FACE_NORTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 1.0 + a_BlockZ); break; + case BLOCK_FACE_SOUTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, a_BlockZ); break; + case BLOCK_FACE_NONE: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break; + } + SetSpeed(0, 0, 0); + + // DEBUG: + LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, hit solid block at face %d", + m_UniqueID, + GetPosX(), GetPosY(), GetPosZ(), + a_BlockFace + ); + + m_IsInGround = true; +} + + + + + +AString cProjectileEntity::GetMCAClassName(void) const +{ + switch (m_ProjectileKind) + { + case pkArrow: return "Arrow"; + case pkSnowball: return "Snowball"; + case pkEgg: return "Egg"; + case pkGhastFireball: return "Fireball"; + case pkFireCharge: return "SmallFireball"; + case pkEnderPearl: return "ThrownEnderPearl"; + case pkExpBottle: return "ThrownExpBottle"; + case pkSplashPotion: return "ThrownPotion"; + case pkWitherSkull: return "WitherSkull"; + case pkFishingFloat: return ""; // Unknown, perhaps MC doesn't save this? + } + ASSERT(!"Unhandled projectile entity kind!"); + return ""; +} + + + + + +void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + BroadcastMovementUpdate(); +} + + + + + +void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) +{ + if (m_IsInGround) + { + // Already-grounded projectiles don't move at all + return; + } + + Vector3d PerTickSpeed = GetSpeed() / 20; + Vector3d Pos = GetPosition(); + + // Trace the tick's worth of movement as a line: + Vector3d NextPos = Pos + PerTickSpeed; + cProjectileTracerCallback TracerCallback(this); + if (cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos)) + { + // Nothing in the way, update the position + SetPosition(NextPos); + } + + // Add gravity effect to the vertical speed component: + SetSpeedY(GetSpeedY() + m_Gravity / 20); + + // DEBUG: + LOGD("Arrow %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}", + m_UniqueID, + GetPosX(), GetPosY(), GetPosZ(), + GetSpeedX(), GetSpeedY(), GetSpeedZ() + ); +} + + + + + +void cProjectileEntity::SpawnOn(cClientHandle & a_Client) +{ + // Default spawning - use the projectile kind to spawn an object: + a_Client.SendSpawnObject(*this, m_ProjectileKind, 0, 0, 0); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cArrowEntity: + +cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5), + m_PickupState(psNoPickup), + m_DamageCoeff(2) +{ + SetSpeed(a_Speed); + SetMass(0.1); + LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f}", + m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ() + ); +} + + + + + +cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : + super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5), + m_PickupState(psInSurvivalOrCreative), + m_DamageCoeff(2) +{ +} + + + + + +bool cArrowEntity::CanPickup(const cPlayer & a_Player) const +{ + switch (m_PickupState) + { + case psNoPickup: return false; + case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative()); + case psInCreative: return a_Player.IsGameModeCreative(); + } + ASSERT(!"Unhandled pickup state"); + return false; +} + + + + + +void cArrowEntity::SpawnOn(cClientHandle & a_Client) +{ + a_Client.SendSpawnObject(*this, pkArrow, 0, 0, 0); +} + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cThrownEggEntity: + +cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownEggEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +{ + // TODO: Random-spawn a chicken or four + + Destroy(); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cThrownEnderPearlEntity : + +cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownEnderPearlEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +{ + // TODO: Teleport the creator here, make them take 5 damage + + Destroy(); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cThrownSnowballEntity : + +cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownSnowballEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +{ + // TODO: Apply damage to certain mobs (blaze etc.) and anger all mobs + + Destroy(); +} + + + + + diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h new file mode 100644 index 000000000..95dc00abc --- /dev/null +++ b/source/Entities/ProjectileEntity.h @@ -0,0 +1,238 @@ + +// ProjectileEntity.h + +// Declares the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types + + + + + +#pragma once + +#include "Entity.h" + + + + + +// tolua_begin + +class cProjectileEntity : + public cEntity +{ + typedef cEntity super; + +public: + /// The kind of the projectile. The numbers correspond to the network type ID used for spawning via the 0x17 packet. + enum eKind + { + pkArrow = 60, + pkSnowball = 61, + pkEgg = 62, + pkGhastFireball = 63, + pkFireCharge = 64, + pkEnderPearl = 65, + pkExpBottle = 75, + pkSplashPotion = 73, + pkWitherSkull = 66, + pkFishingFloat = 90, + } ; + + // tolua_end + + CLASS_PROTODEF(cProjectileEntity); + + cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); + cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height); + + static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL); + + /// Called by the physics blocktracer when the entity hits a solid block, the block's coords and the face hit is given + virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace); + + // tolua_begin + + /// Returns the kind of the projectile (fast class identification) + eKind GetProjectileKind(void) const { return m_ProjectileKind; } + + /// Returns the entity who created this projectile; may be NULL + cEntity * GetCreator(void) { return m_Creator; } + + /// Returns the string that is used as the entity type (class name) in MCA files + AString GetMCAClassName(void) const; + + /// Returns true if the projectile has hit the ground and is stuck there + bool IsInGround(void) const { return m_IsInGround; } + +protected: + eKind m_ProjectileKind; + + /// The entity who has created this projectile; may be NULL (e. g. for dispensers) + cEntity * m_Creator; + + /// True if the projectile has hit the ground and is stuck there + bool m_IsInGround; + + // tolua_end + + // cEntity overrides: + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; + virtual void SpawnOn(cClientHandle & a_Client) override; + + // tolua_begin +} ; + + + + + +class cArrowEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + /// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field + enum ePickupState + { + psNoPickup = 0, + psInSurvivalOrCreative = 1, + psInCreative = 2, + } ; + + // tolua_end + + CLASS_PROTODEF(cArrowEntity); + + /// Creates a new arrow with psNoPickup state and default damage modifier coeff + cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + + /// Creates a new arrow as shot by a player, initializes it from the player object + cArrowEntity(cPlayer & a_Player, double a_Force); + + // tolua_begin + + /// Returns whether the arrow can be picked up by players + ePickupState GetPickupState(void) const { return m_PickupState; } + + /// Sets a new pickup state + void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; } + + /// Returns the damage modifier coeff. + double GetDamageCoeff(void) const { return m_DamageCoeff; } + + /// Sets the damage modifier coeff + void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; } + + /// Returns true if the specified player can pick the arrow up + bool CanPickup(const cPlayer & a_Player) const; + + // tolua_end + +protected: + + /// Determines when the arrow can be picked up by players + ePickupState m_PickupState; + + /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow + double m_DamageCoeff; + + // cProjectileEntity overrides: + virtual void SpawnOn(cClientHandle & a_Client) override; + + // tolua_begin +} ; + + + + + +class cThrownEggEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownEggEntity); + + cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // tolua_end + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + + // tolua_begin + +} ; + + + + + +class cThrownEnderPearlEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownEnderPearlEntity); + + cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // tolua_end + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + + // tolua_begin + +} ; + + + + + +class cThrownSnowballEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownSnowballEntity); + + cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // tolua_end + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + + // tolua_begin + +} ; + + + + + +// tolua_end + + + diff --git a/source/Entities/TNTEntity.cpp b/source/Entities/TNTEntity.cpp index 43a0dea09..ad3d9ae0c 100644 --- a/source/Entities/TNTEntity.cpp +++ b/source/Entities/TNTEntity.cpp @@ -29,20 +29,6 @@ cTNTEntity::cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec) : -bool cTNTEntity::Initialize(cWorld * a_World) -{ - if (super::Initialize(a_World)) - { - a_World->BroadcastSpawnEntity(*this); - return true; - } - return false; -} - - - - - void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle) { a_ClientHandle.SendSpawnObject(*this, 50, 1, 0, 0); // 50 means TNT diff --git a/source/Entities/TNTEntity.h b/source/Entities/TNTEntity.h index ae6fc75e2..eb5040e8a 100644 --- a/source/Entities/TNTEntity.h +++ b/source/Entities/TNTEntity.h @@ -19,7 +19,6 @@ public: cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec); // cEntity overrides: - 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/Items/ItemBow.h b/source/Items/ItemBow.h new file mode 100644 index 000000000..845192ef7 --- /dev/null +++ b/source/Items/ItemBow.h @@ -0,0 +1,80 @@ + +// ItemBow.h + +// Declares the cItemBowHandler class representing the itemhandler for bows + + + + + +#pragma once + +#include "../Entities/ProjectileEntity.h" + + + + + +class cItemBowHandler : + public cItemHandler +{ + typedef cItemHandler super; + +public: + cItemBowHandler(void) : + super(E_ITEM_BOW) + { + } + + + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override + { + ASSERT(a_Player != NULL); + + // Check if the player has an arrow in the inventory, or is in Creative: + if (!(a_Player->IsGameModeCreative() || a_Player->GetInventory().HasItems(cItem(E_ITEM_ARROW)))) + { + return false; + } + a_Player->StartChargingBow(); + return true; + } + + + virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override + { + // Actual shot - produce the arrow with speed based on the ticks that the bow was charged + ASSERT(a_Player != NULL); + + int BowCharge = a_Player->FinishChargingBow(); + double Force = (double)BowCharge / 20; + Force = (Force * Force + 2 * Force) / 3; // This formula is used by the 1.6.2 client + if (Force < 0.1) + { + // Too little force, ignore the shot + return; + } + if (Force > 1) + { + Force = 1; + } + + // Create the arrow entity: + cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2); + if (Arrow == NULL) + { + return; + } + if (!Arrow->Initialize(a_Player->GetWorld())) + { + delete Arrow; + return; + } + a_Player->GetWorld()->BroadcastSpawnEntity(*Arrow); + } +} ; + + + + + diff --git a/source/Items/ItemHandler.cpp b/source/Items/ItemHandler.cpp index 66d36e1a6..2ae193d52 100644 --- a/source/Items/ItemHandler.cpp +++ b/source/Items/ItemHandler.cpp @@ -8,6 +8,7 @@ // Handlers: #include "ItemBed.h" +#include "ItemBow.h" #include "ItemBrewingStand.h" #include "ItemBucket.h" #include "ItemCauldron.h" @@ -21,6 +22,7 @@ #include "ItemLighter.h" #include "ItemMinecart.h" #include "ItemPickaxe.h" +#include "ItemThrowable.h" #include "ItemRedstoneDust.h" #include "ItemRedstoneRepeater.h" #include "ItemSapling.h" @@ -47,18 +49,24 @@ cItemHandler * cItemHandler::m_ItemHandler[2268]; -cItemHandler *cItemHandler::GetItemHandler(int a_ItemType) +cItemHandler * cItemHandler::GetItemHandler(int a_ItemType) { - if(a_ItemType < 0) a_ItemType = 0; + if (a_ItemType < 0) + { + ASSERT(!"Bad item type"); + a_ItemType = 0; + } - if(!m_HandlerInitialized) - { //We have to initialize + if (!m_HandlerInitialized) + { + // We need to initialize memset(m_ItemHandler, 0, sizeof(m_ItemHandler)); m_HandlerInitialized = true; } - if(m_ItemHandler[a_ItemType]) - return m_ItemHandler[a_ItemType]; - m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType); + if (m_ItemHandler[a_ItemType] == NULL) + { + m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType); + } return m_ItemHandler[a_ItemType]; } @@ -77,15 +85,19 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType); case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType); case E_ITEM_BED: return new cItemBedHandler(a_ItemType); + case E_ITEM_BOW: return new cItemBowHandler; case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType); case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType); case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType); + case E_ITEM_EGG: return new cItemEggHandler(); + case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler(); case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType); case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType); case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType); case E_ITEM_REDSTONE_REPEATER: return new cItemRedstoneRepeaterHandler(a_ItemType); case E_ITEM_SHEARS: return new cItemShearsHandler(a_ItemType); case E_ITEM_SIGN: return new cItemSignHandler(a_ItemType); + case E_ITEM_SNOWBALL: return new cItemSnowballHandler(); case E_ITEM_SPAWN_EGG: return new cItemSpawnEggHandler(a_ItemType); case E_ITEM_SUGARCANE: return new cItemSugarcaneHandler(a_ItemType); diff --git a/source/Items/ItemHandler.h b/source/Items/ItemHandler.h index 44d43e8f7..e39bb054b 100644 --- a/source/Items/ItemHandler.h +++ b/source/Items/ItemHandler.h @@ -21,8 +21,11 @@ class cItemHandler public: cItemHandler(int a_ItemType); - /// Called when the player tries to use the item. Return false to make the item unusable. DEFAULT: False - virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir); //eg for fishing or hoes + /// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir); + + /// Called when the client sends the SHOOT status in the lclk packet + virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) {} /// Called while the player diggs a block using this item virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace); @@ -88,7 +91,7 @@ protected: int m_ItemType; static cItemHandler *CreateItemHandler(int m_ItemType); - static cItemHandler *m_ItemHandler[2268]; + static cItemHandler * m_ItemHandler[E_ITEM_LAST + 1]; static bool m_HandlerInitialized; //used to detect if the itemhandlers are initialized }; diff --git a/source/Items/ItemThrowable.h b/source/Items/ItemThrowable.h new file mode 100644 index 000000000..dacdb6157 --- /dev/null +++ b/source/Items/ItemThrowable.h @@ -0,0 +1,90 @@ + +// ItemThrowable.h + +// Declares the itemhandlers for throwable items: eggs, snowballs and ender pearls + + + + + +#pragma once + + + + + +class cItemThrowableHandler : + public cItemHandler +{ + typedef cItemHandler super; +public: + cItemThrowableHandler(int a_ItemType, cProjectileEntity::eKind a_ProjectileKind, double a_SpeedCoeff) : + super(a_ItemType), + m_ProjectileKind(a_ProjectileKind), + m_SpeedCoeff(a_SpeedCoeff) + { + } + + + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override + { + Vector3d Pos = a_Player->GetThrowStartPos(); + Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff; + a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &Speed); + return true; + } + +protected: + cProjectileEntity::eKind m_ProjectileKind; + double m_SpeedCoeff; +} ; + + + + + +class cItemEggHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; +public: + cItemEggHandler(void) : + super(E_ITEM_EGG, cProjectileEntity::pkEgg, 30) + { + } +} ; + + + + +class cItemSnowballHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; + +public: + cItemSnowballHandler(void) : + super(E_ITEM_SNOWBALL, cProjectileEntity::pkSnowball, 30) + { + } +} ; + + + + + +class cItemEnderPearlHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; + +public: + cItemEnderPearlHandler(void) : + super(E_ITEM_ENDER_PEARL, cProjectileEntity::pkEnderPearl, 30) + { + } +} ; + + + + diff --git a/source/LeakFinder.cpp b/source/LeakFinder.cpp index 3242bba04..272e313a0 100644 --- a/source/LeakFinder.cpp +++ b/source/LeakFinder.cpp @@ -116,12 +116,15 @@ /* _X: MSVC 2012 (MSC 1700) seems to use a different allocation scheme for STL containers, * allocating lots of small objects and running out of memory very soon * Thus for MSVC 2012 we cut the callstack buffer length in half +* +* _X 2013_08_25: The callstack tracking gets worse even for MSVC 2008, a single lua_state eats 50 MiB of RAM +* Therefore I decided to further reduce the buffers from 0x2000 to 0x1000 */ // Controlling the callstack depth #if (_MSC_VER < 1700) - #define MAX_CALLSTACK_LEN_BUF 0x2000 -#else #define MAX_CALLSTACK_LEN_BUF 0x1000 +#else + #define MAX_CALLSTACK_LEN_BUF 0x0800 #endif @@ -942,10 +945,10 @@ static int MyAllocHook(int nAllocType, void *pvData, g_CurrentMemUsage += nSize ; g_pCRTTable->Insert(lRequest, c, nSize); - if (g_CurrentMemUsage > 1073741824) //This is 1 gb = 1024 * 1024* 1024. + if (g_CurrentMemUsage > 1536 * 1024* 1024) { printf("******************************************\n"); - printf("** Server reached 1 GiB memory usage, **\n"); + printf("** Server reached 1.5 GiB memory usage, **\n"); printf("** something is probably wrong. **\n"); printf("** Writing memory dump into memdump.xml **\n"); printf("******************************************\n"); diff --git a/source/LineBlockTracer.cpp b/source/LineBlockTracer.cpp index 03464314a..7cc14089d 100644 --- a/source/LineBlockTracer.cpp +++ b/source/LineBlockTracer.cpp @@ -55,6 +55,7 @@ bool cLineBlockTracer::Trace(double a_StartX, double a_StartY, double a_StartZ, m_DirX = (m_StartX < m_EndX) ? 1 : -1; m_DirY = (m_StartY < m_EndY) ? 1 : -1; m_DirZ = (m_StartZ < m_EndZ) ? 1 : -1; + m_CurrentFace = BLOCK_FACE_NONE; // Check the start coords, adjust into the world: if (m_StartY < 0) @@ -178,9 +179,9 @@ bool cLineBlockTracer::MoveToNextBlock(void) // Based on the wall hit, adjust the current coords switch (Direction) { - case dirX: m_CurrentX += m_DirX; break; - case dirY: m_CurrentY += m_DirY; break; - case dirZ: m_CurrentZ += m_DirZ; break; + case dirX: m_CurrentX += m_DirX; m_CurrentFace = (m_DirX > 0) ? BLOCK_FACE_EAST : BLOCK_FACE_WEST; break; + case dirY: m_CurrentY += m_DirY; m_CurrentFace = (m_DirY > 0) ? BLOCK_FACE_BOTTOM : BLOCK_FACE_TOP; break; + case dirZ: m_CurrentZ += m_DirZ; m_CurrentFace = (m_DirZ > 0) ? BLOCK_FACE_SOUTH : BLOCK_FACE_NORTH; break; case dirNONE: return false; } return true; @@ -211,7 +212,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk) int RelX = m_CurrentX - a_Chunk->GetPosX() * cChunkDef::Width; int RelZ = m_CurrentZ - a_Chunk->GetPosZ() * cChunkDef::Width; a_Chunk->GetBlockTypeMeta(RelX, m_CurrentY, RelZ, BlockType, BlockMeta); - if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta)) + if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta, m_CurrentFace)) { // The callback terminated the trace return false; @@ -219,7 +220,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk) } else { - if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ)) + if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ, m_CurrentFace)) { // The callback terminated the trace return false; diff --git a/source/LineBlockTracer.h b/source/LineBlockTracer.h index 4616cb191..ccbb70ea6 100644 --- a/source/LineBlockTracer.h +++ b/source/LineBlockTracer.h @@ -60,6 +60,9 @@ protected: // The current block int m_CurrentX, m_CurrentY, m_CurrentZ; + + // The face through which the current block has been entered + char m_CurrentFace; /// Adjusts the start point above the world to just at the world's top diff --git a/source/LuaState.cpp b/source/LuaState.cpp index bbf47fb27..8d2fa8eca 100644 --- a/source/LuaState.cpp +++ b/source/LuaState.cpp @@ -884,6 +884,49 @@ bool cLuaState::ReportErrors(lua_State * a_LuaState, int a_Status) +void cLuaState::LogStackTrace(void) +{ + LOGWARNING("Stack trace:"); + lua_Debug entry; + int depth = 0; + while (lua_getstack(m_LuaState, depth, &entry)) + { + int status = lua_getinfo(m_LuaState, "Sln", &entry); + assert(status); + + LOGWARNING(" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "?"); + depth++; + } + LOGWARNING("Stack trace end"); +} + + + + + +AString cLuaState::GetTypeText(int a_StackPos) +{ + int Type = lua_type(m_LuaState, a_StackPos); + switch (Type) + { + case LUA_TNONE: return "TNONE"; + case LUA_TNIL: return "TNIL"; + case LUA_TBOOLEAN: return "TBOOLEAN"; + case LUA_TLIGHTUSERDATA: return "TLIGHTUSERDATA"; + case LUA_TNUMBER: return "TNUMBER"; + case LUA_TSTRING: return "TSTRING"; + case LUA_TTABLE: return "TTABLE"; + case LUA_TFUNCTION: return "TFUNCTION"; + case LUA_TUSERDATA: return "TUSERDATA"; + case LUA_TTHREAD: return "TTHREAD"; + } + return Printf("Unknown (%d)", Type); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cLuaState::cRef: diff --git a/source/LuaState.h b/source/LuaState.h index 0eae8206d..caba2484d 100644 --- a/source/LuaState.h +++ b/source/LuaState.h @@ -77,7 +77,7 @@ public: bool IsValid(void) const {return (m_Ref != LUA_REFNIL); } /// Allows to use this class wherever an int (i. e. ref) is to be used - operator int(void) { return m_Ref; } + operator int(void) const { return m_Ref; } protected: cLuaState & m_LuaState; @@ -782,6 +782,12 @@ public: /// If the status is nonzero, prints the text on the top of Lua stack and returns true static bool ReportErrors(lua_State * a_LuaState, int status); + /// Logs all items in the current stack trace to the server console + void LogStackTrace(void); + + /// Returns the type of the item on the specified position in the stack + AString GetTypeText(int a_StackPos); + protected: lua_State * m_LuaState; diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index c975997a5..87efecd35 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -755,6 +755,159 @@ static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) +static int tolua_cPluginManager_AddHook_FnRef(cPluginManager * a_PluginManager, cLuaState & S, int a_ParamIdx) +{ + // Helper function for cPluginmanager:AddHook() binding + // Takes care of the new case (#121): args are HOOK_TYPE and CallbackFunction + // The arg types have already been checked + + // Retrieve the cPlugin from the LuaState: + cPluginLua * Plugin = GetLuaPlugin(S); + if (Plugin == NULL) + { + // An error message has been already printed in GetLuaPlugin() + return 0; + } + + // Retrieve and check the hook type + int HookType = (int)tolua_tonumber(S, a_ParamIdx, -1); + if (!a_PluginManager->IsValidHookType(HookType)) + { + LOGWARNING("cPluginManager.AddHook(): Invalid HOOK_TYPE parameter: %d", HookType); + S.LogStackTrace(); + return 0; + } + + // Add the hook to the plugin + if (!Plugin->AddHookRef(HookType, a_ParamIdx + 1)) + { + LOGWARNING("cPluginManager.AddHook(): Cannot add hook %d, unknown error.", HookType); + S.LogStackTrace(); + return 0; + } + a_PluginManager->AddHook(Plugin, HookType); + + // Success + return 0; +} + + + + + +static int tolua_cPluginManager_AddHook_DefFn(cPluginManager * a_PluginManager, cLuaState & S, int a_ParamIdx) +{ + // Helper function for cPluginmanager:AddHook() binding + // Takes care of the old case (#121): args are cPluginLua and HOOK_TYPE + // The arg types have already been checked + + // Retrieve and check the cPlugin parameter + cPluginLua * Plugin = (cPluginLua *)tolua_tousertype(S, a_ParamIdx, NULL); + if (Plugin == NULL) + { + LOGWARNING("cPluginManager.AddHook(): Invalid Plugin parameter, expected a valid cPlugin object. Hook not added"); + S.LogStackTrace(); + return 0; + } + if (Plugin != GetLuaPlugin(S)) + { + // The plugin parameter passed to us is not our stored plugin. Disallow this! + LOGWARNING("cPluginManager.AddHook(): Invalid Plugin parameter, cannot add hook to foreign plugins. Hook not added."); + S.LogStackTrace(); + return 0; + } + + // Retrieve and check the hook type + int HookType = (int)tolua_tonumber(S, a_ParamIdx + 1, -1); + if (!a_PluginManager->IsValidHookType(HookType)) + { + LOGWARNING("cPluginManager.AddHook(): Invalid HOOK_TYPE parameter: %d", HookType); + S.LogStackTrace(); + return 0; + } + + // Get the standard name for the callback function: + const char * FnName = cPluginLua::GetHookFnName(HookType); + if (FnName == NULL) + { + LOGWARNING("cPluginManager.AddHook(): Unknown hook type (%d). Hook not added.", HookType); + S.LogStackTrace(); + return 0; + } + + // Retrieve the function to call and add it to the plugin: + lua_pushstring(S, FnName); + bool res = Plugin->AddHookRef(HookType, 1); + lua_pop(S, 1); // Pop the function off the stack + if (!res) + { + LOGWARNING("cPluginManager.AddHook(): Function %s not found. Hook not added.", FnName); + S.LogStackTrace(); + return 0; + } + a_PluginManager->AddHook(Plugin, HookType); + + // Success + return 0; +} + + + + + +static int tolua_cPluginManager_AddHook(lua_State * tolua_S) +{ + /* + Function signatures: + cPluginManager.AddHook(HOOK_TYPE, CallbackFunction) -- (1) recommended + cPluginManager:Get():AddHook(HOOK_TYPE, CallbackFunction) -- (2) accepted silently + cPluginManager:Get():AddHook(Plugin, HOOK_TYPE) -- (3) old style (#121), accepted but complained about + cPluginManager.AddHook(Plugin, HOOK_TYPE) -- (4) old style (#121) mangled, accepted but complained about + */ + + cLuaState S(tolua_S); + cPluginManager * PlgMgr = cPluginManager::Get(); + + // If the first param is a cPluginManager, use it instead of the global one: + int ParamIdx = 1; + tolua_Error err; + if (tolua_isusertype(S, 1, "cPluginManager", 0, &err)) + { + // Style 2 or 3, retrieve the PlgMgr instance + PlgMgr = (cPluginManager *)tolua_tousertype(S, 1, NULL); + if (PlgMgr == NULL) + { + LOGWARNING("Malformed plugin, use cPluginManager.AddHook(HOOK_TYPE, CallbackFunction). Fixing the call for you."); + S.LogStackTrace(); + PlgMgr = cPluginManager::Get(); + } + ParamIdx += 1; + } + + if (lua_isnumber(S, ParamIdx) && lua_isfunction(S, ParamIdx + 1)) + { + // The next params are a number and a function, assume style 1 or 2 + return tolua_cPluginManager_AddHook_FnRef(PlgMgr, S, ParamIdx); + } + else if (tolua_isusertype(S, ParamIdx, "cPlugin", 0, &err) && lua_isnumber(S, ParamIdx + 1)) + { + // The next params are a cPlugin and a number, assume style 3 or 4 + LOGINFO("cPluginManager.AddHook(): Deprecated format used, use cPluginManager.AddHook(HOOK_TYPE, CallbackFunction) instead. Fixing the call for you."); + S.LogStackTrace(); + return tolua_cPluginManager_AddHook_DefFn(PlgMgr, S, ParamIdx); + } + + AString ParamDesc; + Printf(ParamDesc, "%s, %s, %s", S.GetTypeText(1).c_str(), S.GetTypeText(2).c_str(), S.GetTypeText(3).c_str()); + LOGWARNING("cPluginManager.AddHook(): bad parameters. Expected HOOK_TYPE and CallbackFunction, got %s. Hook not added.", ParamDesc.c_str()); + S.LogStackTrace(); + return 0; +} + + + + + static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S) { int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ @@ -1496,7 +1649,7 @@ public: { } - virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override { if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlock")) { @@ -1508,6 +1661,7 @@ public: m_LuaState.Push(a_BlockZ); m_LuaState.Push(a_BlockType); m_LuaState.Push(a_BlockMeta); + m_LuaState.Push(a_EntryFace); if (!m_LuaState.CallFunction(1)) { return false; @@ -1521,7 +1675,7 @@ public: return res; } - virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) override + virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) override { if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlockNoData")) { @@ -1531,6 +1685,7 @@ public: m_LuaState.Push(a_BlockX); m_LuaState.Push(a_BlockY); m_LuaState.Push(a_BlockZ); + m_LuaState.Push(a_EntryFace); if (!m_LuaState.CallFunction(1)) { return false; @@ -1699,6 +1854,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "ForEachCommand", tolua_cPluginManager_ForEachCommand); tolua_function(tolua_S, "ForEachConsoleCommand", tolua_cPluginManager_ForEachConsoleCommand); tolua_function(tolua_S, "GetAllPlugins", tolua_cPluginManager_GetAllPlugins); + tolua_function(tolua_S, "AddHook", tolua_cPluginManager_AddHook); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPlayer"); diff --git a/source/OSSupport/IsThread.cpp b/source/OSSupport/IsThread.cpp index 45e329a68..d5fbfcf19 100644 --- a/source/OSSupport/IsThread.cpp +++ b/source/OSSupport/IsThread.cpp @@ -136,17 +136,29 @@ bool cIsThread::Wait(void) { return true; } - LOGD("Waiting for thread %s to finish", m_ThreadName.c_str()); + + #ifdef LOGD // ProtoProxy doesn't have LOGD + LOGD("Waiting for thread %s to finish", m_ThreadName.c_str()); + #endif // LOGD #ifdef _WIN32 int res = WaitForSingleObject(m_Handle, INFINITE); m_Handle = NULL; - LOGD("Thread %s finished", m_ThreadName.c_str()); + + #ifdef LOGD // ProtoProxy doesn't have LOGD + LOGD("Thread %s finished", m_ThreadName.c_str()); + #endif // LOGD + return (res == WAIT_OBJECT_0); #else // _WIN32 int res = pthread_join(m_Handle, NULL); m_Handle = NULL; - LOGD("Thread %s finished", m_ThreadName.c_str()); + + #ifdef LOGD // ProtoProxy doesn't have LOGD + LOGD("Thread %s finished", m_ThreadName.c_str()); + #endif // LOGD + + m_HasStarted = false; return (res == 0); #endif // else _WIN32 } diff --git a/source/OSSupport/ListenThread.cpp b/source/OSSupport/ListenThread.cpp index c586227df..0890aabc8 100644 --- a/source/OSSupport/ListenThread.cpp +++ b/source/OSSupport/ListenThread.cpp @@ -80,7 +80,7 @@ void cListenThread::Stop(void) super::Wait(); // Close all the listening sockets: - for (cSockets::iterator itr = m_Sockets.begin(), end = m_Sockets.end(); itr != end; ++itr) + for (cSockets::iterator itr = m_Sockets.begin() + 1, end = m_Sockets.end(); itr != end; ++itr) { itr->CloseSocket(); } // for itr - m_Sockets[] diff --git a/source/OSSupport/Socket.cpp b/source/OSSupport/Socket.cpp index f79bdbf47..48b5d704d 100644 --- a/source/OSSupport/Socket.cpp +++ b/source/OSSupport/Socket.cpp @@ -74,11 +74,11 @@ void cSocket::CloseSocket() if (shutdown(m_Socket, SHUT_RDWR) != 0)//SD_BOTH); { - LOGWARN("Error on shutting down socket (%s): %s", m_IPString.c_str(), GetLastErrorString().c_str()); + LOGWARN("Error on shutting down socket %d (%s): %s", m_Socket, m_IPString.c_str(), GetLastErrorString().c_str()); } if (close(m_Socket) != 0) { - LOGWARN("Error closing socket (%s): %s", m_IPString.c_str(), GetLastErrorString().c_str()); + LOGWARN("Error closing socket %d (%s): %s", m_Socket, m_IPString.c_str(), GetLastErrorString().c_str()); } #endif // else _WIN32 diff --git a/source/OSSupport/Timer.cpp b/source/OSSupport/Timer.cpp index ab7325b5e..ed16f9e3a 100644 --- a/source/OSSupport/Timer.cpp +++ b/source/OSSupport/Timer.cpp @@ -8,33 +8,30 @@ -cTimer::cTimer() -#ifdef _WIN32 - : m_TicksPerSecond( new LARGE_INTEGER ) -#endif +cTimer::cTimer(void) { -#ifdef _WIN32 - QueryPerformanceFrequency( (LARGE_INTEGER*)m_TicksPerSecond ); -#endif + #ifdef _WIN32 + QueryPerformanceFrequency(&m_TicksPerSecond); + #endif } -cTimer::~cTimer() + + + + +long long cTimer::GetNowTime(void) { -#ifdef _WIN32 - delete (LARGE_INTEGER*)m_TicksPerSecond; -#endif + #ifdef _WIN32 + LARGE_INTEGER now; + QueryPerformanceCounter(&now); + return ((now.QuadPart * 1000) / m_TicksPerSecond.QuadPart); + #else + struct timeval now; + gettimeofday(&now, NULL); + return (long long)(now.tv_sec * 1000 + now.tv_usec / 1000); + #endif } -long long cTimer::GetNowTime() -{ -#ifdef _WIN32 - LARGE_INTEGER now; - QueryPerformanceCounter( &now ); - LARGE_INTEGER & tps = *((LARGE_INTEGER*)m_TicksPerSecond); - return ((now.QuadPart*1000) / tps.QuadPart ); -#else - struct timeval now; - gettimeofday(&now, NULL); - return (long long)(now.tv_sec*1000 + now.tv_usec/1000); -#endif -}
\ No newline at end of file + + + diff --git a/source/OSSupport/Timer.h b/source/OSSupport/Timer.h index 5969d0fc9..a059daa41 100644 --- a/source/OSSupport/Timer.h +++ b/source/OSSupport/Timer.h @@ -1,15 +1,32 @@ + +// Timer.h + +// Declares the cTimer class representing an OS-independent of retrieving current time with msec accuracy + + + + + #pragma once + + + + class cTimer { public: - cTimer(); - ~cTimer(); + cTimer(void); - long long GetNowTime(); + // Returns the current time expressed in milliseconds + long long GetNowTime(void); private: -#ifdef _WIN32 - void* m_TicksPerSecond; // LARGE_INTEGER* -#endif -};
\ No newline at end of file + #ifdef _WIN32 + LARGE_INTEGER m_TicksPerSecond; + #endif +} ; + + + + diff --git a/source/Plugin.h b/source/Plugin.h index 2595b9470..be803bab2 100644 --- a/source/Plugin.h +++ b/source/Plugin.h @@ -113,13 +113,6 @@ public: /// All bound console commands are to be removed, do any language-dependent cleanup here virtual void ClearConsoleCommands(void) {} ; - /** Called from cPluginManager::AddHook() to check if the hook can be added. - Plugin API providers may check if the plugin is written correctly (has the hook handler function) - Returns true if the hook can be added (handler exists) - Descendants should also log the specific error message as a warning if they return false. - */ - virtual bool CanAddHook(cPluginManager::PluginHook a_Hook) = 0; - // tolua_begin const AString & GetName(void) const { return m_Name; } void SetName(const AString & a_Name) { m_Name = a_Name; } diff --git a/source/PluginLua.cpp b/source/PluginLua.cpp index 5128ef0b0..81a536838 100644 --- a/source/PluginLua.cpp +++ b/source/PluginLua.cpp @@ -36,7 +36,33 @@ cPluginLua::cPluginLua(const AString & a_PluginDirectory) : cPluginLua::~cPluginLua() { cCSLock Lock(m_CriticalSection); - m_LuaState.Close(); + Close(); +} + + + + + +void cPluginLua::Close(void) +{ + if (m_LuaState.IsValid()) + { + // Release all the references in the hook map: + for (cHookMap::iterator itrH = m_HookMap.begin(), endH = m_HookMap.end(); itrH != endH; ++itrH) + { + for (cLuaRefs::iterator itrR = itrH->second.begin(), endR = itrH->second.end(); itrR != endR; ++itrR) + { + delete *itrR; + } // for itrR - itrH->second[] + } // for itrH - m_HookMap[] + m_HookMap.clear(); + + m_LuaState.Close(); + } + else + { + ASSERT(m_HookMap.empty()); + } } @@ -70,7 +96,7 @@ bool cPluginLua::Initialize(void) AString Path = PluginPath + *itr; if (!m_LuaState.LoadFile(Path)) { - m_LuaState.Close(); + Close(); return false; } } // for itr - Files[] @@ -80,14 +106,14 @@ bool cPluginLua::Initialize(void) if (!m_LuaState.Call("Initialize", this, cLuaState::Return, res)) { LOGWARNING("Error in plugin %s: Cannot call the Initialize() function. Plugin is temporarily disabled.", GetName().c_str()); - m_LuaState.Close(); + Close(); return false; } if (!res) { LOGINFO("Plugin %s: Initialize() call failed, plugin is temporarily disabled.", GetName().c_str()); - m_LuaState.Close(); + Close(); return false; } @@ -115,7 +141,11 @@ void cPluginLua::OnDisable(void) void cPluginLua::Tick(float a_Dt) { cCSLock Lock(m_CriticalSection); - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_TICK), a_Dt); + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TICK]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_Dt); + } } @@ -126,8 +156,16 @@ bool cPluginLua::OnBlockToPickups(cWorld * a_World, cEntity * a_Digger, int a_Bl { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_BLOCK_TO_PICKUPS), a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, &a_Pickups, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_TO_PICKUPS]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, &a_Pickups, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -138,8 +176,16 @@ bool cPluginLua::OnChat(cPlayer * a_Player, AString & a_Message) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHAT), a_Player, a_Message, cLuaState::Return, res, a_Message); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHAT]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_Player, a_Message, cLuaState::Return, res, a_Message); + if (res) + { + return true; + } + } + return false; } @@ -150,8 +196,16 @@ bool cPluginLua::OnChunkAvailable(cWorld * a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHUNK_AVAILABLE), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_AVAILABLE]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -162,8 +216,16 @@ bool cPluginLua::OnChunkGenerated(cWorld * a_World, int a_ChunkX, int a_ChunkZ, { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHUNK_GENERATED), a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATED]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -174,8 +236,16 @@ bool cPluginLua::OnChunkGenerating(cWorld * a_World, int a_ChunkX, int a_ChunkZ, { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHUNK_GENERATING), a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -186,8 +256,16 @@ bool cPluginLua::OnChunkUnloaded(cWorld * a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHUNK_UNLOADED), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADED]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -198,8 +276,16 @@ bool cPluginLua::OnChunkUnloading(cWorld * a_World, int a_ChunkX, int a_ChunkZ) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHUNK_UNLOADING), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -210,8 +296,16 @@ bool cPluginLua::OnCollectingPickup(cPlayer * a_Player, cPickup * a_Pickup) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_COLLECTING_PICKUP), a_Player, a_Pickup, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_COLLECTING_PICKUP]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_Player, a_Pickup, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -222,8 +316,16 @@ bool cPluginLua::OnCraftingNoRecipe(const cPlayer * a_Player, const cCraftingGri { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CRAFTING_NO_RECIPE), (cPlayer *)a_Player, a_Grid, a_Recipe, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CRAFTING_NO_RECIPE]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), (cPlayer *)a_Player, a_Grid, a_Recipe, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -234,8 +336,16 @@ bool cPluginLua::OnDisconnect(cPlayer * a_Player, const AString & a_Reason) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_DISCONNECT), a_Player, a_Reason, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_Player, a_Reason, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -246,8 +356,16 @@ bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Sp { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_EXECUTE_COMMAND), a_Player, a_Split, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXECUTE_COMMAND]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_Player, a_Split, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -258,26 +376,33 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can { cCSLock Lock(m_CriticalSection); bool res = false; - const char * FnName = GetHookFnName(cPluginManager::HOOK_EXPLODED); - switch (a_Source) - { - case esOther: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; - case esPrimedTNT: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res); break; - case esCreeper: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res); break; - case esBed: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break; - case esEnderCrystal: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break; - case esGhastFireball: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; - case esWitherSkullBlack: - case esWitherSkullBlue: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; - case esWitherBirth: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; - case esPlugin: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; - default: + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODED]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + switch (a_Source) { - ASSERT(!"Unhandled ExplosionSource"); - return false; + case esOther: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; + case esPrimedTNT: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res); break; + case esCreeper: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res); break; + case esBed: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break; + case esEnderCrystal: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break; + case esGhastFireball: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; + case esWitherSkullBlack: + case esWitherSkullBlue: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; + case esWitherBirth: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; + case esPlugin: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; + default: + { + ASSERT(!"Unhandled ExplosionSource"); + return false; + } + } + if (res) + { + return true; } } - return res; + return false; } @@ -288,26 +413,33 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & { cCSLock Lock(m_CriticalSection); bool res = false; - const char * FnName = GetHookFnName(cPluginManager::HOOK_EXPLODING); - switch (a_Source) - { - case esOther: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esPrimedTNT: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esCreeper: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esBed: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esEnderCrystal: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esGhastFireball: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esWitherSkullBlack: - case esWitherSkullBlue: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esWitherBirth: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esPlugin: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - default: + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + switch (a_Source) { - ASSERT(!"Unhandled ExplosionSource"); - return false; + case esOther: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esPrimedTNT: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esCreeper: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esBed: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esEnderCrystal: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esGhastFireball: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esWitherSkullBlack: + case esWitherSkullBlue: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esWitherBirth: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esPlugin: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + default: + { + ASSERT(!"Unhandled ExplosionSource"); + return false; + } + } + if (res) + { + return true; } } - return res; + return false; } @@ -318,8 +450,16 @@ bool cPluginLua::OnHandshake(cClientHandle * a_Client, const AString & a_Usernam { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_HANDSHAKE), a_Client, a_Username, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HANDSHAKE]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_Client, a_Username, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -330,8 +470,17 @@ bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper, { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_HOPPER_PULLING_ITEM), &a_World, &a_Hopper, a_DstSlotNum, &a_SrcEntity, a_SrcSlotNum, cLuaState::Return, res); - return res; + + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PULLING_ITEM]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_World, &a_Hopper, a_DstSlotNum, &a_SrcEntity, a_SrcSlotNum, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -342,8 +491,16 @@ bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper, { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_HOPPER_PUSHING_ITEM), &a_World, &a_Hopper, a_SrcSlotNum, &a_DstEntity, a_DstSlotNum, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PUSHING_ITEM]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_World, &a_Hopper, a_SrcSlotNum, &a_DstEntity, a_DstSlotNum, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -354,8 +511,16 @@ bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_KILLING), &a_Victim, a_Killer, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_KILLING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Victim, a_Killer, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -366,8 +531,16 @@ bool cPluginLua::OnLogin(cClientHandle * a_Client, int a_ProtocolVersion, const { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_LOGIN), a_Client, a_ProtocolVersion, a_Username, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_LOGIN]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_Client, a_ProtocolVersion, a_Username, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -378,8 +551,16 @@ bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_ANIMATION), &a_Player, a_Animation, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_ANIMATION]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_Animation, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -390,8 +571,16 @@ bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_B { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_BREAKING_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BREAKING_BLOCK]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -402,8 +591,16 @@ bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_Blo { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_BROKEN_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BROKEN_BLOCK]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -414,8 +611,16 @@ bool cPluginLua::OnPlayerEating(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_EATING), &a_Player, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_EATING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -426,8 +631,16 @@ bool cPluginLua::OnPlayerJoined(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_JOINED), &a_Player, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_JOINED]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -438,8 +651,16 @@ bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_Block { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_LEFT_CLICK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_LEFT_CLICK]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -450,8 +671,16 @@ bool cPluginLua::OnPlayerMoved(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_MOVING), &a_Player, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_MOVING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -462,8 +691,16 @@ bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, int a_BlockX, int a_Blo { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_PLACED_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACED_BLOCK]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -474,8 +711,16 @@ bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, int a_BlockX, int a_Bl { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_PLACING_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACING_BLOCK]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -486,8 +731,16 @@ bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_Bloc { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_RIGHT_CLICK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICK]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -498,8 +751,16 @@ bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Ent { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY), &a_Player, &a_Entity, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, &a_Entity, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -510,8 +771,16 @@ bool cPluginLua::OnPlayerShooting(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_SHOOTING), &a_Player, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SHOOTING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -522,8 +791,16 @@ bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_SPAWNED), &a_Player, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SPAWNED]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -534,8 +811,16 @@ bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_TOSSING_ITEM), &a_Player, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_TOSSING_ITEM]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -546,8 +831,16 @@ bool cPluginLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_Block { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_USED_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_BLOCK]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -558,8 +851,16 @@ bool cPluginLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_USED_ITEM), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_ITEM]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -570,8 +871,16 @@ bool cPluginLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_Bloc { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_USING_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_BLOCK]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -582,8 +891,16 @@ bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_Block { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_USING_ITEM), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_ITEM]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -594,8 +911,16 @@ bool cPluginLua::OnPostCrafting(const cPlayer * a_Player, const cCraftingGrid * { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_POST_CRAFTING), a_Player, a_Grid, a_Recipe, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_POST_CRAFTING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_Player, a_Grid, a_Recipe, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -606,8 +931,16 @@ bool cPluginLua::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid * a { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PRE_CRAFTING), a_Player, a_Grid, a_Recipe, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PRE_CRAFTING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_Player, a_Grid, a_Recipe, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -618,8 +951,16 @@ bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_SPAWNED_ENTITY), &a_World, &a_Entity, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_ENTITY]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_World, &a_Entity, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -630,8 +971,16 @@ bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_SPAWNED_MONSTER), &a_World, &a_Monster, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_MONSTER]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_World, &a_Monster, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -642,8 +991,16 @@ bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_SPAWNING_ENTITY), &a_World, &a_Entity, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_ENTITY]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_World, &a_Entity, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -654,8 +1011,16 @@ bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_SPAWNING_MONSTER), &a_World, &a_Monster, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_MONSTER]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_World, &a_Monster, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -666,8 +1031,16 @@ bool cPluginLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_TAKE_DAMAGE), &a_Receiver, &a_TDI, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TAKE_DAMAGE]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_Receiver, &a_TDI, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -683,8 +1056,16 @@ bool cPluginLua::OnUpdatedSign( { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_UPDATED_SIGN), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATED_SIGN]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -700,8 +1081,16 @@ bool cPluginLua::OnUpdatingSign( { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_UPDATING_SIGN), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res, a_Line1, a_Line2, a_Line3, a_Line4); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATING_SIGN]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res, a_Line1, a_Line2, a_Line3, a_Line4); + if (res) + { + return true; + } + } + return false; } @@ -712,8 +1101,16 @@ bool cPluginLua::OnWeatherChanged(cWorld & a_World) { cCSLock Lock(m_CriticalSection); bool res = false; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_WEATHER_CHANGED), &a_World, cLuaState::Return, res); - return res; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGED]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_World, cLuaState::Return, res); + if (res) + { + return true; + } + } + return false; } @@ -725,9 +1122,18 @@ bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather) cCSLock Lock(m_CriticalSection); bool res = false; int NewWeather = a_NewWeather; - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_WEATHER_CHANGING), &a_World, a_NewWeather, cLuaState::Return, res, NewWeather); + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGING]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_World, NewWeather, cLuaState::Return, res, NewWeather); + if (res) + { + a_NewWeather = (eWeather)NewWeather; + return true; + } + } a_NewWeather = (eWeather)NewWeather; - return res; + return false; } @@ -737,7 +1143,11 @@ bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather) bool cPluginLua::OnWorldTick(cWorld & a_World, float a_Dt) { cCSLock Lock(m_CriticalSection); - m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_WORLD_TICK), &a_World, a_Dt); + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_TICK]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + m_LuaState.Call((int)(**itr), &a_World, a_Dt); + } return false; } @@ -830,13 +1240,16 @@ void cPluginLua::ClearConsoleCommands(void) -bool cPluginLua::CanAddHook(cPluginManager::PluginHook a_Hook) +bool cPluginLua::CanAddOldStyleHook(int a_HookType) { - const char * FnName = GetHookFnName(a_Hook); + const char * FnName = GetHookFnName(a_HookType); if (FnName == NULL) { // Unknown hook ID - LOGWARNING("Plugin %s wants to add an unknown hook ID (%d). The plugin need not work properly.", GetName().c_str(), a_Hook); + LOGWARNING("Plugin %s wants to add an unknown hook ID (%d). The plugin need not work properly.", + GetName().c_str(), a_HookType + ); + m_LuaState.LogStackTrace(); return false; } @@ -847,23 +1260,9 @@ bool cPluginLua::CanAddHook(cPluginManager::PluginHook a_Hook) } LOGWARNING("Plugin %s wants to add a hook (%d), but it doesn't provide the callback function \"%s\" for it. The plugin need not work properly.", - GetName().c_str(), a_Hook, FnName + GetName().c_str(), a_HookType, FnName ); - - // Lua stacktrace: - LOGWARNING("Stack trace:"); - lua_Debug entry; - int depth = 0; - while (lua_getstack(m_LuaState, depth, &entry)) - { - int status = lua_getinfo(m_LuaState, "Sln", &entry); - assert(status); - - LOGWARNING(" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "?"); - depth++; - } - LOGWARNING("Stack trace end"); - + m_LuaState.LogStackTrace(); return false; } @@ -871,9 +1270,9 @@ bool cPluginLua::CanAddHook(cPluginManager::PluginHook a_Hook) -const char * cPluginLua::GetHookFnName(cPluginManager::PluginHook a_Hook) +const char * cPluginLua::GetHookFnName(int a_HookType) { - switch (a_Hook) + switch (a_HookType) { case cPluginManager::HOOK_BLOCK_TO_PICKUPS: return "OnBlockToPickups"; case cPluginManager::HOOK_CHAT: return "OnChat"; @@ -928,6 +1327,28 @@ const char * cPluginLua::GetHookFnName(cPluginManager::PluginHook a_Hook) +bool cPluginLua::AddHookRef(int a_HookType, int a_FnRefIdx) +{ + ASSERT(m_CriticalSection.IsLockedByCurrentThread()); // It probably has to be, how else would we have a LuaState? + + // Check if the function reference is valid: + cLuaState::cRef * Ref = new cLuaState::cRef(m_LuaState, a_FnRefIdx); + if ((Ref == NULL) || !Ref->IsValid()) + { + LOGWARNING("Plugin %s tried to add a hook %d with bad handler function.", GetName().c_str(), a_HookType); + m_LuaState.LogStackTrace(); + delete Ref; + return false; + } + + m_HookMap[a_HookType].push_back(Ref); + return true; +} + + + + + AString cPluginLua::HandleWebRequest(const HTTPRequest * a_Request ) { cCSLock Lock(m_CriticalSection); diff --git a/source/PluginLua.h b/source/PluginLua.h index 300fadc8b..fee9c4986 100644 --- a/source/PluginLua.h +++ b/source/PluginLua.h @@ -100,7 +100,8 @@ public: virtual void ClearConsoleCommands(void) override; - virtual bool CanAddHook(cPluginManager::PluginHook a_Hook) override; + /// Returns true if the plugin contains the function for the specified hook type, using the old-style registration (#121) + bool CanAddOldStyleHook(int a_HookType); // cWebPlugin override virtual const AString GetWebTitle(void) const {return GetName(); } @@ -128,18 +129,35 @@ public: /// Calls the plugin-specified "cLuaWindow slot changed" callback. void CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, int a_SlotNum); -protected: - cCriticalSection m_CriticalSection; - cLuaState m_LuaState; + /// Returns the name of Lua function that should handle the specified hook type in the older (#121) API + static const char * GetHookFnName(int a_HookType); + /** Adds a Lua function to be called for the specified hook. + The function has to be on the Lua stack at the specified index a_FnRefIdx + Returns true if the hook was added successfully. + */ + bool AddHookRef(int a_HookType, int a_FnRefIdx); + +protected: /// Maps command name into Lua function reference typedef std::map<AString, int> CommandMap; + /// Provides an array of Lua function references + typedef std::vector<cLuaState::cRef *> cLuaRefs; + + /// Maps hook types into arrays of Lua function references to call for each hook type + typedef std::map<int, cLuaRefs> cHookMap; + + cCriticalSection m_CriticalSection; + cLuaState m_LuaState; + CommandMap m_Commands; CommandMap m_ConsoleCommands; - - /// Returns the name of Lua function that should handle the specified hook - const char * GetHookFnName(cPluginManager::PluginHook a_Hook); + + cHookMap m_HookMap; + + /// Releases all Lua references and closes the LuaState + void Close(void); } ; // tolua_export diff --git a/source/PluginManager.cpp b/source/PluginManager.cpp index e6ff3e6e2..93ee71926 100644 --- a/source/PluginManager.cpp +++ b/source/PluginManager.cpp @@ -61,7 +61,7 @@ void cPluginManager::FindPlugins(void) // First get a clean list of only the currently running plugins, we don't want to mess those up for (PluginMap::iterator itr = m_Plugins.begin(); itr != m_Plugins.end();) { - if( itr->second == NULL ) + if (itr->second == NULL) { PluginMap::iterator thiz = itr; ++thiz; @@ -1585,6 +1585,15 @@ void cPluginManager::TabCompleteCommand(const AString & a_Text, AStringVector & +bool cPluginManager::IsValidHookType(int a_HookType) +{ + return ((a_HookType >= 0) && (a_HookType <= HOOK_MAX)); +} + + + + + bool cPluginManager::AddPlugin(cPlugin * a_Plugin) { m_Plugins[a_Plugin->GetDirectory()] = a_Plugin; @@ -1603,17 +1612,13 @@ bool cPluginManager::AddPlugin(cPlugin * a_Plugin) -void cPluginManager::AddHook(cPlugin * a_Plugin, PluginHook a_Hook) +void cPluginManager::AddHook(cPlugin * a_Plugin, int a_Hook) { if (!a_Plugin) { LOGWARN("Called cPluginManager::AddHook() with a_Plugin == NULL"); return; } - if (!a_Plugin->CanAddHook(a_Hook)) - { - return; - } PluginList & Plugins = m_Hooks[a_Hook]; Plugins.remove(a_Plugin); Plugins.push_back(a_Plugin); diff --git a/source/PluginManager.h b/source/PluginManager.h index 0933d389f..816e4a40c 100644 --- a/source/PluginManager.h +++ b/source/PluginManager.h @@ -110,6 +110,10 @@ public: // tolua_export // Note that if a hook type is added, it may need processing in cPlugin::CanAddHook() descendants, // and it definitely needs adding in cPluginLua::GetHookFnName() ! + + // Keep these two as the last items, they are used for validity checking and get their values automagically + HOOK_NUM_HOOKS, + HOOK_MAX = HOOK_NUM_HOOKS - 1, } ; // tolua_end @@ -133,7 +137,9 @@ public: // tolua_export void FindPlugins(); // tolua_export void ReloadPlugins(); // tolua_export - void AddHook( cPlugin* a_Plugin, PluginHook a_Hook ); // tolua_export + + /// Adds the plugin to the list of plugins called for the specified hook type. Handles multiple adds as a single add + void AddHook(cPlugin * a_Plugin, int a_HookType); unsigned int GetNumPlugins() const; // tolua_export @@ -237,6 +243,9 @@ public: // tolua_export */ void TabCompleteCommand(const AString & a_Text, AStringVector & a_Results, cPlayer * a_Player); + /// Returns true if the specified hook type is within the allowed range + static bool IsValidHookType(int a_HookType); + private: friend class cRoot; @@ -248,7 +257,7 @@ private: AString m_HelpString; } ; - typedef std::map< cPluginManager::PluginHook, cPluginManager::PluginList > HookMap; + typedef std::map<int, cPluginManager::PluginList> HookMap; typedef std::map<AString, cCommandReg> CommandMap; PluginList m_DisablePluginList; diff --git a/source/Protocol/Protocol132.cpp b/source/Protocol/Protocol132.cpp index 2e5c305cc..26a1a9fad 100644 --- a/source/Protocol/Protocol132.cpp +++ b/source/Protocol/Protocol132.cpp @@ -340,9 +340,6 @@ void cProtocol132::SendLogin(const cPlayer & a_Player, const cWorld & a_World) Flush(); SendCompass(a_World); - - // Send the initial position (so that confirmation works, FS #245): - SendPlayerMoveLook(); } diff --git a/source/StringUtils.cpp b/source/StringUtils.cpp index 403b10a7c..cb91a4da7 100644 --- a/source/StringUtils.cpp +++ b/source/StringUtils.cpp @@ -350,6 +350,33 @@ AString & RawBEToUTF8(short * a_RawData, int a_NumShorts, AString & a_UTF8) // UTF-8 conversion code adapted from: // http://stackoverflow.com/questions/2867123/convert-utf-16-to-utf-8-under-windows-and-linux-in-c +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Begin of Unicode, Inc.'s code / information +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* +Notice from the original file: +* Copyright 2001-2004 Unicode, Inc. +* +* Disclaimer +* +* This source code is provided as is by Unicode, Inc. No claims are +* made as to fitness for any particular purpose. No warranties of any +* kind are expressed or implied. The recipient agrees to determine +* applicability of information provided. If this file has been +* purchased on magnetic or optical media from Unicode, Inc., the +* sole remedy for any claim will be exchange of defective media +* within 90 days of receipt. +* +* Limitations on Rights to Redistribute This Code +* +* Unicode, Inc. hereby grants the right to freely use the information +* supplied in this file in the creation of products supporting the +* Unicode Standard, and to make copies of this file in any form +* for internal or external distribution as long as this notice +* remains attached. +*/ + #define UNI_MAX_BMP 0x0000FFFF #define UNI_MAX_UTF16 0x0010FFFF #define UNI_MAX_UTF32 0x7FFFFFFF @@ -505,18 +532,24 @@ AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a } while (tmpBytesToRead > 0); } - --------------------------------------------------------------------- */ - + --------------------------------------------------------------------- +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// End of Unicode, Inc.'s code / information +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/* + + + +#define HEX(x) ((x) > 9 ? (x) + 'A' - 10 : (x) + '0') + +/** format binary data this way: 00001234: 31 32 33 34 35 36 37 38 39 30 61 62 63 64 65 66 1234567890abcdef */ -#define HEX(x) ((x) > 9 ? (x) + 'A' - 10 : (x) + '0') - AString & CreateHexDump(AString & a_Out, const void * a_Data, int a_Size, int a_LineLength) { ASSERT(a_LineLength <= 120); // Due to using a fixed size line buffer; increase line[]'s size to lift this max diff --git a/source/Tracer.cpp b/source/Tracer.cpp index 6d37f2ed8..42f1ae5dd 100644 --- a/source/Tracer.cpp +++ b/source/Tracer.cpp @@ -133,9 +133,9 @@ void cTracer::SetValues(const Vector3f & a_Start, const Vector3f & a_Direction) int cTracer::Trace( const Vector3f & a_Start, const Vector3f & a_Direction, int a_Distance) { - if (a_Start.y < 0) + if ((a_Start.y < 0) || (a_Start.y >= cChunkDef::Height)) { - LOGD("%s: Start is below the world", __FUNCTION__); + LOGD("%s: Start Y is outside the world (%.2f), not tracing.", __FUNCTION__, a_Start.y); return 0; } diff --git a/source/Vector3d.h b/source/Vector3d.h index 6f28a857b..ecc72e421 100644 --- a/source/Vector3d.h +++ b/source/Vector3d.h @@ -30,12 +30,13 @@ public: // tolua_export void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; } void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; } - Vector3d operator + ( const Vector3d& v2 ) const { return Vector3d( x + v2.x, y + v2.y, z + v2.z ); } // tolua_export - Vector3d operator + ( const Vector3d* v2 ) const { return Vector3d( x + v2->x, y + v2->y, z + v2->z ); } // tolua_export - Vector3d operator - ( const Vector3d& v2 ) const { return Vector3d( x - v2.x, y - v2.y, z - v2.z ); } // tolua_export - Vector3d operator - ( const Vector3d* v2 ) const { return Vector3d( x - v2->x, y - v2->y, z - v2->z ); } // tolua_export - Vector3d operator * ( const double f ) const { return Vector3d( x * f, y * f, z * f ); } // tolua_export - Vector3d operator * ( const Vector3d& v2 ) const { return Vector3d( x * v2.x, y * v2.y, z * v2.z ); } // tolua_export + Vector3d operator + (const Vector3d & v2) const { return Vector3d(x + v2.x, y + v2.y, z + v2.z ); } // tolua_export + Vector3d operator + (const Vector3d * v2) const { return Vector3d(x + v2->x, y + v2->y, z + v2->z ); } // tolua_export + Vector3d operator - (const Vector3d & v2) const { return Vector3d(x - v2.x, y - v2.y, z - v2.z ); } // tolua_export + Vector3d operator - (const Vector3d * v2) const { return Vector3d(x - v2->x, y - v2->y, z - v2->z ); } // tolua_export + Vector3d operator * (const double f) const { return Vector3d(x * f, y * f, z * f ); } // tolua_export + Vector3d operator * (const Vector3d & v2) const { return Vector3d(x * v2.x, y * v2.y, z * v2.z ); } // tolua_export + Vector3d operator / (const double f) const { return Vector3d(x / f, y / f, z / f ); } // tolua_export double x, y, z; // tolua_export diff --git a/source/World.cpp b/source/World.cpp index 053eaedc7..ab783d7a7 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -5,8 +5,6 @@ #include "World.h" #include "ChunkDef.h" #include "ClientHandle.h" -#include "Entities/Pickup.h" -#include "Entities/Player.h" #include "Server.h" #include "Item.h" #include "Root.h" @@ -14,6 +12,11 @@ #include "ChunkMap.h" #include "OSSupport/Timer.h" +// Entities (except mobs): +#include "Entities/Pickup.h" +#include "Entities/Player.h" +#include "Entities/TNTEntity.h" + // Simulators: #include "Simulator/SimulatorManager.h" #include "Simulator/FloodyFluidSimulator.h" @@ -55,7 +58,6 @@ #include "PluginManager.h" #include "Blocks/BlockHandler.h" #include "Vector3d.h" -#include "Entities/TNTEntity.h" #include "Tracer.h" #include "tolua++.h" @@ -2202,15 +2204,12 @@ cPlayer * cWorld::FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit) Vector3f Pos = (*itr)->GetPosition(); float Distance = (Pos - a_Pos).Length(); - if (Distance <= a_SightLimit) + if (Distance < ClosestDistance) { if (!LineOfSight.Trace(a_Pos,(Pos - a_Pos),(int)(Pos - a_Pos).Length())) { - if (Distance < ClosestDistance) - { - ClosestDistance = Distance; - ClosestPlayer = *itr; - } + ClosestDistance = Distance; + ClosestPlayer = *itr; } } } @@ -2650,6 +2649,26 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp +int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed) +{ + cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Speed); + if (Projectile == NULL) + { + return -1; + } + if (!Projectile->Initialize(this)) + { + delete Projectile; + return -1; + } + BroadcastSpawnEntity(*Projectile); + return Projectile->GetUniqueID(); +} + + + + + void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Results) { cCSLock Lock(m_CSPlayers); diff --git a/source/World.h b/source/World.h index 8c90b08c4..1f82f4efc 100644 --- a/source/World.h +++ b/source/World.h @@ -1,716 +1,728 @@ - -#pragma once - -#ifndef _WIN32 - #include "BlockID.h" -#else - enum ENUM_ITEM_ID; -#endif - -#define MAX_PLAYERS 65535 - -#include "Simulator/SimulatorManager.h" -#include "MersenneTwister.h" -#include "ChunkMap.h" -#include "WorldStorage/WorldStorage.h" -#include "Generating/ChunkGenerator.h" -#include "Vector3i.h" -#include "Vector3f.h" -#include "ChunkSender.h" -#include "Defines.h" -#include "LightingThread.h" -#include "Item.h" -#include "Mobs/Monster.h" - - - - - -class cRedstone; -class cFireSimulator; -class cFluidSimulator; -class cSandSimulator; -class cRedstoneSimulator; -class cItem; -class cPlayer; -class cClientHandle; -class cEntity; -class cBlockEntity; -class cWorldGenerator; // The generator that actually generates the chunks for a single world -class cChunkGenerator; // The thread responsible for generating chunks -class cChestEntity; -class cDispenserEntity; -class cFurnaceEntity; - -typedef std::list< cPlayer * > cPlayerList; - -typedef cItemCallback<cPlayer> cPlayerListCallback; -typedef cItemCallback<cEntity> cEntityCallback; -typedef cItemCallback<cChestEntity> cChestCallback; -typedef cItemCallback<cDispenserEntity> cDispenserCallback; -typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; - - - - - - -// tolua_begin -class cWorld -{ -public: - - // tolua_end - - /// A simple RAII locker for the chunkmap - locks the chunkmap in its constructor, unlocks it in the destructor - class cLock : - public cCSLock - { - typedef cCSLock super; - public: - cLock(cWorld & a_World); - } ; - - /// A common ancestor for all tasks queued onto the tick thread - class cTask - { - public: - virtual void Run(cWorld & a_World) = 0; - } ; - - typedef std::vector<cTask *> cTasks; - - class cTaskSaveAllChunks : - public cTask - { - protected: - // cTask overrides: - virtual void Run(cWorld & a_World) override; - } ; - - - // tolua_begin - - static const char * GetClassStatic(void) - { - return "cWorld"; - } - - /// Return time in seconds - inline static float GetTime(void) - { - LOGWARNING("cWorld:GetTime() is obsolete, use GetWorldAge() or GetTimeOfDay() for a specific world instead."); - return 0; - } - - int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; } - Int64 GetWorldAge(void) const { return m_WorldAge; } - Int64 GetTimeOfDay(void) const { return m_TimeOfDay; } - - void SetTicksUntilWeatherChange(int a_WeatherInterval) - { - m_WeatherInterval = a_WeatherInterval; - } - - void SetTimeOfDay(Int64 a_TimeOfDay) - { - m_TimeOfDay = a_TimeOfDay; - m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0; - BroadcastTimeUpdate(); - } - - void SetWorldTime(Int64 a_TimeOfDay) - { - LOGWARNING("cWorld:SetWorldTime() is obsolete, use SetTimeOfDay() instead"); - SetTimeOfDay(a_TimeOfDay); - } - - /// Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable - eGameMode GetGameMode(void) const { return m_GameMode; } - - /// Returns true if the world is in Creative mode - bool IsGameModeCreative(void) const { return (m_GameMode == gmCreative); } - - /// Returns true if the world is in Survival mode - bool IsGameModeSurvival(void) const { return (m_GameMode == gmSurvival); } - - /// Returns true if the world is in Adventure mode - bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); } - - bool IsPVPEnabled(void) const { return m_bEnabledPVP; } - bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; } - - eDimension GetDimension(void) const { return m_Dimension; } - - /// Returns the world height at the specified coords; waits for the chunk to get loaded / generated - int GetHeight(int a_BlockX, int a_BlockZ); - - // tolua_end - - /// Retrieves the world height at the specified coords; returns false if chunk not loaded / generated - bool TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height); // Exported in ManualBindings.cpp - - // Broadcast respective packets to all clients of the chunk where the event is taking place - // (Please keep these alpha-sorted) - void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle); - void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL); - void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL); - void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude - void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL); // tolua_export - void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL); - void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL); - void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); - void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastPlayerAnimation (const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL); - void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL); - void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8 - void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); - void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); - void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); - void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL); - void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ); - void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL); - - /// If there is a block entity at the specified coords, sends it to the client specified - void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client); - - void MarkChunkDirty (int a_ChunkX, int a_ChunkZ); - void MarkChunkSaving(int a_ChunkX, int a_ChunkZ); - void MarkChunkSaved (int a_ChunkX, int a_ChunkZ); - - /** Sets the chunk data as either loaded from the storage or generated. - a_BlockLight and a_BlockSkyLight are optional, if not present, chunk will be marked as unlighted. - a_BiomeMap is optional, if not present, biomes will be calculated by the generator - a_HeightMap is optional, if not present, will be calculated. - If a_MarkDirty is set, the chunk is set as dirty (used after generating) - */ - void SetChunkData( - int a_ChunkX, int a_ChunkZ, - const BLOCKTYPE * a_BlockTypes, - const NIBBLETYPE * a_BlockMeta, - const NIBBLETYPE * a_BlockLight, - const NIBBLETYPE * a_BlockSkyLight, - const cChunkDef::HeightMap * a_HeightMap, - const cChunkDef::BiomeMap * a_BiomeMap, - cEntityList & a_Entities, - cBlockEntityList & a_BlockEntities, - bool a_MarkDirty - ); - - void ChunkLighted( - int a_ChunkX, int a_ChunkZ, - const cChunkDef::BlockNibbles & a_BlockLight, - const cChunkDef::BlockNibbles & a_SkyLight - ); - - bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback); - - /// Gets the chunk's blocks, only the block types - bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes); - - bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const; - bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const; - - void UnloadUnusedChunks(void); // tolua_export - - void CollectPickupsByPlayer(cPlayer * a_Player); - - void AddPlayer( cPlayer* a_Player ); - void RemovePlayer( cPlayer* a_Player ); - - /// Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true - bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - - /// Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored - bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - - /// Finds a player from a partial or complete player name and calls the callback - case-insensitive - bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << - - // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action) - cPlayer * FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit); - - void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player - - /// Adds the entity into its appropriate chunk; takes ownership of the entity ptr - void AddEntity(cEntity * a_Entity); - - bool HasEntity(int a_UniqueID); - - /// Removes the entity, the entity ptr ownership is assumed taken by the caller - void RemoveEntity(cEntity * a_Entity); - - /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true - bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true - bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. - bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Compares clients of two chunks, calls the callback accordingly - void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback); - - /// Adds client to a chunk, if not already present; returns true if added, false if present - bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - - /// Removes client from the chunk specified - void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - - /// Removes the client from all chunks it is present in - void RemoveClientFromChunks(cClientHandle * a_Client); - - /// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted) - void SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client); - - /// Removes client from ChunkSender's queue of chunks to be sent - void RemoveClientFromChunkSender(cClientHandle * a_Client); - - /// Touches the chunk, causing it to be loaded or generated - void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - - /// Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before) - bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - - /// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid() - void LoadChunks(const cChunkCoordsList & a_Chunks); - - /// Marks the chunk as failed-to-load: - void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - - /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign() - bool SetSignLines(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 = NULL); // Exported in ManualBindings.cpp - - /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as SetSignLines() - bool UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp - - /// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay! - void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true); - - /// Regenerate the given chunk: - void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export - - /// Generates the given chunk, if not already generated - void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export - - /// Queues a chunk for lighting; a_Callback is called after the chunk is lighted - void QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = NULL); - - bool IsChunkLighted(int a_ChunkX, int a_ChunkZ); - - /// Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully - bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback); - - // tolua_begin - - /** Sets the block at the specified coords to the specified value. - Full processing, incl. updating neighbors, is performed. - */ - void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); - - /** Sets the block at the specified coords to the specified value. - The replacement doesn't trigger block updates. - The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block) - */ - void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); - - /** Queues a SetBlock() with the specified parameters after the specified number of ticks. - Calls SetBlock(), so performs full processing of the replaced block. - */ - void QueueSetBlock(int a_BlockX, int a_BLockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay); - - BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ); - NIBBLETYPE GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ); - void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData); - NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ); - NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ); - bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); - bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); - // TODO: NIBBLETYPE GetBlockActualLight(int a_BlockX, int a_BlockY, int a_BlockZ); - - // Vector3i variants: - void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta ); } - BLOCKTYPE GetBlock (const Vector3i & a_Pos ) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z ); } - NIBBLETYPE GetBlockMeta(const Vector3i & a_Pos ) { return GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z ); } - void SetBlockMeta(const Vector3i & a_Pos, NIBBLETYPE a_MetaData ) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData ); } - // tolua_end - - /** Writes the block area into the specified coords. - Returns true if all chunks have been processed. - Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too. - a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together. - */ - bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes); - - // tolua_begin - - /// Spawns item pickups for each item in the list. May compress pickups if too many entities: - void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0); - - /// Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: - void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ); - - /// Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided - void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1); - - // tolua_end - - /// Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType - void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType); - - /// Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read. - bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure); - - // tolua_begin - bool DigBlock (int a_X, int a_Y, int a_Z); - void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player ); - - double GetSpawnX(void) const { return m_SpawnX; } - double GetSpawnY(void) const { return m_SpawnY; } - double GetSpawnZ(void) const { return m_SpawnZ; } - - /// Wakes up the simulators for the specified block - void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ); - - /// Wakes up the simulators for the specified area of blocks - void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ); - - // tolua_end - - inline cSimulatorManager * GetSimulatorManager(void) { return m_SimulatorManager; } - - inline cFluidSimulator * GetWaterSimulator(void) { return m_WaterSimulator; } - inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; } - - /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true - bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true - bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback); - - /// Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true - bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback); - - /// Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true - bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback); - - /// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true - bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp - - /** Does an explosion with the specified strength at the specified coordinate - a_SourceData exact type depends on the a_Source: - | esOther | void * | - | esPrimedTNT | cTNTEntity * | - | esCreeper | cCreeper * | - | esBed | cVector3i * | - | esEnderCrystal | Vector3i * | - | esGhastFireball | TBD | - | esWitherSkullBlack | TBD | - | esWitherSkullBlue | TBD | - | esWitherBirth | TBD | - | esPlugin | void * | - */ - void DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export - - /// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found - bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found - bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found - bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found - bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found - bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp - - /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found - bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // tolua_export - - /// a_Player is using block entity at [x, y, z], handle that: - void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {m_ChunkMap->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); } - - /// Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback - bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback); - - void GrowTree (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - void GrowTreeFromSapling(int a_BlockX, int a_BlockY, int a_BlockZ, char a_SaplingMeta); // tolua_export - void GrowTreeByBiome (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - - void GrowTreeImage(const sSetBlockVector & a_Blocks); - - /// Grows the plant at the specified block to its ripe stage (bonemeal used); returns false if the block is not growable. If a_IsBonemeal is true, block is not grown if not allowed in world.ini - bool GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsByBonemeal = false); // tolua_export - - /// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config - void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); // tolua_export - - /// Grows a melon or a pumpkin next to the block specified (assumed to be the stem) - void GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockType); // tolua_export - - /// Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config - void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); // tolua_export - - int GetBiomeAt (int a_BlockX, int a_BlockZ); // tolua_export - - const AString & GetName(void) const { return m_WorldName; } // tolua_export - const AString & GetIniFileName(void) const {return m_IniFileName; } - - inline static void AbsoluteToRelative( int & a_X, int & a_Y, int & a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ ) - { - // TODO: Use floor() instead of weird if statements - // Also fix Y - a_ChunkX = a_X/cChunkDef::Width; - if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--; - a_ChunkY = 0; - a_ChunkZ = a_Z/cChunkDef::Width; - if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--; - - a_X = a_X - a_ChunkX*cChunkDef::Width; - a_Y = a_Y - a_ChunkY*cChunkDef::Height; - a_Z = a_Z - a_ChunkZ*cChunkDef::Width; - } - - inline static void BlockToChunk( int a_X, int a_Y, int a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ ) - { - // TODO: Use floor() instead of weird if statements - // Also fix Y - (void)a_Y; // not unused anymore - a_ChunkX = a_X/cChunkDef::Width; - if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--; - a_ChunkY = 0; - a_ChunkZ = a_Z/cChunkDef::Width; - if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--; - } - - /// Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead - void SaveAllChunks(void); // tolua_export - - /// Queues a task to save all chunks onto the tick thread. The prefferred way of saving chunks from external sources - void QueueSaveAllChunks(void); // tolua_export - - /// Queues a task onto the tick thread. The task object will be deleted once the task is finished - void QueueTask(cTask * a_Task); - - /// Returns the number of chunks loaded - int GetNumChunks() const; // tolua_export - - /// Returns the number of chunks loaded and dirty, and in the lighting queue - void GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue); - - // Various queues length queries (cannot be const, they lock their CS): - inline int GetGeneratorQueueLength (void) { return m_Generator.GetQueueLength(); } // tolua_export - inline int GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export - inline int GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export - inline int GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export - - void InitializeSpawn(void); - - /// Starts threads that belong to this world - void Start(void); - - /// Stops threads that belong to this world (part of deinit) - void Stop(void); - - void TickQueuedBlocks(float a_Dt); - - struct BlockTickQueueItem - { - int X; - int Y; - int Z; - float ToWait; - }; - - void QueueBlockForTick(int a_BlockX, int a_BlockY, int a_BlockZ, float a_TimeToWait); // tolua_export - - // tolua_begin - /// Casts a thunderbolt at the specified coords - void CastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ); - - /// Sets the specified weather; resets weather interval; asks and notifies plugins of the change - void SetWeather (eWeather a_NewWeather); - - /// Forces a weather change in the next game tick - void ChangeWeather (void); - - /// Returns the current weather - eWeather GetWeather (void) const { return m_Weather; }; - // tolua_end - - cChunkGenerator & GetGenerator(void) { return m_Generator; } - cWorldStorage & GetStorage (void) { return m_Storage; } - cChunkMap * GetChunkMap (void) { return m_ChunkMap; } - - /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call - void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - - int GetMaxSugarcaneHeight(void) const { return m_MaxSugarcaneHeight; } // tolua_export - int GetMaxCactusHeight (void) const { return m_MaxCactusHeight; } // tolua_export - - bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - - /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise - int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export - - /// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! - int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); } - - /// Appends all usernames starting with a_Text (case-insensitive) into Results - void TabCompleteUserName(const AString & a_Text, AStringVector & a_Results); - -private: - - friend class cRoot; - - class cTickThread : - public cIsThread - { - typedef cIsThread super; - public: - cTickThread(cWorld & a_World); - - protected: - cWorld & m_World; - - // cIsThread overrides: - virtual void Execute(void) override; - } ; - - - AString m_WorldName; - AString m_IniFileName; - - /// Name of the storage schema used to load and save chunks - AString m_StorageSchema; - - /// The dimension of the world, used by the client to provide correct lighting scheme - eDimension m_Dimension; - - /// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe) - MTRand m_TickRand; - - double m_SpawnX; - double m_SpawnY; - double m_SpawnZ; - - double m_WorldAgeSecs; // World age, in seconds. Is only incremented, cannot be set by plugins. - double m_TimeOfDaySecs; // Time of day in seconds. Can be adjusted. Is wrapped to zero each day. - Int64 m_WorldAge; // World age in ticks, calculated off of m_WorldAgeSecs - Int64 m_TimeOfDay; // Time in ticks, calculated off of m_TimeOfDaySecs - Int64 m_LastTimeUpdate; // The tick in which the last time update has been sent. - Int64 m_LastUnload; // The last WorldAge (in ticks) in which unloading was triggerred - Int64 m_LastSave; // The last WorldAge (in ticks) in which save-all was triggerred - Int64 m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned - - eGameMode m_GameMode; - bool m_bEnabledPVP; - bool m_IsDeepSnowEnabled; - - // The cRedstone class simulates redstone and needs access to m_RSList - // friend class cRedstone; - std::vector<int> m_RSList; - - std::vector<BlockTickQueueItem *> m_BlockTickQueue; - std::vector<BlockTickQueueItem *> m_BlockTickQueueCopy; //Second is for safely removing the objects from the queue - - cSimulatorManager * m_SimulatorManager; - cSandSimulator * m_SandSimulator; - cFluidSimulator * m_WaterSimulator; - cFluidSimulator * m_LavaSimulator; - cFireSimulator * m_FireSimulator; - cRedstoneSimulator * m_RedstoneSimulator; - - cCriticalSection m_CSPlayers; - cPlayerList m_Players; - - cWorldStorage m_Storage; - - unsigned int m_MaxPlayers; - - cChunkMap * m_ChunkMap; - - bool m_bAnimals; - Int64 m_SpawnMonsterRate; - - eWeather m_Weather; - int m_WeatherInterval; - - int m_MaxCactusHeight; - int m_MaxSugarcaneHeight; - bool m_IsCactusBonemealable; - bool m_IsCarrotsBonemealable; - bool m_IsCropsBonemealable; - bool m_IsGrassBonemealable; - bool m_IsMelonStemBonemealable; - bool m_IsMelonBonemealable; - bool m_IsPotatoesBonemealable; - bool m_IsPumpkinStemBonemealable; - bool m_IsPumpkinBonemealable; - bool m_IsSaplingBonemealable; - bool m_IsSugarcaneBonemealable; - - cCriticalSection m_CSFastSetBlock; - sSetBlockList m_FastSetBlockQueue; - - cChunkGenerator m_Generator; - - cChunkSender m_ChunkSender; - cLightingThread m_Lighting; - cTickThread m_TickThread; - - /// Guards the m_Tasks - cCriticalSection m_CSTasks; - - /// Tasks that have been queued onto the tick thread; guarded by m_CSTasks - cTasks m_Tasks; - - /// Guards m_Clients - cCriticalSection m_CSClients; - - /// List of clients in this world, these will be ticked by this world - cClientHandleList m_Clients; - - /// Clients that are scheduled for removal (ticked in another world), waiting for TickClients() to remove them - cClientHandleList m_ClientsToRemove; - - /// Clients that are scheduled for adding, waiting for TickClients to add them - cClientHandleList m_ClientsToAdd; - - - cWorld(const AString & a_WorldName); - ~cWorld(); - - void Tick(float a_Dt); - - /// Handles the weather in each tick - void TickWeather(float a_Dt); - - /// Handles the mob spawning each tick - void TickSpawnMobs(float a_Dt); - - /// Executes all tasks queued onto the tick thread - void TickQueuedTasks(void); - - /// Ticks all clients that are in this world - void TickClients(float a_Dt); - - /// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) - cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock); -}; // tolua_export - - - - +
+#pragma once
+
+#ifndef _WIN32
+ #include "BlockID.h"
+#else
+ enum ENUM_ITEM_ID;
+#endif
+
+#define MAX_PLAYERS 65535
+
+#include "Simulator/SimulatorManager.h"
+#include "MersenneTwister.h"
+#include "ChunkMap.h"
+#include "WorldStorage/WorldStorage.h"
+#include "Generating/ChunkGenerator.h"
+#include "Vector3i.h"
+#include "Vector3f.h"
+#include "ChunkSender.h"
+#include "Defines.h"
+#include "LightingThread.h"
+#include "Item.h"
+#include "Mobs/Monster.h"
+#include "Entities/ProjectileEntity.h"
+
+
+
+
+
+class cRedstone;
+class cFireSimulator;
+class cFluidSimulator;
+class cSandSimulator;
+class cRedstoneSimulator;
+class cItem;
+class cPlayer;
+class cClientHandle;
+class cEntity;
+class cBlockEntity;
+class cWorldGenerator; // The generator that actually generates the chunks for a single world
+class cChunkGenerator; // The thread responsible for generating chunks
+class cChestEntity;
+class cDispenserEntity;
+class cFurnaceEntity;
+
+typedef std::list< cPlayer * > cPlayerList;
+
+typedef cItemCallback<cPlayer> cPlayerListCallback;
+typedef cItemCallback<cEntity> cEntityCallback;
+typedef cItemCallback<cChestEntity> cChestCallback;
+typedef cItemCallback<cDispenserEntity> cDispenserCallback;
+typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
+
+
+
+
+
+
+// tolua_begin
+class cWorld
+{
+public:
+
+ // tolua_end
+
+ /// A simple RAII locker for the chunkmap - locks the chunkmap in its constructor, unlocks it in the destructor
+ class cLock :
+ public cCSLock
+ {
+ typedef cCSLock super;
+ public:
+ cLock(cWorld & a_World);
+ } ;
+
+ /// A common ancestor for all tasks queued onto the tick thread
+ class cTask
+ {
+ public:
+ virtual void Run(cWorld & a_World) = 0;
+ } ;
+
+ typedef std::vector<cTask *> cTasks;
+
+ class cTaskSaveAllChunks :
+ public cTask
+ {
+ protected:
+ // cTask overrides:
+ virtual void Run(cWorld & a_World) override;
+ } ;
+
+
+ // tolua_begin
+
+ static const char * GetClassStatic(void)
+ {
+ return "cWorld";
+ }
+
+ /// Return time in seconds
+ inline static float GetTime(void)
+ {
+ LOGWARNING("cWorld:GetTime() is obsolete, use GetWorldAge() or GetTimeOfDay() for a specific world instead.");
+ return 0;
+ }
+
+ int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; }
+ Int64 GetWorldAge(void) const { return m_WorldAge; }
+ Int64 GetTimeOfDay(void) const { return m_TimeOfDay; }
+
+ void SetTicksUntilWeatherChange(int a_WeatherInterval)
+ {
+ m_WeatherInterval = a_WeatherInterval;
+ }
+
+ void SetTimeOfDay(Int64 a_TimeOfDay)
+ {
+ m_TimeOfDay = a_TimeOfDay;
+ m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0;
+ BroadcastTimeUpdate();
+ }
+
+ void SetWorldTime(Int64 a_TimeOfDay)
+ {
+ LOGWARNING("cWorld:SetWorldTime() is obsolete, use SetTimeOfDay() instead");
+ SetTimeOfDay(a_TimeOfDay);
+ }
+
+ /// Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
+ eGameMode GetGameMode(void) const { return m_GameMode; }
+
+ /// Returns true if the world is in Creative mode
+ bool IsGameModeCreative(void) const { return (m_GameMode == gmCreative); }
+
+ /// Returns true if the world is in Survival mode
+ bool IsGameModeSurvival(void) const { return (m_GameMode == gmSurvival); }
+
+ /// Returns true if the world is in Adventure mode
+ bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); }
+
+ bool IsPVPEnabled(void) const { return m_bEnabledPVP; }
+ bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; }
+
+ eDimension GetDimension(void) const { return m_Dimension; }
+
+ /// Returns the world height at the specified coords; waits for the chunk to get loaded / generated
+ int GetHeight(int a_BlockX, int a_BlockZ);
+
+ // tolua_end
+
+ /// Retrieves the world height at the specified coords; returns false if chunk not loaded / generated
+ bool TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height); // Exported in ManualBindings.cpp
+
+ // Broadcast respective packets to all clients of the chunk where the event is taking place
+ // (Please keep these alpha-sorted)
+ void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle);
+ void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL);
+ void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL);
+ void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude
+ void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL); // tolua_export
+ void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL);
+ void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL);
+ void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastPlayerAnimation (const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL);
+ void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL);
+ void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8
+ void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); // tolua_export
+ void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL);
+ void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ );
+ void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL);
+
+ /// If there is a block entity at the specified coords, sends it to the client specified
+ void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client);
+
+ void MarkChunkDirty (int a_ChunkX, int a_ChunkZ);
+ void MarkChunkSaving(int a_ChunkX, int a_ChunkZ);
+ void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
+
+ /** Sets the chunk data as either loaded from the storage or generated.
+ a_BlockLight and a_BlockSkyLight are optional, if not present, chunk will be marked as unlighted.
+ a_BiomeMap is optional, if not present, biomes will be calculated by the generator
+ a_HeightMap is optional, if not present, will be calculated.
+ If a_MarkDirty is set, the chunk is set as dirty (used after generating)
+ */
+ void SetChunkData(
+ int a_ChunkX, int a_ChunkZ,
+ const BLOCKTYPE * a_BlockTypes,
+ const NIBBLETYPE * a_BlockMeta,
+ const NIBBLETYPE * a_BlockLight,
+ const NIBBLETYPE * a_BlockSkyLight,
+ const cChunkDef::HeightMap * a_HeightMap,
+ const cChunkDef::BiomeMap * a_BiomeMap,
+ cEntityList & a_Entities,
+ cBlockEntityList & a_BlockEntities,
+ bool a_MarkDirty
+ );
+
+ void ChunkLighted(
+ int a_ChunkX, int a_ChunkZ,
+ const cChunkDef::BlockNibbles & a_BlockLight,
+ const cChunkDef::BlockNibbles & a_SkyLight
+ );
+
+ bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback);
+
+ /// Gets the chunk's blocks, only the block types
+ bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes);
+
+ bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const;
+ bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const;
+
+ void UnloadUnusedChunks(void); // tolua_export
+
+ void CollectPickupsByPlayer(cPlayer * a_Player);
+
+ void AddPlayer( cPlayer* a_Player );
+ void RemovePlayer( cPlayer* a_Player );
+
+ /// Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true
+ bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+
+ /// Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored
+ bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+
+ /// Finds a player from a partial or complete player name and calls the callback - case-insensitive
+ bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+
+ // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action)
+ cPlayer * FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit);
+
+ void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player
+
+ /// Adds the entity into its appropriate chunk; takes ownership of the entity ptr
+ void AddEntity(cEntity * a_Entity);
+
+ bool HasEntity(int a_UniqueID);
+
+ /// Removes the entity, the entity ptr ownership is assumed taken by the caller
+ void RemoveEntity(cEntity * a_Entity);
+
+ /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true
+ bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true
+ bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false.
+ bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Compares clients of two chunks, calls the callback accordingly
+ void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback);
+
+ /// Adds client to a chunk, if not already present; returns true if added, false if present
+ bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
+
+ /// Removes client from the chunk specified
+ void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
+
+ /// Removes the client from all chunks it is present in
+ void RemoveClientFromChunks(cClientHandle * a_Client);
+
+ /// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted)
+ void SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
+
+ /// Removes client from ChunkSender's queue of chunks to be sent
+ void RemoveClientFromChunkSender(cClientHandle * a_Client);
+
+ /// Touches the chunk, causing it to be loaded or generated
+ void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
+
+ /// Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before)
+ bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
+
+ /// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid()
+ void LoadChunks(const cChunkCoordsList & a_Chunks);
+
+ /// Marks the chunk as failed-to-load:
+ void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
+
+ /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign()
+ bool SetSignLines(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 = NULL); // Exported in ManualBindings.cpp
+
+ /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as SetSignLines()
+ bool UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp
+
+ /// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay!
+ void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true);
+
+ /// Regenerate the given chunk:
+ void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
+
+ /// Generates the given chunk, if not already generated
+ void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
+
+ /// Queues a chunk for lighting; a_Callback is called after the chunk is lighted
+ void QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = NULL);
+
+ bool IsChunkLighted(int a_ChunkX, int a_ChunkZ);
+
+ /// Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully
+ bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback);
+
+ // tolua_begin
+
+ /** Sets the block at the specified coords to the specified value.
+ Full processing, incl. updating neighbors, is performed.
+ */
+ void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
+
+ /** Sets the block at the specified coords to the specified value.
+ The replacement doesn't trigger block updates.
+ The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block)
+ */
+ void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
+
+ /** Queues a SetBlock() with the specified parameters after the specified number of ticks.
+ Calls SetBlock(), so performs full processing of the replaced block.
+ */
+ void QueueSetBlock(int a_BlockX, int a_BLockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay);
+
+ BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ);
+ NIBBLETYPE GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ);
+ void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData);
+ NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ);
+ NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ);
+ bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
+ bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
+ // TODO: NIBBLETYPE GetBlockActualLight(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ // Vector3i variants:
+ void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta ); }
+ BLOCKTYPE GetBlock (const Vector3i & a_Pos ) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z ); }
+ NIBBLETYPE GetBlockMeta(const Vector3i & a_Pos ) { return GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z ); }
+ void SetBlockMeta(const Vector3i & a_Pos, NIBBLETYPE a_MetaData ) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData ); }
+ // tolua_end
+
+ /** Writes the block area into the specified coords.
+ Returns true if all chunks have been processed.
+ Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too.
+ a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together.
+ */
+ bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);
+
+ // tolua_begin
+
+ /// Spawns item pickups for each item in the list. May compress pickups if too many entities:
+ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0);
+
+ /// Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified:
+ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ);
+
+ /// Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided
+ void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1);
+
+ // tolua_end
+
+ /// Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType
+ void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType);
+
+ /// Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read.
+ bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure);
+
+ // tolua_begin
+ bool DigBlock (int a_X, int a_Y, int a_Z);
+ void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player );
+
+ double GetSpawnX(void) const { return m_SpawnX; }
+ double GetSpawnY(void) const { return m_SpawnY; }
+ double GetSpawnZ(void) const { return m_SpawnZ; }
+
+ /// Wakes up the simulators for the specified block
+ void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ /// Wakes up the simulators for the specified area of blocks
+ void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ);
+
+ // tolua_end
+
+ inline cSimulatorManager * GetSimulatorManager(void) { return m_SimulatorManager; }
+
+ inline cFluidSimulator * GetWaterSimulator(void) { return m_WaterSimulator; }
+ inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; }
+
+ /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true
+ bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true
+ bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback);
+
+ /// Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true
+ bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback);
+
+ /// Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true
+ bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback);
+
+ /// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true
+ bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /** Does an explosion with the specified strength at the specified coordinate
+ a_SourceData exact type depends on the a_Source:
+ | esOther | void * |
+ | esPrimedTNT | cTNTEntity * |
+ | esCreeper | cCreeper * |
+ | esBed | cVector3i * |
+ | esEnderCrystal | Vector3i * |
+ | esGhastFireball | TBD |
+ | esWitherSkullBlack | TBD |
+ | esWitherSkullBlue | TBD |
+ | esWitherBirth | TBD |
+ | esPlugin | void * |
+ */
+ void DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export
+
+ /// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found
+ bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found
+ bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found
+ bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found
+ bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found
+ bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
+ bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // tolua_export
+
+ /// a_Player is using block entity at [x, y, z], handle that:
+ void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {m_ChunkMap->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); }
+
+ /// Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback
+ bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback);
+
+ void GrowTree (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+ void GrowTreeFromSapling(int a_BlockX, int a_BlockY, int a_BlockZ, char a_SaplingMeta); // tolua_export
+ void GrowTreeByBiome (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+
+ void GrowTreeImage(const sSetBlockVector & a_Blocks);
+
+ // tolua_begin
+
+ /// Grows the plant at the specified block to its ripe stage (bonemeal used); returns false if the block is not growable. If a_IsBonemeal is true, block is not grown if not allowed in world.ini
+ bool GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsByBonemeal = false);
+
+ /// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config
+ void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
+
+ /// Grows a melon or a pumpkin next to the block specified (assumed to be the stem)
+ void GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockType);
+
+ /// Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config
+ void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
+
+ /// Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value
+ int GetBiomeAt(int a_BlockX, int a_BlockZ);
+
+ /// Returns the name of the world
+ const AString & GetName(void) const { return m_WorldName; }
+
+ /// Returns the name of the world.ini file used by this world
+ const AString & GetIniFileName(void) const {return m_IniFileName; }
+
+ // tolua_end
+
+ inline static void AbsoluteToRelative( int & a_X, int & a_Y, int & a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
+ {
+ // TODO: Use floor() instead of weird if statements
+ // Also fix Y
+ a_ChunkX = a_X/cChunkDef::Width;
+ if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--;
+ a_ChunkY = 0;
+ a_ChunkZ = a_Z/cChunkDef::Width;
+ if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
+
+ a_X = a_X - a_ChunkX*cChunkDef::Width;
+ a_Y = a_Y - a_ChunkY*cChunkDef::Height;
+ a_Z = a_Z - a_ChunkZ*cChunkDef::Width;
+ }
+
+ inline static void BlockToChunk( int a_X, int a_Y, int a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
+ {
+ // TODO: Use floor() instead of weird if statements
+ // Also fix Y
+ (void)a_Y; // not unused anymore
+ a_ChunkX = a_X/cChunkDef::Width;
+ if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--;
+ a_ChunkY = 0;
+ a_ChunkZ = a_Z/cChunkDef::Width;
+ if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
+ }
+
+ /// Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead
+ void SaveAllChunks(void); // tolua_export
+
+ /// Queues a task to save all chunks onto the tick thread. The prefferred way of saving chunks from external sources
+ void QueueSaveAllChunks(void); // tolua_export
+
+ /// Queues a task onto the tick thread. The task object will be deleted once the task is finished
+ void QueueTask(cTask * a_Task);
+
+ /// Returns the number of chunks loaded
+ int GetNumChunks() const; // tolua_export
+
+ /// Returns the number of chunks loaded and dirty, and in the lighting queue
+ void GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue);
+
+ // Various queues length queries (cannot be const, they lock their CS):
+ inline int GetGeneratorQueueLength (void) { return m_Generator.GetQueueLength(); } // tolua_export
+ inline int GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export
+ inline int GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export
+ inline int GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export
+
+ void InitializeSpawn(void);
+
+ /// Starts threads that belong to this world
+ void Start(void);
+
+ /// Stops threads that belong to this world (part of deinit)
+ void Stop(void);
+
+ void TickQueuedBlocks(float a_Dt);
+
+ struct BlockTickQueueItem
+ {
+ int X;
+ int Y;
+ int Z;
+ float ToWait;
+ };
+
+ void QueueBlockForTick(int a_BlockX, int a_BlockY, int a_BlockZ, float a_TimeToWait); // tolua_export
+
+ // tolua_begin
+ /// Casts a thunderbolt at the specified coords
+ void CastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ /// Sets the specified weather; resets weather interval; asks and notifies plugins of the change
+ void SetWeather (eWeather a_NewWeather);
+
+ /// Forces a weather change in the next game tick
+ void ChangeWeather (void);
+
+ /// Returns the current weather
+ eWeather GetWeather (void) const { return m_Weather; };
+ // tolua_end
+
+ cChunkGenerator & GetGenerator(void) { return m_Generator; }
+ cWorldStorage & GetStorage (void) { return m_Storage; }
+ cChunkMap * GetChunkMap (void) { return m_ChunkMap; }
+
+ /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call
+ void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+
+ int GetMaxSugarcaneHeight(void) const { return m_MaxSugarcaneHeight; } // tolua_export
+ int GetMaxCactusHeight (void) const { return m_MaxCactusHeight; } // tolua_export
+
+ bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+
+ /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise
+ int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export
+
+ /// Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise
+ int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export
+
+ /// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread!
+ int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }
+
+ /// Appends all usernames starting with a_Text (case-insensitive) into Results
+ void TabCompleteUserName(const AString & a_Text, AStringVector & a_Results);
+
+private:
+
+ friend class cRoot;
+
+ class cTickThread :
+ public cIsThread
+ {
+ typedef cIsThread super;
+ public:
+ cTickThread(cWorld & a_World);
+
+ protected:
+ cWorld & m_World;
+
+ // cIsThread overrides:
+ virtual void Execute(void) override;
+ } ;
+
+
+ AString m_WorldName;
+ AString m_IniFileName;
+
+ /// Name of the storage schema used to load and save chunks
+ AString m_StorageSchema;
+
+ /// The dimension of the world, used by the client to provide correct lighting scheme
+ eDimension m_Dimension;
+
+ /// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe)
+ MTRand m_TickRand;
+
+ double m_SpawnX;
+ double m_SpawnY;
+ double m_SpawnZ;
+
+ double m_WorldAgeSecs; // World age, in seconds. Is only incremented, cannot be set by plugins.
+ double m_TimeOfDaySecs; // Time of day in seconds. Can be adjusted. Is wrapped to zero each day.
+ Int64 m_WorldAge; // World age in ticks, calculated off of m_WorldAgeSecs
+ Int64 m_TimeOfDay; // Time in ticks, calculated off of m_TimeOfDaySecs
+ Int64 m_LastTimeUpdate; // The tick in which the last time update has been sent.
+ Int64 m_LastUnload; // The last WorldAge (in ticks) in which unloading was triggerred
+ Int64 m_LastSave; // The last WorldAge (in ticks) in which save-all was triggerred
+ Int64 m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned
+
+ eGameMode m_GameMode;
+ bool m_bEnabledPVP;
+ bool m_IsDeepSnowEnabled;
+
+ // The cRedstone class simulates redstone and needs access to m_RSList
+ // friend class cRedstone;
+ std::vector<int> m_RSList;
+
+ std::vector<BlockTickQueueItem *> m_BlockTickQueue;
+ std::vector<BlockTickQueueItem *> m_BlockTickQueueCopy; //Second is for safely removing the objects from the queue
+
+ cSimulatorManager * m_SimulatorManager;
+ cSandSimulator * m_SandSimulator;
+ cFluidSimulator * m_WaterSimulator;
+ cFluidSimulator * m_LavaSimulator;
+ cFireSimulator * m_FireSimulator;
+ cRedstoneSimulator * m_RedstoneSimulator;
+
+ cCriticalSection m_CSPlayers;
+ cPlayerList m_Players;
+
+ cWorldStorage m_Storage;
+
+ unsigned int m_MaxPlayers;
+
+ cChunkMap * m_ChunkMap;
+
+ bool m_bAnimals;
+ Int64 m_SpawnMonsterRate;
+
+ eWeather m_Weather;
+ int m_WeatherInterval;
+
+ int m_MaxCactusHeight;
+ int m_MaxSugarcaneHeight;
+ bool m_IsCactusBonemealable;
+ bool m_IsCarrotsBonemealable;
+ bool m_IsCropsBonemealable;
+ bool m_IsGrassBonemealable;
+ bool m_IsMelonStemBonemealable;
+ bool m_IsMelonBonemealable;
+ bool m_IsPotatoesBonemealable;
+ bool m_IsPumpkinStemBonemealable;
+ bool m_IsPumpkinBonemealable;
+ bool m_IsSaplingBonemealable;
+ bool m_IsSugarcaneBonemealable;
+
+ cCriticalSection m_CSFastSetBlock;
+ sSetBlockList m_FastSetBlockQueue;
+
+ cChunkGenerator m_Generator;
+
+ cChunkSender m_ChunkSender;
+ cLightingThread m_Lighting;
+ cTickThread m_TickThread;
+
+ /// Guards the m_Tasks
+ cCriticalSection m_CSTasks;
+
+ /// Tasks that have been queued onto the tick thread; guarded by m_CSTasks
+ cTasks m_Tasks;
+
+ /// Guards m_Clients
+ cCriticalSection m_CSClients;
+
+ /// List of clients in this world, these will be ticked by this world
+ cClientHandleList m_Clients;
+
+ /// Clients that are scheduled for removal (ticked in another world), waiting for TickClients() to remove them
+ cClientHandleList m_ClientsToRemove;
+
+ /// Clients that are scheduled for adding, waiting for TickClients to add them
+ cClientHandleList m_ClientsToAdd;
+
+
+ cWorld(const AString & a_WorldName);
+ ~cWorld();
+
+ void Tick(float a_Dt);
+
+ /// Handles the weather in each tick
+ void TickWeather(float a_Dt);
+
+ /// Handles the mob spawning each tick
+ void TickSpawnMobs(float a_Dt);
+
+ /// Executes all tasks queued onto the tick thread
+ void TickQueuedTasks(void);
+
+ /// Ticks all clients that are in this world
+ void TickClients(float a_Dt);
+
+ /// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section)
+ cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);
+}; // tolua_export
+
+
+
+
diff --git a/source/WorldStorage/NBTChunkSerializer.cpp b/source/WorldStorage/NBTChunkSerializer.cpp index 706e913ef..baae0dc01 100644 --- a/source/WorldStorage/NBTChunkSerializer.cpp +++ b/source/WorldStorage/NBTChunkSerializer.cpp @@ -22,6 +22,8 @@ #include "../Entities/Minecart.h" #include "../Mobs/Monster.h" #include "../Entities/Pickup.h" +#include "../Entities/ProjectileEntity.h" + @@ -330,6 +332,62 @@ void cNBTChunkSerializer::AddPickupEntity(cPickup * a_Pickup) +void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile) +{ + m_Writer.BeginCompound(""); + AddBasicEntity(a_Projectile, a_Projectile->GetMCAClassName()); + Vector3d Pos = a_Projectile->GetPosition(); + m_Writer.AddShort("xTile", (Int16)floor(Pos.x)); + m_Writer.AddShort("yTile", (Int16)floor(Pos.y)); + m_Writer.AddShort("zTile", (Int16)floor(Pos.z)); + m_Writer.AddShort("inTile", 0); // TODO: Query the block type (is it needed?) + m_Writer.AddShort("shake", 0); // TODO: Any shake? + m_Writer.AddByte ("inGround", a_Projectile->IsInGround() ? 1 : 0); + + switch (a_Projectile->GetProjectileKind()) + { + case cProjectileEntity::pkArrow: + { + m_Writer.AddByte("inData", 0); // TODO: Query the block meta (is it needed?) + m_Writer.AddByte("pickup", ((cArrowEntity *)a_Projectile)->GetPickupState()); + m_Writer.AddDouble("damage", ((cArrowEntity *)a_Projectile)->GetDamageCoeff()); + break; + } + case cProjectileEntity::pkGhastFireball: + { + m_Writer.AddInt("ExplosionPower", 1); + // fall-through: + } + case cProjectileEntity::pkFireCharge: + case cProjectileEntity::pkWitherSkull: + { + m_Writer.BeginList("Motion", TAG_Double); + m_Writer.AddDouble("", a_Projectile->GetSpeedX()); + m_Writer.AddDouble("", a_Projectile->GetSpeedY()); + m_Writer.AddDouble("", a_Projectile->GetSpeedZ()); + m_Writer.EndList(); + break; + } + default: + { + ASSERT(!"Unsaved projectile entity!"); + } + } // switch (ProjectileKind) + cEntity * Creator = a_Projectile->GetCreator(); + if (Creator != NULL) + { + if (Creator->GetEntityType() == cEntity::etPlayer) + { + m_Writer.AddString("ownerName", ((cPlayer *)Creator)->GetName()); + } + } + m_Writer.EndCompound(); +} + + + + + void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart) { m_Writer.BeginList("Items", TAG_Compound); @@ -403,10 +461,11 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity) switch (a_Entity->GetEntityType()) { - case cEntity::etFallingBlock: AddFallingBlockEntity((cFallingBlock *)a_Entity); break; - case cEntity::etMinecart: AddMinecartEntity ((cMinecart *) a_Entity); break; - case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break; - case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break; + case cEntity::etFallingBlock: AddFallingBlockEntity((cFallingBlock *) a_Entity); break; + case cEntity::etMinecart: AddMinecartEntity ((cMinecart *) a_Entity); break; + case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break; + case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break; + case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break; case cEntity::etPlayer: return; // Players aren't saved into the world default: { diff --git a/source/WorldStorage/NBTChunkSerializer.h b/source/WorldStorage/NBTChunkSerializer.h index cd1388f89..481c578f3 100644 --- a/source/WorldStorage/NBTChunkSerializer.h +++ b/source/WorldStorage/NBTChunkSerializer.h @@ -36,6 +36,7 @@ class cMinecartWithHopper; class cMonster; class cPickup; class cItemGrid; +class cProjectileEntity; @@ -97,6 +98,7 @@ protected: void AddMinecartEntity (cMinecart * a_Minecart); void AddMonsterEntity (cMonster * a_Monster); void AddPickupEntity (cPickup * a_Pickup); + void AddProjectileEntity (cProjectileEntity * a_Projectile); void AddMinecartChestContents(cMinecartWithChest * a_Minecart); diff --git a/source/WorldStorage/WSSAnvil.cpp b/source/WorldStorage/WSSAnvil.cpp index 72d583e2b..3ab64148e 100644 --- a/source/WorldStorage/WSSAnvil.cpp +++ b/source/WorldStorage/WSSAnvil.cpp @@ -20,13 +20,13 @@ #include "../Item.h" #include "../ItemGrid.h" #include "../StringCompression.h" -#include "../Entities/Entity.h" #include "../OSSupport/MakeDir.h" #include "FastNBT.h" +#include "../Mobs/Monster.h" #include "../Entities/FallingBlock.h" #include "../Entities/Minecart.h" -#include "../Mobs/Monster.h" #include "../Entities/Pickup.h" +#include "../Entities/ProjectileEntity.h" @@ -956,6 +956,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a { LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx); } + if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0) + { + LoadArrowFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } // TODO: other entities } @@ -1043,7 +1047,7 @@ void cWSSAnvil::LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - //TODO: Everything to do with TNT carts + // TODO: Everything to do with TNT carts a_Entities.push_back(Minecart.release()); } @@ -1060,7 +1064,7 @@ void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT return; } - //TODO: Everything to do with hopper carts + // TODO: Everything to do with hopper carts a_Entities.push_back(Minecart.release()); } @@ -1093,6 +1097,45 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a +void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); + if (!LoadEntityBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx)) + { + return; + } + + // Load pickup state: + int PickupIdx = a_NBT.FindChildByName(a_TagIdx, "pickup"); + if (PickupIdx > 0) + { + Arrow->SetPickupState((cArrowEntity::ePickupState)a_NBT.GetByte(PickupIdx)); + } + else + { + // Try the older "player" tag: + int PlayerIdx = a_NBT.FindChildByName(a_TagIdx, "player"); + if (PlayerIdx > 0) + { + Arrow->SetPickupState((a_NBT.GetByte(PlayerIdx) == 0) ? cArrowEntity::psNoPickup : cArrowEntity::psInSurvivalOrCreative); + } + } + + // Load damage: + int DamageIdx = a_NBT.FindChildByName(a_TagIdx, "damage"); + if (DamageIdx > 0) + { + Arrow->SetDamageCoeff(a_NBT.GetDouble(DamageIdx)); + } + + // Store the new arrow in the entities list: + a_Entities.push_back(Arrow.release()); +} + + + + + bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx) { double Pos[3]; diff --git a/source/WorldStorage/WSSAnvil.h b/source/WorldStorage/WSSAnvil.h index 47fda3f7b..b2556ab50 100644 --- a/source/WorldStorage/WSSAnvil.h +++ b/source/WorldStorage/WSSAnvil.h @@ -145,6 +145,7 @@ protected: void LoadMinecartTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadArrowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); /// Loads entity common data from the NBT compound; returns true if successful bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx); |