summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/CMakeLists.txt4
-rw-r--r--src/Bindings/ManualBindings.cpp159
-rw-r--r--src/Bindings/ManualBindings_World.cpp6
-rw-r--r--src/BlockEntities/CMakeLists.txt2
-rw-r--r--src/BlockEntities/MobHeadEntity.cpp43
-rw-r--r--src/BlockEntities/MobHeadEntity.h24
-rw-r--r--src/Blocks/BlockHandler.cpp29
-rw-r--r--src/Blocks/BlockSlab.h2
-rw-r--r--src/Blocks/CMakeLists.txt2
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/ChunkMap.cpp18
-rw-r--r--src/Cuberite.vcxproj.user27
-rw-r--r--src/Defines.h15
-rw-r--r--src/Entities/CMakeLists.txt7
-rw-r--r--src/Entities/Player.cpp93
-rw-r--r--src/Entities/Player.h30
-rw-r--r--src/Generating/CMakeLists.txt2
-rw-r--r--src/HTTPServer/CMakeLists.txt10
-rw-r--r--src/HTTPServer/UrlParser.cpp200
-rw-r--r--src/HTTPServer/UrlParser.h58
-rw-r--r--src/Items/CMakeLists.txt2
-rw-r--r--src/MCServer.vcproj.user167
-rw-r--r--src/Mobs/AggressiveMonster.cpp4
-rw-r--r--src/Mobs/AggressiveMonster.h8
-rw-r--r--src/Mobs/CMakeLists.txt2
-rw-r--r--src/Mobs/Horse.cpp6
-rw-r--r--src/Mobs/Horse.h6
-rw-r--r--src/Mobs/Monster.cpp60
-rw-r--r--src/Mobs/Monster.h8
-rw-r--r--src/Mobs/Path.cpp331
-rw-r--r--src/Mobs/Path.h63
-rw-r--r--src/Mobs/PathFinder.cpp98
-rw-r--r--src/Mobs/PathFinder.h24
-rw-r--r--src/Noise/CMakeLists.txt2
-rw-r--r--src/OSSupport/CMakeLists.txt2
-rw-r--r--src/PolarSSL++/BlockingSslClientSocket.cpp28
-rw-r--r--src/PolarSSL++/BlockingSslClientSocket.h3
-rw-r--r--src/PolarSSL++/CMakeLists.txt2
-rw-r--r--src/Protocol/CMakeLists.txt2
-rw-r--r--src/Protocol/MojangAPI.cpp4
-rw-r--r--src/Protocol/Protocol17x.cpp2
-rw-r--r--src/Protocol/Protocol18x.cpp50
-rw-r--r--src/RankManager.cpp1
-rw-r--r--src/Resources/Cuberite.rc (renamed from src/Resources/MCServer.rc)2
-rw-r--r--src/Resources/resource_Cuberite.h (renamed from src/Resources/resource_MCServer.h)0
-rw-r--r--src/Root.cpp6
-rw-r--r--src/Simulator/CMakeLists.txt2
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt2
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp7
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h8
-rw-r--r--src/UI/CMakeLists.txt2
-rw-r--r--src/World.cpp2
-rw-r--r--src/WorldStorage/CMakeLists.txt2
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp15
-rwxr-xr-xsrc/WorldStorage/WSSAnvil.cpp43
-rw-r--r--src/main.cpp39
56 files changed, 1238 insertions, 502 deletions
diff --git a/src/Bindings/CMakeLists.txt b/src/Bindings/CMakeLists.txt
index a53e82581..10cda1efb 100644
--- a/src/Bindings/CMakeLists.txt
+++ b/src/Bindings/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
include_directories (".")
@@ -154,5 +154,5 @@ endif()
if(NOT MSVC)
add_library(Bindings ${SRCS} ${HDRS})
- target_link_libraries(Bindings lua sqlite tolualib mbedtls)
+ target_link_libraries(Bindings lua sqlite tolualib mbedtls HTTPServer)
endif()
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 3a595c1d2..42e7e9bd2 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -36,6 +36,7 @@
#include "../StringCompression.h"
#include "../CommandOutput.h"
#include "../BuildInfo.h"
+#include "../HTTPServer/UrlParser.h"
@@ -1956,6 +1957,155 @@ static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S)
+static int tolua_cUrlParser_GetDefaultPort(lua_State * a_LuaState)
+{
+ // API function signature:
+ // cUrlParser:GetDefaultPort("scheme") -> number
+
+ // Check params:
+ cLuaState L(a_LuaState);
+ if (
+ !L.CheckParamUserTable(1, "cUrlParser") ||
+ !L.CheckParamString(2) ||
+ !L.CheckParamEnd(3)
+ )
+ {
+ return 0;
+ }
+
+ // Read params from Lua:
+ AString scheme;
+ L.GetStackValue(2, scheme);
+
+ // Execute and push result:
+ L.Push(cUrlParser::GetDefaultPort(scheme));
+ return 1;
+}
+
+
+
+
+
+static int tolua_cUrlParser_IsKnownScheme(lua_State * a_LuaState)
+{
+ // API function signature:
+ // cUrlParser:IsKnownScheme("scheme") -> bool
+
+ // Check params:
+ cLuaState L(a_LuaState);
+ if (
+ !L.CheckParamUserTable(1, "cUrlParser") ||
+ !L.CheckParamString(2) ||
+ !L.CheckParamEnd(3)
+ )
+ {
+ return 0;
+ }
+
+ // Read params from Lua:
+ AString scheme;
+ L.GetStackValue(2, scheme);
+
+ // Execute and push result:
+ L.Push(cUrlParser::IsKnownScheme(scheme));
+ return 1;
+}
+
+
+
+
+
+static int tolua_cUrlParser_Parse(lua_State * a_LuaState)
+{
+ // API function signature:
+ // cUrlParser:Parse("url") -> "scheme", "user", "password", "host", portnum, "path", "query", "fragment"
+ // On error, returns nil and error message
+
+ // Check params:
+ cLuaState L(a_LuaState);
+ if (
+ !L.CheckParamUserTable(1, "cUrlParser") ||
+ !L.CheckParamString(2) ||
+ !L.CheckParamEnd(3)
+ )
+ {
+ return 0;
+ }
+
+ // Read params from Lua:
+ AString url;
+ L.GetStackValue(2, url);
+
+ // Execute and push result:
+ AString scheme, username, password, host, path, query, fragment;
+ UInt16 port;
+ auto res = cUrlParser::Parse(url, scheme, username, password, host, port, path, query, fragment);
+ if (!res.first)
+ {
+ // Error, return nil and error msg:
+ L.PushNil();
+ L.Push(res.second);
+ return 2;
+ }
+ L.Push(scheme);
+ L.Push(username);
+ L.Push(password);
+ L.Push(host);
+ L.Push(port);
+ L.Push(path);
+ L.Push(query);
+ L.Push(fragment);
+ return 8;
+}
+
+
+
+
+
+static int tolua_cUrlParser_ParseAuthorityPart(lua_State * a_LuaState)
+{
+ // API function signature:
+ // cUrlParser:ParseAuthorityPart("authority") -> "user", "password", "host", portnum
+ // On error, returns nil and error message
+ // Parts not specified in the "authority" are left empty / zero
+
+ // Check params:
+ cLuaState L(a_LuaState);
+ if (
+ !L.CheckParamUserTable(1, "cUrlParser") ||
+ !L.CheckParamString(2) ||
+ !L.CheckParamEnd(3)
+ )
+ {
+ return 0;
+ }
+
+ // Read params from Lua:
+ AString authPart;
+ L.GetStackValue(2, authPart);
+
+ // Execute and push result:
+ AString username, password, host;
+ UInt16 port;
+ auto res = cUrlParser::ParseAuthorityPart(authPart, username, password, host, port);
+ if (!res.first)
+ {
+ // Error, return nil and error msg:
+ L.PushNil();
+ L.Push(res.second);
+ return 2;
+ }
+ L.Push(username);
+ L.Push(password);
+ L.Push(host);
+ L.Push(port);
+ return 4;
+}
+
+
+
+
+
static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S)
{
cWebAdmin * self = reinterpret_cast<cWebAdmin *>(tolua_tousertype(tolua_S, 1, nullptr));
@@ -3224,9 +3374,11 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_usertype(tolua_S, "cCryptoHash");
tolua_usertype(tolua_S, "cLineBlockTracer");
tolua_usertype(tolua_S, "cStringCompression");
+ tolua_usertype(tolua_S, "cUrlParser");
tolua_cclass(tolua_S, "cCryptoHash", "cCryptoHash", "", nullptr);
tolua_cclass(tolua_S, "cLineBlockTracer", "cLineBlockTracer", "", nullptr);
tolua_cclass(tolua_S, "cStringCompression", "cStringCompression", "", nullptr);
+ tolua_cclass(tolua_S, "cUrlParser", "cUrlParser", "", nullptr);
// Globals:
tolua_function(tolua_S, "Clamp", tolua_Clamp);
@@ -3390,6 +3542,13 @@ void cManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "InflateString", tolua_InflateString);
tolua_endmodule(tolua_S);
+ tolua_beginmodule(tolua_S, "cUrlParser");
+ tolua_function(tolua_S, "GetDefaultPort", tolua_cUrlParser_GetDefaultPort);
+ tolua_function(tolua_S, "IsKnownScheme", tolua_cUrlParser_IsKnownScheme);
+ tolua_function(tolua_S, "Parse", tolua_cUrlParser_Parse);
+ tolua_function(tolua_S, "ParseAuthorityPart", tolua_cUrlParser_ParseAuthorityPart);
+ tolua_endmodule(tolua_S);
+
tolua_beginmodule(tolua_S, "cWebAdmin");
tolua_function(tolua_S, "GetHTMLEscapedString", tolua_AllToLua_cWebAdmin_GetHTMLEscapedString);
tolua_function(tolua_S, "GetPlugins", tolua_cWebAdmin_GetPlugins);
diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp
index 225e71af5..f40af9778 100644
--- a/src/Bindings/ManualBindings_World.cpp
+++ b/src/Bindings/ManualBindings_World.cpp
@@ -36,9 +36,9 @@ static int tolua_cWorld_BroadcastParticleEffect(lua_State * tolua_S)
AString Name;
float PosX, PosY, PosZ, OffX, OffY, OffZ;
float ParticleData;
- int ParticleAmmount;
+ int ParticleAmount;
cClientHandle * ExcludeClient = nullptr;
- L.GetStackValues(1, World, Name, PosX, PosY, PosZ, OffX, OffY, OffZ, ParticleData, ParticleAmmount, ExcludeClient);
+ L.GetStackValues(1, World, Name, PosX, PosY, PosZ, OffX, OffY, OffZ, ParticleData, ParticleAmount, ExcludeClient);
if (World == nullptr)
{
LOGWARNING("World:BroadcastParticleEffect(): invalid world parameter");
@@ -53,7 +53,7 @@ static int tolua_cWorld_BroadcastParticleEffect(lua_State * tolua_S)
L.GetStackValue(11 + i, data[static_cast<size_t>(i)]);
}
- World->GetBroadcaster().BroadcastParticleEffect(Name, Vector3f(PosX, PosY, PosZ), Vector3f(OffX, OffY, OffZ), ParticleData, ParticleAmmount, ExcludeClient);
+ World->GetBroadcaster().BroadcastParticleEffect(Name, Vector3f(PosX, PosY, PosZ), Vector3f(OffX, OffY, OffZ), ParticleData, ParticleAmount, ExcludeClient);
return 0;
}
diff --git a/src/BlockEntities/CMakeLists.txt b/src/BlockEntities/CMakeLists.txt
index fbf85d2af..6c164c4b4 100644
--- a/src/BlockEntities/CMakeLists.txt
+++ b/src/BlockEntities/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/BlockEntities/MobHeadEntity.cpp b/src/BlockEntities/MobHeadEntity.cpp
index 3275bf7f2..542e920ba 100644
--- a/src/BlockEntities/MobHeadEntity.cpp
+++ b/src/BlockEntities/MobHeadEntity.cpp
@@ -14,8 +14,7 @@
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("")
+ m_Rotation(SKULL_ROTATION_NORTH)
{
}
@@ -35,9 +34,9 @@ bool cMobHeadEntity::UsedBy(cPlayer * a_Player)
void cMobHeadEntity::SetType(const eMobHeadType & a_Type)
{
- if ((!m_Owner.empty()) && (a_Type != SKULL_TYPE_PLAYER))
+ if ((!m_OwnerName.empty()) && (a_Type != SKULL_TYPE_PLAYER))
{
- m_Owner = "";
+ m_OwnerName = m_OwnerUUID = m_OwnerTexture = m_OwnerTextureSignature = "";
}
m_Type = a_Type;
}
@@ -55,13 +54,43 @@ void cMobHeadEntity::SetRotation(eMobHeadRotation a_Rotation)
-void cMobHeadEntity::SetOwner(const AString & a_Owner)
+void cMobHeadEntity::SetOwner(const cPlayer & a_Owner)
{
- if ((a_Owner.length() > 16) || (m_Type != SKULL_TYPE_PLAYER))
+ if (m_Type != SKULL_TYPE_PLAYER)
{
return;
}
- m_Owner = a_Owner;
+
+ m_OwnerName = a_Owner.GetName();
+ m_OwnerUUID = a_Owner.GetUUID();
+
+ const Json::Value & Properties = a_Owner.GetClientHandle()->GetProperties();
+ for (auto & Node : Properties)
+ {
+ if (Node.get("name", "").asString() == "textures")
+ {
+ m_OwnerTexture = Node.get("value", "").asString();
+ m_OwnerTextureSignature = Node.get("signature", "").asString();
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cMobHeadEntity::SetOwner(const AString & a_OwnerUUID, const AString & a_OwnerName, const AString & a_OwnerTexture, const AString & a_OwnerTextureSignature)
+{
+ if (m_Type != SKULL_TYPE_PLAYER)
+ {
+ return;
+ }
+
+ m_OwnerUUID = a_OwnerUUID;
+ m_OwnerName = a_OwnerName;
+ m_OwnerTexture = a_OwnerTexture;
+ m_OwnerTextureSignature = a_OwnerTextureSignature;
}
diff --git a/src/BlockEntities/MobHeadEntity.h b/src/BlockEntities/MobHeadEntity.h
index f25cb3a16..2eb932068 100644
--- a/src/BlockEntities/MobHeadEntity.h
+++ b/src/BlockEntities/MobHeadEntity.h
@@ -39,8 +39,11 @@ public:
/** Set the rotation of the mob head */
void SetRotation(eMobHeadRotation a_Rotation);
- /** Set the player name for mob heads with player type */
- void SetOwner(const AString & a_Owner);
+ /** Set the player for mob heads with player type */
+ void SetOwner(const cPlayer & a_Owner);
+
+ /** Sets the player components for the mob heads with player type */
+ void SetOwner(const AString & a_OwnerUUID, const AString & a_OwnerName, const AString & a_OwnerTexture, const AString & a_OwnerTextureSignature);
/** Returns the type of the mob head */
eMobHeadType GetType(void) const { return m_Type; }
@@ -49,7 +52,16 @@ public:
eMobHeadRotation GetRotation(void) const { return m_Rotation; }
/** Returns the player name of the mob head */
- AString GetOwner(void) const { return m_Owner; }
+ AString GetOwnerName(void) const { return m_OwnerName; }
+
+ /** Returns the player UUID of the mob head */
+ AString GetOwnerUUID(void) const { return m_OwnerUUID; }
+
+ /** Returns the texture of the mob head */
+ AString GetOwnerTexture(void) const { return m_OwnerTexture; }
+
+ /** Returns the texture signature of the mob head */
+ AString GetOwnerTextureSignature(void) const { return m_OwnerTextureSignature; }
// tolua_end
@@ -60,7 +72,11 @@ private:
eMobHeadType m_Type;
eMobHeadRotation m_Rotation;
- AString m_Owner;
+
+ AString m_OwnerName;
+ AString m_OwnerUUID;
+ AString m_OwnerTexture;
+ AString m_OwnerTextureSignature;
} ; // tolua_export
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 0ad0e2242..22b70f590 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -453,22 +453,49 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac
{
switch (m_BlockType)
{
+ case E_BLOCK_ACACIA_DOOR:
+ case E_BLOCK_ACTIVE_COMPARATOR:
+ case E_BLOCK_BED:
+ case E_BLOCK_BIRCH_DOOR:
+ case E_BLOCK_BREWING_STAND:
case E_BLOCK_CAKE:
case E_BLOCK_CARROTS:
+ case E_BLOCK_CAULDRON:
case E_BLOCK_COCOA_POD:
+ case E_BLOCK_CROPS:
+ case E_BLOCK_DARK_OAK_DOOR:
+ case E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB:
case E_BLOCK_DOUBLE_STONE_SLAB:
case E_BLOCK_DOUBLE_WOODEN_SLAB:
case E_BLOCK_FIRE:
case E_BLOCK_FARMLAND:
+ case E_BLOCK_FLOWER_POT:
+ case E_BLOCK_HEAD:
+ case E_BLOCK_INACTIVE_COMPARATOR:
+ case E_BLOCK_INVERTED_DAYLIGHT_SENSOR:
+ case E_BLOCK_IRON_DOOR:
+ case E_BLOCK_JUNGLE_DOOR:
case E_BLOCK_MELON_STEM:
case E_BLOCK_MOB_SPAWNER:
case E_BLOCK_NETHER_WART:
+ case E_BLOCK_OAK_DOOR:
+ case E_BLOCK_PISTON_EXTENSION:
case E_BLOCK_POTATOES:
case E_BLOCK_PUMPKIN_STEM:
+ case E_BLOCK_REDSTONE_ORE_GLOWING:
+ case E_BLOCK_REDSTONE_REPEATER_OFF:
+ case E_BLOCK_REDSTONE_REPEATER_ON:
+ case E_BLOCK_REDSTONE_TORCH_OFF:
+ case E_BLOCK_REDSTONE_WIRE:
+ case E_BLOCK_SIGN_POST:
case E_BLOCK_SNOW:
+ case E_BLOCK_SPRUCE_DOOR:
+ case E_BLOCK_STANDING_BANNER:
case E_BLOCK_SUGARCANE:
case E_BLOCK_TALL_GRASS:
- case E_BLOCK_CROPS:
+ case E_BLOCK_TRIPWIRE:
+ case E_BLOCK_WALL_BANNER:
+ case E_BLOCK_WALLSIGN:
{
// Silktouch can't be used for these blocks
ConvertToPickups(Pickups, Meta);
diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h
index 79d440cf6..bc7f79099 100644
--- a/src/Blocks/BlockSlab.h
+++ b/src/Blocks/BlockSlab.h
@@ -210,7 +210,7 @@ public:
{
case E_BLOCK_DOUBLE_STONE_SLAB: return E_BLOCK_STONE_SLAB;
case E_BLOCK_DOUBLE_WOODEN_SLAB: return E_BLOCK_WOODEN_SLAB;
- case E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB: return E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB;
+ case E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB: return E_BLOCK_RED_SANDSTONE_SLAB;
}
ASSERT(!"Unhandled double slab type!");
return a_BlockType;
diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt
index 1c12d9fbc..e9b3ce386 100644
--- a/src/Blocks/CMakeLists.txt
+++ b/src/Blocks/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2478d4af4..3d9e10aa5 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -216,7 +216,7 @@ if (NOT MSVC)
# If building a windows version, but not using MSVC, add the resources directly to the makefile:
if (WIN32)
- list(APPEND SOURCE "Resources/MCServer.rc")
+ list(APPEND SOURCE "Resources/Cuberite.rc")
endif()
else ()
# MSVC-specific handling: Put all files into one project, separate by the folders:
@@ -276,7 +276,7 @@ else ()
SET_SOURCE_FILES_PROPERTIES(
"StackWalker.cpp LeakFinder.cpp" PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\""
)
- list(APPEND SOURCE "Resources/MCServer.rc")
+ list(APPEND SOURCE "Resources/Cuberite.rc")
# Make MSVC generate the PDB files even for the release build:
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index edf42abe7..cbbf910fb 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -1896,10 +1896,10 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
public cEntityCallback
{
public:
- cTNTDamageCallback(cBoundingBox & a_bbTNT, Vector3d a_ExplosionPos, int a_ExplosionSize) :
- m_bbTNT(a_bbTNT),
- m_ExplosionPos(a_ExplosionPos),
- m_ExplosionSize(a_ExplosionSize)
+ cTNTDamageCallback(cBoundingBox & a_CBBBTNT, Vector3d a_CBExplosionPos, int a_CBExplosionSize) :
+ m_bbTNT(a_CBBBTNT),
+ m_ExplosionPos(a_CBExplosionPos),
+ m_ExplosionSize(a_CBExplosionSize)
{
}
@@ -2364,10 +2364,10 @@ bool cChunkMap::GenerateChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback *
class cPrepareLoadCallback: public cChunkCoordCallback
{
public:
- cPrepareLoadCallback(cWorld & a_World, cChunkMap & a_ChunkMap, cChunkCoordCallback * a_Callback):
- m_World(a_World),
- m_ChunkMap(a_ChunkMap),
- m_Callback(a_Callback)
+ cPrepareLoadCallback(cWorld & a_CBWorld, cChunkMap & a_CBChunkMap, cChunkCoordCallback * a_CBCallback):
+ m_World(a_CBWorld),
+ m_ChunkMap(a_CBChunkMap),
+ m_Callback(a_CBCallback)
{
}
@@ -2385,7 +2385,7 @@ bool cChunkMap::GenerateChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback *
}
// The chunk failed to load, generate it:
- cCSLock Lock(m_ChunkMap.m_CSLayers);
+ cCSLock CBLock(m_ChunkMap.m_CSLayers);
cChunkPtr CBChunk = m_ChunkMap.GetChunkNoLoad(a_CBChunkX, a_CBChunkZ);
if (CBChunk == nullptr)
diff --git a/src/Cuberite.vcxproj.user b/src/Cuberite.vcxproj.user
new file mode 100644
index 000000000..7ebd19d9b
--- /dev/null
+++ b/src/Cuberite.vcxproj.user
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LocalDebuggerWorkingDirectory>../Server</LocalDebuggerWorkingDirectory>
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseProfile|Win32'">
+ <LocalDebuggerWorkingDirectory>../Server</LocalDebuggerWorkingDirectory>
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RelWithDebInfo|Win32'">
+ <LocalDebuggerWorkingDirectory>../Server</LocalDebuggerWorkingDirectory>
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='MinSizeRel|Win32'">
+ <LocalDebuggerWorkingDirectory>../Server</LocalDebuggerWorkingDirectory>
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LocalDebuggerWorkingDirectory>../Server</LocalDebuggerWorkingDirectory>
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugProfile|Win32'">
+ <LocalDebuggerWorkingDirectory>../Server</LocalDebuggerWorkingDirectory>
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/src/Defines.h b/src/Defines.h
index b0589d8a0..e2f72ed84 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -481,13 +481,20 @@ inline bool IsBlockFence(BLOCKTYPE a_BlockType)
{
switch (a_BlockType)
{
- case E_BLOCK_FENCE:
- case E_BLOCK_OAK_FENCE_GATE:
- case E_BLOCK_NETHER_BRICK_FENCE:
+ case E_BLOCK_ACACIA_FENCE:
+ case E_BLOCK_ACACIA_FENCE_GATE:
+ case E_BLOCK_BIRCH_FENCE:
+ case E_BLOCK_BIRCH_FENCE_GATE:
case E_BLOCK_COBBLESTONE_WALL:
case E_BLOCK_DARK_OAK_FENCE:
+ case E_BLOCK_DARK_OAK_FENCE_GATE:
+ case E_BLOCK_FENCE:
+ case E_BLOCK_JUNGLE_FENCE:
+ case E_BLOCK_JUNGLE_FENCE_GATE:
+ case E_BLOCK_NETHER_BRICK_FENCE:
+ case E_BLOCK_OAK_FENCE_GATE:
+ case E_BLOCK_SPRUCE_FENCE:
case E_BLOCK_SPRUCE_FENCE_GATE:
- case E_BLOCK_ACACIA_FENCE:
{
return true;
}
diff --git a/src/Entities/CMakeLists.txt b/src/Entities/CMakeLists.txt
index 54cca9c90..0416d5338 100644
--- a/src/Entities/CMakeLists.txt
+++ b/src/Entities/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
@@ -61,10 +61,7 @@ SET (HDRS
WitherSkullEntity.h)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
- set_source_files_properties(Entity.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=sign-conversion -Wno-error=global-constructors -Wno-error=switch-enum ")
- set_source_files_properties(EntityEffect.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=switch-enum ")
- set_source_files_properties(Floater.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=sign-conversion ")
- set_source_files_properties(Player.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=sign-conversion -Wno-error=switch-enum -Wno-error=conversion ")
+ set_source_files_properties(Entity.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=global-constructors")
endif()
if(NOT MSVC)
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 33ded6ab9..80f07cb65 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -63,6 +63,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
m_GameMode(eGameMode_NotSet),
m_IP(""),
m_ClientHandle(a_Client),
+ m_FreezeCounter(-1),
m_NormalMaxSpeed(1.0),
m_SprintingMaxSpeed(1.3),
m_FlyingMaxSpeed(1.0),
@@ -112,6 +113,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
m_LastGroundHeight = static_cast<float>(GetPosY());
m_Stance = GetPosY() + 1.62;
+ FreezeInternal(GetPosition(), false); // Freeze. Will be unfrozen once the chunk is loaded
if (m_GameMode == gmNotSet)
{
@@ -220,8 +222,35 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
m_Stats.AddValue(statMinutesPlayed, 1);
+ // Handle a frozen player
+ if (m_IsFrozen)
+ {
+ m_FreezeCounter += 1;
+ if (!m_IsManuallyFrozen && a_Chunk.IsValid())
+ {
+ // If the player was automatically frozen, unfreeze if the chunk the player is inside is loaded
+ Unfreeze();
+ }
+ else
+ {
+ // If the player was externally / manually frozen (plugin, etc.) or if the chunk isn't loaded yet:
+ // 1. Set the location to m_FrozenPosition every tick.
+ // 2. Zero out the speed every tick.
+ // 3. Send location updates every 60 ticks.
+ SetPosition(m_FrozenPosition);
+ SetSpeed(0, 0, 0);
+ if (m_FreezeCounter % 60 == 0)
+ {
+ BroadcastMovementUpdate(m_ClientHandle.get());
+ m_ClientHandle->SendPlayerPosition();
+ }
+ return;
+ }
+ }
+
if (!a_Chunk.IsValid())
{
+ FreezeInternal(GetPosition(), false);
// This may happen if the cPlayer is created before the chunks have the chance of being loaded / generated (#83)
return;
}
@@ -879,7 +908,15 @@ void cPlayer::KilledBy(TakeDamageInfo & a_TDI)
case dtEnderPearl: DamageText = "misused an ender pearl"; break;
case dtAdmin: DamageText = "was administrator'd"; break;
case dtExplosion: DamageText = "blew up"; break;
- default: DamageText = "died, somehow; we've no idea how though"; break;
+ case dtAttack: DamageText = "was attacked by thin air"; break;
+ #ifndef __clang__
+ default:
+ {
+ ASSERT(!"Unknown damage type");
+ DamageText = "died, somehow; we've no idea how though";
+ break;
+ }
+ #endif // __clang__
}
AString DeathMessage = Printf("%s %s", GetName().c_str(), DamageText.c_str());
PluginManager->CallHookKilled(*this, a_TDI, DeathMessage);
@@ -1263,6 +1300,46 @@ void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
+void cPlayer::Freeze(const Vector3d & a_Location)
+{
+ FreezeInternal(a_Location, true);
+}
+
+
+
+
+
+bool cPlayer::IsFrozen()
+{
+ return m_IsFrozen;
+}
+
+
+
+
+
+int cPlayer::GetFrozenDuration()
+{
+ return m_FreezeCounter;
+}
+
+
+
+
+
+void cPlayer::Unfreeze()
+{
+ m_FreezeCounter = -1;
+ m_IsFrozen = false;
+ SetPosition(m_FrozenPosition);
+ BroadcastMovementUpdate(m_ClientHandle.get());
+ m_ClientHandle->SendPlayerPosition();
+}
+
+
+
+
+
void cPlayer::SendRotation(double a_YawDegrees, double a_PitchDegrees)
{
SetYaw(a_YawDegrees);
@@ -1533,6 +1610,20 @@ void cPlayer::TossItems(const cItems & a_Items)
}
+
+
+
+void cPlayer::FreezeInternal(const Vector3d & a_Location, bool a_ManuallyFrozen)
+{
+ m_IsFrozen = true;
+ m_FrozenPosition = a_Location;
+ m_IsManuallyFrozen = a_ManuallyFrozen;
+}
+
+
+
+
+
bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d a_NewPosition)
{
ASSERT(a_World != nullptr);
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index bff9599f7..10c9106a3 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -138,6 +138,18 @@ public:
// tolua_begin
+ /** Prevent the player from moving and lock him into a_Location. */
+ void Freeze(const Vector3d & a_Location);
+
+ /** Is the player frozen? */
+ bool IsFrozen();
+
+ /** How long has the player been frozen? */
+ int GetFrozenDuration();
+
+ /** Cancels Freeze(...) and allows the player to move naturally. */
+ void Unfreeze();
+
/** 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]
@@ -240,7 +252,7 @@ public:
void SendMessageFatal (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtFailure); }
void SendMessagePrivateMsg (const AString & a_Message, const AString & a_Sender) { m_ClientHandle->SendChat(a_Message, mtPrivateMessage, a_Sender); }
void SendMessage (const cCompositeChat & a_Message) { m_ClientHandle->SendChat(a_Message); }
-
+
void SendSystemMessage (const AString & a_Message) { m_ClientHandle->SendChatSystem(a_Message, mtCustom); }
void SendAboveActionBarMessage(const AString & a_Message) { m_ClientHandle->SendChatAboveActionBar(a_Message, mtCustom); }
void SendSystemMessage (const cCompositeChat & a_Message) { m_ClientHandle->SendChatSystem(a_Message); }
@@ -576,6 +588,18 @@ protected:
cSlotNums m_InventoryPaintSlots;
+ /** if m_IsFrozen is true, we lock m_Location to this position. */
+ Vector3d m_FrozenPosition;
+
+ /** If true, we are locking m_Position to m_FrozenPosition. */
+ bool m_IsFrozen;
+
+ /** */
+ int m_FreezeCounter;
+
+ /** Was the player frozen manually by a plugin or automatically by the server? */
+ bool m_IsManuallyFrozen;
+
/** 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. */
@@ -661,6 +685,10 @@ protected:
/** Tosses a list of items. */
void TossItems(const cItems & a_Items);
+ /** Pins the player to a_Location until Unfreeze() is called.
+ If ManuallyFrozen is false, the player will unfreeze when the chunk is loaded. */
+ void FreezeInternal(const Vector3d & a_Location, bool a_ManuallyFrozen);
+
/** Returns the filename for the player data based on the UUID given.
This can be used both for online and offline UUIDs. */
AString GetUUIDFileName(const AString & a_UUID);
diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt
index d15d9eba0..dd346b6c4 100644
--- a/src/Generating/CMakeLists.txt
+++ b/src/Generating/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/HTTPServer/CMakeLists.txt b/src/HTTPServer/CMakeLists.txt
index 6788d50bf..a08a1fcf8 100644
--- a/src/HTTPServer/CMakeLists.txt
+++ b/src/HTTPServer/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
@@ -12,7 +12,9 @@ SET (SRCS
HTTPServer.cpp
MultipartParser.cpp
NameValueParser.cpp
- SslHTTPConnection.cpp)
+ SslHTTPConnection.cpp
+ UrlParser.cpp
+)
SET (HDRS
EnvelopeParser.h
@@ -22,7 +24,9 @@ SET (HDRS
HTTPServer.h
MultipartParser.h
NameValueParser.h
- SslHTTPConnection.h)
+ SslHTTPConnection.h
+ UrlParser.h
+)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set_source_files_properties(HTTPServer.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=global-constructors ")
diff --git a/src/HTTPServer/UrlParser.cpp b/src/HTTPServer/UrlParser.cpp
new file mode 100644
index 000000000..05db3e413
--- /dev/null
+++ b/src/HTTPServer/UrlParser.cpp
@@ -0,0 +1,200 @@
+
+// UrlParser.cpp
+
+// Implements the cUrlParser class that parses string URL into individual parts
+
+#include "Globals.h"
+#include "UrlParser.h"
+
+
+
+
+
+UInt16 cUrlParser::GetDefaultPort(const AString & a_Scheme)
+{
+ if (a_Scheme == "http")
+ {
+ return 80;
+ }
+ else if (a_Scheme == "https")
+ {
+ return 443;
+ }
+ else if (a_Scheme == "ftp")
+ {
+ return 21;
+ }
+ else if (a_Scheme == "mailto")
+ {
+ return 25;
+ }
+ return 0;
+}
+
+
+
+
+
+std::pair<bool, AString> cUrlParser::ParseAuthorityPart(
+ const AString & a_AuthorityPart,
+ AString & a_Username,
+ AString & a_Password,
+ AString & a_Host,
+ UInt16 & a_Port
+)
+{
+ /*
+ a_AuthorityPart format:
+ [user:password@]host[:port]
+ host can be an IPv4, hostname, or an IPv6 enclosed in brackets
+ Assume only the password can contain an additional at-sign
+ */
+
+ // Split the authority on the last at-sign, if present:
+ auto idxLastAtSign = a_AuthorityPart.find_last_of('@');
+ auto credPart = (idxLastAtSign == AString::npos) ? AString() : a_AuthorityPart.substr(0, idxLastAtSign);
+ auto srvrPart = (idxLastAtSign == AString::npos) ? a_AuthorityPart : a_AuthorityPart.substr(idxLastAtSign + 1);
+
+ // User credentials are completely optional:
+ auto idxCredColon = credPart.find(':');
+ a_Username = credPart.substr(0, idxCredColon);
+ a_Password = (idxCredColon == AString::npos) ? AString() : credPart.substr(idxCredColon + 1);
+
+ // Host can be a hostname, IPv4 or [IPv6]. If in brackets, search for the closing bracket first
+ if (srvrPart.empty())
+ {
+ // No host information at all. Bail out with success
+ a_Host.clear();
+ return std::make_pair(true, AString());
+ }
+ if (srvrPart[0] == '[')
+ {
+ // [IPv6] host, search for the closing bracket
+ auto idxClosingBracket = srvrPart.find(']');
+ if (idxClosingBracket == AString::npos)
+ {
+ return std::make_pair(false, "Invalid IPv6-like address, missing closing bracket");
+ }
+ a_Host = srvrPart.substr(0, idxClosingBracket);
+ auto portPart = srvrPart.substr(idxClosingBracket + 1);
+ if (portPart.empty())
+ {
+ // No port was specified, return success
+ return std::make_pair(true, AString());
+ }
+ if (portPart[0] != ':')
+ {
+ return std::make_pair(false, "Invalid port format after IPv6 address, mising colon");
+ }
+ if (!StringToInteger(portPart.substr(2), a_Port))
+ {
+ return std::make_pair(false, "Failed to parse port number after IPv6 address");
+ }
+ return std::make_pair(true, AString());
+ }
+
+ // Not an [IPv6] address, split on the last colon:
+ auto idxLastColon = srvrPart.find_last_of(':');
+ a_Host = srvrPart.substr(0, idxLastColon);
+ if (idxLastColon == AString::npos)
+ {
+ // No port was specified, return success
+ return std::make_pair(true, AString());
+ }
+ auto portPart = srvrPart.substr(idxLastColon + 1);
+ if (!StringToInteger(portPart, a_Port))
+ {
+ return std::make_pair(false, "Failed to parse port number after hostname");
+ }
+ return std::make_pair(true, AString());
+}
+
+
+
+
+
+std::pair<bool, AString> cUrlParser::Parse(
+ const AString & a_Url,
+ AString & a_Scheme,
+ AString & a_Username,
+ AString & a_Password,
+ AString & a_Host,
+ UInt16 & a_Port,
+ AString & a_Path,
+ AString & a_Query,
+ AString & a_Fragment
+)
+{
+ // Find the scheme - the text before the first colon:
+ auto idxColon = a_Url.find(':');
+ if (idxColon == AString::npos)
+ {
+ return std::make_pair(false, "Cannot parse the Scheme part of the URL");
+ }
+ a_Scheme = StrToLower(a_Url.substr(0, idxColon));
+ a_Port = GetDefaultPort(a_Scheme);
+ if (a_Port == 0)
+ {
+ return std::make_pair(false, Printf("Unknown URL scheme: \"%s\"", a_Scheme.c_str()));
+ }
+
+ // If the next two chars are a double-slash, skip them:
+ auto authStart = idxColon + 1;
+ if (a_Url.substr(authStart, 2) == "//")
+ {
+ authStart += 2;
+ }
+
+ // The Authority part follows the Scheme, until the first slash:
+ auto idxFirstSlash = a_Url.find('/', authStart + 1);
+ if (idxFirstSlash == AString::npos)
+ {
+ // No slash, the whole end of the Url is the authority part
+ idxFirstSlash = a_Url.size();
+ }
+
+ // Parse the Authority part into individual components:
+ auto res = ParseAuthorityPart(
+ a_Url.substr(authStart, idxFirstSlash - authStart),
+ a_Username, a_Password,
+ a_Host, a_Port
+ );
+ if (!res.first)
+ {
+ return res;
+ }
+
+ // Parse the rest into a path, query and fragment:
+ a_Path.clear();
+ a_Query.clear();
+ a_Fragment.clear();
+ if (idxFirstSlash == a_Url.size())
+ {
+ // No additional data, bail out with success
+ return std::make_pair(true, AString());
+ }
+ auto idxPathEnd = a_Url.find_first_of("?#", idxFirstSlash + 1);
+ if (idxPathEnd == AString::npos)
+ {
+ a_Path = a_Url.substr(idxFirstSlash);
+ return std::make_pair(true, AString());
+ }
+ a_Path = a_Url.substr(idxFirstSlash, idxPathEnd - idxFirstSlash);
+ auto idxHash = a_Url.find('#', idxPathEnd);
+ if (idxHash == AString::npos)
+ {
+ a_Query = a_Url.substr(idxPathEnd + 1);
+ return std::make_pair(true, AString());
+ }
+ if (idxHash > idxPathEnd)
+ {
+ a_Query = a_Url.substr(idxPathEnd + 1, idxHash - idxPathEnd - 1);
+ }
+ a_Fragment = a_Url.substr(idxHash + 1);
+ return std::make_pair(true, AString());
+}
+
+
+
+
+
diff --git a/src/HTTPServer/UrlParser.h b/src/HTTPServer/UrlParser.h
new file mode 100644
index 000000000..15a63e05d
--- /dev/null
+++ b/src/HTTPServer/UrlParser.h
@@ -0,0 +1,58 @@
+
+// UrlParser.h
+
+// Declares the cUrlParser class that parses string URL into individual parts
+
+
+
+
+
+#pragma once
+
+
+
+
+
+class cUrlParser
+{
+public:
+ /** Returns true if the specified scheme (http, ftp, mailto, ...) is recognized by the URL parser.
+ Is case sensitive, known schemes are always lowercase. */
+ static bool IsKnownScheme(const AString & a_Scheme) { return (GetDefaultPort(a_Scheme) > 0); }
+
+ /** Returns the default port used by the specified scheme / protocol.
+ If the scheme is not known, 0 is returned. */
+ static UInt16 GetDefaultPort(const AString & a_Scheme);
+
+ /** Parses the given Authority part of an URL into individual components.
+ Returns true on success,
+ returns false and error message on failure. */
+ static std::pair<bool, AString> ParseAuthorityPart(
+ const AString & a_AuthorityPart,
+ AString & a_Username,
+ AString & a_Password,
+ AString & a_Host,
+ UInt16 & a_Port
+ );
+
+ /** Parses the given URL into individual components.
+ Returns true on success,
+ returns false and error message on failure.
+ Fails if the scheme (protocol) is not known.
+ If port is missing, the default port for the specific scheme is applied. */
+ static std::pair<bool, AString> Parse(
+ const AString & a_Url,
+ AString & a_Scheme,
+ AString & a_Username,
+ AString & a_Password,
+ AString & a_Host,
+ UInt16 & a_Port,
+ AString & a_Path,
+ AString & a_Query,
+ AString & a_Fragment
+ );
+};
+
+
+
+
diff --git a/src/Items/CMakeLists.txt b/src/Items/CMakeLists.txt
index 2e719d1a6..9b3a2d8b5 100644
--- a/src/Items/CMakeLists.txt
+++ b/src/Items/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/MCServer.vcproj.user b/src/MCServer.vcproj.user
deleted file mode 100644
index b17909f71..000000000
--- a/src/MCServer.vcproj.user
+++ /dev/null
@@ -1,167 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<VisualStudioUserFile
- ProjectType="Visual C++"
- Version="9,00"
- ShowAllFiles="false"
- >
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- >
- <DebugSettings
- Command="$(TargetPath)"
- WorkingDirectory="..\MCServer"
- CommandArguments=""
- Attach="false"
- DebuggerType="3"
- RemoteCommand=""
- HttpUrl=""
- PDBPath=""
- SQLDebugging=""
- Environment=""
- EnvironmentMerge="true"
- DebuggerFlavor="0"
- MPIRunCommand=""
- MPIRunArguments=""
- MPIRunWorkingDirectory=""
- ApplicationCommand=""
- ApplicationArguments=""
- ShimCommand=""
- MPIAcceptMode=""
- MPIAcceptFilter=""
- />
- </Configuration>
- <Configuration
- Name="DebugProfile|Win32"
- >
- <DebugSettings
- Command="$(TargetPath)"
- WorkingDirectory="..\MCServer"
- CommandArguments=""
- Attach="false"
- DebuggerType="3"
- RemoteCommand=""
- HttpUrl=""
- PDBPath=""
- SQLDebugging=""
- Environment=""
- EnvironmentMerge="true"
- DebuggerFlavor="0"
- MPIRunCommand=""
- MPIRunArguments=""
- MPIRunWorkingDirectory=""
- ApplicationCommand=""
- ApplicationArguments=""
- ShimCommand=""
- MPIAcceptMode=""
- MPIAcceptFilter=""
- />
- </Configuration>
- <Configuration
- Name="MinSizeRel|Win32"
- >
- <DebugSettings
- Command="$(TargetPath)"
- WorkingDirectory="..\MCServer"
- CommandArguments=""
- Attach="false"
- DebuggerType="3"
- RemoteCommand=""
- HttpUrl=""
- PDBPath=""
- SQLDebugging=""
- Environment=""
- EnvironmentMerge="true"
- DebuggerFlavor="0"
- MPIRunCommand=""
- MPIRunArguments=""
- MPIRunWorkingDirectory=""
- ApplicationCommand=""
- ApplicationArguments=""
- ShimCommand=""
- MPIAcceptMode=""
- MPIAcceptFilter=""
- />
- </Configuration>
- <Configuration
- Name="Release|Win32"
- >
- <DebugSettings
- Command="$(TargetPath)"
- WorkingDirectory="..\MCServer"
- CommandArguments=""
- Attach="false"
- DebuggerType="3"
- RemoteCommand=""
- HttpUrl=""
- PDBPath=""
- SQLDebugging=""
- Environment=""
- EnvironmentMerge="true"
- DebuggerFlavor="0"
- MPIRunCommand=""
- MPIRunArguments=""
- MPIRunWorkingDirectory=""
- ApplicationCommand=""
- ApplicationArguments=""
- ShimCommand=""
- MPIAcceptMode=""
- MPIAcceptFilter=""
- />
- </Configuration>
- <Configuration
- Name="ReleaseProfile|Win32"
- >
- <DebugSettings
- Command="$(TargetPath)"
- WorkingDirectory="..\MCServer"
- CommandArguments=""
- Attach="false"
- DebuggerType="3"
- Remote="1"
- RemoteMachine="ASAGA"
- RemoteCommand=""
- HttpUrl=""
- PDBPath=""
- SQLDebugging=""
- Environment=""
- EnvironmentMerge="true"
- DebuggerFlavor="0"
- MPIRunCommand=""
- MPIRunArguments=""
- MPIRunWorkingDirectory=""
- ApplicationCommand=""
- ApplicationArguments=""
- ShimCommand=""
- MPIAcceptMode=""
- MPIAcceptFilter=""
- />
- </Configuration>
- <Configuration
- Name="RelWithDebInfo|Win32"
- >
- <DebugSettings
- Command="$(TargetPath)"
- WorkingDirectory="..\MCServer"
- CommandArguments=""
- Attach="false"
- DebuggerType="3"
- RemoteCommand=""
- HttpUrl=""
- PDBPath=""
- SQLDebugging=""
- Environment=""
- EnvironmentMerge="true"
- DebuggerFlavor="0"
- MPIRunCommand=""
- MPIRunArguments=""
- MPIRunWorkingDirectory=""
- ApplicationCommand=""
- ApplicationArguments=""
- ShimCommand=""
- MPIAcceptMode=""
- MPIAcceptFilter=""
- />
- </Configuration>
- </Configurations>
-</VisualStudioUserFile>
diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp
index 309f6d985..56500309d 100644
--- a/src/Mobs/AggressiveMonster.cpp
+++ b/src/Mobs/AggressiveMonster.cpp
@@ -22,9 +22,9 @@ cAggressiveMonster::cAggressiveMonster(const AString & a_ConfigName, eMonsterTyp
// What to do if in Chasing State
-void cAggressiveMonster::InStateChasing(std::chrono::milliseconds a_Dt)
+void cAggressiveMonster::InStateChasing(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
- super::InStateChasing(a_Dt);
+ super::InStateChasing(a_Dt, a_Chunk);
if (m_Target != nullptr)
{
diff --git a/src/Mobs/AggressiveMonster.h b/src/Mobs/AggressiveMonster.h
index 17539d39e..13f59842f 100644
--- a/src/Mobs/AggressiveMonster.h
+++ b/src/Mobs/AggressiveMonster.h
@@ -11,16 +11,16 @@ class cAggressiveMonster :
public cMonster
{
typedef cMonster super;
-
+
public:
cAggressiveMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
virtual void Tick (std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
- virtual void InStateChasing(std::chrono::milliseconds a_Dt) override;
-
+ virtual void InStateChasing(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
+
virtual void EventSeePlayer(cEntity *) override;
-
+
/** Try to perform attack
returns true if attack was deemed successful (hit player, fired projectile, creeper exploded, etc.) even if it didn't actually do damage
return false if e.g. the mob is still in cooldown from a previous attack */
diff --git a/src/Mobs/CMakeLists.txt b/src/Mobs/CMakeLists.txt
index 14c7a8ca3..4336af7c3 100644
--- a/src/Mobs/CMakeLists.txt
+++ b/src/Mobs/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/Mobs/Horse.cpp b/src/Mobs/Horse.cpp
index f133f9912..01906b7b4 100644
--- a/src/Mobs/Horse.cpp
+++ b/src/Mobs/Horse.cpp
@@ -72,7 +72,7 @@ void cHorse::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
m_bIsTame = true;
}
}
-
+
if (m_bIsRearing)
{
if (m_RearTickCount == 20)
@@ -161,12 +161,12 @@ void cHorse::GetDrops(cItems & a_Drops, cEntity * a_Killer)
-void cHorse::InStateIdle(std::chrono::milliseconds a_Dt)
+void cHorse::InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
// If horse is tame and someone is sitting on it, don't walk around
if ((!m_bIsTame) || (m_Attachee == nullptr))
{
- super::InStateIdle(a_Dt);
+ super::InStateIdle(a_Dt, a_Chunk);
}
}
diff --git a/src/Mobs/Horse.h b/src/Mobs/Horse.h
index c87d437c9..7afa5bf29 100644
--- a/src/Mobs/Horse.h
+++ b/src/Mobs/Horse.h
@@ -11,14 +11,14 @@ class cHorse :
public cPassiveMonster
{
typedef cPassiveMonster super;
-
+
public:
cHorse(int Type, int Color, int Style, int TameTimes);
CLASS_PROTODEF(cHorse)
-
+
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
- virtual void InStateIdle(std::chrono::milliseconds a_Dt) override;
+ virtual void InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override;
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index fa36285ba..7d8c3de02 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -133,9 +133,8 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk)
{
if (DoesPosYRequireJump(FloorC(m_NextWayPointPosition.y)))
{
- if (
- (IsOnGround() && (GetSpeedX() == 0.0f) && (GetSpeedY() == 0.0f)) // TODO water handling?
- )
+ if (((IsOnGround()) && (GetSpeed().SqrLength() == 0.0f)) ||
+ (IsSwimming()))
{
m_bOnGround = false;
m_JumpCoolDown = 20;
@@ -303,18 +302,18 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
case IDLE:
{
// If enemy passive we ignore checks for player visibility.
- InStateIdle(a_Dt);
+ InStateIdle(a_Dt, a_Chunk);
break;
}
case CHASING:
{
// If we do not see a player anymore skip chasing action.
- InStateChasing(a_Dt);
+ InStateChasing(a_Dt, a_Chunk);
break;
}
case ESCAPING:
{
- InStateEscaping(a_Dt);
+ InStateEscaping(a_Dt, a_Chunk);
break;
}
case ATTACKING: break;
@@ -377,7 +376,7 @@ void cMonster::SetPitchAndYawFromDestination(bool a_IsFollowingPath)
double HeadRotation, HeadPitch;
HeadDistance.Normalize();
VectorToEuler(HeadDistance.x, HeadDistance.y, HeadDistance.z, HeadRotation, HeadPitch);
- if (std::abs(BodyRotation - HeadRotation) < 90)
+ if ((std::abs(BodyRotation - HeadRotation) < 70) && (std::abs(HeadPitch) < 60))
{
SetHeadYaw(HeadRotation);
SetPitch(-HeadPitch);
@@ -385,7 +384,7 @@ void cMonster::SetPitchAndYawFromDestination(bool a_IsFollowingPath)
else
{
SetHeadYaw(BodyRotation);
- SetPitch(-BodyPitch);
+ SetPitch(0);
}
}
@@ -611,7 +610,7 @@ void cMonster::EventLosePlayer(void)
-void cMonster::InStateIdle(std::chrono::milliseconds a_Dt)
+void cMonster::InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
if (m_PathfinderActivated)
{
@@ -632,9 +631,24 @@ void cMonster::InStateIdle(std::chrono::milliseconds a_Dt)
if ((Dist.SqrLength() > 2) && (rem >= 3))
{
- Vector3d Destination(GetPosX() + Dist.x, 0, GetPosZ() + Dist.z);
- Destination.y = FindFirstNonAirBlockPosition(Destination.x, Destination.z);
- MoveToPosition(Destination);
+
+ Vector3d Destination(GetPosX() + Dist.x, GetPosition().y, GetPosZ() + Dist.z);
+
+ cChunk * Chunk = a_Chunk.GetNeighborChunk(static_cast<int>(Destination.x), static_cast<int>(Destination.z));
+ if ((Chunk == nullptr) || !Chunk->IsValid())
+ {
+ return;
+ }
+
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ int RelX = static_cast<int>(Destination.x) - Chunk->GetPosX() * cChunkDef::Width;
+ int RelZ = static_cast<int>(Destination.z) - Chunk->GetPosZ() * cChunkDef::Width;
+ Chunk->GetBlockTypeMeta(RelX, static_cast<int>(Destination.y) - 1, RelZ, BlockType, BlockMeta);
+ if (BlockType != E_BLOCK_STATIONARY_WATER) // Idle mobs shouldn't enter water on purpose
+ {
+ MoveToPosition(Destination);
+ }
}
}
}
@@ -645,7 +659,7 @@ void cMonster::InStateIdle(std::chrono::milliseconds a_Dt)
// What to do if in Chasing State
// This state should always be defined in each child class
-void cMonster::InStateChasing(std::chrono::milliseconds a_Dt)
+void cMonster::InStateChasing(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
UNUSED(a_Dt);
}
@@ -655,7 +669,7 @@ void cMonster::InStateChasing(std::chrono::milliseconds a_Dt)
// What to do if in Escaping State
-void cMonster::InStateEscaping(std::chrono::milliseconds a_Dt)
+void cMonster::InStateEscaping(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
UNUSED(a_Dt);
@@ -1084,6 +1098,19 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk, bool WouldBurn)
bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk)
{
+ // If the Y coord is out of range, return the most logical result without considering anything else:
+ int RelY = FloorC(a_Location.y);
+ if (RelY < 0)
+ {
+ // Never burn under the world
+ return false;
+ }
+ if (RelY >= cChunkDef::Height)
+ {
+ // Always burn above the world
+ return true;
+ }
+
cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(a_Location.x), FloorC(a_Location.z));
if ((Chunk == nullptr) || (!Chunk->IsValid()))
{
@@ -1091,14 +1118,13 @@ bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk)
}
int RelX = FloorC(a_Location.x) - Chunk->GetPosX() * cChunkDef::Width;
- int RelY = FloorC(a_Location.y);
int RelZ = FloorC(a_Location.z) - Chunk->GetPosZ() * cChunkDef::Width;
if (
(Chunk->GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight
(Chunk->GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand
- (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime
- GetWorld()->IsWeatherSunnyAt(POSX_TOINT, POSZ_TOINT) // Not raining
+ (GetWorld()->GetTimeOfDay() < 12000 + 1000) && // Daytime
+ GetWorld()->IsWeatherSunnyAt(POSX_TOINT, POSZ_TOINT) // Not raining
)
{
return true;
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index 98b67f343..cc830a058 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -79,9 +79,9 @@ public:
virtual void EventLosePlayer(void);
virtual void CheckEventLostPlayer(void);
- virtual void InStateIdle (std::chrono::milliseconds a_Dt);
- virtual void InStateChasing (std::chrono::milliseconds a_Dt);
- virtual void InStateEscaping(std::chrono::milliseconds a_Dt);
+ virtual void InStateIdle (std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
+ virtual void InStateChasing (std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
+ virtual void InStateEscaping(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
int GetAttackRate() { return static_cast<int>(m_AttackRate); }
void SetAttackRate(float a_AttackRate) { m_AttackRate = a_AttackRate; }
@@ -193,7 +193,7 @@ protected:
/** Returns if a monster can reach a given height by jumping. */
inline bool DoesPosYRequireJump(int a_PosY)
{
- return ((a_PosY > POSY_TOINT) && (a_PosY == POSY_TOINT + 1));
+ return ((a_PosY > POSY_TOINT));
}
/** Move in a straight line to the next waypoint in the path, will jump if needed. */
diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp
index 1c8a3657f..03f0ad31a 100644
--- a/src/Mobs/Path.cpp
+++ b/src/Mobs/Path.cpp
@@ -7,6 +7,8 @@
#include "../Chunk.h"
#define JUMP_G_COST 20
+#define NORMAL_G_COST 10
+#define DIAGONAL_G_COST 14
#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.
@@ -30,8 +32,7 @@ bool compareHeuristics::operator()(cPathCell * & a_Cell1, cPathCell * & a_Cell2)
cPath::cPath(
cChunk & a_Chunk,
const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps,
- double a_BoundingBoxWidth, double a_BoundingBoxHeight,
- int a_MaxUp, int a_MaxDown
+ double a_BoundingBoxWidth, double a_BoundingBoxHeight
) :
m_StepsLeft(a_MaxSteps),
m_IsValid(true),
@@ -39,10 +40,8 @@ cPath::cPath(
m_Chunk(&a_Chunk),
m_BadChunkFound(false)
{
- // 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; // Treat all mobs width as 1 until physics is improved. This would also require changes to stepOnce to work.
+ a_BoundingBoxWidth = 1; // Treat all mobs width as 1 until physics is improved.
m_BoundingBoxWidth = CeilC(a_BoundingBoxWidth);
m_BoundingBoxHeight = CeilC(a_BoundingBoxHeight);
@@ -57,7 +56,7 @@ cPath::cPath(
m_Destination.y = FloorC(a_EndingPoint.y);
m_Destination.z = FloorC(a_EndingPoint.z - HalfWidthInt);
- if (!IsWalkable(m_Source))
+ if (!IsWalkable(m_Source, m_Source))
{
m_Status = ePathFinderStatus::PATH_NOT_FOUND;
return;
@@ -126,51 +125,6 @@ Vector3i cPath::AcceptNearbyPath()
-bool cPath::IsSolid(const Vector3i & a_Location)
-{
- ASSERT(m_Chunk != nullptr);
-
- if (!cChunkDef::IsValidHeight(a_Location.y))
- {
- return false;
- }
- auto Chunk = m_Chunk->GetNeighborChunk(a_Location.x, a_Location.z);
- if ((Chunk == nullptr) || !Chunk->IsValid())
- {
- m_BadChunkFound = true;
- return true;
- }
- m_Chunk = Chunk;
-
- BLOCKTYPE BlockType;
- NIBBLETYPE BlockMeta;
- int RelX = a_Location.x - m_Chunk->GetPosX() * cChunkDef::Width;
- int RelZ = a_Location.z - m_Chunk->GetPosZ() * cChunkDef::Width;
-
- m_Chunk->GetBlockTypeMeta(RelX, a_Location.y, RelZ, BlockType, BlockMeta);
- if (
- (BlockType == E_BLOCK_FENCE) ||
- (BlockType == E_BLOCK_OAK_FENCE_GATE) ||
- (BlockType == E_BLOCK_NETHER_BRICK_FENCE) ||
- (BlockType == E_BLOCK_COBBLESTONE_WALL) ||
- ((BlockType >= E_BLOCK_SPRUCE_FENCE_GATE) && (BlockType <= E_BLOCK_ACACIA_FENCE))
- )
- {
- // TODO move this out of IsSolid to a proper place.
- 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.
- }
- if (BlockType == E_BLOCK_STATIONARY_WATER)
- {
- GetCell(a_Location + Vector3i(0, -1, 0))->m_IsSolid = true;
- }
-
- return cBlockInfo::IsSolid(BlockType);
-}
-
-
-
-
-
bool cPath::StepOnce()
{
cPathCell * CurrentCell = OpenListPop();
@@ -209,40 +163,47 @@ bool cPath::StepOnce()
// Now we start checking adjacent cells.
- bool done_east = false,
- done_west = false,
- done_north = false,
- done_south = false; // If true, no need to do more checks in that direction
+ // If true, no need to do more checks in that direction
+ bool DoneEast = false,
+ DoneWest = false,
+ DoneNorth = false,
+ DoneSouth = false;
+
+ // If true, we can walk in that direction without changing height
+ // This is used for deciding if to calculate diagonals
+ bool WalkableEast = false,
+ WalkableWest = false,
+ WalkableNorth = false,
+ WalkableSouth = false;
// If we can jump without hitting the ceiling
- if (BodyFitsIn(CurrentCell->m_Location + Vector3i(0, 1, 0)))
+ if (BodyFitsIn(CurrentCell->m_Location + Vector3i(0, 1, 0), CurrentCell->m_Location))
{
+ // For ladder climbing
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, 0), CurrentCell, JUMP_G_COST);
+
// Check east-up
- if (GetCell(CurrentCell->m_Location + Vector3i(1, 0, 0))->m_IsSolid)
+ if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 1, 0), CurrentCell, JUMP_G_COST))
{
- ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 1, 0), CurrentCell, JUMP_G_COST);
- done_east = true;
+ DoneEast = true;
}
// Check west-up
- if (GetCell(CurrentCell->m_Location + Vector3i(-1, 0, 0))->m_IsSolid)
+ if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 1, 0), CurrentCell, JUMP_G_COST))
{
- ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 1, 0), CurrentCell, JUMP_G_COST);
- done_west = true;
+ DoneWest = true;
}
// Check north-up
- if (GetCell(CurrentCell->m_Location + Vector3i(0, 0, -1))->m_IsSolid)
+ if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, -1), CurrentCell, JUMP_G_COST))
{
- ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, -1), CurrentCell, JUMP_G_COST);
- done_north = true;
+ DoneNorth = true;
}
// Check south-up
- if (GetCell(CurrentCell->m_Location + Vector3i(0, 0, 1))->m_IsSolid)
+ if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, 1), CurrentCell, JUMP_G_COST))
{
- ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, 1), CurrentCell, JUMP_G_COST);
- done_south = true;
+ DoneSouth = true;
}
}
@@ -251,72 +212,87 @@ bool cPath::StepOnce()
// Check North, South, East, West at our own height or below. We are willing to jump up to 3 blocks down.
- if (!done_east)
+ if (!DoneEast)
{
- for (int i = 0; i >= -3; --i)
+ for (int y = 0; y >= -3; --y)
{
- if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, i, 0), CurrentCell, 10))
+ if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, y, 0), CurrentCell, NORMAL_G_COST))
{
- done_east = true;
+ DoneEast = true;
+ if (y == 0)
+ {
+ WalkableEast = true;
+ }
break;
}
}
}
- if (!done_west)
+ if (!DoneWest)
{
- for (int i = 0; i >= -3; --i)
+ for (int y = 0; y >= -3; --y)
{
- if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, i, 0), CurrentCell, 10))
+ if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, y, 0), CurrentCell, NORMAL_G_COST))
{
- done_west = true;
+ DoneWest = true;
+ if (y == 0)
+ {
+ WalkableWest = true;
+ }
break;
}
}
}
- if (!done_south)
+ if (!DoneSouth)
{
- for (int i = 0; i >= -3; --i)
+ for (int y = 0; y >= -3; --y)
{
- if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, i, 1), CurrentCell, 10))
+ if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, y, 1), CurrentCell, NORMAL_G_COST))
{
- done_west = true;
+ DoneWest = true;
+ if (y == 0)
+ {
+ WalkableSouth = true;
+ }
break;
}
}
}
- if (!done_north)
+ if (!DoneNorth)
{
- for (int i = 0; i >= -3; --i)
+ for (int y = 0; y >= -3; --y)
{
- if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, i, -1), CurrentCell, 10))
+ if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, y, -1), CurrentCell, NORMAL_G_COST))
{
- done_north = true;
+ DoneNorth = true;
+ if (y == 0)
+ {
+ WalkableNorth = true;
+ }
break;
}
}
}
-
// Check diagonals
-
- for (int x = -1; x <= 1; x += 2)
+ if (WalkableNorth && WalkableEast)
{
- 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)
- {
- // This prevents falling of "sharp turns" e.g. a 1x1x20 rectangle in the air which breaks in a right angle suddenly.
- if (GetCell(CurrentCell->m_Location + Vector3i(x, -1, 0))->m_IsSolid && GetCell(CurrentCell->m_Location + Vector3i(0, -1, z))->m_IsSolid)
- {
- ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, 0, z), CurrentCell, 14); // 14 is a good enough approximation of sqrt(10 + 10).
- }
- }
- }
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 0, -1), CurrentCell, DIAGONAL_G_COST);
+ }
+ if (WalkableNorth && WalkableWest)
+ {
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 0, -1), CurrentCell, DIAGONAL_G_COST);
+ }
+ if (WalkableSouth && WalkableEast)
+ {
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 0, 1), CurrentCell, DIAGONAL_G_COST);
+ }
+ if (WalkableSouth && WalkableWest)
+ {
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 0, 1), CurrentCell, DIAGONAL_G_COST);
}
return false;
@@ -349,6 +325,12 @@ void cPath::BuildPath()
cPathCell * CurrentCell = GetCell(m_Destination);
while (CurrentCell->m_Parent != nullptr)
{
+ // Waypoints are cylinders that start at some particular x, y, z and have infinite height.
+ // Submerging water waypoints allows swimming mobs to be able to touch them.
+ if (GetCell(CurrentCell->m_Location + Vector3i(0, -1, 0))->m_BlockType == E_BLOCK_STATIONARY_WATER)
+ {
+ CurrentCell->m_Location.y -= 30;
+ }
m_PathPoints.push_back(CurrentCell->m_Location); // Populate the cPath with points. All midpoints are added. Destination is added. Source is excluded.
CurrentCell = CurrentCell->m_Parent;
}
@@ -418,7 +400,7 @@ cPathCell * cPath::OpenListPop() // Popping from the open list also means addin
bool cPath::ProcessIfWalkable(const Vector3i & a_Location, cPathCell * a_Parent, int a_Cost)
{
- if (IsWalkable(a_Location))
+ if (IsWalkable(a_Location, a_Parent->m_Location))
{
ProcessCell(GetCell(a_Location), a_Parent, a_Cost);
return true;
@@ -486,13 +468,72 @@ void cPath::ProcessCell(cPathCell * a_Cell, cPathCell * a_Caller, int a_GDelta)
+void cPath::FillCellAttributes(cPathCell & a_Cell)
+{
+ const Vector3i & Location = a_Cell.m_Location;
+
+ ASSERT(m_Chunk != nullptr);
+
+ if (!cChunkDef::IsValidHeight(Location.y))
+ {
+ // Players can't build outside the game height, so it must be air
+ a_Cell.m_IsSolid = false;
+ a_Cell.m_IsSpecial = false;
+ a_Cell.m_BlockType = E_BLOCK_AIR;
+ return;
+ }
+ auto Chunk = m_Chunk->GetNeighborChunk(Location.x, Location.z);
+ if ((Chunk == nullptr) || !Chunk->IsValid())
+ {
+ m_BadChunkFound = true;
+ a_Cell.m_IsSolid = true;
+ a_Cell.m_IsSpecial = false;
+ a_Cell.m_BlockType = E_BLOCK_AIR; // m_BlockType is never used when m_IsSpecial is false, but it may be used if we implement dijkstra
+ return;
+ }
+ m_Chunk = Chunk;
+
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ int RelX = Location.x - m_Chunk->GetPosX() * cChunkDef::Width;
+ int RelZ = Location.z - m_Chunk->GetPosZ() * cChunkDef::Width;
+
+ m_Chunk->GetBlockTypeMeta(RelX, Location.y, RelZ, BlockType, BlockMeta);
+ a_Cell.m_BlockType = BlockType;
+ a_Cell.m_BlockMeta = BlockMeta;
+
+
+ if (BlockTypeIsSpecial(BlockType))
+ {
+ a_Cell.m_IsSpecial = true;
+ a_Cell.m_IsSolid = true; // Specials are solids only from a certain direction. But their m_IsSolid is always true
+ }
+ else if ((a_Cell.m_BlockType == E_BLOCK_AIR) && IsBlockFence(GetCell(Location + Vector3i(0, -1, 0))->m_BlockType))
+ {
+ // Air blocks with fences below them are consider Special Solids. That is, they sometimes behave as solids.
+ a_Cell.m_IsSpecial = true;
+ a_Cell.m_IsSolid = true;
+ }
+ else
+ {
+
+ a_Cell.m_IsSpecial = false;
+ a_Cell.m_IsSolid = cBlockInfo::IsSolid(BlockType);
+ }
+
+}
+
+
+
+
+
cPathCell * cPath::GetCell(const Vector3i & a_Location)
{
// Create the cell in the hash table if it's not already there.
if (m_Map.count(a_Location) == 0) // Case 1: Cell is not on any list. We've never checked this cell before.
{
m_Map[a_Location].m_Location = a_Location;
- m_Map[a_Location].m_IsSolid = IsSolid(a_Location);
+ FillCellAttributes(m_Map[a_Location]);
m_Map[a_Location].m_Status = eCellStatus::NOLIST;
#ifdef COMPILING_PATHFIND_DEBUGGER
#ifdef COMPILING_PATHFIND_DEBUGGER_MARK_UNCHECKED
@@ -511,16 +552,16 @@ cPathCell * cPath::GetCell(const Vector3i & a_Location)
-bool cPath::IsWalkable(const Vector3i & a_Location)
+bool cPath::IsWalkable(const Vector3i & a_Location, const Vector3i & a_Source)
{
- return (HasSolidBelow(a_Location) && BodyFitsIn(a_Location));
+ return (HasSolidBelow(a_Location) && BodyFitsIn(a_Location, a_Source));
}
-
-bool cPath::BodyFitsIn(const Vector3i & a_Location)
+// We need the source because some special blocks are solid only from a certain direction e.g. doors
+bool cPath::BodyFitsIn(const Vector3i & a_Location, const Vector3i & a_Source)
{
int x, y, z;
for (y = 0; y < m_BoundingBoxHeight; ++y)
@@ -529,9 +570,20 @@ bool cPath::BodyFitsIn(const Vector3i & a_Location)
{
for (z = 0; z < m_BoundingBoxWidth; ++z)
{
- if (GetCell(a_Location + Vector3i(x, y, z))->m_IsSolid)
+ cPathCell * CurrentCell = GetCell(a_Location + Vector3i(x, y, z));
+ if (CurrentCell->m_IsSolid)
{
- return false;
+ if (CurrentCell->m_IsSpecial)
+ {
+ if (SpecialIsSolidFromThisDirection(CurrentCell->m_BlockType, CurrentCell->m_BlockMeta, a_Location - a_Source))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
}
}
}
@@ -543,6 +595,71 @@ bool cPath::BodyFitsIn(const Vector3i & a_Location)
+bool cPath::BlockTypeIsSpecial(BLOCKTYPE a_Type)
+{
+ if (IsBlockFence(a_Type))
+ {
+ return true;
+ }
+
+ switch (a_Type)
+ {
+ case E_BLOCK_OAK_DOOR:
+ case E_BLOCK_DARK_OAK_DOOR:
+ case E_BLOCK_TRAPDOOR:
+ case E_BLOCK_WATER:
+ case E_BLOCK_STATIONARY_WATER:
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+}
+
+
+
+
+
+bool cPath::SpecialIsSolidFromThisDirection(BLOCKTYPE a_Type, NIBBLETYPE a_Meta, const Vector3i & a_Direction)
+{
+ if (a_Direction == Vector3i(0, 0, 0))
+ {
+ return false;
+ }
+
+
+
+ switch (a_Type)
+ {
+ // Air is special only when above a fence
+ case E_BLOCK_AIR:
+ {
+ // Treat the air block as solid if the mob is going upward and trying to climb a fence
+ if (a_Direction.y > 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // TODO Fill this with the other specials after physics is fixed
+ }
+
+
+
+ return true;
+}
+
+
+
+
+
bool cPath::HasSolidBelow(const Vector3i & a_Location)
{
int x, z;
diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h
index ac71968bd..f51b7da77 100644
--- a/src/Mobs/Path.h
+++ b/src/Mobs/Path.h
@@ -7,6 +7,7 @@ enum class ePathFinderStatus;
class cPath;
*/
+
#include "../FastRandom.h"
#ifdef COMPILING_PATHFIND_DEBUGGER
/* Note: the COMPILING_PATHFIND_DEBUGGER flag is used by Native / WiseOldMan95 to debug
@@ -19,22 +20,40 @@ class cPath;
//fwd: ../Chunk.h
class cChunk;
+
/* Various little structs and classes */
enum class ePathFinderStatus {CALCULATING, PATH_FOUND, PATH_NOT_FOUND, NEARBY_FOUND};
enum class eCellStatus {OPENLIST, CLOSEDLIST, NOLIST};
+/** The pathfinder has 3 types of cells (cPathCell).
+1 - empty. m_IsSolid is false, m_IsSpecial is false. Air cells are always traversable by A*.
+2 - occupied / solid. m_IsSolid is true, m_IsSpecial is false. Air cells are never traversable by A*.
+3 - Special. m_IsSolid is true, m_IsSpecial is true. These cells are special: They may either behave as empty
+or as occupied / solid, depending on the mob's direction of movement. For instance, an airblock above a fence is a special cell,
+because when mobs attempt to travel to it by jumping, it acts as a solid. But when mobs fall and land on top of a fence,
+it acts as air. Special cells include: Doors, ladders, trapdoors, water, gates.
+
+The main function which handles special blocks is SpecialIsSolidFromThisDirection.
+This function receives a BlockType, a meta, and a direction of travel,
+then it uses those 3 parameters to decide whether the special block should behave as a solid or as air in this
+particular direction of travel.
+
+Currently, only fences and water are handled properly. The function always returns "true" (meaning: treat as occuiped/solid) for
+the rest of the blocks. This will be fixed once the physics engine issues are fixed. */
struct cPathCell
{
Vector3i m_Location; // Location of the cell in the world.
int m_F, m_G, m_H; // F, G, H as defined in regular A*.
eCellStatus m_Status; // Which list is the cell in? Either non, open, or closed.
cPathCell * m_Parent; // Cell's parent, as defined in regular A*.
- bool m_IsSolid; // Is the cell an air or a solid? Partial solids are currently considered solids.
+ bool m_IsSolid; // Is the cell an air or a solid? Partial solids are considered solids. If m_IsSpecial is true, this is always true.
+ bool m_IsSpecial; // The cell is special - it acts as "solid" or "air" depending on direction, e.g. door or top of fence.
+ BLOCKTYPE m_BlockType;
+ NIBBLETYPE m_BlockMeta;
};
-
class compareHeuristics
{
public:
@@ -48,32 +67,22 @@ public:
class cPath
{
public:
- /** Creates a pathfinder instance. A Mob will probably need a single pathfinder instance for its entire life.
-
- Note that if you have a man-sized mob (1x1x2, zombies, etc), you are advised to call this function without parameters
- because the declaration might change in later version of the pathFinder, and a parameter-less call always assumes a man-sized mob.
+ /** Creates a pathfinder instance.
+ After calling this, you are expected to call CalculationStep() once per tick or once per several ticks
+ until it returns something other than CALCULATING.
- If your mob is not man-sized, you are advised to use cPath(width, height), this would be compatible with future versions,
- but please be aware that as of now those parameters will be ignored and your mob will be assumed to be man sized.
-
- @param a_BoundingBoxWidth the character's boundingbox width in blocks. Currently the parameter is ignored and 1 is assumed.
- @param a_BoundingBoxHeight the character's boundingbox width in blocks. Currently the parameter is ignored and 2 is assumed.
- @param a_MaxUp the character's max jump height in blocks. Currently the parameter is ignored and 1 is assumed.
- @param a_MaxDown How far is the character willing to fall? Currently the parameter is ignored and 1 is assumed. */
- /** Attempts to find a path starting from source to destination.
- After calling this, you are expected to call Step() once per tick or once per several ticks until it returns true. You should then call getPath() to obtain the path.
- Calling this before a path is found resets the current path and starts another search.
@param a_StartingPoint The function expects this position to be the lowest block the mob is in, a rule of thumb: "The block where the Zombie's knees are at".
@param a_EndingPoint "The block where the Zombie's knees want to be".
- @param a_MaxSteps The maximum steps before giving up. */
+ @param a_MaxSteps The maximum steps before giving up.
+ @param a_BoundingBoxWidth the character's boundingbox width in blocks. Currently the parameter is ignored and 1 is assumed.
+ @param a_BoundingBoxHeight the character's boundingbox width in blocks. Currently the parameter is ignored and 2 is assumed. */
cPath(
cChunk & a_Chunk,
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
+ double a_BoundingBoxWidth, double a_BoundingBoxHeight
);
- /** Creates a dummy path which does nothing except returning false when isValid is called. */
+ /** Creates an invalid path which is not usable. You shouldn't call any method other than isValid on such a path. */
cPath();
/** delete default constructors */
@@ -84,9 +93,11 @@ public:
cPath & operator=(cPath && a_other) = delete;
/** Performs part of the path calculation and returns the appropriate status.
+ If PATH_FOUND is returned, the path was found, and you can call query the instance for waypoints via GetNextWayPoint, etc.
If NEARBY_FOUND is returned, it means that the destination is not reachable, but a nearby destination
is reachable. If the user likes the alternative destination, they can call AcceptNearbyPath to treat the path as found,
- and to make consequent calls to step return PATH_FOUND */
+ and to make consequent calls to step return PATH_FOUND
+ If PATH_NOT_FOUND is returned, then no path was found. */
ePathFinderStatus CalculationStep(cChunk & a_Chunk);
/** Called after the PathFinder's step returns NEARBY_FOUND.
@@ -142,7 +153,6 @@ public:
private:
/* General */
- bool IsSolid(const Vector3i & a_Location); // Query our hosting world and ask it if there's a solid at a_location.
bool StepOnce(); // The public version just calls this version * CALCULATIONS_PER_CALL times.
void FinishCalculation(); // Clears the memory used for calculating the path.
void FinishCalculation(ePathFinderStatus a_NewStatus); // Clears the memory used for calculating the path and changes the status.
@@ -152,7 +162,7 @@ private:
/* Openlist and closedlist management */
void OpenListAdd(cPathCell * a_Cell);
cPathCell * OpenListPop();
- bool ProcessIfWalkable(const Vector3i &a_Location, cPathCell * a_Parent, int a_Cost);
+ bool ProcessIfWalkable(const Vector3i & a_Location, cPathCell * a_Source, int a_Cost);
/* Map management */
void ProcessCell(cPathCell * a_Cell, cPathCell * a_Caller, int a_GDelta);
@@ -179,12 +189,15 @@ private:
std::vector<Vector3i> m_PathPoints;
/* Interfacing with the world */
+ void FillCellAttributes(cPathCell & a_Cell); // Query our hosting world and fill the cell with info
cChunk * m_Chunk; // Only valid inside Step()!
bool m_BadChunkFound;
/* High level world queries */
- bool IsWalkable(const Vector3i & a_Location);
- bool BodyFitsIn(const Vector3i & a_Location);
+ bool IsWalkable(const Vector3i & a_Location, const Vector3i & a_Source);
+ bool BodyFitsIn(const Vector3i & a_Location, const Vector3i & a_Source);
+ bool BlockTypeIsSpecial(BLOCKTYPE a_Type);
+ bool SpecialIsSolidFromThisDirection(BLOCKTYPE a_Type, NIBBLETYPE a_Meta, const Vector3i & a_Direction);
bool HasSolidBelow(const Vector3i & a_Location);
#ifdef COMPILING_PATHFIND_DEBUGGER
#include "../path_irrlicht.cpp"
diff --git a/src/Mobs/PathFinder.cpp b/src/Mobs/PathFinder.cpp
index bc79e2440..4b6e70bbd 100644
--- a/src/Mobs/PathFinder.cpp
+++ b/src/Mobs/PathFinder.cpp
@@ -32,12 +32,20 @@ ePathFinderStatus cPathFinder::GetNextWayPoint(cChunk & a_Chunk, const Vector3d
}
// Tweak the destination. If something is wrong with the destination or the chunk, rest for a while.
- if (!EnsureProperDestination(a_Chunk))
+ if (!(EnsureProperPoint(m_FinalDestination, a_Chunk) && EnsureProperPoint(m_Source, a_Chunk)))
{
m_NotFoundCooldown = 20;
return ePathFinderStatus::PATH_NOT_FOUND;
}
+ /* printf("%d %d %d -> %d %d %d\n",
+ static_cast<int>(m_Source.x),
+ static_cast<int>(m_Source.y),
+ static_cast<int>(m_Source.z),
+ static_cast<int>(m_FinalDestination.x),
+ static_cast<int>(m_FinalDestination.y),
+ static_cast<int>(m_FinalDestination.z)); */
+
// Rest is over. Prepare m_Path by calling ResetPathFinding.
if (m_NotFoundCooldown == 0)
{
@@ -83,7 +91,25 @@ ePathFinderStatus cPathFinder::GetNextWayPoint(cChunk & a_Chunk, const Vector3d
{
m_GiveUpCounter -= 1;
- if ((m_GiveUpCounter == 0) || PathIsTooOld())
+ if (m_GiveUpCounter == 0)
+ {
+ if (a_DontCare)
+ {
+ // We're having trouble reaching the next waypoint but the mob
+ // Doesn't care where to go, just tell him we got there ;)
+ m_FinalDestination = m_Source;
+ *a_Destination = m_FinalDestination;
+ ResetPathFinding(a_Chunk);
+ return ePathFinderStatus::CALCULATING;
+ }
+ else
+ {
+ ResetPathFinding(a_Chunk);
+ return ePathFinderStatus::CALCULATING;
+ }
+ }
+
+ if (PathIsTooOld())
{
ResetPathFinding(a_Chunk);
return ePathFinderStatus::CALCULATING;
@@ -153,9 +179,9 @@ void cPathFinder::ResetPathFinding(cChunk &a_Chunk)
-bool cPathFinder::EnsureProperDestination(cChunk & a_Chunk)
+bool cPathFinder::EnsureProperPoint(Vector3d & a_Vector, cChunk & a_Chunk)
{
- cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(m_FinalDestination.x), FloorC(m_FinalDestination.z));
+ cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(a_Vector.x), FloorC(a_Vector.z));
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
@@ -164,14 +190,14 @@ bool cPathFinder::EnsureProperDestination(cChunk & a_Chunk)
return false;
}
- int RelX = FloorC(m_FinalDestination.x) - Chunk->GetPosX() * cChunkDef::Width;
- int RelZ = FloorC(m_FinalDestination.z) - Chunk->GetPosZ() * cChunkDef::Width;
+ int RelX = FloorC(a_Vector.x) - Chunk->GetPosX() * cChunkDef::Width;
+ int RelZ = FloorC(a_Vector.z) - Chunk->GetPosZ() * cChunkDef::Width;
// If destination in the air, first try to go 1 block north, or east, or west.
// This fixes the player leaning issue.
// If that failed, we instead go down to the lowest air block.
- Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
- if (!cBlockInfo::IsSolid(BlockType))
+ Chunk->GetBlockTypeMeta(RelX, FloorC(a_Vector.y) - 1, RelZ, BlockType, BlockMeta);
+ if (!(IsWaterOrSolid(BlockType)))
{
bool InTheAir = true;
int x, z;
@@ -183,18 +209,18 @@ bool cPathFinder::EnsureProperDestination(cChunk & a_Chunk)
{
continue;
}
- Chunk = a_Chunk.GetNeighborChunk(FloorC(m_FinalDestination.x+x), FloorC(m_FinalDestination.z+z));
+ Chunk = a_Chunk.GetNeighborChunk(FloorC(a_Vector.x+x), FloorC(a_Vector.z+z));
if ((Chunk == nullptr) || !Chunk->IsValid())
{
return false;
}
- RelX = FloorC(m_FinalDestination.x+x) - Chunk->GetPosX() * cChunkDef::Width;
- RelZ = FloorC(m_FinalDestination.z+z) - Chunk->GetPosZ() * cChunkDef::Width;
- Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
- if (cBlockInfo::IsSolid(BlockType))
+ RelX = FloorC(a_Vector.x+x) - Chunk->GetPosX() * cChunkDef::Width;
+ RelZ = FloorC(a_Vector.z+z) - Chunk->GetPosZ() * cChunkDef::Width;
+ Chunk->GetBlockTypeMeta(RelX, FloorC(a_Vector.y) - 1, RelZ, BlockType, BlockMeta);
+ if (IsWaterOrSolid((BlockType)))
{
- m_FinalDestination.x += x;
- m_FinalDestination.z += z;
+ a_Vector.x += x;
+ a_Vector.z += z;
InTheAir = false;
goto breakBothLoops;
}
@@ -205,43 +231,28 @@ bool cPathFinder::EnsureProperDestination(cChunk & a_Chunk)
// Go down to the lowest air block.
if (InTheAir)
{
- while (m_FinalDestination.y > 0)
+ while (a_Vector.y > 0)
{
- Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
- if (cBlockInfo::IsSolid(BlockType))
+ Chunk->GetBlockTypeMeta(RelX, FloorC(a_Vector.y) - 1, RelZ, BlockType, BlockMeta);
+ if (IsWaterOrSolid(BlockType))
{
break;
}
- m_FinalDestination.y -= 1;
+ a_Vector.y -= 1;
}
}
}
- // If destination in water, go up to the highest water block.
- // If destination in solid, go up to first air block.
- bool InWater = false;
- while (m_FinalDestination.y < cChunkDef::Height)
+ // If destination in water or solid, go up to the first air block.
+ while (a_Vector.y < cChunkDef::Height)
{
- Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y), RelZ, BlockType, BlockMeta);
- if (BlockType == E_BLOCK_STATIONARY_WATER)
- {
- InWater = true;
- }
- else if (cBlockInfo::IsSolid(BlockType))
- {
- InWater = false;
- }
- else
+ Chunk->GetBlockTypeMeta(RelX, FloorC(a_Vector.y), RelZ, BlockType, BlockMeta);
+ if (!IsWaterOrSolid(BlockType))
{
break;
}
- m_FinalDestination.y += 1;
+ a_Vector.y += 1;
}
- if (InWater)
- {
- m_FinalDestination.y -= 1;
- }
-
return true;
}
@@ -250,6 +261,15 @@ bool cPathFinder::EnsureProperDestination(cChunk & a_Chunk)
+bool cPathFinder::IsWaterOrSolid(BLOCKTYPE a_BlockType)
+{
+ return ((a_BlockType == E_BLOCK_STATIONARY_WATER) || cBlockInfo::IsSolid(a_BlockType));
+}
+
+
+
+
+
bool cPathFinder::PathIsTooOld() const
{
size_t acceptableDeviation = m_Path->WayPointsLeft() / 2;
diff --git a/src/Mobs/PathFinder.h b/src/Mobs/PathFinder.h
index 312bb950c..1bdc13a32 100644
--- a/src/Mobs/PathFinder.h
+++ b/src/Mobs/PathFinder.h
@@ -3,16 +3,11 @@
#include "Path.h"
#define WAYPOINT_RADIUS 0.5
-/*
-TODO DOXY style
-This class wraps cPath.
+/** This class wraps cPath.
cPath is a "dumb device" - You give it point A and point B, and it returns a full path path.
cPathFinder - You give it a constant stream of point A (where you are) and point B (where you want to go),
-and it tells you where to go next. It manages path recalculation internally, and is much more efficient that calling cPath every step.
-
-*/
-
+and it tells you where to go next. It manages path recalculation internally, and is much more efficient that calling cPath every step. */
class cPathFinder
{
@@ -80,17 +75,18 @@ private:
/** When a path is not found, this cooldown prevents any recalculations for several ticks. */
int m_NotFoundCooldown;
- /** Ensures the destination is not buried underground or under water. Also ensures the destination is not in the air.
- Only the Y coordinate of m_FinalDestination might be changed by this call.
- 1. If m_FinalDestination is the position of a water block, m_FinalDestination's Y will be modified to point to the heighest water block in the pool in the current column.
- 2. If m_FinalDestination is the position of a solid, m_FinalDestination's Y will be modified to point to the first airblock above the solid in the current column.
- 3. If m_FinalDestination is the position of an air block, Y will keep decreasing until hitting either a solid or water.
- Now either 1 or 2 is performed. */
- bool EnsureProperDestination(cChunk & a_Chunk);
+ /** Ensures the location is not in the air or under water.
+ May change the Y coordinate of the given vector.
+ 1. If a_Vector is the position of water, a_Vector's Y will be modified to point to the first air block above it.
+ 2. If a_Vector is the position of air, a_Vector's Y will be modified to point to the first airblock below it which has solid or water beneath. */
+ bool EnsureProperPoint(Vector3d & a_Vector, cChunk & a_Chunk);
/** Resets a pathfinding task, typically because m_FinalDestination has deviated too much from m_DeviationOrigin. */
void ResetPathFinding(cChunk &a_Chunk);
+ /** Return true the the blocktype is either water or solid */
+ bool IsWaterOrSolid(BLOCKTYPE a_BlockType);
+
/** Is the path too old and should be recalculated? When this is true ResetPathFinding() is called. */
bool PathIsTooOld() const;
};
diff --git a/src/Noise/CMakeLists.txt b/src/Noise/CMakeLists.txt
index 39f3bc975..4e99347f8 100644
--- a/src/Noise/CMakeLists.txt
+++ b/src/Noise/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt
index ce1d5c530..ee8067c6f 100644
--- a/src/OSSupport/CMakeLists.txt
+++ b/src/OSSupport/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/PolarSSL++/BlockingSslClientSocket.cpp b/src/PolarSSL++/BlockingSslClientSocket.cpp
index e789b5374..61aee211d 100644
--- a/src/PolarSSL++/BlockingSslClientSocket.cpp
+++ b/src/PolarSSL++/BlockingSslClientSocket.cpp
@@ -70,7 +70,9 @@ class cBlockingSslClientSocketLinkCallbacks:
{
m_Socket.OnDisconnected();
}
+
public:
+
cBlockingSslClientSocketLinkCallbacks(cBlockingSslClientSocket & a_Socket):
m_Socket(a_Socket)
{
@@ -143,7 +145,6 @@ bool cBlockingSslClientSocket::Connect(const AString & a_ServerName, UInt16 a_Po
return false;
}
- m_IsConnected = true;
return true;
}
@@ -182,7 +183,11 @@ bool cBlockingSslClientSocket::SetTrustedRootCertsFromString(const AString & a_C
bool cBlockingSslClientSocket::Send(const void * a_Data, size_t a_NumBytes)
{
- ASSERT(m_IsConnected);
+ if (!m_IsConnected)
+ {
+ m_LastErrorText = "Socket is closed";
+ return false;
+ }
// Keep sending the data until all of it is sent:
const char * Data = reinterpret_cast<const char *>(a_Data);
@@ -216,8 +221,7 @@ bool cBlockingSslClientSocket::Send(const void * a_Data, size_t a_NumBytes)
int cBlockingSslClientSocket::Receive(void * a_Data, size_t a_MaxBytes)
{
- ASSERT(m_IsConnected);
-
+ // Even if m_IsConnected is false (socket disconnected), the SSL context may have more data in the queue
int res = m_Ssl.ReadPlain(a_Data, a_MaxBytes);
if (res < 0)
{
@@ -239,9 +243,16 @@ void cBlockingSslClientSocket::Disconnect(void)
}
m_Ssl.NotifyClose();
- m_Socket->Close();
- m_Socket.reset();
m_IsConnected = false;
+
+ // Grab a copy of the socket so that we know it doesn't change under our hands:
+ auto socket = m_Socket;
+ if (socket != nullptr)
+ {
+ socket->Close();
+ }
+
+ m_Socket.reset();
}
@@ -293,6 +304,7 @@ int cBlockingSslClientSocket::SendEncrypted(const unsigned char * a_Buffer, size
+
void cBlockingSslClientSocket::OnConnected(void)
{
m_IsConnected = true;
@@ -305,7 +317,7 @@ void cBlockingSslClientSocket::OnConnected(void)
void cBlockingSslClientSocket::OnConnectError(const AString & a_ErrorMsg)
{
- LOG("Cannot connect to %s: %s", m_ServerName.c_str(), a_ErrorMsg.c_str());
+ LOG("Cannot connect to %s: \"%s\"", m_ServerName.c_str(), a_ErrorMsg.c_str());
m_Event.Set();
}
@@ -337,8 +349,8 @@ void cBlockingSslClientSocket::SetLink(cTCPLinkPtr a_Link)
void cBlockingSslClientSocket::OnDisconnected(void)
{
- m_Socket.reset();
m_IsConnected = false;
+ m_Socket.reset();
m_Event.Set();
}
diff --git a/src/PolarSSL++/BlockingSslClientSocket.h b/src/PolarSSL++/BlockingSslClientSocket.h
index 462ee95a7..3c61f7f89 100644
--- a/src/PolarSSL++/BlockingSslClientSocket.h
+++ b/src/PolarSSL++/BlockingSslClientSocket.h
@@ -9,6 +9,7 @@
#pragma once
+#include <atomic>
#include "OSSupport/Network.h"
#include "CallbackSslContext.h"
@@ -81,7 +82,7 @@ protected:
AString m_LastErrorText;
/** Set to true if the connection established successfully. */
- bool m_IsConnected;
+ std::atomic<bool> m_IsConnected;
/** Protects m_IncomingData against multithreaded access. */
cCriticalSection m_CSIncomingData;
diff --git a/src/PolarSSL++/CMakeLists.txt b/src/PolarSSL++/CMakeLists.txt
index fddb37501..3f268ad13 100644
--- a/src/PolarSSL++/CMakeLists.txt
+++ b/src/PolarSSL++/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt
index 58a69efbf..cd4f33c60 100644
--- a/src/Protocol/CMakeLists.txt
+++ b/src/Protocol/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp
index dfbf9a568..0edb9f33e 100644
--- a/src/Protocol/MojangAPI.cpp
+++ b/src/Protocol/MojangAPI.cpp
@@ -748,7 +748,7 @@ void cMojangAPI::QueryNamesToUUIDs(AStringVector & a_NamesToQuery)
Json::Reader reader;
if (!reader.parse(Response, root, false) || !root.isArray())
{
- LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__);
+ LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON: \"%s\"", __FUNCTION__, reader.getFormattedErrorMessages().c_str());
LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
continue;
}
@@ -861,7 +861,7 @@ void cMojangAPI::QueryUUIDToProfile(const AString & a_UUID)
Json::Value root;
if (!reader.parse(Response, root, false) || !root.isObject())
{
- LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__);
+ LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON: \"%s\"", __FUNCTION__, reader.getFormattedErrorMessages().c_str());
LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return;
}
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 010e1a8ba..1c8c81bbd 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -2784,7 +2784,7 @@ void cProtocol172::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_
Writer.AddInt("z", MobHeadEntity.GetPosZ());
Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF);
Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF);
- Writer.AddString("ExtraType", MobHeadEntity.GetOwner().c_str());
+ Writer.AddString("ExtraType", MobHeadEntity.GetOwnerName());
Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
break;
}
diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp
index ad2964bed..c80907ed8 100644
--- a/src/Protocol/Protocol18x.cpp
+++ b/src/Protocol/Protocol18x.cpp
@@ -1834,39 +1834,44 @@ void cProtocol180::AddReceivedData(const char * a_Data, size_t a_Size)
}
// Check packet for compression:
- UInt32 CompressedSize = 0;
+ UInt32 UncompressedSize = 0;
AString UncompressedData;
if (m_State == 3)
{
UInt32 NumBytesRead = static_cast<UInt32>(m_ReceivedData.GetReadableSpace());
- m_ReceivedData.ReadVarInt(CompressedSize);
- if (CompressedSize > PacketLen)
+
+ if (!m_ReceivedData.ReadVarInt(UncompressedSize))
{
- m_Client->Kick("Bad compression");
+ m_Client->Kick("Compression packet incomplete");
return;
}
- if (CompressedSize > 0)
+
+ NumBytesRead -= static_cast<UInt32>(m_ReceivedData.GetReadableSpace()); // How many bytes has the UncompressedSize taken up?
+ ASSERT(PacketLen > NumBytesRead);
+ PacketLen -= NumBytesRead;
+
+ if (UncompressedSize > 0)
{
// Decompress the data:
AString CompressedData;
- if (!m_ReceivedData.ReadString(CompressedData, CompressedSize) || (InflateString(CompressedData.data(), CompressedSize, UncompressedData) != Z_OK))
+ VERIFY(m_ReceivedData.ReadString(CompressedData, PacketLen));
+ if (InflateString(CompressedData.data(), PacketLen, UncompressedData) != Z_OK)
{
m_Client->Kick("Compression failure");
return;
}
PacketLen = static_cast<UInt32>(UncompressedData.size());
- }
- else
- {
- NumBytesRead -= static_cast<UInt32>(m_ReceivedData.GetReadableSpace()); // How many bytes has the CompressedSize taken up?
- ASSERT(PacketLen > NumBytesRead);
- PacketLen -= NumBytesRead;
+ if (PacketLen != UncompressedSize)
+ {
+ m_Client->Kick("Wrong uncompressed packet size given");
+ return;
+ }
}
}
// Move the packet payload to a separate cByteBuffer, bb:
cByteBuffer bb(PacketLen + 1);
- if (CompressedSize == 0)
+ if (UncompressedSize == 0)
{
// No compression was used, move directly
VERIFY(m_ReceivedData.ReadToByteBuffer(bb, static_cast<size_t>(PacketLen)));
@@ -1916,7 +1921,7 @@ void cProtocol180::AddReceivedData(const char * a_Data, size_t a_Size)
bb.ReadAll(Packet);
Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection
AString Out;
- CreateHexDump(Out, Packet.data(), (int)Packet.size(), 24);
+ CreateHexDump(Out, Packet.data(), Packet.size(), 24);
LOGD("Packet contents:\n%s", Out.c_str());
#endif // _DEBUG
@@ -2145,7 +2150,7 @@ void cProtocol180::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
// Decrypt EncNonce using privkey
cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
- Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
+ UInt32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
int res = rsaDecryptor.Decrypt(reinterpret_cast<const Byte *>(EncNonce.data()), EncNonce.size(), reinterpret_cast<Byte *>(DecryptedNonce), sizeof(DecryptedNonce));
if (res != 4)
{
@@ -3104,8 +3109,21 @@ void cProtocol180::WriteBlockEntity(cPacketizer & a_Pkt, const cBlockEntity & a_
Writer.AddInt("z", MobHeadEntity.GetPosZ());
Writer.AddByte("SkullType", MobHeadEntity.GetType() & 0xFF);
Writer.AddByte("Rot", MobHeadEntity.GetRotation() & 0xFF);
- Writer.AddString("ExtraType", MobHeadEntity.GetOwner().c_str());
Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
+
+ // The new Block Entity format for a Mob Head. See: http://minecraft.gamepedia.com/Head#Block_entity
+ Writer.BeginCompound("Owner");
+ Writer.AddString("Id", MobHeadEntity.GetOwnerUUID());
+ Writer.AddString("Name", MobHeadEntity.GetOwnerName());
+ Writer.BeginCompound("Properties");
+ Writer.BeginList("textures", TAG_Compound);
+ Writer.BeginCompound("");
+ Writer.AddString("Signature", MobHeadEntity.GetOwnerTextureSignature());
+ Writer.AddString("Value", MobHeadEntity.GetOwnerTexture());
+ Writer.EndCompound();
+ Writer.EndList();
+ Writer.EndCompound();
+ Writer.EndCompound();
break;
}
diff --git a/src/RankManager.cpp b/src/RankManager.cpp
index cbe9a85aa..922d9768e 100644
--- a/src/RankManager.cpp
+++ b/src/RankManager.cpp
@@ -2248,6 +2248,7 @@ void cRankManager::CreateDefaults(void)
AddGroupToRank("Everything", "Admin");
// Add permissions to groups:
+ AddPermissionToGroup("core.help", "Default");
AddPermissionToGroup("core.build", "Default");
AddPermissionToGroup("core.teleport", "Teleport");
AddPermissionToGroup("core.kick", "Kick");
diff --git a/src/Resources/MCServer.rc b/src/Resources/Cuberite.rc
index e0fbbea5d..779487458 100644
--- a/src/Resources/MCServer.rc
+++ b/src/Resources/Cuberite.rc
@@ -5,7 +5,7 @@
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
-#include "resource_MCServer.h"
+#include "resource_Cuberite.h"
diff --git a/src/Resources/resource_MCServer.h b/src/Resources/resource_Cuberite.h
index 42f6c4eaf..42f6c4eaf 100644
--- a/src/Resources/resource_MCServer.h
+++ b/src/Resources/resource_Cuberite.h
diff --git a/src/Root.cpp b/src/Root.cpp
index 36fd067b3..dc00b5c82 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -752,10 +752,10 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
}
public:
- cCallback (const AString & a_PlayerName) :
+ cCallback (const AString & a_CBPlayerName) :
m_BestRating(0),
- m_NameLength(a_PlayerName.length()),
- m_PlayerName(a_PlayerName),
+ m_NameLength(a_CBPlayerName.length()),
+ m_PlayerName(a_CBPlayerName),
m_BestMatch(),
m_NumMatches(0)
{}
diff --git a/src/Simulator/CMakeLists.txt b/src/Simulator/CMakeLists.txt
index a798e4b02..98b4499c7 100644
--- a/src/Simulator/CMakeLists.txt
+++ b/src/Simulator/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt b/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt
index e37f3595c..87052d00a 100644
--- a/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt
+++ b/src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp
index 95329f496..3c79d152b 100644
--- a/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp
+++ b/src/Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.cpp
@@ -159,12 +159,5 @@ void cIncrementalRedstoneSimulator::Simulate(float a_dt)
{
m_Data.GetActiveBlocks().emplace_back(CurrentLocation);
}
-
- #ifdef _DEBUG
- for (const auto & UpdateLocation : Updates)
- {
- LOGD("Queueing block for reupdate (%i %i %i)", UpdateLocation.x, UpdateLocation.y, UpdateLocation.z);
- }
- #endif
}
}
diff --git a/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h b/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h
index e196f51a1..e9543bb02 100644
--- a/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h
+++ b/src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h
@@ -35,7 +35,8 @@ public:
const cVector3iArray GetTerracingConnectionOffsets(const Vector3i & a_Position)
{
cVector3iArray RelativePositions;
- bool IsYPTerracingBlocked = cBlockInfo::IsSolid(m_World.GetBlock(a_Position + OffsetYP()));
+ auto YPTerraceBlock = m_World.GetBlock(a_Position + OffsetYP());
+ bool IsYPTerracingBlocked = cBlockInfo::IsSolid(YPTerraceBlock) && !cBlockInfo::IsTransparent(YPTerraceBlock);
for (const auto & Adjacent : GetRelativeLaterals())
{
@@ -46,9 +47,10 @@ public:
{
RelativePositions.emplace_back(Adjacent + OffsetYP());
}
-
+ auto YMTerraceBlock = m_World.GetBlock(a_Position + Adjacent);
if (
- !cBlockInfo::IsSolid(m_World.GetBlock(a_Position + Adjacent)) && // IsYMTerracingBlocked (i.e. check block above lower terracing position, a.k.a. just the plain adjacent)
+ // IsYMTerracingBlocked (i.e. check block above lower terracing position, a.k.a. just the plain adjacent)
+ (!cBlockInfo::IsSolid(YMTerraceBlock) || cBlockInfo::IsTransparent(YMTerraceBlock)) &&
(m_World.GetBlock(a_Position + Adjacent + OffsetYM()) == E_BLOCK_REDSTONE_WIRE)
)
{
diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt
index ad3c00f5f..6753c453e 100644
--- a/src/UI/CMakeLists.txt
+++ b/src/UI/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/World.cpp b/src/World.cpp
index 904f5421b..7ac5af972 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -829,7 +829,7 @@ void cWorld::InitialiseGeneratorDefaults(cIniFile & a_IniFile)
a_IniFile.GetValueSet("Generator", "HeightGen", "Flat");
a_IniFile.GetValueSet("Generator", "FlatHeight", "128");
a_IniFile.GetValueSet("Generator", "CompositionGen", "Nether");
- a_IniFile.GetValueSet("Generator", "Finishers", "SoulsandRims, WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherOreNests, PieceStructures: NetherForts, GlowStone, PreSimulator");
+ a_IniFile.GetValueSet("Generator", "Finishers", "SoulsandRims, WormNestCaves, BottomLava, LavaSprings, NetherClumpFoliage, NetherOreNests, PieceStructures: NetherFort, GlowStone, PreSimulator");
a_IniFile.GetValueSet("Generator", "BottomLavaHeight", "30");
break;
}
diff --git a/src/WorldStorage/CMakeLists.txt b/src/WorldStorage/CMakeLists.txt
index 2192564e8..1d8b60140 100644
--- a/src/WorldStorage/CMakeLists.txt
+++ b/src/WorldStorage/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 2.6)
-project (MCServer)
+project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index b0451e427..3a0823491 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -358,7 +358,20 @@ void cNBTChunkSerializer::AddMobHeadEntity(cMobHeadEntity * a_MobHead)
AddBasicTileEntity(a_MobHead, "Skull");
m_Writer.AddByte ("SkullType", a_MobHead->GetType() & 0xFF);
m_Writer.AddByte ("Rot", a_MobHead->GetRotation() & 0xFF);
- m_Writer.AddString("ExtraType", a_MobHead->GetOwner());
+
+ // The new Block Entity format for a Mob Head. See: http://minecraft.gamepedia.com/Head#Block_entity
+ m_Writer.BeginCompound("Owner");
+ m_Writer.AddString("Id", a_MobHead->GetOwnerUUID());
+ m_Writer.AddString("Name", a_MobHead->GetOwnerName());
+ m_Writer.BeginCompound("Properties");
+ m_Writer.BeginList("textures", TAG_Compound);
+ m_Writer.BeginCompound("");
+ m_Writer.AddString("Signature", a_MobHead->GetOwnerTextureSignature());
+ m_Writer.AddString("Value", a_MobHead->GetOwnerTexture());
+ m_Writer.EndCompound();
+ m_Writer.EndList();
+ m_Writer.EndCompound();
+ m_Writer.EndCompound();
m_Writer.EndCompound();
}
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 5138717a7..3d325d354 100755
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -1293,10 +1293,47 @@ cBlockEntity * cWSSAnvil::LoadMobHeadFromNBT(const cParsedNBT & a_NBT, int a_Tag
MobHead->SetRotation(static_cast<eMobHeadRotation>(a_NBT.GetByte(currentLine)));
}
- currentLine = a_NBT.FindChildByName(a_TagIdx, "ExtraType");
- if (currentLine >= 0)
+ int ownerLine = a_NBT.FindChildByName(a_TagIdx, "Owner");
+ if (ownerLine >= 0)
{
- MobHead->SetOwner(a_NBT.GetString(currentLine));
+ AString OwnerName, OwnerUUID, OwnerTexture, OwnerTextureSignature;
+
+ currentLine = a_NBT.FindChildByName(ownerLine, "Id");
+ if (currentLine >= 0)
+ {
+ OwnerUUID = a_NBT.GetString(currentLine);
+ }
+
+ currentLine = a_NBT.FindChildByName(ownerLine, "Name");
+ if (currentLine >= 0)
+ {
+ OwnerName = a_NBT.GetString(currentLine);
+ }
+
+ int textureLine = a_NBT.GetFirstChild( // The first texture of
+ a_NBT.FindChildByName( // The texture list of
+ a_NBT.FindChildByName( // The Properties compound of
+ ownerLine, // The Owner compound
+ "Properties"
+ ),
+ "textures"
+ )
+ );
+ if (textureLine >= 0)
+ {
+ currentLine = a_NBT.FindChildByName(textureLine, "Signature");
+ if (currentLine >= 0)
+ {
+ OwnerTextureSignature = a_NBT.GetString(currentLine);
+ }
+
+ currentLine = a_NBT.FindChildByName(textureLine, "Value");
+ if (currentLine >= 0)
+ {
+ OwnerTexture = a_NBT.GetString(currentLine);
+ }
+ }
+ MobHead->SetOwner(OwnerUUID, OwnerName, OwnerTexture, OwnerTextureSignature);
}
return MobHead.release();
diff --git a/src/main.cpp b/src/main.cpp
index aa21d8a31..06f979097 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -20,6 +20,15 @@
+
+// Forward declarations to satisfy Clang's -Wmissing-variable-declarations:
+extern bool g_ShouldLogCommIn;
+extern bool g_ShouldLogCommOut;
+
+
+
+
+
/** If something has told the server to stop; checked periodically in cRoot */
bool cRoot::m_TerminateEventRaised = false;
@@ -67,7 +76,8 @@ Synchronize this with Server.cpp to enable the "dumpmem" console command. */
-void NonCtrlHandler(int a_Signal)
+#ifndef _DEBUG
+static void NonCtrlHandler(int a_Signal)
{
LOGD("Terminate event raised from std::signal");
cRoot::Get()->QueueExecuteConsoleCommand("stop");
@@ -110,6 +120,7 @@ void NonCtrlHandler(int a_Signal)
default: break;
}
}
+#endif // _DEBUG
@@ -129,11 +140,11 @@ typedef BOOL (WINAPI *pMiniDumpWriteDump)(
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
-pMiniDumpWriteDump g_WriteMiniDump; // The function in dbghlp DLL that creates dump files
+static pMiniDumpWriteDump g_WriteMiniDump; // The function in dbghlp DLL that creates dump files
-wchar_t g_DumpFileName[MAX_PATH]; // Filename of the dump file; hes to be created before the dump handler kicks in
-char g_ExceptionStack[128 * 1024]; // Substitute stack, just in case the handler kicks in because of "insufficient stack space"
-MINIDUMP_TYPE g_DumpFlags = MiniDumpNormal; // By default dump only the stack and some helpers
+static wchar_t g_DumpFileName[MAX_PATH]; // Filename of the dump file; hes to be created before the dump handler kicks in
+static char g_ExceptionStack[128 * 1024]; // Substitute stack, just in case the handler kicks in because of "insufficient stack space"
+static MINIDUMP_TYPE g_DumpFlags = MiniDumpNormal; // By default dump only the stack and some helpers
@@ -142,7 +153,7 @@ MINIDUMP_TYPE g_DumpFlags = MiniDumpNormal; // By default dump only the stack a
/** This function gets called just before the "program executed an illegal instruction and will be terminated" or similar.
Its purpose is to create the crashdump using the dbghlp DLLs
*/
-LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_ExceptionInfo)
+static LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_ExceptionInfo)
{
char * newStack = &g_ExceptionStack[sizeof(g_ExceptionStack) - 1];
char * oldStack;
@@ -185,7 +196,7 @@ LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_Except
#ifdef _WIN32
// Handle CTRL events in windows, including console window close
-BOOL CtrlHandler(DWORD fdwCtrlType)
+static BOOL CtrlHandler(DWORD fdwCtrlType)
{
cRoot::Get()->QueueExecuteConsoleCommand("stop");
LOGD("Terminate event raised from the Windows CtrlHandler");
@@ -204,7 +215,7 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
////////////////////////////////////////////////////////////////////////////////
// UniversalMain - Main startup logic for both standard running and as a service
-void UniversalMain(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo)
+static void UniversalMain(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo)
{
// Initialize logging subsystem:
cLogger::InitiateMultithreading();
@@ -242,7 +253,7 @@ void UniversalMain(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo
////////////////////////////////////////////////////////////////////////////////
// serviceWorkerThread: Keep the service alive
-DWORD WINAPI serviceWorkerThread(LPVOID lpParam)
+static DWORD WINAPI serviceWorkerThread(LPVOID lpParam)
{
UNREFERENCED_PARAMETER(lpParam);
@@ -262,7 +273,7 @@ DWORD WINAPI serviceWorkerThread(LPVOID lpParam)
////////////////////////////////////////////////////////////////////////////////
// serviceSetState: Set the internal status of the service
-void serviceSetState(DWORD acceptedControls, DWORD newState, DWORD exitCode)
+static void serviceSetState(DWORD acceptedControls, DWORD newState, DWORD exitCode)
{
SERVICE_STATUS serviceStatus = {};
serviceStatus.dwCheckPoint = 0;
@@ -285,7 +296,7 @@ void serviceSetState(DWORD acceptedControls, DWORD newState, DWORD exitCode)
////////////////////////////////////////////////////////////////////////////////
// serviceCtrlHandler: Handle stop events from the Service Control Manager
-void WINAPI serviceCtrlHandler(DWORD CtrlCode)
+static void WINAPI serviceCtrlHandler(DWORD CtrlCode)
{
switch (CtrlCode)
{
@@ -308,7 +319,7 @@ void WINAPI serviceCtrlHandler(DWORD CtrlCode)
////////////////////////////////////////////////////////////////////////////////
// serviceMain: Startup logic for running as a service
-void WINAPI serviceMain(DWORD argc, TCHAR *argv[])
+static void WINAPI serviceMain(DWORD argc, TCHAR *argv[])
{
wchar_t applicationFilename[MAX_PATH];
wchar_t applicationDirectory[MAX_PATH];
@@ -353,7 +364,7 @@ void WINAPI serviceMain(DWORD argc, TCHAR *argv[])
-std::unique_ptr<cMemorySettingsRepository> ParseArguments(int argc, char **argv)
+static std::unique_ptr<cMemorySettingsRepository> ParseArguments(int argc, char ** argv)
{
try
{
@@ -434,7 +445,7 @@ std::unique_ptr<cMemorySettingsRepository> ParseArguments(int argc, char **argv)
////////////////////////////////////////////////////////////////////////////////
// main:
-int main(int argc, char **argv)
+int main(int argc, char ** argv)
{
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
InitLeakFinder();