diff options
114 files changed, 2209 insertions, 1350 deletions
diff --git a/CoverityModel.cpp b/CoverityModel.cpp new file mode 100644 index 000000000..3ee6447ee --- /dev/null +++ b/CoverityModel.cpp @@ -0,0 +1,17 @@ + + +extern "C" { + struct lua_State; + struct tolua_Error + { + int index; + int array; + const char* type; + }; + + void tolua_error (lua_State* L, const char* msg, tolua_Error* err) + { + __coverity_panic__(); + } + +} diff --git a/MCServer/monsters.ini b/MCServer/monsters.ini index fa376bfff..b631fc1a9 100644 --- a/MCServer/monsters.ini +++ b/MCServer/monsters.ini @@ -55,7 +55,7 @@ SightDistance=25.0 MaxHealth=20 IsFireproof=1 -[Cavespider] +[CaveSpider] AttackRange=2.0 AttackRate=1 AttackDamage=2.0 diff --git a/SetFlags.cmake b/SetFlags.cmake index c5a3a0697..4eed529bd 100644 --- a/SetFlags.cmake +++ b/SetFlags.cmake @@ -45,6 +45,8 @@ macro(set_flags) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11") + add_flags_cxx("-stdlib=libc++") + add_flags_lnk("-stdlib=libc++") else() add_flags_cxx("-pthread") endif() diff --git a/lib/expat/CMakeLists.txt b/lib/expat/CMakeLists.txt index 667804b9a..a23f16609 100644 --- a/lib/expat/CMakeLists.txt +++ b/lib/expat/CMakeLists.txt @@ -4,12 +4,11 @@ project (expat) file(GLOB SOURCE "*.c" + "*.h" ) -# add headers to MSVC project files: -if (WIN32) - file(GLOB HEADERS "*.h") - set(SOURCE ${SOURCE} ${HEADERS}) +# Set files to go to a "Sources" folder in MSVC project files: +if (MSVC) source_group("Sources" FILES ${SOURCE}) endif() diff --git a/lib/inifile/CMakeLists.txt b/lib/inifile/CMakeLists.txt index efbd09796..321d501d7 100644 --- a/lib/inifile/CMakeLists.txt +++ b/lib/inifile/CMakeLists.txt @@ -1,7 +1,11 @@ - cmake_minimum_required (VERSION 2.6) project (iniFile) include_directories ("${PROJECT_SOURCE_DIR}/../../src/") -add_library(iniFile iniFile) +file(GLOB SOURCE + "*.h" + "*.cpp" +) + +add_library(iniFile ${SOURCE}) diff --git a/lib/luaexpat/CMakeLists.txt b/lib/luaexpat/CMakeLists.txt index 7eef5c8ce..f6b21c1d7 100644 --- a/lib/luaexpat/CMakeLists.txt +++ b/lib/luaexpat/CMakeLists.txt @@ -7,6 +7,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.c" + "*.h" ) add_library(luaexpat ${SOURCE}) diff --git a/lib/md5/CMakeLists.txt b/lib/md5/CMakeLists.txt index 8ba09a0dd..cd9fe6320 100644 --- a/lib/md5/CMakeLists.txt +++ b/lib/md5/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../../src/") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(md5 ${SOURCE}) diff --git a/lib/zlib/CMakeLists.txt b/lib/zlib/CMakeLists.txt index 6c52578ee..74cf94f8b 100644 --- a/lib/zlib/CMakeLists.txt +++ b/lib/zlib/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../../src/") file(GLOB SOURCE "*.c" + "*.h" ) if(NOT TARGET zlib) diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 92b410481..b3f75aff1 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -1750,7 +1750,6 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S) { return 0; } - cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin); // Read the params: cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, NULL); @@ -1760,8 +1759,12 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S) L.LogStackTrace(); return 0; } + + cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin); + if (!ChunkStay->AddChunks(2)) { + delete ChunkStay; return 0; } diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index dcc816839..cb55715a6 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -1042,7 +1042,7 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), &a_Client, a_Channel, a_Message); + m_LuaState.Call((int)(**itr), &a_Client, a_Channel, a_Message, cLuaState::Return, res); if (res) { return true; diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index 40cca8882..f03fc6042 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -13,18 +13,20 @@ - // This wild construct allows us to pass a function argument and still have it inlined by the compiler :) /// Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinator function -template<typename Combinator> void InternalMergeBlocks( + +typedef void (CombinatorFunc)(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta); + +template<bool MetasValid, CombinatorFunc Combinator> +void InternalMergeBlocks( BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes, NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas, int a_SizeX, int a_SizeY, int a_SizeZ, int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ, int a_DstOffX, int a_DstOffY, int a_DstOffZ, int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ, - int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ, - Combinator a_Combinator + int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ ) { UNUSED(a_SrcSizeY); @@ -41,7 +43,15 @@ template<typename Combinator> void InternalMergeBlocks( int DstIdx = DstBaseZ + a_DstOffX; for (int x = 0; x < a_SizeX; x++) { - a_Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]); + if (MetasValid) + { + Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]); + } + else + { + BLOCKTYPE FakeDestMeta = 0; + Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], FakeDestMeta, (NIBBLETYPE)0); + } ++DstIdx; ++SrcIdx; } // for x @@ -51,13 +61,15 @@ template<typename Combinator> void InternalMergeBlocks( - - /// Combinator used for cBlockArea::msOverwrite merging -static inline void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +template<bool MetaValid> +void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } } @@ -65,12 +77,16 @@ static inline void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_S /// Combinator used for cBlockArea::msFillAir merging -static inline void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +template<bool MetaValid> +void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { if (a_DstType == E_BLOCK_AIR) { a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } } // "else" is the default, already in place } @@ -80,12 +96,16 @@ static inline void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_Src /// Combinator used for cBlockArea::msImprint merging -static inline void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +template<bool MetaValid> +void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { if (a_SrcType != E_BLOCK_AIR) { a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } } // "else" is the default, already in place } @@ -95,7 +115,8 @@ static inline void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_Src /// Combinator used for cBlockArea::msLake merging -static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +template<bool MetaValid> +void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { // Sponge is the NOP block if (a_SrcType == E_BLOCK_SPONGE) @@ -107,7 +128,10 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp if (a_SrcType == E_BLOCK_AIR) { a_DstType = E_BLOCK_AIR; - a_DstMeta = 0; + if (MetaValid) + { + a_DstMeta = 0; + } return; } @@ -132,7 +156,10 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp case E_BLOCK_STATIONARY_LAVA: { a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } return; } } @@ -146,7 +173,10 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp case E_BLOCK_MYCELIUM: { a_DstType = E_BLOCK_STONE; - a_DstMeta = 0; + if (MetaValid) + { + a_DstMeta = 0; + } return; } } @@ -159,13 +189,17 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp /** Combinator used for cBlockArea::msSpongePrint merging */ -static inline void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +template<bool MetaValid> +void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { // Sponge overwrites nothing, everything else overwrites anything if (a_SrcType != E_BLOCK_SPONGE) { a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } } } @@ -174,17 +208,24 @@ static inline void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a /** Combinator used for cBlockArea::msDifference merging */ -static inline void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +template<bool MetaValid> +void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { - if ((a_DstType == a_SrcType) && (a_DstMeta == a_SrcMeta)) + if ((a_DstType == a_SrcType) && (!MetaValid || (a_DstMeta == a_SrcMeta))) { a_DstType = E_BLOCK_AIR; - a_DstMeta = 0; + if (MetaValid) + { + a_DstMeta = 0; + } } else { a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } } } @@ -193,13 +234,17 @@ static inline void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_ /** Combinator used for cBlockArea::msMask merging */ -static inline void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +template<bool MetaValid> +void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { // If the blocks are the same, keep the dest; otherwise replace with air - if ((a_SrcType != a_DstType) || (a_SrcMeta != a_DstMeta)) + if ((a_SrcType != a_DstType) || !MetaValid || (a_SrcMeta != a_DstMeta)) { a_DstType = E_BLOCK_AIR; - a_DstMeta = 0; + if (MetaValid) + { + a_DstMeta = 0; + } } } @@ -484,7 +529,7 @@ void cBlockArea::CopyTo(cBlockArea & a_Into) const a_Into.Clear(); a_Into.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes()); a_Into.m_Origin = m_Origin; - int BlockCount = GetBlockCount(); + size_t BlockCount = GetBlockCount(); if (HasBlockTypes()) { memcpy(a_Into.m_BlockTypes, m_BlockTypes, BlockCount * sizeof(BLOCKTYPE)); @@ -532,7 +577,7 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName) f.Write(&SizeZ, 4); unsigned char DataTypes = (unsigned char)GetDataTypes(); f.Write(&DataTypes, 1); - int NumBlocks = GetBlockCount(); + size_t NumBlocks = GetBlockCount(); if (HasBlockTypes()) { f.Write(m_BlockTypes, NumBlocks * sizeof(BLOCKTYPE)); @@ -637,155 +682,19 @@ void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMa void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy) { - // Block types are compulsory, block metas are voluntary - if (!HasBlockTypes() || !a_Src.HasBlockTypes()) - { - LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__); - return; - } - - // Dst is *this, Src is a_Src - int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading - int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing - int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy - - int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading - int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing - int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy - - int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading - int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing - int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy const NIBBLETYPE * SrcMetas = a_Src.GetBlockMetas(); NIBBLETYPE * DstMetas = m_BlockMetas; + bool IsDummyMetas = ((SrcMetas == NULL) || (DstMetas == NULL)); if (IsDummyMetas) { - SrcMetas = new NIBBLETYPE[a_Src.GetBlockCount()]; - DstMetas = new NIBBLETYPE[GetBlockCount()]; + MergeByStrategy<true>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas); } - - switch (a_Strategy) - { - case msOverwrite: - { - InternalMergeBlocks( - m_BlockTypes, a_Src.GetBlockTypes(), - DstMetas, SrcMetas, - SizeX, SizeY, SizeZ, - SrcOffX, SrcOffY, SrcOffZ, - DstOffX, DstOffY, DstOffZ, - a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), - m_Size.x, m_Size.y, m_Size.z, - MergeCombinatorOverwrite - ); - break; - } // case msOverwrite - - case msFillAir: - { - InternalMergeBlocks( - m_BlockTypes, a_Src.GetBlockTypes(), - DstMetas, SrcMetas, - SizeX, SizeY, SizeZ, - SrcOffX, SrcOffY, SrcOffZ, - DstOffX, DstOffY, DstOffZ, - a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), - m_Size.x, m_Size.y, m_Size.z, - MergeCombinatorFillAir - ); - break; - } // case msFillAir - - case msImprint: - { - InternalMergeBlocks( - m_BlockTypes, a_Src.GetBlockTypes(), - DstMetas, SrcMetas, - SizeX, SizeY, SizeZ, - SrcOffX, SrcOffY, SrcOffZ, - DstOffX, DstOffY, DstOffZ, - a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), - m_Size.x, m_Size.y, m_Size.z, - MergeCombinatorImprint - ); - break; - } // case msImprint - - case msLake: - { - InternalMergeBlocks( - m_BlockTypes, a_Src.GetBlockTypes(), - DstMetas, SrcMetas, - SizeX, SizeY, SizeZ, - SrcOffX, SrcOffY, SrcOffZ, - DstOffX, DstOffY, DstOffZ, - a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), - m_Size.x, m_Size.y, m_Size.z, - MergeCombinatorLake - ); - break; - } // case msLake - - case msSpongePrint: - { - InternalMergeBlocks( - m_BlockTypes, a_Src.GetBlockTypes(), - DstMetas, SrcMetas, - SizeX, SizeY, SizeZ, - SrcOffX, SrcOffY, SrcOffZ, - DstOffX, DstOffY, DstOffZ, - a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), - m_Size.x, m_Size.y, m_Size.z, - MergeCombinatorSpongePrint - ); - break; - } // case msSpongePrint - - case msDifference: - { - InternalMergeBlocks( - m_BlockTypes, a_Src.GetBlockTypes(), - DstMetas, SrcMetas, - SizeX, SizeY, SizeZ, - SrcOffX, SrcOffY, SrcOffZ, - DstOffX, DstOffY, DstOffZ, - a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), - m_Size.x, m_Size.y, m_Size.z, - MergeCombinatorDifference - ); - break; - } // case msDifference - - case msMask: - { - InternalMergeBlocks( - m_BlockTypes, a_Src.GetBlockTypes(), - DstMetas, SrcMetas, - SizeX, SizeY, SizeZ, - SrcOffX, SrcOffY, SrcOffZ, - DstOffX, DstOffY, DstOffZ, - a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), - m_Size.x, m_Size.y, m_Size.z, - MergeCombinatorMask - ); - break; - } // case msMask - - default: - { - LOGWARNING("Unknown block area merge strategy: %d", a_Strategy); - ASSERT(!"Unknown block area merge strategy"); - break; - } - } // switch (a_Strategy) - - if (IsDummyMetas) + else { - delete[] SrcMetas; - delete[] DstMetas; + MergeByStrategy<false>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas); } } @@ -2079,7 +1988,7 @@ void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, i int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX; int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY; int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ; - int BlockCount = NewSizeX * NewSizeY * NewSizeZ; + size_t BlockCount = (size_t)NewSizeX * NewSizeY * NewSizeZ; BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount]; memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE)); int OldIndex = 0; @@ -2109,7 +2018,7 @@ void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMa int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX; int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY; int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ; - int BlockCount = NewSizeX * NewSizeY * NewSizeZ; + size_t BlockCount = (size_t)NewSizeX * NewSizeY * NewSizeZ; NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount]; memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE)); int OldIndex = 0; @@ -2161,4 +2070,137 @@ void cBlockArea::RelSetData( +template<bool MetasValid> +void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas) +{ + // Block types are compulsory, block metas are voluntary + if (!HasBlockTypes() || !a_Src.HasBlockTypes()) + { + LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__); + return; + } + + // Dst is *this, Src is a_Src + int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading + int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing + int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy + + int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading + int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing + int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy + + int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading + int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing + int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy + + switch (a_Strategy) + { + case cBlockArea::msOverwrite: + { + InternalMergeBlocks<MetasValid, MergeCombinatorOverwrite<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + break; + } // case msOverwrite + + case cBlockArea::msFillAir: + { + InternalMergeBlocks<MetasValid, MergeCombinatorFillAir<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + break; + } // case msFillAir + + case cBlockArea::msImprint: + { + InternalMergeBlocks<MetasValid, MergeCombinatorImprint<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + break; + } // case msImprint + + case cBlockArea::msLake: + { + InternalMergeBlocks<MetasValid, MergeCombinatorLake<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + break; + } // case msLake + + case cBlockArea::msSpongePrint: + { + InternalMergeBlocks<MetasValid, MergeCombinatorSpongePrint<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + break; + } // case msSpongePrint + + case cBlockArea::msDifference: + { + InternalMergeBlocks<MetasValid, MergeCombinatorDifference<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + break; + } // case msDifference + + case cBlockArea::msMask: + { + InternalMergeBlocks<MetasValid, MergeCombinatorMask<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + break; + } // case msMask + + default: + { + LOGWARNING("Unknown block area merge strategy: %d", a_Strategy); + ASSERT(!"Unknown block area merge strategy"); + break; + } + } // switch (a_Strategy) +} + + diff --git a/src/BlockArea.h b/src/BlockArea.h index c48175b8c..4c4dfb8ff 100644 --- a/src/BlockArea.h +++ b/src/BlockArea.h @@ -294,7 +294,7 @@ public: NIBBLETYPE * GetBlockMetas (void) const { return m_BlockMetas; } // NOTE: one byte per block! NIBBLETYPE * GetBlockLight (void) const { return m_BlockLight; } // NOTE: one byte per block! NIBBLETYPE * GetBlockSkyLight(void) const { return m_BlockSkyLight; } // NOTE: one byte per block! - int GetBlockCount(void) const { return m_Size.x * m_Size.y * m_Size.z; } + size_t GetBlockCount(void) const { return m_Size.x * m_Size.y * m_Size.z; } int MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const; protected: @@ -363,6 +363,9 @@ protected: int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight ); + + template<bool MetasValid> + void MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas); // tolua_begin } ; // tolua_end diff --git a/src/BlockEntities/CMakeLists.txt b/src/BlockEntities/CMakeLists.txt index 920767f5c..3e3d17f86 100644 --- a/src/BlockEntities/CMakeLists.txt +++ b/src/BlockEntities/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(BlockEntities ${SOURCE}) diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index 96ca0ac37..146ad915b 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -21,7 +21,8 @@ cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) : super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World), m_ShouldExecute(false), - m_IsPowered(false) + m_IsPowered(false), + m_Result(0) {} diff --git a/src/BlockEntities/MobHeadEntity.cpp b/src/BlockEntities/MobHeadEntity.cpp index c0a1781f6..dc9c18d58 100644 --- a/src/BlockEntities/MobHeadEntity.cpp +++ b/src/BlockEntities/MobHeadEntity.cpp @@ -14,6 +14,8 @@ cMobHeadEntity::cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : super(E_BLOCK_HEAD, a_BlockX, a_BlockY, a_BlockZ, a_World), + m_Type(SKULL_TYPE_SKELETON), + m_Rotation(SKULL_ROTATION_NORTH), m_Owner("") { } diff --git a/src/BlockID.cpp b/src/BlockID.cpp index 79e122032..bf95d0798 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -324,7 +324,7 @@ eDimension StringToDimension(const AString & a_DimensionString) { dimOverworld, "Normal"}, { dimOverworld, "World"}, { dimNether, "Nether"}, - { dimNether, "Hell"}, // Alternate name for End + { dimNether, "Hell"}, // Alternate name for Nether { dimEnd, "End"}, { dimEnd, "Sky"}, // Old name for End } ; @@ -337,7 +337,8 @@ eDimension StringToDimension(const AString & a_DimensionString) } // for i - DimensionMap[] // Not found - return (eDimension)-1000; + LOGWARNING("Unknown dimension: \"%s\". Setting to Overworld", a_DimensionString.c_str()); + return dimOverworld; } diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index 082ff41ac..4b8c745ad 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Blocks ${SOURCE}) diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index ad753118b..c27bc4cad 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -888,9 +888,7 @@ void cByteBuffer::AdvanceReadPos(size_t a_Count) void cByteBuffer::CheckValid(void) const { - ASSERT(m_ReadPos >= 0); ASSERT(m_ReadPos < m_BufferSize); - ASSERT(m_WritePos >= 0); ASSERT(m_WritePos < m_BufferSize); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 67bb299db..900577526 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,6 +57,14 @@ if (NOT MSVC) Entities/Pickup.h Entities/Player.h Entities/ProjectileEntity.h + Entities/ArrowEntity.h + Entities/ThrownEggEntity.h + Entities/ThrownEnderPearlEntity.h + Entities/ExpBottleEntity.h + Entities/ThrownSnowballEntity.h + Entities/FireChargeEntity.h + Entities/FireworkEntity.h + Entities/GhastFireballEntity.h Entities/TNTEntity.h Entities/ExpOrb.h Entities/HangingEntity.h @@ -123,6 +131,7 @@ if (NOT MSVC) file(GLOB SOURCE "*.cpp" + "*.h" ) list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/StackWalker.cpp" "${PROJECT_SOURCE_DIR}/LeakFinder.cpp") diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 8bd0985e9..cd3bceda2 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -240,11 +240,24 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback) { a_Callback.HeightMap (&m_HeightMap); a_Callback.BiomeData (&m_BiomeMap); - a_Callback.BlockTypes (m_BlockTypes); - a_Callback.BlockMeta (m_BlockMeta); + + COMPRESSED_BLOCKTYPE Blocks = m_BlockTypes; + Blocks.resize(NumBlocks); + a_Callback.BlockTypes (&Blocks[0]); + + COMPRESSED_NIBBLETYPE Metas = m_BlockMeta; + Metas.resize(NumBlocks / 2); + a_Callback.BlockMeta (&Metas[0]); + a_Callback.LightIsValid (m_IsLightValid); - a_Callback.BlockLight (m_BlockLight); - a_Callback.BlockSkyLight(m_BlockSkyLight); + + COMPRESSED_NIBBLETYPE BlockLights = m_BlockLight; + BlockLights.resize(NumBlocks / 2); + a_Callback.BlockLight (&BlockLights[0]); + + COMPRESSED_NIBBLETYPE BlockSkyLights = m_BlockSkyLight; + BlockSkyLights.resize(NumBlocks / 2, 0xff); + a_Callback.BlockSkyLight(&BlockSkyLights[0]); for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { @@ -262,7 +275,7 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback) void cChunk::SetAllData( - const BLOCKTYPE * a_BlockTypes, + const BLOCKTYPE * a_BlockTypes, const NIBBLETYPE * a_BlockMeta, const NIBBLETYPE * a_BlockLight, const NIBBLETYPE * a_BlockSkyLight, @@ -272,29 +285,61 @@ void cChunk::SetAllData( ) { memcpy(m_BiomeMap, a_BiomeMap, sizeof(m_BiomeMap)); - + if (a_HeightMap != NULL) { memcpy(m_HeightMap, a_HeightMap, sizeof(m_HeightMap)); } + + if (a_HeightMap == NULL) + { + CalculateHeightmap(a_BlockTypes); + } + + int IdxWhereNonEmptyStarts = 0; + { // Blocktype compression + unsigned char Highest = 0; + int X = 0, Z = 0; + m_BlockTypes.clear(); + + for (int x = 0; x < Width; x++) + { + for (int z = 0; z < Width; z++) + { + unsigned char Height = m_HeightMap[x + z * Width]; + if (Height > Highest) + { + Highest = Height; + X = x; Z = z; + } + } + } + + IdxWhereNonEmptyStarts = MakeIndexNoCheck(X, Highest + 1, Z); + + m_BlockTypes.insert(m_BlockTypes.end(), &a_BlockTypes[0], &a_BlockTypes[IdxWhereNonEmptyStarts]); + } + + { // Blockmeta compression + m_BlockMeta.clear(); + m_BlockMeta.insert(m_BlockMeta.end(), &a_BlockMeta[0], &a_BlockMeta[IdxWhereNonEmptyStarts / 2]); + } - memcpy(m_BlockTypes, a_BlockTypes, sizeof(m_BlockTypes)); - memcpy(m_BlockMeta, a_BlockMeta, sizeof(m_BlockMeta)); if (a_BlockLight != NULL) { - memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight)); + // Compress blocklight + m_BlockLight.clear(); + m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[IdxWhereNonEmptyStarts / 2]); } + if (a_BlockSkyLight != NULL) { - memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight)); + // Compress skylight + m_BlockSkyLight.clear(); + m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_BlockSkyLight[0], &a_BlockSkyLight[IdxWhereNonEmptyStarts / 2]); } m_IsLightValid = (a_BlockLight != NULL) && (a_BlockSkyLight != NULL); - - if (a_HeightMap == NULL) - { - CalculateHeightmap(); - } // Clear the block entities present - either the loader / saver has better, or we'll create empty ones: for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) @@ -332,8 +377,17 @@ void cChunk::SetLight( { // TODO: We might get cases of wrong lighting when a chunk changes in the middle of a lighting calculation. // Postponing until we see how bad it is :) - memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight)); - memcpy(m_BlockSkyLight, a_SkyLight, sizeof(m_BlockSkyLight)); + + { // Compress blocklight + m_BlockLight.clear(); + m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[m_BlockTypes.size()]); + } + + { // Compress skylight + m_BlockSkyLight.clear(); + m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_SkyLight[0], &a_SkyLight[m_BlockTypes.size()]); + } + m_IsLightValid = true; } @@ -343,7 +397,8 @@ void cChunk::SetLight( void cChunk::GetBlockTypes(BLOCKTYPE * a_BlockTypes) { - memcpy(a_BlockTypes, m_BlockTypes, NumBlocks); + std::copy(m_BlockTypes.begin(), m_BlockTypes.end(), a_BlockTypes); + std::fill_n(&a_BlockTypes[m_BlockTypes.size()], NumBlocks - m_BlockTypes.size(), E_BLOCK_AIR); } @@ -630,7 +685,7 @@ void cChunk::Tick(float a_Dt) void cChunk::TickBlock(int a_RelX, int a_RelY, int a_RelZ) { unsigned Index = MakeIndex(a_RelX, a_RelY, a_RelZ); - cBlockHandler * Handler = BlockHandler(m_BlockTypes[Index]); + cBlockHandler * Handler = BlockHandler(GetBlock(Index)); ASSERT(Handler != NULL); // Happenned on server restart, FS #243 cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap()); cBlockInServerPluginInterface PluginInterface(*this->GetWorld()); @@ -751,7 +806,7 @@ void cChunk::BroadcastPendingBlockChanges(void) void cChunk::CheckBlocks() { - if (m_ToTickBlocks.size() == 0) + if (m_ToTickBlocks.empty()) { return; } @@ -811,7 +866,7 @@ void cChunk::TickBlocks(void) } unsigned int Index = MakeIndexNoCheck(m_BlockTickX, m_BlockTickY, m_BlockTickZ); - cBlockHandler * Handler = BlockHandler(m_BlockTypes[Index]); + cBlockHandler * Handler = BlockHandler(GetBlock(Index)); ASSERT(Handler != NULL); // Happenned on server restart, FS #243 Handler->OnUpdate(ChunkInterface, *this->GetWorld(), PluginInterface, *this, m_BlockTickX, m_BlockTickY, m_BlockTickZ); } // for i - tickblocks @@ -1296,7 +1351,7 @@ void cChunk::CreateBlockEntities(void) { for (int y = 0; y < Height; y++) { - BLOCKTYPE BlockType = cChunkDef::GetBlock(m_BlockTypes, x, y, z); + BLOCKTYPE BlockType = GetBlock(x, y, z); switch (BlockType) { case E_BLOCK_BEACON: @@ -1349,7 +1404,7 @@ void cChunk::WakeUpSimulators(void) int BlockZ = z + BaseZ; for (int y = GetHeight(x, z); y >= 0; y--) { - BLOCKTYPE Block = cChunkDef::GetBlock(m_BlockTypes, x, y, z); + BLOCKTYPE Block = GetBlock(x, y, z); // The redstone sim takes multiple blocks, use the inbuilt checker if (RedstoneSimulator->IsAllowedBlock(Block)) @@ -1384,7 +1439,7 @@ void cChunk::WakeUpSimulators(void) -void cChunk::CalculateHeightmap() +void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes) { for (int x = 0; x < Width; x++) { @@ -1393,7 +1448,7 @@ void cChunk::CalculateHeightmap() for (int y = Height - 1; y > -1; y--) { int index = MakeIndex( x, y, z ); - if (m_BlockTypes[index] != E_BLOCK_AIR) + if (a_BlockTypes[index] != E_BLOCK_AIR) { m_HeightMap[x + z * Width] = (unsigned char)y; break; @@ -1517,7 +1572,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT ASSERT(IsValid()); const int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); - const BLOCKTYPE OldBlockType = cChunkDef::GetBlock(m_BlockTypes, index); + const BLOCKTYPE OldBlockType = GetBlock(index); const BLOCKTYPE OldBlockMeta = GetNibble(m_BlockMeta, index); if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta)) { @@ -1525,7 +1580,11 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT } MarkDirty(); - + + if ((size_t)index >= m_BlockTypes.size()) + { + m_BlockTypes.resize(index + 1); + } m_BlockTypes[index] = a_BlockType; // The client doesn't need to distinguish between stationary and nonstationary fluids: @@ -1565,7 +1624,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT { for (int y = a_RelY - 1; y > 0; --y) { - if (m_BlockTypes[MakeIndexNoCheck(a_RelX, y, a_RelZ)] != E_BLOCK_AIR) + if (GetBlock(MakeIndexNoCheck(a_RelX, y, a_RelZ)) != E_BLOCK_AIR) { m_HeightMap[a_RelX + a_RelZ * Width] = (unsigned char)y; break; @@ -2452,7 +2511,7 @@ BLOCKTYPE cChunk::GetBlock(int a_RelX, int a_RelY, int a_RelZ) const return 0; // Clip } - return m_BlockTypes[MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ)]; + return GetBlock(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ)); } @@ -2466,8 +2525,13 @@ BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const ASSERT(!"GetBlock(idx) out of bounds!"); return 0; } - - return m_BlockTypes[ a_BlockIdx ]; + + if ((size_t)a_BlockIdx >= m_BlockTypes.size()) + { + return E_BLOCK_AIR; + } + + return m_BlockTypes[a_BlockIdx]; } @@ -2477,7 +2541,7 @@ BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) { int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); - a_BlockType = cChunkDef::GetBlock (m_BlockTypes, Idx); + a_BlockType = GetBlock(Idx); a_BlockMeta = cChunkDef::GetNibble(m_BlockMeta, Idx); } @@ -2488,7 +2552,7 @@ void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_ void cChunk::GetBlockInfo(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight) { int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); - a_BlockType = cChunkDef::GetBlock (m_BlockTypes, Idx); + a_BlockType = GetBlock(Idx); a_Meta = cChunkDef::GetNibble(m_BlockMeta, Idx); a_SkyLight = cChunkDef::GetNibble(m_BlockSkyLight, Idx); a_BlockLight = cChunkDef::GetNibble(m_BlockLight, Idx); diff --git a/src/Chunk.h b/src/Chunk.h index f20134e66..a15d43e00 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -267,7 +267,7 @@ public: void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // [x, y, z] in world block coords void CalculateLighting(); // Recalculate right now - void CalculateHeightmap(); + void CalculateHeightmap(const BLOCKTYPE * a_BlockTypes); // Broadcast various packets to all clients of this chunk: // (Please keep these alpha-sorted) @@ -326,9 +326,9 @@ public: inline void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_BlockIdx, a_Meta); } inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); } - inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); } + inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ, true); } inline NIBBLETYPE GetBlockLight(int a_Idx) const {return cChunkDef::GetNibble(m_BlockLight, a_Idx); } - inline NIBBLETYPE GetSkyLight (int a_Idx) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_Idx); } + inline NIBBLETYPE GetSkyLight (int a_Idx) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_Idx, true); } /** Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */ bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const; @@ -421,10 +421,10 @@ private: cChunkMap * m_ChunkMap; // TODO: Make these pointers and don't allocate what isn't needed - BLOCKTYPE m_BlockTypes [cChunkDef::NumBlocks]; - NIBBLETYPE m_BlockMeta [cChunkDef::NumBlocks / 2]; - NIBBLETYPE m_BlockLight [cChunkDef::NumBlocks / 2]; - NIBBLETYPE m_BlockSkyLight[cChunkDef::NumBlocks / 2]; + COMPRESSED_BLOCKTYPE m_BlockTypes; + COMPRESSED_NIBBLETYPE m_BlockMeta; + COMPRESSED_NIBBLETYPE m_BlockLight; + COMPRESSED_NIBBLETYPE m_BlockSkyLight; cChunkDef::HeightMap m_HeightMap; cChunkDef::BiomeMap m_BiomeMap; diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 9c7753820..054168bdd 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -77,13 +77,19 @@ public: idx = x + Width * z // Need to verify this with the protocol spec, currently unknown! */ typedef EMCSBiome BiomeMap[Width * Width]; - + /// The type used for block type operations and storage, AXIS_ORDER ordering typedef BLOCKTYPE BlockTypes[NumBlocks]; - + /// The type used for block data in nibble format, AXIS_ORDER ordering typedef NIBBLETYPE BlockNibbles[NumBlocks / 2]; + /** The storage wrapper used for compressed blockdata residing in RAMz */ + typedef std::vector<BLOCKTYPE> COMPRESSED_BLOCKTYPE; + + /** The storage wrapper used for compressed nibbledata residing in RAMz */ + typedef std::vector<NIBBLETYPE> COMPRESSED_NIBBLETYPE; + /// Converts absolute block coords into relative (chunk + block) coords: inline static void AbsoluteToRelative(/* in-out */ int & a_X, int & a_Y, int & a_Z, /* out */ int & a_ChunkX, int & a_ChunkZ ) @@ -219,46 +225,67 @@ public: ASSERT((a_Z >= 0) && (a_Z <= Width)); a_BiomeMap[a_X + Width * a_Z] = a_Biome; } - - - static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, int a_BlockIdx) + + + static NIBBLETYPE GetNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_BlockIdx, bool a_IsSkyLightNibble = false) { if ((a_BlockIdx > -1) && (a_BlockIdx < NumBlocks)) { - return (a_Buffer[a_BlockIdx / 2] >> ((a_BlockIdx & 1) * 4)) & 0x0f; + if ((size_t)(a_BlockIdx / 2) >= a_Buffer.size()) + { + return (a_IsSkyLightNibble ? 0xff : 0); + } + return (a_Buffer[(size_t)(a_BlockIdx / 2)] >> ((a_BlockIdx & 1) * 4)) & 0x0f; } ASSERT(!"cChunkDef::GetNibble(): index out of chunk range!"); return 0; } - - + + + static NIBBLETYPE GetNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int x, int y, int z, bool a_IsSkyLightNibble = false) + { + if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1)) + { + int Index = MakeIndexNoCheck(x, y, z); + if ((size_t)(Index / 2) >= a_Buffer.size()) + { + return (a_IsSkyLightNibble ? 0xff : 0); + } + return ExpandNibble(a_Buffer, Index); + } + ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!"); + return 0; + } + + static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, int x, int y, int z) { if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1)) { int Index = MakeIndexNoCheck(x, y, z); - return (a_Buffer[Index / 2] >> ((Index & 1) * 4)) & 0x0f; + return (a_Buffer[(size_t)(Index / 2)] >> ((Index & 1) * 4)) & 0x0f; } ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!"); return 0; } - static void SetNibble(NIBBLETYPE * a_Buffer, int a_BlockIdx, NIBBLETYPE a_Nibble) + static void SetNibble(COMPRESSED_NIBBLETYPE & a_Buffer, int a_BlockIdx, NIBBLETYPE a_Nibble) { if ((a_BlockIdx < 0) || (a_BlockIdx >= NumBlocks)) { ASSERT(!"cChunkDef::SetNibble(): index out of range!"); return; } - a_Buffer[a_BlockIdx / 2] = static_cast<NIBBLETYPE>( - (a_Buffer[a_BlockIdx / 2] & (0xf0 >> ((a_BlockIdx & 1) * 4))) | // The untouched nibble - ((a_Nibble & 0x0f) << ((a_BlockIdx & 1) * 4)) // The nibble being set - ); + if ((size_t)(a_BlockIdx / 2) >= a_Buffer.size()) + { + a_Buffer.resize((size_t)((a_BlockIdx / 2) + 1)); + } + a_Buffer[(size_t)(a_BlockIdx / 2)] = PackNibble(a_Buffer, a_BlockIdx, a_Nibble); } - - - static void SetNibble(NIBBLETYPE * a_Buffer, int x, int y, int z, NIBBLETYPE a_Nibble) + + + static void SetNibble(COMPRESSED_NIBBLETYPE & a_Buffer, int x, int y, int z, NIBBLETYPE a_Nibble) { if ( (x >= Width) || (x < 0) || @@ -271,24 +298,32 @@ public: } int Index = MakeIndexNoCheck(x, y, z); - a_Buffer[Index / 2] = static_cast<NIBBLETYPE>( - (a_Buffer[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble - ((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set - ); + if ((size_t)(Index / 2) >= a_Buffer.size()) + { + a_Buffer.resize((size_t)((Index / 2) + 1)); + } + a_Buffer[(size_t)(Index / 2)] = PackNibble(a_Buffer, Index, a_Nibble); } - inline static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos ) +private: + + + inline static NIBBLETYPE PackNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_Index, NIBBLETYPE a_Nibble) { - return GetNibble(a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z ); + return static_cast<NIBBLETYPE>( + (a_Buffer[a_Index / 2] & (0xf0 >> ((a_Index & 1) * 4))) | // The untouched nibble + ((a_Nibble & 0x0f) << ((a_Index & 1) * 4)) // The nibble being set + ); } - - - inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, NIBBLETYPE a_Value ) + + + inline static NIBBLETYPE ExpandNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_Index) { - SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value ); + return (a_Buffer[a_Index / 2] >> ((a_Index & 1) * 4)) & 0x0f; } + } ; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index ed9103174..537d491c9 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -346,9 +346,8 @@ void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - int x, y, z, ChunkX, ChunkZ; + int x, z, ChunkX, ChunkZ; x = a_BlockX; - y = a_BlockY; z = a_BlockZ; cChunkDef::BlockToChunk(x, z, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); @@ -1146,9 +1145,8 @@ BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ) // First check if it isn't queued in the m_FastSetBlockQueue: { int X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; - int ChunkX, ChunkY, ChunkZ; + int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); - ChunkY = 0; cCSLock Lock(m_CSFastSetBlock); for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr) { @@ -1656,7 +1654,10 @@ void cChunkMap::AddEntity(cEntity * a_Entity) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); - if ((Chunk == NULL) || !Chunk->IsValid()) + if ( + (Chunk == NULL) || // Chunk not present at all + (!Chunk->IsValid() && !a_Entity->IsPlayer()) // Chunk present, but no valid data; players need to spawn in such chunks (#953) + ) { LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.", a_Entity, a_Entity->GetClass(), a_Entity->GetUniqueID() diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 0f26d41e7..f3588c253 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -186,6 +186,51 @@ void cClientHandle::GenerateOfflineUUID(void) +AString cClientHandle::FormatChatPrefix(bool ShouldAppendChatPrefixes, AString a_ChatPrefixS, AString m_Color1, AString m_Color2) +{ + if (ShouldAppendChatPrefixes) + return Printf("%s[%s] %s", m_Color1.c_str(), a_ChatPrefixS.c_str(), m_Color2.c_str()); + else + return Printf("%s", m_Color1.c_str()); +} + + + + + +AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString &a_AdditionalData) +{ + switch (a_ChatPrefix) + { + case mtCustom: return AString(); + case mtFailure: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Rose, cChatColor::White); + case mtInformation: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Yellow, cChatColor::White); + case mtSuccess: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Green, cChatColor::White); + case mtWarning: return FormatChatPrefix(ShouldAppendChatPrefixes, "WARN", cChatColor::Rose, cChatColor::White); + case mtFatal: return FormatChatPrefix(ShouldAppendChatPrefixes, "FATAL", cChatColor::Red, cChatColor::White); + case mtDeath: return FormatChatPrefix(ShouldAppendChatPrefixes, "DEATH", cChatColor::Gray, cChatColor::White); + case mtJoin: return FormatChatPrefix(ShouldAppendChatPrefixes, "JOIN", cChatColor::Yellow, cChatColor::White); + case mtLeave: return FormatChatPrefix(ShouldAppendChatPrefixes, "LEAVE", cChatColor::Yellow, cChatColor::White); + case mtPrivateMessage: + { + if (ShouldAppendChatPrefixes) + { + return Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str()); + } + else + { + return Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str()); + } + } + } + ASSERT(!"Unhandled chat prefix type!"); + return AString(); +} + + + + + AString cClientHandle::GenerateOfflineUUID(const AString & a_Username) { // Proper format for a version 3 UUID is: @@ -1037,7 +1082,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e { HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler); } - else if (ItemHandler->IsFood()) + else if (ItemHandler->IsFood() && !m_Player->IsGameModeCreative()) { if (m_Player->IsSatiated()) { @@ -1849,7 +1894,7 @@ void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlock void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData) { bool ShouldAppendChatPrefixes = true; - + if (GetPlayer()->GetWorld() == NULL) { cWorld * World = cRoot::Get()->GetWorld(GetPlayer()->GetLoadedWorldName()); @@ -1868,89 +1913,9 @@ void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefi ShouldAppendChatPrefixes = false; } - AString Message; - - switch (a_ChatPrefix) - { - case mtCustom: break; - case mtFailure: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[INFO] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Rose.c_str()); - break; - } - case mtInformation: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[INFO] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Yellow.c_str()); - break; - } - case mtSuccess: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[INFO] %s", cChatColor::Green.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Green.c_str()); - break; - } - case mtWarning: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[WARN] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Rose.c_str()); - break; - } - case mtFatal: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[FATAL] %s", cChatColor::Red.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Red.c_str()); - break; - } - case mtDeath: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[DEATH] %s", cChatColor::Gray.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Gray.c_str()); - break; - } - case mtPrivateMessage: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str()); - else - Message = Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str()); - break; - } - case mtJoin: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[JOIN] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Yellow.c_str()); - break; - } - case mtLeave: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[LEAVE] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Yellow.c_str()); - break; - } - default: ASSERT(!"Unhandled chat prefix type!"); return; - } - - Message.append(a_Message); + AString Message = FormatMessageType(ShouldAppendChatPrefixes, a_ChatPrefix, a_AdditionalData); - m_Protocol->SendChat(Message); + m_Protocol->SendChat(Message.append(a_Message)); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 3d01d8034..9f8d44129 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -77,6 +77,11 @@ public: This is used for the offline (non-auth) mode, when there's no UUID source. Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. */ static AString GenerateOfflineUUID(const AString & a_Username); // tolua_export + + /** Formats the type of message with the proper color and prefix for sending to the client. **/ + AString FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString & a_AdditionalData); + + AString FormatChatPrefix(bool ShouldAppendChatPrefixes, AString a_ChatPrefixS, AString m_Color1, AString m_Color2); void Kick(const AString & a_Reason); // tolua_export void Authenticate(const AString & a_Name, const AString & a_UUID); // Called by cAuthenticator when the user passes authentication diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp new file mode 100644 index 000000000..847b39bbc --- /dev/null +++ b/src/Entities/ArrowEntity.cpp @@ -0,0 +1,193 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Player.h" +#include "ArrowEntity.h" +#include "../Chunk.h" + + + + + +cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5), + m_PickupState(psNoPickup), + m_DamageCoeff(2), + m_IsCritical(false), + m_Timer(0), + m_HitGroundTimer(0), + m_bIsCollected(false), + m_HitBlockPos(Vector3i(0, 0, 0)) +{ + SetSpeed(a_Speed); + SetMass(0.1); + SetYawFromSpeed(); + SetPitchFromSpeed(); + LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}", + m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(), + GetYaw(), GetPitch() + ); +} + + + + + +cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : + super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5), + m_PickupState(psInSurvivalOrCreative), + m_DamageCoeff(2), + m_IsCritical((a_Force >= 1)), + m_Timer(0), + m_HitGroundTimer(0), + m_HasTeleported(false), + m_bIsCollected(false), + m_HitBlockPos(0, 0, 0) +{ +} + + + + + +bool cArrowEntity::CanPickup(const cPlayer & a_Player) const +{ + switch (m_PickupState) + { + case psNoPickup: return false; + case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative()); + case psInCreative: return a_Player.IsGameModeCreative(); + } + ASSERT(!"Unhandled pickup state"); + return false; +} + + + + + +void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + if (a_HitFace == BLOCK_FACE_NONE) { return; } + + super::OnHitSolidBlock(a_HitPos, a_HitFace); + int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z; + + switch (a_HitFace) + { + case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed + case BLOCK_FACE_YM: + { + break; + } + default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true); + } + + m_HitBlockPos = Vector3i(a_X, a_Y, a_Z); + + // Broadcast arrow hit sound + m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); +} + + + + + +void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat()) + { + // Not an entity that interacts with an arrow + return; + } + + int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5); + if (m_IsCritical) + { + Damage += m_World->GetTickRandomNumber(Damage / 2 + 2); + } + a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); + + // Broadcast successful hit sound + m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); + + Destroy(); +} + + + + + +void cArrowEntity::CollectedBy(cPlayer * a_Dest) +{ + if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest))) + { + int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW); + if (NumAdded > 0) // Only play effects if there was space in inventory + { + m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest); + // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) + m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); + m_bIsCollected = true; + } + } +} + + + + + +void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + m_Timer += a_Dt; + + if (m_bIsCollected) + { + if (m_Timer > 500.f) // 0.5 seconds + { + Destroy(); + return; + } + } + else if (m_Timer > 1000 * 60 * 5) // 5 minutes + { + Destroy(); + return; + } + + if (m_IsInGround) + { + // When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL + // Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing) + // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync + // Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position + + if (!m_HasTeleported) // Sent a teleport already, don't do again + { + if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case + { + m_World->BroadcastTeleportEntity(*this); + m_HasTeleported = true; + } + else + { + m_HitGroundTimer += a_Dt; + } + } + + int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width; + int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width; + cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ); + + if (Chunk == NULL) + { + // Inside an unloaded chunk, abort + return; + } + + if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed? + { + m_IsInGround = false; // Yes, begin simulating physics again + } + } +} diff --git a/src/Entities/ArrowEntity.h b/src/Entities/ArrowEntity.h new file mode 100644 index 000000000..1fe3032ee --- /dev/null +++ b/src/Entities/ArrowEntity.h @@ -0,0 +1,96 @@ +// +// ArrowEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cArrowEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + /// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field + enum ePickupState + { + psNoPickup = 0, + psInSurvivalOrCreative = 1, + psInCreative = 2, + } ; + + // tolua_end + + CLASS_PROTODEF(cArrowEntity); + + /// Creates a new arrow with psNoPickup state and default damage modifier coeff + cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + + /// Creates a new arrow as shot by a player, initializes it from the player object + cArrowEntity(cPlayer & a_Player, double a_Force); + + // tolua_begin + + /// Returns whether the arrow can be picked up by players + ePickupState GetPickupState(void) const { return m_PickupState; } + + /// Sets a new pickup state + void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; } + + /// Returns the damage modifier coeff. + double GetDamageCoeff(void) const { return m_DamageCoeff; } + + /// Sets the damage modifier coeff + void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; } + + /// Returns true if the specified player can pick the arrow up + bool CanPickup(const cPlayer & a_Player) const; + + /// Returns true if the arrow is set as critical + bool IsCritical(void) const { return m_IsCritical; } + + /// Sets the IsCritical flag + void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; } + + // tolua_end + +protected: + + /// Determines when the arrow can be picked up by players + ePickupState m_PickupState; + + /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow + double m_DamageCoeff; + + /// If true, the arrow deals more damage + bool m_IsCritical; + + /// Timer for pickup collection animation or five minute timeout + float m_Timer; + + /// Timer for client arrow position confirmation via TeleportEntity + float m_HitGroundTimer; + + // Whether the arrow has already been teleported into the proper position in the ground. + bool m_HasTeleported; + + /// If true, the arrow is in the process of being collected - don't go to anyone else + bool m_bIsCollected; + + /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air + Vector3i m_HitBlockPos; + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + virtual void CollectedBy(cPlayer * a_Player) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + +}; // tolua_export diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp index 921252253..31bfe3dc3 100644 --- a/src/Entities/Boat.cpp +++ b/src/Entities/Boat.cpp @@ -33,9 +33,12 @@ void cBoat::SpawnOn(cClientHandle & a_ClientHandle) -void cBoat::DoTakeDamage(TakeDamageInfo & TDI) +bool cBoat::DoTakeDamage(TakeDamageInfo & TDI) { - super::DoTakeDamage(TDI); + if (!super::DoTakeDamage(TDI)) + { + return false; + } if (GetHealth() == 0) { @@ -50,6 +53,7 @@ void cBoat::DoTakeDamage(TakeDamageInfo & TDI) } Destroy(true); } + return true; } diff --git a/src/Entities/Boat.h b/src/Entities/Boat.h index c4c9afe7a..0fcfbd602 100644 --- a/src/Entities/Boat.h +++ b/src/Entities/Boat.h @@ -26,7 +26,7 @@ public: // cEntity overrides: virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void OnRightClicked(cPlayer & a_Player) override; - virtual void DoTakeDamage(TakeDamageInfo & TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override; diff --git a/src/Entities/CMakeLists.txt b/src/Entities/CMakeLists.txt index 85cc45494..c9ca44d38 100644 --- a/src/Entities/CMakeLists.txt +++ b/src/Entities/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Entities ${SOURCE}) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 6da6da54e..5c675a387 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -53,6 +53,8 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_TicksSinceLastVoidDamage(0) , m_IsSwimming(false) , m_IsSubmerged(false) + , m_AirLevel(0) + , m_AirTickTimer(0) , m_HeadYaw( 0.0 ) , m_Rot(0.0, 0.0, 0.0) , m_Pos(a_X, a_Y, a_Z) @@ -60,6 +62,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_Mass (0.001) // Default 1g , m_Width(a_Width) , m_Height(a_Height) + , m_InvulnerableTicks(0) { cCSLock Lock(m_CSCount); m_EntityCount++; @@ -294,17 +297,23 @@ void cEntity::SetPitchFromSpeed(void) -void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) { if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI)) { - return; + return false; } if (m_Health <= 0) { // Can't take damage if already dead - return; + return false; + } + + if (m_InvulnerableTicks > 0) + { + // Entity is invulnerable + return false; } if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) @@ -326,17 +335,49 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) m_Health = 0; } - if (IsMob() || IsPlayer()) // Knockback for only players and mobs + if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != NULL)) // Knockback for only players and mobs { - AddSpeed(a_TDI.Knockback * 2); + int KnockbackLevel = 0; + if (a_TDI.Attacker->GetEquippedWeapon().m_ItemType == E_ITEM_BOW) + { + KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchPunch); + } + else + { + KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback); + } + + Vector3d additionalSpeed(0, 0, 0); + switch (KnockbackLevel) + { + case 1: + { + additionalSpeed.Set(5, .3, 5); + break; + } + case 2: + { + additionalSpeed.Set(8, .3, 8); + break; + } + default: + { + additionalSpeed.Set(2, .3, 2); + break; + } + } + AddSpeed(a_TDI.Knockback * additionalSpeed); } m_World->BroadcastEntityStatus(*this, esGenericHurt); + m_InvulnerableTicks = 10; + if (m_Health <= 0) { KilledBy(a_TDI.Attacker); } + return true; } @@ -381,11 +422,8 @@ int cEntity::GetRawDamageAgainst(const cEntity & a_Receiver) -int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage) +bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType) { - // Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover - - // Filter out damage types that are not protected by armor: // Ref.: http://www.minecraftwiki.net/wiki/Armor#Effects as of 2012_12_20 switch (a_DamageType) { @@ -400,9 +438,34 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama case dtLightning: case dtPlugin: { - return 0; + return false; + } + + case dtAttack: + case dtArrowAttack: + case dtCactusContact: + case dtLavaContact: + case dtFireContact: + case dtEnderPearl: + case dtExplosion: + { + return true; } } + ASSERT(!"Invalid damage type!"); + return false; +} + + + + + +int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage) +{ + // Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover + + // Filter out damage types that are not protected by armor: + if (!ArmorCoversAgainst(a_DamageType)) return 0; // Add up all armor points: // Ref.: http://www.minecraftwiki.net/wiki/Armor#Defense_points as of 2012_12_20 @@ -511,6 +574,11 @@ void cEntity::SetHealth(int a_Health) void cEntity::Tick(float a_Dt, cChunk & a_Chunk) { + if (m_InvulnerableTicks > 0) + { + m_InvulnerableTicks--; + } + if (m_AttachedTo != NULL) { if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5) @@ -773,14 +841,12 @@ void cEntity::TickBurning(cChunk & a_Chunk) // Remember the current burning state: bool HasBeenBurning = (m_TicksLeftBurning > 0); - if (GetWorld()->GetWeather() == eWeather_Rain) + if (m_World->IsWeatherWet()) { - if (HasBeenBurning) + if (POSY_TOINT > m_World->GetHeight(POSX_TOINT, POSZ_TOINT)) { m_TicksLeftBurning = 0; - OnFinishedBurning(); - } - return; + } } // Do the burning damage: diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 86efc5a98..a682701de 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -262,14 +262,19 @@ public: // tolua_end - /// Makes this entity take damage specified in the a_TDI. The TDI is sent through plugins first, then applied - virtual void DoTakeDamage(TakeDamageInfo & a_TDI); + /** Makes this entity take damage specified in the a_TDI. + The TDI is sent through plugins first, then applied. + If it returns false, the entity hasn't receive any damage. */ + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI); // tolua_begin /// Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items virtual int GetRawDamageAgainst(const cEntity & a_Receiver); + /** Returns whether armor will protect against the passed damage type **/ + virtual bool ArmorCoversAgainst(eDamageType a_DamageType); + /// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover virtual int GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_RawDamage); @@ -391,6 +396,12 @@ public: virtual bool IsSubmerged(void) const{ return m_IsSubmerged; } /** Gets remaining air of a monster */ int GetAirLevel(void) const { return m_AirLevel; } + + /** Gets the invulnerable ticks from the entity */ + int GetInvulnerableTicks(void) const { return m_InvulnerableTicks; } + + /** Set the invulnerable ticks from the entity */ + void SetInvulnerableTicks(int a_InvulnerableTicks) { m_InvulnerableTicks = a_InvulnerableTicks; } // tolua_end @@ -475,29 +486,33 @@ protected: int m_AirTickTimer; private: - // Measured in degrees, [-180, +180) + /** Measured in degrees, [-180, +180) */ double m_HeadYaw; - // Measured in meter/second (m/s) + /** Measured in meter/second (m/s) */ Vector3d m_Speed; - // Measured in degrees, [-180, +180) + /** Measured in degrees, [-180, +180) */ Vector3d m_Rot; - /// Position of the entity's XZ center and Y bottom + /** Position of the entity's XZ center and Y bottom */ Vector3d m_Pos; - // Measured in meter / second + /** Measured in meter / second */ Vector3d m_WaterSpeed; - // Measured in Kilograms (Kg) + /** Measured in Kilograms (Kg) */ double m_Mass; - /// Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter. + /** Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter. */ double m_Width; - /// Height of the entity (Y axis) + /** Height of the entity (Y axis) */ double m_Height; + + /** If a player hit a entity, the entity receive a invulnerable of 10 ticks. + While this ticks, a player can't hit this entity. */ + int m_InvulnerableTicks; } ; // tolua_export typedef std::list<cEntity *> cEntityList; diff --git a/src/Entities/ExpBottleEntity.cpp b/src/Entities/ExpBottleEntity.cpp new file mode 100644 index 000000000..202dde942 --- /dev/null +++ b/src/Entities/ExpBottleEntity.cpp @@ -0,0 +1,27 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "ExpBottleEntity.h" +#include "../World.h" + + + + + +cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + // Spawn an experience orb with a reward between 3 and 11. + m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0); + m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8)); + + Destroy(); +} diff --git a/src/Entities/ExpBottleEntity.h b/src/Entities/ExpBottleEntity.h new file mode 100644 index 000000000..b2043d8f1 --- /dev/null +++ b/src/Entities/ExpBottleEntity.h @@ -0,0 +1,33 @@ +// +// ExpBottleEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cExpBottleEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cExpBottleEntity); + + cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + +}; // tolua_export diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp index a66c7e4ae..bcdac0291 100644 --- a/src/Entities/FallingBlock.cpp +++ b/src/Entities/FallingBlock.cpp @@ -87,7 +87,9 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk) AddSpeedY(MilliDt * -9.8f); AddPosition(GetSpeed() * MilliDt); - if ((GetSpeedX() != 0) || (GetSpeedZ() != 0)) + // If not static (One billionth precision) broadcast movement. + static const float epsilon = 0.000000001; + if ((fabs(GetSpeedX()) > epsilon) || (fabs(GetSpeedZ()) > epsilon)) { BroadcastMovementUpdate(); } diff --git a/src/Entities/FireChargeEntity.cpp b/src/Entities/FireChargeEntity.cpp new file mode 100644 index 000000000..aba32602f --- /dev/null +++ b/src/Entities/FireChargeEntity.cpp @@ -0,0 +1,50 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "FireChargeEntity.h" +#include "../World.h" + + + + + +cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125) +{ + SetSpeed(a_Speed); + SetGravity(0); +} + + + + + +void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) + { + m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1); + } +} + + + + + +void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} + + + + + +void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); + + // TODO: Some entities are immune to hits + a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning +} diff --git a/src/Entities/FireChargeEntity.h b/src/Entities/FireChargeEntity.h new file mode 100644 index 000000000..3924c337c --- /dev/null +++ b/src/Entities/FireChargeEntity.h @@ -0,0 +1,36 @@ +// +// FireChargeEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cFireChargeEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cFireChargeEntity); + + cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + +} ; // tolua_export diff --git a/src/Entities/FireworkEntity.cpp b/src/Entities/FireworkEntity.cpp new file mode 100644 index 000000000..403a53c84 --- /dev/null +++ b/src/Entities/FireworkEntity.cpp @@ -0,0 +1,73 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "FireworkEntity.h" +#include "../World.h" +#include "../Chunk.h" + + + + + +cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) : + super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), + m_ExplodeTimer(0), + m_FireworkItem(a_Item) +{ +} + + + + + +void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) +{ + int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width; + int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width; + int PosY = POSY_TOINT; + + if ((PosY < 0) || (PosY >= cChunkDef::Height)) + { + goto setspeed; + } + + if (m_IsInGround) + { + if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR) + { + m_IsInGround = false; + } + else + { + return; + } + } + else + { + if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR) + { + OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM); + return; + } + } + +setspeed: + AddSpeedY(1); + AddPosition(GetSpeed() * (a_Dt / 1000)); +} + + + + + +void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + + if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks) + { + m_World->BroadcastEntityStatus(*this, esFireworkExploding); + Destroy(); + } + + m_ExplodeTimer++; +} diff --git a/src/Entities/FireworkEntity.h b/src/Entities/FireworkEntity.h new file mode 100644 index 000000000..c62ca9402 --- /dev/null +++ b/src/Entities/FireworkEntity.h @@ -0,0 +1,40 @@ +// +// FireworkEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cFireworkEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cFireworkEntity); + + cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item); + const cItem & GetItem(void) const { return m_FireworkItem; } + +protected: + + // cProjectileEntity overrides: + virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + +private: + + int m_ExplodeTimer; + cItem m_FireworkItem; + +}; // tolua_export diff --git a/src/Entities/GhastFireballEntity.cpp b/src/Entities/GhastFireballEntity.cpp new file mode 100644 index 000000000..9e4cb387e --- /dev/null +++ b/src/Entities/GhastFireballEntity.cpp @@ -0,0 +1,44 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "GhastFireballEntity.h" +#include "../World.h" + + + + + +cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1) +{ + SetSpeed(a_Speed); + SetGravity(0); +} + + + + + +void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this); +} + + + + + +void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} + + + + + +void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} diff --git a/src/Entities/GhastFireballEntity.h b/src/Entities/GhastFireballEntity.h new file mode 100644 index 000000000..9e4572c78 --- /dev/null +++ b/src/Entities/GhastFireballEntity.h @@ -0,0 +1,38 @@ +// +// GhastFireballEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cGhastFireballEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cGhastFireballEntity); + + cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + + // TODO: Deflecting the fireballs by arrow- or sword- hits + +} ; // tolua_export diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index db55eb058..7bd440d6d 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -902,18 +902,21 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) -void cMinecart::DoTakeDamage(TakeDamageInfo & TDI) +bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI) { if ((TDI.Attacker != NULL) && TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative()) { Destroy(); TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative - super::DoTakeDamage(TDI); - return; // No drops for creative + SetInvulnerableTicks(0); + return super::DoTakeDamage(TDI); // No drops for creative } m_LastDamage = TDI.FinalDamage; - super::DoTakeDamage(TDI); + if (!super::DoTakeDamage(TDI)) + { + return false; + } m_World->BroadcastEntityMetadata(*this); @@ -952,12 +955,13 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI) default: { ASSERT(!"Unhandled minecart type when spawning pickup!"); - return; + return true; } } m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ()); } + return true; } diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h index ebdb576e0..1e60f091c 100644 --- a/src/Entities/Minecart.h +++ b/src/Entities/Minecart.h @@ -36,7 +36,7 @@ public: // cEntity overrides: virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; - virtual void DoTakeDamage(TakeDamageInfo & TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; virtual void Destroyed() override; int LastDamage(void) const { return m_LastDamage; } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index fedb62527..08b7d3984 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -808,14 +808,14 @@ void cPlayer::SetFlying(bool a_IsFlying) -void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) { if ((a_TDI.DamageType != dtInVoid) && (a_TDI.DamageType != dtPlugin)) { if (IsGameModeCreative()) { // No damage / health in creative mode if not void or plugin damage - return; + return false; } } @@ -828,17 +828,19 @@ void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) if (!m_Team->AllowsFriendlyFire()) { // Friendly fire is disabled - return; + return false; } } } - super::DoTakeDamage(a_TDI); - - // Any kind of damage adds food exhaustion - AddFoodExhaustion(0.3f); - - SendHealth(); + if (super::DoTakeDamage(a_TDI)) + { + // Any kind of damage adds food exhaustion + AddFoodExhaustion(0.3f); + SendHealth(); + return true; + } + return false; } @@ -897,6 +899,7 @@ void cPlayer::KilledBy(cEntity * a_Killer) void cPlayer::Respawn(void) { m_Health = GetMaxHealth(); + SetInvulnerableTicks(20); // Reset food level: m_FoodLevel = MAX_FOOD_LEVEL; diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 78d661015..3029abfe0 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -498,7 +498,7 @@ protected: virtual void Destroyed(void); /** Filters out damage for creative mode/friendly fire */ - virtual void DoTakeDamage(TakeDamageInfo & TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; /** Stops players from burning in creative mode */ virtual void TickBurning(cChunk & a_Chunk) override; diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 96db17ffd..3e48d310c 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -4,15 +4,24 @@ // Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types #include "Globals.h" + #include "../Bindings/PluginManager.h" #include "ProjectileEntity.h" #include "../ClientHandle.h" -#include "Player.h" #include "../LineBlockTracer.h" #include "../BoundingBox.h" #include "../ChunkMap.h" #include "../Chunk.h" +#include "ArrowEntity.h" +#include "ThrownEggEntity.h" +#include "ThrownEnderPearlEntity.h" +#include "ExpBottleEntity.h" +#include "ThrownSnowballEntity.h" +#include "FireChargeEntity.h" +#include "FireworkEntity.h" +#include "GhastFireballEntity.h" + @@ -401,495 +410,3 @@ void cProjectileEntity::CollectedBy(cPlayer * a_Dest) // Overriden in arrow UNUSED(a_Dest); } - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cArrowEntity: - -cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5), - m_PickupState(psNoPickup), - m_DamageCoeff(2), - m_IsCritical(false), - m_Timer(0), - m_HitGroundTimer(0), - m_bIsCollected(false), - m_HitBlockPos(Vector3i(0, 0, 0)) -{ - SetSpeed(a_Speed); - SetMass(0.1); - SetYawFromSpeed(); - SetPitchFromSpeed(); - LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}", - m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(), - GetYaw(), GetPitch() - ); -} - - - - - -cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : - super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5), - m_PickupState(psInSurvivalOrCreative), - m_DamageCoeff(2), - m_IsCritical((a_Force >= 1)), - m_Timer(0), - m_HitGroundTimer(0), - m_bIsCollected(false), - m_HitBlockPos(0, 0, 0) -{ -} - - - - - -bool cArrowEntity::CanPickup(const cPlayer & a_Player) const -{ - switch (m_PickupState) - { - case psNoPickup: return false; - case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative()); - case psInCreative: return a_Player.IsGameModeCreative(); - } - ASSERT(!"Unhandled pickup state"); - return false; -} - - - - - -void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - if (a_HitFace == BLOCK_FACE_NONE) { return; } - - super::OnHitSolidBlock(a_HitPos, a_HitFace); - int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z; - - switch (a_HitFace) - { - case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed - case BLOCK_FACE_YM: - { - break; - } - default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true); - } - - m_HitBlockPos = Vector3i(a_X, a_Y, a_Z); - - // Broadcast arrow hit sound - m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); -} - - - - - -void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) -{ - if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat()) - { - // Not an entity that interacts with an arrow - return; - } - - int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5); - if (m_IsCritical) - { - Damage += m_World->GetTickRandomNumber(Damage / 2 + 2); - } - a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); - - // Broadcast successful hit sound - m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); - - Destroy(); -} - - - - - -void cArrowEntity::CollectedBy(cPlayer * a_Dest) -{ - if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest))) - { - int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW); - if (NumAdded > 0) // Only play effects if there was space in inventory - { - m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest); - // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) - m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); - m_bIsCollected = true; - } - } -} - - - - - -void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) -{ - super::Tick(a_Dt, a_Chunk); - m_Timer += a_Dt; - - if (m_bIsCollected) - { - if (m_Timer > 500.f) // 0.5 seconds - { - Destroy(); - return; - } - } - else if (m_Timer > 1000 * 60 * 5) // 5 minutes - { - Destroy(); - return; - } - - if (m_IsInGround) - { - // When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL - // Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing) - // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync - // Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position - - if (m_HitGroundTimer != -1) // Sent a teleport already, don't do again - { - if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case - { - m_World->BroadcastTeleportEntity(*this); - m_HitGroundTimer = -1; - } - else - { - m_HitGroundTimer += a_Dt; - } - } - - int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width; - int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width; - cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ); - - if (Chunk == NULL) - { - // Inside an unloaded chunk, abort - return; - } - - if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed? - { - m_IsInGround = false; // Yes, begin simulating physics again - } - } -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cThrownEggEntity: - -cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) -{ - SetSpeed(a_Speed); -} - - - - - -void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - if (m_World->GetTickRandomNumber(7) == 1) - { - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); - } - else if (m_World->GetTickRandomNumber(32) == 1) - { - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); - } - Destroy(); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cThrownEnderPearlEntity : - -cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) -{ - SetSpeed(a_Speed); -} - - - - - -void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - // Teleport the creator here, make them take 5 damage: - if (m_Creator != NULL) - { - // TODO: The coords might need some tweaking based on the block face - m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5); - m_Creator->TakeDamage(dtEnderPearl, this, 5, 0); - } - - Destroy(); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cThrownSnowballEntity : - -cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) -{ - SetSpeed(a_Speed); -} - - - - - -void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - Destroy(); -} - - - - - -void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) -{ - int TotalDamage = 0; - if (a_EntityHit.IsMob()) - { - cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType(); - if (MobType == cMonster::mtBlaze) - { - TotalDamage = 3; - } - else if (MobType == cMonster::mtEnderDragon) - { - TotalDamage = 1; - } - } - a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); - - Destroy(true); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cBottleOEnchantingEntity : - -cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : -super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) -{ - SetSpeed(a_Speed); -} - - - - - -void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - // Spawn an experience orb with a reward between 3 and 11. - m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0); - m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8)); - - Destroy(); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cFireworkEntity : - -cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) : -super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), - m_ExplodeTimer(0), - m_FireworkItem(a_Item) -{ -} - - - - - -void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) -{ - int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width; - int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width; - int PosY = POSY_TOINT; - - if ((PosY < 0) || (PosY >= cChunkDef::Height)) - { - goto setspeed; - } - - if (m_IsInGround) - { - if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR) - { - m_IsInGround = false; - } - else - { - return; - } - } - else - { - if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR) - { - OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM); - return; - } - } - -setspeed: - AddSpeedY(1); - AddPosition(GetSpeed() * (a_Dt / 1000)); -} - - - - - -void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk) -{ - super::Tick(a_Dt, a_Chunk); - - if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks) - { - m_World->BroadcastEntityStatus(*this, esFireworkExploding); - Destroy(); - } - - m_ExplodeTimer++; -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cGhastFireballEntity : - -cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1) -{ - SetSpeed(a_Speed); - SetGravity(0); -} - - - - - -void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) -{ - m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this); -} - - - - - -void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - Destroy(); - Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); -} - - - - - -void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) -{ - Destroy(); - Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cFireChargeEntity : - -cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125) -{ - SetSpeed(a_Speed); - SetGravity(0); -} - - - - - -void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) -{ - if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) - { - m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1); - } -} - - - - - -void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - Destroy(); - Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); -} - - - - - -void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) -{ - Destroy(); - Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); - - // TODO: Some entities are immune to hits - a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning -} - - - - diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index efb7ae783..ae06b072f 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -94,300 +94,4 @@ protected: virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; virtual void SpawnOn(cClientHandle & a_Client) override; - // tolua_begin -} ; - - - - - -class cArrowEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - /// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field - enum ePickupState - { - psNoPickup = 0, - psInSurvivalOrCreative = 1, - psInCreative = 2, - } ; - - // tolua_end - - CLASS_PROTODEF(cArrowEntity); - - /// Creates a new arrow with psNoPickup state and default damage modifier coeff - cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - - /// Creates a new arrow as shot by a player, initializes it from the player object - cArrowEntity(cPlayer & a_Player, double a_Force); - - // tolua_begin - - /// Returns whether the arrow can be picked up by players - ePickupState GetPickupState(void) const { return m_PickupState; } - - /// Sets a new pickup state - void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; } - - /// Returns the damage modifier coeff. - double GetDamageCoeff(void) const { return m_DamageCoeff; } - - /// Sets the damage modifier coeff - void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; } - - /// Returns true if the specified player can pick the arrow up - bool CanPickup(const cPlayer & a_Player) const; - - /// Returns true if the arrow is set as critical - bool IsCritical(void) const { return m_IsCritical; } - - /// Sets the IsCritical flag - void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; } - - // tolua_end - -protected: - - /// Determines when the arrow can be picked up by players - ePickupState m_PickupState; - - /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow - double m_DamageCoeff; - - /// If true, the arrow deals more damage - bool m_IsCritical; - - /// Timer for pickup collection animation or five minute timeout - float m_Timer; - - /// Timer for client arrow position confirmation via TeleportEntity - float m_HitGroundTimer; - - /// If true, the arrow is in the process of being collected - don't go to anyone else - bool m_bIsCollected; - - /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air - Vector3i m_HitBlockPos; - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - virtual void CollectedBy(cPlayer * a_Player) override; - virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - - // tolua_begin -} ; - - - - - -class cThrownEggEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cThrownEggEntity); - - cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - // tolua_end - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - - // tolua_begin - -} ; - - - - - -class cThrownEnderPearlEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cThrownEnderPearlEntity); - - cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - // tolua_end - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - - // tolua_begin - -} ; - - - - - -class cThrownSnowballEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cThrownSnowballEntity); - - cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - - // tolua_begin - -} ; - - - - - -class cExpBottleEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cExpBottleEntity); - - cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - - // tolua_begin - -}; - - - - - -class cFireworkEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cFireworkEntity); - - cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item); - const cItem & GetItem(void) const { return m_FireworkItem; } - -protected: - - // cProjectileEntity overrides: - virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; - virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - -private: - - int m_ExplodeTimer; - cItem m_FireworkItem; - - // tolua_begin - -}; - - - - - -class cGhastFireballEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cGhastFireballEntity); - - cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - - // TODO: Deflecting the fireballs by arrow- or sword- hits - - // tolua_begin - -} ; - - - - - -class cFireChargeEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cFireChargeEntity); - - cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - - // tolua_begin - -} ; - - - - -// tolua_end - - - +} ; // tolua_export diff --git a/src/Entities/ThrownEggEntity.cpp b/src/Entities/ThrownEggEntity.cpp new file mode 100644 index 000000000..224019091 --- /dev/null +++ b/src/Entities/ThrownEggEntity.cpp @@ -0,0 +1,59 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "ThrownEggEntity.h" +#include "../World.h" + + + + + +cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + TrySpawnChicken(a_HitPos); + + Destroy(); +} + + + + + +void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + int TotalDamage = 0; + // TODO: If entity is Ender Crystal, destroy it + + TrySpawnChicken(a_HitPos); + a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); + + Destroy(true); +} + + + + + +void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos) +{ + if (m_World->GetTickRandomNumber(7) == 1) + { + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + } + else if (m_World->GetTickRandomNumber(32) == 1) + { + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + } +} diff --git a/src/Entities/ThrownEggEntity.h b/src/Entities/ThrownEggEntity.h new file mode 100644 index 000000000..5ba8f051b --- /dev/null +++ b/src/Entities/ThrownEggEntity.h @@ -0,0 +1,37 @@ +// +// ThrownEggEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cThrownEggEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownEggEntity); + + cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + + // Randomly decides whether to spawn a chicken where the egg lands. + void TrySpawnChicken(const Vector3d & a_HitPos); + +} ; // tolua_export diff --git a/src/Entities/ThrownEnderPearlEntity.cpp b/src/Entities/ThrownEnderPearlEntity.cpp new file mode 100644 index 000000000..c37161145 --- /dev/null +++ b/src/Entities/ThrownEnderPearlEntity.cpp @@ -0,0 +1,54 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "ThrownEnderPearlEntity.h" + + + + + +cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + // TODO: Tweak a_HitPos based on block face. + TeleportCreator(a_HitPos); + + Destroy(); +} + + + + + +void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + int TotalDamage = 0; + // TODO: If entity is Ender Crystal, destroy it + + TeleportCreator(a_HitPos); + a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); + + Destroy(true); +} + + + + + +void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos) +{ + // Teleport the creator here, make them take 5 damage: + if (m_Creator != NULL) + { + m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5); + m_Creator->TakeDamage(dtEnderPearl, this, 5, 0); + } +} diff --git a/src/Entities/ThrownEnderPearlEntity.h b/src/Entities/ThrownEnderPearlEntity.h new file mode 100644 index 000000000..ddee5babe --- /dev/null +++ b/src/Entities/ThrownEnderPearlEntity.h @@ -0,0 +1,37 @@ +// +// ThrownEnderPearlEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cThrownEnderPearlEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownEnderPearlEntity); + + cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + + // Teleports the creator where the ender pearl lands. + void TeleportCreator(const Vector3d & a_HitPos); + +} ; // tolua_export diff --git a/src/Entities/ThrownSnowballEntity.cpp b/src/Entities/ThrownSnowballEntity.cpp new file mode 100644 index 000000000..427f630f7 --- /dev/null +++ b/src/Entities/ThrownSnowballEntity.cpp @@ -0,0 +1,48 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "ThrownSnowballEntity.h" +#include "../World.h" + + + + + +cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + Destroy(); +} + + + + + +void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + int TotalDamage = 0; + if (a_EntityHit.IsMob()) + { + cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType(); + if (MobType == cMonster::mtBlaze) + { + TotalDamage = 3; + } + else if (MobType == cMonster::mtEnderDragon) + { + TotalDamage = 1; + } + } + // TODO: If entity is Ender Crystal, destroy it + a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); + + Destroy(true); +} diff --git a/src/Entities/ThrownSnowballEntity.h b/src/Entities/ThrownSnowballEntity.h new file mode 100644 index 000000000..a09512e37 --- /dev/null +++ b/src/Entities/ThrownSnowballEntity.h @@ -0,0 +1,34 @@ +// +// ThrownSnowballEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cThrownSnowballEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownSnowballEntity); + + cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + +} ; // tolua_export diff --git a/src/FastRandom.cpp b/src/FastRandom.cpp index c45261947..42bf5f3f9 100644 --- a/src/FastRandom.cpp +++ b/src/FastRandom.cpp @@ -91,7 +91,8 @@ int cFastRandom::m_SeedCounter = 0; cFastRandom::cFastRandom(void) : - m_Seed(m_SeedCounter++) + m_Seed(m_SeedCounter++), + m_Counter(0) { } diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt index 1147744c0..3dacb5066 100644 --- a/src/Generating/CMakeLists.txt +++ b/src/Generating/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Generating ${SOURCE}) diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp index c0c9e8a13..44d5097de 100644 --- a/src/Generating/Prefab.cpp +++ b/src/Generating/Prefab.cpp @@ -283,7 +283,7 @@ void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef) if ((NumElements >= 3) && !CharDef[2].empty()) { BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str()); - ASSERT((BlockMeta >= 0) && (BlockMeta <= 15)); + ASSERT((BlockMeta <= 15)); } a_CharMapOut[Src].m_BlockMeta = BlockMeta; } // for itr - Lines[] diff --git a/src/Generating/Prefabs/CMakeLists.txt b/src/Generating/Prefabs/CMakeLists.txt index 1e60447e7..a1f09112d 100644 --- a/src/Generating/Prefabs/CMakeLists.txt +++ b/src/Generating/Prefabs/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Generating_Prefabs ${SOURCE}) diff --git a/src/HTTPServer/CMakeLists.txt b/src/HTTPServer/CMakeLists.txt index 3badc669f..dc894368d 100644 --- a/src/HTTPServer/CMakeLists.txt +++ b/src/HTTPServer/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(HTTPServer ${SOURCE}) diff --git a/src/Items/CMakeLists.txt b/src/Items/CMakeLists.txt index 44a9f594f..a6fe6ea70 100644 --- a/src/Items/CMakeLists.txt +++ b/src/Items/CMakeLists.txt @@ -4,4 +4,9 @@ project (MCServer) include_directories ("${PROJECT_SOURCE_DIR}/../") -add_library(Items ItemHandler) +file(GLOB SOURCE + "*.cpp" + "*.h" +) + +add_library(Items ${SOURCE}) diff --git a/src/Items/ItemArmor.h b/src/Items/ItemArmor.h new file mode 100644 index 000000000..08cddb1ad --- /dev/null +++ b/src/Items/ItemArmor.h @@ -0,0 +1,67 @@ + +#pragma once + +#include "ItemHandler.h" +#include "../World.h" + + + + + +class cItemArmorHandler : + public cItemHandler +{ +public: + cItemArmorHandler(int a_ItemType) : + cItemHandler(a_ItemType) + { + } + + /** Move the armor to the armor slot of the player's inventory */ + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override + { + int SlotNum; + if (ItemCategory::IsHelmet(a_Item.m_ItemType)) + { + SlotNum = 0; + } + else if (ItemCategory::IsChestPlate(a_Item.m_ItemType)) + { + SlotNum = 1; + } + else if (ItemCategory::IsLeggings(a_Item.m_ItemType)) + { + SlotNum = 2; + } + else if (ItemCategory::IsBoots(a_Item.m_ItemType)) + { + SlotNum = 3; + } + else + { + LOGWARNING("Used unknown armor: %i", a_Item.m_ItemType); + return false; + } + + if (!a_Player->GetInventory().GetArmorSlot(SlotNum).IsEmpty()) + { + return false; + } + + a_Player->GetInventory().SetArmorSlot(SlotNum, a_Item.CopyOne()); + + cItem Item(a_Item); + Item.m_ItemCount--; + if (Item.m_ItemCount <= 0) + { + Item.Empty(); + } + a_Player->GetInventory().SetHotbarSlot(a_Player->GetInventory().GetEquippedSlotNum(), Item); + return true; + } + +} ; + + + + diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index 410c5f512..8c0b3a0a3 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -9,7 +9,7 @@ #pragma once -#include "../Entities/ProjectileEntity.h" +#include "../Entities/ArrowEntity.h" diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 5151eac38..ce9593a70 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -8,6 +8,7 @@ #include "../BlockInServerPluginInterface.h" // Handlers: +#include "ItemArmor.h" #include "ItemBed.h" #include "ItemBoat.h" #include "ItemBow.h" @@ -222,6 +223,31 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) { return new cItemFoodHandler(a_ItemType); } + + // Armor: + case E_ITEM_LEATHER_CAP: + case E_ITEM_GOLD_HELMET: + case E_ITEM_CHAIN_HELMET: + case E_ITEM_IRON_HELMET: + case E_ITEM_DIAMOND_HELMET: + case E_ITEM_LEATHER_TUNIC: + case E_ITEM_GOLD_CHESTPLATE: + case E_ITEM_CHAIN_CHESTPLATE: + case E_ITEM_IRON_CHESTPLATE: + case E_ITEM_DIAMOND_CHESTPLATE: + case E_ITEM_LEATHER_PANTS: + case E_ITEM_GOLD_LEGGINGS: + case E_ITEM_CHAIN_LEGGINGS: + case E_ITEM_IRON_LEGGINGS: + case E_ITEM_DIAMOND_LEGGINGS: + case E_ITEM_LEATHER_BOOTS: + case E_ITEM_GOLD_BOOTS: + case E_ITEM_CHAIN_BOOTS: + case E_ITEM_IRON_BOOTS: + case E_ITEM_DIAMOND_BOOTS: + { + return new cItemArmorHandler(a_ItemType); + } } } diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index f3d78335e..4993eac85 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -21,13 +21,13 @@ class cItemHandler public: cItemHandler(int a_ItemType); - // Force virtual destructor + /** Force virtual destructor */ virtual ~cItemHandler() {} - /// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False + /** Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False */ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir); - /// Called when the client sends the SHOOT status in the lclk packet + /** Called when the client sends the SHOOT status in the lclk packet */ virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) { UNUSED(a_BlockX); @@ -36,7 +36,7 @@ public: UNUSED(a_BlockFace); } - /// Called every tick while the item is on the player's inventory (Used by maps) - For now, called only for equipped items + /** Called every tick while the item is on the player's inventory (Used by maps) - For now, called only for equipped items */ virtual void OnUpdate(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item) { UNUSED(a_World); @@ -44,16 +44,16 @@ public: UNUSED(a_Item); } - /// Called while the player diggs a block using this item + /** Called while the player diggs a block using this item */ virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace); - /// Called when the player destroys a block using this item. This also calls the drop function for the destroyed block + /** Called when the player destroys a block using this item. This also calls the drop function for the destroyed block */ virtual void OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_X, int a_Y, int a_Z); - /// Called after the player has eaten this item. + /** Called after the player has eaten this item. */ virtual void OnFoodEaten(cWorld *a_World, cPlayer *a_Player, cItem *a_Item); - /// Returns the maximum stack size for a given item + /** Returns the maximum stack size for a given item */ virtual char GetMaxStackSize(void); struct FoodInfo @@ -70,22 +70,22 @@ public: } } ; - /// Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance) + /** Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance) */ virtual FoodInfo GetFoodInfo(); - /// Lets the player eat a selected item. Returns true if the player ate the item + /** Lets the player eat a selected item. Returns true if the player ate the item */ virtual bool EatItem(cPlayer *a_Player, cItem *a_Item); - /// Indicates if this item is a tool + /** Indicates if this item is a tool */ virtual bool IsTool(void); - /// Indicates if this item is food + /** Indicates if this item is food */ virtual bool IsFood(void); - /// Blocks simply get placed + /** Blocks simply get placed */ virtual bool IsPlaceable(void); - /** Called before a block is placed into a world. + /** Called before a block is placed into a world. The handler should return true to allow placement, false to refuse. Also, the handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block. */ @@ -96,7 +96,7 @@ public: BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ); - /// Returns whether this tool/item can harvest a specific block (e.g. wooden pickaxe can harvest stone, but wood can´t) DEFAULT: False + /** Returns whether this tool/item can harvest a specific block (e.g. wooden pickaxe can harvest stone, but wood can�t) DEFAULT: False */ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType); static cItemHandler * GetItemHandler(int a_ItemType); diff --git a/src/LineBlockTracer.cpp b/src/LineBlockTracer.cpp index f4f29e833..b03652bab 100644 --- a/src/LineBlockTracer.cpp +++ b/src/LineBlockTracer.cpp @@ -171,7 +171,6 @@ bool cLineBlockTracer::MoveToNextBlock(void) double CoeffZ = (DestZ - m_StartZ) / m_DiffZ; if (CoeffZ < Coeff) { - Coeff = CoeffZ; Direction = dirZ; } } diff --git a/src/MCLogger.cpp b/src/MCLogger.cpp index 80fa7b173..583438d65 100644 --- a/src/MCLogger.cpp +++ b/src/MCLogger.cpp @@ -9,7 +9,6 @@ cMCLogger * cMCLogger::s_MCLogger = NULL; -bool g_ShouldColorOutput = false; #ifdef _WIN32 #include <io.h> // Needed for _isatty(), not available on Linux @@ -33,7 +32,8 @@ cMCLogger * cMCLogger::GetInstance(void) -cMCLogger::cMCLogger(void) +cMCLogger::cMCLogger(void): + m_ShouldColorOutput(false) { AString FileName; Printf(FileName, "LOG_%d.txt", (int)time(NULL)); @@ -76,15 +76,15 @@ void cMCLogger::InitLog(const AString & a_FileName) #ifdef _WIN32 // See whether we are writing to a console the default console attrib: - g_ShouldColorOutput = (_isatty(_fileno(stdin)) != 0); - if (g_ShouldColorOutput) + m_ShouldColorOutput = (_isatty(_fileno(stdin)) != 0); + if (m_ShouldColorOutput) { CONSOLE_SCREEN_BUFFER_INFO sbi; GetConsoleScreenBufferInfo(g_Console, &sbi); g_DefaultConsoleAttrib = sbi.wAttributes; } #elif defined (__linux) && !defined(ANDROID_NDK) - g_ShouldColorOutput = isatty(fileno(stdout)); + m_ShouldColorOutput = isatty(fileno(stdout)); // TODO: Check if the terminal supports colors, somehow? #endif } @@ -178,7 +178,7 @@ void cMCLogger::Error(const char * a_Format, va_list a_ArgList) void cMCLogger::SetColor(eColorScheme a_Scheme) { - if (!g_ShouldColorOutput) + if (!m_ShouldColorOutput) { return; } @@ -211,7 +211,7 @@ void cMCLogger::SetColor(eColorScheme a_Scheme) void cMCLogger::ResetColor(void) { - if (!g_ShouldColorOutput) + if (!m_ShouldColorOutput) { return; } diff --git a/src/MCLogger.h b/src/MCLogger.h index c0150c124..114210f63 100644 --- a/src/MCLogger.h +++ b/src/MCLogger.h @@ -52,6 +52,7 @@ private: cCriticalSection m_CriticalSection; cLog * m_Log; static cMCLogger * s_MCLogger; + bool m_ShouldColorOutput; /// Sets the specified color scheme in the terminal (TODO: if coloring available) diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp index 0901f85a9..447bf3549 100644 --- a/src/Mobs/AggressiveMonster.cpp +++ b/src/Mobs/AggressiveMonster.cpp @@ -37,7 +37,7 @@ void cAggressiveMonster::InStateChasing(float a_Dt) } } - if (((float)m_FinalDestination.x != (float)m_Target->GetPosX()) || ((float)m_FinalDestination.z != (float)m_Target->GetPosZ())) + if (!IsMovingToTargetPosition()) { MoveToPosition(m_Target->GetPosition()); } @@ -106,3 +106,18 @@ void cAggressiveMonster::Attack(float a_Dt) +bool cAggressiveMonster::IsMovingToTargetPosition() +{ + static const float epsilon = 0.000000000001f; + // Difference between destination x and target x is negligible (to 10^-12 precision) + if (fabsf((float)m_FinalDestination.x - (float)m_Target->GetPosX()) < epsilon) + { + return false; + } + // Difference between destination z and target z is negligible (to 10^-12 precision) + else if (fabsf((float)m_FinalDestination.z - (float)m_Target->GetPosZ()) > epsilon) + { + return false; + } + return true; +} diff --git a/src/Mobs/AggressiveMonster.h b/src/Mobs/AggressiveMonster.h index 152260f95..d70ff04a3 100644 --- a/src/Mobs/AggressiveMonster.h +++ b/src/Mobs/AggressiveMonster.h @@ -22,6 +22,10 @@ public: virtual void EventSeePlayer(cEntity *) override; virtual void Attack(float a_Dt); +protected: + /** Whether this mob's destination is the same as its target's position. */ + bool IsMovingToTargetPosition(); + } ; diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp index 84ff8929b..326b42f07 100644 --- a/src/Mobs/Blaze.cpp +++ b/src/Mobs/Blaze.cpp @@ -3,6 +3,7 @@ #include "Blaze.h" #include "../World.h" +#include "../Entities/FireChargeEntity.h" diff --git a/src/Mobs/CMakeLists.txt b/src/Mobs/CMakeLists.txt index 87fbfd2fc..53c265803 100644 --- a/src/Mobs/CMakeLists.txt +++ b/src/Mobs/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Mobs ${SOURCE}) diff --git a/src/Mobs/Cavespider.cpp b/src/Mobs/CaveSpider.cpp index 94e93283d..56ecd2d28 100644 --- a/src/Mobs/Cavespider.cpp +++ b/src/Mobs/CaveSpider.cpp @@ -1,15 +1,14 @@ - #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules -#include "Cavespider.h" +#include "CaveSpider.h" #include "../World.h" -cCavespider::cCavespider(void) : - super("Cavespider", mtCaveSpider, "mob.spider.say", "mob.spider.death", 0.7, 0.5) +cCaveSpider::cCaveSpider(void) : + super("CaveSpider", mtCaveSpider, "mob.spider.say", "mob.spider.death", 0.7, 0.5) { } @@ -17,7 +16,7 @@ cCavespider::cCavespider(void) : -void cCavespider::Tick(float a_Dt, cChunk & a_Chunk) +void cCaveSpider::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); @@ -29,7 +28,7 @@ void cCavespider::Tick(float a_Dt, cChunk & a_Chunk) -void cCavespider::GetDrops(cItems & a_Drops, cEntity * a_Killer) +void cCaveSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; if (a_Killer != NULL) diff --git a/src/Mobs/Cavespider.h b/src/Mobs/CaveSpider.h index 10ea03f7b..be9f174f9 100644 --- a/src/Mobs/Cavespider.h +++ b/src/Mobs/CaveSpider.h @@ -1,4 +1,3 @@ - #pragma once #include "AggressiveMonster.h" @@ -7,13 +6,13 @@ -class cCavespider : +class cCaveSpider : public cAggressiveMonster { typedef cAggressiveMonster super; public: - cCavespider(void); + cCaveSpider(void); CLASS_PROTODEF(cCaveSpider); diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp index 3471b4cf1..9cf539427 100644 --- a/src/Mobs/Creeper.cpp +++ b/src/Mobs/Creeper.cpp @@ -75,9 +75,12 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer) -void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (!super::DoTakeDamage(a_TDI)) + { + return false; + } if (a_TDI.DamageType == dtLightning) { @@ -85,6 +88,7 @@ void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI) } m_World->BroadcastEntityMetadata(*this); + return true; } diff --git a/src/Mobs/Creeper.h b/src/Mobs/Creeper.h index 9abca369b..fc7db6716 100644 --- a/src/Mobs/Creeper.h +++ b/src/Mobs/Creeper.h @@ -18,7 +18,7 @@ public: CLASS_PROTODEF(cCreeper); virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Attack(float a_Dt) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void OnRightClicked(cPlayer & a_Player) override; diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp index fe18f5e76..d8a7663f8 100644 --- a/src/Mobs/Ghast.cpp +++ b/src/Mobs/Ghast.cpp @@ -3,6 +3,7 @@ #include "Ghast.h" #include "../World.h" +#include "../Entities/GhastFireballEntity.h" diff --git a/src/Mobs/IncludeAllMonsters.h b/src/Mobs/IncludeAllMonsters.h index 1b436a11f..3460db993 100644 --- a/src/Mobs/IncludeAllMonsters.h +++ b/src/Mobs/IncludeAllMonsters.h @@ -1,6 +1,6 @@ #include "Bat.h" #include "Blaze.h" -#include "Cavespider.h" +#include "CaveSpider.h" #include "Chicken.h" #include "Cow.h" #include "Creeper.h" @@ -10,7 +10,7 @@ #include "Giant.h" #include "Horse.h" #include "IronGolem.h" -#include "Magmacube.h" +#include "MagmaCube.h" #include "Mooshroom.h" #include "Ocelot.h" #include "Pig.h" @@ -26,4 +26,4 @@ #include "Wither.h" #include "Wolf.h" #include "Zombie.h" -#include "Zombiepigman.h" +#include "ZombiePigman.h" diff --git a/src/Mobs/Magmacube.cpp b/src/Mobs/MagmaCube.cpp index 05405f082..3e9abc108 100644 --- a/src/Mobs/Magmacube.cpp +++ b/src/Mobs/MagmaCube.cpp @@ -1,7 +1,6 @@ - #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules -#include "Magmacube.h" +#include "MagmaCube.h" diff --git a/src/Mobs/Magmacube.h b/src/Mobs/MagmaCube.h index 130952970..43065cae5 100644 --- a/src/Mobs/Magmacube.h +++ b/src/Mobs/MagmaCube.h @@ -1,4 +1,3 @@ - #pragma once #include "AggressiveMonster.h" diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 248e88f5d..c66ab4e04 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -457,9 +457,12 @@ int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ) -void cMonster::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (!super::DoTakeDamage(a_TDI)) + { + return false; + } if((m_SoundHurt != "") && (m_Health > 0)) m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f); @@ -468,6 +471,7 @@ void cMonster::DoTakeDamage(TakeDamageInfo & a_TDI) { m_Target = a_TDI.Attacker; } + return true; } @@ -761,8 +765,10 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type) case mtChicken: return mfPassive; case mtCow: return mfPassive; case mtCreeper: return mfHostile; + case mtEnderDragon: return mfNoSpawn; case mtEnderman: return mfHostile; case mtGhast: return mfHostile; + case mtGiant: return mfNoSpawn; case mtHorse: return mfPassive; case mtIronGolem: return mfPassive; case mtMagmaCube: return mfHostile; @@ -773,17 +779,20 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type) case mtSilverfish: return mfHostile; case mtSkeleton: return mfHostile; case mtSlime: return mfHostile; + case mtSnowGolem: return mfNoSpawn; case mtSpider: return mfHostile; case mtSquid: return mfWater; case mtVillager: return mfPassive; case mtWitch: return mfHostile; - case mtWither: return mfHostile; + case mtWither: return mfNoSpawn; case mtWolf: return mfHostile; case mtZombie: return mfHostile; case mtZombiePigman: return mfHostile; - } ; + + case mtInvalidType: break; + } ASSERT(!"Unhandled mob type"); - return mfMaxplusone; + return mfUnhandled; } @@ -794,10 +803,12 @@ int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily) { switch (a_MobFamily) { - case mfHostile: return 40; - case mfPassive: return 40; - case mfAmbient: return 40; - case mfWater: return 400; + case mfHostile: return 40; + case mfPassive: return 40; + case mfAmbient: return 40; + case mfWater: return 400; + case mfNoSpawn: return -1; + case mfUnhandled: break; } ASSERT(!"Unhandled mob family"); return -1; @@ -859,13 +870,14 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType) case mtBat: toReturn = new cBat(); break; case mtBlaze: toReturn = new cBlaze(); break; - case mtCaveSpider: toReturn = new cCavespider(); break; + case mtCaveSpider: toReturn = new cCaveSpider(); break; 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 mtGiant: toReturn = new cGiant(); break; case mtIronGolem: toReturn = new cIronGolem(); break; case mtMooshroom: toReturn = new cMooshroom(); break; case mtOcelot: toReturn = new cOcelot(); break; diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index 70b3783fc..7d7e90eb2 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -66,7 +66,8 @@ public: mfAmbient = 2, // Bats mfWater = 3, // Squid - mfMaxplusone, // Nothing. Be sure this is the last and the others are in order + mfNoSpawn, + mfUnhandled, // Nothing. Be sure this is the last and the others are in order } ; // tolua_end @@ -87,7 +88,7 @@ public: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void KilledBy(cEntity * a_Killer) override; diff --git a/src/Mobs/PassiveAggressiveMonster.cpp b/src/Mobs/PassiveAggressiveMonster.cpp index 4b45f9a2a..24501b1ba 100644 --- a/src/Mobs/PassiveAggressiveMonster.cpp +++ b/src/Mobs/PassiveAggressiveMonster.cpp @@ -19,9 +19,12 @@ cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigNam -void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (!super::DoTakeDamage(a_TDI)) + { + return false; + } if ((m_Target != NULL) && (m_Target->IsPlayer())) { @@ -30,6 +33,7 @@ void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) m_EMState = CHASING; } } + return true; } diff --git a/src/Mobs/PassiveAggressiveMonster.h b/src/Mobs/PassiveAggressiveMonster.h index 2c5ef30b1..a0da50e8e 100644 --- a/src/Mobs/PassiveAggressiveMonster.h +++ b/src/Mobs/PassiveAggressiveMonster.h @@ -15,7 +15,7 @@ class cPassiveAggressiveMonster : public: cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; } ; diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp index 904cd63cc..2861d7314 100644 --- a/src/Mobs/PassiveMonster.cpp +++ b/src/Mobs/PassiveMonster.cpp @@ -18,13 +18,17 @@ cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, eType a_MobType, -void cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (!super::DoTakeDamage(a_TDI)) + { + return false; + } if ((a_TDI.Attacker != this) && (a_TDI.Attacker != NULL)) { m_EMState = ESCAPING; } + return true; } diff --git a/src/Mobs/PassiveMonster.h b/src/Mobs/PassiveMonster.h index 0b3c155da..70574585a 100644 --- a/src/Mobs/PassiveMonster.h +++ b/src/Mobs/PassiveMonster.h @@ -18,7 +18,7 @@ public: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; /// When hit by someone, run away - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; /** Returns the item that the animal of this class follows when a player holds it in hand Return an empty item not to follow (default). */ virtual const cItem GetFollowedItem(void) const { return cItem(); } diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp index 1685f40c5..1e62d7987 100644 --- a/src/Mobs/Skeleton.cpp +++ b/src/Mobs/Skeleton.cpp @@ -3,6 +3,7 @@ #include "Skeleton.h" #include "../World.h" +#include "../Entities/ArrowEntity.h" diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp index d049acc1e..41283acf4 100644 --- a/src/Mobs/Villager.cpp +++ b/src/Mobs/Villager.cpp @@ -23,9 +23,13 @@ cVillager::cVillager(eVillagerType VillagerType) : -void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (!super::DoTakeDamage(a_TDI)) + { + return false; + } + if ((a_TDI.Attacker != NULL) && a_TDI.Attacker->IsPlayer()) { if (m_World->GetTickRandomNumber(5) == 3) @@ -33,6 +37,7 @@ void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI) m_World->BroadcastEntityStatus(*this, esVillagerAngry); } } + return true; } diff --git a/src/Mobs/Villager.h b/src/Mobs/Villager.h index 5bba4d4ba..abde48407 100644 --- a/src/Mobs/Villager.h +++ b/src/Mobs/Villager.h @@ -30,7 +30,7 @@ public: CLASS_PROTODEF(cVillager); // cEntity overrides - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Tick (float a_Dt, cChunk & a_Chunk) override; // cVillager functions diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp index 8f5d28b68..5b6e895e1 100644 --- a/src/Mobs/Wither.cpp +++ b/src/Mobs/Wither.cpp @@ -10,7 +10,7 @@ cWither::cWither(void) : super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0), - m_InvulnerableTicks(220) + m_WitherInvulnerableTicks(220) { SetMaxHealth(300); } @@ -40,24 +40,24 @@ bool cWither::Initialize(cWorld * a_World) -void cWither::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cWither::DoTakeDamage(TakeDamageInfo & a_TDI) { if (a_TDI.DamageType == dtDrowning) { - return; + return false; } - if (m_InvulnerableTicks > 0) + if (m_WitherInvulnerableTicks > 0) { - return; + return false; } if (IsArmored() && (a_TDI.DamageType == dtRangedAttack)) { - return; + return false; } - super::DoTakeDamage(a_TDI); + return super::DoTakeDamage(a_TDI); } @@ -68,16 +68,16 @@ void cWither::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); - if (m_InvulnerableTicks > 0) + if (m_WitherInvulnerableTicks > 0) { - unsigned int NewTicks = m_InvulnerableTicks - 1; + unsigned int NewTicks = m_WitherInvulnerableTicks - 1; if (NewTicks == 0) { m_World->DoExplosionAt(7.0, GetPosX(), GetPosY(), GetPosZ(), false, esWitherBirth, this); } - m_InvulnerableTicks = NewTicks; + m_WitherInvulnerableTicks = NewTicks; if ((NewTicks % 10) == 0) { diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h index bc78bfaad..08b460009 100644 --- a/src/Mobs/Wither.h +++ b/src/Mobs/Wither.h @@ -17,9 +17,9 @@ public: CLASS_PROTODEF(cWither); - unsigned int GetNumInvulnerableTicks(void) const { return m_InvulnerableTicks; } + unsigned int GetWitherInvulnerableTicks(void) const { return m_WitherInvulnerableTicks; } - void SetNumInvulnerableTicks(unsigned int a_Ticks) { m_InvulnerableTicks = a_Ticks; } + void SetWitherInvulnerableTicks(unsigned int a_Ticks) { m_WitherInvulnerableTicks = a_Ticks; } /** Returns whether the wither is invulnerable to arrows. */ bool IsArmored(void) const; @@ -27,13 +27,13 @@ public: // cEntity overrides virtual bool Initialize(cWorld * a_World) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; private: /** The number of ticks of invulnerability left after being initially created. Zero once invulnerability has expired. */ - unsigned int m_InvulnerableTicks; + unsigned int m_WitherInvulnerableTicks; } ; diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp index f02b8a4fc..e6268abc7 100644 --- a/src/Mobs/Wolf.cpp +++ b/src/Mobs/Wolf.cpp @@ -25,14 +25,19 @@ cWolf::cWolf(void) : -void cWolf::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (super::DoTakeDamage(a_TDI)) + { + return false; + } + if (!m_IsTame) { m_IsAngry = true; } m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face + return true; } diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h index 5925373e1..fb8a7c995 100644 --- a/src/Mobs/Wolf.h +++ b/src/Mobs/Wolf.h @@ -18,7 +18,7 @@ public: CLASS_PROTODEF(cWolf); - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void OnRightClicked(cPlayer & a_Player) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void TickFollowPlayer(); diff --git a/src/Mobs/Zombiepigman.cpp b/src/Mobs/ZombiePigman.cpp index a0142b566..c9d94face 100644 --- a/src/Mobs/Zombiepigman.cpp +++ b/src/Mobs/ZombiePigman.cpp @@ -1,7 +1,6 @@ - #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules -#include "Zombiepigman.h" +#include "ZombiePigman.h" #include "../World.h" diff --git a/src/Mobs/Zombiepigman.h b/src/Mobs/ZombiePigman.h index 67991d56a..ab3cebf6d 100644 --- a/src/Mobs/Zombiepigman.h +++ b/src/Mobs/ZombiePigman.h @@ -1,4 +1,3 @@ - #pragma once #include "PassiveAggressiveMonster.h" diff --git a/src/Noise.cpp b/src/Noise.cpp index efbb128c3..13a194938 100644 --- a/src/Noise.cpp +++ b/src/Noise.cpp @@ -608,6 +608,8 @@ void cCubicNoise::Generate2D( NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY ///< Noise-space coords of the array in the Y direction ) const { + ASSERT(a_SizeX > 0); + ASSERT(a_SizeY > 0); ASSERT(a_SizeX < MAX_SIZE); ASSERT(a_SizeY < MAX_SIZE); ASSERT(a_StartX < a_EndX); @@ -744,6 +746,8 @@ void cCubicNoise::CalcFloorFrac( int * a_Same, int & a_NumSame ) const { + ASSERT(a_Size > 0); + NOISE_DATATYPE val = a_Start; NOISE_DATATYPE dif = (a_End - a_Start) / (a_Size - 1); for (int i = 0; i < a_Size; i++) diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt index 497cd0ba3..dee60b450 100644 --- a/src/OSSupport/CMakeLists.txt +++ b/src/OSSupport/CMakeLists.txt @@ -5,6 +5,7 @@ project (MCServer) include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(OSSupport ${SOURCE}) diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index 7f0f0ad2f..33b9cfc3f 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -67,11 +67,11 @@ bool cFile::Open(const AString & iFileName, eMode iMode) case fmRead: Mode = "rb"; break; case fmWrite: Mode = "wb"; break; case fmReadWrite: Mode = "rb+"; break; - default: - { - ASSERT(!"Unhandled file mode"); - return false; - } + } + if (Mode == NULL) + { + ASSERT(!"Unhandled file mode"); + return false; } #ifdef _WIN32 @@ -143,7 +143,7 @@ bool cFile::IsEOF(void) const -int cFile::Read (void * iBuffer, int iNumBytes) +int cFile::Read (void * iBuffer, size_t iNumBytes) { ASSERT(IsOpen()); @@ -159,7 +159,7 @@ int cFile::Read (void * iBuffer, int iNumBytes) -int cFile::Write(const void * iBuffer, int iNumBytes) +int cFile::Write(const void * iBuffer, size_t iNumBytes) { ASSERT(IsOpen()); diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h index b394c5cb9..2a7ecf0ed 100644 --- a/src/OSSupport/File.h +++ b/src/OSSupport/File.h @@ -80,10 +80,10 @@ public: bool IsEOF(void) const; /** Reads up to iNumBytes bytes into iBuffer, returns the number of bytes actually read, or -1 on failure; asserts if not open */ - int Read (void * iBuffer, int iNumBytes); + int Read (void * iBuffer, size_t iNumBytes); /** Writes up to iNumBytes bytes from iBuffer, returns the number of bytes actually written, or -1 on failure; asserts if not open */ - int Write(const void * iBuffer, int iNumBytes); + int Write(const void * iBuffer, size_t iNumBytes); /** Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open */ int Seek (int iPosition); diff --git a/src/OSSupport/GZipFile.cpp b/src/OSSupport/GZipFile.cpp index 7a8433f4f..22d887783 100644 --- a/src/OSSupport/GZipFile.cpp +++ b/src/OSSupport/GZipFile.cpp @@ -11,7 +11,7 @@ cGZipFile::cGZipFile(void) : - m_File(NULL) + m_File(NULL), m_Mode(fmRead) { } diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt index 107b79627..849ec27ca 100644 --- a/src/Protocol/CMakeLists.txt +++ b/src/Protocol/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Protocol ${SOURCE}) diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index 3282a827f..35ab72bfc 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -26,7 +26,7 @@ Documentation: #include "../Root.h" #include "../Server.h" -#include "../Entities/ProjectileEntity.h" +#include "../Entities/ArrowEntity.h" #include "../Entities/Minecart.h" #include "../Entities/FallingBlock.h" @@ -2013,7 +2013,7 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) case cMonster::mtWither: { WriteByte(0x54); // Int at index 20 - WriteInt((Int32)((const cWither &)a_Mob).GetNumInvulnerableTicks()); + WriteInt((Int32)((const cWither &)a_Mob).GetWitherInvulnerableTicks()); WriteByte(0x66); // Float at index 6 WriteFloat((float)(a_Mob.GetHealth())); break; diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index e57b551cb..a04d8ac3c 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -31,6 +31,8 @@ Implements the 1.7.x protocol classes: #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" #include "../CompositeChat.h" +#include "../Entities/ArrowEntity.h" +#include "../Entities/FireworkEntity.h" @@ -637,9 +639,11 @@ void cProtocol172::SendLoginSuccess(void) { ASSERT(m_State == 2); // State: login? - cPacketizer Pkt(*this, 0x02); // Login success packet - Pkt.WriteString(m_Client->GetUUID()); - Pkt.WriteString(m_Client->GetUsername()); + { + cPacketizer Pkt(*this, 0x02); // Login success packet + Pkt.WriteString(m_Client->GetUUID()); + Pkt.WriteString(m_Client->GetUsername()); + } m_State = 3; // State = Game } @@ -2820,7 +2824,7 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob) case cMonster::mtWither: { WriteByte(0x54); // Int at index 20 - WriteInt(((const cWither &)a_Mob).GetNumInvulnerableTicks()); + WriteInt(((const cWither &)a_Mob).GetWitherInvulnerableTicks()); WriteByte(0x66); // Float at index 6 WriteFloat((float)(a_Mob.GetHealth())); break; diff --git a/src/Simulator/CMakeLists.txt b/src/Simulator/CMakeLists.txt index 4f3f1ad0e..b2a29d45c 100644 --- a/src/Simulator/CMakeLists.txt +++ b/src/Simulator/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Simulator ${SOURCE}) diff --git a/src/Statistics.cpp b/src/Statistics.cpp new file mode 100644 index 000000000..2c980d98e --- /dev/null +++ b/src/Statistics.cpp @@ -0,0 +1,139 @@ + +// Statistics.cpp + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Statistics.h" + + + +cStatInfo cStatInfo::ms_Info[statCount] = { + // The order must match the order of enum eStatistic + + // http://minecraft.gamepedia.com/Achievements + + /* Type | Name | Prerequisite */ + cStatInfo(achOpenInv, "openInventory"), + cStatInfo(achMineWood, "mineWood", achOpenInv), + cStatInfo(achCraftWorkbench, "buildWorkBench", achMineWood), + cStatInfo(achCraftPickaxe, "buildPickaxe", achCraftWorkbench), + cStatInfo(achCraftFurnace, "buildFurnace", achCraftPickaxe), + cStatInfo(achAcquireIron, "acquireIron", achCraftFurnace), + cStatInfo(achCraftHoe, "buildHoe", achCraftWorkbench), + cStatInfo(achMakeBread, "makeBread", achCraftHoe), + cStatInfo(achBakeCake, "bakeCake", achCraftHoe), + cStatInfo(achCraftBetterPick, "buildBetterPickaxe", achCraftPickaxe), + cStatInfo(achCookFish, "cookFish", achAcquireIron), + cStatInfo(achOnARail, "onARail", achAcquireIron), + cStatInfo(achCraftSword, "buildSword", achCraftWorkbench), + cStatInfo(achKillMonster, "killEnemy", achCraftSword), + cStatInfo(achKillCow, "killCow", achCraftSword), + cStatInfo(achFlyPig, "flyPig", achKillCow), + cStatInfo(achSnipeSkeleton, "snipeSkeleton", achKillMonster), + cStatInfo(achDiamonds, "diamonds", achAcquireIron), + cStatInfo(achEnterPortal, "portal", achDiamonds), + cStatInfo(achReturnToSender, "ghast", achEnterPortal), + cStatInfo(achBlazeRod, "blazeRod", achEnterPortal), + cStatInfo(achBrewPotion, "potion", achBlazeRod), + cStatInfo(achEnterTheEnd, "theEnd", achBlazeRod), + cStatInfo(achDefeatDragon, "theEnd2", achEnterTheEnd), + cStatInfo(achCraftEnchantTable, "enchantments", achDiamonds), + cStatInfo(achOverkill, "overkill", achCraftEnchantTable), + cStatInfo(achBookshelf, "bookcase", achCraftEnchantTable), + cStatInfo(achExploreAllBiomes, "exploreAllBiomes", achEnterTheEnd), + cStatInfo(achSpawnWither, "spawnWither", achDefeatDragon), + cStatInfo(achKillWither, "killWither", achSpawnWither), + cStatInfo(achFullBeacon, "fullBeacon", achKillWither), + cStatInfo(achBreedCow, "breedCow", achKillCow), + cStatInfo(achThrowDiamonds, "diamondsToYou", achDiamonds), + + // http://minecraft.gamepedia.com/Statistics + + /* Type | Name */ + cStatInfo(statGamesQuit, "stat.leaveGame"), + cStatInfo(statMinutesPlayed, "stat.playOneMinute"), + cStatInfo(statDistWalked, "stat.walkOnCm"), + cStatInfo(statDistSwum, "stat.swimOneCm"), + cStatInfo(statDistFallen, "stat.fallOneCm"), + cStatInfo(statDistClimbed, "stat.climbOneCm"), + cStatInfo(statDistFlown, "stat.flyOneCm"), + cStatInfo(statDistMinecart, "stat.minecartOneCm"), + cStatInfo(statDistBoat, "stat.boatOneCm"), + cStatInfo(statDistPig, "stat.pigOneCm"), + cStatInfo(statDistHorse, "stat.horseOneCm"), + cStatInfo(statJumps, "stat.jump"), + cStatInfo(statItemsDropped, "stat.drop"), + cStatInfo(statDamageDealt, "stat.damageDealth"), + cStatInfo(statDamageTaken, "stat.damageTaken"), + cStatInfo(statDeaths, "stat.deaths"), + cStatInfo(statMobKills, "stat.mobKills"), + cStatInfo(statAnimalsBred, "stat.animalsBred"), + cStatInfo(statPlayerKills, "stat.playerKills"), + cStatInfo(statFishCaught, "stat.fishCaught"), + cStatInfo(statJunkFished, "stat.junkFished"), + cStatInfo(statTreasureFished, "stat.treasureFished") +}; + + + + + + +cStatInfo::cStatInfo() + : m_Type(statInvalid) + , m_Depends(statInvalid) +{} + + + + + +cStatInfo::cStatInfo(const eStatistic a_Type, const AString & a_Name, const eStatistic a_Depends) + : m_Type(a_Type) + , m_Name(a_Name) + , m_Depends(a_Depends) +{} + + + + + +const AString & cStatInfo::GetName(const eStatistic a_Type) +{ + ASSERT((a_Type > statInvalid) && (a_Type < statCount)); + + return ms_Info[a_Type].m_Name; +} + + + + + +eStatistic cStatInfo::GetType(const AString & a_Name) +{ + for (unsigned int i = 0; i < ARRAYCOUNT(ms_Info); ++i) + { + if (NoCaseCompare(ms_Info[i].m_Name, a_Name)) + { + return ms_Info[i].m_Type; + } + } + + return statInvalid; +} + + + + + +eStatistic cStatInfo::GetPrerequisite(const eStatistic a_Type) +{ + ASSERT((a_Type > statInvalid) && (a_Type < statCount)); + + return ms_Info[a_Type].m_Depends; +} + + + + + diff --git a/src/Statistics.h b/src/Statistics.h new file mode 100644 index 000000000..540df38cc --- /dev/null +++ b/src/Statistics.h @@ -0,0 +1,116 @@ + +// Statistics.h + + + + +#pragma once + + + + +enum eStatistic +{ + // The order must match the order of cStatInfo::ms_Info + + statInvalid = -1, + + /* Achievements */ + achOpenInv, /* Taking Inventory */ + achMineWood, /* Getting Wood */ + achCraftWorkbench, /* Benchmarking */ + achCraftPickaxe, /* Time to Mine! */ + achCraftFurnace, /* Hot Topic */ + achAcquireIron, /* Acquire Hardware */ + achCraftHoe, /* Time to Farm! */ + achMakeBread, /* Bake Bread */ + achBakeCake, /* The Lie */ + achCraftBetterPick, /* Getting an Upgrade */ + achCookFish, /* Delicious Fish */ + achOnARail, /* On A Rail */ + achCraftSword, /* Time to Strike! */ + achKillMonster, /* Monster Hunter */ + achKillCow, /* Cow Tipper */ + achFlyPig, /* When Pigs Fly */ + achSnipeSkeleton, /* Sniper Duel */ + achDiamonds, /* DIAMONDS! */ + achEnterPortal, /* We Need to Go Deeper */ + achReturnToSender, /* Return to Sender */ + achBlazeRod, /* Into Fire */ + achBrewPotion, /* Local Brewery */ + achEnterTheEnd, /* The End? */ + achDefeatDragon, /* The End. */ + achCraftEnchantTable, /* Enchanter */ + achOverkill, /* Overkill */ + achBookshelf, /* Librarian */ + achExploreAllBiomes, /* Adventuring Time */ + achSpawnWither, /* The Beginning? */ + achKillWither, /* The Beginning. */ + achFullBeacon, /* Beaconator */ + achBreedCow, /* Repopulation */ + achThrowDiamonds, /* Diamonds to you! */ + + /* Statistics */ + statGamesQuit, + statMinutesPlayed, + statDistWalked, + statDistSwum, + statDistFallen, + statDistClimbed, + statDistFlown, + statDistDove, + statDistMinecart, + statDistBoat, + statDistPig, + statDistHorse, + statJumps, + statItemsDropped, + statDamageDealt, + statDamageTaken, + statDeaths, + statMobKills, + statAnimalsBred, + statPlayerKills, + statFishCaught, + statJunkFished, + statTreasureFished, + + statCount +}; + + + + + + +/** Class used to store and query statistic-related information. */ +class cStatInfo +{ +public: + + cStatInfo(); + + cStatInfo(const eStatistic a_Type, const AString & a_Name, const eStatistic a_Depends = statInvalid); + + /** Type -> Name */ + static const AString & GetName(const eStatistic a_Type); + + /** Name -> Type */ + static eStatistic GetType(const AString & a_Name); + + /** Returns stat prerequisite. (Used for achievements) */ + static eStatistic GetPrerequisite(const eStatistic a_Type); + +private: + + eStatistic m_Type; + + AString m_Name; + + eStatistic m_Depends; + + static cStatInfo ms_Info[statCount]; +}; + + + diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt index cef2a9f35..5b5b8cc18 100644 --- a/src/UI/CMakeLists.txt +++ b/src/UI/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(UI ${SOURCE}) diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index 2d58388b1..87b4032e0 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -1091,6 +1091,80 @@ void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bo +void cSlotAreaArmor::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) +{ + ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); + + bool bAsync = false; + if (GetSlot(a_SlotNum, a_Player) == NULL) + { + LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + return; + } + + if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick)) + { + ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); + return; + } + + // Armors haven't a dbl click + if (a_ClickAction == caDblClick) + { + return; + } + + cItem Slot(*GetSlot(a_SlotNum, a_Player)); + if (!Slot.IsSameType(a_ClickedItem)) + { + LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots); + LOGWARNING("My item: %s", ItemToFullString(Slot).c_str()); + LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str()); + bAsync = true; + } + cItem & DraggingItem = a_Player.GetDraggingItem(); + if ((a_ClickAction != caRightClick) && (a_ClickAction != caLeftClick)) + { + LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction)); + m_ParentWindow.BroadcastWholeWindow(); + return; + } + + if (DraggingItem.IsEmpty() || CanPlaceInSlot(a_SlotNum, DraggingItem)) + { + // Swap contents + cItem tmp(DraggingItem); + DraggingItem = Slot; + Slot = tmp; + } + + SetSlot(a_SlotNum, a_Player, Slot); + if (bAsync) + { + m_ParentWindow.BroadcastWholeWindow(); + } +} + + + + + +bool cSlotAreaArmor::CanPlaceInSlot(int a_SlotNum, const cItem & a_Item) +{ + switch (a_SlotNum) + { + case 0: return ItemCategory::IsHelmet (a_Item.m_ItemType); + case 1: return ItemCategory::IsChestPlate(a_Item.m_ItemType); + case 2: return ItemCategory::IsLeggings (a_Item.m_ItemType); + case 3: return ItemCategory::IsBoots (a_Item.m_ItemType); + } + return false; +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cSlotAreaItemGrid: diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index bab1098bb..254722822 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -145,8 +145,13 @@ public: { } - // Distributing the stack is allowed only for compatible items (helmets into helmet slot etc.) + /** Distributing the stack is allowed only for compatible items (helmets into helmet slot etc.) */ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + + /** Called when a player clicks in the window. Parameters taken from the click packet. */ + virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; + + bool CanPlaceInSlot(int a_SlotNum, const cItem & a_Item); } ; diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp index a3b3cc5be..737705d7c 100644 --- a/src/WebAdmin.cpp +++ b/src/WebAdmin.cpp @@ -285,11 +285,6 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque Content = GetDefaultPage(); } - if (ShouldWrapInTemplate && (URL.size() > 1)) - { - Content += "\n<p><a href='" + BaseURL + "'>Go back</a></p>"; - } - int MemUsageKiB = cRoot::GetPhysicalRAMUsage(); if (MemUsageKiB > 0) { diff --git a/src/World.cpp b/src/World.cpp index 25ac9b021..5ac8e0a6e 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -316,12 +316,9 @@ int cWorld::GetDefaultWeatherInterval(eWeather a_Weather) { return 2400 + (m_TickRand.randInt() % 4800); // 2 - 6 minutes } - default: - { - LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather); - return -1; - } - } // switch (Weather) + } + LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather); + return -1; } @@ -521,21 +518,6 @@ void cWorld::Start(void) } AString Dimension = IniFile.GetValueSet("General", "Dimension", "Overworld"); m_Dimension = StringToDimension(Dimension); - switch (m_Dimension) - { - case dimNether: - case dimOverworld: - case dimEnd: - { - break; - } - default: - { - LOGWARNING("Unknown dimension: \"%s\". Setting to Overworld", Dimension.c_str()); - m_Dimension = dimOverworld; - break; - } - } // switch (m_Dimension) // Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found int KeyNum = IniFile.FindKey("SpawnPosition"); @@ -592,12 +574,6 @@ void cWorld::Start(void) case dimOverworld: DefaultMonsters = "bat, cavespider, chicken, cow, creeper, enderman, horse, mooshroom, ocelot, pig, sheep, silverfish, skeleton, slime, spider, squid, wolf, zombie"; break; case dimNether: DefaultMonsters = "blaze, ghast, magmacube, skeleton, zombie, zombiepigman"; break; case dimEnd: DefaultMonsters = "enderman"; break; - default: - { - ASSERT(!"Unhandled world dimension"); - DefaultMonsters = "wither"; - break; - } } m_bAnimals = IniFile.GetValueSetB("Monsters", "AnimalsOn", true); AString AllMonsters = IniFile.GetValueSet("Monsters", "Types", DefaultMonsters); @@ -687,6 +663,30 @@ void cWorld::GenerateRandomSpawn(void) +eWeather cWorld::ChooseNewWeather() +{ + // Pick a new weather. Only reasonable transitions allowed: + switch (m_Weather) + { + case eWeather_Sunny: + case eWeather_ThunderStorm: return eWeather_Rain; + + case eWeather_Rain: + { + // 1/8 chance of turning into a thunderstorm + return ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny; + } + } + + LOGWARNING("Unknown current weather: %d. Setting sunny.", m_Weather); + ASSERT(!"Unknown weather"); + return eWeather_Sunny; +} + + + + + void cWorld::Stop(void) { // Delete the clients that have been in this world: @@ -786,30 +786,8 @@ void cWorld::TickWeather(float a_Dt) else { // Change weather: - - // Pick a new weather. Only reasonable transitions allowed: - eWeather NewWeather = m_Weather; - switch (m_Weather) - { - case eWeather_Sunny: NewWeather = eWeather_Rain; break; - case eWeather_ThunderStorm: NewWeather = eWeather_Rain; break; - case eWeather_Rain: - { - // 1/8 chance of turning into a thunderstorm - NewWeather = ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny; - break; - } - - default: - { - LOGWARNING("Unknown current weather: %d. Setting sunny.", m_Weather); - ASSERT(!"Unknown weather"); - NewWeather = eWeather_Sunny; - } - } - - SetWeather(NewWeather); - } // else (m_WeatherInterval > 0) + SetWeather(ChooseNewWeather()); + } if (m_Weather == eWeather_ThunderStorm) { diff --git a/src/World.h b/src/World.h index e2be4cd35..f789916df 100644 --- a/src/World.h +++ b/src/World.h @@ -938,7 +938,10 @@ private: /** <summary>Generates a random spawnpoint on solid land by walking chunks and finding their biomes</summary> */ void GenerateRandomSpawn(void); - + + /** Chooses a reasonable transition from the current weather to a new weather **/ + eWeather ChooseNewWeather(void); + /** Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) */ cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock); diff --git a/src/WorldStorage/CMakeLists.txt b/src/WorldStorage/CMakeLists.txt index 2c83c4662..2844f7fe5 100644 --- a/src/WorldStorage/CMakeLists.txt +++ b/src/WorldStorage/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(WorldStorage ${SOURCE}) diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 415693ae2..fd356c7de 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -28,7 +28,7 @@ #include "../Entities/Boat.h" #include "../Entities/Minecart.h" #include "../Entities/Pickup.h" -#include "../Entities/ProjectileEntity.h" +#include "../Entities/ArrowEntity.h" #include "../Entities/TNTEntity.h" #include "../Entities/ExpOrb.h" #include "../Entities/HangingEntity.h" @@ -39,7 +39,7 @@ #include "../Mobs/Creeper.h" #include "../Mobs/Enderman.h" #include "../Mobs/Horse.h" -#include "../Mobs/Magmacube.h" +#include "../Mobs/MagmaCube.h" #include "../Mobs/Sheep.h" #include "../Mobs/Slime.h" #include "../Mobs/Skeleton.h" @@ -516,7 +516,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster) } case cMonster::mtWither: { - m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetNumInvulnerableTicks()); + m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetWitherInvulnerableTicks()); break; } case cMonster::mtWolf: @@ -621,10 +621,10 @@ void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging) m_Writer.AddInt("TileZ", a_Hanging->GetTileZ()); switch (a_Hanging->GetDirection()) { - case 0: m_Writer.AddByte("Dir", (unsigned char)2); break; - case 1: m_Writer.AddByte("Dir", (unsigned char)1); break; - case 2: m_Writer.AddByte("Dir", (unsigned char)0); break; - case 3: m_Writer.AddByte("Dir", (unsigned char)3); break; + case BLOCK_FACE_YM: m_Writer.AddByte("Dir", (unsigned char)2); break; + case BLOCK_FACE_YP: m_Writer.AddByte("Dir", (unsigned char)1); break; + case BLOCK_FACE_ZM: m_Writer.AddByte("Dir", (unsigned char)0); break; + case BLOCK_FACE_ZP: m_Writer.AddByte("Dir", (unsigned char)3); break; } } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 48934d074..33f34728e 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -27,7 +27,6 @@ #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" - #include "../Mobs/Monster.h" #include "../Mobs/IncludeAllMonsters.h" @@ -36,7 +35,12 @@ #include "../Entities/FallingBlock.h" #include "../Entities/Minecart.h" #include "../Entities/Pickup.h" -#include "../Entities/ProjectileEntity.h" +#include "../Entities/ArrowEntity.h" +#include "../Entities/ThrownEggEntity.h" +#include "../Entities/ThrownEnderPearlEntity.h" +#include "../Entities/ThrownSnowballEntity.h" +#include "../Entities/FireChargeEntity.h" +#include "../Entities/GhastFireballEntity.h" #include "../Entities/TNTEntity.h" #include "../Entities/ExpOrb.h" #include "../Entities/HangingEntity.h" @@ -1757,7 +1761,7 @@ void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cCavespider> Monster(new cCavespider()); + std::auto_ptr<cCaveSpider> Monster(new cCaveSpider()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -2272,7 +2276,7 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a int CurrLine = a_NBT.FindChildByName(a_TagIdx, "Invul"); if (CurrLine > 0) { - Monster->SetNumInvulnerableTicks(a_NBT.GetInt(CurrLine)); + Monster->SetWitherInvulnerableTicks(a_NBT.GetInt(CurrLine)); } a_Entities.push_back(Monster.release()); diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp index 5435e6d5a..359bac4a8 100644 --- a/src/WorldStorage/WSSCompact.cpp +++ b/src/WorldStorage/WSSCompact.cpp @@ -468,7 +468,15 @@ cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_ for (int i = 0; i < NumChunks; i++) { sChunkHeader * Header = new sChunkHeader; - READ(*Header); + + // Here we do not use the READ macro, as it does not free the resources + // allocated with new in case of error. + if (f.Read(Header, sizeof(*Header)) != sizeof(*Header)) + { + LOGERROR("ERROR READING %s FROM FILE %s (line %d); file offset %d", "Header", m_FileName.c_str(), __LINE__, f.Tell()); + delete Header; + return; + } m_ChunkHeaders.push_back(Header); } // for i - chunk headers @@ -797,7 +805,6 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() ++index2; } InChunkOffset += index2 / 2; - index2 = 0; AString Converted(ConvertedData, ExpectedSize); |