diff options
author | Alexander Harkness <bearbin@gmail.com> | 2013-11-24 15:37:03 +0100 |
---|---|---|
committer | Alexander Harkness <bearbin@gmail.com> | 2013-11-24 15:37:03 +0100 |
commit | c3cd436ec3526962f0f0698ab2d75774247c340b (patch) | |
tree | af5fa89e891ede194f981399af8b830afc6dec97 /src | |
parent | Removed pedantic build and added optimisation to debug builds. (diff) | |
parent | RCONClient: Initial implementation. (diff) | |
download | cuberite-c3cd436ec3526962f0f0698ab2d75774247c340b.tar cuberite-c3cd436ec3526962f0f0698ab2d75774247c340b.tar.gz cuberite-c3cd436ec3526962f0f0698ab2d75774247c340b.tar.bz2 cuberite-c3cd436ec3526962f0f0698ab2d75774247c340b.tar.lz cuberite-c3cd436ec3526962f0f0698ab2d75774247c340b.tar.xz cuberite-c3cd436ec3526962f0f0698ab2d75774247c340b.tar.zst cuberite-c3cd436ec3526962f0f0698ab2d75774247c340b.zip |
Diffstat (limited to 'src')
66 files changed, 2365 insertions, 1497 deletions
diff --git a/src/Bindings.cpp b/src/Bindings.cpp index 93c66d233..ad3ad8423 100644 --- a/src/Bindings.cpp +++ b/src/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/15/13 10:14:19. +** Generated automatically by tolua++-1.0.92 on 11/23/13 19:57:30. */ #ifndef __cplusplus @@ -190,7 +190,7 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cThrownEnderPearlEntity"); tolua_usertype(tolua_S,"cFurnaceEntity"); tolua_usertype(tolua_S,"cEntity"); - tolua_usertype(tolua_S,"cCuboid"); + tolua_usertype(tolua_S,"cExpBottleEntity"); tolua_usertype(tolua_S,"cEnchantments"); tolua_usertype(tolua_S,"cMonster"); tolua_usertype(tolua_S,"cPluginLua"); @@ -199,9 +199,8 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cPickup"); tolua_usertype(tolua_S,"sWebAdminPage"); tolua_usertype(tolua_S,"cFireChargeEntity"); - tolua_usertype(tolua_S,"cWorld"); + tolua_usertype(tolua_S,"cClientHandle"); tolua_usertype(tolua_S,"cChunkDesc"); - tolua_usertype(tolua_S,"cFurnaceRecipe"); tolua_usertype(tolua_S,"cPluginManager"); tolua_usertype(tolua_S,"Vector3f"); tolua_usertype(tolua_S,"cCraftingRecipes"); @@ -212,49 +211,51 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cLineBlockTracer"); tolua_usertype(tolua_S,"cListeners"); tolua_usertype(tolua_S,"cThrownSnowballEntity"); - tolua_usertype(tolua_S,"Vector3d"); + tolua_usertype(tolua_S,"cFireworkEntity"); tolua_usertype(tolua_S,"TakeDamageInfo"); tolua_usertype(tolua_S,"cCraftingRecipe"); tolua_usertype(tolua_S,"cPlugin"); tolua_usertype(tolua_S,"cItemGrid"); tolua_usertype(tolua_S,"cHTTPServer::cCallbacks"); tolua_usertype(tolua_S,"cLuaWindow"); - tolua_usertype(tolua_S,"cInventory"); + tolua_usertype(tolua_S,"cServer"); tolua_usertype(tolua_S,"cHopperEntity"); tolua_usertype(tolua_S,"std::vector<AString>"); tolua_usertype(tolua_S,"cBlockEntityWithItems"); tolua_usertype(tolua_S,"cWindow"); tolua_usertype(tolua_S,"cCraftingGrid"); - tolua_usertype(tolua_S,"cItem"); + tolua_usertype(tolua_S,"cWorld"); tolua_usertype(tolua_S,"cBlockArea"); + tolua_usertype(tolua_S,"cItem"); + tolua_usertype(tolua_S,"cGroup"); tolua_usertype(tolua_S,"cArrowEntity"); tolua_usertype(tolua_S,"cDropSpenserEntity"); - tolua_usertype(tolua_S,"cGroup"); tolua_usertype(tolua_S,"cTracer"); tolua_usertype(tolua_S,"cBoundingBox"); + tolua_usertype(tolua_S,"cCuboid"); tolua_usertype(tolua_S,"cNoteEntity"); tolua_usertype(tolua_S,"Vector3i"); tolua_usertype(tolua_S,"cBlockEntity"); tolua_usertype(tolua_S,"cCriticalSection"); tolua_usertype(tolua_S,"HTTPTemplateRequest"); - tolua_usertype(tolua_S,"cPlayer"); - tolua_usertype(tolua_S,"cServer"); - tolua_usertype(tolua_S,"cSignEntity"); + tolua_usertype(tolua_S,"Vector3d"); tolua_usertype(tolua_S,"cFile"); tolua_usertype(tolua_S,"cItems"); - tolua_usertype(tolua_S,"cClientHandle"); - tolua_usertype(tolua_S,"cIniFile"); tolua_usertype(tolua_S,"cWebPlugin"); - tolua_usertype(tolua_S,"cChatColor"); - tolua_usertype(tolua_S,"cPawn"); - tolua_usertype(tolua_S,"cThrownEggEntity"); - tolua_usertype(tolua_S,"cGroupManager"); tolua_usertype(tolua_S,"cWebAdmin"); + tolua_usertype(tolua_S,"cChatColor"); + tolua_usertype(tolua_S,"cIniFile"); tolua_usertype(tolua_S,"HTTPRequest"); - tolua_usertype(tolua_S,"cProjectileEntity"); tolua_usertype(tolua_S,"HTTPFormData"); + tolua_usertype(tolua_S,"cPawn"); + tolua_usertype(tolua_S,"cPlayer"); + tolua_usertype(tolua_S,"cGroupManager"); + tolua_usertype(tolua_S,"cSignEntity"); tolua_usertype(tolua_S,"cItemGrid::cListener"); + tolua_usertype(tolua_S,"cProjectileEntity"); tolua_usertype(tolua_S,"cDropperEntity"); + tolua_usertype(tolua_S,"cInventory"); + tolua_usertype(tolua_S,"cThrownEggEntity"); } /* method: new of class cIniFile */ @@ -2302,6 +2303,37 @@ static int tolua_AllToLua_cFile_CreateFolder00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: ReadWholeFile of class cFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cFile_ReadWholeFile00 +static int tolua_AllToLua_cFile_ReadWholeFile00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cFile",0,&tolua_err) || + !tolua_iscppstring(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const AString a_FileName = ((const AString) tolua_tocppstring(tolua_S,2,0)); + { + AString tolua_ret = (AString) cFile::ReadWholeFile(a_FileName); + tolua_pushcppstring(tolua_S,(const char*)tolua_ret); + tolua_pushcppstring(tolua_S,(const char*)a_FileName); + } + } + return 2; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'ReadWholeFile'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* function: BlockStringToType */ #ifndef TOLUA_DISABLE_tolua_AllToLua_BlockStringToType00 static int tolua_AllToLua_BlockStringToType00(lua_State* tolua_S) @@ -7650,9 +7682,9 @@ static int tolua_AllToLua_cEntity_IsInvisible00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: SetExperience of class cPlayer */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_SetExperience00 -static int tolua_AllToLua_cPlayer_SetExperience00(lua_State* tolua_S) +/* method: SetCurrentExperience of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_SetCurrentExperience00 +static int tolua_AllToLua_cPlayer_SetCurrentExperience00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -7666,27 +7698,27 @@ static int tolua_AllToLua_cPlayer_SetExperience00(lua_State* tolua_S) #endif { cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); - int a_XpTotal = ((int) tolua_tonumber(tolua_S,2,0)); + short a_XpTotal = ((short) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetExperience'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetCurrentExperience'", NULL); #endif { - bool tolua_ret = (bool) self->SetExperience(a_XpTotal); + bool tolua_ret = (bool) self->SetCurrentExperience(a_XpTotal); tolua_pushboolean(tolua_S,(bool)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'SetExperience'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'SetCurrentExperience'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE -/* method: AddExperience of class cPlayer */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_AddExperience00 -static int tolua_AllToLua_cPlayer_AddExperience00(lua_State* tolua_S) +/* method: DeltaExperience of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_DeltaExperience00 +static int tolua_AllToLua_cPlayer_DeltaExperience00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -7700,27 +7732,27 @@ static int tolua_AllToLua_cPlayer_AddExperience00(lua_State* tolua_S) #endif { cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); - int a_Xp_delta = ((int) tolua_tonumber(tolua_S,2,0)); + short a_Xp_delta = ((short) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'AddExperience'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DeltaExperience'", NULL); #endif { - int tolua_ret = (int) self->AddExperience(a_Xp_delta); + short tolua_ret = (short) self->DeltaExperience(a_Xp_delta); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'AddExperience'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'DeltaExperience'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE -/* method: XpGetTotal of class cPlayer */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_XpGetTotal00 -static int tolua_AllToLua_cPlayer_XpGetTotal00(lua_State* tolua_S) +/* method: GetXpLifetimeTotal of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetXpLifetimeTotal00 +static int tolua_AllToLua_cPlayer_GetXpLifetimeTotal00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -7734,25 +7766,25 @@ static int tolua_AllToLua_cPlayer_XpGetTotal00(lua_State* tolua_S) { cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'XpGetTotal'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetXpLifetimeTotal'", NULL); #endif { - int tolua_ret = (int) self->XpGetTotal(); + short tolua_ret = (short) self->GetXpLifetimeTotal(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'XpGetTotal'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'GetXpLifetimeTotal'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE -/* method: XpGetLevel of class cPlayer */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_XpGetLevel00 -static int tolua_AllToLua_cPlayer_XpGetLevel00(lua_State* tolua_S) +/* method: GetCurrentXp of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetCurrentXp00 +static int tolua_AllToLua_cPlayer_GetCurrentXp00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -7766,25 +7798,25 @@ static int tolua_AllToLua_cPlayer_XpGetLevel00(lua_State* tolua_S) { cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'XpGetLevel'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetCurrentXp'", NULL); #endif { - int tolua_ret = (int) self->XpGetLevel(); + short tolua_ret = (short) self->GetCurrentXp(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'XpGetLevel'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'GetCurrentXp'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE -/* method: XpGetPercentage of class cPlayer */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_XpGetPercentage00 -static int tolua_AllToLua_cPlayer_XpGetPercentage00(lua_State* tolua_S) +/* method: GetXpLevel of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetXpLevel00 +static int tolua_AllToLua_cPlayer_GetXpLevel00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -7798,17 +7830,109 @@ static int tolua_AllToLua_cPlayer_XpGetPercentage00(lua_State* tolua_S) { cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'XpGetPercentage'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetXpLevel'", NULL); #endif { - float tolua_ret = (float) self->XpGetPercentage(); + short tolua_ret = (short) self->GetXpLevel(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'XpGetPercentage'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'GetXpLevel'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetXpPercentage of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetXpPercentage00 +static int tolua_AllToLua_cPlayer_GetXpPercentage00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cPlayer",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetXpPercentage'", NULL); +#endif + { + float tolua_ret = (float) self->GetXpPercentage(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetXpPercentage'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: XpForLevel of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_XpForLevel00 +static int tolua_AllToLua_cPlayer_XpForLevel00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cPlayer",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + short int a_Level = ((short int) tolua_tonumber(tolua_S,2,0)); + { + short tolua_ret = (short) cPlayer::XpForLevel(a_Level); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'XpForLevel'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: CalcLevelFromXp of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_CalcLevelFromXp00 +static int tolua_AllToLua_cPlayer_CalcLevelFromXp00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cPlayer",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + short int a_CurrentXp = ((short int) tolua_tonumber(tolua_S,2,0)); + { + short tolua_ret = (short) cPlayer::CalcLevelFromXp(a_CurrentXp); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'CalcLevelFromXp'.",&tolua_err); return 0; #endif } @@ -19621,33 +19745,31 @@ static int tolua_AllToLua_cRoot_GetCraftingRecipes00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: GetFurnaceRecipe of class cRoot */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cRoot_GetFurnaceRecipe00 -static int tolua_AllToLua_cRoot_GetFurnaceRecipe00(lua_State* tolua_S) +/* method: GetFurnaceFuelBurnTime of class cRoot */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cRoot_GetFurnaceFuelBurnTime00 +static int tolua_AllToLua_cRoot_GetFurnaceFuelBurnTime00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( - !tolua_isusertype(tolua_S,1,"cRoot",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) + !tolua_isusertable(tolua_S,1,"cRoot",0,&tolua_err) || + (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const cItem",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,3,&tolua_err) ) goto tolua_lerror; else #endif { - cRoot* self = (cRoot*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetFurnaceRecipe'", NULL); -#endif + const cItem* a_Fuel = ((const cItem*) tolua_tousertype(tolua_S,2,0)); { - cFurnaceRecipe* tolua_ret = (cFurnaceRecipe*) self->GetFurnaceRecipe(); - tolua_pushusertype(tolua_S,(void*)tolua_ret,"cFurnaceRecipe"); + int tolua_ret = (int) cRoot::GetFurnaceFuelBurnTime(*a_Fuel); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'GetFurnaceRecipe'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'GetFurnaceFuelBurnTime'.",&tolua_err); return 0; #endif } @@ -29447,6 +29569,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"IsFile",tolua_AllToLua_cFile_IsFile00); tolua_function(tolua_S,"GetSize",tolua_AllToLua_cFile_GetSize00); tolua_function(tolua_S,"CreateFolder",tolua_AllToLua_cFile_CreateFolder00); + tolua_function(tolua_S,"ReadWholeFile",tolua_AllToLua_cFile_ReadWholeFile00); tolua_endmodule(tolua_S); tolua_constant(tolua_S,"E_BLOCK_AIR",E_BLOCK_AIR); tolua_constant(tolua_S,"E_BLOCK_STONE",E_BLOCK_STONE); @@ -30417,11 +30540,14 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"EATING_TICKS",cPlayer::EATING_TICKS); tolua_constant(tolua_S,"MAX_AIR_LEVEL",cPlayer::MAX_AIR_LEVEL); tolua_constant(tolua_S,"DROWNING_TICKS",cPlayer::DROWNING_TICKS); - tolua_function(tolua_S,"SetExperience",tolua_AllToLua_cPlayer_SetExperience00); - tolua_function(tolua_S,"AddExperience",tolua_AllToLua_cPlayer_AddExperience00); - tolua_function(tolua_S,"XpGetTotal",tolua_AllToLua_cPlayer_XpGetTotal00); - tolua_function(tolua_S,"XpGetLevel",tolua_AllToLua_cPlayer_XpGetLevel00); - tolua_function(tolua_S,"XpGetPercentage",tolua_AllToLua_cPlayer_XpGetPercentage00); + tolua_function(tolua_S,"SetCurrentExperience",tolua_AllToLua_cPlayer_SetCurrentExperience00); + tolua_function(tolua_S,"DeltaExperience",tolua_AllToLua_cPlayer_DeltaExperience00); + tolua_function(tolua_S,"GetXpLifetimeTotal",tolua_AllToLua_cPlayer_GetXpLifetimeTotal00); + tolua_function(tolua_S,"GetCurrentXp",tolua_AllToLua_cPlayer_GetCurrentXp00); + tolua_function(tolua_S,"GetXpLevel",tolua_AllToLua_cPlayer_GetXpLevel00); + tolua_function(tolua_S,"GetXpPercentage",tolua_AllToLua_cPlayer_GetXpPercentage00); + tolua_function(tolua_S,"XpForLevel",tolua_AllToLua_cPlayer_XpForLevel00); + tolua_function(tolua_S,"CalcLevelFromXp",tolua_AllToLua_cPlayer_CalcLevelFromXp00); tolua_function(tolua_S,"GetEyeHeight",tolua_AllToLua_cPlayer_GetEyeHeight00); tolua_function(tolua_S,"GetEyePosition",tolua_AllToLua_cPlayer_GetEyePosition00); tolua_function(tolua_S,"IsOnGround",tolua_AllToLua_cPlayer_IsOnGround00); @@ -30509,6 +30635,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) 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,"pkFirework",cProjectileEntity::pkFirework); tolua_constant(tolua_S,"pkWitherSkull",cProjectileEntity::pkWitherSkull); tolua_constant(tolua_S,"pkFishingFloat",cProjectileEntity::pkFishingFloat); tolua_function(tolua_S,"GetProjectileKind",tolua_AllToLua_cProjectileEntity_GetProjectileKind00); @@ -30538,6 +30665,12 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_cclass(tolua_S,"cThrownSnowballEntity","cThrownSnowballEntity","cProjectileEntity",NULL); tolua_beginmodule(tolua_S,"cThrownSnowballEntity"); tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cExpBottleEntity","cExpBottleEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cExpBottleEntity"); + tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cFireworkEntity","cFireworkEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cFireworkEntity"); + tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cGhastFireballEntity","cGhastFireballEntity","cProjectileEntity",NULL); tolua_beginmodule(tolua_S,"cGhastFireballEntity"); tolua_endmodule(tolua_S); @@ -31022,7 +31155,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"SetPrimaryServerVersion",tolua_AllToLua_cRoot_SetPrimaryServerVersion00); tolua_function(tolua_S,"GetGroupManager",tolua_AllToLua_cRoot_GetGroupManager00); tolua_function(tolua_S,"GetCraftingRecipes",tolua_AllToLua_cRoot_GetCraftingRecipes00); - tolua_function(tolua_S,"GetFurnaceRecipe",tolua_AllToLua_cRoot_GetFurnaceRecipe00); + tolua_function(tolua_S,"GetFurnaceFuelBurnTime",tolua_AllToLua_cRoot_GetFurnaceFuelBurnTime00); tolua_function(tolua_S,"GetWebAdmin",tolua_AllToLua_cRoot_GetWebAdmin00); tolua_function(tolua_S,"GetPluginManager",tolua_AllToLua_cRoot_GetPluginManager00); tolua_function(tolua_S,"QueueExecuteConsoleCommand",tolua_AllToLua_cRoot_QueueExecuteConsoleCommand00); diff --git a/src/Bindings.h b/src/Bindings.h index 13f398a4d..bc8589293 100644 --- a/src/Bindings.h +++ b/src/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/15/13 10:14:20. +** Generated automatically by tolua++-1.0.92 on 11/23/13 19:57:31. */ /* Exported function */ diff --git a/src/BlockEntities/BlockEntity.h b/src/BlockEntities/BlockEntity.h index a2de3160a..0d358b556 100644 --- a/src/BlockEntities/BlockEntity.h +++ b/src/BlockEntities/BlockEntity.h @@ -52,6 +52,11 @@ public: /// Returns NULL for unknown block types static cBlockEntity * CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World = NULL); + static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates + { + return "cBlockEntity"; + } + // tolua_begin // Position, in absolute block coordinates: diff --git a/src/BlockID.cpp b/src/BlockID.cpp index f8949577e..a4a1ab2d8 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -461,23 +461,26 @@ eDimension StringToDimension(const AString & a_DimensionString) /// Translates damage type constant to a string representation (built-in). AString DamageTypeToString(eDamageType a_DamageType) { + // Make sure to keep this alpha-sorted. switch (a_DamageType) { + case dtAdmin: return "dtAdmin"; case dtAttack: return "dtAttack"; - case dtRangedAttack: return "dtRangedAttack"; - case dtLightning: return "dtLightning"; - case dtFalling: return "dtFalling"; - case dtDrowning: return "dtDrowning"; - case dtSuffocating: return "dtSuffocation"; - case dtStarving: return "dtStarving"; case dtCactusContact: return "dtCactusContact"; - case dtLavaContact: return "dtLavaContact"; - case dtPoisoning: return "dtPoisoning"; - case dtOnFire: return "dtOnFire"; + case dtDrowning: return "dtDrowning"; + case dtEnderPearl: return "dtEnderPearl"; + case dtFalling: return "dtFalling"; case dtFireContact: return "dtFireContact"; case dtInVoid: return "dtInVoid"; + case dtLavaContact: return "dtLavaContact"; + case dtLightning: return "dtLightning"; + case dtOnFire: return "dtOnFire"; + case dtPoisoning: return "dtPoisoning"; case dtPotionOfHarming: return "dtPotionOfHarming"; - case dtAdmin: return "dtAdmin"; + case dtRangedAttack: return "dtRangedAttack"; + case dtStarving: return "dtStarving"; + case dtSuffocating: return "dtSuffocation"; + } // Unknown damage type: @@ -666,13 +669,13 @@ public: g_BlockTransparent[E_BLOCK_FLOWER_POT] = true; g_BlockTransparent[E_BLOCK_GLASS] = true; g_BlockTransparent[E_BLOCK_GLASS_PANE] = true; - g_BlockTransparent[E_BLOCK_STAINED_GLASS] = true; - g_BlockTransparent[E_BLOCK_STAINED_GLASS_PANE] = true; + g_BlockTransparent[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE] = true; g_BlockTransparent[E_BLOCK_ICE] = true; g_BlockTransparent[E_BLOCK_IRON_DOOR] = true; g_BlockTransparent[E_BLOCK_LAVA] = true; g_BlockTransparent[E_BLOCK_LEAVES] = true; g_BlockTransparent[E_BLOCK_LEVER] = true; + g_BlockTransparent[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = true; g_BlockTransparent[E_BLOCK_MELON_STEM] = true; g_BlockTransparent[E_BLOCK_NETHER_BRICK_FENCE] = true; g_BlockTransparent[E_BLOCK_NEW_LEAVES] = true; @@ -684,6 +687,8 @@ public: g_BlockTransparent[E_BLOCK_RED_MUSHROOM] = true; g_BlockTransparent[E_BLOCK_SIGN_POST] = true; g_BlockTransparent[E_BLOCK_SNOW] = true; + g_BlockTransparent[E_BLOCK_STAINED_GLASS] = true; + g_BlockTransparent[E_BLOCK_STAINED_GLASS_PANE] = true; g_BlockTransparent[E_BLOCK_STATIONARY_LAVA] = true; g_BlockTransparent[E_BLOCK_STATIONARY_WATER] = true; g_BlockTransparent[E_BLOCK_STONE_PRESSURE_PLATE] = true; @@ -697,7 +702,7 @@ public: // TODO: Any other transparent blocks? - // One hit break blocks + // One hit break blocks: g_BlockOneHitDig[E_BLOCK_ACTIVE_COMPARATOR] = true; g_BlockOneHitDig[E_BLOCK_BIG_FLOWER] = true; g_BlockOneHitDig[E_BLOCK_BROWN_MUSHROOM] = true; @@ -708,7 +713,6 @@ public: g_BlockOneHitDig[E_BLOCK_FLOWER] = true; g_BlockOneHitDig[E_BLOCK_FLOWER_POT] = true; g_BlockOneHitDig[E_BLOCK_INACTIVE_COMPARATOR] = true; - g_BlockOneHitDig[E_BLOCK_LOCKED_CHEST] = true; g_BlockOneHitDig[E_BLOCK_MELON_STEM] = true; g_BlockOneHitDig[E_BLOCK_POTATOES] = true; g_BlockOneHitDig[E_BLOCK_PUMPKIN_STEM] = true; @@ -724,7 +728,7 @@ public: g_BlockOneHitDig[E_BLOCK_TALL_GRASS] = true; g_BlockOneHitDig[E_BLOCK_TORCH] = true; - // Blocks that breaks when pushed by piston + // Blocks that break when pushed by piston: g_BlockPistonBreakable[E_BLOCK_ACTIVE_COMPARATOR] = true; g_BlockPistonBreakable[E_BLOCK_AIR] = true; g_BlockPistonBreakable[E_BLOCK_BED] = true; @@ -762,11 +766,12 @@ public: g_BlockPistonBreakable[E_BLOCK_TORCH] = true; g_BlockPistonBreakable[E_BLOCK_VINES] = true; g_BlockPistonBreakable[E_BLOCK_WATER] = true; + g_BlockPistonBreakable[E_BLOCK_WOODEN_BUTTON] = true; g_BlockPistonBreakable[E_BLOCK_WOODEN_DOOR] = true; g_BlockPistonBreakable[E_BLOCK_WOODEN_PRESSURE_PLATE] = true; - // Blocks that can be snowed over: + // Blocks that cannot be snowed over: g_BlockIsSnowable[E_BLOCK_ACTIVE_COMPARATOR] = false; g_BlockIsSnowable[E_BLOCK_AIR] = false; g_BlockIsSnowable[E_BLOCK_BIG_FLOWER] = false; @@ -782,7 +787,6 @@ public: g_BlockIsSnowable[E_BLOCK_INACTIVE_COMPARATOR] = false; g_BlockIsSnowable[E_BLOCK_LAVA] = false; g_BlockIsSnowable[E_BLOCK_LILY_PAD] = false; - g_BlockIsSnowable[E_BLOCK_LOCKED_CHEST] = false; g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_OFF] = false; g_BlockIsSnowable[E_BLOCK_REDSTONE_REPEATER_ON] = false; g_BlockIsSnowable[E_BLOCK_REDSTONE_TORCH_OFF] = false; @@ -793,6 +797,8 @@ public: g_BlockIsSnowable[E_BLOCK_SAPLING] = false; g_BlockIsSnowable[E_BLOCK_SIGN_POST] = false; g_BlockIsSnowable[E_BLOCK_SNOW] = false; + g_BlockIsSnowable[E_BLOCK_STAINED_GLASS] = false; + g_BlockIsSnowable[E_BLOCK_STAINED_GLASS_PANE] = false; g_BlockIsSnowable[E_BLOCK_STATIONARY_LAVA] = false; g_BlockIsSnowable[E_BLOCK_STATIONARY_WATER] = false; g_BlockIsSnowable[E_BLOCK_TALL_GRASS] = false; @@ -803,7 +809,7 @@ public: g_BlockIsSnowable[E_BLOCK_WATER] = false; - // Blocks that don't drop without a special tool + // Blocks that don't drop without a special tool: g_BlockRequiresSpecialTool[E_BLOCK_BRICK] = true; g_BlockRequiresSpecialTool[E_BLOCK_CAULDRON] = true; g_BlockRequiresSpecialTool[E_BLOCK_COAL_ORE] = true; @@ -838,7 +844,7 @@ public: g_BlockRequiresSpecialTool[E_BLOCK_STONE_SLAB] = true; g_BlockRequiresSpecialTool[E_BLOCK_VINES] = true; - // Nonsolid Blocks: + // Nonsolid blocks: g_BlockIsSolid[E_BLOCK_ACTIVATOR_RAIL] = false; g_BlockIsSolid[E_BLOCK_AIR] = false; g_BlockIsSolid[E_BLOCK_BIG_FLOWER] = false; @@ -857,11 +863,8 @@ public: g_BlockIsSolid[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE] = false; g_BlockIsSolid[E_BLOCK_MELON_STEM] = false; g_BlockIsSolid[E_BLOCK_NETHER_PORTAL] = false; - g_BlockIsSolid[E_BLOCK_PISTON] = false; g_BlockIsSolid[E_BLOCK_PISTON_EXTENSION] = false; g_BlockIsSolid[E_BLOCK_RAIL] = false; - g_BlockIsSolid[E_BLOCK_REDSTONE_REPEATER_OFF] = false; - g_BlockIsSolid[E_BLOCK_REDSTONE_REPEATER_ON] = false; g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false; g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_ON] = false; g_BlockIsSolid[E_BLOCK_REDSTONE_WIRE] = false; @@ -884,7 +887,7 @@ public: g_BlockIsSolid[E_BLOCK_WOODEN_PRESSURE_PLATE] = false; g_BlockIsSolid[E_BLOCK_WOODEN_SLAB] = false; - // Torch placeable + // Torch placeable blocks: g_BlockIsTorchPlaceable[E_BLOCK_BEDROCK] = true; g_BlockIsTorchPlaceable[E_BLOCK_BLOCK_OF_COAL] = true; g_BlockIsTorchPlaceable[E_BLOCK_BLOCK_OF_REDSTONE] = true; @@ -930,7 +933,7 @@ public: g_BlockIsTorchPlaceable[E_BLOCK_NETHER_QUARTZ_ORE] = true; g_BlockIsTorchPlaceable[E_BLOCK_NOTE_BLOCK] = true; g_BlockIsTorchPlaceable[E_BLOCK_OBSIDIAN] = true; - g_BlockIsTorchPlaceable[E_BLOCK_PACKED_ICE] = true; + g_BlockIsTorchPlaceable[E_BLOCK_PACKED_ICE] = true; g_BlockIsTorchPlaceable[E_BLOCK_PLANKS] = true; g_BlockIsTorchPlaceable[E_BLOCK_PUMPKIN] = true; g_BlockIsTorchPlaceable[E_BLOCK_QUARTZ_BLOCK] = true; @@ -952,3 +955,4 @@ public: + diff --git a/src/Blocks/BlockButton.cpp b/src/Blocks/BlockButton.cpp index 1011f9351..19b055b62 100644 --- a/src/Blocks/BlockButton.cpp +++ b/src/Blocks/BlockButton.cpp @@ -17,21 +17,14 @@ cBlockButtonHandler::cBlockButtonHandler(BLOCKTYPE a_BlockType) void cBlockButtonHandler::OnUse(cWorld *a_World, cPlayer *a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { - // Flip the ON bit on/off. Using XOR bitwise operation to turn it on/off. + // Flip the ON bit on/off using the XOR bitwise operation NIBBLETYPE Meta = ((a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08) & 0x0f); - a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); - - if (Meta & 0x08) - { - a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); - } - else - { - a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.5f); - } - - // Queue a button reset (unpress), with a GetBlock to prevent duplication of buttons (press, break, wait for reset) - a_World->QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ), ((a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08) & 0x0f), m_BlockType == E_BLOCK_STONE_BUTTON ? 20 : 25); + + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta); + a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f); + + // Queue a button reset (unpress) + a_World->QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, ((a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08) & 0x0f), m_BlockType == E_BLOCK_STONE_BUTTON ? 20 : 30); } diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index e3f655bfa..15649acc0 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -14,11 +14,11 @@ public: virtual void OnUse(cWorld * a_World, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; - + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // Reset meta to 0 - a_Pickups.push_back(cItem(m_BlockType == E_BLOCK_WOODEN_BUTTON ? E_BLOCK_WOODEN_BUTTON : E_BLOCK_STONE_BUTTON, 1, 0)); + a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } @@ -51,10 +51,10 @@ public: { switch (a_BlockFace) { - case BLOCK_FACE_ZP: { return 0x4; } - case BLOCK_FACE_ZM: { return 0x3; } - case BLOCK_FACE_XP: { return 0x2; } - case BLOCK_FACE_XM: { return 0x1; } + case BLOCK_FACE_ZM: { return 0x4; } + case BLOCK_FACE_ZP: { return 0x3; } + case BLOCK_FACE_XM: { return 0x2; } + case BLOCK_FACE_XP: { return 0x1; } default: { ASSERT(!"Unhandled block face!"); @@ -62,6 +62,30 @@ public: } } } + + inline static NIBBLETYPE BlockMetaDataToBlockFace(NIBBLETYPE a_Meta) + { + switch (a_Meta & 0x7) + { + case 0x1: return BLOCK_FACE_XP; + case 0x2: return BLOCK_FACE_XM; + case 0x3: return BLOCK_FACE_ZP; + case 0x4: return BLOCK_FACE_ZM; + default: + { + ASSERT(!"Unhandled block meta!"); + return BLOCK_FACE_NONE; + } + } + } + + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + { + NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); + + AddFaceDirection(a_RelX, a_RelY, a_RelZ, BlockMetaDataToBlockFace(Meta), true); + return (a_RelY > 0) && (g_BlockIsSolid[a_Chunk.GetBlock(a_RelX, a_RelY, a_RelZ)]); + } } ; diff --git a/src/Blocks/BlockComparator.cpp b/src/Blocks/BlockComparator.cpp index b4e5a55d0..8bc0ac5ac 100644 --- a/src/Blocks/BlockComparator.cpp +++ b/src/Blocks/BlockComparator.cpp @@ -1,7 +1,7 @@ #include "Globals.h" #include "BlockComparator.h" -#include "../Simulator/RedstoneSimulator.h" +#include "BlockRedstoneRepeater.h" #include "../Entities/Player.h" @@ -44,7 +44,7 @@ bool cBlockComparatorHandler::GetPlacementBlockTypeMeta( ) { a_BlockType = m_BlockType; - a_BlockMeta = cRedstoneSimulator::RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation()); return true; } diff --git a/src/Blocks/BlockLever.cpp b/src/Blocks/BlockLever.cpp index a9bd6c990..2739fa3a9 100644 --- a/src/Blocks/BlockLever.cpp +++ b/src/Blocks/BlockLever.cpp @@ -19,18 +19,11 @@ cBlockLeverHandler::cBlockLeverHandler(BLOCKTYPE a_BlockType) void cBlockLeverHandler::OnUse(cWorld *a_World, cPlayer *a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) { - // Flip the ON bit on/off. Using XOR bitwise operation to turn it on/off. + // Flip the ON bit on/off using the XOR bitwise operation NIBBLETYPE Meta = ((a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08) & 0x0f); - a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); - if (Meta & 0x08) - { - a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); - } - else - { - a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.5f); - } + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta); + a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f); } diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 5553170e2..fe7ecdf7e 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -1,7 +1,6 @@ #pragma once #include "BlockHandler.h" -#include "../Simulator/RedstoneSimulator.h" @@ -37,11 +36,27 @@ public: ) override { a_BlockType = m_BlockType; - a_BlockMeta = cRedstoneSimulator::LeverDirectionToMetaData(a_BlockFace); + a_BlockMeta = LeverDirectionToMetaData(a_BlockFace); return true; } + inline static NIBBLETYPE LeverDirectionToMetaData(char a_Dir) + { + // Determine lever direction: + switch (a_Dir) + { + case BLOCK_FACE_TOP: return 0x6; + case BLOCK_FACE_EAST: return 0x1; + case BLOCK_FACE_WEST: return 0x2; + case BLOCK_FACE_SOUTH: return 0x3; + case BLOCK_FACE_NORTH: return 0x4; + case BLOCK_FACE_BOTTOM: return 0x0; + default: return 0x6; + } + } + + virtual const char * GetStepSound(void) override { return "step.wood"; diff --git a/src/Blocks/BlockRedstoneRepeater.cpp b/src/Blocks/BlockRedstoneRepeater.cpp index 72ea21012..3ab5bc559 100644 --- a/src/Blocks/BlockRedstoneRepeater.cpp +++ b/src/Blocks/BlockRedstoneRepeater.cpp @@ -1,7 +1,6 @@ #include "Globals.h" #include "BlockRedstoneRepeater.h" -#include "../Simulator/RedstoneSimulator.h" #include "../Entities/Player.h" @@ -42,7 +41,7 @@ bool cBlockRedstoneRepeaterHandler::GetPlacementBlockTypeMeta( ) { a_BlockType = m_BlockType; - a_BlockMeta = cRedstoneSimulator::RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetRotation()); return true; } diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 958841a34..a61121d3a 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -48,6 +48,33 @@ public: { return "step.wood"; } + + + inline static NIBBLETYPE RepeaterRotationToMetaData(double a_Rotation) + { + a_Rotation += 90 + 45; // So its not aligned with axis + if (a_Rotation > 360) + { + a_Rotation -= 360; + } + + if ((a_Rotation >= 0) && (a_Rotation < 90)) + { + return 0x1; + } + else if ((a_Rotation >= 180) && (a_Rotation < 270)) + { + return 0x3; + } + else if ((a_Rotation >= 90) && (a_Rotation < 180)) + { + return 0x2; + } + else + { + return 0x0; + } + } } ; diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index 36383a524..72a313126 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -169,8 +169,6 @@ public: virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { char Face = MetaDataToDirection(a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ)); - int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width; - int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width; AddFaceDirection(a_RelX, a_RelY, a_RelZ, Face, true); BLOCKTYPE BlockInQuestion; diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index 1cdd2f430..8f2b76c1f 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -13,6 +13,25 @@ +// Try to determine endianness: +#if ( \ + defined(__i386__) || defined(__alpha__) || \ + defined(__ia64) || defined(__ia64__) || \ + defined(_M_IX86) || defined(_M_IA64) || \ + defined(_M_ALPHA) || defined(__amd64) || \ + defined(__amd64__) || defined(_M_AMD64) || \ + defined(__x86_64) || defined(__x86_64__) || \ + defined(_M_X64) || defined(__bfin__) || \ + defined(__ARMEL__) || \ + (defined(_WIN32) && defined(__ARM__) && defined(_MSC_VER)) \ +) + #define IS_LITTLE_ENDIAN +#elif defined (__ARMEB__) + #define IS_BIG_ENDIAN +#else + #error Cannot determine endianness of this platform +#endif + // If a string sent over the protocol is larger than this, a warning is emitted to the console #define MAX_STRING_SIZE (512 KiB) @@ -416,6 +435,25 @@ bool cByteBuffer::ReadVarUTF8String(AString & a_Value) +bool cByteBuffer::ReadLEInt(int & a_Value) +{ + CHECK_THREAD; + CheckValid(); + NEEDBYTES(4); + ReadBuf(&a_Value, 4); + + #ifdef IS_BIG_ENDIAN + // Convert: + a_Value = ((a_Value >> 24) & 0xff) | ((a_Value >> 16) & 0xff00) | ((a_Value >> 8) & 0xff0000) | (a_Value & 0xff000000); + #endif + + return true; +} + + + + + bool cByteBuffer::WriteChar(char a_Value) { CHECK_THREAD; @@ -572,6 +610,22 @@ bool cByteBuffer::WriteVarUTF8String(const AString & a_Value) +bool cByteBuffer::WriteLEInt(int a_Value) +{ + CHECK_THREAD; + CheckValid(); + #ifdef IS_LITTLE_ENDIAN + return WriteBuf((const char *)&a_Value, 4); + #else + int Value = ((a_Value >> 24) & 0xff) | ((a_Value >> 16) & 0xff00) | ((a_Value >> 8) & 0xff0000) | (a_Value & 0xff000000); + return WriteBuf((const char *)&Value, 4); + #endif +} + + + + + bool cByteBuffer::ReadBuf(void * a_Buffer, int a_Count) { CHECK_THREAD; diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h index 21abb0377..a9dd7f5ea 100644 --- a/src/ByteBuffer.h +++ b/src/ByteBuffer.h @@ -60,6 +60,7 @@ public: bool ReadBEUTF16String16(AString & a_Value); // string length as BE short, then string as UTF-16BE bool ReadVarInt (UInt32 & a_Value); bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8 + bool ReadLEInt (int & a_Value); /// Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) template <typename T> bool ReadVarInt(T & a_Value) @@ -85,6 +86,7 @@ public: bool WriteBEUTF16String16(const AString & a_Value); // string length as BE short, then string as UTF-16BE bool WriteVarInt (UInt32 a_Value); bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8 + bool WriteLEInt (int a_Value); /// Reads a_Count bytes into a_Buffer; returns true if successful bool ReadBuf(void * a_Buffer, int a_Count); diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 1c937c894..7e71e9ea7 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -682,17 +682,17 @@ void cChunk::ProcessQueuedSetBlocks(void) Int64 CurrTick = m_World->GetWorldAge(); for (sSetBlockQueueVector::iterator itr = m_SetBlockQueue.begin(); itr != m_SetBlockQueue.end();) { - if (itr->m_Tick < CurrTick) + if (itr->m_Tick <= CurrTick) { - // Not yet - ++itr; - continue; + // Current world age is bigger than/equal to target world age - delay time reached + SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta); + itr = m_SetBlockQueue.erase(itr); } else { - // Now is the time to set the block - SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta); - itr = m_SetBlockQueue.erase(itr); + // Not yet + ++itr; + continue; } } // for itr - m_SetBlockQueue[] } @@ -1840,6 +1840,24 @@ bool cChunk::DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool +bool cChunk::ForEachBlockEntity(cBlockEntityCallback & a_Callback) +{ + // The blockentity list is locked by the parent chunkmap's CS + for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2) + { + ++itr2; + if (a_Callback.Item(*itr)) + { + return false; + } + } // for itr - m_BlockEntitites[] + return true; +} + + + + + bool cChunk::ForEachChest(cChestCallback & a_Callback) { // The blockentity list is locked by the parent chunkmap's CS @@ -1958,6 +1976,32 @@ bool cChunk::ForEachFurnace(cFurnaceCallback & a_Callback) +bool cChunk::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) +{ + // The blockentity list is locked by the parent chunkmap's CS + for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2) + { + ++itr2; + if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ)) + { + continue; + } + + if (a_Callback.Item(*itr)) + { + return false; + } + return true; + } // for itr - m_BlockEntitites[] + + // Not found: + return false; +} + + + + + bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { // The blockentity list is locked by the parent chunkmap's CS diff --git a/src/Chunk.h b/src/Chunk.h index 63a8f75cd..895b407a3 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -6,6 +6,7 @@ #include "Simulator/FireSimulator.h" #include "Simulator/SandSimulator.h" +#include "Simulator/RedstoneSimulator.h" @@ -206,6 +207,9 @@ public: /// 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. bool DoWithEntityByID(int a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible + /// Calls the callback for each block entity; returns true if all block entities processed, false if the callback aborted by returning true + bool ForEachBlockEntity(cBlockEntityCallback & a_Callback); // Lua-accessible + /// Calls the callback for each chest; returns true if all chests processed, false if the callback aborted by returning true bool ForEachChest(cChestCallback & a_Callback); // Lua-accessible @@ -221,6 +225,9 @@ public: /// Calls the callback for each furnace; returns true if all furnaces processed, false if the callback aborted by returning true bool ForEachFurnace(cFurnaceCallback & a_Callback); // Lua-accessible + /// Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found + bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible + /// 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); // Lua-acessible @@ -338,6 +345,7 @@ public: cFluidSimulatorData * GetWaterSimulatorData(void) { return m_WaterSimulatorData; } cFluidSimulatorData * GetLavaSimulatorData (void) { return m_LavaSimulatorData; } cSandSimulatorChunkData & GetSandSimulatorData (void) { return m_SandSimulatorData; } + cRedstoneSimulatorChunkData & GetRedstoneSimulatorData(void) { return m_RedstoneSimulatorData; } cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ); cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); } @@ -407,6 +415,7 @@ private: cFluidSimulatorData * m_WaterSimulatorData; cFluidSimulatorData * m_LavaSimulatorData; cSandSimulatorChunkData m_SandSimulatorData; + cRedstoneSimulatorChunkData m_RedstoneSimulatorData; // pick up a random block of this chunk diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 73a16dbb4..9d55917e5 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1702,6 +1702,21 @@ bool cChunkMap::DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback) +bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + if ((Chunk == NULL) && !Chunk->IsValid()) + { + return false; + } + return Chunk->ForEachBlockEntity(a_Callback); +} + + + + + bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback) { cCSLock Lock(m_CSLayers); @@ -1777,6 +1792,24 @@ bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallba +bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) +{ + int ChunkX, ChunkZ; + int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; + cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + if ((Chunk == NULL) && !Chunk->IsValid()) + { + return false; + } + return Chunk->DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + + bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { int ChunkX, ChunkZ; diff --git a/src/ChunkMap.h b/src/ChunkMap.h index f68cb6472..2a1d78ff8 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -32,6 +32,7 @@ class cMobSpawner; typedef std::list<cClientHandle *> cClientHandleList; typedef cChunk * cChunkPtr; typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cBlockEntity> cBlockEntityCallback; typedef cItemCallback<cChestEntity> cChestCallback; typedef cItemCallback<cDispenserEntity> cDispenserCallback; typedef cItemCallback<cDropperEntity> cDropperCallback; @@ -191,8 +192,11 @@ public: /// 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); // Lua-accessible + /// Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true + bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Lua-accessible + /// 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); // Lua-accessible + bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Lua-accessible /// 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); @@ -206,8 +210,11 @@ public: /// 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); // Lua-accessible + /// Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found + bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible + /// 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); // Lua-acessible + bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible /// 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); // Lua-accessible diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index f8fd4a8b7..daf09d4ea 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -260,6 +260,9 @@ void cClientHandle::Authenticate(void) // Send health m_Player->SendHealth(); + + // Send experience + m_Player->SendExperience(); // Send gamemode (1.6.1 movementSpeed): SendGameMode(m_Player->GetGameMode()); @@ -1873,6 +1876,15 @@ void cClientHandle::SendRespawn(void) +void cClientHandle::SendExperience(void) +{ + m_Protocol->SendExperience(); +} + + + + + void cClientHandle::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { m_Protocol->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch); diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 3844937ad..b887bb11a 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -120,6 +120,7 @@ public: void SendPlayerPosition (void); void SendPlayerSpawn (const cPlayer & a_Player); void SendRespawn (void); + void SendExperience (void); void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch); // a_Src coords are Block * 8 void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data); void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock); diff --git a/src/Defines.h b/src/Defines.h index 5621aeac1..06410cab4 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -59,20 +59,20 @@ enum enum eBlockFace { BLOCK_FACE_NONE = -1, // Interacting with no block face - swinging the item in the air - BLOCK_FACE_XM = 5, // Interacting with the X- face of the block - BLOCK_FACE_XP = 4, // Interacting with the X+ face of the block + BLOCK_FACE_XM = 4, // Interacting with the X- face of the block + BLOCK_FACE_XP = 5, // Interacting with the X+ face of the block BLOCK_FACE_YM = 0, // Interacting with the Y- face of the block BLOCK_FACE_YP = 1, // Interacting with the Y+ face of the block - BLOCK_FACE_ZM = 3, // Interacting with the Z- face of the block - BLOCK_FACE_ZP = 2, // Interacting with the Z+ face of the block + BLOCK_FACE_ZM = 2, // Interacting with the Z- face of the block + BLOCK_FACE_ZP = 3, // Interacting with the Z+ face of the block // Synonyms using the (deprecated) world directions: BLOCK_FACE_BOTTOM = BLOCK_FACE_YM, // Interacting with the bottom face of the block BLOCK_FACE_TOP = BLOCK_FACE_YP, // Interacting with the top face of the block - BLOCK_FACE_NORTH = BLOCK_FACE_ZP, // Interacting with the northern face of the block - BLOCK_FACE_SOUTH = BLOCK_FACE_ZM, // Interacting with the southern face of the block - BLOCK_FACE_WEST = BLOCK_FACE_XP, // Interacting with the western face of the block - BLOCK_FACE_EAST = BLOCK_FACE_XM, // Interacting with the eastern face of the block + BLOCK_FACE_NORTH = BLOCK_FACE_ZM, // Interacting with the northern face of the block + BLOCK_FACE_SOUTH = BLOCK_FACE_ZP, // Interacting with the southern face of the block + BLOCK_FACE_WEST = BLOCK_FACE_XM, // Interacting with the western face of the block + BLOCK_FACE_EAST = BLOCK_FACE_XP, // Interacting with the eastern face of the block } ; @@ -305,12 +305,12 @@ inline void AddFaceDirection(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cha { switch (a_BlockFace) { - case BLOCK_FACE_BOTTOM: a_BlockY--; break; - case BLOCK_FACE_TOP: a_BlockY++; break; - case BLOCK_FACE_EAST: a_BlockX++; break; - case BLOCK_FACE_WEST: a_BlockX--; break; - case BLOCK_FACE_NORTH: a_BlockZ--; break; - case BLOCK_FACE_SOUTH: a_BlockZ++; break; + case BLOCK_FACE_YP: a_BlockY++; break; + case BLOCK_FACE_YM: a_BlockY--; break; + case BLOCK_FACE_ZM: a_BlockZ--; break; + case BLOCK_FACE_ZP: a_BlockZ++; break; + case BLOCK_FACE_XP: a_BlockX++; break; + case BLOCK_FACE_XM: a_BlockX--; break; default: { LOGWARNING("%s: Unknown face: %d", __FUNCTION__, a_BlockFace); @@ -323,12 +323,12 @@ inline void AddFaceDirection(int & a_BlockX, int & a_BlockY, int & a_BlockZ, cha { switch (a_BlockFace) { - case BLOCK_FACE_BOTTOM: a_BlockY++; break; - case BLOCK_FACE_TOP: a_BlockY--; break; - case BLOCK_FACE_EAST: a_BlockX--; break; - case BLOCK_FACE_WEST: a_BlockX++; break; - case BLOCK_FACE_NORTH: a_BlockZ++; break; - case BLOCK_FACE_SOUTH: a_BlockZ--; break; + case BLOCK_FACE_YP: a_BlockY--; break; + case BLOCK_FACE_YM: a_BlockY++; break; + case BLOCK_FACE_ZM: a_BlockZ++; break; + case BLOCK_FACE_ZP: a_BlockZ--; break; + case BLOCK_FACE_XP: a_BlockX--; break; + case BLOCK_FACE_XM: a_BlockX++; break; default: { LOGWARNING("%s: Unknown inv face: %d", __FUNCTION__, a_BlockFace); diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 098417dc5..f37a23f22 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -66,7 +66,9 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_EatingFinishTick(-1) , m_IsChargingBow(false) , m_BowCharge(0) - , m_XpTotal(0) + , m_CurrentXp(0) + , m_LifetimeTotalXp(0) + , m_bDirtyExperience(false) { LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", a_PlayerName.c_str(), a_Client->GetIPString().c_str(), @@ -222,6 +224,12 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) { m_BowCharge += 1; } + + //handle updating experience + if (m_bDirtyExperience) + { + SendExperience(); + } if (m_bDirtyPosition) { @@ -262,7 +270,7 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) -int cPlayer::CalcLevelFromXp(int a_XpTotal) +short cPlayer::CalcLevelFromXp(short a_XpTotal) { //level 0 to 15 if(a_XpTotal <= XP_TO_LEVEL15) @@ -273,18 +281,18 @@ int cPlayer::CalcLevelFromXp(int a_XpTotal) //level 30+ if(a_XpTotal > XP_TO_LEVEL30) { - return (int) (151.5 + sqrt( 22952.25 - (14 * (2220 - a_XpTotal)))) / 7; + return (short) (151.5 + sqrt( 22952.25 - (14 * (2220 - a_XpTotal)))) / 7; } //level 16 to 30 - return (int) ( 29.5 + sqrt( 870.25 - (6 * ( 360 - a_XpTotal )))) / 3; + return (short) ( 29.5 + sqrt( 870.25 - (6 * ( 360 - a_XpTotal )))) / 3; } -int cPlayer::XpForLevel(int a_Level) +short cPlayer::XpForLevel(short a_Level) { //level 0 to 15 if(a_Level <= 15) @@ -295,46 +303,51 @@ int cPlayer::XpForLevel(int a_Level) //level 30+ if(a_Level >= 31) { - return (int) ( (3.5 * a_Level * a_Level) - (151.5 * a_Level) + 2220 ); + return (short) ( (3.5 * a_Level * a_Level) - (151.5 * a_Level) + 2220 ); } //level 16 to 30 - return (int) ( (1.5 * a_Level * a_Level) - (29.5 * a_Level) + 360 ); + return (short) ( (1.5 * a_Level * a_Level) - (29.5 * a_Level) + 360 ); } -int cPlayer::XpGetLevel() +short cPlayer::GetXpLevel() { - return CalcLevelFromXp(m_XpTotal); + return CalcLevelFromXp(m_CurrentXp); } -float cPlayer::XpGetPercentage() +float cPlayer::GetXpPercentage() { - int currentLevel = CalcLevelFromXp(m_XpTotal); + short int currentLevel = CalcLevelFromXp(m_CurrentXp); + short int currentLevel_XpBase = XpForLevel(currentLevel); - return (float)m_XpTotal / (float)XpForLevel(1+currentLevel); + return (float)(m_CurrentXp - currentLevel_XpBase) / + (float)(XpForLevel(1+currentLevel) - currentLevel_XpBase); } -bool cPlayer::SetExperience(int a_XpTotal) +bool cPlayer::SetCurrentExperience(short int a_CurrentXp) { - if(!(a_XpTotal >= 0) || (a_XpTotal > (INT_MAX - m_XpTotal))) + if(!(a_CurrentXp >= 0) || (a_CurrentXp > (SHRT_MAX - m_LifetimeTotalXp))) { - LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_XpTotal); + LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_CurrentXp); return false; //oops, they gave us a dodgey number } - m_XpTotal = a_XpTotal; + m_CurrentXp = a_CurrentXp; + + // Set experience to be updated + m_bDirtyExperience = true; return true; } @@ -343,21 +356,37 @@ bool cPlayer::SetExperience(int a_XpTotal) -int cPlayer::AddExperience(int a_Xp_delta) +short cPlayer::DeltaExperience(short a_Xp_delta) { - if(a_Xp_delta < 0) + if (a_Xp_delta > (SHRT_MAX - m_CurrentXp)) { - //value was negative, abort and report - LOGWARNING("Attempt was made to increment Xp by %d, must be positive", + // Value was bad, abort and report + LOGWARNING("Attempt was made to increment Xp by %d, which overflowed the short datatype. Ignoring.", a_Xp_delta); - return -1; //should we instead just return the current Xp? + return -1; // Should we instead just return the current Xp? + } + + m_CurrentXp += a_Xp_delta; + + // Make sure they didn't subtract too much + if (m_CurrentXp < 0) + { + m_CurrentXp = 0; + } + + // Update total for score calculation + if (a_Xp_delta > 0) + { + m_LifetimeTotalXp += a_Xp_delta; } - - LOGD("Player \"%s\" earnt %d experience", m_PlayerName.c_str(), a_Xp_delta); - m_XpTotal += a_Xp_delta; + LOGD("Player \"%s\" gained/lost %d experience, total is now: %d", + m_PlayerName.c_str(), a_Xp_delta, m_CurrentXp); - return m_XpTotal; + // Set experience to be updated + m_bDirtyExperience = true; + + return m_CurrentXp; } @@ -607,6 +636,19 @@ void cPlayer::SendHealth(void) +void cPlayer::SendExperience(void) +{ + if (m_ClientHandle != NULL) + { + m_ClientHandle->SendExperience(); + m_bDirtyExperience = false; + } +} + + + + + void cPlayer::ClearInventoryPaintSlots(void) { // Clear the list of slots that are being inventory-painted. Used by cWindow only @@ -759,6 +801,11 @@ void cPlayer::Respawn(void) m_FoodLevel = MAX_FOOD_LEVEL; m_FoodSaturationLevel = 5; + // Reset Experience + m_CurrentXp = 0; + m_LifetimeTotalXp = 0; + // ToDo: send score to client? How? + m_ClientHandle->SendRespawn(); // Extinguish the fire: @@ -1411,14 +1458,16 @@ bool cPlayer::LoadFromDisk() SetRoll ((float)JSON_PlayerRotation[(unsigned int)2].asDouble()); } - m_Health = root.get("health", 0).asInt(); + m_Health = root.get("health", 0).asInt(); m_AirLevel = root.get("air", MAX_AIR_LEVEL).asInt(); m_FoodLevel = root.get("food", MAX_FOOD_LEVEL).asInt(); m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble(); m_FoodTickTimer = root.get("foodTickTimer", 0).asInt(); m_FoodExhaustionLevel = root.get("foodExhaustion", 0).asDouble(); + m_LifetimeTotalXp = (short) root.get("xpTotal", 0).asInt(); + m_CurrentXp = (short) root.get("xpCurrent", 0).asInt(); - SetExperience(root.get("experience", 0).asInt()); + //SetExperience(root.get("experience", 0).asInt()); m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt(); @@ -1460,7 +1509,8 @@ bool cPlayer::SaveToDisk() root["rotation"] = JSON_PlayerRotation; root["inventory"] = JSON_Inventory; root["health"] = m_Health; - root["experience"] = m_XpTotal; + root["xpTotal"] = m_LifetimeTotalXp; + root["xpCurrent"] = m_CurrentXp; root["air"] = m_AirLevel; root["food"] = m_FoodLevel; root["foodSaturation"] = m_FoodSaturationLevel; diff --git a/src/Entities/Player.h b/src/Entities/Player.h index ab2f94d4c..44cab7d74 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -71,21 +71,31 @@ public: Returns true on success "should" really only be called at init or player death, plugins excepted */ - bool SetExperience(int a_XpTotal); + bool SetCurrentExperience(short a_XpTotal); - /* Adds Xp, "should" not inc more than MAX_EXPERIENCE_ORB_SIZE unless you're a plugin being funny, *cough* cheating - Returns the new total experience, -1 on error + /* changes Xp by Xp_delta, you "shouldn't" inc more than MAX_EXPERIENCE_ORB_SIZE + Wont't allow xp to go negative + Returns the new current experience, -1 on error */ - int AddExperience(int a_Xp_delta); + short DeltaExperience(short a_Xp_delta); - /// Gets the experience total - XpTotal - inline int XpGetTotal(void) { return m_XpTotal; } + /// Gets the experience total - XpTotal for score on death + inline short GetXpLifetimeTotal(void) { return m_LifetimeTotalXp; } + + /// Gets the currrent experience + inline short GetCurrentXp(void) { return m_CurrentXp; } /// Gets the current level - XpLevel - int XpGetLevel(void); + short GetXpLevel(void); /// Gets the experience bar percentage - XpP - float XpGetPercentage(void); + float GetXpPercentage(void); + + /// Caculates the amount of XP needed for a given level, ref: http://minecraft.gamepedia.com/XP + static short XpForLevel(short int a_Level); + + /// inverse of XpForLevel, ref: http://minecraft.gamepedia.com/XP values are as per this with pre-calculations + static short CalcLevelFromXp(short int a_CurrentXp); // tolua_end @@ -269,6 +279,8 @@ public: void UseEquippedItem(void); void SendHealth(void); + + void SendExperience(void); // In UI windows, the item that the player is dragging: bool IsDraggingItem(void) const { return !m_DraggingItem.IsEmpty(); } @@ -319,9 +331,7 @@ public: virtual bool IsCrouched (void) const { return m_IsCrouched; } virtual bool IsSprinting(void) const { return m_IsSprinting; } virtual bool IsRclking (void) const { return IsEating(); } - - - + protected: typedef std::map< std::string, bool > PermissionMap; PermissionMap m_ResolvedPermissions; @@ -413,17 +423,16 @@ protected: Int64 m_EatingFinishTick; /// Player Xp level - int m_XpTotal; + short int m_LifetimeTotalXp; + short int m_CurrentXp; - /// Caculates the Xp needed for a given level, ref: http://minecraft.gamepedia.com/XP - static int XpForLevel(int a_Level); + // flag saying we need to send a xp update to client + bool m_bDirtyExperience; - /// inverse of XpAtLevel, ref: http://minecraft.gamepedia.com/XP values are as per this with pre-calculations - static int CalcLevelFromXp(int a_XpTotal); - bool m_IsChargingBow; int m_BowCharge; + virtual void Destroyed(void); /// Filters out damage for creative mode diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index c63b9523b..fb25aea35 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -230,6 +230,8 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed); case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed); case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkFirework: return new cFireworkEntity (a_Creator, a_X, a_Y, a_Z ); // TODO: the rest } @@ -287,7 +289,11 @@ AString cProjectileEntity::GetMCAClassName(void) const void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); - BroadcastMovementUpdate(); + + if (GetProjectileKind() != pkArrow) // See cArrow::Tick + { + BroadcastMovementUpdate(); + } } @@ -391,7 +397,8 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a m_IsCritical(false), m_Timer(0), m_bIsCollected(false), - m_HitBlockPos(Vector3i(0, 0, 0)) + m_HitBlockPos(Vector3i(0, 0, 0)), + m_HitGroundTimer(0) { SetSpeed(a_Speed); SetMass(0.1); @@ -414,7 +421,8 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : m_IsCritical((a_Force >= 1)), m_Timer(0), m_bIsCollected(false), - m_HitBlockPos(0, 0, 0) + m_HitBlockPos(0, 0, 0), + m_HitGroundTimer(0) { } @@ -440,37 +448,25 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { - if (a_HitFace == BLOCK_FACE_NONE) - { - return; - } + if (a_HitFace == BLOCK_FACE_NONE) { return; } super::OnHitSolidBlock(a_HitPos, a_HitFace); int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z; - - if (a_HitFace != BLOCK_FACE_YP) - { - AddFaceDirection(a_X, a_Y, a_Z, a_HitFace); - } - else if (a_HitFace == BLOCK_FACE_YP) // These conditions because xoft got a little confused on block face directions, so AddFace works with all but YP & YM - { - a_Y--; - } - else + + switch (a_HitFace) { - a_Y++; + case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed + case BLOCK_FACE_YM: + { + break; + } + default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true); } m_HitBlockPos = Vector3i(a_X, a_Y, a_Z); // Broadcast arrow hit sound m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); - - // Broadcast the position and speed packets before teleporting: - BroadcastMovementUpdate(); - - // Teleport the entity to the exact hit coords: - m_World->BroadcastTeleportEntity(*this); } @@ -542,6 +538,24 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) if (m_IsInGround) { + // When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL + // Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing) + // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync + // Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position + + if (m_HitGroundTimer != -1) // Sent a teleport already, don't do again + { + if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case + { + m_World->BroadcastTeleportEntity(*this); + m_HitGroundTimer = -1; + } + else + { + m_HitGroundTimer += a_Dt; + } + } + int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width; int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width; cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ); @@ -651,6 +665,104 @@ void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_Hi /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cBottleOEnchantingEntity : + +cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : +super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) +{ + // TODO: Spawn experience orbs + + Destroy(); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cFireworkEntity : + +cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z) : +super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ +} + + + + + +void cFireworkEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) +{ + if ((a_HitFace != BLOCK_FACE_BOTTOM) && (a_HitFace != BLOCK_FACE_NONE)) + { + return; + } + + SetSpeed(0, 0, 0); + SetPosition(GetPosX(), GetPosY() - 0.5, GetPosZ()); + + std::cout << a_HitPos.x << " " << a_HitPos.y << " " << a_HitPos.z << std::endl; + + m_IsInGround = true; + + BroadcastMovementUpdate(); +} + + + + + +void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) +{ + if (m_IsInGround) + { + if (a_Chunk.GetBlock((int)GetPosX(), (int)GetPosY() + 1, (int)GetPosZ()) == E_BLOCK_AIR) + { + m_IsInGround = false; + } + else + { + 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)) + { + // Something has been hit, abort all other processing + return; + } + // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff + + // Update the position: + SetPosition(NextPos); + + // Add slowdown and gravity effect to the speed: + Vector3d NewSpeed(GetSpeed()); + NewSpeed.y += 2; + NewSpeed *= TracerCallback.GetSlowdownCoeff(); + SetSpeed(NewSpeed); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cGhastFireballEntity : cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index 28dd76935..959e81ae5 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -34,6 +34,7 @@ public: pkEnderPearl = 65, pkExpBottle = 75, pkSplashPotion = 73, + pkFirework = 76, pkWitherSkull = 66, pkFishingFloat = 90, } ; @@ -83,7 +84,7 @@ protected: /// True if the projectile has hit the ground and is stuck there bool m_IsInGround; - + // cEntity overrides: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; @@ -159,6 +160,9 @@ protected: /// Timer for pickup collection animation or five minute timeout float m_Timer; + /// Timer for client arrow position confirmation via TeleportEntity + float m_HitGroundTimer; + /// If true, the arrow is in the process of being collected - don't go to anyone else bool m_bIsCollected; @@ -260,6 +264,59 @@ protected: +class cExpBottleEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cExpBottleEntity); + + cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; + + // tolua_begin + +}; + + + + + +class cFireworkEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cFireworkEntity); + + cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override; + virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; + + // tolua_begin + +}; + + + + + class cGhastFireballEntity : public cProjectileEntity { diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp index 4221ea187..df45bb4c2 100644 --- a/src/Generating/Caves.cpp +++ b/src/Generating/Caves.cpp @@ -55,7 +55,7 @@ struct cCaveDefPoint int m_BlockY; int m_BlockZ; int m_Radius; - + cCaveDefPoint(int a_BlockX, int a_BlockY, int a_BlockZ, int a_Radius) : m_BlockX(a_BlockX), m_BlockY(a_BlockY), @@ -78,22 +78,22 @@ class cCaveTunnel int m_MinBlockX, m_MaxBlockX; int m_MinBlockY, m_MaxBlockY; int m_MinBlockZ, m_MaxBlockZ; - + /// Generates the shaping defpoints for the ravine, based on the ravine block coords and noise void Randomize(cNoise & a_Noise); - + /// Refines (adds and smooths) defpoints from a_Src into a_Dst; returns false if no refinement possible (segments too short) bool RefineDefPoints(const cCaveDefPoints & a_Src, cCaveDefPoints & a_Dst); - + /// Does rounds of smoothing, two passes of RefineDefPoints(), as long as they return true void Smooth(void); - + /// Linearly interpolates the points so that the maximum distance between two neighbors is max 1 block void FinishLinear(void); - + /// Calculates the bounding box of the points present void CalcBoundingBox(void); - + public: cCaveDefPoints m_Points; @@ -102,14 +102,14 @@ public: int a_BlockEndX, int a_BlockEndY, int a_BlockEndZ, int a_EndRadius, cNoise & a_Noise ); - + /// Carves the tunnel into the chunk specified void ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, + int a_ChunkX, int a_ChunkZ, + cChunkDef::BlockTypes & a_BlockTypes, cChunkDef::HeightMap & a_HeightMap ); - + #ifdef _DEBUG AString ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const; #endif // _DEBUG @@ -128,17 +128,17 @@ public: // The generating block position; is read directly in cStructGenWormNestCaves::GetCavesForChunk() int m_BlockX; int m_BlockZ; - + cCaveSystem(int a_BlockX, int a_BlockZ, int a_MaxOffset, int a_Size, cNoise & a_Noise); ~cCaveSystem(); - + /// Carves the cave system into the chunk specified void ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, + int a_ChunkX, int a_ChunkZ, + cChunkDef::BlockTypes & a_BlockTypes, cChunkDef::HeightMap & a_HeightMap ); - + #ifdef _DEBUG AString ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const; #endif // _DEBUG @@ -146,15 +146,15 @@ public: protected: int m_Size; cCaveTunnels m_Tunnels; - + void Clear(void); /// Generates a_Segment successive tunnels, with possible branches. Generates the same output for the same [x, y, z, a_Segments] void GenerateTunnelsFromPoint( - int a_OriginX, int a_OriginY, int a_OriginZ, + int a_OriginX, int a_OriginY, int a_OriginZ, cNoise & a_Noise, int a_Segments ); - + /// Returns a radius based on the location provided. int GetRadius(cNoise & a_Noise, int a_OriginX, int a_OriginY, int a_OriginZ); } ; @@ -174,19 +174,19 @@ cCaveTunnel::cCaveTunnel( { m_Points.push_back(cCaveDefPoint(a_BlockStartX, a_BlockStartY, a_BlockStartZ, a_StartRadius)); m_Points.push_back(cCaveDefPoint(a_BlockEndX, a_BlockEndY, a_BlockEndZ, a_EndRadius)); - + if ((a_BlockStartY <= 0) && (a_BlockEndY <= 0)) { // Don't bother detailing this cave, it's under the world anyway return; } - + Randomize(a_Noise); Smooth(); - + // We know that the linear finishing won't affect the bounding box, so let's calculate it now, as we have less data: CalcBoundingBox(); - + FinishLinear(); } @@ -308,7 +308,7 @@ void cCaveTunnel::FinishLinear(void) // For each segment, use Bresenham's 3D line algorithm to draw a "line" of defpoints cCaveDefPoints Pts; std::swap(Pts, m_Points); - + m_Points.reserve(Pts.size() * 3); int PrevX = Pts.front().m_BlockX; int PrevY = Pts.front().m_BlockY; @@ -324,7 +324,6 @@ void cCaveTunnel::FinishLinear(void) int sx = (PrevX < x1) ? 1 : -1; int sy = (PrevY < y1) ? 1 : -1; int sz = (PrevZ < z1) ? 1 : -1; - int err = dx - dz; int R = itr->m_Radius; if (dx >= std::max(dy, dz)) // x dominant @@ -418,7 +417,7 @@ void cCaveTunnel::FinishLinear(void) PrevY += sy; yd -= dz; } - + // move along z PrevZ += sz; xd += dx; @@ -453,8 +452,8 @@ void cCaveTunnel::CalcBoundingBox(void) void cCaveTunnel::ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, + int a_ChunkX, int a_ChunkZ, + cChunkDef::BlockTypes & a_BlockTypes, cChunkDef::HeightMap & a_HeightMap ) { @@ -462,7 +461,7 @@ void cCaveTunnel::ProcessChunk( int BaseZ = a_ChunkZ * cChunkDef::Width; if ( (BaseX > m_MaxBlockX) || (BaseX + cChunkDef::Width < m_MinBlockX) || - (BaseX > m_MaxBlockX) || (BaseX + cChunkDef::Width < m_MinBlockX) + (BaseZ > m_MaxBlockZ) || (BaseZ + cChunkDef::Width < m_MinBlockZ) ) { // Tunnel does not intersect the chunk at all, bail out @@ -485,7 +484,7 @@ void cCaveTunnel::ProcessChunk( // Cannot intersect, bail out early continue; } - + // Carve out a sphere around the xyz point, m_Radius in diameter; skip 3/7 off the top and bottom: int DifX = itr->m_BlockX - BlockStartX; // substitution for faster calc int DifY = itr->m_BlockY; @@ -493,7 +492,7 @@ void cCaveTunnel::ProcessChunk( int Bottom = std::max(itr->m_BlockY - 3 * itr->m_Radius / 7, 1); int Top = std::min(itr->m_BlockY + 3 * itr->m_Radius / 7, (int)(cChunkDef::Height)); int SqRad = itr->m_Radius * itr->m_Radius; - for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++) + for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++) { for (int y = Bottom; y <= Top; y++) { @@ -527,9 +526,9 @@ void cCaveTunnel::ProcessChunk( } // for y } // for x, z } // for itr - m_Points[] - + /* - #ifdef _DEBUG + #ifdef _DEBUG // For debugging purposes, outline the shape of the cave using glowstone, *after* carving the entire cave: for (cCaveDefPoints::const_iterator itr = m_Points.begin(), end = m_Points.end(); itr != end; ++itr) { @@ -587,7 +586,7 @@ cStructGenWormNestCaves::cCaveSystem::cCaveSystem(int a_BlockX, int a_BlockZ, in int OriginX = a_BlockX + (a_Noise.IntNoise3DInt(13 * a_BlockX, 17 * a_BlockZ, 11 * i) / 19) % a_MaxOffset; int OriginZ = a_BlockZ + (a_Noise.IntNoise3DInt(17 * a_BlockX, 13 * a_BlockZ, 11 * i) / 23) % a_MaxOffset; int OriginY = 20 + (a_Noise.IntNoise3DInt(19 * a_BlockX, 13 * a_BlockZ, 11 * i) / 17) % 20; - + // Generate three branches from the origin point: // The tunnels generated depend on X, Y, Z and Branches, // for the same set of numbers it generates the same offsets! @@ -613,8 +612,8 @@ cStructGenWormNestCaves::cCaveSystem::~cCaveSystem() void cStructGenWormNestCaves::cCaveSystem::ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, + int a_ChunkX, int a_ChunkZ, + cChunkDef::BlockTypes & a_BlockTypes, cChunkDef::HeightMap & a_HeightMap ) { @@ -645,14 +644,14 @@ AString cStructGenWormNestCaves::cCaveSystem::ExportAsSVG(int a_Color, int a_Off AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ - 5, a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ + 5 ); - + // A gray line from the base point to the first point of the ravine, for identification: AppendPrintf(SVG, "<path style=\"fill:none;stroke:#cfcfcf;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ, - a_OffsetX + m_Tunnels.front()->m_Points.front().m_BlockX, + a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ, + a_OffsetX + m_Tunnels.front()->m_Points.front().m_BlockX, a_OffsetZ + m_Tunnels.front()->m_Points.front().m_BlockZ ); - + // Offset guides: if (a_OffsetX > 0) { @@ -666,7 +665,7 @@ AString cStructGenWormNestCaves::cCaveSystem::ExportAsSVG(int a_Color, int a_Off a_OffsetZ, a_OffsetZ ); } - + return SVG; } #endif // _DEBUG @@ -689,7 +688,7 @@ void cStructGenWormNestCaves::cCaveSystem::Clear(void) void cStructGenWormNestCaves::cCaveSystem::GenerateTunnelsFromPoint( - int a_OriginX, int a_OriginY, int a_OriginZ, + int a_OriginX, int a_OriginY, int a_OriginZ, cNoise & a_Noise, int a_NumSegments ) { @@ -727,7 +726,7 @@ int cStructGenWormNestCaves::cCaveSystem::GetRadius(cNoise & a_Noise, int a_Orig // We want mapping 384 -> 3, 0 -> 19, 768 -> 19, so divide by 24 to get [0 .. 31] with center at 16, then use abs() to fold around the center int res = 3 + abs((sum / 24) - 16); */ - + // Algorithm of choice: random value in the range of zero to random value - heavily towards zero int res = MIN_RADIUS + (rnd >> 8) % ((rnd % (MAX_RADIUS - MIN_RADIUS)) + 1); return res; @@ -815,7 +814,7 @@ void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStru ++itr; } } // for itr - m_Cache[] - + for (int x = 0; x < NEIGHBORHOOD_SIZE; x++) { int RealX = (BaseX + x) * m_Grid; @@ -837,11 +836,11 @@ void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStru } } } - + // Copy a_Caves into m_Cache to the beginning: cCaveSystems CavesCopy(a_Caves); m_Cache.splice(m_Cache.begin(), CavesCopy, CavesCopy.begin(), CavesCopy.end()); - + // Trim the cache if it's too long: if (m_Cache.size() > 100) { @@ -855,7 +854,7 @@ void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStru std::advance(itr, 100); m_Cache.erase(itr, m_Cache.end()); } - + /* // Uncomment this block for debugging the caves' shapes in 2D using an SVG export #ifdef _DEBUG @@ -869,7 +868,7 @@ void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStru SVG.append((*itr)->ExportAsSVG(Color, 512, 512)); } SVG.append("</svg>\n"); - + AString fnam; Printf(fnam, "wnc\\%03d_%03d.svg", a_ChunkX, a_ChunkZ); cFile File(fnam, cFile::fmWrite); @@ -905,13 +904,13 @@ static float GetMarbleNoise( float x, float y, float z, cNoise & a_Noise ) void cStructGenMarbleCaves::GenStructures(cChunkDesc & a_ChunkDesc) { cNoise Noise(m_Seed); - for (int z = 0; z < cChunkDef::Width; z++) + for (int z = 0; z < cChunkDef::Width; z++) { const float zz = (float)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + z); for (int x = 0; x < cChunkDef::Width; x++) { const float xx = (float)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + x); - + int Top = a_ChunkDesc.GetHeight(x, z); for (int y = 1; y < Top; ++y ) { @@ -940,18 +939,17 @@ void cStructGenMarbleCaves::GenStructures(cChunkDesc & a_ChunkDesc) void cStructGenDualRidgeCaves::GenStructures(cChunkDesc & a_ChunkDesc) { - for (int z = 0; z < cChunkDef::Width; z++) + for (int z = 0; z < cChunkDef::Width; z++) { const float zz = (float)(a_ChunkDesc.GetChunkZ() * cChunkDef::Width + z) / 10; for (int x = 0; x < cChunkDef::Width; x++) { const float xx = (float)(a_ChunkDesc.GetChunkX() * cChunkDef::Width + x) / 10; - + int Top = a_ChunkDesc.GetHeight(x, z); for (int y = 1; y <= Top; ++y) { const float yy = (float)y / 10; - const float WaveNoise = 1; float n1 = m_Noise1.CubicNoise3D(xx, yy, zz); float n2 = m_Noise2.CubicNoise3D(xx, yy, zz); float n3 = m_Noise1.CubicNoise3D(xx * 4, yy * 4, zz * 4) / 4; diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp index 9fb306996..6050430fd 100644 --- a/src/Generating/ChunkDesc.cpp +++ b/src/Generating/ChunkDesc.cpp @@ -271,7 +271,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX a_MaxRelX += 1; a_MaxRelY += 1; a_MaxRelZ += 1; - + // Check coords validity: if (a_MinRelX < 0) { @@ -314,7 +314,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX LOGWARNING("%s: MaxRelY more than chunk height, adjusting to chunk height", __FUNCTION__); a_MaxRelY = cChunkDef::Height - 1; } - + if (a_MinRelZ < 0) { LOGWARNING("%s: MinRelZ less than zero, adjusting to zero", __FUNCTION__); @@ -371,7 +371,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX HEIGHTTYPE cChunkDesc::GetMaxHeight(void) const { HEIGHTTYPE MaxHeight = m_HeightMap[0]; - for (int i = 1; i < ARRAYCOUNT(m_HeightMap); i++) + for (unsigned int i = 1; i < ARRAYCOUNT(m_HeightMap); i++) { if (m_HeightMap[i] > MaxHeight) { @@ -398,7 +398,7 @@ void cChunkDesc::FillRelCuboid( int MaxX = std::min(a_MaxX, cChunkDef::Width - 1); int MaxY = std::min(a_MaxY, cChunkDef::Height - 1); int MaxZ = std::min(a_MaxZ, cChunkDef::Width - 1); - + for (int y = MinY; y <= MaxY; y++) { for (int z = MinZ; z <= MaxZ; z++) @@ -429,7 +429,7 @@ void cChunkDesc::ReplaceRelCuboid( int MaxX = std::min(a_MaxX, cChunkDef::Width - 1); int MaxY = std::min(a_MaxY, cChunkDef::Height - 1); int MaxZ = std::min(a_MaxZ, cChunkDef::Width - 1); - + for (int y = MinY; y <= MaxY; y++) { for (int z = MinZ; z <= MaxZ; z++) @@ -465,7 +465,7 @@ void cChunkDesc::FloorRelCuboid( int MaxX = std::min(a_MaxX, cChunkDef::Width - 1); int MaxY = std::min(a_MaxY, cChunkDef::Height - 1); int MaxZ = std::min(a_MaxZ, cChunkDef::Width - 1); - + for (int y = MinY; y <= MaxY; y++) { for (int z = MinZ; z <= MaxZ; z++) @@ -506,7 +506,7 @@ void cChunkDesc::RandomFillRelCuboid( int MaxX = std::min(a_MaxX, cChunkDef::Width - 1); int MaxY = std::min(a_MaxY, cChunkDef::Height - 1); int MaxZ = std::min(a_MaxZ, cChunkDef::Width - 1); - + for (int y = MinY; y <= MaxY; y++) { for (int z = MinZ; z <= MaxZ; z++) @@ -565,7 +565,7 @@ cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ) void cChunkDesc::CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas) { const NIBBLETYPE * AreaMetas = m_BlockArea.GetBlockMetas(); - for (int i = 0; i < ARRAYCOUNT(a_DestMetas); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(a_DestMetas); i++) { a_DestMetas[i] = AreaMetas[2 * i] | (AreaMetas[2 * i + 1] << 4); } diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp index 59a00b540..33c956eba 100644 --- a/src/Generating/ChunkGenerator.cpp +++ b/src/Generating/ChunkGenerator.cpp @@ -15,10 +15,10 @@ /// If the generation queue size exceeds this number, a warning will be output -const int QUEUE_WARNING_LIMIT = 1000; +const unsigned int QUEUE_WARNING_LIMIT = 1000; /// If the generation queue size exceeds this number, chunks with no clients will be skipped -const int QUEUE_SKIP_LIMIT = 500; +const unsigned int QUEUE_SKIP_LIMIT = 500; @@ -53,7 +53,7 @@ bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile) m_World = a_World; m_Seed = a_IniFile.GetValueSetI("Seed", "Seed", rnd.randInt()); AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable"); - + if (NoCaseCompare(GeneratorName, "Noise3D") == 0) { m_Generator = new cNoise3DGenerator(*this); @@ -72,9 +72,9 @@ bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile) LOGERROR("Generator could not start, aborting the server"); return false; } - + m_Generator->Initialize(a_World, a_IniFile); - + return super::Start(); } @@ -101,7 +101,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk { { cCSLock Lock(m_CS); - + // Check if it is already in the queue: for (cChunkCoordsList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr) { @@ -111,7 +111,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk return; } } // for itr - m_Queue[] - + // Add to queue, issue a warning if too many: if (m_Queue.size() >= QUEUE_WARNING_LIMIT) { @@ -119,7 +119,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk } m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ)); } - + m_Event.Set(); } @@ -196,7 +196,7 @@ void cChunkGenerator::Execute(void) int NumChunksGenerated = 0; // Number of chunks generated since the queue was last empty clock_t GenerationStart = clock(); // Clock tick when the queue started to fill clock_t LastReportTick = clock(); // Clock tick of the last report made (so that performance isn't reported too often) - + while (!m_ShouldTerminate) { cCSLock Lock(m_CS); @@ -219,7 +219,7 @@ void cChunkGenerator::Execute(void) GenerationStart = clock(); LastReportTick = clock(); } - + cChunkCoords coords = m_Queue.front(); // Get next coord from queue m_Queue.erase( m_Queue.begin() ); // Remove coordinate from queue bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT); @@ -243,19 +243,19 @@ void cChunkGenerator::Execute(void) // Already generated, ignore request continue; } - + if (SkipEnabled && !m_World->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ)) { LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); continue; } - + LOGD("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - + // Save the chunk right after generating, so that we don't have to generate it again on next run m_World->GetStorage().QueueSaveChunk(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - + NumChunksGenerated++; } // while (!bStop) } @@ -269,17 +269,17 @@ void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) cRoot::Get()->GetPluginManager()->CallHookChunkGenerating(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc); m_Generator->DoGenerate(a_ChunkX, a_ChunkZ, ChunkDesc); cRoot::Get()->GetPluginManager()->CallHookChunkGenerated(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc); - + #ifdef _DEBUG // Verify that the generator has produced valid data: ChunkDesc.VerifyHeightmap(); #endif - + cChunkDef::BlockNibbles BlockMetas; ChunkDesc.CompressBlockMetas(BlockMetas); - + m_World->SetChunkData( - a_ChunkX, a_ChunkZ, + a_ChunkX, a_ChunkZ, ChunkDesc.GetBlockTypes(), BlockMetas, NULL, NULL, // We don't have lighting, chunk will be lighted when needed &ChunkDesc.GetHeightMap(), &ChunkDesc.GetBiomeMap(), diff --git a/src/Generating/DistortedHeightmap.cpp b/src/Generating/DistortedHeightmap.cpp index 98eab31b5..7e46c251e 100644 --- a/src/Generating/DistortedHeightmap.cpp +++ b/src/Generating/DistortedHeightmap.cpp @@ -30,7 +30,7 @@ const cDistortedHeightmap::sGenParam cDistortedHeightmap::m_GenParam[biNumBiomes /* biExtremeHills */ {16.0f, 16.0f}, /* biForest */ { 3.0f, 3.0f}, /* biTaiga */ { 1.5f, 1.5f}, - + /* biSwampland */ { 0.0f, 0.0f}, /* biRiver */ { 0.0f, 0.0f}, /* biNether */ { 0.0f, 0.0f}, // Unused, but must be here due to indexing @@ -81,7 +81,7 @@ void cDistortedHeightmap::Initialize(cIniFile & a_IniFile) { return; } - + // Read the params from the INI file: m_SeaLevel = a_IniFile.GetValueSetI("Generator", "DistortedHeightmapSeaLevel", 62); m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "DistortedHeightmapFrequencyX", 10); @@ -103,8 +103,8 @@ void cDistortedHeightmap::PrepareState(int a_ChunkX, int a_ChunkZ) } m_CurChunkX = a_ChunkX; m_CurChunkZ = a_ChunkZ; - - + + m_HeightGen.GenHeightMap(a_ChunkX, a_ChunkZ, m_CurChunkHeights); UpdateDistortAmps(); GenerateHeightArray(); @@ -126,13 +126,13 @@ void cDistortedHeightmap::GenerateHeightArray(void) NOISE_DATATYPE EndY = ((NOISE_DATATYPE)(257)) / m_FrequencyY; NOISE_DATATYPE StartZ = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width)) / m_FrequencyZ; NOISE_DATATYPE EndZ = ((NOISE_DATATYPE)((m_CurChunkZ + 1) * cChunkDef::Width - 1)) / m_FrequencyZ; - + m_NoiseDistortX.Generate3D(DistortNoiseX, DIM_X, DIM_Y, DIM_Z, StartX, EndX, StartY, EndY, StartZ, EndZ, Workspace); m_NoiseDistortZ.Generate3D(DistortNoiseZ, DIM_X, DIM_Y, DIM_Z, StartX, EndX, StartY, EndY, StartZ, EndZ, Workspace); // The distorted heightmap, before linear upscaling NOISE_DATATYPE DistHei[DIM_X * DIM_Y * DIM_Z]; - + // Distort the heightmap using the distortion: for (int z = 0; z < DIM_Z; z++) { @@ -151,7 +151,7 @@ void cDistortedHeightmap::GenerateHeightArray(void) } } } - + // Upscale the distorted heightmap into full dimensions: LinearUpscale3DArray( DistHei, DIM_X, DIM_Y, DIM_Z, @@ -208,7 +208,7 @@ void cDistortedHeightmap::ComposeTerrain(cChunkDesc & a_ChunkDesc) // Prepare the internal state for generating this chunk: PrepareState(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ()); - + // Compose: a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0); for (int z = 0; z < cChunkDef::Width; z++) @@ -348,7 +348,7 @@ int cDistortedHeightmap::GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z) { return cChunkDef::GetHeight(m_CurChunkHeights, RelX, RelZ); } - + // Ask the cache: HEIGHTTYPE res = 0; if (m_HeightGen.GetHeightAt(ChunkX, ChunkZ, RelX, RelZ, res)) @@ -356,7 +356,7 @@ int cDistortedHeightmap::GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z) // The height was in the cache return res; } - + // The height is not in the cache, generate full heightmap and get it there: cChunkDef::HeightMap Heightmap; m_HeightGen.GenHeightMap(ChunkX, ChunkZ, Heightmap); @@ -385,7 +385,7 @@ void cDistortedHeightmap::UpdateDistortAmps(void) GetDistortAmpsAt(Biomes, x * INTERPOL_X, z * INTERPOL_Z, m_DistortAmpX[x + DIM_X * z], m_DistortAmpZ[x + DIM_X * z]); } } -} +} @@ -430,7 +430,7 @@ void cDistortedHeightmap::GetDistortAmpsAt(BiomeNeighbors & a_Neighbors, int a_R // For each biome type that has a nonzero count, calc its amps and add it: NOISE_DATATYPE AmpX = 0; NOISE_DATATYPE AmpZ = 0; - for (int i = 0; i < ARRAYCOUNT(BiomeCounts); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(BiomeCounts); i++) { AmpX += BiomeCounts[i] * m_GenParam[i].m_DistortAmpX; AmpZ += BiomeCounts[i] * m_GenParam[i].m_DistortAmpZ; diff --git a/src/Generating/EndGen.cpp b/src/Generating/EndGen.cpp index 3eba5c47b..90a8071fa 100644 --- a/src/Generating/EndGen.cpp +++ b/src/Generating/EndGen.cpp @@ -18,7 +18,7 @@ enum INTERPOL_X = 4, INTERPOL_Y = 4, INTERPOL_Z = 4, - + // Size of chunk data, downscaled before interpolation: DIM_X = 16 / INTERPOL_X + 1, DIM_Y = 256 / INTERPOL_Y + 1, @@ -59,7 +59,7 @@ void cEndGen::Initialize(cIniFile & a_IniFile) m_FrequencyX = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "EndGenFrequencyX", m_FrequencyX); m_FrequencyY = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "EndGenFrequencyY", m_FrequencyY); m_FrequencyZ = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "EndGenFrequencyZ", m_FrequencyZ); - + // Recalculate the min and max chunk coords of the island m_MaxChunkX = (m_IslandSizeX + cChunkDef::Width - 1) / cChunkDef::Width; m_MinChunkX = -m_MaxChunkX; @@ -75,15 +75,15 @@ void cEndGen::Initialize(cIniFile & a_IniFile) void cEndGen::PrepareState(int a_ChunkX, int a_ChunkZ) { ASSERT(!IsChunkOutsideRange(a_ChunkX, a_ChunkZ)); // Should be filtered before calling this function - + if ((m_LastChunkX == a_ChunkX) && (m_LastChunkZ == a_ChunkZ)) { return; } - + m_LastChunkX = a_ChunkX; m_LastChunkZ = a_ChunkZ; - + GenerateNoiseArray(); } @@ -96,7 +96,7 @@ void cEndGen::GenerateNoiseArray(void) { NOISE_DATATYPE NoiseData[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y] NOISE_DATATYPE Workspace[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y] - + // Generate the downscaled noise: NOISE_DATATYPE StartX = ((NOISE_DATATYPE)(m_LastChunkX * cChunkDef::Width)) / m_FrequencyX; NOISE_DATATYPE EndX = ((NOISE_DATATYPE)((m_LastChunkX + 1) * cChunkDef::Width)) / m_FrequencyX; @@ -105,7 +105,7 @@ void cEndGen::GenerateNoiseArray(void) NOISE_DATATYPE StartY = 0; NOISE_DATATYPE EndY = ((NOISE_DATATYPE)257) / m_FrequencyY; m_Perlin.Generate3D(NoiseData, DIM_X, DIM_Z, DIM_Y, StartX, EndX, StartZ, EndZ, StartY, EndY, Workspace); - + // Add distance: int idx = 0; for (int y = 0; y < DIM_Y; y++) @@ -125,7 +125,7 @@ void cEndGen::GenerateNoiseArray(void) } // for x } // for z } // for y - + // Upscale into real chunk size: LinearUpscale3DArray(NoiseData, DIM_X, DIM_Z, DIM_Y, m_NoiseArray, INTERPOL_X, INTERPOL_Z, INTERPOL_Y); } @@ -133,14 +133,14 @@ void cEndGen::GenerateNoiseArray(void) - + /// Returns true if the chunk is outside of the island's dimensions bool cEndGen::IsChunkOutsideRange(int a_ChunkX, int a_ChunkZ) { return ( (a_ChunkX < m_MinChunkX) || (a_ChunkX > m_MaxChunkX) || (a_ChunkZ < m_MinChunkZ) || (a_ChunkZ > m_MaxChunkZ) - ); + ); } @@ -151,15 +151,15 @@ void cEndGen::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_ { if (IsChunkOutsideRange(a_ChunkX, a_ChunkZ)) { - for (int i = 0; i < ARRAYCOUNT(a_HeightMap); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(a_HeightMap); i++) { a_HeightMap[i] = 0; } return; } - + PrepareState(a_ChunkX, a_ChunkZ); - + int MaxY = std::min((int)(1.75 * m_IslandSizeY + 1), cChunkDef::Height - 1); for (int z = 0; z < cChunkDef::Width; z++) { @@ -189,9 +189,9 @@ void cEndGen::ComposeTerrain(cChunkDesc & a_ChunkDesc) a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0); return; } - + PrepareState(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ()); - + int MaxY = std::min((int)(1.75 * m_IslandSizeY + 1), cChunkDef::Height - 1); for (int z = 0; z < cChunkDef::Width; z++) { diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp index 159e6b4ea..f42240e55 100644 --- a/src/Generating/MineShafts.cpp +++ b/src/Generating/MineShafts.cpp @@ -41,8 +41,8 @@ public: mskCrossing, mskStaircase, } ; - - + + enum eDirection { dirXP, @@ -50,8 +50,8 @@ public: dirXM, dirZM, } ; - - + + cStructGenMineShafts::cMineShaftSystem & m_ParentSystem; eKind m_Kind; cCuboid m_BoundingBox; @@ -62,25 +62,25 @@ public: m_Kind(a_Kind) { } - + cMineShaft(cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, eKind a_Kind, const cCuboid & a_BoundingBox) : m_ParentSystem(a_ParentSystem), m_Kind(a_Kind), m_BoundingBox(a_BoundingBox) { } - + /// Returns true if this mineshaft intersects the specified cuboid bool DoesIntersect(const cCuboid & a_Other) { return m_BoundingBox.DoesIntersect(a_Other); } - + /** If recursion level is not too large, appends more branches to the parent system, using exit points specific to this class. */ virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) = 0; - + /// Imprints this shape into the specified chunk's data virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) = 0; } ; @@ -95,10 +95,10 @@ class cMineShaftDirtRoom : public cMineShaft { typedef cMineShaft super; - + public: cMineShaftDirtRoom(cStructGenMineShafts::cMineShaftSystem & a_Parent, cNoise & a_Noise); - + // cMineShaft overrides: virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override; virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override; @@ -112,7 +112,7 @@ class cMineShaftCorridor : public cMineShaft { typedef cMineShaft super; - + public: /** Creates a new Corridor attached to the specified pivot point and direction. Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit. @@ -123,36 +123,36 @@ public: int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction, cNoise & a_Noise ); - + protected: static const int MAX_SEGMENTS = 5; - + int m_NumSegments; eDirection m_Direction; bool m_HasFullBeam[MAX_SEGMENTS]; ///< If true, segment at that index has a full beam support (planks in the top center block) int m_ChestPosition; ///< If <0, no chest; otherwise an offset from m_BoundingBox's p1.x or p1.z, depenging on m_Direction int m_SpawnerPosition; ///< If <0, no spawner; otherwise an offset from m_BoundingBox's p1.x or p1.z, depenging on m_Direction bool m_HasTracks; ///< If true, random tracks will be placed on the floor - + cMineShaftCorridor( cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, const cCuboid & a_BoundingBox, int a_NumSegments, eDirection a_Direction, cNoise & a_Noise ); - + // cMineShaft overrides: virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override; virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override; /// Places a chest, if the corridor has one void PlaceChest(cChunkDesc & a_ChunkDesc); - + /// If this corridor has tracks, places them randomly void PlaceTracks(cChunkDesc & a_ChunkDesc); - + /// If this corridor has a spawner, places the spawner void PlaceSpawner(cChunkDesc & a_ChunkDesc); - + /// Randomly places torches around the central beam block void PlaceTorches(cChunkDesc & a_ChunkDesc); } ; @@ -165,7 +165,7 @@ class cMineShaftCrossing : public cMineShaft { typedef cMineShaft super; - + public: /** Creates a new Crossing attached to the specified pivot point and direction. Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit. @@ -176,10 +176,10 @@ public: int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction, cNoise & a_Noise ); - + protected: cMineShaftCrossing(cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, const cCuboid & a_BoundingBox); - + // cMineShaft overrides: virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override; virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override; @@ -193,14 +193,14 @@ class cMineShaftStaircase : public cMineShaft { typedef cMineShaft super; - + public: enum eSlope { sUp, sDown, } ; - + /** Creates a new Staircase attached to the specified pivot point and direction. Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit. May return NULL if cannot fit. @@ -210,12 +210,12 @@ public: int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction, cNoise & a_Noise ); - + protected: eDirection m_Direction; eSlope m_Slope; - - + + cMineShaftStaircase( cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, const cCuboid & a_BoundingBox, @@ -257,7 +257,7 @@ public: /// Carves the system into the chunk data void ProcessChunk(cChunkDesc & a_Chunk); - + /** Creates new cMineShaft descendant connected at the specified point, heading the specified direction, if it fits, appends it to the list and calls its AppendBranches() */ @@ -266,7 +266,7 @@ public: cMineShaft::eDirection a_Direction, cNoise & a_Noise, int a_RecursionLevel ); - + /// Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the bounding box is valid bool CanAppend(const cCuboid & a_BoundingBox); } ; @@ -294,7 +294,7 @@ cStructGenMineShafts::cMineShaftSystem::cMineShaftSystem( m_ChanceTorch(1000) // TODO: settable { m_MineShafts.reserve(100); - + cMineShaft * Start = new cMineShaftDirtRoom(*this, a_Noise); m_MineShafts.push_back(Start); @@ -302,9 +302,9 @@ cStructGenMineShafts::cMineShaftSystem::cMineShaftSystem( Start->m_BoundingBox.p1.x - a_MaxSystemSize / 2, 2, Start->m_BoundingBox.p1.z - a_MaxSystemSize / 2, Start->m_BoundingBox.p2.x + a_MaxSystemSize / 2, 50, Start->m_BoundingBox.p2.z + a_MaxSystemSize / 2 ); - + Start->AppendBranches(0, a_Noise); - + for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr) { ASSERT((*itr)->m_BoundingBox.IsSorted()); @@ -341,7 +341,7 @@ void cStructGenMineShafts::cMineShaftSystem::ProcessChunk(cChunkDesc & a_Chunk) void cStructGenMineShafts::cMineShaftSystem::AppendBranch( - int a_PivotX, int a_PivotY, int a_PivotZ, + int a_PivotX, int a_PivotY, int a_PivotZ, cMineShaft::eDirection a_Direction, cNoise & a_Noise, int a_RecursionLevel ) @@ -350,7 +350,7 @@ void cStructGenMineShafts::cMineShaftSystem::AppendBranch( { return; } - + cMineShaft * Next = NULL; int rnd = (a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_RecursionLevel * 16, a_PivotZ) / 13) % m_ProbLevelStaircase; if (rnd < m_ProbLevelCorridor) @@ -384,7 +384,7 @@ bool cStructGenMineShafts::cMineShaftSystem::CanAppend(const cCuboid & a_Boundin // Too far away, or too low / too high return false; } - + // Check intersections: for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr) { @@ -436,7 +436,7 @@ void cMineShaftDirtRoom::AppendBranches(int a_RecursionLevel, cNoise & a_Noise) rnd >>= 4; m_ParentSystem.AppendBranch(x, m_BoundingBox.p1.y + (rnd % Height), m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel); } - + for (int z = m_BoundingBox.p1.z + 1; z < m_BoundingBox.p2.z; z += 4) { int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x, a_RecursionLevel, z) / 13; @@ -464,13 +464,13 @@ void cMineShaftDirtRoom::ProcessChunk(cChunkDesc & a_ChunkDesc) // Early bailout - cannot intersect this chunk return; } - + // Chunk-relative coords of the boundaries: int MinX = std::max(BlockX, m_BoundingBox.p1.x) - BlockX; int MaxX = std::min(BlockX + cChunkDef::Width, m_BoundingBox.p2.x + 1) - BlockX; int MinZ = std::max(BlockZ, m_BoundingBox.p1.z) - BlockZ; int MaxZ = std::min(BlockZ + cChunkDef::Width, m_BoundingBox.p2.z + 1) - BlockZ; - + // Carve the room out: for (int z = MinZ; z < MaxZ; z++) { @@ -513,7 +513,7 @@ cMineShaftCorridor::cMineShaftCorridor( rnd >>= 2; } m_HasTracks = ((rnd % 4) < 2); // 50 % chance of tracks - + rnd = a_Noise.IntNoise3DInt(a_BoundingBox.p1.z, a_BoundingBox.p1.x, a_BoundingBox.p1.y) / 7; int ChestCheck = rnd % 250; rnd >>= 8; @@ -597,7 +597,7 @@ void cMineShaftCorridor::AppendBranches(int a_RecursionLevel, cNoise & a_Noise) } break; } - + case dirZM: { m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + 1, Height, m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel); @@ -646,14 +646,14 @@ void cMineShaftCorridor::ProcessChunk(cChunkDesc & a_ChunkDesc) Top.p2.y += 1; Top.p1.y = Top.p2.y; a_ChunkDesc.FillRelCuboid(RelBoundingBox, E_BLOCK_AIR, 0); - a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_AIR, 0, BlockX ^ BlockZ + BlockX, 8000); + a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_AIR, 0, (BlockX ^ (BlockZ + BlockX)), 8000); if (m_SpawnerPosition >= 0) { // Cobwebs around the spider spawner - a_ChunkDesc.RandomFillRelCuboid(RelBoundingBox, E_BLOCK_COBWEB, 0, BlockX ^ BlockZ + BlockZ, 8000); - a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, BlockX ^ BlockZ + BlockX, 5000); + a_ChunkDesc.RandomFillRelCuboid(RelBoundingBox, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockZ)), 8000); + a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockX)), 5000); } - a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, BlockX ^ BlockZ + BlockX + 10, 500); + a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockX + 10)), 500); RelBoundingBox.p1.y = m_BoundingBox.p1.y; RelBoundingBox.p2.y = m_BoundingBox.p1.y; a_ChunkDesc.FloorRelCuboid(RelBoundingBox, E_BLOCK_PLANKS, 0); @@ -693,7 +693,7 @@ void cMineShaftCorridor::ProcessChunk(cChunkDesc & a_ChunkDesc) } // for i - NumSegments break; } - + case dirZM: case dirZP: { @@ -729,7 +729,7 @@ void cMineShaftCorridor::ProcessChunk(cChunkDesc & a_ChunkDesc) break; } // case dirZ? } // for i - + PlaceChest(a_ChunkDesc); PlaceTracks(a_ChunkDesc); PlaceSpawner(a_ChunkDesc); // (must be after Tracks!) @@ -762,7 +762,7 @@ void cMineShaftCorridor::PlaceChest(cChunkDesc & a_ChunkDesc) { return; } - + int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; int x, z; @@ -777,9 +777,10 @@ void cMineShaftCorridor::PlaceChest(cChunkDesc & a_ChunkDesc) Meta = E_META_CHEST_FACING_ZP; break; } - + case dirZM: case dirZP: + default: { x = m_BoundingBox.p1.x - BlockX; z = m_BoundingBox.p1.z + m_ChestPosition - BlockZ; @@ -829,7 +830,7 @@ void cMineShaftCorridor::PlaceTracks(cChunkDesc & a_ChunkDesc) Meta = E_META_TRACKS_X; break; } - + case dirZM: case dirZP: { @@ -921,7 +922,7 @@ void cMineShaftCorridor::PlaceTorches(cChunkDesc & a_ChunkDesc) } // for i break; } - + case dirZM: case dirZP: { @@ -1034,14 +1035,14 @@ void cMineShaftCrossing::AppendBranches(int a_RecursionLevel, cNoise & a_Noise) { 5, 5, 2, dirXP}, { 2, 5, 5, dirZP}, } ; - for (int i = 0; i < ARRAYCOUNT(Exits); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(Exits); i++) { if (m_BoundingBox.p1.y + Exits[i].y >= m_BoundingBox.p2.y) { // This exit is not available (two-level exit on a one-level crossing) continue; } - + int Height = m_BoundingBox.p1.y + Exits[i].y; m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + Exits[i].x, Height, m_BoundingBox.p1.z + Exits[i].z, Exits[i].dir, a_Noise, a_RecursionLevel); } // for i @@ -1089,7 +1090,7 @@ void cMineShaftCrossing::ProcessChunk(cChunkDesc & a_ChunkDesc) a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Mid, Ceil, box.p1.z, box.p1.z, E_BLOCK_AIR, 0); a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Mid, Ceil, box.p2.z, box.p2.z, E_BLOCK_AIR, 0); } - + // The floor, if needed: box.p2.y = box.p1.y; a_ChunkDesc.FloorRelCuboid(box, E_BLOCK_PLANKS, 0); @@ -1198,7 +1199,7 @@ void cMineShaftStaircase::ProcessChunk(cChunkDesc & a_ChunkDesc) // No intersection between this staircase and this chunk return; } - + int SFloor = RelB.p1.y + ((m_Slope == sDown) ? 5 : 1); int DFloor = RelB.p1.y + ((m_Slope == sDown) ? 1 : 5); int Add = (m_Slope == sDown) ? -1 : 1; @@ -1221,7 +1222,7 @@ void cMineShaftStaircase::ProcessChunk(cChunkDesc & a_ChunkDesc) } break; } - + case dirXP: { a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p1.x + 1, SFloor, SFloor + 2, RelB.p1.z, RelB.p2.z, E_BLOCK_AIR, 0); @@ -1253,7 +1254,7 @@ void cMineShaftStaircase::ProcessChunk(cChunkDesc & a_ChunkDesc) } break; } - + case dirZP: { a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p2.x, SFloor, SFloor + 2, RelB.p1.z, RelB.p1.z + 1, E_BLOCK_AIR, 0); @@ -1269,7 +1270,7 @@ void cMineShaftStaircase::ProcessChunk(cChunkDesc & a_ChunkDesc) } break; } - + } // switch (m_Direction) } @@ -1359,7 +1360,7 @@ void cStructGenMineShafts::GetMineShaftSystemsForChunk( ++itr; } } // for itr - m_Cache[] - + for (int x = 0; x < NEIGHBORHOOD_SIZE; x++) { int RealX = (BaseX + x) * m_GridSize; @@ -1381,11 +1382,11 @@ void cStructGenMineShafts::GetMineShaftSystemsForChunk( } } // for z } // for x - + // Copy a_MineShafts into m_Cache to the beginning: cMineShaftSystems MineShaftsCopy(a_MineShafts); m_Cache.splice(m_Cache.begin(), MineShaftsCopy, MineShaftsCopy.begin(), MineShaftsCopy.end()); - + // Trim the cache if it's too long: if (m_Cache.size() > 100) { diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp index f47c64430..03626a800 100644 --- a/src/Generating/Noise3DGenerator.cpp +++ b/src/Generating/Noise3DGenerator.cpp @@ -25,8 +25,8 @@ public: DoTest1(); DoTest2(); } - - + + void DoTest1(void) { float In[3 * 3 * 3]; @@ -39,8 +39,8 @@ public: LinearUpscale3DArray(In, 3, 3, 3, Out, 8, 16, 17); Debug3DNoise(Out, 17, 33, 35, "Upscale3D test"); } - - + + void DoTest2(void) { float In[3 * 3]; @@ -53,7 +53,7 @@ public: LinearUpscale2DArray(In, 3, 3, Out, 8, 16); Debug2DNoise(Out, 17, 33, "Upscale2D test"); } - + } gTest; //*/ @@ -72,7 +72,7 @@ cNoise3DGenerator::cNoise3DGenerator(cChunkGenerator & a_ChunkGenerator) : m_Perlin.AddOctave(1, (NOISE_DATATYPE)0.5); m_Perlin.AddOctave((NOISE_DATATYPE)0.5, 1); m_Perlin.AddOctave((NOISE_DATATYPE)0.5, 2); - + #if 0 // DEBUG: Test the noise generation: // NOTE: In order to be able to run MCS with this code, you need to increase the default thread stack size @@ -84,7 +84,7 @@ cNoise3DGenerator::cNoise3DGenerator(cChunkGenerator & a_ChunkGenerator) : m_FrequencyY = 4; m_FrequencyZ = 4; m_AirThreshold = 0.5; - + const int NumChunks = 4; NOISE_DATATYPE Noise[NumChunks][cChunkDef::Width * cChunkDef::Width * cChunkDef::Height]; for (int x = 0; x < NumChunks; x++) @@ -153,7 +153,7 @@ cNoise3DGenerator::~cNoise3DGenerator() void cNoise3DGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile) { m_World = a_World; - + // Params: m_SeaLevel = a_IniFile.GetValueSetI("Generator", "Noise3DSeaLevel", 62); m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0); @@ -170,7 +170,7 @@ void cNoise3DGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile) void cNoise3DGenerator::GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) { - for (int i = 0; i < ARRAYCOUNT(a_BiomeMap); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(a_BiomeMap); i++) { a_BiomeMap[i] = biExtremeHills; } @@ -184,7 +184,7 @@ void cNoise3DGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_Ch { NOISE_DATATYPE Noise[17 * 257 * 17]; GenerateNoiseArray(a_ChunkX, a_ChunkZ, Noise); - + // Output noise into chunk: for (int z = 0; z < cChunkDef::Width; z++) { @@ -207,7 +207,7 @@ void cNoise3DGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_Ch } } } - + UpdateHeightmap(a_ChunkDesc); ComposeTerrain (a_ChunkDesc); } @@ -228,19 +228,19 @@ void cNoise3DGenerator::GenerateNoiseArray(int a_ChunkX, int a_ChunkZ, NOISE_DAT NOISE_DATATYPE EndZ = ((NOISE_DATATYPE)((a_ChunkZ + 1) * cChunkDef::Width) - 1) / m_FrequencyZ; NOISE_DATATYPE StartY = 0; NOISE_DATATYPE EndY = ((NOISE_DATATYPE)256) / m_FrequencyY; - + m_Perlin.Generate3D(NoiseO, DIM_X, DIM_Y, DIM_Z, StartX, EndX, StartY, EndY, StartZ, EndZ, NoiseW); - + // DEBUG: Debug3DNoise(NoiseO, DIM_X, DIM_Y, DIM_Z, Printf("Chunk_%d_%d_orig", a_ChunkX, a_ChunkZ)); - + // Precalculate a "height" array: NOISE_DATATYPE Height[DIM_X * DIM_Z]; // Output for the cubic noise heightmap ("source") m_Cubic.Generate2D(Height, DIM_X, DIM_Z, StartX / 25, EndX / 25, StartZ / 25, EndZ / 25); - for (int i = 0; i < ARRAYCOUNT(Height); i++) + for (unsigned int i = 0; i < ARRAYCOUNT(Height); i++) { Height[i] = abs(Height[i]) * m_HeightAmplification + 1; } - + // Modify the noise by height data: for (int y = 0; y < DIM_Y; y++) { @@ -257,13 +257,13 @@ void cNoise3DGenerator::GenerateNoiseArray(int a_ChunkX, int a_ChunkZ, NOISE_DAT } // DEBUG: Debug3DNoise(NoiseO, DIM_X, DIM_Y, DIM_Z, Printf("Chunk_%d_%d_hei", a_ChunkX, a_ChunkZ)); - + // Upscale the Perlin noise into full-blown chunk dimensions: LinearUpscale3DArray( NoiseO, DIM_X, DIM_Y, DIM_Z, a_OutNoise, UPSCALE_X, UPSCALE_Y, UPSCALE_Z ); - + // DEBUG: Debug3DNoise(a_OutNoise, 17, 257, 17, Printf("Chunk_%d_%d_lerp", a_ChunkX, a_ChunkZ)); } @@ -383,15 +383,11 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) } m_LastChunkX = a_ChunkX; m_LastChunkZ = a_ChunkZ; - + // Upscaling parameters: const int UPSCALE_X = 8; const int UPSCALE_Y = 4; const int UPSCALE_Z = 8; - - const int DIM_X = 1 + cChunkDef::Width / UPSCALE_X; - const int DIM_Y = 1 + cChunkDef::Height / UPSCALE_Y; - const int DIM_Z = 1 + cChunkDef::Width / UPSCALE_Z; // Precalculate a "height" array: NOISE_DATATYPE Height[17 * 17]; // x + 17 * z @@ -405,8 +401,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) Height[x + 17 * z] = val * val * val; } } - - int idx = 0; + for (int y = 0; y < 257; y += UPSCALE_Y) { NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)y) / m_FrequencyY; @@ -419,7 +414,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) for (int x = 0; x < 17; x += UPSCALE_X) { NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width + x)) / m_FrequencyX; - CurFloor[x + 17 * z] = + CurFloor[x + 17 * z] = m_Noise1.CubicNoise3D(NoiseX, NoiseY, NoiseZ) * (NOISE_DATATYPE)0.5 + m_Noise2.CubicNoise3D(NoiseX / 2, NoiseY / 2, NoiseZ / 2) + m_Noise3.CubicNoise3D(NoiseX / 4, NoiseY / 4, NoiseZ / 4) * 2 + @@ -429,7 +424,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) // Linear-interpolate this XZ floor: LinearUpscale2DArrayInPlace(CurFloor, 17, 17, UPSCALE_X, UPSCALE_Z); } - + // Finish the 3D linear interpolation by interpolating between each XZ-floors on the Y axis for (int y = 1; y < cChunkDef::Height; y++) { @@ -455,7 +450,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) idx += 1; // Skipping one X column } } - + // The noise array is now fully interpolated /* // DEBUG: Output two images of the array, sliced by XY and XZ: @@ -504,7 +499,7 @@ void cNoise3DComposable::GenerateNoiseArrayIfNeeded(int a_ChunkX, int a_ChunkZ) void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) { GenerateNoiseArrayIfNeeded(a_ChunkX, a_ChunkZ); - + for (int z = 0; z < cChunkDef::Width; z++) { for (int x = 0; x < cChunkDef::Width; x++) @@ -529,9 +524,9 @@ void cNoise3DComposable::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::Hei void cNoise3DComposable::ComposeTerrain(cChunkDesc & a_ChunkDesc) { GenerateNoiseArrayIfNeeded(a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ()); - + a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0); - + // Make basic terrain composition: for (int z = 0; z < cChunkDef::Width; z++) { diff --git a/src/Items/ItemComparator.h b/src/Items/ItemComparator.h index 53dbd020d..3fbb7603d 100644 --- a/src/Items/ItemComparator.h +++ b/src/Items/ItemComparator.h @@ -2,7 +2,7 @@ #pragma once #include "ItemHandler.h" -#include "../Simulator/RedstoneSimulator.h" +#include "../Blocks/BlockRedstoneRepeater.h" @@ -30,7 +30,7 @@ public: ) override { a_BlockType = E_BLOCK_INACTIVE_COMPARATOR; - a_BlockMeta = cRedstoneSimulator::RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation()); return true; } } ; diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 13f5293b9..92ba94999 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -90,6 +90,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType); case E_ITEM_BED: return new cItemBedHandler(a_ItemType); case E_ITEM_BOAT: return new cItemBoatHandler(a_ItemType); + case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler(); 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); @@ -97,6 +98,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int 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_FIREWORK_ROCKET: return new cItemFireworkHandler(); 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); diff --git a/src/Items/ItemRedstoneRepeater.h b/src/Items/ItemRedstoneRepeater.h index 459070579..f69f24eb8 100644 --- a/src/Items/ItemRedstoneRepeater.h +++ b/src/Items/ItemRedstoneRepeater.h @@ -2,7 +2,7 @@ #pragma once #include "ItemHandler.h" -#include "../Simulator/RedstoneSimulator.h" +#include "../Blocks/BlockRedstoneRepeater.h" @@ -30,7 +30,7 @@ public: ) override { a_BlockType = E_BLOCK_REDSTONE_REPEATER_OFF; - a_BlockMeta = cRedstoneSimulator::RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation()); return true; } } ; diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h index 85579daf2..fc24e775a 100644 --- a/src/Items/ItemThrowable.h +++ b/src/Items/ItemThrowable.h @@ -94,3 +94,47 @@ public: + +class cItemBottleOEnchantingHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; +public: + cItemBottleOEnchantingHandler(void) : + super(E_ITEM_BOTTLE_O_ENCHANTING, cProjectileEntity::pkExpBottle, 10) + { + } +}; + + + + + +class cItemFireworkHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; +public: + cItemFireworkHandler(void) : + super(E_ITEM_FIREWORK_ROCKET, cProjectileEntity::pkFirework, 0) + { + } + + 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 + { + if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) + { + return false; + } + + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + } + + a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, 0); + + return true; + } + +};
\ No newline at end of file diff --git a/src/LinearUpscale.h b/src/LinearUpscale.h index b7ac84c6a..b337b3219 100644 --- a/src/LinearUpscale.h +++ b/src/LinearUpscale.h @@ -31,7 +31,7 @@ Linearly interpolates values in the array between the equidistant anchor points Works in-place (input is already present at the correct output coords) */ template<typename TYPE> void LinearUpscale2DArrayInPlace( - TYPE * a_Array, + TYPE * a_Array, int a_SizeX, int a_SizeY, // Dimensions of the array int a_AnchorStepX, int a_AnchorStepY // Distances between the anchor points in each direction ) @@ -53,7 +53,7 @@ template<typename TYPE> void LinearUpscale2DArrayInPlace( Idx += a_AnchorStepX; } // for x } // for y - + // Now interpolate in rows, each row has values in the anchor columns int LastXCell = a_SizeX - a_AnchorStepX; for (int y = 0; y < a_SizeY; y++) @@ -92,7 +92,7 @@ template<typename TYPE> void LinearUpscale2DArray( // Feel free to enlarge them if needed, but keep in mind that they're on the stack const int MAX_UPSCALE_X = 128; const int MAX_UPSCALE_Y = 128; - + ASSERT(a_Src != NULL); ASSERT(a_Dst != NULL); ASSERT(a_SrcSizeX > 0); @@ -101,7 +101,7 @@ template<typename TYPE> void LinearUpscale2DArray( ASSERT(a_UpscaleY > 0); ASSERT(a_UpscaleX <= MAX_UPSCALE_X); ASSERT(a_UpscaleY <= MAX_UPSCALE_Y); - + // Pre-calculate the upscaling ratios: TYPE RatioX[MAX_UPSCALE_X]; TYPE RatioY[MAX_UPSCALE_Y]; @@ -113,7 +113,7 @@ template<typename TYPE> void LinearUpscale2DArray( { RatioY[y] = (TYPE)y / a_UpscaleY; } - + // Interpolate each XY cell: int DstSizeX = (a_SrcSizeX - 1) * a_UpscaleX + 1; int DstSizeY = (a_SrcSizeY - 1) * a_UpscaleY + 1; @@ -163,7 +163,7 @@ template<typename TYPE> void LinearUpscale3DArray( const int MAX_UPSCALE_X = 128; const int MAX_UPSCALE_Y = 128; const int MAX_UPSCALE_Z = 128; - + ASSERT(a_Src != NULL); ASSERT(a_Dst != NULL); ASSERT(a_SrcSizeX > 0); @@ -175,11 +175,11 @@ template<typename TYPE> void LinearUpscale3DArray( ASSERT(a_UpscaleX <= MAX_UPSCALE_X); ASSERT(a_UpscaleY <= MAX_UPSCALE_Y); ASSERT(a_UpscaleZ <= MAX_UPSCALE_Z); - + // Pre-calculate the upscaling ratios: TYPE RatioX[MAX_UPSCALE_X]; TYPE RatioY[MAX_UPSCALE_Y]; - TYPE RatioZ[MAX_UPSCALE_Y]; + TYPE RatioZ[MAX_UPSCALE_Z]; for (int x = 0; x <= a_UpscaleX; x++) { RatioX[x] = (TYPE)x / a_UpscaleX; @@ -192,7 +192,7 @@ template<typename TYPE> void LinearUpscale3DArray( { RatioZ[z] = (TYPE)z / a_UpscaleZ; } - + // Interpolate each XYZ cell: int DstSizeX = (a_SrcSizeX - 1) * a_UpscaleX + 1; int DstSizeY = (a_SrcSizeY - 1) * a_UpscaleY + 1; diff --git a/src/Log.cpp b/src/Log.cpp index fc19595db..a0de4531b 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -124,7 +124,7 @@ void cLog::Log(const char * a_Format, va_list argList) #endif if (m_File) { - fprintf(m_File, "%s\n", Line.c_str(), m_File); + fprintf(m_File, "%s\n", Line.c_str()); fflush(m_File); } diff --git a/src/LuaState.cpp b/src/LuaState.cpp index 8d2fa8eca..644f4972c 100644 --- a/src/LuaState.cpp +++ b/src/LuaState.cpp @@ -739,6 +739,39 @@ bool cLuaState::CallFunction(int a_NumResults) +bool cLuaState::CheckParamUserTable(int a_StartParam, const char * a_UserTable, int a_EndParam) +{ + ASSERT(IsValid()); + + if (a_EndParam < 0) + { + a_EndParam = a_StartParam; + } + + tolua_Error tolua_err; + for (int i = a_StartParam; i <= a_EndParam; i++) + { + if (tolua_isusertable(m_LuaState, i, a_UserTable, 0, &tolua_err)) + { + continue; + } + // Not the correct parameter + lua_Debug entry; + VERIFY(lua_getstack(m_LuaState, 0, &entry)); + VERIFY(lua_getinfo (m_LuaState, "n", &entry)); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); + return false; + } // for i - Param + + // All params checked ok + return true; +} + + + + + bool cLuaState::CheckParamUserType(int a_StartParam, const char * a_UserType, int a_EndParam) { ASSERT(IsValid()); @@ -838,6 +871,39 @@ bool cLuaState::CheckParamNumber(int a_StartParam, int a_EndParam) +bool cLuaState::CheckParamString(int a_StartParam, int a_EndParam) +{ + ASSERT(IsValid()); + + if (a_EndParam < 0) + { + a_EndParam = a_StartParam; + } + + tolua_Error tolua_err; + for (int i = a_StartParam; i <= a_EndParam; i++) + { + if (tolua_isstring(m_LuaState, i, 0, &tolua_err)) + { + continue; + } + // Not the correct parameter + lua_Debug entry; + VERIFY(lua_getstack(m_LuaState, 0, &entry)); + VERIFY(lua_getinfo (m_LuaState, "n", &entry)); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); + return false; + } // for i - Param + + // All params checked ok + return true; +} + + + + + bool cLuaState::CheckParamEnd(int a_Param) { tolua_Error tolua_err; diff --git a/src/LuaState.h b/src/LuaState.h index caba2484d..aa71ee226 100644 --- a/src/LuaState.h +++ b/src/LuaState.h @@ -764,15 +764,21 @@ public: */ bool CallFunction(int a_NumReturnValues); - /// Returns true if the specified parameters on the stack are of the specified usertype; also logs warning if not + /// Returns true if the specified parameters on the stack are of the specified usertable type; also logs warning if not. Used for static functions + bool CheckParamUserTable(int a_StartParam, const char * a_UserTable, int a_EndParam = -1); + + /// Returns true if the specified parameters on the stack are of the specified usertype; also logs warning if not. Used for regular functions bool CheckParamUserType(int a_StartParam, const char * a_UserType, int a_EndParam = -1); - /// Returns true if the specified parameters on the stack are a table; also logs warning if not + /// Returns true if the specified parameters on the stack are tables; also logs warning if not bool CheckParamTable(int a_StartParam, int a_EndParam = -1); - /// Returns true if the specified parameters on the stack are a number; also logs warning if not + /// Returns true if the specified parameters on the stack are numbers; also logs warning if not bool CheckParamNumber(int a_StartParam, int a_EndParam = -1); + /// Returns true if the specified parameters on the stack are strings; also logs warning if not + bool CheckParamString(int a_StartParam, int a_EndParam = -1); + /// Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters) bool CheckParamEnd(int a_Param); diff --git a/src/ManualBindings.cpp b/src/ManualBindings.cpp index f98e25880..02b3347f6 100644 --- a/src/ManualBindings.cpp +++ b/src/ManualBindings.cpp @@ -171,6 +171,29 @@ cPluginLua * GetLuaPlugin(lua_State * L) +static int tolua_cFile_GetFolderContents(lua_State * tolua_S) +{ + cLuaState LuaState(tolua_S); + if ( + !LuaState.CheckParamUserTable(1, "cFile") || + !LuaState.CheckParamString (2) || + !LuaState.CheckParamEnd (3) + ) + { + return 0; + } + + AString Folder = (AString)tolua_tocppstring(LuaState, 2, 0); + + AStringVector Contents = cFile::GetFolderContents(Folder); + LuaState.Push(Contents); + return 1; +} + + + + + template< class Ty1, class Ty2, @@ -2063,6 +2086,46 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S) +static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if ( + !L.CheckParamUserTable(1, "cRoot") || + !L.CheckParamUserType (2, "const cItem") || + !L.CheckParamEnd (3) + ) + { + return 0; + } + + // Check the input param: + cItem * Input = (cItem *)tolua_tousertype(L, 2, NULL); + if (Input == NULL) + { + LOGWARNING("cRoot:GetFurnaceRecipe: the Input parameter is nil or missing."); + return 0; + } + + // Get the recipe for the input + cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe(); + const cFurnaceRecipe::Recipe * Recipe = FR->GetRecipeFrom(*Input); + if (Recipe == NULL) + { + // There is no such furnace recipe for this input, return no value + return 0; + } + + // Push the output, number of ticks and input as the three return values: + tolua_pushusertype(L, Recipe->Out, "const cItem"); + tolua_pushnumber (L, (lua_Number)(Recipe->CookTime)); + tolua_pushusertype(L, Recipe->In, "const cItem"); + return 3; +} + + + + + static int tolua_cHopperEntity_GetOutputBlockPos(lua_State * tolua_S) { // function cHopperEntity::GetOutputBlockPos() @@ -2113,6 +2176,10 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN); tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR); + tolua_beginmodule(tolua_S, "cFile"); + tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cHopperEntity"); tolua_function(tolua_S, "GetOutputBlockPos", tolua_cHopperEntity_GetOutputBlockPos); tolua_endmodule(tolua_S); @@ -2125,29 +2192,32 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith <cRoot, cPlayer, &cRoot::FindAndDoWithPlayer>); tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach<cRoot, cPlayer, &cRoot::ForEachPlayer>); tolua_function(tolua_S, "ForEachWorld", tolua_ForEach<cRoot, cWorld, &cRoot::ForEachWorld>); + tolua_function(tolua_S, "GetFurnaceRecipe", tolua_cRoot_GetFurnaceRecipe); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWorld"); - tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); - tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>); - tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>); - tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); - tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); - tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); - tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); - tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); - tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); - tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); - tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>); - tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>); - tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>); - tolua_function(tolua_S, "GetBlockInfo", tolua_cWorld_GetBlockInfo); - tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cWorld_GetBlockTypeMeta); - tolua_function(tolua_S, "GetSignLines", tolua_cWorld_GetSignLines); - tolua_function(tolua_S, "QueueTask", tolua_cWorld_QueueTask); - tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines); - tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight); - tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines); + tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>); + tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); + tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>); + tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>); + tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); + tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); + tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); + tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); + tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); + tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>); + tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); + tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); + tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>); + tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>); + tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>); + tolua_function(tolua_S, "GetBlockInfo", tolua_cWorld_GetBlockInfo); + tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cWorld_GetBlockTypeMeta); + tolua_function(tolua_S, "GetSignLines", tolua_cWorld_GetSignLines); + tolua_function(tolua_S, "QueueTask", tolua_cWorld_QueueTask); + tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines); + tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight); + tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPlugin"); diff --git a/src/Mobs/Giant.cpp b/src/Mobs/Giant.cpp index f41977535..bbcad46f0 100644 --- a/src/Mobs/Giant.cpp +++ b/src/Mobs/Giant.cpp @@ -8,9 +8,9 @@ cGiant::cGiant(void) : - // TODO: The size is only a guesstimate, measure in vanilla and fix the size values here - super("Giant", mtGiant, "mob.zombie.hurt", "mob.zombie.death", 2.0, 13.5) + super("Giant", mtGiant, "mob.zombie.hurt", "mob.zombie.death", 3.6, 10.8) { + } diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index d2eea498a..274aa52da 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -360,6 +360,82 @@ bool cFile::CreateFolder(const AString & a_FolderPath) +AStringVector cFile::GetFolderContents(const AString & a_Folder) +{ + AStringVector AllFiles; + + #ifdef _WIN32 + + // If the folder name doesn't contain the terminating slash / backslash, add it: + AString FileFilter = a_Folder; + if ( + !FileFilter.empty() && + (FileFilter[FileFilter.length() - 1] != '\\') && + (FileFilter[FileFilter.length() - 1] != '/') + ) + { + FileFilter.push_back('\\'); + } + + // Find all files / folders: + FileFilter.append("*.*"); + HANDLE hFind; + WIN32_FIND_DATA FindFileData; + if ((hFind = FindFirstFile(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE) + { + do + { + AllFiles.push_back(FindFileData.cFileName); + } while (FindNextFile(hFind, &FindFileData)); + FindClose(hFind); + } + + #else // _WIN32 + + DIR * dp; + struct dirent *dirp; + if (*a_Directory == 0) + { + a_Directory = "."; + } + if ((dp = opendir(a_Directory)) == NULL) + { + LOGERROR("Error (%i) opening directory \"%s\"\n", errno, a_Directory ); + } + else + { + while ((dirp = readdir(dp)) != NULL) + { + AllFiles.push_back(dirp->d_name); + } + closedir(dp); + } + + #endif // else _WIN32 + + return AllFiles; +} + + + + + +AString cFile::ReadWholeFile(const AString & a_FileName) +{ + cFile f; + if (!f.Open(a_FileName, fmRead)) + { + return ""; + } + AString Contents; + f.ReadRestOfFile(Contents); + return Contents; +} + + + + + int cFile::Printf(const char * a_Fmt, ...) { AString buf; diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h index cfb3a2019..01663a229 100644 --- a/src/OSSupport/File.h +++ b/src/OSSupport/File.h @@ -121,8 +121,14 @@ public: /// Creates a new folder with the specified name. Returns true if successful. Path may be relative or absolute static bool CreateFolder(const AString & a_FolderPath); + /// Returns the entire contents of the specified file as a string. Returns empty string on error. + static AString ReadWholeFile(const AString & a_FileName); + // tolua_end + /// Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there). + static AStringVector GetFolderContents(const AString & a_Folder); // Exported in ManualBindings.cpp + int Printf(const char * a_Fmt, ...); private: diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp index 48b5d704d..c461d38a4 100644 --- a/src/OSSupport/Socket.cpp +++ b/src/OSSupport/Socket.cpp @@ -169,7 +169,7 @@ bool cSocket::SetReuseAddress(void) -int cSocket::WSAStartup() +int cSocket::WSAStartup(void) { #ifdef _WIN32 WSADATA wsaData; @@ -336,23 +336,23 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por { // First try IP Address string to hostent conversion, because it's faster unsigned long addr = inet_addr(a_HostNameOrAddr.c_str()); - hostent * hp = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET); - if (hp == NULL) + if (addr == INADDR_NONE) { // It is not an IP Address string, but rather a regular hostname, resolve: - hp = gethostbyname(a_HostNameOrAddr.c_str()); + hostent * hp = gethostbyname(a_HostNameOrAddr.c_str()); if (hp == NULL) { - LOGWARN("cTCPLink: Could not resolve hostname \"%s\"", a_HostNameOrAddr.c_str()); + LOGWARNING("%s: Could not resolve hostname \"%s\"", __FUNCTION__, a_HostNameOrAddr.c_str()); CloseSocket(); return false; } + addr = *((unsigned long*)hp->h_addr); } sockaddr_in server; - server.sin_addr.s_addr = *((unsigned long*)hp->h_addr); + server.sin_addr.s_addr = addr; server.sin_family = AF_INET; - server.sin_port = htons( (unsigned short)a_Port ); + server.sin_port = htons((unsigned short)a_Port); return (connect(m_Socket, (sockaddr *)&server, sizeof(server)) == 0); } diff --git a/src/OSSupport/Socket.h b/src/OSSupport/Socket.h index 34f09cc74..81bfd28fc 100644 --- a/src/OSSupport/Socket.h +++ b/src/OSSupport/Socket.h @@ -38,6 +38,7 @@ public: /// Sets the address-reuse socket flag; returns true on success bool SetReuseAddress(void); + /// Initializes the network stack. Returns 0 on success, or another number as an error code. static int WSAStartup(void); static AString GetErrorString(int a_ErrNo); diff --git a/src/Piston.cpp b/src/Piston.cpp index 136100922..048cc355d 100644 --- a/src/Piston.cpp +++ b/src/Piston.cpp @@ -14,14 +14,8 @@ -extern bool g_BlockPistonBreakable[]; - - - - - /// Number of ticks that the piston extending / retracting waits before setting the block -const int PISTON_TICK_DELAY = 20; +const int PISTON_TICK_DELAY = 6; @@ -77,9 +71,6 @@ void cPiston::ExtendPiston(int pistx, int pisty, int pistz) return; } - m_World->BroadcastBlockAction(pistx, pisty, pistz, 0, pistonMeta, pistonBlock); - m_World->BroadcastSoundEffect("tile.piston.out", pistx * 8, pisty * 8, pistz * 8, 0.5f, 0.7f); - int dist = FirstPassthroughBlock(pistx, pisty, pistz, pistonMeta); if (dist < 0) { @@ -87,6 +78,9 @@ void cPiston::ExtendPiston(int pistx, int pisty, int pistz) return; } + m_World->BroadcastBlockAction(pistx, pisty, pistz, 0, pistonMeta, pistonBlock); + m_World->BroadcastSoundEffect("tile.piston.out", pistx * 8, pisty * 8, pistz * 8, 0.5f, 0.7f); + // Drop the breakable block in the line, if appropriate: AddDir(pistx, pisty, pistz, pistonMeta, dist + 1); // "pist" now at the breakable / empty block BLOCKTYPE currBlock; @@ -120,7 +114,7 @@ void cPiston::ExtendPiston(int pistx, int pisty, int pistz) AddDir(pistx, pisty, pistz, pistonMeta, -1); // "pist" now at piston body, "ext" at future extension - m_World->QueueSetBlock( pistx, pisty, pistz, pistonBlock, pistonMeta | 0x8, PISTON_TICK_DELAY); + m_World->SetBlock( pistx, pisty, pistz, pistonBlock, pistonMeta | 0x8); m_World->QueueSetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0), PISTON_TICK_DELAY); } @@ -141,7 +135,7 @@ void cPiston::RetractPiston(int pistx, int pisty, int pistz) m_World->BroadcastBlockAction(pistx, pisty, pistz, 1, pistonMeta & ~(8), pistonBlock); m_World->BroadcastSoundEffect("tile.piston.in", pistx * 8, pisty * 8, pistz * 8, 0.5f, 0.7f); - m_World->QueueSetBlock(pistx, pisty, pistz, pistonBlock, pistonMeta & ~(8), PISTON_TICK_DELAY); + m_World->SetBlock(pistx, pisty, pistz, pistonBlock, pistonMeta & ~(8)); // Check the extension: AddDir(pistx, pisty, pistz, pistonMeta, 1); @@ -199,15 +193,6 @@ bool cPiston::IsSticky(BLOCKTYPE a_BlockType) -bool cPiston::IsStickyExtension(NIBBLETYPE a_ExtMeta) -{ - return ((a_ExtMeta & 0x08) != 0); -} - - - - - bool cPiston::CanPush(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { switch (a_BlockType) diff --git a/src/Piston.h b/src/Piston.h index cc051e454..92ddf6938 100644 --- a/src/Piston.h +++ b/src/Piston.h @@ -63,9 +63,6 @@ public: /// Returns true if the piston (with the specified meta) is extended static bool IsExtended(NIBBLETYPE a_PistonMeta); - - /// Returns true if the extension (with the specified meta) is sticky - static bool IsStickyExtension(NIBBLETYPE a_ExtMeta); /// Returns true if the specified block can be pushed by a piston (and left intact) static bool CanPush(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); diff --git a/src/PluginLua.cpp b/src/PluginLua.cpp index 03aefb098..23d079b05 100644 --- a/src/PluginLua.cpp +++ b/src/PluginLua.cpp @@ -86,11 +86,11 @@ bool cPluginLua::Initialize(void) lua_setglobal(m_LuaState, "g_Plugin"); } - std::string PluginPath = FILE_IO_PREFIX + GetLocalDirectory() + "/"; + std::string PluginPath = FILE_IO_PREFIX + GetLocalFolder() + "/"; // Load all files for this plugin, and execute them - AStringList Files = GetDirectoryContents(PluginPath.c_str()); - for (AStringList::const_iterator itr = Files.begin(); itr != Files.end(); ++itr) + AStringVector Files = cFile::GetFolderContents(PluginPath.c_str()); + for (AStringVector::const_iterator itr = Files.begin(); itr != Files.end(); ++itr) { if (itr->rfind(".lua") == AString::npos) { diff --git a/src/PluginManager.cpp b/src/PluginManager.cpp index c1f695163..e08ebe503 100644 --- a/src/PluginManager.cpp +++ b/src/PluginManager.cpp @@ -72,8 +72,8 @@ void cPluginManager::FindPlugins(void) ++itr; } - AStringList Files = GetDirectoryContents(PluginsPath.c_str()); - for (AStringList::const_iterator itr = Files.begin(); itr != Files.end(); ++itr) + AStringVector Files = cFile::GetFolderContents(PluginsPath.c_str()); + for (AStringVector::const_iterator itr = Files.begin(); itr != Files.end(); ++itr) { if ((*itr == ".") || (*itr == "..") || (!cFile::IsFolder(PluginsPath + *itr))) { @@ -113,9 +113,13 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) FindPlugins(); cServer::BindBuiltInConsoleCommands(); - - unsigned int KeyNum = a_SettingsIni.FindKey("Plugins"); + + // Check if the Plugins section exists. + int KeyNum = a_SettingsIni.FindKey("Plugins"); + + // If it does, how many plugins are there? unsigned int NumPlugins = ((KeyNum != -1) ? (a_SettingsIni.GetNumValues(KeyNum)) : 0); + if (KeyNum == -1) { InsertDefaultPlugins(a_SettingsIni); @@ -202,7 +206,7 @@ void cPluginManager::Tick(float a_Dt) bool cPluginManager::CallHookBlockToPickups( cWorld * a_World, cEntity * a_Digger, - int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, + int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups ) { @@ -247,7 +251,7 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) { return false; } - + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { if ((*itr)->OnChat(a_Player, a_Message)) @@ -255,7 +259,7 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message) return true; } } - + return false; } @@ -1230,27 +1234,27 @@ bool cPluginManager::CallHookWorldTick(cWorld & a_World, float a_Dt) bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command, bool a_ShouldCheckPermissions) { ASSERT(a_Player != NULL); - + AStringVector Split(StringSplit(a_Command, " ")); if (Split.empty()) { return false; } - + CommandMap::iterator cmd = m_Commands.find(Split[0]); if (cmd == m_Commands.end()) { // Command not found return false; } - + // Ask plugins first if a command is okay to execute the command: if (CallHookExecuteCommand(a_Player, Split)) { LOGINFO("Player \"%s\" tried executing command \"%s\" that was stopped by the HOOK_EXECUTE_COMMAND hook", a_Player->GetName().c_str(), Split[0].c_str()); return false; } - + if ( a_ShouldCheckPermissions && !cmd->second.m_Permission.empty() && @@ -1262,8 +1266,8 @@ bool cPluginManager::HandleCommand(cPlayer * a_Player, const AString & a_Command } ASSERT(cmd->second.m_Plugin != NULL); - - return cmd->second.m_Plugin->HandleCommand(Split, a_Player); + + return cmd->second.m_Plugin->HandleCommand(Split, a_Player); } @@ -1320,7 +1324,7 @@ bool cPluginManager::DisablePlugin(const AString & a_PluginName) { return false; } - + if (itr->first.compare(a_PluginName) == 0) // _X 2013_02_01: wtf? Isn't this supposed to be what find() does? { m_DisablePluginList.push_back(itr->second); @@ -1365,7 +1369,7 @@ void cPluginManager::RemovePlugin(cPlugin * a_Plugin) break; } } - + RemovePluginCommands(a_Plugin); RemovePluginConsoleCommands(a_Plugin); RemoveHooks(a_Plugin); @@ -1386,7 +1390,7 @@ void cPluginManager::RemovePluginCommands(cPlugin * a_Plugin) { a_Plugin->ClearCommands(); } - + for (CommandMap::iterator itr = m_Commands.begin(); itr != m_Commands.end();) { if (itr->second.m_Plugin == a_Plugin) @@ -1414,7 +1418,7 @@ bool cPluginManager::BindCommand(const AString & a_Command, cPlugin * a_Plugin, LOGWARNING("Command \"%s\" is already bound to plugin \"%s\".", a_Command.c_str(), cmd->second.m_Plugin->GetName().c_str()); return false; } - + m_Commands[a_Command].m_Plugin = a_Plugin; m_Commands[a_Command].m_Permission = a_Permission; m_Commands[a_Command].m_HelpString = a_HelpString; @@ -1484,7 +1488,7 @@ void cPluginManager::RemovePluginConsoleCommands(cPlugin * a_Plugin) { a_Plugin->ClearConsoleCommands(); } - + for (CommandMap::iterator itr = m_ConsoleCommands.begin(); itr != m_ConsoleCommands.end();) { if (itr->second.m_Plugin == a_Plugin) @@ -1519,7 +1523,7 @@ bool cPluginManager::BindConsoleCommand(const AString & a_Command, cPlugin * a_P } return false; } - + m_ConsoleCommands[a_Command].m_Plugin = a_Plugin; m_ConsoleCommands[a_Command].m_Permission = ""; m_ConsoleCommands[a_Command].m_HelpString = a_HelpString; @@ -1561,20 +1565,20 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cComma { return false; } - + CommandMap::iterator cmd = m_ConsoleCommands.find(a_Split[0]); if (cmd == m_ConsoleCommands.end()) { // Command not found return false; } - + if (cmd->second.m_Plugin == NULL) { // This is a built-in command return false; } - + // Ask plugins first if a command is okay to execute the console command: if (CallHookExecuteCommand(NULL, a_Split)) { @@ -1582,7 +1586,7 @@ bool cPluginManager::ExecuteConsoleCommand(const AStringVector & a_Split, cComma return false; } - return cmd->second.m_Plugin->HandleConsoleCommand(a_Split, a_Output); + return cmd->second.m_Plugin->HandleConsoleCommand(a_Split, a_Output); } @@ -1656,7 +1660,7 @@ void cPluginManager::AddHook(cPlugin * a_Plugin, int a_Hook) unsigned int cPluginManager::GetNumPlugins() const { - return m_Plugins.size(); + return m_Plugins.size(); } diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index 5023ea227..542060ece 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -22,9 +22,9 @@ class cWindow; class cInventory; class cPawn; class cPickup; +class cWorld; class cMonster; class cChunkDataSerializer; -class cWorld; class cFallingBlock; @@ -85,6 +85,7 @@ public: virtual void SendPlayerPosition (void) = 0; virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; virtual void SendRespawn (void) = 0; + virtual void SendExperience (void) = 0; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) = 0; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) = 0; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index 9f2770815..54be65b12 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -72,6 +72,7 @@ enum PACKET_ENT_STATUS = 0x26, PACKET_ATTACH_ENTITY = 0x27, PACKET_METADATA = 0x28, + PACKET_EXPERIENCE = 0x2b, PACKET_PRE_CHUNK = 0x32, PACKET_MAP_CHUNK = 0x33, PACKET_MULTI_BLOCK = 0x34, @@ -690,6 +691,20 @@ void cProtocol125::SendRespawn(void) +void cProtocol125::SendExperience(void) +{ + cCSLock Lock(m_CSPacket); + WriteByte (PACKET_EXPERIENCE); + WriteFloat (m_Client->GetPlayer()->GetXpPercentage()); + WriteShort (m_Client->GetPlayer()->GetXpLevel()); + WriteShort (m_Client->GetPlayer()->GetCurrentXp()); + Flush(); +} + + + + + void cProtocol125::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { // Not needed in this protocol version diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index db913bb57..c5f44c818 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -62,6 +62,7 @@ public: virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; + virtual void SendExperience (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 628b8e071..ae1df7395 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -597,6 +597,18 @@ void cProtocol172::SendRespawn(void) +void cProtocol172::SendExperience (void) +{ + cPacketizer Pkt(*this, 0x1F); //Experience Packet + Pkt.WriteFloat(m_Client->GetPlayer()->GetXpPercentage()); + Pkt.WriteShort(m_Client->GetPlayer()->GetXpLevel()); + Pkt.WriteShort(m_Client->GetPlayer()->GetCurrentXp()); +} + + + + + void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8 { cPacketizer Pkt(*this, 0x29); // Sound Effect packet diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 844069403..e3f2ad922 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -72,6 +72,7 @@ public: virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 + virtual void SendExperience (void) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; virtual void SendSpawnMob (const cMonster & a_Mob) override; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 9234785b5..64bd83075 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -466,6 +466,16 @@ void cProtocolRecognizer::SendRespawn(void) +void cProtocolRecognizer::SendExperience(void) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendExperience(); +} + + + + + void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { ASSERT(m_Protocol != NULL); diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index c085e2cd8..03f48fb35 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -97,6 +97,7 @@ public: virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; virtual void SendRespawn (void) override; + virtual void SendExperience (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override; virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override; diff --git a/src/RCONServer.cpp b/src/RCONServer.cpp index 93f2ccdd3..3f86a7ca2 100644 --- a/src/RCONServer.cpp +++ b/src/RCONServer.cpp @@ -241,6 +241,7 @@ bool cRCONServer::cConnection::ProcessPacket(int a_RequestID, int a_PacketType, if (strncmp(a_Payload, m_RCONServer.m_Password.c_str(), a_PayloadLength) != 0) { LOGINFO("RCON: Invalid password from client %s, dropping connection.", m_IPAddress.c_str()); + SendResponse(-1, RCON_PACKET_RESPONSE, 0, NULL); return false; } m_IsAuthenticated = true; diff --git a/src/Root.cpp b/src/Root.cpp index be5a0553c..5bb04abfb 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -742,3 +742,13 @@ void cRoot::LogChunkStats(cCommandOutputCallback & a_Output) + +int cRoot::GetFurnaceFuelBurnTime(const cItem & a_Fuel) +{ + cFurnaceRecipe * FR = Get()->GetFurnaceRecipe(); + return FR->GetBurnTime(a_Fuel); +} + + + + diff --git a/src/Root.h b/src/Root.h index 175084c53..4e38dd17f 100644 --- a/src/Root.h +++ b/src/Root.h @@ -56,7 +56,11 @@ public: cGroupManager * GetGroupManager (void) { return m_GroupManager; } // tolua_export cCraftingRecipes * GetCraftingRecipes(void) { return m_CraftingRecipes; } // tolua_export - cFurnaceRecipe * GetFurnaceRecipe (void) { return m_FurnaceRecipe; } // tolua_export + cFurnaceRecipe * GetFurnaceRecipe (void) { return m_FurnaceRecipe; } // Exported in ManualBindings.cpp with quite a different signature + + /// Returns the number of ticks for how long the item would fuel a furnace. Returns zero if not a fuel + static int GetFurnaceFuelBurnTime(const cItem & a_Fuel); // tolua_export + cWebAdmin * GetWebAdmin (void) { return m_WebAdmin; } // tolua_export cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export cAuthenticator & GetAuthenticator (void) { return m_Authenticator; } diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index 8526a888e..906961490 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -3,12 +3,10 @@ #include "RedstoneSimulator.h" #include "../BlockEntities/DropSpenserEntity.h" +#include "../Entities/TNTEntity.h" #include "../Blocks/BlockTorch.h" +#include "../Blocks/BlockDoor.h" #include "../Piston.h" -#include "../World.h" -#include "../BlockID.h" -#include "../Chunk.h" -#include "../Entities/TNTEntity.h" @@ -31,1104 +29,1024 @@ cRedstoneSimulator::~cRedstoneSimulator() -void cRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) +void cRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) { - if (a_Chunk == NULL) + if ((a_Chunk == NULL) || !a_Chunk->IsValid()) { return; } - int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; - int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; - - // Check if any close neighbor is redstone-related: - int MinY = (a_BlockY > 0) ? -1 : 0; - int MaxY = (a_BlockY < cChunkDef::Height - 1) ? 1 : 0; - for (int y = MinY; y <= MaxY; y++) for (int x = -1; x < 2; x++) for (int z = -1; z < 2; z++) + else if ((a_BlockY < 0) || (a_BlockY > cChunkDef::Height)) { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if (!a_Chunk->UnboundedRelGetBlock(RelX + x, a_BlockY + y, RelZ + z, BlockType, BlockMeta)) - { - continue; - } - switch (BlockType) - { - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - case E_BLOCK_REDSTONE_LAMP_OFF: - case E_BLOCK_REDSTONE_LAMP_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_REDSTONE_WIRE: - case E_BLOCK_LEVER: - case E_BLOCK_STONE_BUTTON: - case E_BLOCK_WOODEN_BUTTON: - case E_BLOCK_TRIPWIRE_HOOK: - { - m_Blocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); - return; - } - } // switch (BlockType) - } // for y, x, z - neighbors -} - - - + return; + } + int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; -void cRedstoneSimulator::Simulate(float a_Dt) -{ - // Toggle torches on/off - while (!m_RefreshTorchesAround.empty()) + if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_BlockY, RelZ))) { - Vector3i pos = m_RefreshTorchesAround.front(); - m_RefreshTorchesAround.pop_front(); - - RefreshTorchesAround(pos); + return; } - // Set repeaters to correct values, and decrement ticks - for (RepeaterList::iterator itr = m_SetRepeaters.begin(); itr != m_SetRepeaters.end();) + // Check for duplicates: + cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData(); + for (cRedstoneSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr) { - if (--itr->Ticks > 0) - { - // Not yet, move to next item in the list - ++itr; - continue; - } - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(itr->Position.x, itr->Position.y, itr->Position.z, BlockType, BlockMeta); - if (itr->bPowerOn && (BlockType == E_BLOCK_REDSTONE_REPEATER_OFF)) - { - m_World.FastSetBlock(itr->Position.x, itr->Position.y, itr->Position.z, E_BLOCK_REDSTONE_REPEATER_ON, BlockMeta); - m_Blocks.push_back(itr->Position); - } - else if (!itr->bPowerOn && (BlockType == E_BLOCK_REDSTONE_REPEATER_ON)) - { - m_World.FastSetBlock(itr->Position.x, itr->Position.y, itr->Position.z, E_BLOCK_REDSTONE_REPEATER_OFF, BlockMeta); - m_Blocks.push_back(itr->Position); - } - - if (itr->bPowerOffNextTime) - { - itr->bPowerOn = false; - itr->bPowerOffNextTime = false; - itr->Ticks = 10; // TODO: Look up actual ticks from block metadata - ++itr; - } - else + if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) { - itr = m_SetRepeaters.erase(itr); + return; } } - // Handle changed blocks - { - cCSLock Lock(m_CS); - std::swap(m_Blocks, m_BlocksBuffer); - } - for (BlockList::iterator itr = m_BlocksBuffer.begin(); itr != m_BlocksBuffer.end(); ++itr) - { - HandleChange(*itr); - } - m_BlocksBuffer.clear(); + ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ)); } -void cRedstoneSimulator::RefreshTorchesAround(const Vector3i & a_BlockPos) +void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) { - static Vector3i Surroundings [] = { - Vector3i(-1, 0, 0), - Vector3i(1, 0, 0), - Vector3i(0, 0,-1), - Vector3i(0, 0, 1), - Vector3i(0, 1, 0), // Also toggle torch on top - }; - BLOCKTYPE TargetBlockType = E_BLOCK_REDSTONE_TORCH_ON; - BLOCKTYPE TargetRepeaterType = E_BLOCK_REDSTONE_REPEATER_OFF; - if (IsPowered(a_BlockPos, true)) + cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData(); + if (ChunkData.empty()) + { + return; + } + + int BaseX = a_Chunk->GetPosX() * cChunkDef::Width; + int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width; + + for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;) { - TargetBlockType = E_BLOCK_REDSTONE_TORCH_OFF; - TargetRepeaterType = E_BLOCK_REDSTONE_REPEATER_ON; - //Make TNT Explode when it gets powered. - if (m_World.GetBlock(a_BlockPos) == E_BLOCK_TNT) + BLOCKTYPE BlockType = a_Chunk->GetBlock(dataitr->x, dataitr->y, dataitr->z); + if (!IsAllowedBlock(BlockType)) { - m_World.BroadcastSoundEffect("random.fuse", a_BlockPos.x * 8, a_BlockPos.y * 8, a_BlockPos.z * 8, 0.5f, 0.6f); - m_World.SpawnPrimedTNT(a_BlockPos.x + 0.5, a_BlockPos.y + 0.5, a_BlockPos.z + 0.5, 4); // 4 seconds to boom - m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_AIR, 0); + dataitr = ChunkData.erase(dataitr); + continue; } - //Turn a redstone lamp on when it gets powered. - if (m_World.GetBlock(a_BlockPos) == E_BLOCK_REDSTONE_LAMP_OFF) + + // Check to see if PoweredBlocks have invalid items (source is air or an unpowered source) + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end();) { - m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_ON, 0); + sPoweredBlocks & Change = *itr; + BLOCKTYPE SourceBlockType = m_World.GetBlock(Change.a_SourcePos); + + if (SourceBlockType != Change.a_SourceBlock) + { + itr = m_PoweredBlocks.erase(itr); + } + else if ( + // Changeable sources + ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (m_World.GetBlockMeta(Change.a_SourcePos) == 0)) || + ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(m_World.GetBlockMeta(Change.a_SourcePos))) || + ((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (m_World.GetBlockMeta(Change.a_SourcePos) & 0x08) == 0x08) || + (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(m_World.GetBlockMeta(Change.a_SourcePos)))) + ) + { + itr = m_PoweredBlocks.erase(itr); + } + else + { + itr++; + } } - //if (m_World.GetBlock(a_BlockPos) == E_BLOCK_DIRT) - //{ - // m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_STONE, 0); - //} - } - else - { - //Turn a redstone lamp off when it gets powered. - if (m_World.GetBlock(a_BlockPos) == E_BLOCK_REDSTONE_LAMP_ON) + + // Check to see if LinkedPoweredBlocks have invalid items: source, block powered through, or power destination block has changed + for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end();) { - m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_OFF, 0); + sLinkedPoweredBlocks & Change = *itr; + BLOCKTYPE SourceBlockType = m_World.GetBlock(Change.a_SourcePos); + BLOCKTYPE MiddleBlockType = m_World.GetBlock(Change.a_MiddlePos); + + if (SourceBlockType != Change.a_SourceBlock) + { + itr = m_LinkedPoweredBlocks.erase(itr); + } + else if (MiddleBlockType != Change.a_MiddleBlock) + { + itr = m_LinkedPoweredBlocks.erase(itr); + } + else if ( + // Things that can send power through a block but which depends on meta + ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (m_World.GetBlockMeta(Change.a_SourcePos) == 0)) || + ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(m_World.GetBlockMeta(Change.a_SourcePos))) || + (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(m_World.GetBlockMeta(Change.a_SourcePos)))) + ) + { + itr = m_LinkedPoweredBlocks.erase(itr); + } + else + { + itr++; + } } - //if (m_World.GetBlock(a_BlockPos) == E_BLOCK_STONE) - //{ - // m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_DIRT, 0); - //} - } - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) - { - Vector3i TorchPos = a_BlockPos + Surroundings[i]; - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(TorchPos.x, TorchPos.y, TorchPos.z, BlockType, BlockMeta); + // PoweredBlock list was fine, now to the actual handling + int a_X = BaseX + dataitr->x; + int a_Z = BaseZ + dataitr->z; switch (BlockType) { - case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break; + case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break; + case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break; + case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break; + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: { - if (BlockType != TargetBlockType) - { - if (cBlockTorchHandler::IsAttachedTo(TorchPos, BlockMeta, a_BlockPos)) - { - m_World.FastSetBlock(TorchPos.x, TorchPos.y, TorchPos.z, TargetBlockType, BlockMeta); - m_Blocks.push_back(TorchPos); - } - } + HandleRedstoneTorch(a_X, dataitr->y, a_Z, BlockType); + break; + } + case E_BLOCK_STONE_BUTTON: + case E_BLOCK_WOODEN_BUTTON: + { + HandleRedstoneButton(a_X, dataitr->y, a_Z, BlockType); break; } - case E_BLOCK_REDSTONE_REPEATER_ON: case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: { - if ((BlockType != TargetRepeaterType) && IsRepeaterPointingAway(TorchPos, BlockMeta, a_BlockPos)) - { - SetRepeater(TorchPos, 10, (TargetRepeaterType == E_BLOCK_REDSTONE_REPEATER_ON)); - } + HandleRedstoneRepeater(a_X, dataitr->y, a_Z, BlockType); break; } - } // switch (BlockType) - } // for i - Surroundings[] -} - - - - - -void cRedstoneSimulator::HandleChange(const Vector3i & a_BlockPos) -{ - std::deque< Vector3i > SpreadStack; - - static const Vector3i Surroundings[] = { - Vector3i(1, 0, 0), - Vector3i(1, 1, 0), - Vector3i(1,-1, 0), - Vector3i(-1, 0, 0), - Vector3i(-1, 1, 0), - Vector3i(-1,-1, 0), - Vector3i(0, 0, 1), - Vector3i(0, 1, 1), - Vector3i(0,-1, 1), - Vector3i(0, 0,-1), - Vector3i(0, 1,-1), - Vector3i(0,-1,-1), - Vector3i(0,-1, 0), - }; - - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - - // First check whether torch should be on or off - switch (BlockType) - { - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_REDSTONE_TORCH_OFF: - { - static const Vector3i Surroundings [] = { - Vector3i(-1, 0, 0), - Vector3i(1, 0, 0), - Vector3i(0, 0,-1), - Vector3i(0, 0, 1), - Vector3i(0,-1, 0), - }; - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: { - Vector3i pos = a_BlockPos + Surroundings[i]; - BLOCKTYPE OtherBlock = m_World.GetBlock(pos); - if ( - (OtherBlock != E_BLOCK_AIR) && - (OtherBlock != E_BLOCK_REDSTONE_TORCH_ON) && - (OtherBlock != E_BLOCK_REDSTONE_TORCH_OFF) - ) - { - RefreshTorchesAround(pos); - } + HandlePiston(a_X, dataitr->y, a_Z); + break; } - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - break; - } // case "torches" - - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: - { - // Check if repeater is powered by a 'powered block' (not wires/torch) - Vector3i Direction = GetRepeaterDirection(BlockMeta); - Vector3i pos = a_BlockPos - Direction; // NOTE: It's minus Direction - BLOCKTYPE OtherBlock = m_World.GetBlock(pos); - if ( - (OtherBlock != E_BLOCK_AIR) && - (OtherBlock != E_BLOCK_REDSTONE_TORCH_ON) && - (OtherBlock != E_BLOCK_REDSTONE_TORCH_OFF) && - (OtherBlock != E_BLOCK_REDSTONE_WIRE) - ) + case E_BLOCK_REDSTONE_LAMP_OFF: + case E_BLOCK_REDSTONE_LAMP_ON: { - RefreshTorchesAround(pos); + HandleRedstoneLamp(a_X, dataitr->y, a_Z, BlockType); + break; } - else + case E_BLOCK_DISPENSER: + case E_BLOCK_DROPPER: { - SetRepeater(a_BlockPos, 10, IsPowered(a_BlockPos, false)); + HandleDropSpenser(a_X, dataitr->y, a_Z); + break; + } + case E_BLOCK_WOODEN_DOOR: + case E_BLOCK_IRON_DOOR: + { + HandleDoor(a_X, dataitr->y, a_Z); + break; + } + case E_BLOCK_ACTIVATOR_RAIL: + case E_BLOCK_DETECTOR_RAIL: + case E_BLOCK_POWERED_RAIL: + { + HandleRail(a_X, dataitr->y, a_Z, BlockType); + break; } - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - break; } - } // switch (BlockType) - BlockList Sources; - switch (BlockType) + ++dataitr; + } +} + + + + + +void cRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) +{ + static const struct // Define which directions the torch can power { - case E_BLOCK_REDSTONE_TORCH_ON: + int x, y, z; + } gCrossCoords[] = + { + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 0, 1, 0}, + } ; + + if (a_MyState == E_BLOCK_REDSTONE_TORCH_ON) + { + // Check if the block the torch is on is powered + int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ; + AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on + + if (AreCoordsPowered(X, Y, Z)) { - // If torch is still on, use it as a source - Sources.push_back(a_BlockPos); - break; + // There was a match, torch goes off + // FastSetBlock so the server doesn't fail an assert -_- + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); + return; } - - case E_BLOCK_REDSTONE_REPEATER_ON: + + // Torch still on, make all 4(X, Z) + 1(Y) sides powered + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { - // Repeater only spreads charge right in front, and up to one block up: - static const Vector3i Surroundings [] = { - Vector3i(0, 0, 0), - Vector3i(0, 1, 0), - }; - Vector3i Direction = GetRepeaterDirection(BlockMeta); - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + BLOCKTYPE Type = m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z); + if (i < ARRAYCOUNT(gCrossCoords) - 1) // Sides of torch, not top (top is last) { - Vector3i pos = a_BlockPos + Direction + Surroundings[i]; - if (PowerBlock(pos, a_BlockPos, 0xf)) + if ( + ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc. + (!Vector3i(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on + ) { - SpreadStack.push_back(pos); + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); } } - break; - } // case E_BLOCK_REDSTONE_REPEATER_ON - - case E_BLOCK_LEVER: - { - // Adding lever to the source queue - if (cRedstoneSimulator::IsLeverOn(BlockMeta)) + else { - Sources.push_back(a_BlockPos); + // Top side, power whatever is there, including blocks + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); } - break; - } // case E_BLOCK_LEVER - } // switch (BlockType) + } - // Power all blocks legally connected to the sources - if (BlockType != E_BLOCK_REDSTONE_REPEATER_ON) - { - BlockList NewSources = RemoveCurrent(a_BlockPos); - Sources.insert(Sources.end(), NewSources.begin(), NewSources.end()); - while (!Sources.empty()) + if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0x5) // Is torch standing on ground? If not (i.e. on wall), power block beneath { - Vector3i SourcePos = Sources.back(); - Sources.pop_back(); + BLOCKTYPE Type = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(SourcePos.x, SourcePos.y, SourcePos.z, BlockType, BlockMeta); - switch (BlockType) + if ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) // Still can't make a normal block powered though! { - case E_BLOCK_LEVER: // Treating lever as a torch - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: - { - static Vector3i Surroundings [] = { - Vector3i(-1, 0, 0), - Vector3i(1, 0, 0), - Vector3i(0, 0,-1), - Vector3i(0, 0, 1), - }; - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) - { - Vector3i OtherPos = SourcePos + Surroundings[i]; - if (PowerBlock(OtherPos, a_BlockPos, 0xf)) - { - SpreadStack.push_back(OtherPos); // Changed, so add to stack - } - } - break; - } - - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: - { - static Vector3i Surroundings [] = { - Vector3i(0, 0, 0), - Vector3i(0, 1, 0), - }; - Vector3i Direction = GetRepeaterDirection(BlockMeta); - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) - { - Vector3i pos = SourcePos + Direction + Surroundings[i]; - if (PowerBlock(pos, a_BlockPos, 0xf)) - { - SpreadStack.push_back(pos); - } - } - break; - } - } // switch (BlockType) - } // while (Sources[]) - } // if (!repeater_on) - - // Do a floodfill - while (!SpreadStack.empty()) + SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); + } + } + } + else { - Vector3i pos = SpreadStack.back(); - SpreadStack.pop_back(); - NIBBLETYPE Meta = m_World.GetBlockMeta(pos); + // Check if the block the torch is on is powered + int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ; + AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + // See if off state torch can be turned on again + if (AreCoordsPowered(X, Y, Z)) { - Vector3i OtherPos = pos + Surroundings[i]; - if (PowerBlock(OtherPos, pos, Meta - 1)) - { - SpreadStack.push_back(OtherPos); // Changed, so add to stack - } + return; // Something matches, torch still powered } + + // Block torch on not powered, can be turned on again! + // FastSetBlock so the server doesn't fail an assert -_- + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); } + return; +} - // Only after a redstone area has been completely simulated the redstone entities can react - while (!m_RefreshPistons.empty()) - { - Vector3i pos = m_RefreshPistons.back(); - m_RefreshPistons.pop_back(); - BLOCKTYPE BlockType = m_World.GetBlock(pos); - switch (BlockType) - { - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: - { - if (IsPowered(pos)) - { - cPiston Piston(&m_World); - Piston.ExtendPiston(pos.x, pos.y, pos.z); - } - else - { - cPiston Piston(&m_World); - Piston.RetractPiston(pos.x, pos.y, pos.z); - } - break; - } - } // switch (BlockType) - } // while (m_RefreshPistons[]) - while (!m_RefreshDropSpensers.empty()) - { - Vector3i pos = m_RefreshDropSpensers.back(); - m_RefreshDropSpensers.pop_back(); - BLOCKTYPE BlockType = m_World.GetBlock(pos); - if ((BlockType == E_BLOCK_DISPENSER) || (BlockType == E_BLOCK_DROPPER)) - { - class cSetPowerToDropSpenser : - public cDropSpenserCallback - { - bool m_IsPowered; - public: - cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} - - virtual bool Item(cDropSpenserEntity * a_DropSpenser) override - { - a_DropSpenser->SetRedstonePower(m_IsPowered); - return false; - } - } DrSpSP(IsPowered(pos)); - m_World.DoWithDropSpenserAt(pos.x, pos.y, pos.z, DrSpSP); - } + +void cRedstoneSimulator::HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + static const struct // Define which directions the redstone block can power + { + int x, y, z; + } gCrossCoords[] = + { + { 0, 0, 0}, // Oh, anomalous redstone. Only block that powers itself + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 0, 1, 0}, + { 0,-1, 0}, + } ; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + { + // Power everything + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); } + return; } -bool cRedstoneSimulator::PowerBlock(const Vector3i & a_BlockPos, const Vector3i & a_FromBlock, char a_Power) +void cRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ) { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - switch (BlockType) + if (IsLeverOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ))) { - case E_BLOCK_REDSTONE_WIRE: - { - if (BlockMeta < a_Power) - { - m_World.SetBlockMeta(a_BlockPos, a_Power); - return true; - } - break; - } - - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: + static const struct // Define which directions the redstone lever can power (all sides) { - m_RefreshPistons.push_back(a_BlockPos); - break; - } - - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - { - m_RefreshDropSpensers.push_back(a_BlockPos); - break; - } - - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_REDSTONE_REPEATER_ON: + int x, y, z; + } gCrossCoords[] = { - if (IsRepeaterPointingAway(a_BlockPos, BlockMeta, a_FromBlock)) - { - SetRepeater(a_BlockPos, 10, true); - } - break; - } - - case E_BLOCK_REDSTONE_LAMP_OFF: + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 0, 1, 0}, + { 0,-1, 0}, + } ; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { - m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_ON, 0); - break; + // Power everything + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LEVER); } - case E_BLOCK_TNT: - { - m_World.BroadcastSoundEffect("random.fuse", a_BlockPos.x * 8, a_BlockPos.y * 8, a_BlockPos.z * 8, 0.5f, 0.6f); - m_World.SpawnPrimedTNT(a_BlockPos.x + 0.5, a_BlockPos.y + 0.5, a_BlockPos.z + 0.5, 4); // 4 seconds to boom - m_World.SetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_AIR, 0); - break; - } + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_LEVER); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_LEVER); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_LEVER); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_LEVER); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_LEVER); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_LEVER); + } + return; +} - default: + + + + +void cRedstoneSimulator::HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType) +{ + if (IsButtonOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ))) + { + static const struct // Define which directions the redstone button can power (all sides) { - if ( - (BlockType != E_BLOCK_AIR) && - (BlockType != E_BLOCK_REDSTONE_TORCH_ON) && - (BlockType != E_BLOCK_REDSTONE_TORCH_OFF) && - (BlockType != E_BLOCK_LEVER) // Treating lever as a torch, for refreshing - ) - { - if (IsPowered(a_BlockPos, true)) - { - m_RefreshTorchesAround.push_back(a_BlockPos); - } - } - break; + int x, y, z; + } gCrossCoords[] = + { + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 0, 1, 0}, + { 0,-1, 0}, + } ; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + { + // Power everything + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_BlockType); } - } // switch (BlockType) - return false; + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, a_BlockType); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, a_BlockType); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, a_BlockType); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, a_BlockType); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, a_BlockType); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, a_BlockType); + } } -int cRedstoneSimulator::UnPowerBlock(const Vector3i & a_BlockPos, const Vector3i & a_FromBlock) +void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ) { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - if ((a_BlockPos.y < 0) || (a_BlockPos.y >= cChunkDef::Height)) + static const struct // Define which directions the wire can receive power from { - return 0; + int x, y, z; + } gCrossCoords[] = + { + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 1, 1, 0}, // From here to end, check for wire placed on sides of blocks + {-1, 1, 0}, + { 0, 1, 1}, + { 0, 1, -1}, + { 1,-1, 0}, + {-1,-1, 0}, + { 0,-1, 1}, + { 0,-1, -1}, + } ; + + // Check to see if directly beside a power source + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 15); // Maximum power } - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - switch (BlockType) + else { - case E_BLOCK_REDSTONE_WIRE: + NIBBLETYPE MyMeta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + int TimesMetaSmaller = 0, TimesFoundAWire = 0; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power { - if (BlockMeta > 0) + BLOCKTYPE SurroundType; + NIBBLETYPE SurroundMeta; + m_World.GetBlockTypeMeta(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, SurroundType, SurroundMeta); + + if (SurroundType == E_BLOCK_REDSTONE_WIRE) { - m_World.SetBlockMeta(a_BlockPos, 0); - return 1; - } - break; - } - - case E_BLOCK_PISTON: - case E_BLOCK_STICKY_PISTON: - { - m_RefreshPistons.push_back(a_BlockPos); - break; - } + TimesFoundAWire++; - case E_BLOCK_DISPENSER: - case E_BLOCK_DROPPER: - { - m_RefreshDropSpensers.push_back(a_BlockPos); - break; + if (SurroundMeta > 1) // Wires of power 1 or 0 cannot transfer power TO ME, don't bother checking + { + if (SurroundMeta > MyMeta) // Does surrounding wire have a higher power level than self? + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, SurroundMeta - 1); + } + } + + if (SurroundMeta < MyMeta) // Go through all surroundings to see if self power is larger than everyone else's + { + TimesMetaSmaller++; + } + } } - - case E_BLOCK_REDSTONE_TORCH_ON: + + if (TimesMetaSmaller == TimesFoundAWire) { - return 2; - break; - } - - case E_BLOCK_LEVER: + // All surrounding metas were smaller - self must have been a wire that was + // transferring power to other wires around. + // However, self not directly powered anymore, so source must have been removed, + // therefore, self must be set to meta zero + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0); + } + } + + if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0) // A powered wire + { + //SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); // No matter what, block underneath gets powered + + switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ)) { - // Check if lever is ON. If it is, report it back as a source - if (cRedstoneSimulator::IsLeverOn(BlockMeta)) + case REDSTONE_NONE: { - return 2; + static const struct // Define which directions the redstone wire can power + { + int x, y, z; + } gCrossCoords[] = + { + { 1, 0, 0}, // Power block in front + { 2, 0, 0}, // Power block in front of that (strongly power) + {-1, 0, 0}, + {-2, 0, 0}, + { 0, 0, 1}, + { 0, 0, 2}, + { 0, 0, -1}, + { 0, 0, -2}, + { 0, 1, 0}, + { 0, 2, 0}, + { 0,-1, 0}, + { 0,-2, 0}, + } ; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + { + // Power if block is solid, CURRENTLY all mechanisms are solid + if (g_BlockIsSolid[m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z)]) + { + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + } + } + break; } - break; - } - - case E_BLOCK_REDSTONE_REPEATER_ON: - { - if ( - IsRepeaterPointingTo(a_BlockPos, BlockMeta, a_FromBlock) || // Repeater is next to wire - IsRepeaterPointingTo(a_BlockPos, BlockMeta, a_FromBlock - Vector3i(0, 1, 0)) // Repeater is below wire - ) + case REDSTONE_X_POS: { - return 2; + if (m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ) != E_BLOCK_REDSTONE_WIRE) + { + SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + } + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE); + break; } - else if (IsRepeaterPointingAway(a_BlockPos, BlockMeta, a_FromBlock)) + case REDSTONE_X_NEG: { - SetRepeater(a_BlockPos, 10, false); + if (m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ) != E_BLOCK_REDSTONE_WIRE) + { + SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + } + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE); + break; } - // fall-through: - } - - case E_BLOCK_REDSTONE_REPEATER_OFF: - { - if (IsRepeaterPointingAway(a_BlockPos, BlockMeta, a_FromBlock)) + case REDSTONE_Z_POS: { - SetRepeater(a_BlockPos, 10, false); + if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1) != E_BLOCK_REDSTONE_WIRE) + { + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + } + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE); + break; } - break; - } - - case E_BLOCK_REDSTONE_LAMP_ON: - { - m_World.FastSetBlock(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, E_BLOCK_REDSTONE_LAMP_OFF, 0); - break; - } - - default: - { - if ( - (BlockType != E_BLOCK_AIR) && - (BlockType != E_BLOCK_REDSTONE_TORCH_ON) && - (BlockType != E_BLOCK_REDSTONE_TORCH_OFF) && - (BlockType != E_BLOCK_LEVER) - ) + case REDSTONE_Z_NEG: { - if (!IsPowered(a_BlockPos, true)) + if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1) != E_BLOCK_REDSTONE_WIRE) { - m_RefreshTorchesAround.push_back(a_BlockPos); + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); } + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE); + break; } - break; } - } // switch (BlockType) - - return 0; + } + return; } -// Removes current from all powered redstone wires until it reaches an energy source. -// Also returns all energy sources it encountered -cRedstoneSimulator::BlockList cRedstoneSimulator::RemoveCurrent(const Vector3i & a_BlockPos) +void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) { - - - std::deque< Vector3i > SpreadStack; - std::deque< Vector3i > FoundSources; - - Vector3i Surroundings[] = { - Vector3i(1, 0, 0), - Vector3i(1, 1, 0), - Vector3i(1,-1, 0), - Vector3i(-1, 0, 0), - Vector3i(-1, 1, 0), - Vector3i(-1,-1, 0), - Vector3i(0, 0, 1), - Vector3i(0, 1, 1), - Vector3i(0,-1, 1), - Vector3i(0, 0,-1), - Vector3i(0, 1,-1), - Vector3i(0,-1,-1), - Vector3i(0,-1, 0), - }; - - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - switch (BlockType) + NIBBLETYPE a_Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + if (a_MyState == E_BLOCK_REDSTONE_REPEATER_OFF) { - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: + if (IsRepeaterPowered(a_BlockX, a_BlockY, a_BlockZ, a_Meta & 0x3)) { - // Repeaters only spread to their front front and 0 or 1 block up - static Vector3i Surroundings [] = { - Vector3i(0, 0, 0), - Vector3i(0, 1, 0), - }; - Vector3i Direction = GetRepeaterDirection(BlockMeta); - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); + switch (a_Meta & 0x3) // We only want the direction (bottom) bits { - Vector3i pos = a_BlockPos + Direction + Surroundings[i]; - int RetVal = UnPowerBlock(pos, a_BlockPos); - if (RetVal == 1) + case 0x0: { - // Changed, so add to stack - SpreadStack.push_back(pos); + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_REPEATER_ON); + break; } - else if (RetVal == 2) + case 0x1: { - FoundSources.push_back(pos); + SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_REPEATER_ON); + break; } - } - break; - } - - case E_BLOCK_REDSTONE_TORCH_OFF: - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_LEVER: - { - static Vector3i Surroundings [] = { // Torches only spread on the same level - Vector3i(-1, 0, 0), - Vector3i(1, 0, 0), - Vector3i(0, 0,-1), - Vector3i(0, 0, 1), - }; - - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) - { - Vector3i pos = Vector3i(a_BlockPos) + Surroundings[i]; - int RetVal = UnPowerBlock(pos, a_BlockPos); - if (RetVal == 1) + case 0x2: { - SpreadStack.push_back(pos); // Changed, so add to stack + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_REPEATER_ON); + break; } - else if (RetVal == 2) + case 0x3: { - FoundSources.push_back(pos); + SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_REPEATER_ON); + break; } } - break; } - - default: + } + else + { + if (!IsRepeaterPowered(a_BlockX, a_BlockY, a_BlockZ, a_Meta & 0x3)) { - SpreadStack.push_back(a_BlockPos); - break; + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta); } - } // switch (BlockType) + } + return; +} + + + + + +void cRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + { + cPiston Piston(&m_World); + Piston.ExtendPiston(a_BlockX, a_BlockY, a_BlockZ); + } + else + { + cPiston Piston(&m_World); + Piston.RetractPiston(a_BlockX, a_BlockY, a_BlockZ); + } + return; +} + + - while (!SpreadStack.empty()) + +void cRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + class cSetPowerToDropSpenser : + public cDropSpenserCallback { - Vector3i pos = SpreadStack.back(); - SpreadStack.pop_back(); + bool m_IsPowered; + public: + cSetPowerToDropSpenser(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} + + virtual bool Item(cDropSpenserEntity * a_DropSpenser) override + { + a_DropSpenser->SetRedstonePower(m_IsPowered); + return false; + } + } DrSpSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)); + + m_World.DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, DrSpSP); + return; +} + + - for (unsigned int i = 0; i < ARRAYCOUNT(Surroundings); ++i) + + +void cRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) +{ + if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF) + { + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { - Vector3i OtherPos = pos + Surroundings[i]; - int RetVal = UnPowerBlock(OtherPos, pos); - if (RetVal == 1) - { - SpreadStack.push_back(OtherPos); // Changed, so add to stack - } - else if (RetVal == 2) - { - FoundSources.push_back(OtherPos); - } + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0); + } + } + else + { + if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + { + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0); } } + return; +} + + + + - return FoundSources; +void cRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + { + m_World.BroadcastSoundEffect("random.fuse", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); + m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom + m_World.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + } + return; } -bool cRedstoneSimulator::IsPowering(const Vector3i & a_PowerPos, const Vector3i & a_BlockPos, eRedstoneDirection a_WireDirection, bool a_bOnlyByWire) +void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ) { - BLOCKTYPE PowerBlock; - NIBBLETYPE PowerMeta; - m_World.GetBlockTypeMeta(a_PowerPos.x, a_PowerPos.y, a_PowerPos.z, PowerBlock, PowerMeta); - - // Filter out powering blocks for a_bOnlyByWire - if ( - !a_bOnlyByWire && ( - (PowerBlock == E_BLOCK_REDSTONE_TORCH_ON) || - (PowerBlock == E_BLOCK_LEVER) - ) - ) + if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08) { - return true; + // Block position is located at top half of door + // Is Y - 1 both within world boundaries, a door block, and the bottom half of a door? + // The bottom half stores the open/closed information + if ( + (a_BlockY - 1 >= 0) && + ((m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_WOODEN_DOOR) || (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_IRON_DOOR)) && + (m_World.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ & 0x08) == 0) + ) + { + if ((m_World.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ) & 0x04) == 0) // Closed door? + { + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Powered? If so, toggle open + { + cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); + } + } + else // Opened door + { + if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Unpowered? Close if so + { + cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); + } + } + } } - - switch (PowerBlock) + else { - case E_BLOCK_REDSTONE_REPEATER_ON: + if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x04) == 0) // Closed door? { - // A repeater pointing towards block is regarded as wire - if (IsRepeaterPointingTo(a_PowerPos, PowerMeta, a_BlockPos)) + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Powered? If so, toggle open { - return true; + cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); } - break; } - - case E_BLOCK_REDSTONE_WIRE: + else // Opened door { - if (PowerMeta > 0) + if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Unpowered? Close if so { - if (GetWireDirection(a_PowerPos) == a_WireDirection) - { - return true; - } + cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); } - break; } - } // switch (PowerBlock) - - return false; + } + return; } -bool cRedstoneSimulator::IsPowered(const Vector3i & a_BlockPos, bool a_bOnlyByWire /* = false */) +void cRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType) { - BLOCKTYPE BlockType; - NIBBLETYPE BlockMeta; - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, BlockType, BlockMeta); - if ((BlockType == E_BLOCK_REDSTONE_REPEATER_OFF) || (BlockType == E_BLOCK_REDSTONE_REPEATER_ON)) + switch (a_MyType) { - Vector3i Behind = a_BlockPos - GetRepeaterDirection(BlockMeta); - BLOCKTYPE BehindBlock; - NIBBLETYPE BehindMeta; - m_World.GetBlockTypeMeta(Behind.x, Behind.y, Behind.z, BehindBlock, BehindMeta); - switch (BehindBlock) + case E_BLOCK_DETECTOR_RAIL: { - case E_BLOCK_REDSTONE_TORCH_ON: - case E_BLOCK_LEVER: + if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08) { - // _X: TODO: Shouldn't a lever be checked if it is switched on? - return true; + static const struct // Define which directions the rail can power (all sides) + { + int x, y, z; + } gCrossCoords[] = + { + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + { 0, 1, 0}, + { 0,-1, 0}, + } ; + + for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + { + // Power everything + SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_MyType); + } } - case E_BLOCK_REDSTONE_WIRE: + break; + } + case E_BLOCK_ACTIVATOR_RAIL: + case E_BLOCK_POWERED_RAIL: + { + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { - return (BehindMeta > 0); + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x08); } - case E_BLOCK_REDSTONE_REPEATER_ON: + else { - return IsRepeaterPointingTo(Behind, BehindMeta, a_BlockPos); + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07); } - } // switch (BehindBlock) - return false; - } - - if (IsPowering(Vector3i(a_BlockPos.x - 1, a_BlockPos.y, a_BlockPos.z), a_BlockPos, REDSTONE_X_POS, a_bOnlyByWire)) - { - return true; - } - if (IsPowering(Vector3i(a_BlockPos.x + 1, a_BlockPos.y, a_BlockPos.z), a_BlockPos, REDSTONE_X_NEG, a_bOnlyByWire)) - { - return true; - } - if (IsPowering(Vector3i(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z - 1), a_BlockPos, REDSTONE_Z_POS, a_bOnlyByWire)) - { - return true; - } - if (IsPowering(Vector3i(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z + 1), a_BlockPos, REDSTONE_Z_NEG, a_bOnlyByWire)) - { - return true; - } - - // Only wires can power the bottom block - BLOCKTYPE PosYType; - NIBBLETYPE PosYMeta; - m_World.GetBlockTypeMeta(a_BlockPos.x, a_BlockPos.y + 1, a_BlockPos.z, PosYType, PosYMeta); - if (PosYType == E_BLOCK_REDSTONE_WIRE) - { - return (PosYMeta > 0); + break; + } } - - return false; } -// Believe me, it works!! TODO: Add repeaters and low/high wires -cRedstoneSimulator::eRedstoneDirection cRedstoneSimulator::GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ) -{ - int Dir = REDSTONE_NONE; - BLOCKTYPE NegX = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); - if ( - (NegX == E_BLOCK_REDSTONE_WIRE) || - (NegX == E_BLOCK_REDSTONE_TORCH_ON) || - (NegX == E_BLOCK_LEVER) - ) - { - Dir |= (REDSTONE_X_POS); - } - - BLOCKTYPE PosX = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); - if ( - (PosX == E_BLOCK_REDSTONE_WIRE) || - (PosX == E_BLOCK_REDSTONE_TORCH_ON) || - (PosX == E_BLOCK_LEVER) - ) - { - Dir |= (REDSTONE_X_NEG); - } - - BLOCKTYPE NegZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); - if ( - (NegZ == E_BLOCK_REDSTONE_WIRE) || - (NegZ == E_BLOCK_REDSTONE_TORCH_ON) || - (NegZ == E_BLOCK_LEVER) - ) +bool cRedstoneSimulator::AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + sPoweredBlocks & Change = *itr; + + if (Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; + return true; } - Dir |= REDSTONE_Z_POS; } - - BLOCKTYPE PosZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); - if ( - (PosZ == E_BLOCK_REDSTONE_WIRE) || - (PosZ == E_BLOCK_REDSTONE_TORCH_ON) || - (PosZ == E_BLOCK_LEVER) - ) + + for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + sLinkedPoweredBlocks & Change = *itr; + + if (Change.a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; + return true; } - Dir |= REDSTONE_Z_NEG; } - - return (eRedstoneDirection)Dir; + return false; } -bool cRedstoneSimulator::IsRepeaterPointingTo(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos) +bool cRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) { - switch (a_MetaData & 0x3) + // Check through powered blocks list + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) { - case 0x0: + sPoweredBlocks & Change = *itr; + + switch (a_Meta) { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0, 1))) + case 0x0: { - return true; + // Flip the coords to check the back of the repeater + if (Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } + break; } - break; - } - - case 0x1: - { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(-1, 0, 0))) + case 0x1: + { + if (Change.a_SourcePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } + break; + } + case 0x2: { - return true; + if (Change.a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } + break; } - break; - } - - case 0x2: - { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0,-1))) + case 0x3: { - return true; + if (Change.a_SourcePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } + break; } - break; } - - case 0x3: + } + + // Check linked powered list, 'middle' blocks + for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) + { + sLinkedPoweredBlocks & Change = *itr; + + switch (a_Meta) { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(1, 0, 0))) + case 0x0: { - return true; + if (Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } + break; + } + case 0x1: + { + if (Change.a_MiddlePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } + break; + } + case 0x2: + { + if (Change.a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } + break; + } + case 0x3: + { + if (Change.a_MiddlePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } + break; } - break; } } - return false; + return false; // Couldn't find power source behind repeater } -bool cRedstoneSimulator::IsRepeaterPointingAway(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos) +void cRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType) { - switch (a_MetaData & 0x3) + switch (a_Direction) { - case 0x0: + case BLOCK_FACE_XM: { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0,-1))) - { - return true; - } + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX - 2, a_BlockY, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); break; } - - case 0x1: + case BLOCK_FACE_XP: { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(1, 0, 0))) - { - return true; - } + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX + 2, a_BlockY, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); break; } - - case 0x2: + case BLOCK_FACE_YM: { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(0, 0, 1))) - { - return true; - } + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX, a_BlockY - 2, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); break; } - - case 0x3: + case BLOCK_FACE_YP: { - if ((a_RepeaterPos - a_BlockPos).Equals(Vector3i(-1, 0, 0))) - { - return true; - } + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX, a_BlockY + 2, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + break; + } + case BLOCK_FACE_ZM: + { + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ - 2, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + break; + } + case BLOCK_FACE_ZP: + { + BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); + if (!g_BlockIsSolid[MiddleBlock]) { return; } + + SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ + 2, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + break; + } + default: + { + ASSERT(!"Unhandled face direction when attempting to set blocks as linked powered!"); break; } } - return false; + return; } -NIBBLETYPE cRedstoneSimulator::RepeaterRotationToMetaData(double a_Rotation) +void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock) { - a_Rotation += 90 + 45; // So its not aligned with axis - if (a_Rotation > 360) - { - a_Rotation -= 360; - } - - if ((a_Rotation >= 0) && (a_Rotation < 90)) - { - return 0x1; - } - else if ((a_Rotation >= 180) && (a_Rotation < 270)) - { - return 0x3; - } - else if ((a_Rotation >= 90) && (a_Rotation < 180)) - { - return 0x2; - } - else - { - return 0x0; - } + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { return; } // Check for duplicates + + sPoweredBlocks RC; + RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); + RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); + RC.a_SourceBlock = a_SourceBlock; + m_PoweredBlocks.push_back(RC); + return; } -Vector3i cRedstoneSimulator::GetRepeaterDirection(NIBBLETYPE a_MetaData) +void cRedstoneSimulator::SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, + int a_MiddleX, int a_MiddleY, int a_MiddleZ, + int a_SourceX, int a_SourceY, int a_SourceZ, + BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock + ) { - switch (a_MetaData & 0x3) - { - case 0x0: return Vector3i(0, 0,-1); - case 0x1: return Vector3i(1, 0, 0); - case 0x2: return Vector3i(0, 0, 1); - case 0x3: return Vector3i(-1, 0, 0); - } - return Vector3i(); + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { return; } // Check for duplicates + + sLinkedPoweredBlocks RC; + RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); + RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ); + RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); + RC.a_SourceBlock = a_SourceBlock; + RC.a_MiddleBlock = a_MiddleBlock; + m_LinkedPoweredBlocks.push_back(RC); + return; } -NIBBLETYPE cRedstoneSimulator::LeverDirectionToMetaData(char a_Dir) +cRedstoneSimulator::eRedstoneDirection cRedstoneSimulator::GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ) { - // Determine lever direction: - switch (a_Dir) + int Dir = REDSTONE_NONE; + + BLOCKTYPE NegX = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); + if (IsPotentialSource(NegX)) + { + Dir |= (REDSTONE_X_POS); + } + + BLOCKTYPE PosX = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); + if (IsPotentialSource(PosX)) { - case BLOCK_FACE_TOP: return 0x6; - case BLOCK_FACE_EAST: return 0x1; - case BLOCK_FACE_WEST: return 0x2; - case BLOCK_FACE_SOUTH: return 0x3; - case BLOCK_FACE_NORTH: return 0x4; - case BLOCK_FACE_BOTTOM: return 0x0; - default: return 0x6; + Dir |= (REDSTONE_X_NEG); } -} - - - - - -bool cRedstoneSimulator::IsLeverOn(cWorld * a_World, const Vector3i & a_BlockPos) -{ - // Extract the metadata and ask the lower level: - return IsLeverOn(a_World->GetBlockMeta(a_BlockPos)); + + BLOCKTYPE NegZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); + if (IsPotentialSource(NegZ)) + { + if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_POS; + } + + BLOCKTYPE PosZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); + if (IsPotentialSource(PosZ)) + { + if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_NEG; + } + return (eRedstoneDirection)Dir; } @@ -1145,32 +1063,9 @@ bool cRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta) -void cRedstoneSimulator::SetRepeater(const Vector3i & a_Position, int a_Ticks, bool a_bPowerOn) +bool cRedstoneSimulator::IsButtonOn(NIBBLETYPE a_BlockMeta) { - for (RepeaterList::iterator itr = m_SetRepeaters.begin(); itr != m_SetRepeaters.end(); ++itr) - { - sRepeaterChange & Change = *itr; - if (Change.Position.Equals(a_Position)) - { - if (Change.bPowerOn && !a_bPowerOn) - { - Change.bPowerOffNextTime = true; - } - if (a_bPowerOn) - { - Change.bPowerOffNextTime = false; - } - Change.bPowerOn |= a_bPowerOn; - return; - } - } - - sRepeaterChange RC; - RC.Position = a_Position; - RC.Ticks = a_Ticks; - RC.bPowerOn = a_bPowerOn; - RC.bPowerOffNextTime = false; - m_SetRepeaters.push_back(RC); + return IsLeverOn(a_BlockMeta); } diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index c0d5795c7..d68c6daeb 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -3,6 +3,9 @@ #include "Simulator.h" +/// Per-chunk data for the simulator, specified individual chunks to simulate; 'Data' is not used +typedef cCoordWithIntList cRedstoneSimulatorChunkData; + @@ -12,13 +15,13 @@ class cRedstoneSimulator : { typedef cSimulator super; public: + cRedstoneSimulator(cWorld & a_World); ~cRedstoneSimulator(); - virtual void Simulate( float a_Dt ) override; - virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override { return true; } - - virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + virtual void Simulate(float a_Dt) override {}; // Not used in this simulator + virtual void SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override; + virtual bool IsAllowedBlock( BLOCKTYPE a_BlockType ) override { return IsRedstone(a_BlockType); } enum eRedstoneDirection { @@ -31,56 +34,166 @@ public: eRedstoneDirection GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ); eRedstoneDirection GetWireDirection(const Vector3i & a_Pos) { return GetWireDirection(a_Pos.x, a_Pos.y, a_Pos.z); } - static bool IsRepeaterPointingTo (const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos); - static bool IsRepeaterPointingAway(const Vector3i & a_RepeaterPos, char a_MetaData, const Vector3i & a_BlockPos); - static NIBBLETYPE RepeaterRotationToMetaData(double a_Rotation); - static Vector3i GetRepeaterDirection(NIBBLETYPE a_MetaData); - static NIBBLETYPE LeverDirectionToMetaData(char a_Dir); - static bool IsLeverOn(cWorld * a_World, const Vector3i & a_BlockPos); - static bool IsLeverOn(NIBBLETYPE a_BlockMeta); - - private: - struct sRepeaterChange + + struct sPoweredBlocks // Define structure of the directly powered blocks list { - Vector3i Position; - int Ticks; - bool bPowerOn; - bool bPowerOffNextTime; + Vector3i a_BlockPos; // Position of powered block + Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos + BLOCKTYPE a_SourceBlock; // The source block type (for pistons pushing away sources and replacing with non source etc.) }; - typedef std::deque <Vector3i> BlockList; - - typedef std::deque< sRepeaterChange > RepeaterList; - RepeaterList m_SetRepeaters; - - void SetRepeater(const Vector3i & a_Position, int a_Ticks, bool a_bPowerOn); - - virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override {} - - void HandleChange( const Vector3i & a_BlockPos ); - BlockList RemoveCurrent( const Vector3i & a_BlockPos ); - - bool PowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock, char a_Power ); - int UnPowerBlock( const Vector3i & a_BlockPos, const Vector3i & a_FromBlock ); - - bool IsPowered( const Vector3i & a_BlockPos, bool a_bOnlyByWire = false ); - bool IsPowering( const Vector3i & a_PowerPos, const Vector3i & a_BlockPos, eRedstoneDirection a_WireDirection, bool a_bOnlyByWire ); - - BlockList m_Blocks; - BlockList m_BlocksBuffer; - - BlockList m_RefreshPistons; - BlockList m_RefreshDropSpensers; - - BlockList m_RefreshTorchesAround; + struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side) + { + Vector3i a_BlockPos; + Vector3i a_MiddlePos; + Vector3i a_SourcePos; + BLOCKTYPE a_SourceBlock; + BLOCKTYPE a_MiddleBlock; + }; - void RefreshTorchesAround( const Vector3i & a_BlockPos ); - - // TODO: The entire simulator is synchronized, no need to lock data structures; remove this - cCriticalSection m_CS; -}; - - - - + typedef std::vector <sPoweredBlocks> PoweredBlocksList; + typedef std::vector <sLinkedPoweredBlocks> LinkedBlocksList; + + PoweredBlocksList m_PoweredBlocks; + LinkedBlocksList m_LinkedPoweredBlocks; + + virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override; + + // We want a_MyState for devices needing a full FastSetBlock (as opposed to meta) because with our simulation model, we cannot keep setting the block if it is already set correctly + // In addition to being non-performant, it would stop the player from actually breaking said device + + /* ====== SOURCES ====== */ + ///<summary>Handles the redstone torch</summary> + void HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + ///<summary>Handles the redstone block</summary> + void HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ); + ///<summary>Handles levers</summary> + void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ); + ///<summary>Handles buttons</summary> + void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType); + /* ==================== */ + + /* ====== CARRIERS ====== */ + ///<summary>Handles redstone wire</summary> + void HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ); + ///<summary>Handles repeaters</summary> + void HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + /* ====================== */ + + /* ====== DEVICES ====== */ + ///<summary>Handles pistons</summary> + void HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ); + ///<summary>Handles dispensers and droppers</summary> + void HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ); + ///<summary>Handles TNT (exploding)</summary> + void HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ); + ///<summary>Handles redstone lamps</summary> + void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + ///<summary>Handles doords</summary> + void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ); + ///<summary>Handles activator, detector, and powered rails</summary> + void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); + /* ===================== */ + + /* ====== Helper functions ====== */ + void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock); + void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock); + void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType); + + bool AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ); + bool IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta); + + bool IsLeverOn(NIBBLETYPE a_BlockMeta); + bool IsButtonOn(NIBBLETYPE a_BlockMeta); + /* ============================== */ + + inline static bool IsMechanism(BLOCKTYPE Block) + { + switch (Block) + { + case E_BLOCK_PISTON: + case E_BLOCK_STICKY_PISTON: + case E_BLOCK_DISPENSER: + case E_BLOCK_DROPPER: + case E_BLOCK_TNT: + case E_BLOCK_REDSTONE_LAMP_OFF: + case E_BLOCK_REDSTONE_LAMP_ON: + case E_BLOCK_WOODEN_DOOR: + case E_BLOCK_IRON_DOOR: + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_POWERED_RAIL: + { + return true; + } + default: return false; + } + } + + inline static bool IsPotentialSource(BLOCKTYPE Block) + { + switch (Block) + { + case E_BLOCK_WOODEN_BUTTON: + case E_BLOCK_STONE_BUTTON: + case E_BLOCK_REDSTONE_WIRE: + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_LEVER: + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_BLOCK_OF_REDSTONE: + case E_BLOCK_ACTIVE_COMPARATOR: + case E_BLOCK_INACTIVE_COMPARATOR: + { + return true; + } + default: return false; + } + } + + inline static bool IsRedstone(BLOCKTYPE Block) + { + switch (Block) + { + // All redstone devices, please alpha sort + case E_BLOCK_ACTIVATOR_RAIL: + case E_BLOCK_ACTIVE_COMPARATOR: + case E_BLOCK_BLOCK_OF_REDSTONE: + case E_BLOCK_DETECTOR_RAIL: + case E_BLOCK_DISPENSER: + case E_BLOCK_DAYLIGHT_SENSOR: + case E_BLOCK_DROPPER: + case E_BLOCK_FENCE_GATE: + case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: + case E_BLOCK_HOPPER: + case E_BLOCK_INACTIVE_COMPARATOR: + case E_BLOCK_IRON_DOOR: + case E_BLOCK_LEVER: + case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: + case E_BLOCK_NOTE_BLOCK: + case E_BLOCK_REDSTONE_LAMP_OFF: + case E_BLOCK_REDSTONE_LAMP_ON: + case E_BLOCK_REDSTONE_REPEATER_OFF: + case E_BLOCK_REDSTONE_REPEATER_ON: + case E_BLOCK_REDSTONE_TORCH_OFF: + case E_BLOCK_REDSTONE_TORCH_ON: + case E_BLOCK_REDSTONE_WIRE: + case E_BLOCK_STICKY_PISTON: + case E_BLOCK_STONE_BUTTON: + case E_BLOCK_STONE_PRESSURE_PLATE: + case E_BLOCK_TNT: + case E_BLOCK_TRAPDOOR: + case E_BLOCK_TRIPWIRE_HOOK: + case E_BLOCK_WOODEN_BUTTON: + case E_BLOCK_WOODEN_DOOR: + case E_BLOCK_WOODEN_PRESSURE_PLATE: + case E_BLOCK_PISTON: + { + return true; + } + default: return false; + } + } +};
\ No newline at end of file diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index d52b1323f..f7aeeed26 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -270,55 +270,6 @@ void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & -AStringList GetDirectoryContents(const char * a_Directory) -{ - AStringList AllFiles; - - #ifdef _WIN32 - - AString FileFilter = AString(a_Directory) + "*.*"; - HANDLE hFind; - WIN32_FIND_DATA FindFileData; - - if ((hFind = FindFirstFile(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE) - { - do - { - AllFiles.push_back(FindFileData.cFileName); - } while (FindNextFile(hFind, &FindFileData)); - FindClose(hFind); - } - - #else // _WIN32 - - DIR * dp; - struct dirent *dirp; - if (*a_Directory == 0) - { - a_Directory = "."; - } - if ((dp = opendir(a_Directory)) == NULL) - { - LOGERROR("Error (%i) opening directory \"%s\"\n", errno, a_Directory ); - } - else - { - while ((dirp = readdir(dp)) != NULL) - { - AllFiles.push_back(dirp->d_name); - } - closedir(dp); - } - - #endif // else _WIN32 - - return AllFiles; -} - - - - - // Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8 AString & RawBEToUTF8(short * a_RawData, int a_NumShorts, AString & a_UTF8) { diff --git a/src/StringUtils.h b/src/StringUtils.h index ec9ba96ce..3917cc4ec 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -57,9 +57,6 @@ extern unsigned int RateCompareString(const AString & s1, const AString & s2 ); /// Replaces *each* occurence of iNeedle in iHayStack with iReplaceWith extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & iReplaceWith); // tolua_export -/// Returns the list of all items in the specified directory (files, folders, nix pipes, whatever's there) -extern AStringList GetDirectoryContents(const char * a_Directory); - /// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8 extern AString & RawBEToUTF8(short * a_RawData, int a_NumShorts, AString & a_UTF8); diff --git a/src/World.cpp b/src/World.cpp index 0f9df8a62..531952e37 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -922,6 +922,15 @@ void cWorld::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinB +bool cWorld::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback) +{ + return m_ChunkMap->ForEachBlockEntityInChunk(a_ChunkX, a_ChunkZ, a_Callback); +} + + + + + bool cWorld::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback) { return m_ChunkMap->ForEachChestInChunk(a_ChunkX, a_ChunkZ, a_Callback); @@ -1010,6 +1019,15 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo +bool cWorld::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) +{ + return m_ChunkMap->DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + + bool cWorld::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback) { return m_ChunkMap->DoWithChestAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); diff --git a/src/World.h b/src/World.h index ee4a23b14..d10aa3b78 100644 --- a/src/World.h +++ b/src/World.h @@ -385,8 +385,11 @@ public: inline cFluidSimulator * GetWaterSimulator(void) { return m_WaterSimulator; } inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; } + /// Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true + bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp + /// 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 + 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); @@ -415,8 +418,11 @@ public: */ void DoExplosionAt(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 block entity at the specified coords; returns false if there's no block entity at those coords, true if found + bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp + /// 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 + 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 |