diff options
author | Tycho Bickerstaff <work.tycho@gmail.com> | 2013-12-22 16:21:34 +0100 |
---|---|---|
committer | Tycho Bickerstaff <work.tycho@gmail.com> | 2013-12-22 16:21:34 +0100 |
commit | 1a9d93665f9f82ccd9054aa1c8e9c24f13776a91 (patch) | |
tree | e9572b3fdf1d47c0769a3d43d3fc4dfac68fd0dd /src | |
parent | basic threadsafe queue interface (diff) | |
parent | Update GETTING-STARTED.md (diff) | |
download | cuberite-1a9d93665f9f82ccd9054aa1c8e9c24f13776a91.tar cuberite-1a9d93665f9f82ccd9054aa1c8e9c24f13776a91.tar.gz cuberite-1a9d93665f9f82ccd9054aa1c8e9c24f13776a91.tar.bz2 cuberite-1a9d93665f9f82ccd9054aa1c8e9c24f13776a91.tar.lz cuberite-1a9d93665f9f82ccd9054aa1c8e9c24f13776a91.tar.xz cuberite-1a9d93665f9f82ccd9054aa1c8e9c24f13776a91.tar.zst cuberite-1a9d93665f9f82ccd9054aa1c8e9c24f13776a91.zip |
Diffstat (limited to 'src')
60 files changed, 1990 insertions, 233 deletions
diff --git a/src/Bindings/AllToLua.bat b/src/Bindings/AllToLua.bat index f7867fadb..b2a192880 100644 --- a/src/Bindings/AllToLua.bat +++ b/src/Bindings/AllToLua.bat @@ -1,27 +1,22 @@ :: AllToLua.bat - :: This scripts updates the automatically-generates Lua bindings in Bindings.cpp / Bindings.h +:: When called without any parameters, it will pause for a keypress at the end +:: Call with any parameter to disable the wait (for buildserver use) -:: If there was a Git conflict, resolve it by resetting to HEAD; we're regenerating the files from scratch anyway -git checkout --ours Bindings.cpp -git add -u Bindings.cpp -git checkout --ours Bindings.h -git add -u Bindings.h - +:: Regenerate the files: +"tolua++.exe" -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg -:: Regenerate the files: -"tolua++.exe" -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg - +: Wait for keypress, if no param given: +if %ALLTOLUA_WAIT%N == N pause -if %ALLTOLUA_WAIT%N == N pause diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index cfa3f70ca..64a818a60 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -18,7 +18,7 @@ extern "C" // fwd: SQLite/lsqlite3.c extern "C" { - LUALIB_API int luaopen_lsqlite3(lua_State * L); + int luaopen_lsqlite3(lua_State * L); } // fwd: LuaExpat/lxplib.c: @@ -309,7 +309,7 @@ void cLuaState::Push(const AStringVector & a_Vector) { ASSERT(IsValid()); - lua_createtable(m_LuaState, a_Vector.size(), 0); + lua_createtable(m_LuaState, (int)a_Vector.size(), 0); int newTable = lua_gettop(m_LuaState); int index = 1; for (AStringVector::const_iterator itr = a_Vector.begin(), end = a_Vector.end(); itr != end; ++itr, ++index) diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 15b0cdeff..40bb67e69 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -240,6 +240,25 @@ public: return CallFunction(0); } + /// Call any 0-param 1-return Lua function in a single line: + template< + typename FnT, typename RetT1 + > + bool Call(FnT a_FnName, const cRet & a_Mark, RetT1 & a_Ret1) + { + if (!PushFunction(a_FnName)) + { + return false; + } + if (!CallFunction(1)) + { + return false; + } + GetReturn(-1, a_Ret1); + lua_pop(m_LuaState, 1); + return true; + } + /// Call any 1-param 1-return Lua function in a single line: template< typename FnT, typename ArgT1, typename RetT1 diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 9a3c2383e..ee0f8a062 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -82,6 +82,7 @@ public: virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0; virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) = 0; + virtual bool OnPluginsLoaded (void) = 0; virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 0d17c9ce2..69e83fb0a 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -386,7 +386,7 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can { case esOther: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; case esPrimedTNT: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res); break; - case esCreeper: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res); break; + case esMonster: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cMonster *)a_SourceData, cLuaState::Return, res); break; case esBed: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break; case esEnderCrystal: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break; case esGhastFireball: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break; @@ -910,6 +910,24 @@ bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_Block +bool cPluginLua::OnPluginsLoaded(void) +{ + cCSLock Lock(m_CriticalSection); + bool res = false; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGINS_LOADED]; + for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) + { + bool ret = false; + m_LuaState.Call((int)(**itr), cLuaState::Return, ret); + res = res || ret; + } + return res; +} + + + + + bool cPluginLua::OnPostCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) { cCSLock Lock(m_CriticalSection); diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index e1e274c72..1b257285e 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -79,6 +79,7 @@ public: virtual bool OnPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; virtual bool OnPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override; virtual bool OnPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override; + virtual bool OnPluginsLoaded (void) override; virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 832dc4249..ffffe1a23 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -118,7 +118,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) int KeyNum = a_SettingsIni.FindKey("Plugins"); // If it does, how many plugins are there? - unsigned int NumPlugins = ((KeyNum != -1) ? (a_SettingsIni.GetNumValues(KeyNum)) : 0); + int NumPlugins = ((KeyNum != -1) ? (a_SettingsIni.GetNumValues(KeyNum)) : 0); if (KeyNum == -1) { @@ -126,7 +126,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) } else if (NumPlugins > 0) { - for(unsigned int i = 0; i < NumPlugins; i++) + for (int i = 0; i < NumPlugins; i++) { AString ValueName = a_SettingsIni.GetValueName(KeyNum, i); if (ValueName.compare("Plugin") == 0) @@ -136,7 +136,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) { if (m_Plugins.find(PluginFile) != m_Plugins.end()) { - LoadPlugin( PluginFile ); + LoadPlugin(PluginFile); } } } @@ -155,6 +155,7 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) { LOG("-- Loaded 1 Plugin --"); } + CallHookPluginsLoaded(); } @@ -987,6 +988,25 @@ bool cPluginManager::CallHookPlayerUsingItem(cPlayer & a_Player, int a_BlockX, i +bool cPluginManager::CallHookPluginsLoaded(void) +{ + HookMap::iterator Plugins = m_Hooks.find(HOOK_PLUGINS_LOADED); + if (Plugins == m_Hooks.end()) + { + return false; + } + bool res = false; + for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) + { + res = !(*itr)->OnPluginsLoaded() || res; + } + return res; +} + + + + + bool cPluginManager::CallHookPostCrafting(const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) { HookMap::iterator Plugins = m_Hooks.find(HOOK_POST_CRAFTING); diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index 04d6470c7..5abb8be84 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -94,6 +94,7 @@ public: // tolua_export HOOK_PLAYER_USED_ITEM, HOOK_PLAYER_USING_BLOCK, HOOK_PLAYER_USING_ITEM, + HOOK_PLUGINS_LOADED, HOOK_POST_CRAFTING, HOOK_PRE_CRAFTING, HOOK_SPAWNED_ENTITY, @@ -181,6 +182,7 @@ public: // tolua_export bool CallHookPlayerUsedItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ); bool CallHookPlayerUsingBlock (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); bool CallHookPlayerUsingItem (cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ); + bool CallHookPluginsLoaded (void); bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity); diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index a5309f995..1148908c6 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -301,10 +301,10 @@ bool cBlockArea::Read(cWorld * a_World, int a_MinBlockX, int a_MaxBlockX, int a_ LOGWARNING("%s: MaxBlockY less than zero, adjusting to zero", __FUNCTION__); a_MaxBlockY = 0; } - else if (a_MaxBlockY >= cChunkDef::Height) + else if (a_MaxBlockY > cChunkDef::Height) { LOGWARNING("%s: MaxBlockY more than chunk height, adjusting to chunk height", __FUNCTION__); - a_MaxBlockY = cChunkDef::Height - 1; + a_MaxBlockY = cChunkDef::Height; } // Allocate the needed memory: @@ -349,10 +349,10 @@ bool cBlockArea::Write(cWorld * a_World, int a_MinBlockX, int a_MinBlockY, int a LOGWARNING("%s: MinBlockY less than zero, adjusting to zero", __FUNCTION__); a_MinBlockY = 0; } - else if (a_MinBlockY >= cChunkDef::Height - m_SizeY) + else if (a_MinBlockY > cChunkDef::Height - m_SizeY) { LOGWARNING("%s: MinBlockY + m_SizeY more than chunk height, adjusting to chunk height", __FUNCTION__); - a_MinBlockY = cChunkDef::Height - m_SizeY - 1; + a_MinBlockY = cChunkDef::Height - m_SizeY; } return a_World->WriteBlockArea(*this, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes); diff --git a/src/BlockID.h b/src/BlockID.h index 9742e9745..288719ccf 100644 --- a/src/BlockID.h +++ b/src/BlockID.h @@ -833,14 +833,17 @@ enum eExplosionSource { esOther, esPrimedTNT, - esCreeper, + esMonster, esBed, esEnderCrystal, esGhastFireball, esWitherSkullBlack, esWitherSkullBlue, esWitherBirth, - esPlugin + esPlugin, + + // Obsolete constants, kept for compatibility, will be removed after some time: + esCreeper = esMonster, } ; // tolua_end diff --git a/src/Blocks/BlockCactus.h b/src/Blocks/BlockCactus.h index f77df5e42..88be25dc0 100644 --- a/src/Blocks/BlockCactus.h +++ b/src/Blocks/BlockCactus.h @@ -54,7 +54,7 @@ public: NIBBLETYPE BlockMeta; if ( a_Chunk.UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta) && - (BlockType != E_BLOCK_AIR) + (g_BlockIsSolid[BlockType]) ) { return false; diff --git a/src/Blocks/BlockPumpkin.h b/src/Blocks/BlockPumpkin.h index 76abc6818..724241935 100644 --- a/src/Blocks/BlockPumpkin.h +++ b/src/Blocks/BlockPumpkin.h @@ -13,6 +13,70 @@ public: : cBlockHandler(a_BlockType) { } + + virtual void OnPlacedByPlayer(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, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + { + // Check whether the pumpkin is a part of a golem or a snowman + + if (a_BlockY < 2) + { + // The pumpkin is too low for a golem / snowman + return; + } + + BLOCKTYPE BlockY1 = a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + BLOCKTYPE BlockY2 = a_World->GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ); + + // Check for a snow golem: + if ((BlockY1 == E_BLOCK_SNOW_BLOCK) && (BlockY2 == E_BLOCK_SNOW_BLOCK)) + { + a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_World->FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_World->FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); + a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtSnowGolem); + return; + } + + // Check for an iron golem. First check only the body and legs, since those are the same for both orientations: + if ((BlockY1 != E_BLOCK_IRON_BLOCK) || (BlockY2 != E_BLOCK_IRON_BLOCK)) + { + // One of the blocks is not an iron, no chance of a golem here + return; + } + + // Now check both orientations for hands: + if ( + (a_World->GetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ) == E_BLOCK_IRON_BLOCK) && + (a_World->GetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ) == E_BLOCK_IRON_BLOCK) + ) + { + // Remove the iron blocks: + a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_World->FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_World->FastSetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_World->FastSetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_World->FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); + + // Spawn the golem: + a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtIronGolem); + } + else if ( + (a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1) == E_BLOCK_IRON_BLOCK) && + (a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1) == E_BLOCK_IRON_BLOCK) + ) + { + // Remove the iron blocks: + a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_World->FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_World->FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1, E_BLOCK_AIR, 0); + a_World->FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1, E_BLOCK_AIR, 0); + a_World->FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); + + // Spawn the golem: + a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtIronGolem); + } + } + virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index 24a101652..55cadfa48 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -43,6 +43,40 @@ public: } + virtual void OnPlaced(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + { + super::OnPlaced(a_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta); + + // Alert diagonal rails + OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY + 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY + 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ + 1); + OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ - 1); + + OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY - 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY - 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ + 1); + OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ - 1); + } + + + virtual void OnDestroyed(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override + { + super::OnDestroyed(a_World, a_BlockX, a_BlockY, a_BlockZ); + + // Alert diagonal rails + OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY + 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY + 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ + 1); + OnNeighborChanged(a_World, a_BlockX, a_BlockY + 1, a_BlockZ - 1); + + OnNeighborChanged(a_World, a_BlockX + 1, a_BlockY - 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX - 1, a_BlockY - 1, a_BlockZ); + OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ + 1); + OnNeighborChanged(a_World, a_BlockX, a_BlockY - 1, a_BlockZ - 1); + } + + virtual void OnNeighborChanged(cWorld *a_World, int a_BlockX, int a_BlockY, int a_BlockZ) override { NIBBLETYPE Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 00c3059b5..88e469b74 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,72 +12,81 @@ include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include") set(FOLDERS OSSupport HTTPServer Bindings Items Blocks Protocol Generating) set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities) -if(NOT WIN32) -foreach(folder ${FOLDERS}) - add_subdirectory(${folder}) -endforeach(folder) -file(GLOB SOURCE - "*.cpp" -) -else() +if (NOT WIN32) + foreach(folder ${FOLDERS}) + add_subdirectory(${folder}) + endforeach(folder) -function(includefolder PATH) - FILE(GLOB FOLDER_FILES - "${PATH}/*.cpp" - "${PATH}/*.h" + file(GLOB SOURCE + "*.cpp" ) - source_group("${PATH}" FILES ${FOLDER_FILES}) -endfunction(includefolder) + list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/StackWalker.cpp" "${PROJECT_SOURCE_DIR}/LeakFinder.cpp") -foreach(folder ${FOLDERS}) - includefolder(${folder}) -endforeach(folder) +else () -file(GLOB_RECURSE SOURCE - "*.cpp" - "*.h" -) + function(includefolder PATH) + FILE(GLOB FOLDER_FILES + "${PATH}/*.cpp" + "${PATH}/*.h" + ) + source_group("${PATH}" FILES ${FOLDER_FILES}) + endfunction(includefolder) -include_directories("${PROJECT_SOURCE_DIR}") + foreach(folder ${FOLDERS}) + includefolder(${folder}) + endforeach(folder) -source_group("" FILES ${SOURCE}) - -#precompiledheaders + file(GLOB_RECURSE SOURCE + "*.cpp" + "*.h" + ) -file(GLOB_RECURSE HEADERS - "*.h" -) + include_directories("${PROJECT_SOURCE_DIR}") -foreach(header ${HEADERS}) - set(FLAGS "/Yu ${header} /Yc ${header}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAGS}") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAGS}") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAGS}") - set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${FLAGS}") - set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_PROFILE} ${FLAGS}") - set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_PROFILE} ${FLAGS}") -endforeach() + source_group("" FILES ${SOURCE}) + # Precompiled headers (1st part) + SET_SOURCE_FILES_PROPERTIES( + Globals.cpp PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\"" + ) + # CMake cannot "remove" the precompiled header flags, so we use a dummy precompiled header compatible with just this one file: + SET_SOURCE_FILES_PROPERTIES( + Bindings/Bindings.cpp PROPERTIES COMPILE_FLAGS "/Yc\"string.h\" /Fp\"$(IntDir)/Bindings.pch\"" + ) + SET_SOURCE_FILES_PROPERTIES( + "StackWalker.cpp LeakFinder.h" PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\"" + ) endif() -list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/StackWalker.cpp" "${PROJECT_SOURCE_DIR}/LeakFinder.cpp") -if(UNIX) +if (UNIX) set(EXECUTABLE ../MCServer/MCServer) -else() +else () set(EXECUTABLE MCServer) -endif() +endif () + add_executable(${EXECUTABLE} ${SOURCE}) -if(NOT WIN32) -target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks) -target_link_libraries(${EXECUTABLE} Protocol Generating WorldStorage) -target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities) + +# Precompiled headers (2nd part) +if (WIN32) + SET_TARGET_PROPERTIES( + ${EXECUTABLE} PROPERTIES COMPILE_FLAGS "/Yu\"Globals.h\"" + OBJECT_DEPENDS "$(IntDir)/$(TargetName.pch)" + ) +endif () + + +if (NOT WIN32) + target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks) + target_link_libraries(${EXECUTABLE} Protocol Generating WorldStorage) + target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities) +endif () +if (WIN32) + target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib) endif() -target_link_libraries(${EXECUTABLE} md5 luaexpat iniFile jsoncpp cryptopp zlib lua) +target_link_libraries(${EXECUTABLE} md5 luaexpat iniFile jsoncpp cryptopp zlib lua sqlite) diff --git a/src/ChatColor.cpp b/src/ChatColor.cpp index 2b223ee76..72a0a6928 100644 --- a/src/ChatColor.cpp +++ b/src/ChatColor.cpp @@ -1,4 +1,3 @@ - #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "ChatColor.h" @@ -29,11 +28,5 @@ const std::string cChatColor::Underlined = cChatColor::Color + "n"; const std::string cChatColor::Italic = cChatColor::Color + "o"; const std::string cChatColor::Plain = cChatColor::Color + "r"; -const std::string cChatColor::MakeColor( char a_Color ) -{ - return cChatColor::Color + a_Color; -} - - diff --git a/src/ChatColor.h b/src/ChatColor.h index 85b10f400..643c4d5d8 100644 --- a/src/ChatColor.h +++ b/src/ChatColor.h @@ -29,15 +29,14 @@ public: static const std::string Yellow; static const std::string White; - // Styles ( source: http://wiki.vg/Chat ) - static const std::string Random; - static const std::string Bold; - static const std::string Strikethrough; - static const std::string Underlined; - static const std::string Italic; - static const std::string Plain; - - static const std::string MakeColor( char a_Color ); + // Styles ( source: http://wiki.vg/Chat ) + static const std::string Random; + static const std::string Bold; + static const std::string Strikethrough; + static const std::string Underlined; + static const std::string Italic; + static const std::string Plain; + }; // tolua_end diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 3c44b91d0..c446db9a6 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -2745,6 +2745,22 @@ void cChunk::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation +void cChunk::BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude) +{ + for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr ) + { + if (*itr == a_Exclude) + { + continue; + } + (*itr)->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount); + } // for itr - LoadedByClient[] +} + + + + + void cChunk::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude) { for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr ) diff --git a/src/Chunk.h b/src/Chunk.h index 1d762c0ca..05a96d419 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -277,6 +277,7 @@ public: void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL); + void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL); void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL); void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8 void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index c67d8e2e8..86fbceff7 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -605,6 +605,25 @@ void cChunkMap::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animat +void cChunkMap::BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude) +{ + cCSLock Lock(m_CSLayers); + int ChunkX, ChunkZ; + + cChunkDef::BlockToChunk((int) a_SrcX, (int) a_SrcZ, ChunkX, ChunkZ); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); + if (Chunk == NULL) + { + return; + } + // It's perfectly legal to broadcast packets even to invalid chunks! + Chunk->BroadcastParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount, a_Exclude); +} + + + + + void cChunkMap::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); diff --git a/src/ChunkMap.h b/src/ChunkMap.h index dcc6abdc3..e688d1f93 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -74,6 +74,7 @@ public: void BroadcastEntityStatus(const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); void BroadcastEntityVelocity(const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL); + void BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL); void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL); void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8 void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 65b376d38..99df47bfb 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1872,6 +1872,15 @@ void cClientHandle::SendInventorySlot(char a_WindowID, short a_SlotNum, const cI +void cClientHandle::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) +{ + m_Protocol->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount); +} + + + + + void cClientHandle::SendPickupSpawn(const cPickup & a_Pickup) { m_Protocol->SendPickupSpawn(a_Pickup); diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 6f82d5d46..26d5e74b7 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -113,6 +113,7 @@ public: void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item); void SendPickupSpawn (const cPickup & a_Pickup); void SendEntityAnimation (const cEntity & a_Entity, char a_Animation); + void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount); void SendPlayerAbilities (void); void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline); void SendPlayerMaxSpeed (void); ///< Informs the client of the maximum player speed (1.6.1+) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 8fcdcc82f..8a74c9da4 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -13,6 +13,7 @@ #include "../Bindings/PluginManager.h" #include "../Tracer.h" #include "Minecart.h" +#include "Player.h" @@ -239,10 +240,14 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R TDI.Attacker = a_Attacker; TDI.RawDamage = a_RawDamage; TDI.FinalDamage = a_FinalDamage; - Vector3d Heading; - Heading.x = sin(GetRotation()); - Heading.y = 0.4; // TODO: adjust the amount of "up" knockback when testing - Heading.z = cos(GetRotation()); + + Vector3d Heading(0, 0, 0); + if (a_Attacker != NULL) + { + Heading = a_Attacker->GetLookVector() * (a_Attacker->IsSprinting() ? 10 : 8); + } + Heading.y = 2; + TDI.Knockback = Heading * a_KnockbackAmount; DoTakeDamage(TDI); } @@ -297,6 +302,16 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) return; } + if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) + { + // IsOnGround() only is false if the player is moving downwards + if (!((cPlayer *)a_TDI.Attacker)->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain) + { + a_TDI.FinalDamage += 2; + m_World->BroadcastEntityAnimation(*this, 4); // Critical hit + } + } + m_Health -= (short)a_TDI.FinalDamage; // TODO: Apply damage to armor @@ -306,6 +321,8 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) m_Health = 0; } + AddSpeed(a_TDI.Knockback * 2); + m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT); if (m_Health <= 0) diff --git a/src/Entities/Floater.cpp b/src/Entities/Floater.cpp index ac7a82f91..dfe77f059 100644 --- a/src/Entities/Floater.cpp +++ b/src/Entities/Floater.cpp @@ -1,6 +1,8 @@ #include "Globals.h" +#include "../BoundingBox.h" +#include "../Chunk.h" #include "Floater.h" #include "Player.h" #include "../ClientHandle.h" @@ -9,11 +11,103 @@ -cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID) : - cEntity(etFloater, a_X, a_Y, a_Z, 0.98, 0.98), +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cFloaterEntityCollisionCallback +class cFloaterEntityCollisionCallback : + public cEntityCallback +{ +public: + cFloaterEntityCollisionCallback(cFloater * a_Floater, const Vector3d & a_Pos, const Vector3d & a_NextPos) : + m_Floater(a_Floater), + m_Pos(a_Pos), + m_NextPos(a_NextPos), + m_MinCoeff(1), + m_HitEntity(NULL) + { + } + virtual bool Item(cEntity * a_Entity) override + { + if (!a_Entity->IsMob()) // Floaters can only pull mobs not other entities. + { + return false; + } + + cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); + + double LineCoeff; + char Face; + EntBox.Expand(m_Floater->GetWidth() / 2, m_Floater->GetHeight() / 2, m_Floater->GetWidth() / 2); + if (!EntBox.CalcLineIntersection(m_Pos, m_NextPos, LineCoeff, Face)) + { + // No intersection whatsoever + return false; + } + + if (LineCoeff < m_MinCoeff) + { + // The entity is closer than anything we've stored so far, replace it as the potential victim + m_MinCoeff = LineCoeff; + m_HitEntity = a_Entity; + } + + // Don't break the enumeration, we want all the entities + return false; + } + + /// Returns the nearest entity that was hit, after the enumeration has been completed + cEntity * GetHitEntity(void) const { return m_HitEntity; } + + /// Returns true if the callback has encountered a true hit + bool HasHit(void) const { return (m_MinCoeff < 1); } + +protected: + cFloater * m_Floater; + const Vector3d & m_Pos; + const Vector3d & m_NextPos; + double m_MinCoeff; // The coefficient of the nearest hit on the Pos line + + // Although it's bad(tm) to store entity ptrs from a callback, we can afford it here, because the entire callback + // is processed inside the tick thread, so the entities won't be removed in between the calls and the final processing + cEntity * m_HitEntity; // The nearest hit entity +} ; + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cFloaterCheckEntityExist +class cFloaterCheckEntityExist : + public cEntityCallback +{ +public: + cFloaterCheckEntityExist(void) : + m_EntityExists(false) + { + } + + bool Item(cEntity * a_Entity) override + { + m_EntityExists = true; + return false; + } + + bool DoesExist(void) const { return m_EntityExists; } +protected: + bool m_EntityExists; +} ; + + + + + +cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime) : + cEntity(etFloater, a_X, a_Y, a_Z, 0.2, 0.2), m_PickupCountDown(0), m_PlayerID(a_PlayerID), - m_CanPickupItem(false) + m_CanPickupItem(false), + m_CountDownTime(a_CountDownTime), + m_AttachedMobID(-1) { SetSpeed(a_Speed); } @@ -36,21 +130,49 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk) HandlePhysics(a_Dt, a_Chunk); if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())) && m_World->GetBlockMeta((int) GetPosX(), (int) GetPosY(), (int) GetPosZ()) == 0) { - if ((!m_CanPickupItem) && (m_World->GetTickRandomNumber(100) == 0)) - { - SetPosY(GetPosY() - 1); - m_CanPickupItem = true; - m_PickupCountDown = 20; - LOGD("Floater %i can be picked up", GetUniqueID()); - } - else + if ((!m_CanPickupItem) && (m_AttachedMobID == -1)) // Check if you can't already pickup a fish and if the floater isn't attached to a mob. { - SetSpeedY(0.7); + if (m_CountDownTime <= 0) + { + m_World->BroadcastSoundEffect("random.splash", (int) floor(GetPosX() * 8), (int) floor(GetPosY() * 8), (int) floor(GetPosZ() * 8), 1, 1); + SetPosY(GetPosY() - 1); + m_CanPickupItem = true; + m_PickupCountDown = 20; + m_CountDownTime = 100 + m_World->GetTickRandomNumber(800); + LOGD("Floater %i can be picked up", GetUniqueID()); + } + else if (m_CountDownTime == 20) // Calculate the position where the particles should spawn and start producing them. + { + LOGD("Started producing particles for floater %i", GetUniqueID()); + m_ParticlePos.Set(GetPosX() + (-4 + m_World->GetTickRandomNumber(8)), GetPosY(), GetPosZ() + (-4 + m_World->GetTickRandomNumber(8))); + m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15); + } + else if (m_CountDownTime < 20) + { + m_ParticlePos = (m_ParticlePos + (GetPosition() - m_ParticlePos) / 6); + m_World->BroadcastParticleEffect("splash", (float) m_ParticlePos.x, (float) m_ParticlePos.y, (float) m_ParticlePos.z, 0, 0, 0, 0, 15); + } + + m_CountDownTime--; + if (m_World->GetHeight((int) GetPosX(), (int) GetPosZ()) == (int) GetPosY()) + { + if (m_World->IsWeatherWet() && m_World->GetTickRandomNumber(3) == 0) // 25% chance of an extra countdown when being rained on. + { + m_CountDownTime--; + } + } + else // if the floater is underground it has a 50% chance of not decreasing the countdown. + { + if (m_World->GetTickRandomNumber(1) == 0) + { + m_CountDownTime++; + } + } } + SetSpeedY(0.7); } - SetSpeedX(GetSpeedX() * 0.95); - SetSpeedZ(GetSpeedZ() * 0.95); - if (CanPickup()) + + if (CanPickup()) // Make sure the floater "loses its fish" { m_PickupCountDown--; if (m_PickupCountDown == 0) @@ -59,9 +181,38 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk) LOGD("The fish is gone. Floater %i can not pick an item up.", GetUniqueID()); } } - BroadcastMovementUpdate(); -} + if ((GetSpeed().Length() > 4) && (m_AttachedMobID == -1)) + { + cFloaterEntityCollisionCallback Callback(this, GetPosition(), GetPosition() + GetSpeed() / 20); + + a_Chunk.ForEachEntity(Callback); + if (Callback.HasHit()) + { + AttachTo(Callback.GetHitEntity()); + Callback.GetHitEntity()->TakeDamage(*this); // TODO: the player attacked the mob not the floater. + m_AttachedMobID = Callback.GetHitEntity()->GetUniqueID(); + } + } + cFloaterCheckEntityExist EntityCallback; + m_World->DoWithEntityByID(m_PlayerID, EntityCallback); + if (!EntityCallback.DoesExist()) // The owner doesn't exist anymore. Destroy the floater entity. + { + Destroy(true); + } + if (m_AttachedMobID != -1) + { + m_World->DoWithEntityByID(m_AttachedMobID, EntityCallback); // The mob the floater was attached to doesn't exist anymore. + if (!EntityCallback.DoesExist()) + { + m_AttachedMobID = -1; + } + } + + SetSpeedX(GetSpeedX() * 0.95); + SetSpeedZ(GetSpeedZ() * 0.95); + BroadcastMovementUpdate(); +}
\ No newline at end of file diff --git a/src/Entities/Floater.h b/src/Entities/Floater.h index 9bc5039f8..4bbe3f352 100644 --- a/src/Entities/Floater.h +++ b/src/Entities/Floater.h @@ -14,16 +14,27 @@ class cFloater : public: - cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID); + cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime); virtual void SpawnOn(cClientHandle & a_Client) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - bool CanPickup(void) const { return m_CanPickupItem; } + bool CanPickup(void) const { return m_CanPickupItem; } + int GetOwnerID(void) const { return m_PlayerID; } + int GetAttachedMobID(void) const { return m_AttachedMobID; } protected: - Vector3d m_Speed; + // Position + Vector3d m_ParticlePos; + + // Bool needed to check if you can get a fish. + bool m_CanPickupItem; + + // Countdown times int m_PickupCountDown; + int m_CountDownTime; + + // Entity IDs int m_PlayerID; - bool m_CanPickupItem; + int m_AttachedMobID; } ;
\ No newline at end of file diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 8f30cd4cc..67d5a47ef 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -240,6 +240,11 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) HandleFood(); } + if (m_IsFishing) + { + HandleFloater(); + } + // Send Player List (Once per m_LastPlayerListTime/1000 ms) cTimer t1; if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime()) @@ -247,6 +252,11 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) m_World->SendPlayerList(this); m_LastPlayerListTime = t1.GetNowTime(); } + + if (IsFlying()) + { + m_LastGroundHeight = (float)GetPosY(); + } } @@ -447,10 +457,16 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) if (m_LastJumpHeight > m_LastGroundHeight) Damage++; m_LastJumpHeight = (float)GetPosY(); - if ((Damage > 0) && (!IsGameModeCreative())) + if (Damage > 0) { - TakeDamage(dtFalling, NULL, Damage, Damage, 0); - } + if (!IsGameModeCreative()) + { + TakeDamage(dtFalling, NULL, Damage, Damage, 0); + } + + // Mojang uses floor() to get X and Z positions, instead of just casting it to an (int) + GetWorld()->BroadcastSoundParticleEffect(2006, (int)floor(GetPosX()), (int)GetPosY() - 1, (int)floor(GetPosZ()), Damage /* Used as particle effect speed modifier */); + } m_LastGroundHeight = (float)GetPosY(); } @@ -804,6 +820,22 @@ void cPlayer::KilledBy(cEntity * a_Killer) m_Inventory.Clear(); m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10); SaveToDisk(); // Save it, yeah the world is a tough place ! + + if (a_Killer == NULL) + { + GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by environmental damage", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str())); + } + else if (a_Killer->IsPlayer()) + { + GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by %s", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str(), ((cPlayer *)a_Killer)->GetName().c_str())); + } + else + { + AString KillerClass = a_Killer->GetClass(); + KillerClass.erase(KillerClass.begin()); // Erase the 'c' of the class (e.g. "cWitch" -> "Witch") + + GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by a %s", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str(), KillerClass.c_str())); + } } @@ -974,6 +1006,12 @@ void cPlayer::SetGameMode(eGameMode a_GameMode) m_GameMode = a_GameMode; m_ClientHandle->SendGameMode(a_GameMode); + + if (!IsGameModeCreative()) + { + SetFlying(false); + SetCanFly(false); + } } @@ -1289,7 +1327,7 @@ AString cPlayer::GetColor(void) const { if ( m_Color != '-' ) { - return cChatColor::MakeColor( m_Color ); + return cChatColor::Color + m_Color; } if ( m_Groups.size() < 1 ) @@ -1781,6 +1819,30 @@ void cPlayer::HandleFood(void) +void cPlayer::HandleFloater() +{ + if (GetEquippedItem().m_ItemType == E_ITEM_FISHING_ROD) + { + return; + } + class cFloaterCallback : + public cEntityCallback + { + public: + virtual bool Item(cEntity * a_Entity) override + { + a_Entity->Destroy(true); + return true; + } + } Callback; + m_World->DoWithEntityByID(m_FloaterID, Callback); + SetIsFishing(false); +} + + + + + void cPlayer::ApplyFoodExhaustionFromMovement() { if (IsGameModeCreative()) diff --git a/src/Entities/Player.h b/src/Entities/Player.h index c0ad9eeac..66f1c07a7 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -466,6 +466,9 @@ protected: /// Called in each tick to handle food-related processing void HandleFood(void); + + /// Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item. + void HandleFloater(void); /// Called in each tick to handle air-related processing i.e. drowning void HandleAir(); diff --git a/src/Generating/DistortedHeightmap.cpp b/src/Generating/DistortedHeightmap.cpp index 342a4483f..15e352e30 100644 --- a/src/Generating/DistortedHeightmap.cpp +++ b/src/Generating/DistortedHeightmap.cpp @@ -101,7 +101,21 @@ static cDistortedHeightmap::sBlockInfo tbMycelium[] = {E_BLOCK_DIRT, 0}, } ; +static cDistortedHeightmap::sBlockInfo tbGravel[] = +{ + {E_BLOCK_GRAVEL, 0}, + {E_BLOCK_GRAVEL, 0}, + {E_BLOCK_GRAVEL, 0}, + {E_BLOCK_STONE, 0}, +} ; +static cDistortedHeightmap::sBlockInfo tbStone[] = +{ + {E_BLOCK_STONE, 0}, + {E_BLOCK_STONE, 0}, + {E_BLOCK_STONE, 0}, + {E_BLOCK_STONE, 0}, +} ; @@ -146,6 +160,8 @@ static cPattern patDirt (tbDirt, ARRAYCOUNT(tbDirt)); static cPattern patPodzol (tbPodzol, ARRAYCOUNT(tbPodzol)); static cPattern patGrassLess(tbGrassLess, ARRAYCOUNT(tbGrassLess)); static cPattern patMycelium (tbMycelium, ARRAYCOUNT(tbMycelium)); +static cPattern patGravel (tbGravel, ARRAYCOUNT(tbGravel)); +static cPattern patStone (tbStone, ARRAYCOUNT(tbStone)); static cPattern patOFSand (tbOFSand, ARRAYCOUNT(tbOFSand)); static cPattern patOFClay (tbOFClay, ARRAYCOUNT(tbOFClay)); @@ -648,7 +664,6 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in { case biOcean: case biPlains: - case biExtremeHills: case biForest: case biTaiga: case biSwampland: @@ -671,11 +686,9 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in case biRoofedForest: case biColdTaiga: case biColdTaigaHills: - case biExtremeHillsPlus: case biSavanna: case biSavannaPlateau: case biSunflowerPlains: - case biExtremeHillsM: case biFlowerForest: case biTaigaM: case biSwamplandM: @@ -686,7 +699,6 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in case biBirchForestHillsM: case biRoofedForestM: case biColdTaigaM: - case biExtremeHillsPlusM: case biSavannaM: case biSavannaPlateauM: { @@ -737,6 +749,30 @@ void cDistortedHeightmap::ComposeColumn(cChunkDesc & a_ChunkDesc, int a_RelX, in FillColumnMesa(a_ChunkDesc, a_RelX, a_RelZ); return; } + + case biExtremeHillsPlus: + case biExtremeHills: + { + // Select the pattern to use - stone or grass: + NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX; + NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ; + NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY); + const sBlockInfo * Pattern = (Val < -0.1) ? patStone.Get() : patGrass.Get(); + FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern); + return; + } + + case biExtremeHillsPlusM: + case biExtremeHillsM: + { + // Select the pattern to use - gravel, stone or grass: + NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX)) / FrequencyX; + NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ)) / FrequencyZ; + NOISE_DATATYPE Val = m_OceanFloorSelect.CubicNoise2D(NoiseX, NoiseY); + const sBlockInfo * Pattern = (Val < -0.9) ? patStone.Get() : ((Val > 0) ? patGravel.Get() : patGrass.Get()); + FillColumnPattern(a_ChunkDesc, a_RelX, a_RelZ, Pattern); + return; + } default: ASSERT(!"Unhandled biome"); return; diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index fbed57cb6..7e8a3c75f 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -216,7 +216,14 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); break; } - + + case biBirchForestM: + case biBirchForestHillsM: + { + GetTallBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); + break; + } + case biRoofedForest: case biColdTaiga: case biColdTaigaHills: @@ -237,8 +244,6 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No case biIcePlainsSpikes: case biJungleM: case biJungleEdgeM: - case biBirchForestM: - case biBirchForestHillsM: case biRoofedForestM: case biColdTaigaM: case biMegaSpruceTaiga: @@ -377,6 +382,44 @@ void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Nois +void GetTallBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks) +{ + int Height = 9 + (a_Noise.IntNoise3DInt(a_BlockX + 64 * a_Seq, a_BlockY, a_BlockZ) % 3); + + // Prealloc, so that we don't realloc too often later: + a_LogBlocks.reserve(Height); + a_OtherBlocks.reserve(80); + + // The entire trunk, out of logs: + for (int i = Height - 1; i >= 0; --i) + { + a_LogBlocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_LOG, E_META_LOG_BIRCH)); + } + int h = a_BlockY + Height; + + // Top layer - just the Plus: + PushCoordBlocks(a_BlockX, h, a_BlockZ, a_OtherBlocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH); + a_OtherBlocks.push_back(sSetBlock(a_BlockX, h, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH)); // There's no log at this layer + h--; + + // Second layer - log, Plus and maybe Corners: + PushCoordBlocks (a_BlockX, h, a_BlockZ, a_OtherBlocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH); + PushCornerBlocks(a_BlockX, h, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_OtherBlocks, 1, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH); + h--; + + // Third and fourth layers - BigO2 and maybe 2*Corners: + for (int Row = 0; Row < 2; Row++) + { + PushCoordBlocks (a_BlockX, h, a_BlockZ, a_OtherBlocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH); + PushCornerBlocks(a_BlockX, h, a_BlockZ, a_Seq, a_Noise, 0x3fffffff + Row * 0x10000000, a_OtherBlocks, 2, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH); + h--; + } // for Row - 2* +} + + + + + void GetConiferTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks) { // Half chance for a spruce, half for a pine: diff --git a/src/Generating/Trees.h b/src/Generating/Trees.h index f5148ad6f..514158eb7 100644 --- a/src/Generating/Trees.h +++ b/src/Generating/Trees.h @@ -63,6 +63,9 @@ void GetLargeAppleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a /// Generates an image of a random birch tree void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks); +/// Generates an image of a random large birch tree +void GetTallBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks,sSetBlockVector & a_OtherBlocks); + /// Generates an image of a random conifer tree void GetConiferTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks); diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index 1ffe3812f..792acc2c3 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -79,11 +79,11 @@ cGroupManager::cGroupManager() Group->SetName( KeyName ); char Color = IniFile.GetValue( KeyName, "Color", "-" )[0]; if( Color != '-' ) - Group->SetColor( cChatColor::MakeColor(Color) ); + Group->SetColor( cChatColor::Color + Color ); else Group->SetColor( cChatColor::White ); - std::string Commands = IniFile.GetValue( KeyName, "Commands", "" ); + AString Commands = IniFile.GetValue( KeyName, "Commands", "" ); if( Commands.size() > 0 ) { AStringVector Split = StringSplit( Commands, "," ); @@ -93,7 +93,7 @@ cGroupManager::cGroupManager() } } - std::string Permissions = IniFile.GetValue( KeyName, "Permissions", "" ); + AString Permissions = IniFile.GetValue( KeyName, "Permissions", "" ); if( Permissions.size() > 0 ) { AStringVector Split = StringSplit( Permissions, "," ); diff --git a/src/ItemGrid.cpp b/src/ItemGrid.cpp index e9b86173e..d2e6b1c69 100644 --- a/src/ItemGrid.cpp +++ b/src/ItemGrid.cpp @@ -580,11 +580,11 @@ bool cItemGrid::DamageItem(int a_X, int a_Y, short a_Amount) -void cItemGrid::GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, int a_CountLootProbabs, int a_NumSlots, int a_Seed) +void cItemGrid::GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, size_t a_CountLootProbabs, int a_NumSlots, int a_Seed) { // Calculate the total weight: int TotalProbab = 1; - for (int i = 0; i < a_CountLootProbabs; i++) + for (size_t i = 0; i < a_CountLootProbabs; i++) { TotalProbab += a_LootProbabs[i].m_Weight; } @@ -597,7 +597,7 @@ void cItemGrid::GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, i int LootRnd = Rnd % TotalProbab; Rnd >>= 8; cItem CurrentLoot = cItem(E_ITEM_BOOK, 1, 0); // TODO: enchantment - for (int j = 0; j < a_CountLootProbabs; j++) + for (size_t j = 0; j < a_CountLootProbabs; j++) { LootRnd -= a_LootProbabs[i].m_Weight; if (LootRnd < 0) diff --git a/src/ItemGrid.h b/src/ItemGrid.h index a4af523cf..b344e3daf 100644 --- a/src/ItemGrid.h +++ b/src/ItemGrid.h @@ -157,7 +157,7 @@ public: A total of a_NumSlots are taken by the loot. Cannot export to Lua due to raw array a_LootProbabs. TODO: Make this exportable / export through ManualBindings.cpp with a Lua table as LootProbabs */ - void GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, int a_CountLootProbabs, int a_NumSlots, int a_Seed); + void GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, size_t a_CountLootProbabs, int a_NumSlots, int a_Seed); /// Adds a callback that gets called whenever a slot changes. Must not be called from within the listener callback! void AddListener(cListener & a_Listener); diff --git a/src/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h index 87021fbd2..941ce3b71 100644 --- a/src/Items/ItemFishingRod.h +++ b/src/Items/ItemFishingRod.h @@ -15,6 +15,61 @@ +///////////////////////////////////////////////////////////////////////////////////// +// cFloaterCallback +class cFloaterCallback : + public cEntityCallback +{ +public: + cFloaterCallback(void) : + m_CanPickup(false), + m_AttachedMobID(-1) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + m_CanPickup = ((cFloater *)a_Entity)->CanPickup(); + m_Pos = Vector3d(a_Entity->GetPosX(), a_Entity->GetPosY(), a_Entity->GetPosZ()); + m_AttachedMobID = ((cFloater *)a_Entity)->GetAttachedMobID(); + a_Entity->Destroy(true); + return true; + } + + bool CanPickup(void) const { return m_CanPickup; } + bool IsAttached(void) const { return (m_AttachedMobID != -1); } + int GetAttachedMobID(void) const { return m_AttachedMobID; } + Vector3d GetPos(void) const { return m_Pos; } + +protected: + bool m_CanPickup; + int m_AttachedMobID; + Vector3d m_Pos; +} ; + +//////////////////////////////////////////////////////////////////////////// +// cSweepEntityCallback +class cSweepEntityCallback : + public cEntityCallback +{ +public: + cSweepEntityCallback(Vector3d a_PlayerPos) : + m_PlayerPos(a_PlayerPos) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + Vector3d Speed = m_PlayerPos - a_Entity->GetPosition(); + a_Entity->AddSpeed(Speed); + return true; + } + +protected: + Vector3d m_PlayerPos; +} ; + + class cItemFishingRodHandler : public cItemHandler @@ -36,45 +91,134 @@ public: if (a_Player->IsFishing()) { - class cFloaterCallback : - public cEntityCallback + cFloaterCallback FloaterInfo; + a_World->DoWithEntityByID(a_Player->GetFloaterID(), FloaterInfo); + a_Player->SetIsFishing(false); + + if (FloaterInfo.IsAttached()) + { + cSweepEntityCallback SweepEntity(a_Player->GetPosition()); + a_World->DoWithEntityByID(FloaterInfo.GetAttachedMobID(), SweepEntity); + } + else if (FloaterInfo.CanPickup()) { - public: - cFloaterCallback(void) : - m_CanPickup(false) + cItems Drops; + int ItemCategory = a_World->GetTickRandomNumber(99); + if (ItemCategory <= 4) // Treasures 5% { + int Treasure = a_World->GetTickRandomNumber(5); + switch (Treasure) + { + case 0: + { + Drops.Add(cItem(E_ITEM_BOW)); // TODO: Enchantments + break; + } + case 1: + { + Drops.Add(cItem(E_ITEM_BOOK)); // TODO: Enchanted book + break; + } + case 2: + { + Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, a_World->GetTickRandomNumber(50))); // Fishing rod with durability. TODO: Enchantments on it + break; + } + case 3: + { + Drops.Add(cItem(E_ITEM_NAME_TAG)); + break; + } + case 4: + { + Drops.Add(cItem(E_ITEM_SADDLE)); + break; + } + case 5: + { + Drops.Add(cItem(E_BLOCK_LILY_PAD)); + break; + } + } } - - bool CanPickup(void) const { return m_CanPickup; } - Vector3d GetPos(void) const { return m_Pos; } - - virtual bool Item(cEntity * a_Entity) override + else if (ItemCategory <= 14) // Junk 10% { - m_CanPickup = ((cFloater *)a_Entity)->CanPickup(); - m_Pos = Vector3d(a_Entity->GetPosX(), a_Entity->GetPosY(), a_Entity->GetPosZ()); - a_Entity->Destroy(true); - return true; + int Junk = a_World->GetTickRandomNumber(70); + if (Junk <= 1) + { + Drops.Add(cItem(E_ITEM_DYE, 10, 0)); + } + else if (Junk <= 4) + { + Drops.Add(cItem(E_ITEM_BOW, 1, a_World->GetTickRandomNumber(64))); + } + else if (Junk <= 9) + { + Drops.Add(cItem(E_ITEM_STICK)); + } + else if (Junk <= 14) + { + Drops.Add(cItem(E_ITEM_STRING)); + } + else if (Junk <= 22) + { + Drops.Add(cItem(E_ITEM_BOWL)); + } + else if (Junk <= 30) + { + Drops.Add(cItem(E_ITEM_LEATHER)); + } + else if (Junk <= 38) + { + Drops.Add(cItem(E_ITEM_LEATHER_BOOTS)); + } + else if (Junk <= 46) + { + Drops.Add(cItem(E_ITEM_ROTTEN_FLESH)); + } + else if (Junk <= 54) + { + Drops.Add(cItem(E_ITEM_POTIONS)); + } + else if (Junk <= 62) + { + Drops.Add(cItem(E_ITEM_BONE)); + } + else if (Junk <= 70) + { + Drops.Add(cItem(E_BLOCK_TRIPWIRE_HOOK)); + } + } + else // Fish + { + int FishType = a_World->GetTickRandomNumber(99); + if (FishType <= 1) // Clownfish has a 2% chance of spawning + { + Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH)); + } + else if (FishType <= 12) // Pufferfish has a 13% chance of spawning + { + Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH)); + } + else if (FishType <= 24) + { + Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_SALMON)); + } + else + { + Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_FISH)); + } } - protected: - bool m_CanPickup; - Vector3d m_Pos; - } Callbacks; - a_World->DoWithEntityByID(a_Player->GetFloaterID(), Callbacks); - a_Player->SetIsFishing(false); - if (Callbacks.CanPickup()) - { - cItems Drops; - Drops.Add(cItem(E_ITEM_RAW_FISH)); - Vector3d FloaterPos(Callbacks.GetPos()); - Vector3d FlyDirection(a_Player->GetPosition() - FloaterPos); - a_World->SpawnItemPickups(Drops, FloaterPos.x, FloaterPos.y, FloaterPos.z, FlyDirection.x, FlyDirection.Length() / (FlyDirection.y * 2), FlyDirection.z); - // TODO: More types of pickups. + + Vector3d FloaterPos = FloaterInfo.GetPos(); + Vector3d FlyDirection = a_Player->GetEyePosition() - FloaterPos; + a_World->SpawnItemPickups(Drops, FloaterPos.x, FloaterPos.y, FloaterPos.z, FlyDirection.x, FlyDirection.y + 1, FlyDirection.z); } } else { - cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID()); + cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), 100 + a_World->GetTickRandomNumber(800) - (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100)); Floater->Initialize(a_World); a_Player->SetIsFishing(true, Floater->GetUniqueID()); } diff --git a/src/LeakFinder.cpp b/src/LeakFinder.cpp index 0f84adb2b..9d7f185ba 100644 --- a/src/LeakFinder.cpp +++ b/src/LeakFinder.cpp @@ -95,15 +95,11 @@ * **********************************************************************/ -#include <windows.h> -#include <objidl.h> // Needed if compiled with "WIN32_LEAN_AND_MEAN" +#include "Globals.h" + #include <tchar.h> +#include <objidl.h> // Needed if compiled with "WIN32_LEAN_AND_MEAN" #include <crtdbg.h> -#include <stdio.h> - -#include <string> -#include <vector> - #include "LeakFinder.h" @@ -463,11 +459,11 @@ public: pHashEntry->nDataSize = nDataSize; pHashEntry->Next = NULL; #ifdef _M_IX86 - pHashEntry->pCallstackOffset = (LPVOID) min(context.Ebp, context.Esp); + pHashEntry->pCallstackOffset = (LPVOID) std::min(context.Ebp, context.Esp); #elif _M_X64 - pHashEntry->pCallstackOffset = (LPVOID) min(context.Rdi, context.Rsp); + pHashEntry->pCallstackOffset = (LPVOID) std::min(context.Rdi, context.Rsp); #elif _M_IA64 - pHashEntry->pCallstackOffset = (LPVOID) min(context.IntSp, context.RsBSP); + pHashEntry->pCallstackOffset = (LPVOID) std::min(context.IntSp, context.RsBSP); #else #error "Platform not supported!" #endif @@ -490,7 +486,7 @@ public: if (pHashEntry->nMaxStackSize > 0) { SIZE_T len = ((SIZE_T) pHashEntry->pStackBaseAddr + pHashEntry->nMaxStackSize) - (SIZE_T)pHashEntry->pCallstackOffset; - bytesToRead = min(len, MAX_CALLSTACK_LEN_BUF); + bytesToRead = std::min(len, (SIZE_T)MAX_CALLSTACK_LEN_BUF); } // Now read the callstack: if (ReadProcessMemory(GetCurrentProcess(), (LPCVOID) pHashEntry->pCallstackOffset, &(pHashEntry->pcCallstackAddr), bytesToRead, &(pHashEntry->nCallstackLen)) == 0) diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index e5d21b2f2..76df76633 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -40,8 +40,10 @@ static const struct {cMonster::mtCow, "cow"}, {cMonster::mtCreeper, "creeper"}, {cMonster::mtEnderman, "enderman"}, + {cMonster::mtEnderDragon, "enderdragon"}, {cMonster::mtGhast, "ghast"}, {cMonster::mtHorse, "horse"}, + {cMonster::mtIronGolem, "irongolem"}, {cMonster::mtMagmaCube, "magmacube"}, {cMonster::mtMooshroom, "mooshroom"}, {cMonster::mtOcelot, "ocelot"}, @@ -49,11 +51,13 @@ static const struct {cMonster::mtSheep, "sheep"}, {cMonster::mtSilverfish, "silverfish"}, {cMonster::mtSkeleton, "skeleton"}, + {cMonster::mtSnowGolem, "snowgolem"}, {cMonster::mtSlime, "slime"}, {cMonster::mtSpider, "spider"}, {cMonster::mtSquid, "squid"}, {cMonster::mtVillager, "villager"}, {cMonster::mtWitch, "witch"}, + {cMonster::mtWither, "wither"}, {cMonster::mtWolf, "wolf"}, {cMonster::mtZombie, "zombie"}, {cMonster::mtZombiePigman, "zombiepigman"}, @@ -642,9 +646,10 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type) case mtEnderman: return mfHostile; case mtGhast: return mfHostile; case mtHorse: return mfPassive; + case mtIronGolem: return mfPassive; case mtMagmaCube: return mfHostile; case mtMooshroom: return mfHostile; - case mtOcelot: return mfHostile; + case mtOcelot: return mfPassive; case mtPig: return mfPassive; case mtSheep: return mfPassive; case mtSilverfish: return mfHostile; @@ -739,16 +744,20 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType) case mtChicken: toReturn = new cChicken(); break; case mtCow: toReturn = new cCow(); break; case mtCreeper: toReturn = new cCreeper(); break; + case mtEnderDragon: toReturn = new cEnderDragon(); break; case mtEnderman: toReturn = new cEnderman(); break; case mtGhast: toReturn = new cGhast(); break; + case mtIronGolem: toReturn = new cIronGolem(); break; case mtMooshroom: toReturn = new cMooshroom(); break; case mtOcelot: toReturn = new cOcelot(); break; case mtPig: toReturn = new cPig(); break; case mtSheep: toReturn = new cSheep (Random.NextInt(15)); break; // Colour parameter case mtSilverfish: toReturn = new cSilverfish(); break; + case mtSnowGolem: toReturn = new cSnowGolem(); break; case mtSpider: toReturn = new cSpider(); break; case mtSquid: toReturn = new cSquid(); break; case mtWitch: toReturn = new cWitch(); break; + case mtWither: toReturn = new cWither(); break; case mtWolf: toReturn = new cWolf(); break; case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter case mtZombiePigman: toReturn = new cZombiePigman(); break; diff --git a/src/Mobs/SnowGolem.cpp b/src/Mobs/SnowGolem.cpp index 9e199f87e..06021cca5 100644 --- a/src/Mobs/SnowGolem.cpp +++ b/src/Mobs/SnowGolem.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "SnowGolem.h" +#include "../World.h" @@ -24,3 +25,21 @@ void cSnowGolem::GetDrops(cItems & a_Drops, cEntity * a_Killer) + +void cSnowGolem::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + if (IsBiomeNoDownfall((EMCSBiome) m_World->GetBiomeAt((int) floor(GetPosX()), (int) floor(GetPosZ())) )) + { + TakeDamage(*this); + } + else + { + BLOCKTYPE BlockBelow = m_World->GetBlock((int) floor(GetPosX()), (int) floor(GetPosY()) - 1, (int) floor(GetPosZ())); + BLOCKTYPE Block = m_World->GetBlock((int) floor(GetPosX()), (int) floor(GetPosY()), (int) floor(GetPosZ())); + if (Block == E_BLOCK_AIR && g_BlockIsSolid[BlockBelow]) + { + m_World->SetBlock((int) floor(GetPosX()), (int) floor(GetPosY()), (int) floor(GetPosZ()), E_BLOCK_SNOW, 0); + } + } +} diff --git a/src/Mobs/SnowGolem.h b/src/Mobs/SnowGolem.h index d1344adfd..ff5e90da8 100644 --- a/src/Mobs/SnowGolem.h +++ b/src/Mobs/SnowGolem.h @@ -17,6 +17,7 @@ public: CLASS_PROTODEF(cSnowGolem); + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; } ; diff --git a/src/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h index ecbac3aeb..858729c49 100644 --- a/src/OSSupport/SocketThreads.h +++ b/src/OSSupport/SocketThreads.h @@ -61,6 +61,9 @@ public: class cCallback { public: + // Force a virtual destructor in all subclasses: + virtual ~cCallback() {} + /// Called when data is received from the remote party virtual void DataReceived(const char * a_Data, int a_Size) = 0; diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index d90ece2b0..fdbffb3e9 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -81,6 +81,7 @@ public: virtual void SendPickupSpawn (const cPickup & a_Pickup) = 0; virtual void SendPlayerAbilities (void) = 0; virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) = 0; + virtual void SendParticleEffect (const AString & a_SoundName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) = 0; virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) = 0; virtual void SendPlayerMaxSpeed (void) = 0; ///< Informs the client of the maximum player speed (1.6.1+) virtual void SendPlayerMoveLook (void) = 0; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index 48f23801c..e49dd43ff 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -608,6 +608,15 @@ void cProtocol125::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio +void cProtocol125::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) +{ + // Not supported by this protocol version +} + + + + + void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) { cCSLock Lock(m_CSPacket); diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index ebbcd762a..0b32137d8 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -54,6 +54,7 @@ public: virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; virtual void SendKeepAlive (int a_PingID) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; + virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override; virtual void SendPickupSpawn (const cPickup & a_Pickup) override; virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override; diff --git a/src/Protocol/Protocol15x.cpp b/src/Protocol/Protocol15x.cpp index c337d26e7..7e2aa9490 100644 --- a/src/Protocol/Protocol15x.cpp +++ b/src/Protocol/Protocol15x.cpp @@ -36,6 +36,7 @@ Implements the 1.5.x protocol classes: enum { PACKET_WINDOW_OPEN = 0x64, + PACKET_PARTICLE_EFFECT = 0x3F, } ; @@ -76,6 +77,26 @@ void cProtocol150::SendWindowOpen(const cWindow & a_Window) +void cProtocol150::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_PARTICLE_EFFECT); + WriteString(a_ParticleName); + WriteFloat(a_SrcX); + WriteFloat(a_SrcY); + WriteFloat(a_SrcZ); + WriteFloat(a_OffsetX); + WriteFloat(a_OffsetY); + WriteFloat(a_OffsetZ); + WriteFloat(a_ParticleData); + WriteInt(a_ParticleAmmount); + Flush(); +} + + + + + int cProtocol150::ParseWindowClick(void) { HANDLE_PACKET_READ(ReadChar, char, WindowID); diff --git a/src/Protocol/Protocol15x.h b/src/Protocol/Protocol15x.h index e554fe130..0074b3a83 100644 --- a/src/Protocol/Protocol15x.h +++ b/src/Protocol/Protocol15x.h @@ -28,8 +28,9 @@ class cProtocol150 : public: cProtocol150(cClientHandle * a_Client); - virtual void SendWindowOpen(const cWindow & a_Window) override; - + virtual void SendWindowOpen (const cWindow & a_Window) override; + virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override; + virtual int ParseWindowClick(void); } ; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 161e81936..bbbd5e973 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -521,6 +521,24 @@ void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio +void cProtocol172::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) +{ + cPacketizer Pkt(*this, 0x2A); + Pkt.WriteString(a_ParticleName); + Pkt.WriteFloat(a_SrcX); + Pkt.WriteFloat(a_SrcY); + Pkt.WriteFloat(a_SrcZ); + Pkt.WriteFloat(a_OffsetX); + Pkt.WriteFloat(a_OffsetY); + Pkt.WriteFloat(a_OffsetZ); + Pkt.WriteFloat(a_ParticleData); + Pkt.WriteInt(a_ParticleAmmount); +} + + + + + void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) { cPacketizer Pkt(*this, 0x38); // Playerlist Item packet diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 4a91f0e56..cc0eda1e7 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -66,6 +66,7 @@ public: virtual void SendPickupSpawn (const cPickup & a_Pickup) override; virtual void SendPlayerAbilities (void) override; virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override; + virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override; virtual void SendPlayerListItem (const cPlayer & a_Player, bool a_IsOnline) override; virtual void SendPlayerMaxSpeed (void) override; virtual void SendPlayerMoveLook (void) override; diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 30b48a92f..1cae4a750 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -386,6 +386,16 @@ void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_W +void cProtocolRecognizer::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount); +} + + + + + void cProtocolRecognizer::SendPickupSpawn(const cPickup & a_Pickup) { ASSERT(m_Protocol != NULL); diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index 0d69e9406..fbcf59f3b 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -89,6 +89,7 @@ public: virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; virtual void SendKeepAlive (int a_PingID) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; + virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override; virtual void SendPickupSpawn (const cPickup & a_Pickup) override; virtual void SendPlayerAbilities (void) override; virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override; diff --git a/src/Root.cpp b/src/Root.cpp index fffd8fb47..798f965be 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -22,6 +22,7 @@ #include "inifile/iniFile.h" #ifdef _WIN32 + #include "conio.h" #include <psapi.h> #elif defined(__linux__) #include <fstream> @@ -29,6 +30,8 @@ #include <mach/mach.h> #endif +extern bool g_TERMINATE_EVENT_RAISED; + @@ -76,7 +79,7 @@ void cRoot::InputThread(void * a_Params) cLogCommandOutputCallback Output; - while (!(self.m_bStop || self.m_bRestart) && std::cin.good()) + while (!self.m_bStop && !self.m_bRestart && !g_TERMINATE_EVENT_RAISED && std::cin.good()) { AString Command; std::getline(std::cin, Command); @@ -85,10 +88,10 @@ void cRoot::InputThread(void * a_Params) self.ExecuteConsoleCommand(TrimString(Command), Output); } } - - if (!(self.m_bStop || self.m_bRestart)) + + if (g_TERMINATE_EVENT_RAISED || !std::cin.good()) { - // We have come here because the std::cin has received an EOF and the server is still running; stop the server: + // We have come here because the std::cin has received an EOF / a terminate signal has been sent, and the server is still running; stop the server: self.m_bStop = true; } } @@ -99,6 +102,12 @@ void cRoot::InputThread(void * a_Params) void cRoot::Start(void) { + #ifdef _WIN32 + HWND hwnd = GetConsoleWindow(); + HMENU hmenu = GetSystemMenu(hwnd, FALSE); + EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED); // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling + #endif + cDeadlockDetect dd; delete m_Log; m_Log = new cMCLogger(); @@ -192,12 +201,20 @@ void cRoot::Start(void) finishmseconds -= mseconds; LOG("Startup complete, took %i ms!", finishmseconds); + #ifdef _WIN32 + EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button + #endif - while (!m_bStop && !m_bRestart) // These are modified by external threads + while (!m_bStop && !m_bRestart && !g_TERMINATE_EVENT_RAISED) // These are modified by external threads { cSleep::MilliSleep(1000); } + if (g_TERMINATE_EVENT_RAISED) + { + m_bStop = true; + } + #if !defined(ANDROID_NDK) delete m_InputThread; m_InputThread = NULL; #endif @@ -222,7 +239,7 @@ void cRoot::Start(void) delete m_FurnaceRecipe; m_FurnaceRecipe = NULL; delete m_CraftingRecipes; m_CraftingRecipes = NULL; LOGD("Forgetting groups..."); - delete m_GroupManager; m_GroupManager = 0; + delete m_GroupManager; m_GroupManager = NULL; LOGD("Unloading worlds..."); UnloadWorlds(); @@ -233,12 +250,11 @@ void cRoot::Start(void) cBlockHandler::Deinit(); LOG("Cleaning up..."); - //delete HeartBeat; HeartBeat = 0; - delete m_Server; m_Server = 0; + delete m_Server; m_Server = NULL; LOG("Shutdown successful!"); } - delete m_Log; m_Log = 0; + delete m_Log; m_Log = NULL; } diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index e53c7c172..f65908729 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -8,6 +8,7 @@ #include "../Blocks/BlockTorch.h" #include "../Blocks/BlockDoor.h" #include "../Piston.h" +#include "../Tracer.h" @@ -106,21 +107,47 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) || ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) || ((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (SourceBlockMeta & 0x08) == 0x08) || - (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) + (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) || + (((SourceBlockType == E_BLOCK_STONE_PRESSURE_PLATE) || (SourceBlockType == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (SourceBlockMeta == 0)) ) { LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(itr->a_SourceBlock).c_str()); itr = m_PoweredBlocks.erase(itr); } + else if (SourceBlockType == E_BLOCK_DAYLIGHT_SENSOR) + { + if (!a_Chunk->IsLightValid()) + { + m_World.QueueLightChunk(a_ChunkX, a_ChunkZ); + ++itr; + continue; + } + else + { + NIBBLETYPE SkyLight; + a_Chunk->UnboundedRelGetBlockSkyLight(RelX, itr->a_SourcePos.y + 1, RelZ, SkyLight); + + if (a_Chunk->GetTimeAlteredLight(SkyLight) <= 8) // Could use SkyLight - m_World.GetSkyDarkness(); + { + LOGD("cRedstoneSimulator: Erased daylight sensor from powered blocks list due to insufficient light level"); + itr = m_PoweredBlocks.erase(itr); + } + else + { + ++itr; + continue; + } + } + } else if ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (DestBlockType == E_BLOCK_REDSTONE_WIRE)) { // It is simply not allowed that a wire powers another wire, presuming that data here is sane and a dest and source are beside each other - LOGD("cRedstoneSimulator: Erased redstone wire from powered blocks list because it's source was also wire"); + LOGD("cRedstoneSimulator: Erased redstone wire from powered blocks list because its source was also wire"); itr = m_PoweredBlocks.erase(itr); } else { - itr++; + ++itr; } } @@ -165,7 +192,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c } else { - itr++; + ++itr; } } @@ -186,7 +213,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c } else { - itr++; + ++itr; } } @@ -206,12 +233,8 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c itr = m_RepeatersDelayList.erase(itr); continue; } - else if (itr->a_ElapsedTicks < itr->a_DelayTicks) - { - itr->a_ElapsedTicks++; - } - itr++; + ++itr; } for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;) @@ -285,6 +308,12 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c HandleRail(a_X, dataitr->y, a_Z, BlockType); break; } + case E_BLOCK_WOODEN_PRESSURE_PLATE: + case E_BLOCK_STONE_PRESSURE_PLATE: + { + HandlePressurePlate(a_X, dataitr->y, a_Z, BlockType); + break; + } } ++dataitr; @@ -601,7 +630,7 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, 0, false); } - for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); itr++) + for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr) { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -659,8 +688,14 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int return; } } - - // Tick incrementing handled in SimChunk + else + { + // Apparently, incrementing ticks only works reliably here, and not in SimChunk; + // With a world with lots of redstone, the repeaters simply do not delay + // I am confounded to say why. Perhaps optimisation failure. + LOGD("Incremented a repeater @ %i %i %i | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks); + itr->a_ElapsedTicks++; + } } } @@ -897,9 +932,112 @@ void cRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, int a_Block void cRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ) { - if (m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) > 10) + int a_ChunkX, a_ChunkZ; + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, a_ChunkX, a_ChunkZ); + + if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ)) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR); + m_World.QueueLightChunk(a_ChunkX, a_ChunkZ); + } + else + { + NIBBLETYPE SkyLight = m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) - m_World.GetSkyDarkness(); + if (SkyLight > 8) + { + SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR); + } + } +} + + + + + +void cRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType) +{ + switch (a_MyType) + { + case E_BLOCK_STONE_PRESSURE_PLATE: + { + // MCS feature - stone pressure plates can only be triggered by players :D + cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(a_BlockX + 0.5f, (float)a_BlockY, a_BlockZ + 0.5f), 0.5f); + + if (a_Player != NULL) + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1); + SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_STONE_PRESSURE_PLATE); + } + else + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0); + } + break; + } + case E_BLOCK_WOODEN_PRESSURE_PLATE: + { + class cWoodenPressurePlateCallback : + public cEntityCallback + { + public: + cWoodenPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : + m_X(a_BlockX), + m_Y(a_BlockY), + m_Z(a_BlockZ), + m_World(a_World), + m_Entity(NULL) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + cTracer LineOfSight(m_World); + + Vector3f EntityPos = a_Entity->GetPosition(); + Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); + float Distance = (EntityPos - BlockPos).Length(); + + if (Distance < 0.5) + { + if (!LineOfSight.Trace(BlockPos, (EntityPos - BlockPos), (int)(EntityPos - BlockPos).Length())) + { + m_Entity = a_Entity; + return true; // Break out, we only need to know for wooden plates that at least one entity is on top + } + } + return false; + } + + bool FoundEntity(void) const + { + return m_Entity != NULL; + } + + protected: + cEntity * m_Entity; + cWorld * m_World; + + int m_X; + int m_Y; + int m_Z; + } ; + + cWoodenPressurePlateCallback WoodenPressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ, &m_World); + m_World.ForEachEntity(WoodenPressurePlateCallback); + + if (WoodenPressurePlateCallback.FoundEntity()) + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1); + SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WOODEN_PRESSURE_PLATE); + } + else + { + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0); + } + break; + } + default: + LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str()); + break; } } @@ -1308,7 +1446,7 @@ void cRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn) { - for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); itr++) + for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr) { if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { @@ -1318,7 +1456,7 @@ void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, in } // Already in here (normal to allow repeater to continue on powering and updating blocks in front) - just update info and quit - itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; // See below for description + itr->a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2; // See below for description itr->a_ElapsedTicks = 0; itr->ShouldPowerOn = ShouldPowerOn; return; @@ -1331,7 +1469,8 @@ void cRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, in // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.) // * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed - RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; + // We don't +1 when powering off because everything seems to already delay a tick when powering off, why? No idea :P + RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + (ShouldPowerOn ? 1 : 0)) * 2; RC.a_ElapsedTicks = 0; diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index 309135497..60c86a3c5 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -89,6 +89,10 @@ private: 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); + /// <summary>Handles daylight sensors</summary> + void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ); + /// <summary>Handles pressure plates</summary> + void HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); /* ==================== */ /* ====== CARRIERS ====== */ @@ -115,8 +119,6 @@ private: void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ); /// <summary>Handles noteblocks</summary> void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Handles noteblocks</summary> - void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ); /* ===================== */ /* ====== Helper functions ====== */ diff --git a/src/StackWalker.cpp b/src/StackWalker.cpp index bf18b9fc9..b4f8ed8c7 100644 --- a/src/StackWalker.cpp +++ b/src/StackWalker.cpp @@ -73,10 +73,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **********************************************************************/ -#include <windows.h> + +#include "Globals.h" + #include <tchar.h> -#include <stdio.h> -#include <stdlib.h> #pragma comment(lib, "version.lib") // for "VerQueryValue" #pragma warning(disable:4826) diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp index 462702893..a1f0842aa 100644 --- a/src/WebAdmin.cpp +++ b/src/WebAdmin.cpp @@ -100,10 +100,10 @@ bool cWebAdmin::Init(void) LOGD("Initialising WebAdmin..."); - AString PortsIPv4 = m_IniFile.GetValueSet("WebAdmin", "Port", "8080"); - AString PortsIPv6 = m_IniFile.GetValueSet("WebAdmin", "PortsIPv6", ""); + m_PortsIPv4 = m_IniFile.GetValueSet("WebAdmin", "Port", "8080"); + m_PortsIPv6 = m_IniFile.GetValueSet("WebAdmin", "PortsIPv6", ""); - if (!m_HTTPServer.Initialize(PortsIPv4, PortsIPv6)) + if (!m_HTTPServer.Initialize(m_PortsIPv4, m_PortsIPv6)) { return false; } diff --git a/src/WebAdmin.h b/src/WebAdmin.h index c629d44ff..0907e7bc3 100644 --- a/src/WebAdmin.h +++ b/src/WebAdmin.h @@ -132,6 +132,9 @@ public: /// Escapes text passed into it, so it can be embedded into html. static AString GetHTMLEscapedString(const AString & a_Input); + AString GetIPv4Ports(void) const { return m_PortsIPv4; } + AString GetIPv6Ports(void) const { return m_PortsIPv6; } + // tolua_end /// Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) @@ -180,6 +183,9 @@ protected: PluginList m_Plugins; + AString m_PortsIPv4; + AString m_PortsIPv6; + /// The Lua template script to provide templates: cLuaState m_TemplateScript; diff --git a/src/World.cpp b/src/World.cpp index 976af671d..28c46c27e 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1878,6 +1878,15 @@ void cWorld::BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation +void cWorld::BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude) +{ + m_ChunkMap->BroadcastParticleEffect(a_ParticleName, a_SrcX, a_SrcY, a_SrcZ, a_OffsetX, a_OffsetY, a_OffsetZ, a_ParticleData, a_ParticleAmmount, a_Exclude); +} + + + + + void cWorld::BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSPlayers); diff --git a/src/World.h b/src/World.h index 1effc5d5d..c067252d9 100644 --- a/src/World.h +++ b/src/World.h @@ -162,6 +162,7 @@ public: void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL); void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL); void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL); + void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL); void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL); void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL); void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8 @@ -419,7 +420,7 @@ public: a_SourceData exact type depends on the a_Source: | esOther | void * | | esPrimedTNT | cTNTEntity * | - | esCreeper | cCreeper * | + | esMonster | cMonster * | | esBed | cVector3i * | | esEnderCrystal | Vector3i * | | esGhastFireball | cGhastFireball * | diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 5c87c2679..e5043de1f 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -5,6 +5,10 @@ #include "Globals.h" #include "NBTChunkSerializer.h" #include "../BlockID.h" +#include "../ItemGrid.h" +#include "../StringCompression.h" +#include "FastNBT.h" + #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" @@ -13,17 +17,27 @@ #include "../BlockEntities/JukeboxEntity.h" #include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/SignEntity.h" -#include "../ItemGrid.h" -#include "../StringCompression.h" + #include "../Entities/Entity.h" -#include "FastNBT.h" #include "../Entities/FallingBlock.h" #include "../Entities/Boat.h" #include "../Entities/Minecart.h" -#include "../Mobs/Monster.h" #include "../Entities/Pickup.h" #include "../Entities/ProjectileEntity.h" +#include "../Mobs/Monster.h" +#include "../Mobs/Bat.h" +#include "../Mobs/Creeper.h" +#include "../Mobs/Enderman.h" +#include "../Mobs/Horse.h" +#include "../Mobs/Magmacube.h" +#include "../Mobs/Sheep.h" +#include "../Mobs/Slime.h" +#include "../Mobs/Skeleton.h" +#include "../Mobs/Villager.h" +#include "../Mobs/Wolf.h" +#include "../Mobs/Zombie.h" + @@ -322,7 +336,120 @@ void cNBTChunkSerializer::AddMinecartEntity(cMinecart * a_Minecart) void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster) { - // TODO + const char * EntityClass = NULL; + switch (a_Monster->GetMobType()) + { + case cMonster::mtBat: EntityClass = "Bat"; break; + case cMonster::mtBlaze: EntityClass = "Blaze"; break; + case cMonster::mtCaveSpider: EntityClass = "CaveSpider"; break; + case cMonster::mtChicken: EntityClass = "Chicken"; break; + case cMonster::mtCow: EntityClass = "Cow"; break; + case cMonster::mtCreeper: EntityClass = "Creeper"; break; + case cMonster::mtEnderDragon: EntityClass = "EnderDragon"; break; + case cMonster::mtEnderman: EntityClass = "Enderman"; break; + case cMonster::mtGhast: EntityClass = "Ghast"; break; + case cMonster::mtGiant: EntityClass = "Giant"; break; + case cMonster::mtHorse: EntityClass = "Horse"; break; + case cMonster::mtIronGolem: EntityClass = "VillagerGolem"; break; + case cMonster::mtMagmaCube: EntityClass = "LavaSlime"; break; + case cMonster::mtMooshroom: EntityClass = "MushroomCow"; break; + case cMonster::mtOcelot: EntityClass = "Ozelot"; break; + case cMonster::mtPig: EntityClass = "Pig"; break; + case cMonster::mtSheep: EntityClass = "Sheep"; break; + case cMonster::mtSilverfish: EntityClass = "Silverfish"; break; + case cMonster::mtSkeleton: EntityClass = "Skeleton"; break; + case cMonster::mtSlime: EntityClass = "Slime"; break; + case cMonster::mtSnowGolem: EntityClass = "SnowMan"; break; + case cMonster::mtSpider: EntityClass = "Spider"; break; + case cMonster::mtSquid: EntityClass = "Squid"; break; + case cMonster::mtVillager: EntityClass = "Villager"; break; + case cMonster::mtWitch: EntityClass = "Witch"; break; + case cMonster::mtWither: EntityClass = "Wither"; break; + case cMonster::mtWolf: EntityClass = "Wolf"; break; + case cMonster::mtZombie: EntityClass = "Zombie"; break; + case cMonster::mtZombiePigman: EntityClass = "PigZombie"; break; + default: + { + ASSERT(!"Unhandled monster type"); + return; + } + } // switch (payload) + + m_Writer.BeginCompound(""); + AddBasicEntity(a_Monster, EntityClass); + switch (a_Monster->GetMobType()) + { + case cMonster::mtBat: + { + m_Writer.AddByte("BatFlags", ((const cBat *)a_Monster)->IsHanging()); + break; + } + case cMonster::mtCreeper: + { + m_Writer.AddByte("powered", ((const cCreeper *)a_Monster)->IsCharged()); + m_Writer.AddByte("ignited", ((const cCreeper *)a_Monster)->IsBlowing()); + break; + } + case cMonster::mtEnderman: + { + m_Writer.AddShort("carried", (Int16)((const cEnderman *)a_Monster)->GetCarriedBlock()); + m_Writer.AddShort("carriedData", (Int16)((const cEnderman *)a_Monster)->GetCarriedMeta()); + break; + } + case cMonster::mtHorse: + { + const cHorse & Horse = *((const cHorse *)a_Monster); + m_Writer.AddByte("ChestedHorse", Horse.IsChested()); + m_Writer.AddByte("EatingHaystack", Horse.IsEating()); + m_Writer.AddByte("Tame", Horse.IsTame()); + m_Writer.AddInt ("Type", Horse.GetHorseType()); + m_Writer.AddInt ("Color", Horse.GetHorseColor()); + m_Writer.AddInt ("Style", Horse.GetHorseStyle()); + m_Writer.AddInt ("ArmorType", Horse.GetHorseArmour()); + m_Writer.AddByte("Saddle", Horse.IsSaddled()); + break; + } + case cMonster::mtMagmaCube: + { + m_Writer.AddByte("Size", ((const cMagmaCube *)a_Monster)->GetSize()); + break; + } + case cMonster::mtSheep: + { + m_Writer.AddByte("Sheared", ((const cSheep *)a_Monster)->IsSheared()); + m_Writer.AddByte("Color", ((const cSheep *)a_Monster)->GetFurColor()); + break; + } + case cMonster::mtSlime: + { + m_Writer.AddInt("Size", ((const cSlime *)a_Monster)->GetSize()); + break; + } + case cMonster::mtSkeleton: + { + m_Writer.AddByte("SkeletonType", (((const cSkeleton *)a_Monster)->IsWither() ? 1 : 0)); + break; + } + case cMonster::mtVillager: + { + m_Writer.AddInt("Profession", ((const cVillager *)a_Monster)->GetVilType()); + break; + } + case cMonster::mtWolf: + { + // TODO: + // _X: CopyPasta error: m_Writer.AddInt("Profession", ((const cVillager *)a_Monster)->GetVilType()); + break; + } + case cMonster::mtZombie: + { + m_Writer.AddByte("IsVillager", (((const cZombie *)a_Monster)->IsVillagerZombie() ? 1 : 0)); + m_Writer.AddByte("IsBaby", (((const cZombie *)a_Monster)->IsBaby() ? 1 : 0)); + m_Writer.AddByte("IsConverting", (((const cZombie *)a_Monster)->IsConverting() ? 1 : 0)); + break; + } + } + m_Writer.EndCompound(); } @@ -479,6 +606,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity) case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break; case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break; case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break; + case cEntity::etExpOrb: /* TODO */ break; case cEntity::etPlayer: return; // Players aren't saved into the world default: { diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index dd06f19fa..8605930b6 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -6,9 +6,14 @@ #include "Globals.h" #include "WSSAnvil.h" #include "NBTChunkSerializer.h" -#include "../World.h" +#include "FastNBT.h" #include "zlib/zlib.h" +#include "../World.h" #include "../BlockID.h" +#include "../Item.h" +#include "../ItemGrid.h" +#include "../StringCompression.h" + #include "../BlockEntities/ChestEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" @@ -17,11 +22,11 @@ #include "../BlockEntities/JukeboxEntity.h" #include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/SignEntity.h" -#include "../Item.h" -#include "../ItemGrid.h" -#include "../StringCompression.h" -#include "FastNBT.h" + + #include "../Mobs/Monster.h" +#include "../Mobs/IncludeAllMonsters.h" + #include "../Entities/Boat.h" #include "../Entities/FallingBlock.h" #include "../Entities/Minecart.h" @@ -984,6 +989,122 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a { LoadThrownEnderpearlFromNBT(a_Entities, a_NBT, a_EntityTagIdx); } + else if (strncmp(a_IDTag, "Bat", a_IDTagLength) == 0) + { + LoadBatFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Blaze", a_IDTagLength) == 0) + { + LoadBlazeFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "CaveSpider", a_IDTagLength) == 0) + { + LoadCaveSpiderFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Chicken", a_IDTagLength) == 0) + { + LoadChickenFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Cow", a_IDTagLength) == 0) + { + LoadCowFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Creeper", a_IDTagLength) == 0) + { + LoadCreeperFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "EnderDragon", a_IDTagLength) == 0) + { + LoadEnderDragonFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Enderman", a_IDTagLength) == 0) + { + LoadEndermanFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Ghast", a_IDTagLength) == 0) + { + LoadGhastFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Giant", a_IDTagLength) == 0) + { + LoadGiantFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Horse", a_IDTagLength) == 0) + { + LoadHorseFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "VillagerGolem", a_IDTagLength) == 0) + { + LoadIronGolemFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "LavaSlime", a_IDTagLength) == 0) + { + LoadMagmaCubeFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "MushroomCow", a_IDTagLength) == 0) + { + LoadMooshroomFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Ozelot", a_IDTagLength) == 0) + { + LoadOcelotFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Pig", a_IDTagLength) == 0) + { + LoadPigFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Sheep", a_IDTagLength) == 0) + { + LoadSheepFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Silverfish", a_IDTagLength) == 0) + { + LoadSilverfishFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Skeleton", a_IDTagLength) == 0) + { + LoadSkeletonFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Slime", a_IDTagLength) == 0) + { + LoadSlimeFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "SnowMan", a_IDTagLength) == 0) + { + LoadSnowGolemFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Spider", a_IDTagLength) == 0) + { + LoadSpiderFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Squid", a_IDTagLength) == 0) + { + LoadSquidFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Villager", a_IDTagLength) == 0) + { + LoadVillagerFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Witch", a_IDTagLength) == 0) + { + LoadWitchFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Wither", a_IDTagLength) == 0) + { + LoadWitherFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Wolf", a_IDTagLength) == 0) + { + LoadWolfFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "Zombie", a_IDTagLength) == 0) + { + LoadZombieFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } + else if (strncmp(a_IDTag, "PigZombie", a_IDTagLength) == 0) + { + LoadPigZombieFromNBT(a_Entities, a_NBT, a_EntityTagIdx); + } // TODO: other entities } @@ -1007,7 +1128,20 @@ void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - // TODO + int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "TileID"); + int MetaIdx = a_NBT.FindChildByName(a_TagIdx, "Data"); + + if ((TypeIdx < 0) || (MetaIdx < 0)) { return; } + + int Type = a_NBT.GetInt(TypeIdx); + NIBBLETYPE Meta = (NIBBLETYPE)a_NBT.GetByte(MetaIdx); + + std::auto_ptr<cFallingBlock> FallingBlock(new cFallingBlock(Vector3i(0, 0, 0), Type, Meta)); + if (!LoadEntityBaseFromNBT(*FallingBlock.get(), a_NBT, a_TagIdx)) + { + return; + } + a_Entities.push_back(FallingBlock.release()); } @@ -1254,6 +1388,488 @@ void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cPar +void cWSSAnvil::LoadBatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cBat> Monster(new cBat()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cBlaze> Monster(new cBlaze()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cCavespider> Monster(new cCavespider()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadChickenFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cChicken> Monster(new cChicken()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadCowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cCow> Monster(new cCow()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadCreeperFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cCreeper> Monster(new cCreeper()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadEnderDragonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cEnderDragon> Monster(new cEnderDragon()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadEndermanFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cEnderman> Monster(new cEnderman()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadGhastFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cGhast> Monster(new cGhast()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadGiantFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cGiant> Monster(new cGiant()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadHorseFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "Type"); + int ColorIdx = a_NBT.FindChildByName(a_TagIdx, "Color"); + int StyleIdx = a_NBT.FindChildByName(a_TagIdx, "Style"); + + if ((TypeIdx < 0) || (ColorIdx < 0) || (StyleIdx < 0)) { return; } + + int Type = a_NBT.GetInt(TypeIdx); + int Color = a_NBT.GetInt(ColorIdx); + int Style = a_NBT.GetInt(StyleIdx); + + std::auto_ptr<cHorse> Monster(new cHorse(Type, Color, Style, 1)); + + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadIronGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cIronGolem> Monster(new cIronGolem()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size"); + + if (SizeIdx < 0) { return; } + + int Size = a_NBT.GetInt(SizeIdx); + + std::auto_ptr<cMagmaCube> Monster(new cMagmaCube(Size)); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadMooshroomFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cMooshroom> Monster(new cMooshroom()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadOcelotFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cOcelot> Monster(new cOcelot()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cPig> Monster(new cPig()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + int ColorIdx = a_NBT.FindChildByName(a_TagIdx, "Color"); + + if (ColorIdx < 0) { return; } + + int Color = (int)a_NBT.GetByte(ColorIdx); + + std::auto_ptr<cSheep> Monster(new cSheep(Color)); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadSilverfishFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cSilverfish> Monster(new cSilverfish()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadSkeletonFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "SkeletonType"); + + if (TypeIdx < 0) { return; } + + bool Type = ((a_NBT.GetByte(TypeIdx) == 1) ? true : false); + + std::auto_ptr<cSkeleton> Monster(new cSkeleton(Type)); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size"); + + if (SizeIdx < 0) { return; } + + int Size = a_NBT.GetInt(SizeIdx); + + std::auto_ptr<cSlime> Monster(new cSlime(Size)); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadSnowGolemFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cSnowGolem> Monster(new cSnowGolem()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cSpider> Monster(new cSpider()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadSquidFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cSquid> Monster(new cSquid()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadVillagerFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "Profession"); + + if (TypeIdx < 0) { return; } + + int Type = a_NBT.GetInt(TypeIdx); + + std::auto_ptr<cVillager> Monster(new cVillager(cVillager::eVillagerType(Type))); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadWitchFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cWitch> Monster(new cWitch()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cWither> Monster(new cWither()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadWolfFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cWolf> Monster(new cWolf()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + int IsVillagerIdx = a_NBT.FindChildByName(a_TagIdx, "IsVillager"); + + if (IsVillagerIdx < 0) { return; } + + bool IsVillagerZombie = ((a_NBT.GetByte(IsVillagerIdx) == 1) ? true : false); + + std::auto_ptr<cZombie> Monster(new cZombie(IsVillagerZombie)); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + +void cWSSAnvil::LoadPigZombieFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + std::auto_ptr<cZombiePigman> Monster(new cZombiePigman()); + if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) + { + return; + } + + a_Entities.push_back(Monster.release()); +} + + + + + bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx) { double Pos[3]; diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 7685d2236..0a7406267 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -142,18 +142,50 @@ protected: void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadMinecartFFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadMinecartTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadArrowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadSnowballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadEggFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadFireballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadFireChargeFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + + void LoadBatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadBlazeFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadCaveSpiderFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadChickenFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadCowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadCreeperFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadEnderDragonFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadEndermanFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadGhastFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadGiantFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadHorseFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadIronGolemFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadMagmaCubeFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadMooshroomFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadOcelotFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadPigFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSheepFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSilverfishFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSkeletonFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSlimeFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSnowGolemFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSpiderFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSquidFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadVillagerFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadWitchFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadWitherFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadWolfFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadPigZombieFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); /// Loads entity common data from the NBT compound; returns true if successful bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx); diff --git a/src/main.cpp b/src/main.cpp index 1f6aad24f..81c6b41e4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,10 @@ #include <dbghelp.h> #endif // _MSC_VER +// Here, we have some ALL CAPS variables, to give the impression that this is deeeep, gritty programming :P +bool g_TERMINATE_EVENT_RAISED = false; // If something has told the server to stop; checked periodically in cRoot +bool g_SERVER_TERMINATED = false; // Set to true when the server terminates, so our CTRL handler can then tell Windows to close the console + @@ -33,14 +37,21 @@ - -void ShowCrashReport(int) +void NonCtrlHandler(int a_Signal) { - std::signal(SIGSEGV, SIG_DFL); + LOGD("Terminate event raised from std::signal"); + g_TERMINATE_EVENT_RAISED = true; - printf("\n\nMCServer has crashed!\n"); - - exit(-1); + switch (a_Signal) + { + case SIGSEGV: + { + std::signal(SIGSEGV, SIG_DFL); + LOGWARN("Segmentation fault; MCServer has crashed :("); + exit(EXIT_FAILURE); + } + default: break; + } } @@ -111,13 +122,33 @@ LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_Except +#ifdef _WIN32 +// Handle CTRL events in windows, including console window close +BOOL CtrlHandler(DWORD fdwCtrlType) +{ + g_TERMINATE_EVENT_RAISED = true; + LOGD("Terminate event raised from the Windows CtrlHandler"); + + if (fdwCtrlType == CTRL_CLOSE_EVENT) // Console window closed via 'x' button, Windows will try to close immediately, therefore... + { + while (!g_SERVER_TERMINATED) { cSleep::MilliSleep(100); } // Delay as much as possible to try to get the server to shut down cleanly + } + + return TRUE; +} +#endif + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // main: int main( int argc, char **argv ) { - (void)argc; - (void)argv; + UNUSED(argc); + UNUSED(argv); #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) InitLeakFinder(); @@ -149,6 +180,13 @@ int main( int argc, char **argv ) } #endif // _WIN32 && !_WIN64 // End of dump-file magic + + #ifdef _WIN32 + if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE)) + { + LOGERROR("Could not install the Windows CTRL handler!"); + } + #endif #if defined(_DEBUG) && defined(_MSC_VER) _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); @@ -160,7 +198,9 @@ int main( int argc, char **argv ) #endif // _DEBUG && _MSC_VER #ifndef _DEBUG - std::signal(SIGSEGV, ShowCrashReport); + std::signal(SIGSEGV, NonCtrlHandler); + std::signal(SIGTERM, NonCtrlHandler); + std::signal(SIGINT, NonCtrlHandler); #endif // DEBUG: test the dumpfile creation: @@ -188,8 +228,10 @@ int main( int argc, char **argv ) #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) DeinitLeakFinder(); #endif - - return 0; + + g_SERVER_TERMINATED = true; + + return EXIT_SUCCESS; } |