diff options
46 files changed, 668 insertions, 283 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bb780eba..ae83662c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,9 @@ if(MSVC OR MSVC_IDE) endif() endif() +set(BUILD_TOOLS OFF CACHE BOOL "") +set(SELF_TEST OFF CACHE BOOL "") + # This has to be done before any flags have been set up. if(${BUILD_TOOLS}) message("Building tools") diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 21654428f..1e73fb699 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -2,6 +2,7 @@ Many people have contributed to MCServer, and this list attempts to broadcast at BasedDoge (Donated AlchemistVillage prefabs) bearbin (Alexander Harkness) +beeduck derouinw Diusrex Duralex @@ -23,9 +24,10 @@ p-mcgowan rs2k SafwatHalaby (Safwat Halaby) SamJBarney +Seadragon91 (Lukas Pioch) Sofapriester SphinxC0re -STR_Warrior +NiLSPACE (formerly STR_Warrior) structinf (xdot) Sxw1212 Taugeshtu @@ -34,7 +36,7 @@ tonibm19 UltraCoderRU WebFreak001 worktycho -xoft +xoft (Mattes Dolak/madmaxoft on GH) Yeeeeezus (Donated AlchemistVillage prefabs) Please add yourself to this list if you contribute to MCServer. diff --git a/MCServer/Plugins/APIDump/Hooks/OnEntityChangedWorld.lua b/MCServer/Plugins/APIDump/Hooks/OnEntityChangedWorld.lua index 00645c152..6675fdbe0 100644 --- a/MCServer/Plugins/APIDump/Hooks/OnEntityChangedWorld.lua +++ b/MCServer/Plugins/APIDump/Hooks/OnEntityChangedWorld.lua @@ -7,7 +7,7 @@ return Desc = [[ This hook is called after the server has moved the {{cEntity|entity}} to the given world. This is an information-only callback, the entity is already in the new world.<p> - See also the {{OnEntityChangeWorld|HOOK_ENTITY_CHANGE_WORLD}} hook for a similar hook called before the + See also the {{OnEntityChangingWorld|HOOK_ENTITY_CHANGING_WORLD}} hook for a similar hook called before the entity is moved to the new world. ]], Params = diff --git a/MCServer/Plugins/APIDump/Hooks/OnEntityChangeWorld.lua b/MCServer/Plugins/APIDump/Hooks/OnEntityChangingWorld.lua index 25072ca5c..521f829c7 100644 --- a/MCServer/Plugins/APIDump/Hooks/OnEntityChangeWorld.lua +++ b/MCServer/Plugins/APIDump/Hooks/OnEntityChangingWorld.lua @@ -1,9 +1,9 @@ return { - HOOK_ENTITY_CHANGE_WORLD = + HOOK_ENTITY_CHANGING_WORLD = { CalledWhen = "Before a entity is changing the world.", - DefaultFnName = "OnEntityChangeWorld", -- also used as pagename + DefaultFnName = "OnEntityChangingWorld", -- also used as pagename Desc = [[ This hook is called before the server moves the {{cEntity|entity}} to the given world. Plugins may refuse the changing of the entity to the new world.<p> @@ -20,7 +20,7 @@ return returns true, no other callback is called for this event and the change of the entity to the world is cancelled. ]], - }, -- HOOK_ENTITY_CHANGE_WORLD + }, -- HOOK_ENTITY_CHANGING_WORLD } diff --git a/MCServer/items.ini b/MCServer/items.ini index daf366654..5eb04619c 100644 --- a/MCServer/items.ini +++ b/MCServer/items.ini @@ -815,7 +815,7 @@ rawrabbit=411 cookedrabbit=412 rabbitstew=413 rabbitsoup=413 -rabbitsfood=414 +rabbitsfoot=414 rabbithide=415 armorstand=416 ironhorsearmor=417 @@ -22,7 +22,11 @@ For Windows, you just need to download a file and extract it: - [Windows 32 bit](http://builds.cuberite.org/job/MCServer%20Windows%20x86/lastSuccessfulBuild/artifact/Install/MCServer.zip) - [Windows 64 bit](http://builds.cuberite.org/job/MCServer%20Windows%20x64/lastSuccessfulBuild/artifact/Install/MCServer.zip) -For other operating systems you need to download and compile yourself. There is also an archive of binary builds on the buildserver: http://builds.cuberite.org +For other operating systems you need to download and compile yourself. This can be done either manually, or with this automatic script: + + bash -c "$(wget -O - https://raw.githubusercontent.com/mc-server/MCServer/master/compile.sh)" + +There is also an archive of binary builds on the buildserver: http://builds.cuberite.org Compiling the server yourself has other benefits: you may get better performance performance (1.5-3x as fast) and it supports more operating systems. See the [COMPILING.md](https://github.com/mc-server/MCServer/blob/master/COMPILING.md) file for more details. diff --git a/SetFlags.cmake b/SetFlags.cmake index 0d1bd99b3..b05585f7d 100644 --- a/SetFlags.cmake +++ b/SetFlags.cmake @@ -263,6 +263,10 @@ macro(set_exe_flags) # flags introduced in 3.2 add_flags_cxx("-Wno-documentation") endif() + if ("${CLANG_VERSION}" VERSION_GREATER 3.5) + # Use this flag to ignore error for a reserved macro problem in sqlite 3 + add_flags_cxx("-Wno-reserved-id-macro") + endif() endif() endif() diff --git a/compile.sh b/compile.sh new file mode 100755 index 000000000..329d79d81 --- /dev/null +++ b/compile.sh @@ -0,0 +1,199 @@ +#|| goto :windows_detected + +# Do we already have a repo? +if [[ -d .git && -f easyinstall.sh && -f MakeLuaAPI.cmd ]]; then # A good enough indicator that we're in the MCServer git repo. +cd ../ +echo "MCServer repository detected. This should make the process faster, especially if you compiled before." +fi + +# Error functions. +function error +{ + echo + echo "-----------------" + echo "Script aborted, reason:" + echo $1 + exit -1 +} + +function missingDepsExit +{ + echo + echo "Please install the dependencies, then come back." + echo + exit -2 +} + + +# Echo: Greetings. +echo +echo "Hello, this script will download and compile Cuberite/MCServer." +echo "On subsequent runs, it will update your MCServer." +echo "The compilation and download will occur in the current directory." +echo "If you're updating, you should run <Path to MCServer>/MCServer/compile.sh" +echo "Compiling from source takes time, but it usually generates better executables." +echo "If you prefer ready-to-use binaries or if you want more info, please visit:" +echo "http://cuberite.org/" +echo "http://mc-server.org/" + +MISSING_PROGRAMS="" + +# Compiler check. +GCC_EXISTS=0 +CLANG_EXISTS=0 +g++ --help > /dev/null 2> /dev/null && GCC_EXISTS=1 +clang --help > /dev/null 2> /dev/null && CLANG_EXISTS=1 +if [[ $GCC_EXISTS == 0 && $CLANG_EXISTS == 0 ]]; then +MISSING_PROGRAMS="gcc g++" +fi + +# Depdendency check. +while read program; do +$program --help > /dev/null 2> /dev/null || MISSING_PROGRAMS="$MISSING_PROGRAMS $program" +done <<"EOF" +git +make +cmake +EOF +if [[ $MISSING_PROGRAMS != "" ]]; then + echo + echo "-----------------" + echo "You have missing compilation dependencies:" + echo $MISSING_PROGRAMS + echo + + # apt-get guide. + apt-get --help > /dev/null 2> /dev/null && \ + echo "You can install the missing depndencies via:" && \ + echo -n "sudo apt-get install " && echo $MISSING_PROGRAMS && missingDepsExit + + # yum guide. + yum --help > /dev/null 2> /dev/null && \ + echo "You can install the missing depndencies via:" && \ + echo -n "sudo yum install " && echo $MISSING_PROGRAMS && missingDepsExit + + # rpm guide. + rpm --help > /dev/null 2> /dev/null && \ + echo "You can install the missing depndencies via:" && \ + echo -n "sudo rpm -i " && echo $MISSING_PROGRAMS && missingDepsExit + + # pacman guide. + pacman --help > /dev/null 2> /dev/null && \ + echo "You can install the missing depndencies via:" && \ + echo -n "sudo pacman -S " && echo $MISSING_PROGRAMS && missingDepsExit + + missingDepsExit +fi + +exit +# Echo: Branch choice. +echo +echo "You can choose between 2 branches:" +echo "* (S)Stable: (Coming soon) Choose the stable branch if you want the most reliable server." +echo " As of now, Stable is not yet available, please use testing instead." +echo +echo "* (T)Testing: The testing branch is less stable," +echo " but using it and finding and reporting bugs helps us a lot!" +echo +echo "* (D)Dev: The least stable of the three. (Master branch)" +echo " Choose the development branch if you are feeling adventurous and" +echo " want to try new, bleeding edge features." +echo + + +# Input: Branch choice. +echo -n "Choose the branch (s/t/d): " +read BRANCH +if [[ ($BRANCH == "s") || ($BRANCH == "S" ) ]]; then + #BRANCH="stable" + error "We don't have a stable branch yet, please use testing, sorry." +elif [[ ($BRANCH == "t") || ($BRANCH == "T" ) ]]; then + BRANCH="testing" +elif [[ ($BRANCH == "d") || ($BRANCH == "D" ) ]]; then + BRANCH="master" +else + error "Unrecognized user input." +fi + +# Echo: Compile mode choice. +echo +echo "Choose compile mode:" +echo "* (N)Normal: Compiles normally." +echo +echo "* (D)Debug: Compiles in debug mode. Makes your console and crashes much more verbose." +echo " But it costs performance." +echo +echo "Note that the script will connect to the internet in order to fetch code after this step." +echo "It will then compile your program." +echo + +# Input: Compile mode choice. +echo -n "Choose compile mode: (n/d): " +read BUILDTYPE +if [[ ($BUILDTYPE == "d") || ($BUILDTYPE == "D") ]]; then + BUILDTYPE="Debug" +elif [[ ($BUILDTYPE == "n") || ($BUILDTYPE == "N") ]]; then + BUILDTYPE="Release" +else + error "Unrecognized user input." +fi + + +# Echo: Downloading began. +echo +echo " --- Downloading MCServer's source code from the $BRANCH branch..." + + +# Git: Clone. +if [ ! -d MCServer ]; then + echo " --- Looks like your first run, cloning the whole code..." + git clone https://github.com/mc-server/MCServer.git +fi + + +# Git: Fetch. +pushd MCServer +echo " --- Updating the $BRANCH branch..." +git fetch origin $BRANCH || error "git fetch failed" +git checkout $BRANCH || error "git checkout failed" +git merge origin/$BRANCH || error "git merge failed" + + +# Git: Submodules. +echo " --- Updating submodules..." +git submodule init +git submodule update + + +# Cmake. +echo " --- Running cmake..." +popd +if [ ! -d build-mcserver ]; then mkdir build-mcserver; fi +pushd build-mcserver +cmake ../MCServer/ -DCMAKE_BUILD_TYPE=$BUILDTYPE || error "cmake failed" + + +# Make. +echo " --- Compiling..." +make -j`nproc` || error "Compiling failed" +echo + + +# Echo: Compilation complete. +popd +pushd MCServer/MCServer +echo +echo "-----------------" +echo "Compilation done!" +echo +echo "Cuberite awaits you at:" +echo "`pwd`/MCServer" +echo +echo "Enjoy :)" +popd +exit 0 + +:windows_detected +echo "This script is not available for Windows yet, sorry." +echo "You can still download the Windows binaries from: http://mc-server.org" + diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp index 3ee5ca498..5becbba92 100644 --- a/src/Bindings/ManualBindings_World.cpp +++ b/src/Bindings/ManualBindings_World.cpp @@ -530,7 +530,7 @@ static int tolua_cWorld_TryGetHeight(lua_State * tolua_S) // Call the implementation: int Height = 0; bool res = self->TryGetHeight(BlockX, BlockZ, Height); - L.Push(res ? 1 : 0); + L.Push(res); if (res) { L.Push(Height); diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index b4bbfd802..1330bca0d 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -56,7 +56,7 @@ public: virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) = 0; virtual bool OnEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) = 0; virtual bool OnEntityTeleport (cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition) = 0; - virtual bool OnEntityChangeWorld (cEntity & a_Entity, cWorld & a_World) = 0; + virtual bool OnEntityChangingWorld (cEntity & a_Entity, cWorld & a_World) = 0; virtual bool OnEntityChangedWorld (cEntity & a_Entity, cWorld & a_World) = 0; virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, cPluginManager::CommandResult & a_Result) = 0; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index a8be26f71..234bf579b 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -534,7 +534,7 @@ bool cPluginLua::OnEntityAddEffect(cEntity & a_Entity, int a_EffectType, int a_E -bool cPluginLua::OnEntityChangeWorld(cEntity & a_Entity, cWorld & a_World) +bool cPluginLua::OnEntityChangingWorld(cEntity & a_Entity, cWorld & a_World) { cCSLock Lock(m_CriticalSection); if (!m_LuaState.IsValid()) @@ -542,7 +542,7 @@ bool cPluginLua::OnEntityChangeWorld(cEntity & a_Entity, cWorld & a_World) return false; } bool res = false; - cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_CHANGE_WORLD]; + cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_ENTITY_CHANGING_WORLD]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { m_LuaState.Call((int)(**itr), &a_Entity, &a_World, cLuaState::Return, res); @@ -1932,7 +1932,7 @@ const char * cPluginLua::GetHookFnName(int a_HookType) case cPluginManager::HOOK_DISCONNECT: return "OnDisconnect"; case cPluginManager::HOOK_PLAYER_ANIMATION: return "OnPlayerAnimation"; case cPluginManager::HOOK_ENTITY_ADD_EFFECT: return "OnEntityAddEffect"; - case cPluginManager::HOOK_ENTITY_CHANGE_WORLD: return "OnEntityChangeWorld"; + case cPluginManager::HOOK_ENTITY_CHANGING_WORLD: return "OnEntityChangingWorld"; case cPluginManager::HOOK_ENTITY_CHANGED_WORLD: return "OnEntityChangedWorld"; case cPluginManager::HOOK_ENTITY_TELEPORT: return "OnEntityTeleport"; case cPluginManager::HOOK_EXECUTE_COMMAND: return "OnExecuteCommand"; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index 533dc0331..a763cdfdf 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -115,7 +115,7 @@ public: virtual bool OnCraftingNoRecipe (cPlayer & a_Player, cCraftingGrid & a_Grid, cCraftingRecipe & a_Recipe) override; virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) override; virtual bool OnEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier) override; - virtual bool OnEntityChangeWorld (cEntity & a_Entity, cWorld & a_World) override; + virtual bool OnEntityChangingWorld (cEntity & a_Entity, cWorld & a_World) override; virtual bool OnEntityChangedWorld (cEntity & a_Entity, cWorld & a_World) override; virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, cPluginManager::CommandResult & a_Result) override; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override; @@ -179,7 +179,7 @@ public: bool CanAddOldStyleHook(int a_HookType); // cWebPlugin overrides - virtual const AString GetWebTitle(void) const {return GetName(); } + virtual const AString GetWebTitle(void) const override {return GetName(); } virtual AString HandleWebRequest(const HTTPRequest & a_Request) override; /** Adds a new web tab to webadmin. diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 6fb6ef4fa..4dc3e20d3 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -525,14 +525,14 @@ bool cPluginManager::CallHookEntityTeleport(cEntity & a_Entity, const Vector3d & -bool cPluginManager::CallHookEntityChangeWorld(cEntity & a_Entity, cWorld & a_World) +bool cPluginManager::CallHookEntityChangingWorld(cEntity & a_Entity, cWorld & a_World) { - FIND_HOOK(HOOK_ENTITY_CHANGE_WORLD); + FIND_HOOK(HOOK_ENTITY_CHANGING_WORLD); VERIFY_HOOK; for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { - if ((*itr)->OnEntityChangeWorld(a_Entity, a_World)) + if ((*itr)->OnEntityChangingWorld(a_Entity, a_World)) { return true; } diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index e528c049f..6bcef87bf 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -86,7 +86,7 @@ public: HOOK_DISCONNECT, HOOK_PLAYER_ANIMATION, HOOK_ENTITY_ADD_EFFECT, - HOOK_ENTITY_CHANGE_WORLD, + HOOK_ENTITY_CHANGING_WORLD, HOOK_ENTITY_CHANGED_WORLD, HOOK_EXECUTE_COMMAND, HOOK_EXPLODED, @@ -203,7 +203,7 @@ public: bool CallHookDisconnect (cClientHandle & a_Client, const AString & a_Reason); bool CallHookEntityAddEffect (cEntity & a_Entity, int a_EffectType, int a_EffectDurationTicks, int a_EffectIntensity, double a_DistanceModifier); bool CallHookEntityTeleport (cEntity & a_Entity, const Vector3d & a_OldPosition, const Vector3d & a_NewPosition); - bool CallHookEntityChangeWorld (cEntity & a_Entity, cWorld & a_World); + bool CallHookEntityChangingWorld (cEntity & a_Entity, cWorld & a_World); bool CallHookEntityChangedWorld (cEntity & a_Entity, cWorld & a_World); bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split, const AString & a_EntireCommand, CommandResult & a_Result); // If a_Player == nullptr, it is a console cmd bool CallHookExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData); diff --git a/src/BlockEntities/BlockEntityWithItems.h b/src/BlockEntities/BlockEntityWithItems.h index 740dbca51..30a09bc02 100644 --- a/src/BlockEntities/BlockEntityWithItems.h +++ b/src/BlockEntities/BlockEntityWithItems.h @@ -76,7 +76,7 @@ protected: cItemGrid m_Contents; // cItemGrid::cListener overrides: - virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) + virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) override { UNUSED(a_SlotNum); ASSERT(a_Grid == &m_Contents); diff --git a/src/BlockEntities/NoteEntity.h b/src/BlockEntities/NoteEntity.h index d3f85e9d2..f350ef4c4 100644 --- a/src/BlockEntities/NoteEntity.h +++ b/src/BlockEntities/NoteEntity.h @@ -52,7 +52,7 @@ public: virtual void UsedBy(cPlayer * a_Player) override; virtual void SendTo(cClientHandle &) override {} - virtual void SetRedstonePower(bool a_Value) + virtual void SetRedstonePower(bool a_Value) override { if (a_Value) { diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp index d13c8d657..a4e375cf0 100644 --- a/src/Blocks/BlockDoor.cpp +++ b/src/Blocks/BlockDoor.cpp @@ -50,10 +50,24 @@ void cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterfac UNUSED(a_CursorY); UNUSED(a_CursorZ); - if (a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_WOODEN_DOOR) + switch (a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ)) { - ChangeDoor(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); - a_Player->GetWorld()->BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0, a_Player->GetClientHandle()); + default: + { + ASSERT(!"Unhandled door block type"); + } + case E_BLOCK_ACACIA_DOOR: + case E_BLOCK_BIRCH_DOOR: + case E_BLOCK_DARK_OAK_DOOR: + case E_BLOCK_JUNGLE_DOOR: + case E_BLOCK_SPRUCE_DOOR: + case E_BLOCK_IRON_DOOR: + case E_BLOCK_WOODEN_DOOR: + { + ChangeDoor(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); + a_Player->GetWorld()->BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0, a_Player->GetClientHandle()); + break; + } } } diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index d63df94cf..3abc572f3 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -103,6 +103,11 @@ public: case E_BLOCK_STAINED_GLASS: case E_BLOCK_FENCE: case E_BLOCK_NETHER_BRICK_FENCE: + case E_BLOCK_SPRUCE_FENCE: + case E_BLOCK_BIRCH_FENCE: + case E_BLOCK_JUNGLE_FENCE: + case E_BLOCK_DARK_OAK_FENCE: + case E_BLOCK_ACACIA_FENCE: case E_BLOCK_COBBLESTONE_WALL: { // Torches can only be placed on top of these blocks diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index 00d7a69b8..3d06a8223 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -177,7 +177,7 @@ public: } - virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) + virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { UNUSED(a_ChunkInterface); UNUSED(a_WorldInterface); diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index bc2b3e93e..dca44488b 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1403,10 +1403,10 @@ bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) return false; } - // Ask the plugins if the entity is allowed to change the world - if (cRoot::Get()->GetPluginManager()->CallHookEntityChangeWorld(*this, *a_World)) + // Ask the plugins if the entity is allowed to changing the world + if (cRoot::Get()->GetPluginManager()->CallHookEntityChangingWorld(*this, *a_World)) { - // A Plugin doesn't allow the entity to change the world + // A Plugin doesn't allow the entity to changing the world return false; } diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h index d1736e9b9..05eaf16e9 100644 --- a/src/Entities/Minecart.h +++ b/src/Entities/Minecart.h @@ -135,7 +135,7 @@ protected: virtual void Destroyed() override; // cItemGrid::cListener overrides: - virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) + virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum) override { UNUSED(a_SlotNum); ASSERT(a_Grid == &m_Contents); diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 01ad26297..e3e3fac4f 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -94,7 +94,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) : SetMaxHealth(MAX_HEALTH); m_Health = MAX_HEALTH; - + m_LastPlayerListTime = std::chrono::steady_clock::now(); m_PlayerName = a_PlayerName; @@ -106,7 +106,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) : SetPosY(World->GetSpawnY()); SetPosZ(World->GetSpawnZ()); SetBedPos(Vector3i(static_cast<int>(World->GetSpawnX()), static_cast<int>(World->GetSpawnY()), static_cast<int>(World->GetSpawnZ()))); - + LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}", a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ() ); @@ -128,7 +128,14 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) : m_IsFlying = true; } } - + + if (m_GameMode == gmSpectator) // If player is reconnecting to the server in spectator mode + { + m_CanFly = true; + m_IsFlying = true; + m_bVisible = false; + } + cRoot::Get()->GetServer()->PlayerCreated(this); } @@ -145,17 +152,17 @@ cPlayer::~cPlayer(void) } LOGD("Deleting cPlayer \"%s\" at %p, ID %d", GetName().c_str(), this, GetUniqueID()); - + // Notify the server that the player is being destroyed cRoot::Get()->GetServer()->PlayerDestroying(this); SaveToDisk(); m_ClientHandle = nullptr; - + delete m_InventoryWindow; m_InventoryWindow = nullptr; - + LOGD("Player %p deleted", this); } @@ -201,7 +208,7 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) m_ClientHandle = nullptr; return; } - + if (!m_ClientHandle->IsPlaying()) { // We're not yet in the game, ignore everything @@ -210,21 +217,21 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) } m_Stats.AddValue(statMinutesPlayed, 1); - + if (!a_Chunk.IsValid()) { // This may happen if the cPlayer is created before the chunks have the chance of being loaded / generated (#83) return; } - + super::Tick(a_Dt, a_Chunk); - + // Handle charging the bow: if (m_IsChargingBow) { m_BowCharge += 1; } - + // Handle updating experience if (m_bDirtyExperience) { @@ -236,7 +243,7 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { // Apply food exhaustion from movement: ApplyFoodExhaustionFromMovement(); - + if (cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this, m_LastPos, GetPosition())) { CanMove = false; @@ -257,10 +264,10 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) { FinishEating(); } - + HandleFood(); } - + if (m_IsFishing) { HandleFloater(); @@ -460,7 +467,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) { return; } - + m_bTouchGround = a_bTouchGround; if (!m_bTouchGround) @@ -509,7 +516,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) { // cPlayer makes sure damage isn't applied in creative, no need to check here TakeDamage(dtFalling, nullptr, Damage, Damage, 0); - + // Fall particles GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, static_cast<int>(GetPosY()) - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */); } @@ -541,7 +548,7 @@ void cPlayer::SetFoodLevel(int a_FoodLevel) m_FoodSaturationLevel = 5.0; return; } - + m_FoodLevel = FoodLevel; SendHealth(); } @@ -609,7 +616,7 @@ void cPlayer::StartEating(void) { // Set the timer: m_EatingFinishTick = m_World->GetWorldAge() + EATING_TICKS; - + // Send the packets: m_World->BroadcastEntityAnimation(*this, 3); m_World->BroadcastEntityMetadata(*this); @@ -623,7 +630,7 @@ void cPlayer::FinishEating(void) { // Reset the timer: m_EatingFinishTick = -1; - + // Send the packets: m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted); m_World->BroadcastEntityMetadata(*this); @@ -757,7 +764,7 @@ void cPlayer::SetSprintingMaxSpeed(double a_Speed) void cPlayer::SetFlyingMaxSpeed(double a_Speed) { m_FlyingMaxSpeed = a_Speed; - + // Update the flying speed, always: m_ClientHandle->SendPlayerAbilities(); } @@ -769,7 +776,7 @@ void cPlayer::SetFlyingMaxSpeed(double a_Speed) void cPlayer::SetCrouch(bool a_IsCrouched) { // Set the crouch status, broadcast to all visible players - + if (a_IsCrouched == m_IsCrouched) { // No change @@ -790,7 +797,7 @@ void cPlayer::SetSprint(bool a_IsSprinting) // No change return; } - + m_IsSprinting = a_IsSprinting; m_ClientHandle->SendPlayerMaxSpeed(); } @@ -876,7 +883,7 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) } } } - + if (super::DoTakeDamage(a_TDI)) { // Any kind of damage adds food exhaustion @@ -1005,7 +1012,7 @@ void cPlayer::Respawn(void) m_Health = GetMaxHealth(); SetInvulnerableTicks(20); - + // Reset food level: m_FoodLevel = MAX_FOOD_LEVEL; m_FoodSaturationLevel = 5.0; @@ -1017,7 +1024,7 @@ void cPlayer::Respawn(void) // ToDo: send score to client? How? m_ClientHandle->SendRespawn(GetWorld()->GetDimension(), true); - + // Extinguish the fire: StopBurning(); @@ -1151,7 +1158,7 @@ void cPlayer::CloseWindow(bool a_CanRefuse) m_CurrentWindow = m_InventoryWindow; return; } - + if (m_CurrentWindow->ClosedByPlayer(*this, a_CanRefuse) || !a_CanRefuse) { // Close accepted, go back to inventory window (the default): @@ -1189,21 +1196,17 @@ void cPlayer::SetGameMode(eGameMode a_GameMode) LOGWARNING("%s: Setting invalid gamemode: %d", GetName().c_str(), a_GameMode); return; } - + if (m_GameMode == a_GameMode) { // Gamemode already set return; } - + m_GameMode = a_GameMode; m_ClientHandle->SendGameMode(a_GameMode); - if (!(IsGameModeCreative() || IsGameModeSpectator())) - { - SetFlying(false); - SetCanFly(false); - } + SetCapabilities(); m_World->BroadcastPlayerListUpdateGameMode(*this); } @@ -1215,6 +1218,30 @@ void cPlayer::SetGameMode(eGameMode a_GameMode) void cPlayer::LoginSetGameMode( eGameMode a_GameMode) { m_GameMode = a_GameMode; + + SetCapabilities(); +} + + + + + +void cPlayer::SetCapabilities() +{ + if (!IsGameModeCreative() || IsGameModeSpectator()) + { + SetFlying(false); + SetCanFly(false); + } + + if (IsGameModeSpectator()) + { + SetVisible(false); + } + else + { + SetVisible(true); + } } @@ -1306,12 +1333,12 @@ void cPlayer::SendRotation(double a_YawDegrees, double a_PitchDegrees) Vector3d cPlayer::GetThrowStartPos(void) const { Vector3d res = GetEyePosition(); - + // Adjust the position to be just outside the player's bounding box: res.x += 0.16 * cos(GetPitch()); res.y += -0.1; res.z += 0.16 * sin(GetPitch()); - + return res; } @@ -1323,9 +1350,9 @@ Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const { Vector3d res = GetLookVector(); res.Normalize(); - + // TODO: Add a slight random change (+-0.0075 in each direction) - + return res * a_SpeedCoeff; } @@ -1370,13 +1397,13 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos) } return; } - + // TODO: should do some checks to see if player is not moving through terrain // TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too Vector3d DeltaPos = a_NewPos - GetPosition(); UpdateMovementStats(DeltaPos); - + SetPosition( a_NewPos); SetStance(a_NewPos.y + 1.62); } @@ -1411,7 +1438,7 @@ bool cPlayer::HasPermission(const AString & a_Permission) // Empty permission request is always granted return true; } - + AStringVector Split = StringSplit(a_Permission, "."); // Iterate over all restrictions; if any matches, then return failure: @@ -1583,7 +1610,7 @@ void cPlayer::TossItems(const cItems & a_Items) { return; } - + m_Stats.AddValue(statItemsDropped, (StatValue)a_Items.Size()); double vX = 0, vY = 0, vZ = 0; @@ -1605,10 +1632,11 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) // Don't move to same world return false; } - - if (cRoot::Get()->GetPluginManager()->CallHookEntityChangeWorld(*this, *a_World)) + + // Ask the plugins if the player is allowed to changing the world + if (cRoot::Get()->GetPluginManager()->CallHookEntityChangingWorld(*this, *a_World)) { - // A Plugin doesn't allow the player to change the world + // A Plugin doesn't allow the player to changing the world return false; } @@ -1641,7 +1669,7 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) // Broadcast the player into the new world. a_World->BroadcastSpawnEntity(*this); - + // Player changed the world, call the hook cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, *OldWorld); @@ -1661,7 +1689,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World) { return true; } - + // Load from the offline UUID file, if allowed: AString OfflineUUID = cClientHandle::GenerateOfflineUUID(GetName()); const char * OfflineUsage = " (unused)"; @@ -1673,7 +1701,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World) return true; } } - + // Load from the old-style name-based file, if allowed: if (cRoot::Get()->GetServer()->ShouldLoadNamedPlayerData()) { @@ -1688,7 +1716,7 @@ bool cPlayer::LoadFromDisk(cWorldPtr & a_World) return true; } } - + // None of the files loaded successfully LOG("Player data file not found for %s (%s, offline %s%s), will be reset to defaults.", GetName().c_str(), m_UUID.c_str(), OfflineUUID.c_str(), OfflineUsage @@ -1765,7 +1793,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World) { m_CanFly = true; } - + m_Inventory.LoadFromJson(root["inventory"]); cEnderChestEntity::LoadFromJson(root["enderchestinventory"], m_EnderChestContents); @@ -1784,11 +1812,11 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World) // We use the default world name (like bukkit) because stats are shared between dimensions / worlds. cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats); StatSerializer.Load(); - + LOGD("Player %s was read from file \"%s\", spawning at {%.2f, %.2f, %.2f} in world \"%s\"", GetName().c_str(), a_FileName.c_str(), GetPosX(), GetPosY(), GetPosZ(), a_World->GetName().c_str() ); - + return true; } @@ -2144,7 +2172,7 @@ void cPlayer::ApplyFoodExhaustionFromMovement() { return; } - + // Calculate the distance travelled, update the last pos: Vector3d Movement(GetPosition() - m_LastPos); Movement.y = 0; // Only take XZ movement into account @@ -2347,7 +2375,7 @@ AString cPlayer::GetUUIDFileName(const AString & a_UUID) { AString UUID = cMojangAPI::MakeUUIDDashed(a_UUID); ASSERT(UUID.length() == 36); - + AString res("players/"); res.append(UUID, 0, 2); res.push_back('/'); @@ -2355,7 +2383,3 @@ AString cPlayer::GetUUIDFileName(const AString & a_UUID) res.append(".json"); return res; } - - - - diff --git a/src/Entities/Player.h b/src/Entities/Player.h index a0cd9b1d6..a84fdd0c7 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -26,42 +26,42 @@ class cPlayer : public cPawn { typedef cPawn super; - + public: static const int MAX_HEALTH; - + static const int MAX_FOOD_LEVEL; - + /** Number of ticks it takes to eat an item */ static const int EATING_TICKS; - + // tolua_end - + CLASS_PROTODEF(cPlayer) - + cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName); - + virtual ~cPlayer(); virtual void SpawnOn(cClientHandle & a_Client) override; - + virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; virtual void HandlePhysics(std::chrono::milliseconds a_Dt, cChunk &) override { UNUSED(a_Dt); } /** Returns the curently equipped weapon; empty item if none */ virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); } - + /** Returns the currently equipped helmet; empty item if none */ virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); } - + /** Returns the currently equipped chestplate; empty item if none */ virtual cItem GetEquippedChestplate(void) const override { return m_Inventory.GetEquippedChestplate(); } /** Returns the currently equipped leggings; empty item if none */ virtual cItem GetEquippedLeggings(void) const override { return m_Inventory.GetEquippedLeggings(); } - + /** Returns the currently equipped boots; empty item if none */ virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); } @@ -104,16 +104,16 @@ public: static int CalcLevelFromXp(int a_CurrentXp); // tolua_end - + /** Starts charging the equipped bow */ void StartChargingBow(void); - + /** Finishes charging the current bow. Returns the number of ticks for which the bow has been charged */ int FinishChargingBow(void); - + /** Cancels the current bow charging */ void CancelChargingBow(void); - + /** Returns true if the player is currently charging the bow */ bool IsChargingBow(void) const { return m_IsChargingBow; } @@ -128,7 +128,7 @@ public: /** Gets the contents of the player's associated enderchest */ cItemGrid & GetEnderChestContents(void) { return m_EnderChestContents; } - + inline const cItem & GetEquippedItem(void) const { return GetInventory().GetEquippedItem(); } // tolua_export /** Returns whether the player is climbing (ladders, vines etc.) */ @@ -137,43 +137,49 @@ public: virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override; // tolua_begin - + /** Sends the "look" packet to the player, forcing them to set their rotation to the specified values. a_YawDegrees is clipped to range [-180, +180), a_PitchDegrees is clipped to range [-180, +180) but the client only uses [-90, +90] */ void SendRotation(double a_YawDegrees, double a_PitchDegrees); - + /** Returns the position where projectiles thrown by this player should start, player eye position + adjustment */ Vector3d GetThrowStartPos(void) const; - + /** Returns the initial speed vector of a throw, with a 3D length of a_SpeedCoeff. */ Vector3d GetThrowSpeed(double a_SpeedCoeff) const; - + /** Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable */ eGameMode GetGameMode(void) const { return m_GameMode; } - + /** Returns the current effective gamemode (inherited gamemode is resolved before returning) */ eGameMode GetEffectiveGameMode(void) const { return (m_GameMode == gmNotSet) ? m_World->GetGameMode() : m_GameMode; } - + /** Sets the gamemode for the player. The gamemode may be gmNotSet, in that case the player inherits the world's gamemode. Updates the gamemode on the client (sends the packet) */ void SetGameMode(eGameMode a_GameMode); + // Sets the current gamemode, doesn't check validity, doesn't send update packets to client + void LoginSetGameMode(eGameMode a_GameMode); + + // Updates player's capabilities - flying, visibility, etc. from their gamemode. + void SetCapabilities(); + /** Returns true if the player is in Creative mode, either explicitly, or by inheriting from current world */ bool IsGameModeCreative(void) const; - + /** Returns true if the player is in Survival mode, either explicitly, or by inheriting from current world */ bool IsGameModeSurvival(void) const; - + /** Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world */ bool IsGameModeAdventure(void) const; - + /** Returns true if the player is in Spectator mode, either explicitly, or by inheriting from current world */ bool IsGameModeSpectator(void) const; - + AString GetIP(void) const { return m_IP; } // tolua_export /** Returns the associated team, nullptr if none */ @@ -195,11 +201,8 @@ public: If the achievement has been already awarded to the player, this method will just increment the stat counter. Returns the _new_ stat value. (0 = Could not award achievement) */ unsigned int AwardAchievement(const eStatistic a_Ach); - + void SetIP(const AString & a_IP); - - // Sets the current gamemode, doesn't check validity, doesn't send update packets to client - void LoginSetGameMode(eGameMode a_GameMode); /** Forces the player to move in the given direction. @deprecated Use SetSpeed instead. */ @@ -210,15 +213,15 @@ public: cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export const cWindow * GetWindow(void) const { return m_CurrentWindow; } - + /** Opens the specified window; closes the current one first using CloseWindow() */ void OpenWindow(cWindow * a_Window); // Exported in ManualBindings.cpp - + // tolua_begin - + /** Closes the current window, resets current window to m_InventoryWindow. A plugin may refuse the closing if a_CanRefuse is true */ void CloseWindow(bool a_CanRefuse = true); - + /** Closes the current window if it matches the specified ID, resets current window to m_InventoryWindow */ void CloseWindowIfID(char a_WindowID, bool a_CanRefuse = true); @@ -243,7 +246,7 @@ public: const AString & GetName(void) const { return m_PlayerName; } void SetName(const AString & a_Name) { m_PlayerName = a_Name; } - + // tolua_end bool HasPermission(const AString & a_Permission); // tolua_export @@ -260,7 +263,7 @@ public: const AStringVector & GetRestrictions(void) const { return m_Restrictions; } // Exported in ManualBindings.cpp // tolua_begin - + /** Returns the full color code to use for this player, based on their rank. The returned value either is empty, or includes the cChatColor::Delimiter. */ AString GetColor(void) const; @@ -279,15 +282,15 @@ public: /** Heals the player by the specified amount of HPs (positive only); sends health update */ virtual void Heal(int a_Health) override; - + int GetFoodLevel (void) const { return m_FoodLevel; } double GetFoodSaturationLevel (void) const { return m_FoodSaturationLevel; } int GetFoodTickTimer (void) const { return m_FoodTickTimer; } double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; } - + /** Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore */ bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); } - + void SetFoodLevel (int a_FoodLevel); void SetFoodSaturationLevel (double a_FoodSaturationLevel); void SetFoodTickTimer (int a_FoodTickTimer); @@ -298,10 +301,10 @@ public: /** Adds the specified exhaustion to m_FoodExhaustion. Expects only positive values. */ void AddFoodExhaustion(double a_Exhaustion); - + /** Returns true if the player is currently in the process of eating the currently equipped item */ bool IsEating(void) const { return (m_EatingFinishTick >= 0); } - + /** Returns true if the player is currently flying. */ bool IsFlying(void) const { return m_IsFlying; } @@ -329,16 +332,16 @@ public: GetWorld()->BroadcastEntityAnimation(*this, 2); } } - + /** Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet */ void StartEating(void); - + /** Finishes eating the currently equipped item. Consumes the item, updates health and broadcasts the packets */ void FinishEating(void); - + /** Aborts the current eating operation */ void AbortEating(void); - + virtual void KilledBy(TakeDamageInfo & a_TDI) override; virtual void Killed(cEntity * a_Victim) override; @@ -356,69 +359,69 @@ public: bool SaveToDisk(void); typedef cWorld * cWorldPtr; - + /** Loads the player data from the disk file Sets a_World to the world where the player will spawn, based on the stored world name or the default world by calling LoadFromFile() Returns true on success, false on failure */ bool LoadFromDisk(cWorldPtr & a_World); - + /** Loads the player data from the specified file Sets a_World to the world where the player will spawn, based on the stored world name or the default world Returns true on success, false on failure */ bool LoadFromFile(const AString & a_FileName, cWorldPtr & a_World); - + const AString & GetLoadedWorldName() { return m_LoadedWorldName; } void UseEquippedItem(int a_Amount = 1); - + void SendHealth(void); void SendExperience(void); - + /** In UI windows, get the item that the player is dragging */ cItem & GetDraggingItem(void) {return m_DraggingItem; } - + // In UI windows, when inventory-painting: /** Clears the list of slots that are being inventory-painted. To be used by cWindow only */ void ClearInventoryPaintSlots(void); - + /** Adds a slot to the list for inventory painting. To be used by cWindow only */ void AddInventoryPaintSlot(int a_SlotNum); - + /** Returns the list of slots currently stored for inventory painting. To be used by cWindow only */ const cSlotNums & GetInventoryPaintSlots(void) const; - + // tolua_begin - + /** Returns the current relative maximum speed (takes current sprinting / flying state into account) */ double GetMaxSpeed(void) const; - + /** Gets the normal relative maximum speed */ double GetNormalMaxSpeed(void) const { return m_NormalMaxSpeed; } - + /** Gets the sprinting relative maximum speed */ double GetSprintingMaxSpeed(void) const { return m_SprintingMaxSpeed; } - + /** Gets the flying relative maximum speed */ double GetFlyingMaxSpeed(void) const { return m_FlyingMaxSpeed; } - + /** Sets the normal relative maximum speed. Sends the update to player, if needed. */ void SetNormalMaxSpeed(double a_Speed); - + /** Sets the sprinting relative maximum speed. Sends the update to player, if needed. */ void SetSprintingMaxSpeed(double a_Speed); - + /** Sets the flying relative maximum speed. Sends the update to player, if needed. */ void SetFlyingMaxSpeed(double a_Speed); - + /** Sets the crouch status, broadcasts to all visible players */ void SetCrouch(bool a_IsCrouched); - + /** Starts or stops sprinting, sends the max speed update to the client, if needed */ void SetSprint(bool a_IsSprinting); - + /** Flags the player as flying */ void SetFlying(bool a_IsFlying); @@ -442,17 +445,17 @@ public: /** Sets the player's bed (home) position */ void SetBedPos(const Vector3i & a_Pos) { m_LastBedPos = a_Pos; } - + // tolua_end /** Update movement-related statistics. */ void UpdateMovementStats(const Vector3d & a_DeltaPos); - + // tolua_begin /** Returns wheter the player can fly or not. */ virtual bool CanFly(void) const { return m_CanFly; } - + /** Returns the UUID (short format) that has been read from the client, or empty string if not available. */ const AString & GetUUID(void) const { return m_UUID; } @@ -483,16 +486,16 @@ public: bool PlaceBlocks(const sSetBlockVector & a_Blocks); // cEntity overrides: - virtual bool IsCrouched (void) const { return m_IsCrouched; } - virtual bool IsSprinting(void) const { return m_IsSprinting; } - virtual bool IsRclking (void) const { return IsEating() || IsChargingBow(); } + virtual bool IsCrouched (void) const override { return m_IsCrouched; } + virtual bool IsSprinting(void) const override { return m_IsSprinting; } + virtual bool IsRclking (void) const override { return IsEating() || IsChargingBow(); } - virtual void Detach(void); + virtual void Detach(void) override; /** Called by cClientHandle when the client is being destroyed. The player removes its m_ClientHandle ownership so that the ClientHandle gets deleted. */ void RemoveClientHandle(void); - + protected: typedef std::vector<std::vector<AString> > AStringVectorVector; @@ -535,16 +538,16 @@ protected: // Food-related variables: /** Represents the food bar, one point equals half a "drumstick" */ int m_FoodLevel; - + /** "Overcharge" for the m_FoodLevel; is depleted before m_FoodLevel */ double m_FoodSaturationLevel; - + /** Count-up to the healing or damaging action, based on m_FoodLevel */ int m_FoodTickTimer; - + /** A "buffer" which adds up hunger before it is substracted from m_FoodSaturationLevel or m_FoodLevel. Each action adds a little */ double m_FoodExhaustionLevel; - + float m_LastJumpHeight; float m_LastGroundHeight; bool m_bTouchGround; @@ -564,31 +567,31 @@ protected: eGameMode m_GameMode; AString m_IP; - + /** The item being dragged by the cursor while in a UI window */ cItem m_DraggingItem; std::chrono::steady_clock::time_point m_LastPlayerListTime; cClientHandlePtr m_ClientHandle; - + cSlotNums m_InventoryPaintSlots; - + /** Max speed, relative to the game default. 1 means regular speed, 2 means twice as fast, 0.5 means half-speed. Default value is 1. */ double m_NormalMaxSpeed; - + /** Max speed, relative to the game default max speed, when sprinting. 1 means regular speed, 2 means twice as fast, 0.5 means half-speed. Default value is 1.3. */ double m_SprintingMaxSpeed; - + /** Max speed, relative to the game default flying max speed, when flying. 1 means regular speed, 2 means twice as fast, 0.5 means half-speed. Default value is 1. */ double m_FlyingMaxSpeed; - + bool m_IsCrouched; bool m_IsSprinting; bool m_IsFlying; @@ -629,7 +632,7 @@ protected: Will not apply food penalties if found to be true; will set to false after processing */ bool m_bIsTeleporting; - + /** The short UUID (no dashes) of the player, as read from the ClientHandle. If no ClientHandle is given, the UUID is initialized to empty. */ AString m_UUID; @@ -642,14 +645,14 @@ protected: void ResolvePermissions(void); void ResolveGroups(void); - virtual void Destroyed(void); + virtual void Destroyed(void) override; /** Filters out damage for creative mode / friendly fire */ virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; /** Stops players from burning in creative mode */ virtual void TickBurning(cChunk & a_Chunk) override; - + /** Called in each tick to handle food-related processing */ void HandleFood(void); @@ -666,7 +669,3 @@ protected: This can be used both for online and offline UUIDs. */ AString GetUUIDFileName(const AString & a_UUID); } ; // tolua_export - - - - diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index 69ae59c18..c988224e6 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -1259,7 +1259,7 @@ bool cFinishGenPassiveMobs::TrySpawnAnimals(cChunkDesc & a_ChunkDesc, int a_RelX } if ( (BlockUnderFeet != E_BLOCK_GRASS) && - ((AnimalToSpawn == mtSheep) || (AnimalToSpawn == mtChicken) || (AnimalToSpawn == mtPig)) + ((AnimalToSpawn == mtWolf) || (AnimalToSpawn == mtRabbit) || (AnimalToSpawn == mtCow) || (AnimalToSpawn == mtSheep) || (AnimalToSpawn == mtChicken) || (AnimalToSpawn == mtPig)) ) { return false; diff --git a/src/Generating/TwoHeights.cpp b/src/Generating/TwoHeights.cpp index e75c301de..06c474458 100644 --- a/src/Generating/TwoHeights.cpp +++ b/src/Generating/TwoHeights.cpp @@ -69,7 +69,7 @@ public: } - virtual void InitializeShapeGen(cIniFile & a_IniFile) + virtual void InitializeShapeGen(cIniFile & a_IniFile) override { m_FrequencyX = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "TwoHeightsFrequencyX", 40)); m_FrequencyY = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "TwoHeightsFrequencyY", 40)); diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp index a3f8caa46..27146e757 100644 --- a/src/Generating/VillageGen.cpp +++ b/src/Generating/VillageGen.cpp @@ -259,13 +259,13 @@ protected: // cPiecePool overrides: - virtual cPieces GetPiecesWithConnector(int a_ConnectorType) + virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override { return m_Prefabs.GetPiecesWithConnector(a_ConnectorType); } - virtual cPieces GetStartingPieces(void) + virtual cPieces GetStartingPieces(void) override { return m_Prefabs.GetStartingPieces(); } diff --git a/src/IniFile.h b/src/IniFile.h index 861be3800..2a4113fb4 100644 --- a/src/IniFile.h +++ b/src/IniFile.h @@ -89,7 +89,7 @@ public: void Clear(void); /** Returns true iff the specified value exists. */ - bool HasValue(const AString & a_KeyName, const AString & a_ValueName) const; + bool HasValue(const AString & a_KeyName, const AString & a_ValueName) const override; /// Returns index of specified key, or noID if not found int FindKey(const AString & keyname) const; @@ -101,7 +101,7 @@ public: int GetNumKeys(void) const { return (int)keys.size(); } /// Add a key name - int AddKeyName(const AString & keyname); + int AddKeyName(const AString & keyname) override; // Returns key names by index. AString GetKeyName(const int keyID) const; @@ -117,7 +117,7 @@ public: // Gets value of [keyname] valuename =. // Overloaded to return string, int, and double. // Returns defValue if key / value not found. - AString GetValue (const AString & keyname, const AString & valuename, const AString & defValue = "") const; + AString GetValue (const AString & keyname, const AString & valuename, const AString & defValue = "") const override; AString GetValue (const int keyID, const int valueID, const AString & defValue = "") const; double GetValueF(const AString & keyname, const AString & valuename, const double defValue = 0) const; int GetValueI(const AString & keyname, const AString & valuename, const int defValue = 0) const; @@ -127,18 +127,18 @@ public: } // Gets the value; if not found, write the default to the INI file - AString GetValueSet (const AString & keyname, const AString & valuename, const AString & defValue = ""); + AString GetValueSet (const AString & keyname, const AString & valuename, const AString & defValue = "") override; double GetValueSetF(const AString & keyname, const AString & valuename, const double defValue = 0.0); - int GetValueSetI(const AString & keyname, const AString & valuename, const int defValue = 0); - Int64 GetValueSetI(const AString & keyname, const AString & valuename, const Int64 defValue = 0); - bool GetValueSetB(const AString & keyname, const AString & valuename, const bool defValue = false) + int GetValueSetI(const AString & keyname, const AString & valuename, const int defValue = 0) override; + Int64 GetValueSetI(const AString & keyname, const AString & valuename, const Int64 defValue = 0) override; + bool GetValueSetB(const AString & keyname, const AString & valuename, const bool defValue = false) override { return (GetValueSetI(keyname, valuename, defValue ? 1 : 0) != 0); } // Adds a new value to the specified key. // If a value of the same name already exists, creates another one (non-standard INI file) - void AddValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value); + void AddValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value) override; void AddValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value); void AddValueB(const AString & a_KeyName, const AString & a_ValueName, const bool a_Value) { @@ -151,8 +151,8 @@ public: // Returns true if value set, false otherwise. // Overloaded to accept string, int, and double. bool SetValue (const int keyID, const int valueID, const AString & value); - bool SetValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists = true); - bool SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists = true); + bool SetValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists = true) override; + bool SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists = true) override; bool SetValueI(const AString & a_Keyname, const AString & a_ValueName, const Int64 a_Value, const bool a_CreateIfNotExists = true); bool SetValueB(const AString & a_KeyName, const AString & a_ValueName, const bool a_Value, const bool a_CreateIfNotExists = true) { @@ -163,7 +163,7 @@ public: // Deletes specified value. // Returns true if value existed and deleted, false otherwise. bool DeleteValueByID(const int keyID, const int valueID); - bool DeleteValue(const AString & keyname, const AString & valuename); + bool DeleteValue(const AString & keyname, const AString & valuename) override; // Deletes specified key and all values contained within. // Returns true if key existed and deleted, false otherwise. @@ -204,15 +204,15 @@ public: bool AddKeyComment(const int keyID, const AString & comment); /// Add a key comment - bool AddKeyComment(const AString & keyname, const AString & comment); + bool AddKeyComment(const AString & keyname, const AString & comment) override; /// Return a key comment AString GetKeyComment(const int keyID, const int commentID) const; - AString GetKeyComment(const AString & keyname, const int commentID) const; + AString GetKeyComment(const AString & keyname, const int commentID) const override; // Delete a key comment. bool DeleteKeyComment(const int keyID, const int commentID); - bool DeleteKeyComment(const AString & keyname, const int commentID); + bool DeleteKeyComment(const AString & keyname, const int commentID) override; // Delete all comments for a key. bool DeleteKeyComments(const int keyID); diff --git a/src/Items/ItemSign.h b/src/Items/ItemSign.h index dabbdbba1..3da93e2f1 100644 --- a/src/Items/ItemSign.h +++ b/src/Items/ItemSign.h @@ -25,7 +25,7 @@ public: cWorld & a_World, cPlayer & a_Player, const cItem & a_EquippedItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ - ) + ) override { // If the regular placement doesn't work, do no further processing: if (!super::OnPlayerPlace(a_World, a_Player, a_EquippedItem, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp index 055ff47d2..648599999 100644 --- a/src/Mobs/AggressiveMonster.cpp +++ b/src/Mobs/AggressiveMonster.cpp @@ -76,9 +76,11 @@ void cAggressiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) } cTracer LineOfSight(GetWorld()); - Vector3d AttackDirection(m_Target->GetPosition() - GetPosition()); + Vector3d MyHeadPosition = GetPosition() + Vector3d(0, GetHeight(), 0); + Vector3d AttackDirection(m_Target->GetPosition() + Vector3d(0, m_Target->GetHeight(), 0) - MyHeadPosition); - if (ReachedFinalDestination() && !LineOfSight.Trace(GetPosition(), AttackDirection, (int)AttackDirection.Length())) + + if (ReachedFinalDestination() && !LineOfSight.Trace(MyHeadPosition, AttackDirection, static_cast<int>(AttackDirection.Length()))) { // Attack if reached destination, target isn't null, and have a clear line of sight to target (so won't attack through walls) Attack(a_Dt); diff --git a/src/Mobs/Horse.h b/src/Mobs/Horse.h index be283705e..27168ebae 100644 --- a/src/Mobs/Horse.h +++ b/src/Mobs/Horse.h @@ -26,7 +26,7 @@ public: bool IsEating (void) const {return m_bIsEating; } bool IsRearing (void) const {return m_bIsRearing; } bool IsMthOpen (void) const {return m_bIsMouthOpen; } - bool IsTame (void) const {return m_bIsTame; } + bool IsTame (void) const override {return m_bIsTame; } int GetHorseType (void) const {return m_Type; } int GetHorseColor (void) const {return m_Color; } int GetHorseStyle (void) const {return m_Style; } diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 2b00f6959..1da4124ed 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -169,7 +169,7 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) m_NoPathToTarget = false; m_NoMoreWayPoints = false; m_PathFinderDestination = m_FinalDestination; - m_Path = new cPath(a_Chunk, GetPosition().Floor(), m_PathFinderDestination.Floor(), 20); + m_Path = new cPath(a_Chunk, GetPosition(), m_PathFinderDestination, 20, GetWidth(), GetHeight()); } switch (m_Path->Step(a_Chunk)) @@ -177,13 +177,14 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) case ePathFinderStatus::NEARBY_FOUND: { m_NoPathToTarget = true; - m_Path->AcceptNearbyPath(); + m_PathFinderDestination = m_Path->AcceptNearbyPath(); break; } case ePathFinderStatus::PATH_NOT_FOUND: { - StopMovingToPosition(); // Give up pathfinding to that destination. + StopMovingToPosition(); // Try to calculate a path again. + // Note that the next time may succeed, e.g. if a player breaks a barrier. break; } case ePathFinderStatus::CALCULATING: @@ -202,7 +203,7 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) { if ((m_Path->IsFirstPoint() || ReachedNextWaypoint())) { - m_NextWayPointPosition = Vector3d(0.5, 0, 0.5) + m_Path->GetNextPoint(); + m_NextWayPointPosition = m_Path->GetNextPoint(); m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition. } } diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index bf5e4ba5e..6f3d43305 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -6,6 +6,8 @@ #include "Path.h" #include "../Chunk.h" +#define JUMP_G_COST 20 + #define DISTANCE_MANHATTAN 0 // 1: More speed, a bit less accuracy 0: Max accuracy, less speed. #define HEURISTICS_ONLY 0 // 1: Much more speed, much less accurate. #define CALCULATIONS_PER_STEP 10 // Higher means more CPU load but faster path calculations. @@ -30,12 +32,11 @@ bool compareHeuristics::operator()(cPathCell * & a_Cell1, cPathCell * & a_Cell2) /* cPath implementation */ cPath::cPath( cChunk & a_Chunk, - const Vector3i & a_StartingPoint, const Vector3i & a_EndingPoint, int a_MaxSteps, + const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps, double a_BoundingBoxWidth, double a_BoundingBoxHeight, int a_MaxUp, int a_MaxDown ) : - m_Destination(a_EndingPoint.Floor()), - m_Source(a_StartingPoint.Floor()), + m_CurrentPoint(0), // GetNextPoint increments this to 1, but that's fine, since the first cell is always a_StartingPoint m_Chunk(&a_Chunk), m_BadChunkFound(false) @@ -43,6 +44,21 @@ cPath::cPath( // TODO: if src not walkable OR dest not walkable, then abort. // Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable + a_BoundingBoxWidth = 1; // Until we improve physics, if ever. + + m_BoundingBoxWidth = ceil(a_BoundingBoxWidth); + m_BoundingBoxHeight = ceil(a_BoundingBoxHeight); + m_HalfWidth = a_BoundingBoxWidth / 2; + + int HalfWidthInt = a_BoundingBoxWidth / 2; + m_Source.x = floor(a_StartingPoint.x - HalfWidthInt); + m_Source.y = floor(a_StartingPoint.y); + m_Source.z = floor(a_StartingPoint.z - HalfWidthInt); + + m_Destination.x = floor(a_EndingPoint.x - HalfWidthInt); + m_Destination.y = floor(a_EndingPoint.y); + m_Destination.z = floor(a_EndingPoint.z - HalfWidthInt); + if (GetCell(m_Source)->m_IsSolid || GetCell(m_Destination)->m_IsSolid) { m_Status = ePathFinderStatus::PATH_NOT_FOUND; @@ -147,7 +163,7 @@ bool cPath::IsSolid(const Vector3i & a_Location) } if (BlockType == E_BLOCK_STATIONARY_WATER) { - GetCell(a_Location + Vector3i(0, -1, 0))->m_IsSolid = true; // Mobs will always think that the fence is 2 blocks high and therefore won't jump over. + GetCell(a_Location + Vector3i(0, -1, 0))->m_IsSolid = true; } return cBlockInfo::IsSolid(BlockType); @@ -178,28 +194,57 @@ bool cPath::Step_Internal() // Calculation not finished yet. // Check if we have a new NearestPoint. - if (CurrentCell->m_H < m_NearestPointToTarget->m_H) + // TODO I don't like this that much, there should be a smarter way. + if ((m_Destination - CurrentCell->m_Location).Length() < 5) + { + if (m_Rand.NextInt(4) == 0) + { + m_NearestPointToTarget = CurrentCell; + } + } + else if (CurrentCell->m_H < m_NearestPointToTarget->m_H) { m_NearestPointToTarget = CurrentCell; } - // process a currentCell by inspecting all neighbors. - // Check North, South, East, West on all 3 different heights. - int i; - for (i = -1; i <= 1; ++i) + + // Check North, South, East, West on our height. + ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 0, 0), CurrentCell, 10); + ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 0, 0), CurrentCell, 10); + ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 0, 1), CurrentCell, 10); + ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 0, -1), CurrentCell, 10); + + // Check diagonals on XY plane. + for (int x = -1; x <= 1; x += 2) { - ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, i, 0), CurrentCell, 10); - ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, i, 0), CurrentCell, 10); - ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, i, 1), CurrentCell, 10); - ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, i, -1), CurrentCell, 10); + if (GetCell(CurrentCell->m_Location + Vector3i(x, 0, 0))->m_IsSolid) // If there's a solid our east / west. + { + ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, 1, 0), CurrentCell, JUMP_G_COST); // Check east / west-up. + } + else + { + ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, -1, 0), CurrentCell, 14); // Else check east / west-down. + } + } + + // Check diagonals on the YZ plane. + for (int z = -1; z <= 1; z += 2) + { + if (GetCell(CurrentCell->m_Location + Vector3i(0, 0, z))->m_IsSolid) // If there's a solid our east / west. + { + ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, z), CurrentCell, JUMP_G_COST); // Check east / west-up. + } + else + { + ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, -1, z), CurrentCell, 14); // Else check east / west-down. + } } - // Check diagonals on mob's height only. - int x, z; - for (x = -1; x <= 1; x += 2) + // Check diagonals on the XZ plane. (Normal diagonals, this plane is special because of gravity, etc) + for (int x = -1; x <= 1; x += 2) { - for (z = -1; z <= 1; z += 2) + for (int z = -1; z <= 1; z += 2) { // This condition prevents diagonal corner cutting. if (!GetCell(CurrentCell->m_Location + Vector3i(x, 0, 0))->m_IsSolid && !GetCell(CurrentCell->m_Location + Vector3i(0, 0, z))->m_IsSolid) @@ -312,7 +357,53 @@ si::setBlock((Ret)->m_Location.x, (Ret)->m_Location.y, (Ret)->m_Location.z, debu void cPath::ProcessIfWalkable(const Vector3i & a_Location, cPathCell * a_Parent, int a_Cost) { cPathCell * cell = GetCell(a_Location); - if (!cell->m_IsSolid && GetCell(a_Location + Vector3i(0, -1, 0))->m_IsSolid && !GetCell(a_Location + Vector3i(0, 1, 0))->m_IsSolid) + int x, y, z; + + // Make sure we fit in the position. + for (y = 0; y < m_BoundingBoxHeight; ++y) + { + for (x = 0; x < m_BoundingBoxWidth; ++x) + { + for (z = 0; z < m_BoundingBoxWidth; ++z) + { + if (GetCell(a_Location + Vector3i(x, y, z))->m_IsSolid) + { + return; + } + } + } + } + + /*y =-1; + for (x = 0; x < m_BoundingBoxWidth; ++x) + { + for (z = 0; z < m_BoundingBoxWidth; ++z) + { + if (!GetCell(a_Location + Vector3i(x, y, z))->m_IsSolid) + { + return; + } + } + } + ProcessCell(cell, a_Parent, a_Cost);*/ + + // Make sure there's at least 1 piece of solid below us. + + bool GroundFlag = false; + y =-1; + for (x = 0; x < m_BoundingBoxWidth; ++x) + { + for (z = 0; z < m_BoundingBoxWidth; ++z) + { + if (GetCell(a_Location + Vector3i(x, y, z))->m_IsSolid) + { + GroundFlag = true; + break; + } + } + } + + if (GroundFlag) { ProcessCell(cell, a_Parent, a_Cost); } diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h index acc56ef2d..3b9c0400e 100644 --- a/src/Mobs/Path.h +++ b/src/Mobs/Path.h @@ -1,16 +1,13 @@ #pragma once -/* Wanna use the pathfinder? Put this in your header file: - -// Fwd: cPath +/* +// Needed Fwds: cPath enum class ePathFinderStatus; class cPath; - -Put this in your .cpp: -#include "...Path.h" */ +#include "../FastRandom.h" #ifdef COMPILING_PATHFIND_DEBUGGER /* Note: the COMPILING_PATHFIND_DEBUGGER flag is used by Native / WiseOldMan95 to debug this class outside of MCServer. This preprocessor flag is never set when compiling MCServer. */ @@ -71,8 +68,8 @@ public: @param a_MaxSteps The maximum steps before giving up. */ cPath( cChunk & a_Chunk, - const Vector3i & a_StartingPoint, const Vector3i & a_EndingPoint, int a_MaxSteps, - double a_BoundingBoxWidth = 1, double a_BoundingBoxHeight = 2, + const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps, + double a_BoundingBoxWidth, double a_BoundingBoxHeight, int a_MaxUp = 1, int a_MaxDown = 1 ); @@ -92,10 +89,11 @@ public: /* Point retrieval functions, inlined for performance. */ /** Returns the next point in the path. */ - inline Vector3i GetNextPoint() + inline Vector3d GetNextPoint() { ASSERT(m_Status == ePathFinderStatus::PATH_FOUND); - return m_PathPoints[m_PathPoints.size() - 1 - (++m_CurrentPoint)]; + Vector3i Point = m_PathPoints[m_PathPoints.size() - 1 - (++m_CurrentPoint)]; + return Vector3d(Point.x + m_HalfWidth, Point.y, Point.z + m_HalfWidth); } /** Checks whether this is the last point or not. Never call getnextPoint when this is true. */ inline bool IsLastPoint() @@ -109,11 +107,12 @@ public: return (m_CurrentPoint == 0); } /** Get the point at a_index. Remark: Internally, the indexes are reversed. */ - inline Vector3i GetPoint(size_t a_index) + inline Vector3d GetPoint(size_t a_index) { ASSERT(m_Status == ePathFinderStatus::PATH_FOUND); ASSERT(a_index < m_PathPoints.size()); - return m_PathPoints[m_PathPoints.size() - 1 - a_index]; + Vector3i Point = m_PathPoints[m_PathPoints.size() - 1 - a_index]; + return Vector3d(Point.x + m_HalfWidth, Point.y, Point.z + m_HalfWidth); } /** Returns the total number of points this path has. */ inline int GetPointCount() @@ -164,8 +163,12 @@ private: std::unordered_map<Vector3i, cPathCell, VectorHasher> m_Map; Vector3i m_Destination; Vector3i m_Source; + int m_BoundingBoxWidth; + int m_BoundingBoxHeight; + double m_HalfWidth; int m_StepsLeft; cPathCell * m_NearestPointToTarget; + cFastRandom m_Rand; /* Control fields */ ePathFinderStatus m_Status; diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h index 73ffb55c2..5de83acd8 100644 --- a/src/Mobs/Wolf.h +++ b/src/Mobs/Wolf.h @@ -25,8 +25,8 @@ public: virtual void Attack(std::chrono::milliseconds a_Dt) override; // Get functions - bool IsSitting (void) const { return m_IsSitting; } - bool IsTame (void) const { return m_IsTame; } + bool IsSitting (void) const override { return m_IsSitting; } + bool IsTame (void) const override { return m_IsTame; } bool IsBegging (void) const { return m_IsBegging; } bool IsAngry (void) const { return m_IsAngry; } AString GetOwnerName (void) const { return m_OwnerName; } diff --git a/src/OverridesSettingsRepository.cpp b/src/OverridesSettingsRepository.cpp index 6defdd6b5..e63f2c44c 100644 --- a/src/OverridesSettingsRepository.cpp +++ b/src/OverridesSettingsRepository.cpp @@ -260,7 +260,7 @@ bool cOverridesSettingsRepository::DeleteValue(const AString & a_KeyName, const } else { - return m_Overrides->DeleteValue(a_KeyName, a_ValueName); + return m_Main->DeleteValue(a_KeyName, a_ValueName); } } diff --git a/src/PolarSSL++/BlockingSslClientSocket.cpp b/src/PolarSSL++/BlockingSslClientSocket.cpp index 821125b31..f5ad2f08c 100644 --- a/src/PolarSSL++/BlockingSslClientSocket.cpp +++ b/src/PolarSSL++/BlockingSslClientSocket.cpp @@ -54,19 +54,19 @@ class cBlockingSslClientSocketLinkCallbacks: } - virtual void OnReceivedData(const char * a_Data, size_t a_Length) + virtual void OnReceivedData(const char * a_Data, size_t a_Length) override { m_Socket.OnReceivedData(a_Data, a_Length); } - virtual void OnRemoteClosed(void) + virtual void OnRemoteClosed(void) override { m_Socket.OnDisconnected(); } - virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) + virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override { m_Socket.OnDisconnected(); } diff --git a/src/PolarSSL++/BlockingSslClientSocket.h b/src/PolarSSL++/BlockingSslClientSocket.h index 319e82bf2..462ee95a7 100644 --- a/src/PolarSSL++/BlockingSslClientSocket.h +++ b/src/PolarSSL++/BlockingSslClientSocket.h @@ -21,6 +21,11 @@ class cBlockingSslClientSocket : { public: cBlockingSslClientSocket(void); + + ~cBlockingSslClientSocket(void) + { + Disconnect(); + } /** Connects to the specified server and performs SSL handshake. Returns true if successful, false on failure. Sets internal error text on failure. */ diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp index 4c7fd4a23..5ac4bc227 100644 --- a/src/PolarSSL++/SslContext.cpp +++ b/src/PolarSSL++/SslContext.cpp @@ -152,7 +152,7 @@ void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_Ex m_CACerts = a_CACert; // Set the trusted CA root cert store: - ssl_set_authmode(&m_Ssl, SSL_VERIFY_OPTIONAL); + ssl_set_authmode(&m_Ssl, SSL_VERIFY_REQUIRED); ssl_set_ca_chain(&m_Ssl, m_CACerts->GetInternal(), nullptr, m_ExpectedPeerName.empty() ? nullptr : m_ExpectedPeerName.c_str()); } diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp index 294b6e9be..bfbe5028d 100644 --- a/src/Protocol/Authenticator.cpp +++ b/src/Protocol/Authenticator.cpp @@ -19,6 +19,10 @@ #define DEFAULT_AUTH_SERVER "sessionserver.mojang.com" #define DEFAULT_AUTH_ADDRESS "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%" + + + + cAuthenticator::cAuthenticator(void) : super("cAuthenticator"), m_Server(DEFAULT_AUTH_SERVER), @@ -267,3 +271,7 @@ bool cAuthenticator::GetPlayerProperties(const AString & a_UUID, Json::Value & a return true; } */ + + + + diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp index 51b8e90e7..110590359 100644 --- a/src/Protocol/MojangAPI.cpp +++ b/src/Protocol/MojangAPI.cpp @@ -38,12 +38,36 @@ const int MAX_PER_QUERY = 100; -/** This is the data of the root certs for Starfield Technologies, the CA that signed sessionserver.mojang.com's cert: -Downloaded from http://certs.starfieldtech.com/repository/ */ -static const AString & StarfieldCACert(void) +/** Returns the CA certificates that should be trusted for Mojang-related connections. */ +static const AString & GetCACerts(void) { static const AString Cert( - // G2 cert + // Equifax root CA cert + // Currently used for signing *.mojang.com's cert + // Exported from Mozilla Firefox's built-in CA repository + "-----BEGIN CERTIFICATE-----\n" + "MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV\n" + "UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy\n" + "dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1\n" + "MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx\n" + "dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B\n" + "AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f\n" + "BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A\n" + "cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC\n" + "AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ\n" + "MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm\n" + "aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw\n" + "ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj\n" + "IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF\n" + "MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA\n" + "A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y\n" + "7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh\n" + "1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4\n" + "-----END CERTIFICATE-----\n\n" + + // Starfield G2 cert + // This is the data of the root certs for Starfield Technologies, the CA that used to sign sessionserver.mojang.com's cert + // Downloaded from http://certs.starfieldtech.com/repository/ "-----BEGIN CERTIFICATE-----\n" "MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\n" "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n" @@ -67,7 +91,8 @@ static const AString & StarfieldCACert(void) "pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\n" "mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n" "-----END CERTIFICATE-----\n\n" - // Original (G1) cert: + + // Starfield original (G1) cert: "-----BEGIN CERTIFICATE-----\n" "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n" "MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n" @@ -390,7 +415,7 @@ bool cMojangAPI::SecureRequest(const AString & a_ServerName, const AString & a_R { // Connect the socket: cBlockingSslClientSocket Socket; - Socket.SetTrustedRootCertsFromString(StarfieldCACert(), a_ServerName); + Socket.SetTrustedRootCertsFromString(GetCACerts(), a_ServerName); if (!Socket.Connect(a_ServerName, 443)) { LOGWARNING("%s: Can't connect to %s: %s", __FUNCTION__, a_ServerName.c_str(), Socket.GetLastErrorText().c_str()); @@ -434,7 +459,6 @@ bool cMojangAPI::SecureRequest(const AString & a_ServerName, const AString & a_R a_Response.append((const char *)buf, (size_t)ret); } - Socket.Disconnect(); return true; } diff --git a/src/RCONServer.h b/src/RCONServer.h index 81b019516..ecd936eeb 100644 --- a/src/RCONServer.h +++ b/src/RCONServer.h @@ -61,7 +61,7 @@ protected: // cTCPLink::cCallbacks overrides: - virtual void OnLinkCreated(cTCPLinkPtr a_Link); + virtual void OnLinkCreated(cTCPLinkPtr a_Link) override; virtual void OnReceivedData(const char * a_Data, size_t a_Length) override; virtual void OnRemoteClosed(void) override; virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override; diff --git a/src/Server.cpp b/src/Server.cpp index 01d5a176a..fd3188b18 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -72,7 +72,7 @@ class cServerListenCallbacks: virtual void OnAccepted(cTCPLink & a_Link) override {} - virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) + virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override { LOGWARNING("Cannot listen on port %d: %d (%s).", m_Port, a_ErrorCode, a_ErrorMsg.c_str()); } diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index f6a9972d6..664c6502c 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -239,7 +239,7 @@ public: // cSlotAreaTemporary overrides: virtual void Clicked (cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; - virtual void DblClicked (cPlayer & a_Player, int a_SlotNum); + virtual void DblClicked (cPlayer & a_Player, int a_SlotNum) override; virtual void OnPlayerRemoved(cPlayer & a_Player) override; virtual void SetSlot (int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; diff --git a/src/World.cpp b/src/World.cpp index e93d6bb26..3c39de317 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -150,7 +150,7 @@ protected: int m_LastReportChunkCount; // cChunkCoordCallback override: - virtual void Call(int a_ChunkX, int a_ChunkZ) + virtual void Call(int a_ChunkX, int a_ChunkZ) override { // Check if this was the last chunk: m_NumPrepared += 1; @@ -362,6 +362,7 @@ cWorld::~cWorld() void cWorld::CastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) { BroadcastThunderbolt(a_BlockX, a_BlockY, a_BlockZ); + BroadcastSoundEffect("ambient.weather.thunder", a_BlockX, a_BlockY, a_BlockZ, 50, 1); } diff --git a/src/World.h b/src/World.h index 6c0548ae6..2ecdd519c 100644 --- a/src/World.h +++ b/src/World.h @@ -203,10 +203,10 @@ public: bool VillagersShouldHarvestCrops(void) const { return m_VillagersShouldHarvestCrops; } - virtual eDimension GetDimension(void) const { return m_Dimension; } + virtual eDimension GetDimension(void) const override { return m_Dimension; } /** Returns the world height at the specified coords; waits for the chunk to get loaded / generated */ - virtual int GetHeight(int a_BlockX, int a_BlockZ); + virtual int GetHeight(int a_BlockX, int a_BlockZ) override; // tolua_end @@ -253,7 +253,7 @@ public: void BroadcastScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); void BroadcastScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode); void BroadcastDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display); - void BroadcastSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = nullptr); // tolua_export + void BroadcastSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = nullptr) override; // tolua_export void BroadcastSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = nullptr); // tolua_export void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = nullptr); @@ -788,7 +788,7 @@ public: bool IsWeatherWet(void) const { return !IsWeatherSunny(); } /** Returns true if it is raining, stormy or snowing at the specified location. This takes into account biomes. */ - virtual bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) + virtual bool IsWeatherWetAt(int a_BlockX, int a_BlockZ) override { return (IsWeatherWet() && !IsBiomeNoDownfall(GetBiomeAt(a_BlockX, a_BlockZ))); } diff --git a/src/main.cpp b/src/main.cpp index 8a237b8ee..5cd057278 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -374,6 +374,14 @@ std::unique_ptr<cMemorySettingsRepository> parseArguments(int argc, char **argv) TCLAP::MultiArg<int> portsArg("p", "port", "The port number the server should listen to", false, "port", cmd); + TCLAP::SwitchArg commLogArg("", "log-comm", "Log server client communications to file", cmd); + + TCLAP::SwitchArg commLogInArg("", "log-comm-in", "Log inbound server client communications to file", cmd); + + TCLAP::SwitchArg commLogOutArg("", "log-comm-out", "Log outbound server client communications to file", cmd); + + TCLAP::SwitchArg noBufArg("", "no-output-buffering", "Disable output buffering", cmd); + cmd.parse(argc, argv); auto repo = cpp14::make_unique<cMemorySettingsRepository>(); @@ -396,6 +404,22 @@ std::unique_ptr<cMemorySettingsRepository> parseArguments(int argc, char **argv) } } + if (commLogArg.getValue()) + { + g_ShouldLogCommIn = true; + g_ShouldLogCommOut = true; + } + else + { + g_ShouldLogCommIn = commLogInArg.getValue(); + g_ShouldLogCommOut = commLogOutArg.getValue(); + } + + if (noBufArg.getValue()) + { + setvbuf(stdout, nullptr, _IONBF, 0); + } + repo->SetReadOnly(); return repo; @@ -473,35 +497,7 @@ int main(int argc, char **argv) for (int i = 0; i < argc; i++) { AString Arg(argv[i]); - if ( - (NoCaseCompare(Arg, "/commlog") == 0) || - (NoCaseCompare(Arg, "/logcomm") == 0) - ) - { - g_ShouldLogCommIn = true; - g_ShouldLogCommOut = true; - } - else if ( - (NoCaseCompare(Arg, "/commlogin") == 0) || - (NoCaseCompare(Arg, "/comminlog") == 0) || - (NoCaseCompare(Arg, "/logcommin") == 0) - ) - { - g_ShouldLogCommIn = true; - } - else if ( - (NoCaseCompare(Arg, "/commlogout") == 0) || - (NoCaseCompare(Arg, "/commoutlog") == 0) || - (NoCaseCompare(Arg, "/logcommout") == 0) - ) - { - g_ShouldLogCommOut = true; - } - else if (NoCaseCompare(Arg, "nooutbuf") == 0) - { - setvbuf(stdout, nullptr, _IONBF, 0); - } - else if (NoCaseCompare(Arg, "/service") == 0) + if (NoCaseCompare(Arg, "/service") == 0) { cRoot::m_RunAsService = true; } |