summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortycho <work.tycho@gmail.com>2015-05-28 12:05:41 +0200
committertycho <work.tycho@gmail.com>2015-05-28 12:05:41 +0200
commite19693e529bf26e62a54f60c167d1b4870d7d44a (patch)
tree0b2cb131fa2f009723dd0ecd739ff911a369c763
parentFix warnings in cPath (diff)
parentMerge pull request #2151 from SafwatHalaby/wolf (diff)
downloadcuberite-e19693e529bf26e62a54f60c167d1b4870d7d44a.tar
cuberite-e19693e529bf26e62a54f60c167d1b4870d7d44a.tar.gz
cuberite-e19693e529bf26e62a54f60c167d1b4870d7d44a.tar.bz2
cuberite-e19693e529bf26e62a54f60c167d1b4870d7d44a.tar.lz
cuberite-e19693e529bf26e62a54f60c167d1b4870d7d44a.tar.xz
cuberite-e19693e529bf26e62a54f60c167d1b4870d7d44a.tar.zst
cuberite-e19693e529bf26e62a54f60c167d1b4870d7d44a.zip
-rw-r--r--CONTRIBUTORS1
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua61
-rw-r--r--MCServer/crafting.txt2
-rw-r--r--SetFlags.cmake5
-rw-r--r--lib/sqlite/CMakeLists.txt2
-rw-r--r--lib/tolua++/CMakeLists.txt4
-rw-r--r--src/Bindings/PluginManager.cpp2
-rw-r--r--src/CMakeLists.txt5
-rw-r--r--src/ClientHandle.cpp74
-rw-r--r--src/ClientHandle.h7
-rw-r--r--src/Entities/Pickup.cpp1
-rw-r--r--src/Inventory.cpp31
-rw-r--r--src/Inventory.h10
-rw-r--r--src/Items/ItemBucket.h4
-rw-r--r--src/Items/ItemEmptyMap.h2
-rw-r--r--src/Items/ItemMushroomSoup.h2
-rw-r--r--src/Mobs/Monster.cpp13
-rw-r--r--src/Mobs/Wolf.cpp3
-rw-r--r--src/OSSupport/Errors.cpp2
-rw-r--r--src/Protocol/Protocol.h7
-rw-r--r--src/Protocol/Protocol17x.cpp63
-rw-r--r--src/Protocol/Protocol17x.h7
-rw-r--r--src/Protocol/Protocol18x.cpp86
-rw-r--r--src/Protocol/Protocol18x.h7
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp70
-rw-r--r--src/Protocol/ProtocolRecognizer.h7
-rw-r--r--src/Root.cpp32
-rw-r--r--src/Root.h69
-rw-r--r--src/UI/SlotArea.cpp8
-rw-r--r--src/UI/Window.cpp14
30 files changed, 483 insertions, 118 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 1e73fb699..4a6850a2f 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -18,6 +18,7 @@ Masy98
mborland
mgueydan
MikeHunsinger
+missingchar (mathias-github)
mtilden
nesco
p-mcgowan
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 2c26ccecc..4af01c0a4 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -29,7 +29,7 @@ g_APIDesc =
{
ConstantName = { Notes = "Notes about the constant" },
} ,
-
+
ConstantGroups =
{
GroupName1 = -- GroupName1 is used as the HTML anchor name
@@ -270,7 +270,7 @@ g_APIDesc =
<h3>Special strategies</h3>
<p>For each strategy, evaluate the table rows from top downwards, the first match wins.</p>
-
+
<p>
<strong>msDifference</strong> - changes all the blocks which are the same to air. Otherwise the source block gets placed.
</p>
@@ -282,8 +282,8 @@ g_APIDesc =
<td> B </td><td> B </td><td> Air </td><td> The blocks are the same so we get air. </td>
</tr>
</tbody></table>
-
-
+
+
<p>
<strong>msLake</strong> - used for merging areas with lava and water lakes, in the appropriate generator.
</p>
@@ -363,7 +363,7 @@ g_APIDesc =
<td> A </td><td> non-A </td><td> A </td><td> Differing blocks are kept from 'self' </td>
</tr>
</tbody></table>
-
+
<p>
<strong>msSimpleCompare</strong> - the blocks that are the same in both areas are replaced with air, all the
differing blocks are replaced with stone. Meta is used in the comparison, too, two blocks of the
@@ -535,7 +535,7 @@ g_APIDesc =
function OnChunkGenerated(a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc)
-- Get the topmost block coord:
local Height = a_ChunkDesc:GetHeight(0, 0);
-
+
-- Create a sign there:
a_ChunkDesc:SetBlockTypeMeta(0, Height + 1, 0, E_BLOCK_SIGN_POST, 0);
local BlockEntity = a_ChunkDesc:GetBlockEntity(0, Height + 1, 0);
@@ -666,7 +666,7 @@ end</pre>
},
}, -- AdditionalInfo
}, -- cCompositeChat
-
+
cCraftingGrid =
{
Desc = [[
@@ -738,7 +738,7 @@ local Hash = cCryptoHash.sha1HexString("DataToHash")
</pre></p>
<p>Each cryptographic hash has two variants, one returns the hash as a raw binary string, the other returns the hash as a hex-encoded string twice as long as the binary string.
]],
-
+
Functions =
{
md5 = { Params = "Data", Return = "string", Notes = "(STATIC) Calculates the md5 hash of the data, returns it as a raw (binary) string of 16 characters." },
@@ -747,7 +747,7 @@ local Hash = cCryptoHash.sha1HexString("DataToHash")
sha1HexString = { Params = "Data", Return = "string", Notes = "(STATIC) Calculates the sha1 hash of the data, returns it as a hex-encoded string of 40 characters." },
},
}, -- cCryptoHash
-
+
cEnchantments =
{
Desc = [[
@@ -1038,7 +1038,7 @@ cFile:Delete("/usr/bin/virus.exe");
},
Inherits = "cEntity",
},
-
+
cIniFile =
{
Desc = [[
@@ -1073,7 +1073,7 @@ ValueName0=SomeOtherValue
{
constructor = { Params = "", Return = "cIniFile", Notes = "Creates a new empty cIniFile object." },
AddHeaderComment = { Params = "Comment", Return = "", Notes = "Adds a comment to be stored in the file header." },
- AddKeyComment =
+ AddKeyComment =
{
{ Params = "KeyID, Comment", Return = "", Notes = "Adds a comment to be stored in the file under the specified key" },
{ Params = "KeyName, Comment", Return = "", Notes = "Adds a comment to be stored in the file under the specified key" },
@@ -1117,12 +1117,12 @@ ValueName0=SomeOtherValue
{ Params = "KeyName", Return = "number", Notes = "Returns the number of comments under the specified key" },
},
GetNumKeys = { Params = "", Return = "number", Notes = "Returns the total number of keys. This is the range for the KeyID (0 .. GetNumKeys() - 1)" },
- GetNumValues =
+ GetNumValues =
{
{ Params = "KeyID", Return = "number", Notes = "Returns the number of values stored under the specified key." },
{ Params = "KeyName", Return = "number", Notes = "Returns the number of values stored under the specified key." },
},
- GetValue =
+ GetValue =
{
{ Params = "KeyName, ValueName", Return = "string", Notes = "Returns the value of the specified name under the specified key. Returns an empty string if the value doesn't exist." },
{ Params = "KeyID, ValueID", Return = "string", Notes = "Returns the value of the specified name under the specified key. Returns an empty string if the value doesn't exist." },
@@ -1130,7 +1130,7 @@ ValueName0=SomeOtherValue
GetValueB = { Params = "KeyName, ValueName", Return = "bool", Notes = "Returns the value of the specified name under the specified key, as a bool. Returns false if the value doesn't exist." },
GetValueF = { Params = "KeyName, ValueName", Return = "number", Notes = "Returns the value of the specified name under the specified key, as a floating-point number. Returns zero if the value doesn't exist." },
GetValueI = { Params = "KeyName, ValueName", Return = "number", Notes = "Returns the value of the specified name under the specified key, as an integer. Returns zero if the value doesn't exist." },
- GetValueName =
+ GetValueName =
{
{ Params = "KeyID, ValueID", Return = "string", Notes = "Returns the name of the specified value Inverse for FindValue()." },
{ Params = "KeyName, ValueID", Return = "string", Notes = "Returns the name of the specified value Inverse for FindValue()." },
@@ -1141,7 +1141,7 @@ ValueName0=SomeOtherValue
GetValueSetI = { Params = "KeyName, ValueName, Default", Return = "number", Notes = "Returns the value of the specified name under the specified key, as an integer. If the value doesn't exist, creates it with the specified default." },
HasValue = { Params = "KeyName, ValueName", Return = "bool", Notes = "Returns true if the specified value is present." },
ReadFile = { Params = "FileName, [AllowExampleFallback]", Return = "bool", Notes = "Reads the values from the specified file. Previous in-memory contents are lost. If the file cannot be opened, and AllowExample is true, another file, \"filename.example.ini\", is loaded and then saved as \"filename.ini\". Returns true if successful, false if not." },
- SetValue =
+ SetValue =
{
{ Params = "KeyID, ValueID, NewValue", Return = "bool", Notes = "Overwrites the specified value with a new value. If the specified value doesn't exist, returns false (doesn't add)." },
{ Params = "KeyName, ValueName, NewValue, [CreateIfNotExists]", Return = "bool", Notes = "Overwrites the specified value with a new value. If CreateIfNotExists is true (default) and the value doesn't exist, it is first created. Returns true if the value was successfully set, false if not (didn't exists, CreateIfNotExists false)." },
@@ -2061,6 +2061,7 @@ a_Player:OpenWindow(Window);
GetPrimaryServerVersion = { Params = "", Return = "number", Notes = "Returns the servers primary server version." },
GetProtocolVersionTextFromInt = { Params = "Protocol Version", Return = "string", Notes = "Returns the Minecraft version from the given Protocol. If there is no version found, it returns 'Unknown protocol(Parameter)'" },
GetServer = { Params = "", Return = "{{cServer|cServer}}", Notes = "Returns the cServer object." },
+ GetServerUpTime = { Params = "", Return = "number", Notes = "Returns the uptime of the server in seconds." },
GetTotalChunkCount = { Params = "", Return = "number", Notes = "Returns the amount of loaded chunks." },
GetVirtualRAMUsage = { Params = "", Return = "number", Notes = "Returns the amount of virtual RAM that the entire MCServer process is using, in KiB. Negative if the OS doesn't support this query." },
GetWebAdmin = { Params = "", Return = "{{cWebAdmin|cWebAdmin}}", Notes = "Returns the cWebAdmin object." },
@@ -2146,7 +2147,7 @@ end
ShouldAuthenticate = { Params = "", Return = "bool", Notes = "Returns true iff the server is set to authenticate players (\"online mode\")." },
},
}, -- cServer
-
+
cStringCompression =
{
Desc = [[
@@ -2157,7 +2158,7 @@ end
local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
</pre>
]],
-
+
Functions =
{
CompressStringGZIP = {Params = "string", Return = "string", Notes = "Compress a string using GZIP"},
@@ -2205,7 +2206,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
},
Inherits = "cEntity",
},
-
+
cWebPlugin =
{
Desc = "",
@@ -2361,7 +2362,7 @@ local CompressedString = cStringCompression.CompressStringGZIP("DataToCompress")
GetGeneratorQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks that are queued in the chunk generator." },
GetHeight = { Params = "BlockX, BlockZ", Return = "number", Notes = "Returns the maximum height of the particula block column in the world. If the chunk is not loaded, it waits for it to load / generate. <b>WARNING</b>: Do not use, Use TryGetHeight() instead for a non-waiting version, otherwise you run the risk of a deadlock!" },
GetIniFileName = { Params = "", Return = "string", Notes = "Returns the name of the world.ini file that the world uses to store the information." },
- GetLightingQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks in the lighting thread's queue." },
+ GetLightingQueueLength = { Params = "", Return = "number", Notes = "Returns the number of chunks in the lighting thread's queue." },
GetLinkedEndWorldName = { Params = "", Return = "string", Notes = "Returns the name of the end world this world is linked to." },
GetLinkedNetherWorldName = { Params = "", Return = "string", Notes = "Returns the name of the Netherworld linked to this world." },
GetLinkedOverworldName = { Params = "", Return = "string", Notes = "Returns the name of the world this world is linked to." },
@@ -2514,7 +2515,7 @@ World:ForEachEntity(
if not(a_Entity:IsMob()) then
return;
end
-
+
-- Get the cMonster out of cEntity, now that we know the entity represents one.
local Monster = tolua.cast(a_Entity, "cMonster");
if (Monster:GetMobType() == mtSpider) then
@@ -2565,7 +2566,7 @@ end
}
},
}, -- ItemCategory
-
+
lxp =
{
Desc = [[
@@ -2635,7 +2636,7 @@ local Callbacks = {
CharacterData = function(a_Parser, a_String)
LOG(string.rep(" ", Depth) .. "* " .. a_String);
end
-
+
EndElement = function(a_Parser, a_ElementName)
Depth = Depth - 1;
LOG(string.rep(" ", Depth) .. "- " .. a_ElementName);
@@ -2671,12 +2672,12 @@ Parser:close();
},
}, -- AdditionalInfo
}, -- lxp
-
+
sqlite3 =
{
Desc = [[
]],
-
+
Functions =
{
complete = { Params = "string", Return = "bool", Notes = "Returns true if the string sql comprises one or more complete SQL statements and false otherwise." },
@@ -2700,7 +2701,7 @@ myDB:close()
version = { Return = "string", Notes = "Returns a string with SQLite version information, in the form 'x.y[.z]'." },
},
},
-
+
TakeDamageInfo =
{
Desc = [[
@@ -2994,7 +2995,7 @@ end
"WriteHtmlHook",
"WriteStats",
},
-
+
IgnoreConstants =
{
"cChestEntity.__cBlockEntityWindowOwner__",
@@ -3003,12 +3004,12 @@ end
"cHopperEntity.__cBlockEntityWindowOwner__",
"cLuaWindow.__cItemGrid__cListener__",
},
-
+
IgnoreVariables =
{
"__.*__", -- tolua exports multiple inheritance this way
} ,
-
+
ExtraPages =
{
-- No sorting is provided for these, they will be output in the same order as defined here
@@ -3020,7 +3021,3 @@ end
{ FileName = "WebWorldThreads.html", Title = "Webserver vs World threads" },
}
} ;
-
-
-
-
diff --git a/MCServer/crafting.txt b/MCServer/crafting.txt
index e7d11ab92..daac9e098 100644
--- a/MCServer/crafting.txt
+++ b/MCServer/crafting.txt
@@ -322,7 +322,7 @@ MushroomStew = Bowl, * | BrownMushroom, * | RedMushroom, *
Bread = Wheat, 1:1, 2:1, 3:1
Sugar = Sugarcane, *
Cake = MilkBucket, 1:1, 2:1, 3:1 | Sugar, 1:2, 3:2 | Egg, 2:2 | Wheat, 1:3, 2:3, 3:3
-Cookie = Wheat, *, * | CocoaBeans, *
+Cookie, 8 = Wheat, *, * | CocoaBeans, *
GoldenApple = RedApple, 2:2 | GoldIngot, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
EnchantedGoldenApple = RedApple, 2:2 | GoldBlock, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
Melon = MelonSlice, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
diff --git a/SetFlags.cmake b/SetFlags.cmake
index d824d054a..e336bd6c8 100644
--- a/SetFlags.cmake
+++ b/SetFlags.cmake
@@ -246,6 +246,11 @@ macro(set_exe_flags)
# we support non-IEEE 754 fpus so can make no guarentees about error
add_flags_cxx("-ffast-math")
+ if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
+ # backtrace() and friends are in libexecinfo
+ add_flags_lnk("-lexecinfo")
+ endif()
+
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
if ("${CLANG_VERSION}" VERSION_LESS 3.0)
message(FATAL_ERROR "MCServer requires clang version 3.0 or higher, version is ${CLANG_VERSION}")
diff --git a/lib/sqlite/CMakeLists.txt b/lib/sqlite/CMakeLists.txt
index 993dac146..b9471c1f2 100644
--- a/lib/sqlite/CMakeLists.txt
+++ b/lib/sqlite/CMakeLists.txt
@@ -25,7 +25,7 @@ endif()
# FreeBSD requires us to define this to get POSIX 2001 standard
if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
- add_flags_cxx(-D__POSIX_VISIBLE=200112)
+ add_flags_cxx("-D_XOPEN_SOURCE=600")
endif()
add_library(sqlite ${SOURCE})
diff --git a/lib/tolua++/CMakeLists.txt b/lib/tolua++/CMakeLists.txt
index 12054323b..02883397e 100644
--- a/lib/tolua++/CMakeLists.txt
+++ b/lib/tolua++/CMakeLists.txt
@@ -53,4 +53,8 @@ if(UNIX)
target_link_libraries(tolua m ${DYNAMIC_LOADER})
endif()
+if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
+ add_flags_lnk(-L/usr/local/lib)
+endif()
+
target_link_libraries(tolua tolualib lua)
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index 4dc3e20d3..5b6bec728 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -1935,7 +1935,7 @@ size_t cPluginManager::GetNumLoadedPlugins(void) const
AStringVector cPluginManager::GetFoldersToLoad(cSettingsRepositoryInterface & a_Settings)
{
// Check if the Plugins section exists.
- if (a_Settings.KeyExists("Plugins"))
+ if (!a_Settings.KeyExists("Plugins"))
{
InsertDefaultPlugins(a_Settings);
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index dba6822c2..a23e02789 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -364,4 +364,9 @@ endif ()
if (WIN32)
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
endif()
+
+if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
+ add_flags_lnk(-L/usr/local/lib)
+endif()
+
target_link_libraries(${EXECUTABLE} luaexpat jsoncpp mbedtls zlib sqlite lua SQLiteCpp event_core event_extra)
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index c8ccc1cf5..765ccdee2 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -2329,6 +2329,15 @@ void cClientHandle::SendHealth(void)
+void cClientHandle::SendHideTitle(void)
+{
+ m_Protocol->SendHideTitle();
+}
+
+
+
+
+
void cClientHandle::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
{
m_Protocol->SendInventorySlot(a_WindowID, a_SlotNum, a_Item);
@@ -2532,6 +2541,15 @@ void cClientHandle::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effec
+void cClientHandle::SendResetTitle()
+{
+ m_Protocol->SendResetTitle();
+}
+
+
+
+
+
void cClientHandle::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks)
{
m_Protocol->SendRespawn(a_Dimension, a_ShouldIgnoreDimensionChecks);
@@ -2586,6 +2604,42 @@ void cClientHandle::SendDisplayObjective(const AString & a_Objective, cScoreboar
+void cClientHandle::SendSetSubTitle(const cCompositeChat & a_SubTitle)
+{
+ m_Protocol->SendSetSubTitle(a_SubTitle);
+}
+
+
+
+
+
+void cClientHandle::SendSetRawSubTitle(const AString & a_SubTitle)
+{
+ m_Protocol->SendSetRawSubTitle(a_SubTitle);
+}
+
+
+
+
+
+void cClientHandle::SendSetTitle(const cCompositeChat & a_Title)
+{
+ m_Protocol->SendSetTitle(a_Title);
+}
+
+
+
+
+
+void cClientHandle::SendSetRawTitle(const AString & a_Title)
+{
+ m_Protocol->SendSetRawTitle(a_Title);
+}
+
+
+
+
+
void cClientHandle::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
{
m_Protocol->SendSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch);
@@ -2676,6 +2730,15 @@ void cClientHandle::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cClientHandle::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks)
+{
+ m_Protocol->SendTitleTimes(a_FadeInTicks, a_DisplayTicks, a_FadeOutTicks);
+}
+
+
+
+
+
void cClientHandle::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
{
m_Protocol->SendTimeUpdate(a_WorldAge, a_TimeOfDay, a_DoDaylightCycle);
@@ -2894,13 +2957,20 @@ void cClientHandle::PacketError(UInt32 a_PacketType)
void cClientHandle::SocketClosed(void)
{
// The socket has been closed for any reason
-
+
if (!m_Username.empty()) // Ignore client pings
{
LOGD("Client %s @ %s disconnected", m_Username.c_str(), m_IPString.c_str());
cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, "Player disconnected");
}
-
+ if (m_State < csDestroying)
+ {
+ cWorld * World = m_Player->GetWorld();
+ if (World != nullptr)
+ {
+ World->RemovePlayer(m_Player, true); // Must be called before cPlayer::Destroy() as otherwise cChunk tries to delete the player, and then we do it again
+ }
+ }
Destroy();
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 61f29b57c..bcfa55825 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -172,6 +172,7 @@ public: // tolua_export
void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion);
void SendGameMode (eGameMode a_GameMode);
void SendHealth (void);
+ void SendHideTitle (void);
void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item);
void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length, unsigned int m_Scale);
void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators, unsigned int m_Scale);
@@ -192,9 +193,14 @@ public: // tolua_export
void SendPlayerSpawn (const cPlayer & a_Player);
void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp
void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID);
+ void SendResetTitle (void);
void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks = false);
void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode);
void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode);
+ void SendSetSubTitle (const cCompositeChat & a_SubTitle);
+ void SendSetRawSubTitle (const AString & a_SubTitle);
+ void SendSetTitle (const cCompositeChat & a_Title);
+ void SendSetRawTitle (const AString & a_Title);
void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch); // tolua_export
void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data);
void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock);
@@ -205,6 +211,7 @@ public: // tolua_export
void SendTabCompletionResults (const AStringVector & a_Results);
void SendTeleportEntity (const cEntity & a_Entity);
void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ);
+ void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks);
void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle); // tolua_export
void SendUnloadChunk (int a_ChunkX, int a_ChunkZ);
void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity);
diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp
index 24736350e..e4576a8f2 100644
--- a/src/Entities/Pickup.cpp
+++ b/src/Entities/Pickup.cpp
@@ -228,6 +228,7 @@ bool cPickup::CollectedBy(cPlayer & a_Dest)
m_Item.m_ItemCount -= NumAdded;
m_World->BroadcastCollectEntity(*this, a_Dest);
+
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
m_World->BroadcastSoundEffect("random.pop", GetPosX(), GetPosY(), GetPosZ(), 0.5, (0.75f + (static_cast<float>((GetUniqueID() * 23) % 32)) / 64));
if (m_Item.m_ItemCount <= 0)
diff --git a/src/Inventory.cpp b/src/Inventory.cpp
index 079743e90..6b3c8e62f 100644
--- a/src/Inventory.cpp
+++ b/src/Inventory.cpp
@@ -98,7 +98,7 @@ int cInventory::HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int
-int cInventory::AddItem(const cItem & a_Item, bool a_AllowNewStacks, bool a_tryToFillEquippedFirst)
+int cInventory::AddItem(const cItem & a_Item, bool a_AllowNewStacks)
{
cItem ToAdd(a_Item);
int res = 0;
@@ -116,8 +116,29 @@ int cInventory::AddItem(const cItem & a_Item, bool a_AllowNewStacks, bool a_tryT
}
}
- res += m_HotbarSlots.AddItem(ToAdd, a_AllowNewStacks, a_tryToFillEquippedFirst ? m_EquippedSlotNum : -1);
- ToAdd.m_ItemCount = a_Item.m_ItemCount - static_cast<char>(res);
+ for (int SlotIdx = 0; SlotIdx < m_InventorySlots.GetNumSlots(); ++SlotIdx)
+ {
+ auto & Slot = m_InventorySlots.GetSlot(SlotIdx);
+ if (Slot.IsEqual(a_Item))
+ {
+ cItemHandler Handler(Slot.m_ItemType);
+ int AmountToAdd = std::min(static_cast<char>(Handler.GetMaxStackSize() - Slot.m_ItemCount), ToAdd.m_ItemCount);
+ res += AmountToAdd;
+
+ cItem SlotAdjusted(Slot);
+ SlotAdjusted.m_ItemCount += AmountToAdd;
+ m_InventorySlots.SetSlot(SlotIdx, SlotAdjusted);
+
+ ToAdd.m_ItemCount -= AmountToAdd;
+ if (ToAdd.m_ItemCount == 0)
+ {
+ return res;
+ }
+ }
+ }
+
+ res += m_HotbarSlots.AddItem(ToAdd, a_AllowNewStacks);
+ ToAdd.m_ItemCount = a_Item.m_ItemCount - res;
if (ToAdd.m_ItemCount == 0)
{
return res;
@@ -131,12 +152,12 @@ int cInventory::AddItem(const cItem & a_Item, bool a_AllowNewStacks, bool a_tryT
-int cInventory::AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks, bool a_tryToFillEquippedFirst)
+int cInventory::AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks)
{
int TotalAdded = 0;
for (cItems::iterator itr = a_ItemStackList.begin(); itr != a_ItemStackList.end();)
{
- int NumAdded = AddItem(*itr, a_AllowNewStacks, a_tryToFillEquippedFirst);
+ int NumAdded = AddItem(*itr, a_AllowNewStacks);
if (itr->m_ItemCount == NumAdded)
{
itr = a_ItemStackList.erase(itr);
diff --git a/src/Inventory.h b/src/Inventory.h
index b2a8f658b..5501399bd 100644
--- a/src/Inventory.h
+++ b/src/Inventory.h
@@ -70,23 +70,17 @@ public:
/** Adds as many items out of a_ItemStack as can fit.
If a_AllowNewStacks is set to false, only existing stacks can be topped up;
if a_AllowNewStacks is set to true, empty slots can be used for the rest.
- If a_tryToFillEquippedFirst is set to true, the currently equipped slot will be used first (if empty or
- compatible with added items)
- if a_tryToFillEquippedFirst is set to false, the regular order applies.
Returns the number of items that fit.
*/
- int AddItem(const cItem & a_ItemStack, bool a_AllowNewStacks = true, bool a_tryToFillEquippedFirst = false);
+ int AddItem(const cItem & a_ItemStack, bool a_AllowNewStacks = true);
/** Same as AddItem, but works on an entire list of item stacks.
The a_ItemStackList is modified to reflect the leftover items.
If a_AllowNewStacks is set to false, only existing stacks can be topped up;
if a_AllowNewStacks is set to true, empty slots can be used for the rest.
- If a_tryToFillEquippedFirst is set to true, the currently equipped slot will be used first (if empty or
- compatible with added items)
- if a_tryToFillEquippedFirst is set to false, the regular order applies.
Returns the total number of items that fit.
*/
- int AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks, bool a_tryToFillEquippedFirst);
+ int AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks);
/** Removes the specified item from the inventory, as many as possible, up to a_ItemStack.m_ItemCount.
Returns the number of items that were removed. */
diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h
index 78a5e3744..4d39bde82 100644
--- a/src/Items/ItemBucket.h
+++ b/src/Items/ItemBucket.h
@@ -103,7 +103,7 @@ public:
ASSERT(!"Inventory bucket mismatch");
return true;
}
- if (a_Player->GetInventory().AddItem(cItem(NewItem), true, true) != 1)
+ if (a_Player->GetInventory().AddItem(cItem(NewItem)) != 1)
{
// The bucket didn't fit, toss it as a pickup:
a_Player->TossPickup(cItem(NewItem));
@@ -151,7 +151,7 @@ public:
return false;
}
cItem Item(E_ITEM_BUCKET, 1);
- if (!a_Player->GetInventory().AddItem(Item, true, true))
+ if (!a_Player->GetInventory().AddItem(Item))
{
return false;
}
diff --git a/src/Items/ItemEmptyMap.h b/src/Items/ItemEmptyMap.h
index 6e944b4da..fba8c0a2c 100644
--- a/src/Items/ItemEmptyMap.h
+++ b/src/Items/ItemEmptyMap.h
@@ -60,7 +60,7 @@ public:
return true;
}
- a_Player->GetInventory().AddItem(cItem(E_ITEM_MAP, 1, (short)(NewMap->GetID() & 0x7fff)), true, true);
+ a_Player->GetInventory().AddItem(cItem(E_ITEM_MAP, 1, (short)(NewMap->GetID() & 0x7fff)));
return true;
}
diff --git a/src/Items/ItemMushroomSoup.h b/src/Items/ItemMushroomSoup.h
index dba313ec5..1a761cbf1 100644
--- a/src/Items/ItemMushroomSoup.h
+++ b/src/Items/ItemMushroomSoup.h
@@ -41,7 +41,7 @@ public:
// Return a bowl to the inventory
if (!a_Player->IsGameModeCreative())
{
- a_Player->GetInventory().AddItem(cItem(E_ITEM_BOWL), true, true);
+ a_Player->GetInventory().AddItem(cItem(E_ITEM_BOWL));
}
return true;
}
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index e2906efa6..44a037805 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -196,7 +196,15 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk)
{
if (m_NoMoreWayPoints || (--m_GiveUpCounter == 0))
{
- ResetPathFinding(); // Try to calculate a path again.
+ if (m_EMState == ATTACKING)
+ {
+ ResetPathFinding(); // Try to calculate a path again.
+ // This results in mobs hanging around an unreachable target (player).
+ }
+ else
+ {
+ StopMovingToPosition(); // Find a different place to go to.
+ }
return false;
}
else if (!m_Path->IsLastPoint()) // Have we arrived at the next cell, as denoted by m_NextWayPointPosition?
@@ -391,6 +399,7 @@ void cMonster::MoveToPosition(const Vector3d & a_Position)
void cMonster::StopMovingToPosition()
{
m_IsFollowingPath = false;
+ ResetPathFinding();
}
@@ -520,7 +529,7 @@ void cMonster::SetPitchAndYawFromDestination()
double HeadRotation, HeadPitch;
Distance.Normalize();
VectorToEuler(Distance.x, Distance.y, Distance.z, HeadRotation, HeadPitch);
- if (std::abs(BodyRotation - HeadRotation) < 120)
+ if (std::abs(BodyRotation - HeadRotation) < 90)
{
SetHeadYaw(HeadRotation);
SetPitch(-HeadPitch);
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index 61c28c467..7b5953523 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -20,6 +20,7 @@ cWolf::cWolf(void) :
m_OwnerName(""),
m_CollarColor(14)
{
+ m_RelativeWalkSpeed = 2;
}
@@ -230,7 +231,7 @@ void cWolf::TickFollowPlayer()
{
// The player is present in the world, follow him:
double Distance = (Callback.OwnerPos - GetPosition()).Length();
- if (Distance > 30)
+ if (Distance > 20)
{
Callback.OwnerPos.y = FindFirstNonAirBlockPosition(Callback.OwnerPos.x, Callback.OwnerPos.z);
TeleportToCoords(Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z);
diff --git a/src/OSSupport/Errors.cpp b/src/OSSupport/Errors.cpp
index a5361e1a6..407799495 100644
--- a/src/OSSupport/Errors.cpp
+++ b/src/OSSupport/Errors.cpp
@@ -22,7 +22,7 @@ AString GetOSErrorString( int a_ErrNo)
// According to http://linux.die.net/man/3/strerror_r there are two versions of strerror_r():
- #if !defined(__APPLE__) && ( _GNU_SOURCE) && !defined(ANDROID_NDK) // GNU version of strerror_r()
+ #if !defined(__APPLE__) && defined( _GNU_SOURCE) && !defined(ANDROID_NDK) // GNU version of strerror_r()
char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer));
if (res != nullptr)
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index 3bca7551b..7be72014a 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -88,6 +88,7 @@ public:
virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) = 0;
virtual void SendGameMode (eGameMode a_GameMode) = 0;
virtual void SendHealth (void) = 0;
+ virtual void SendHideTitle (void) = 0;
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) = 0;
virtual void SendKeepAlive (int a_PingID) = 0;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 0;
@@ -112,12 +113,17 @@ public:
virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0;
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0;
+ virtual void SendResetTitle (void) = 0;
virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) = 0;
virtual void SendExperience (void) = 0;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) = 0;
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) = 0;
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) = 0;
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) = 0;
+ virtual void SendSetSubTitle (const cCompositeChat & a_SubTitle) = 0;
+ virtual void SendSetRawSubTitle (const AString & a_SubTitle) = 0;
+ virtual void SendSetTitle (const cCompositeChat & a_Title) = 0;
+ virtual void SendSetRawTitle (const AString & a_Title) = 0;
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) = 0;
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) = 0;
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0;
@@ -128,6 +134,7 @@ public:
virtual void SendTabCompletionResults (const AStringVector & a_Results) = 0;
virtual void SendTeleportEntity (const cEntity & a_Entity) = 0;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
+ virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) = 0;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) = 0;
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) = 0;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) = 0;
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 0540ae9e1..6aa36e2a5 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -555,6 +555,15 @@ void cProtocol172::SendHealth(void)
+void cProtocol172::SendHideTitle(void)
+{
+ // Not implemented in this protocol version
+}
+
+
+
+
+
void cProtocol172::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
{
ASSERT(m_State == 3); // In game mode?
@@ -995,6 +1004,15 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect
+void cProtocol172::SendResetTitle(void)
+{
+ // Not implemented in this protocol version
+}
+
+
+
+
+
void cProtocol172::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks)
{
if ((m_LastSentDimension == a_Dimension) && !a_ShouldIgnoreDimensionChecks)
@@ -1094,6 +1112,42 @@ void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard
+void cProtocol172::SendSetSubTitle(const cCompositeChat & a_SubTitle)
+{
+ // Not implemented in this protocol version
+}
+
+
+
+
+
+void cProtocol172::SendSetRawSubTitle(const AString & a_SubTitle)
+{
+ // Not implemented in this protocol version
+}
+
+
+
+
+
+void cProtocol172::SendSetTitle(const cCompositeChat & a_Title)
+{
+ // Not implemented in this protocol version
+}
+
+
+
+
+
+void cProtocol172::SendSetRawTitle(const AString & a_Title)
+{
+ // Not implemented in this protocol version
+}
+
+
+
+
+
void cProtocol172::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
{
ASSERT(m_State == 3); // In game mode?
@@ -1296,6 +1350,15 @@ void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cProtocol172::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks)
+{
+ // Not implemented in this protocol version
+}
+
+
+
+
+
void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
{
ASSERT(m_State == 3); // In game mode?
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 773c39f87..ead2935b0 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -90,6 +90,7 @@ public:
virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override;
virtual void SendGameMode (eGameMode a_GameMode) override;
virtual void SendHealth (void) override;
+ virtual void SendHideTitle (void) override;
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
@@ -113,9 +114,14 @@ public:
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
+ virtual void SendResetTitle (void) override;
virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) override;
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override;
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
+ virtual void SendSetSubTitle (const cCompositeChat & a_SubTitle) override;
+ virtual void SendSetRawSubTitle (const AString & a_SubTitle) override;
+ virtual void SendSetTitle (const cCompositeChat & a_Title) override;
+ virtual void SendSetRawTitle (const AString & a_Title) override;
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
@@ -126,6 +132,7 @@ public:
virtual void SendTabCompletionResults (const AStringVector & a_Results) override;
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
+ virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override;
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
diff --git a/src/Protocol/Protocol18x.cpp b/src/Protocol/Protocol18x.cpp
index 4612af4a5..d06022ce0 100644
--- a/src/Protocol/Protocol18x.cpp
+++ b/src/Protocol/Protocol18x.cpp
@@ -542,6 +542,18 @@ void cProtocol180::SendHealth(void)
+void cProtocol180::SendHideTitle(void)
+{
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x45); // Title packet
+ Pkt.WriteVarInt32(3); // Hide title
+}
+
+
+
+
+
void cProtocol180::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
{
ASSERT(m_State == 3); // In game mode?
@@ -1065,6 +1077,18 @@ void cProtocol180::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect
+void cProtocol180::SendResetTitle(void)
+{
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x45); // Title packet
+ Pkt.WriteVarInt32(4); // Reset title
+}
+
+
+
+
+
void cProtocol180::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks)
{
if ((m_LastSentDimension == a_Dimension) && !a_ShouldIgnoreDimensionChecks)
@@ -1167,6 +1191,52 @@ void cProtocol180::SendDisplayObjective(const AString & a_Objective, cScoreboard
+void cProtocol180::SendSetSubTitle(const cCompositeChat & a_SubTitle)
+{
+ SendSetRawSubTitle(a_SubTitle.CreateJsonString(false));
+}
+
+
+
+
+
+void cProtocol180::SendSetRawSubTitle(const AString & a_SubTitle)
+{
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x45); // Title packet
+ Pkt.WriteVarInt32(1); // Set subtitle
+
+ Pkt.WriteString(a_SubTitle);
+}
+
+
+
+
+
+void cProtocol180::SendSetTitle(const cCompositeChat & a_Title)
+{
+ SendSetRawTitle(a_Title.CreateJsonString(false));
+}
+
+
+
+
+
+void cProtocol180::SendSetRawTitle(const AString & a_Title)
+{
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x45); // Title packet
+ Pkt.WriteVarInt32(0); // Set title
+
+ Pkt.WriteString(a_Title);
+}
+
+
+
+
+
void cProtocol180::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
{
ASSERT(m_State == 3); // In game mode?
@@ -1374,6 +1444,22 @@ void cProtocol180::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
+void cProtocol180::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks)
+{
+ ASSERT(m_State == 3); // In game mode?
+
+ cPacketizer Pkt(*this, 0x45); // Title packet
+ Pkt.WriteVarInt32(2); // Set title display times
+
+ Pkt.WriteBEInt32(a_FadeInTicks);
+ Pkt.WriteBEInt32(a_DisplayTicks);
+ Pkt.WriteBEInt32(a_FadeOutTicks);
+}
+
+
+
+
+
void cProtocol180::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
{
ASSERT(m_State == 3); // In game mode?
diff --git a/src/Protocol/Protocol18x.h b/src/Protocol/Protocol18x.h
index 21024d702..6143e8b4e 100644
--- a/src/Protocol/Protocol18x.h
+++ b/src/Protocol/Protocol18x.h
@@ -85,6 +85,7 @@ public:
virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override;
virtual void SendGameMode (eGameMode a_GameMode) override;
virtual void SendHealth (void) override;
+ virtual void SendHideTitle (void) override;
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
@@ -109,6 +110,7 @@ public:
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
+ virtual void SendResetTitle (void) override;
virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) override;
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
virtual void SendExperience (void) override;
@@ -116,6 +118,10 @@ public:
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override;
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override;
+ virtual void SendSetSubTitle (const cCompositeChat & a_SubTitle) override;
+ virtual void SendSetRawSubTitle (const AString & a_SubTitle) override;
+ virtual void SendSetTitle (const cCompositeChat & a_Title) override;
+ virtual void SendSetRawTitle (const AString & a_Title) override;
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
virtual void SendSpawnMob (const cMonster & a_Mob) override;
@@ -125,6 +131,7 @@ public:
virtual void SendTabCompletionResults (const AStringVector & a_Results) override;
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
+ virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override;
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index e7f7a4526..477f2d71e 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -350,6 +350,16 @@ void cProtocolRecognizer::SendHealth(void)
+void cProtocolRecognizer::SendHideTitle(void)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendHideTitle();
+}
+
+
+
+
+
void cProtocolRecognizer::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value)
{
ASSERT(m_Protocol != nullptr);
@@ -599,6 +609,16 @@ void cProtocolRecognizer::SendRemoveEntityEffect(const cEntity & a_Entity, int a
+void cProtocolRecognizer::SendResetTitle(void)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendResetTitle();
+}
+
+
+
+
+
void cProtocolRecognizer::SendRespawn(eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks)
{
ASSERT(m_Protocol != nullptr);
@@ -659,6 +679,46 @@ void cProtocolRecognizer::SendDisplayObjective(const AString & a_Objective, cSco
+void cProtocolRecognizer::SendSetSubTitle(const cCompositeChat & a_SubTitle)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendSetSubTitle(a_SubTitle);
+}
+
+
+
+
+
+void cProtocolRecognizer::SendSetRawSubTitle(const AString & a_SubTitle)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendSetRawSubTitle(a_SubTitle);
+}
+
+
+
+
+
+void cProtocolRecognizer::SendSetTitle(const cCompositeChat & a_Title)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendSetTitle(a_Title);
+}
+
+
+
+
+
+void cProtocolRecognizer::SendSetRawTitle(const AString & a_Title)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendSetRawTitle(a_Title);
+}
+
+
+
+
+
void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
{
ASSERT(m_Protocol != nullptr);
@@ -759,6 +819,16 @@ void cProtocolRecognizer::SendThunderbolt(int a_BlockX, int a_BlockY, int a_Bloc
+void cProtocolRecognizer::SendTitleTimes(int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks)
+{
+ ASSERT(m_Protocol != nullptr);
+ m_Protocol->SendTitleTimes(a_FadeInTicks, a_DisplayTicks, a_FadeOutTicks);
+}
+
+
+
+
+
void cProtocolRecognizer::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle)
{
ASSERT(m_Protocol != nullptr);
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index 6c2185d6d..956b5dcc0 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -73,6 +73,7 @@ public:
virtual void SendExplosion (double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) override;
virtual void SendGameMode (eGameMode a_GameMode) override;
virtual void SendHealth (void) override;
+ virtual void SendHideTitle (void) override;
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
@@ -97,12 +98,17 @@ public:
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
+ virtual void SendResetTitle (void) override;
virtual void SendRespawn (eDimension a_Dimension, bool a_ShouldIgnoreDimensionChecks) override;
virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override;
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override;
+ virtual void SendSetSubTitle (const cCompositeChat & a_SubTitle) override;
+ virtual void SendSetRawSubTitle (const AString & a_SubTitle) override;
+ virtual void SendSetTitle (const cCompositeChat & a_Title) override;
+ virtual void SendSetRawTitle (const AString & a_Title) override;
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
@@ -113,6 +119,7 @@ public:
virtual void SendTabCompletionResults (const AStringVector & a_Results) override;
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
+ virtual void SendTitleTimes (int a_FadeInTicks, int a_DisplayTicks, int a_FadeOutTicks) override;
virtual void SendTimeUpdate (Int64 a_WorldAge, Int64 a_TimeOfDay, bool a_DoDaylightCycle) override;
virtual void SendUnloadChunk (int a_ChunkX, int a_ChunkZ) override;
virtual void SendUpdateBlockEntity (cBlockEntity & a_BlockEntity) override;
diff --git a/src/Root.cpp b/src/Root.cpp
index c3c880e73..b28e7c894 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -72,7 +72,7 @@ cRoot::~cRoot()
void cRoot::InputThread(cRoot & a_Params)
{
cLogCommandOutputCallback Output;
-
+
while (!cRoot::m_ShouldStop && !a_Params.m_bRestart && !m_TerminateEventRaised && std::cin.good())
{
AString Command;
@@ -105,12 +105,12 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo)
HMENU hmenu = GetSystemMenu(hwnd, FALSE);
EnableMenuItem(hmenu, SC_CLOSE, MF_GRAYED); // Disable close button when starting up; it causes problems with our CTRL-CLOSE handling
#endif
-
+
cLogger::cListener * consoleLogListener = MakeConsoleListener();
cLogger::cListener * fileLogListener = new cFileListener();
cLogger::GetInstance().AttachListener(consoleLogListener);
cLogger::GetInstance().AttachListener(fileLogListener);
-
+
LOG("--- Started Log ---\n");
#ifdef BUILD_ID
@@ -162,30 +162,30 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo)
m_RankManager->Initialize(*m_MojangAPI);
m_CraftingRecipes = new cCraftingRecipes;
m_FurnaceRecipe = new cFurnaceRecipe();
-
+
LOGD("Loading worlds...");
LoadWorlds(*settingsRepo);
LOGD("Loading plugin manager...");
m_PluginManager = new cPluginManager();
m_PluginManager->ReloadPluginsNow(*settingsRepo);
-
+
LOGD("Loading MonsterConfig...");
m_MonsterConfig = new cMonsterConfig;
// This sets stuff in motion
LOGD("Starting Authenticator...");
m_Authenticator.Start(*settingsRepo);
-
+
LOGD("Starting worlds...");
StartWorlds();
-
+
if (settingsRepo->GetValueSetB("DeadlockDetect", "Enabled", true))
{
LOGD("Starting deadlock detector...");
dd.Start(settingsRepo->GetValueSetI("DeadlockDetect", "IntervalSec", 20));
}
-
+
settingsRepo->Flush();
LOGD("Finalising startup...");
@@ -207,6 +207,10 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo)
#endif
LOG("Startup complete, took %ldms!", static_cast<long int>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - BeginTime).count()));
+
+ // Save the current time
+ m_StartTime = std::chrono::steady_clock::now();
+
#ifdef _WIN32
EnableMenuItem(hmenu, SC_CLOSE, MF_ENABLED); // Re-enable close button
#endif
@@ -253,7 +257,7 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo)
LOGD("Unloading worlds...");
UnloadWorlds();
-
+
LOGD("Stopping plugin manager...");
delete m_PluginManager; m_PluginManager = nullptr;
@@ -264,9 +268,9 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> overridesRepo)
LOG("Shutdown successful!");
}
-
+
LOG("--- Stopped Log ---");
-
+
cLogger::GetInstance().DetachListener(consoleLogListener);
delete consoleLogListener;
cLogger::GetInstance().DetachListener(fileLogListener);
@@ -299,7 +303,7 @@ void cRoot::LoadWorlds(cSettingsRepositoryInterface & a_Settings)
{
return;
}
-
+
bool FoundAdditionalWorlds = false;
for (auto WorldNameValue : Worlds)
{
@@ -850,7 +854,3 @@ int cRoot::GetFurnaceFuelBurnTime(const cItem & a_Fuel)
cFurnaceRecipe * FR = Get()->GetFurnaceRecipe();
return FR->GetBurnTime(a_Fuel);
}
-
-
-
-
diff --git a/src/Root.h b/src/Root.h
index 2b30afaff..ab820427f 100644
--- a/src/Root.h
+++ b/src/Root.h
@@ -70,22 +70,31 @@ public:
a_OverworldName should be set for non-overworld dimensions if one wishes that world to link back to an overworld via portals
*/
cWorld * CreateAndInitializeWorld(const AString & a_WorldName, eDimension a_Dimension = dimOverworld, const AString & a_OverworldName = "");
+
+ /** Returns the up time of the server in seconds */
+ int GetServerUpTime(void)
+ {
+ return static_cast<int>(std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - m_StartTime).count());
+ }
// tolua_end
-
+
/// Calls the callback for each world; returns true if the callback didn't abort (return true)
bool ForEachWorld(cWorldListCallback & a_Callback); // >> Exported in ManualBindings <<
-
+
/// Writes chunkstats, for each world and totals, to the output callback
void LogChunkStats(cCommandOutputCallback & a_Output);
-
+
cMonsterConfig * GetMonsterConfig(void) { return m_MonsterConfig; }
cCraftingRecipes * GetCraftingRecipes(void) { return m_CraftingRecipes; } // tolua_export
cFurnaceRecipe * GetFurnaceRecipe (void) { return m_FurnaceRecipe; } // Exported in ManualBindings.cpp with quite a different signature
-
+
/// Returns the number of ticks for how long the item would fuel a furnace. Returns zero if not a fuel
static int GetFurnaceFuelBurnTime(const cItem & a_Fuel); // tolua_export
-
+
+ /** The current time where the startup of the server has been completed */
+ std::chrono::steady_clock::time_point m_StartTime;
+
cWebAdmin * GetWebAdmin (void) { return m_WebAdmin; } // tolua_export
cPluginManager * GetPluginManager (void) { return m_PluginManager; } // tolua_export
cAuthenticator & GetAuthenticator (void) { return m_Authenticator; }
@@ -98,32 +107,32 @@ public:
"stop" and "restart" commands have special handling.
*/
void QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output);
-
+
/** Queues a console command for execution through the cServer class.
The command will be executed in the tick thread
The command's output will be sent to console
"stop" and "restart" commands have special handling.
*/
void QueueExecuteConsoleCommand(const AString & a_Cmd); // tolua_export
-
+
/// Executes a console command through the cServer class; does special handling for "stop" and "restart".
void ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output);
-
+
/// Kicks the user, no matter in what world they are. Used from cAuthenticator
void KickUser(int a_ClientID, const AString & a_Reason);
-
+
/// Called by cAuthenticator to auth the specified user
void AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID, const Json::Value & a_Properties);
-
+
/// Executes commands queued in the command queue
void TickCommands(void);
/// Returns the number of chunks loaded
int GetTotalChunkCount(void); // tolua_export
-
+
/// Saves all chunks in all worlds
void SaveAllChunks(void); // tolua_export
-
+
/// Calls the callback for each player in all worlds
bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
@@ -132,12 +141,12 @@ public:
/** Finds the player over his uuid and calls the callback */
bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
-
+
/** Finds the player using it's complete username and calls the callback */
bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback);
-
+
// tolua_begin
-
+
/// Sends a chat message to all connected clients (in all worlds)
void BroadcastChat (const AString & a_Message, eMessageType a_ChatPrefix = mtCustom);
void BroadcastChat (const cCompositeChat & a_Message);
@@ -149,18 +158,18 @@ public:
void BroadcastChatLeave (const AString & a_Message) { BroadcastChat(a_Message, mtLeave); }
void BroadcastChatSuccess(const AString & a_Message) { BroadcastChat(a_Message, mtSuccess); }
void BroadcastChatWarning(const AString & a_Message) { BroadcastChat(a_Message, mtWarning); }
-
+
/// Returns the textual description of the protocol version: 49 -> "1.4.4". Provided specifically for Lua API
static AString GetProtocolVersionTextFromInt(int a_ProtocolVersionNum);
-
+
/// Returns the amount of virtual RAM used, in KiB. Returns a negative number on error
static int GetVirtualRAMUsage(void);
-
+
/// Returns the amount of virtual RAM used, in KiB. Returns a negative number on error
static int GetPhysicalRAMUsage(void);
-
+
// tolua_end
-
+
private:
class cCommand
{
@@ -170,17 +179,17 @@ private:
m_Output(a_Output)
{
}
-
+
AString m_Command;
cCommandOutputCallback * m_Output;
} ;
-
+
typedef std::map<AString, cWorld *> WorldMap;
typedef std::vector<cCommand> cCommandQueue;
cWorld * m_pDefaultWorld;
WorldMap m_WorldsByName;
-
+
cCriticalSection m_CSPendingCommands;
cCommandQueue m_PendingCommands;
@@ -206,24 +215,20 @@ private:
/// Loads the worlds from settings.ini, creates the worldmap
void LoadWorlds(cSettingsRepositoryInterface & a_Settings);
-
+
/// Starts each world's life
void StartWorlds(void);
-
+
/// Stops each world's threads, so that it's safe to unload them
void StopWorlds(void);
-
+
/// Unloads all worlds from memory
void UnloadWorlds(void);
-
+
/// Does the actual work of executing a command
void DoExecuteConsoleCommand(const AString & a_Cmd);
-
+
static cRoot * s_Root;
static void InputThread(cRoot & a_Params);
}; // tolua_export
-
-
-
-
diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index 37683a8e5..5b58b18b6 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -1394,7 +1394,7 @@ void cSlotAreaBeacon::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
// cSlotAreaEnchanting:
cSlotAreaEnchanting::cSlotAreaEnchanting(cWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ) :
- cSlotAreaTemporary(1, a_ParentWindow),
+ cSlotAreaTemporary(2, a_ParentWindow),
m_BlockX(a_BlockX),
m_BlockY(a_BlockY),
m_BlockZ(a_BlockZ)
@@ -2154,10 +2154,10 @@ bool cSlotAreaArmor::CanPlaceArmorInSlot(int a_SlotNum, const cItem & a_Item)
{
switch (a_SlotNum)
{
- case 0: return ItemCategory::IsHelmet (a_Item.m_ItemType);
+ case 0: return (ItemCategory::IsHelmet(a_Item.m_ItemType) || (a_Item.m_ItemType == E_BLOCK_PUMPKIN));
case 1: return ItemCategory::IsChestPlate(a_Item.m_ItemType);
- case 2: return ItemCategory::IsLeggings (a_Item.m_ItemType);
- case 3: return ItemCategory::IsBoots (a_Item.m_ItemType);
+ case 2: return ItemCategory::IsLeggings(a_Item.m_ItemType);
+ case 3: return ItemCategory::IsBoots(a_Item.m_ItemType);
}
return false;
}
diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp
index d1c08acec..61e25651b 100644
--- a/src/UI/Window.cpp
+++ b/src/UI/Window.cpp
@@ -92,9 +92,9 @@ const AString cWindow::GetWindowTypeName(void) const
int cWindow::GetNumSlots(void) const
{
int res = 0;
- for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
+ for (const auto & itr : m_SlotAreas)
{
- res += (*itr)->GetNumSlots();
+ res += itr->GetNumSlots();
} // for itr - m_SlotAreas[]
return res;
}
@@ -261,16 +261,14 @@ void cWindow::Clicked(
}
int LocalSlotNum = a_SlotNum;
- int idx = 0;
- for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
+ for (const auto & itr : m_SlotAreas)
{
- if (LocalSlotNum < (*itr)->GetNumSlots())
+ if (LocalSlotNum < itr->GetNumSlots())
{
- (*itr)->Clicked(a_Player, LocalSlotNum, a_ClickAction, a_ClickedItem);
+ itr->Clicked(a_Player, LocalSlotNum, a_ClickAction, a_ClickedItem);
return;
}
- LocalSlotNum -= (*itr)->GetNumSlots();
- idx++;
+ LocalSlotNum -= itr->GetNumSlots();
}
LOGWARNING("Slot number higher than available window slots: %d, max %d received from \"%s\"; ignoring.",