diff --git a/.gitignore b/.gitignore
index e271cc0195..170ef36972 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
build/
+build*/
nbproject/
ipch/
Win32/
@@ -122,3 +123,6 @@ build-cuberite
# clang-tidy
tidy-build
run-clang-tidy.py
+
+# ctags output
+tags
diff --git a/COMPILING.md b/COMPILING.md
index 030121ad46..a83257627c 100644
--- a/COMPILING.md
+++ b/COMPILING.md
@@ -33,7 +33,13 @@ If you're using Git to get the source, use the following command to set up the l
git clone --recursive https://github.com/cuberite/cuberite.git
```
-Now that you have the source, it's time to prepare the project files for your favorite compiler. Open a command window in the folder with the source and type in `cmake .` . This will run CMake, it will auto-detect your Visual Studio version and produce the appropriate project and solution files.
+Now that you have the source, it's time to prepare the project files for your favorite compiler. Open a command window in the folder with the source and type in:
+```
+mkdir build
+cd build
+cmake ..
+```
+This creates a `build` folder where the build will take place, then runs CMake, which will auto-detect your Visual Studio version and produce the appropriate project and solution files.
Finally, open the newly created file, `Cuberite.sln`, in your Visual Studio.
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 314182d9e7..3c6d838e2b 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -65,6 +65,7 @@ NiLSPACE (formerly STR_Warrior)
npresley0506
p-mcgowan
Persson-dev
+plan1231
pokechu22
ProjectBM
pwnOrbitals
diff --git a/GETTING-STARTED.md b/GETTING-STARTED.md
index 016659a492..53ac9d8bab 100644
--- a/GETTING-STARTED.md
+++ b/GETTING-STARTED.md
@@ -117,7 +117,7 @@ Issues that should be easy to get started with are tagged as [easy][6] in GitHub
Other good places to get started are:
- - Cleaning up some of the compiler warnings. Check [Travis CI][7] for a list of them.
+ - Cleaning up some of the compiler warnings. Check [our CI][7] for a list of them.
- Writing some plugins: They are written in lua, with excellent API documentation available via [APIDump][8]. The [Core plugin][9] should also help quite a bit here.
Special Things
@@ -131,6 +131,6 @@ Special Things
[4]: https://github.com/cuberite/cuberite/blob/master/CONTRIBUTING.md
[5]: https://github.com/cuberite/cuberite/blob/master/COMPILING.md
[6]: https://github.com/cuberite/cuberite/issues?q=is%3Aopen+is%3Aissue+label%3Aeffort%2Feasy
-[7]: https://travis-ci.org/cuberite/cuberite
+[7]: https://builds.cuberite.org/job/cuberite/job/master/lastSuccessfulBuild/console
[8]: https://api.cuberite.org/
[9]: https://github.com/cuberite/Core
diff --git a/README.md b/README.md
index 34f3320df3..18000a2042 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
Cuberite is a Minecraft-compatible multiplayer game server that is written in C++ and designed to be efficient with memory and CPU, as well as having a flexible Lua Plugin API. Cuberite is compatible with the Java Edition Minecraft client.
-Cuberite runs on Windows, *nix and Android operating systems. This includes Android phones and tablets as well as Raspberry Pis.
+Cuberite runs on Windows, *nix and Android operating systems. This includes Android phones and tablets as well as Raspberry Pis; support for small embedded devices is experimental.
Currently we support Release 1.8 - 1.12.2 Minecraft protocol versions.
diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua
index e1f5ef1ca7..955978670b 100644
--- a/Server/Plugins/APIDump/APIDesc.lua
+++ b/Server/Plugins/APIDump/APIDesc.lua
@@ -2228,18 +2228,21 @@ end
Chaining example below for details.
Each part of the composite chat message takes a "Style" parameter, this is a string that describes
- the formatting. It uses the following strings, concatenated together:
+ the formatting. It uses the "standard" minecraft format code without the '&' symbole, concatenated
+ together:
String | Style |
- b | Bold text |
- i | Italic text |
- u | Underlined text |
- s | Strikethrough text |
- o | Obfuscated text |
- @X | color [0–9a–f], same as dye meta |
+ l | Bold text |
+ o | Italic text |
+ n | Underlined text |
+ m | Strikethrough text |
+ k | Obfuscated text |
+ r | Reset Style |
+ [0-9a-f] | colors |
+ You can escape the '&' character with an antislash in front of it. as follow: `I love Choco\&chips`
The following picture, taken from the Minecraft Wiki, illustrates the color codes:
-
+
]],
Functions =
{
@@ -17950,6 +17953,10 @@ end
{
Notes = "A TNT explosion. The SourceData param is the {{cTNTEntity|TNT entity}} object.",
},
+ esTNTMinecart =
+ {
+ Notes = "A TNT minecart explosion. The SourceData param is the {{cMinecartWithTNT|Minecart with TNT entity}} object.",
+ },
esWitherBirth =
{
Notes = "An explosion at a wither's birth. The SourceData param is the {{cMonster|wither entity}} object.",
diff --git a/Server/Plugins/Core b/Server/Plugins/Core
index 6d8a62087a..27185c6388 160000
--- a/Server/Plugins/Core
+++ b/Server/Plugins/Core
@@ -1 +1 @@
-Subproject commit 6d8a62087aae6aa9c272b137d1f1a0fcada66ce6
+Subproject commit 27185c638834da6a852bc3ea831b8229f45934f1
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index f5517dc843..40ab0467b4 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -3949,7 +3949,7 @@ static int tolua_cCompositeChat_AddRunCommandPart(lua_State * tolua_S)
}
// Add the part:
- AString Text, Command, Style = "u@a";
+ AString Text, Command, Style = "na";
L.GetStackValue(2, Text);
L.GetStackValue(3, Command);
L.GetStackValue(4, Style);
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index 69a8626c1c..caa02acf91 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -4,6 +4,8 @@
// Implements the cPluginLua class representing a plugin written in Lua
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+#include "Defines.h"
+#include "Entities/Minecart.h"
#ifdef __APPLE__
#define LUA_USE_MACOSX
@@ -431,6 +433,7 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can
case esOther: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res); break;
case esPlugin: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res); break;
case esPrimedTNT: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res); break;
+ case esTNTMinecart: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res); break;
case esWitherBirth: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res); break;
case esWitherSkull: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res); break;
case esMax:
@@ -471,6 +474,7 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool &
case esOther: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
case esPlugin: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
case esPrimedTNT: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esTNTMinecart: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
case esWitherBirth: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
case esWitherSkull: hook->Call(&a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, static_cast (a_SourceData), cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
case esMax:
diff --git a/src/BlockInfo.h b/src/BlockInfo.h
index a15868abeb..7d2781847c 100644
--- a/src/BlockInfo.h
+++ b/src/BlockInfo.h
@@ -65,7 +65,6 @@ class cBlockInfo
-
bool IsBlockWater(BLOCKTYPE a_BlockType);
bool IsBlockIce(BLOCKTYPE a_BlockType);
diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h
index d703d73bd4..1a141eff35 100644
--- a/src/Blocks/BlockButton.h
+++ b/src/Blocks/BlockButton.h
@@ -1,10 +1,15 @@
#pragma once
#include "BlockHandler.h"
+#include "BlockSlab.h"
+#include "BlockStairs.h"
#include "../BlockInfo.h"
#include "../Chunk.h"
+#include "Defines.h"
+#include "Entities/Player.h"
#include "Mixins.h"
#include "ChunkInterface.h"
+#include "World.h"
@@ -132,7 +137,37 @@ class cBlockButtonHandler final :
return false;
}
BLOCKTYPE SupportBlockType;
- a_Chunk.UnboundedRelGetBlockType(SupportRelPos, SupportBlockType);
+ NIBBLETYPE SupportBlockMeta;
+ a_Chunk.UnboundedRelGetBlock(SupportRelPos, SupportBlockType, SupportBlockMeta);
+ eBlockFace Face = BlockMetaDataToBlockFace(a_Meta);
+
+ // upside down slabs
+ if (cBlockSlabHandler::IsAnySlabType(SupportBlockType))
+ {
+ return (Face == BLOCK_FACE_YP) && (SupportBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN);
+ }
+
+ // stairs (top and sides)
+ if (cBlockStairsHandler::IsAnyStairType(SupportBlockType))
+ {
+ switch (Face)
+ {
+ case eBlockFace::BLOCK_FACE_YP:
+ return (SupportBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN);
+ case eBlockFace::BLOCK_FACE_XP:
+ return ((SupportBlockMeta & 0b11) == E_BLOCK_STAIRS_XP);
+ case eBlockFace::BLOCK_FACE_XM:
+ return ((SupportBlockMeta & 0b11) == E_BLOCK_STAIRS_XM);
+ case eBlockFace::BLOCK_FACE_ZP:
+ return ((SupportBlockMeta & 0b11) == E_BLOCK_STAIRS_ZP);
+ case eBlockFace::BLOCK_FACE_ZM:
+ return ((SupportBlockMeta & 0b11) == E_BLOCK_STAIRS_ZM);
+ default:
+ {
+ return false;
+ }
+ }
+ }
return cBlockInfo::FullyOccupiesVoxel(SupportBlockType);
}
diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h
index e58b386c34..18aa2a8b90 100644
--- a/src/Blocks/BlockComparator.h
+++ b/src/Blocks/BlockComparator.h
@@ -167,14 +167,19 @@ class cBlockComparatorHandler final :
{
return true;
}
- else if (cBlockSlabHandler::IsAnySlabType(BelowBlock))
+
+ // upside down slabs
+ if (cBlockSlabHandler::IsAnySlabType(BelowBlock))
{
- // Check if the slab is turned up side down
- if ((BelowBlockMeta & 0x08) == 0x08)
- {
- return true;
- }
+ return BelowBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN;
}
+
+ // upside down stairs
+ if (cBlockStairsHandler::IsAnyStairType(BelowBlock))
+ {
+ return BelowBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN;
+ }
+
return false;
}
diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h
index bf6f911a11..60db4ddee7 100644
--- a/src/Blocks/BlockLever.h
+++ b/src/Blocks/BlockLever.h
@@ -2,6 +2,9 @@
#include "BlockHandler.h"
#include "../Chunk.h"
+#include "Blocks/BlockStairs.h"
+#include "ChunkDef.h"
+#include "Defines.h"
#include "Mixins.h"
#include "BlockSlab.h"
@@ -117,7 +120,28 @@ class cBlockLeverHandler final :
(((NeighborMeta & 0x08) == 0) && (NeighborFace == BLOCK_FACE_BOTTOM))
);
}
-
+ else if (cBlockStairsHandler::IsAnyStairType(NeighborBlockType))
+ {
+ switch (NeighborFace)
+ {
+ case eBlockFace::BLOCK_FACE_YM:
+ return !(NeighborMeta & E_BLOCK_STAIRS_UPSIDE_DOWN);
+ case eBlockFace::BLOCK_FACE_YP:
+ return (NeighborMeta & E_BLOCK_STAIRS_UPSIDE_DOWN);
+ case eBlockFace::BLOCK_FACE_XP:
+ return ((NeighborMeta & 0b11) == E_BLOCK_STAIRS_XP);
+ case eBlockFace::BLOCK_FACE_XM:
+ return ((NeighborMeta & 0b11) == E_BLOCK_STAIRS_XM);
+ case eBlockFace::BLOCK_FACE_ZP:
+ return ((NeighborMeta & 0b11) == E_BLOCK_STAIRS_ZP);
+ case eBlockFace::BLOCK_FACE_ZM:
+ return ((NeighborMeta & 0b11) == E_BLOCK_STAIRS_ZM);
+ default:
+ {
+ return false;
+ }
+ }
+ }
return false;
}
diff --git a/src/Blocks/BlockPressurePlate.h b/src/Blocks/BlockPressurePlate.h
index d2f05b2e7f..6d852bfc05 100644
--- a/src/Blocks/BlockPressurePlate.h
+++ b/src/Blocks/BlockPressurePlate.h
@@ -2,6 +2,9 @@
#pragma once
#include "BlockHandler.h"
+#include "BlockSlab.h"
+#include "../Chunk.h"
+#include "BlockStairs.h"
@@ -24,9 +27,22 @@ class cBlockPressurePlateHandler final :
return false;
}
- // TODO: check if the block is upside-down slab or upside-down stairs
+ BLOCKTYPE Block;
+ NIBBLETYPE BlockMeta;
+ a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), Block, BlockMeta);
+
+ // upside down slabs
+ if (cBlockSlabHandler::IsAnySlabType(Block))
+ {
+ return BlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN;
+ }
+
+ // upside down stairs
+ if (cBlockStairsHandler::IsAnyStairType(Block))
+ {
+ return BlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN;
+ }
- const auto Block = a_Chunk.GetBlock(a_Position.addedY(-1));
switch (Block)
{
case E_BLOCK_ACACIA_FENCE:
diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h
index 6c43673345..4e2e6211fc 100644
--- a/src/Blocks/BlockRail.h
+++ b/src/Blocks/BlockRail.h
@@ -1,6 +1,14 @@
-
#pragma once
+#include "BlockHandler.h"
+#include "BlockSlab.h"
+#include "BlockStairs.h"
+#include "BlockType.h"
+#include "Blocks/Mixins.h"
+#include "../BlockInfo.h"
+#include "../Chunk.h"
+#include "ChunkDef.h"
+
@@ -154,9 +162,26 @@ class cBlockRailHandler final :
private:
+ static bool CanBeSupportedBy(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
+ {
+ if (cBlockSlabHandler::IsAnySlabType(a_BlockType))
+ {
+ return (a_BlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN);
+ }
+ else if (cBlockStairsHandler::IsAnyStairType(a_BlockType))
+ {
+ return (a_BlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN);
+ }
+ return cBlockInfo::FullyOccupiesVoxel(a_BlockType);
+ }
+
virtual bool CanBeAt(const cChunk & a_Chunk, const Vector3i a_Position, NIBBLETYPE a_Meta) const override
{
- if ((a_Position.y <= 0) || !cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(a_Position.addedY(-1))))
+ BLOCKTYPE BelowBlock;
+ NIBBLETYPE BelowBlockMeta;
+ a_Chunk.GetBlockTypeMeta(a_Position.addedY(-1), BelowBlock, BelowBlockMeta);
+
+ if ((a_Position.y <= 0) || !CanBeSupportedBy(BelowBlock, BelowBlockMeta))
{
return false;
}
@@ -187,6 +212,7 @@ class cBlockRailHandler final :
return cBlockInfo::FullyOccupiesVoxel(BlockType);
}
}
+
return true;
}
diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h
index 4b9650e90b..893691d7bc 100644
--- a/src/Blocks/BlockRedstoneRepeater.h
+++ b/src/Blocks/BlockRedstoneRepeater.h
@@ -2,9 +2,11 @@
#pragma once
#include "BlockHandler.h"
+#include "BlockType.h"
#include "Mixins.h"
#include "ChunkInterface.h"
#include "BlockSlab.h"
+#include "BlockStairs.h"
#include "../Chunk.h"
@@ -120,14 +122,19 @@ class cBlockRedstoneRepeaterHandler final :
{
return true;
}
- else if (cBlockSlabHandler::IsAnySlabType(BelowBlock))
+
+ // upside down slabs
+ if (cBlockSlabHandler::IsAnySlabType(BelowBlock))
{
- // Check if the slab is turned up side down
- if ((BelowBlockMeta & 0x08) == 0x08)
- {
- return true;
- }
+ return BelowBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN;
}
+
+ // upside down stairs
+ if (cBlockStairsHandler::IsAnyStairType(BelowBlock))
+ {
+ return BelowBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN;
+ }
+
return false;
}
diff --git a/src/Blocks/BlockRedstoneWire.h b/src/Blocks/BlockRedstoneWire.h
index 3976afa906..de8e59a402 100644
--- a/src/Blocks/BlockRedstoneWire.h
+++ b/src/Blocks/BlockRedstoneWire.h
@@ -3,7 +3,8 @@
#include "BlockHandler.h"
#include "BlockSlab.h"
-
+#include "BlockStairs.h"
+#include "../Chunk.h"
@@ -34,14 +35,19 @@ class cBlockRedstoneWireHandler final :
{
return true;
}
- else if (cBlockSlabHandler::IsAnySlabType(BelowBlock))
+
+ // upside down slabs
+ if (cBlockSlabHandler::IsAnySlabType(BelowBlock))
+ {
+ return BelowBlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN;
+ }
+
+ // upside down stairs
+ if (cBlockStairsHandler::IsAnyStairType(BelowBlock))
{
- // Check if the slab is turned up side down
- if ((BelowBlockMeta & 0x08) == 0x08)
- {
- return true;
- }
+ return BelowBlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN;
}
+
return false;
}
diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h
index 55a9e877ef..76614bb620 100644
--- a/src/Blocks/BlockStairs.h
+++ b/src/Blocks/BlockStairs.h
@@ -16,6 +16,32 @@ class cBlockStairsHandler final :
using Super::Super;
+ static bool IsAnyStairType(BLOCKTYPE a_Block)
+ {
+ switch (a_Block)
+ {
+ case E_BLOCK_SANDSTONE_STAIRS:
+ case E_BLOCK_BIRCH_WOOD_STAIRS:
+ case E_BLOCK_QUARTZ_STAIRS:
+ case E_BLOCK_JUNGLE_WOOD_STAIRS:
+ case E_BLOCK_RED_SANDSTONE_STAIRS:
+ case E_BLOCK_COBBLESTONE_STAIRS:
+ case E_BLOCK_STONE_BRICK_STAIRS:
+ case E_BLOCK_OAK_WOOD_STAIRS:
+ case E_BLOCK_ACACIA_WOOD_STAIRS:
+ case E_BLOCK_PURPUR_STAIRS:
+ case E_BLOCK_DARK_OAK_WOOD_STAIRS:
+ case E_BLOCK_BRICK_STAIRS:
+ case E_BLOCK_NETHER_BRICK_STAIRS:
+ case E_BLOCK_SPRUCE_WOOD_STAIRS:
+ return true;
+ default:
+ {
+ return false;
+ }
+ }
+ }
+
private:
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) const override
@@ -25,9 +51,6 @@ class cBlockStairsHandler final :
}
-
-
-
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const override
{
UNUSED(a_Meta);
diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h
index 0b96ad2464..ad69cf5eb6 100644
--- a/src/Blocks/BlockTorch.h
+++ b/src/Blocks/BlockTorch.h
@@ -1,8 +1,12 @@
#pragma once
#include "BlockHandler.h"
+#include "BlockSlab.h"
+#include "BlockStairs.h"
#include "../Chunk.h"
+#include "BlockType.h"
#include "ChunkInterface.h"
+#include "Defines.h"
#include "Mixins.h"
@@ -22,6 +26,34 @@ class cBlockTorchBaseHandler :
/** Returns true if the torch can be placed on the specified block's face. */
static bool CanBePlacedOn(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_BlockFace)
{
+ // upside down slabs
+ if (cBlockSlabHandler::IsAnySlabType(a_BlockType))
+ {
+ return (a_BlockFace == BLOCK_FACE_YP) && (a_BlockMeta & E_META_WOODEN_SLAB_UPSIDE_DOWN);
+ }
+
+ // stairs (top and sides)
+ if (cBlockStairsHandler::IsAnyStairType(a_BlockType))
+ {
+ switch (a_BlockFace)
+ {
+ case eBlockFace::BLOCK_FACE_YP:
+ return (a_BlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN);
+ case eBlockFace::BLOCK_FACE_XP:
+ return ((a_BlockMeta & 0b11) == E_BLOCK_STAIRS_XP);
+ case eBlockFace::BLOCK_FACE_XM:
+ return ((a_BlockMeta & 0b11) == E_BLOCK_STAIRS_XM);
+ case eBlockFace::BLOCK_FACE_ZP:
+ return ((a_BlockMeta & 0b11) == E_BLOCK_STAIRS_ZP);
+ case eBlockFace::BLOCK_FACE_ZM:
+ return ((a_BlockMeta & 0b11) == E_BLOCK_STAIRS_ZM);
+ default:
+ {
+ return false;
+ }
+ }
+ }
+
switch (a_BlockType)
{
case E_BLOCK_END_PORTAL_FRAME:
@@ -44,28 +76,6 @@ class cBlockTorchBaseHandler :
// Torches can only be placed on top of these blocks
return (a_BlockFace == BLOCK_FACE_YP);
}
- case E_BLOCK_STONE_SLAB:
- case E_BLOCK_WOODEN_SLAB:
- {
- // Toches can be placed only on the top of top-half-slabs
- return ((a_BlockFace == BLOCK_FACE_YP) && ((a_BlockMeta & 0x08) == 0x08));
- }
- case E_BLOCK_OAK_WOOD_STAIRS:
- case E_BLOCK_COBBLESTONE_STAIRS:
- case E_BLOCK_BRICK_STAIRS:
- case E_BLOCK_STONE_BRICK_STAIRS:
- case E_BLOCK_NETHER_BRICK_STAIRS:
- case E_BLOCK_SANDSTONE_STAIRS:
- case E_BLOCK_SPRUCE_WOOD_STAIRS:
- case E_BLOCK_BIRCH_WOOD_STAIRS:
- case E_BLOCK_JUNGLE_WOOD_STAIRS:
- case E_BLOCK_QUARTZ_STAIRS:
- case E_BLOCK_ACACIA_WOOD_STAIRS:
- case E_BLOCK_DARK_OAK_WOOD_STAIRS:
- case E_BLOCK_RED_SANDSTONE_STAIRS:
- {
- return (a_BlockFace == BLOCK_FACE_TOP) && (a_BlockMeta & E_BLOCK_STAIRS_UPSIDE_DOWN);
- }
default:
{
if (cBlockInfo::FullyOccupiesVoxel(a_BlockType))
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index 46f2ba0d48..8121fc3efe 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -214,6 +214,24 @@ size_t cByteBuffer::GetReadableSpace(void) const
+bool cByteBuffer::CanBEInt8Represent(int a_Value)
+{
+ return (-128 <= a_Value) && (a_Value <= 127);
+}
+
+
+
+
+
+bool cByteBuffer::CanBEInt16Represent(int a_Value)
+{
+ return (-32768 <= a_Value) && (a_Value <= 32767);
+}
+
+
+
+
+
bool cByteBuffer::CanReadBytes(size_t a_Count) const
{
CHECK_THREAD
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index 1d108fca22..6648871327 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -31,6 +31,7 @@ their own synchronization.
class cByteBuffer
{
public:
+
cByteBuffer(size_t a_BufferSize);
~cByteBuffer();
@@ -47,7 +48,13 @@ class cByteBuffer
size_t GetReadableSpace(void) const;
/** Returns the current data start index. For debugging purposes. */
- size_t GetDataStart(void) const { return m_DataStart; }
+ size_t GetDataStart(void) const { return m_DataStart; }
+
+ /** Returns if the given value can fit in a protocol big-endian 8 bit integer. */
+ static bool CanBEInt8Represent(int a_Value);
+
+ /** Returns if the given value can fit in a protocol big-endian 16 bit integer. */
+ static bool CanBEInt16Represent(int a_Value);
/** Returns true if the specified amount of bytes are available for reading */
bool CanReadBytes(size_t a_Count) const;
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 4bf4557d92..c9bd1dbcff 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -684,21 +684,6 @@ void cChunk::SpawnMobs(cMobSpawner & a_MobSpawner)
void cChunk::Tick(std::chrono::milliseconds a_Dt)
{
- const auto ShouldTick = ShouldBeTicked();
-
- // If we are not valid, tick players and bailout
- if (!ShouldTick)
- {
- for (const auto & Entity : m_Entities)
- {
- if (Entity->IsPlayer())
- {
- Entity->Tick(a_Dt, *this);
- }
- }
- return;
- }
-
TickBlocks();
// Tick all block entities in this chunk:
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 16e8fa2670..7dd7901fd5 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -1347,7 +1347,10 @@ void cChunkMap::Tick(std::chrono::milliseconds a_Dt)
// Do the magic of updating the world:
for (auto & Chunk : m_Chunks)
{
- Chunk.second.Tick(a_Dt);
+ if (Chunk.second.ShouldBeTicked())
+ {
+ Chunk.second.Tick(a_Dt);
+ }
}
// Finally, only after all chunks are ticked, tell the client about all aggregated changes:
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 5a2e1d6206..7fc678de00 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1884,6 +1884,19 @@ void cClientHandle::HandleUseItem(bool a_UsedMainHand)
+void cClientHandle::HandleResourcePack(UInt8 a_Status)
+{
+ // Kick player if client declined the resource pack
+ if ((a_Status == 1) && cRoot::Get()->GetServer()->ShouldRequireResourcePack())
+ {
+ Kick("You must accept the resource pack");
+ }
+}
+
+
+
+
+
void cClientHandle::HandleRespawn(void)
{
if (m_Player->GetHealth() > 0)
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index c5949b57b7..a452d765af 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -377,6 +377,7 @@ class cClientHandle // tolua_export
void HandlePluginMessage (const AString & a_Channel, ContiguousByteBufferView a_Message);
+ void HandleResourcePack (UInt8 a_Status);
void HandleRespawn (void);
void HandleRightClick (Vector3i a_BlockPos, eBlockFace a_BlockFace, Vector3i a_Cursor, bool a_UsedMainHand);
void HandleSlotSelected (Int16 a_SlotNum);
diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp
index 46712a0f52..94ed781977 100644
--- a/src/CompositeChat.cpp
+++ b/src/CompositeChat.cpp
@@ -96,50 +96,52 @@ void cCompositeChat::AddShowAchievementPart(const AString & a_PlayerName, const
-
+/**
+* Parse the input message to add colors or link then add it to the object.
+*
+* It detects every & of the message and the next character for it to colorize.
+* It detect : in the text to detect link structures.
+*
+* @param a_ParseText The input text to parse
+*/
void cCompositeChat::ParseText(const AString & a_ParseText)
{
size_t len = a_ParseText.length();
- size_t first = 0; // First character of the currently parsed block
+ size_t cursor = 0;
AString CurrentStyle;
AString CurrentText;
+
for (size_t i = 0; i < len; i++)
{
switch (a_ParseText[i])
{
- case '@':
+ case '&': //< Color code
{
- // Color code
- i++;
- if (i >= len)
+ if ((i != 0) && (a_ParseText[i-1] == '\\'))
{
- // Not enough following text
- break;
+ CurrentText.append(a_ParseText, cursor, i - cursor - 1).append("&");
+ AddTextPart(CurrentText, CurrentStyle);
+ CurrentText.clear();
+ cursor = ++i;
+ continue;
}
- if (a_ParseText[i] == '@')
+
+ if (cursor < i)
{
- // "@@" escape, just put a "@" into the current text and keep parsing as text
- if (i > first + 1)
- {
- CurrentText.append(a_ParseText.c_str() + first, i - first - 1);
- }
- first = i + 1;
- continue;
+ CurrentText.append(a_ParseText, cursor, i - cursor);
+ AddTextPart(CurrentText, CurrentStyle);
+ CurrentText.clear();
+ }
+ i++;
+ cursor = i + 1;
+
+ if (a_ParseText[i] == 'r')
+ {
+ CurrentStyle = "";
}
else
{
- // True color code. Create a part for the CurrentText and start parsing anew:
- if (i >= first)
- {
- CurrentText.append(a_ParseText.c_str() + first, i - first - 1);
- first = i + 1;
- }
- if (!CurrentText.empty())
- {
- AddTextPart(CurrentText, CurrentStyle);
- CurrentText.clear();
- }
- AddStyle(CurrentStyle, a_ParseText.substr(i - 1, 2));
+ CurrentStyle.push_back(a_ParseText[i]);
}
break;
}
@@ -157,15 +159,15 @@ void cCompositeChat::ParseText(const AString & a_ParseText)
{
size_t PrefixLen = Prefix.size();
if (
- (i >= first + PrefixLen) && // There is enough space in front of the colon for the prefix
+ (i >= cursor + PrefixLen) && // There is enough space in front of the colon for the prefix
(std::string_view(a_ParseText).substr(i - PrefixLen, PrefixLen) == Prefix) // the prefix matches
)
{
// Add everything before this as a text part:
- if (i > first + PrefixLen)
+ if (i > cursor+ PrefixLen)
{
- CurrentText.append(a_ParseText.c_str() + first, i - first - PrefixLen);
- first = i - PrefixLen;
+ CurrentText.append(a_ParseText.c_str() + cursor, i - cursor - PrefixLen);
+ cursor= i - PrefixLen;
}
if (!CurrentText.empty())
{
@@ -181,8 +183,8 @@ void cCompositeChat::ParseText(const AString & a_ParseText)
break;
}
}
- AddUrlPart(a_ParseText.substr(first, i - first), a_ParseText.substr(first, i - first), CurrentStyle);
- first = i;
+ AddUrlPart(a_ParseText.substr(cursor, i - cursor), a_ParseText.substr(cursor, i - cursor), CurrentStyle);
+ cursor = i;
break;
}
} // for Prefix - LinkPrefix[]
@@ -190,9 +192,11 @@ void cCompositeChat::ParseText(const AString & a_ParseText)
} // case ':'
} // switch (a_ParseText[i])
} // for i - a_ParseText[]
- if (first < len)
+ if (cursor < len)
{
- AddTextPart(a_ParseText.substr(first, len - first), CurrentStyle);
+ CurrentText.clear();
+ CurrentText.append(a_ParseText, cursor, len - cursor);
+ AddTextPart(CurrentText, CurrentStyle);
}
}
@@ -218,7 +222,7 @@ void cCompositeChat::UnderlineUrls(void)
{
[](TextPart & a_Part) { },
[](ClientTranslatedPart & a_Part) { },
- [](UrlPart & a_Part) { a_Part.Style += 'u'; },
+ [](UrlPart & a_Part) { a_Part.Style += 'n'; },
[](RunCommandPart & a_Part) { },
[](SuggestCommandPart & a_Part) { },
[](ShowAchievementPart & a_Part) { },
@@ -276,29 +280,6 @@ eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType)
-void cCompositeChat::AddStyle(AString & a_Style, const AString & a_AddStyle)
-{
- if (a_AddStyle.empty())
- {
- return;
- }
- if (a_AddStyle[0] == '@')
- {
- size_t idx = a_Style.find('@');
- if ((idx != AString::npos) && (idx != a_Style.length()))
- {
- a_Style.erase(idx, 2);
- }
- a_Style.append(a_AddStyle);
- return;
- }
- a_Style.append(a_AddStyle);
-}
-
-
-
-
-
AString cCompositeChat::CreateJsonString(bool a_ShouldUseChatPrefixes) const
{
Json::Value Message;
@@ -404,70 +385,34 @@ void cCompositeChat::AddChatPartStyle(Json::Value & a_Value, const AString & a_P
{
switch (a_PartStyle[i])
{
- case 'b':
- {
- // bold
- a_Value["bold"] = Json::Value(true);
- break;
- }
-
- case 'i':
- {
- // italic
- a_Value["italic"] = Json::Value(true);
- break;
- }
-
- case 'u':
- {
- // Underlined
- a_Value["underlined"] = Json::Value(true);
- break;
- }
+ case 'k': a_Value["obfuscated"] = Json::Value(true); break;
+ case 'l': a_Value["bold"] = Json::Value(true); break;
+ case 's': // Deprecated
+ LOGERROR("Value s in AddChatPartStyle() is deprecated");
+ case 'm': a_Value["strikethrough"] = Json::Value(true); break;
+ case 'u': // Deprecated
+ LOGERROR("Value u in AddChatPartStyle() is deprecated");
+ case 'n': a_Value["underlined"] = Json::Value(true); break;
+ case 'i': // Deprecated
+ LOGERROR("Value i in AddChatPartStyle() is deprecated");
+ case 'o': a_Value["italic"] = Json::Value(true); break;
+ case '0': a_Value["color"] = Json::Value("black"); break;
+ case '1': a_Value["color"] = Json::Value("dark_blue"); break;
+ case '2': a_Value["color"] = Json::Value("dark_green"); break;
+ case '3': a_Value["color"] = Json::Value("dark_aqua"); break;
+ case '4': a_Value["color"] = Json::Value("dark_red"); break;
+ case '5': a_Value["color"] = Json::Value("dark_purple"); break;
+ case '6': a_Value["color"] = Json::Value("gold"); break;
+ case '7': a_Value["color"] = Json::Value("gray"); break;
+ case '8': a_Value["color"] = Json::Value("dark_gray"); break;
+ case '9': a_Value["color"] = Json::Value("blue"); break;
+ case 'a': a_Value["color"] = Json::Value("green"); break;
+ case 'b': a_Value["color"] = Json::Value("aqua"); break;
+ case 'c': a_Value["color"] = Json::Value("red"); break;
+ case 'd': a_Value["color"] = Json::Value("light_purple"); break;
+ case 'e': a_Value["color"] = Json::Value("yellow"); break;
+ case 'f': a_Value["color"] = Json::Value("white"); break;
- case 's':
- {
- // strikethrough
- a_Value["strikethrough"] = Json::Value(true);
- break;
- }
-
- case 'o':
- {
- // obfuscated
- a_Value["obfuscated"] = Json::Value(true);
- break;
- }
-
- case '@':
- {
- // Color, specified by the next char:
- i++;
- if (i >= len)
- {
- // String too short, didn't contain a color
- break;
- }
- switch (a_PartStyle[i])
- {
- case '0': a_Value["color"] = Json::Value("black"); break;
- case '1': a_Value["color"] = Json::Value("dark_blue"); break;
- case '2': a_Value["color"] = Json::Value("dark_green"); break;
- case '3': a_Value["color"] = Json::Value("dark_aqua"); break;
- case '4': a_Value["color"] = Json::Value("dark_red"); break;
- case '5': a_Value["color"] = Json::Value("dark_purple"); break;
- case '6': a_Value["color"] = Json::Value("gold"); break;
- case '7': a_Value["color"] = Json::Value("gray"); break;
- case '8': a_Value["color"] = Json::Value("dark_gray"); break;
- case '9': a_Value["color"] = Json::Value("blue"); break;
- case 'a': a_Value["color"] = Json::Value("green"); break;
- case 'b': a_Value["color"] = Json::Value("aqua"); break;
- case 'c': a_Value["color"] = Json::Value("red"); break;
- case 'd': a_Value["color"] = Json::Value("light_purple"); break;
- case 'e': a_Value["color"] = Json::Value("yellow"); break;
- case 'f': a_Value["color"] = Json::Value("white"); break;
- } // switch (color)
- } // case '@'
} // switch (Style[i])
} // for i - a_PartStyle[]
}
diff --git a/src/CompositeChat.h b/src/CompositeChat.h
index 78c8e0c9b7..4150bccc4e 100644
--- a/src/CompositeChat.h
+++ b/src/CompositeChat.h
@@ -21,12 +21,13 @@ Each part corresponds roughly to the behavior supported by the client messaging:
- clickable commands (suggest)
Each part has a text assigned to it that can be styled. The style is specified using a string,
each character / character combination in the string specifies the style to use:
- - b = bold
- - i = italic
- - u = underlined
- - s = strikethrough
- - o = obfuscated
- - @X = color X (X is 0 - 9 or a - f, same as dye meta
+ - (char from 0 - 9 or a - f) = color X
+ - k = obfuscated
+ - l = bold
+ - m = strikethrough
+ - n = underlined
+ - o = italic
+ - r = reset
If the protocol version doesn't support all the features, it degrades gracefully.
*/
class cCompositeChat
@@ -102,7 +103,7 @@ class cCompositeChat
cCompositeChat(void);
/** Creates a new chat message and parses the text into parts.
- Recognizes "http:" and "https:" links and @color-codes.
+ Recognizes "http:" and "https:" links and &format-character.
Uses ParseText() for the actual parsing.
Exported manually due to ToLua++ generating extra output parameter. */
cCompositeChat(const AString & a_ParseText, eMessageType a_MessageType = mtCustom);
@@ -121,15 +122,15 @@ class cCompositeChat
/** Adds a part that opens an URL when clicked.
The default style is underlined light blue text. */
- void AddUrlPart(const AString & a_Text, const AString & a_Url, const AString & a_Style = "u@c");
+ void AddUrlPart(const AString & a_Text, const AString & a_Url, const AString & a_Style = "nc");
/** Adds a part that runs a command when clicked.
The default style is underlined light green text. */
- void AddRunCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style = "u@a");
+ void AddRunCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style = "na");
/** Adds a part that suggests a command (enters it into the chat message area, but doesn't send) when clicked.
The default style is underlined yellow text. */
- void AddSuggestCommandPart(const AString & a_Text, const AString & a_SuggestedCommand, const AString & a_Style = "u@b");
+ void AddSuggestCommandPart(const AString & a_Text, const AString & a_SuggestedCommand, const AString & a_Style = "nb");
/** Adds a part that fully formats a specified achievement using client translatable strings
Takes achievement name and player awarded to. Displays as {player} has earned the achievement {achievement_name}.
@@ -137,7 +138,7 @@ class cCompositeChat
void AddShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style = "");
/** Parses text into various parts, adds those.
- Recognizes "http:" and "https:" URLs and @color-codes. */
+ Recognizes "http:" and "https:" URLs and &color-codes. */
void ParseText(const AString & a_ParseText);
/** Adds the "underline" style to each part that is an URL. */
@@ -185,8 +186,4 @@ class cCompositeChat
/** Additional data pertaining to message type, for example, the name of a mtPrivateMsg sender */
AString m_AdditionalMessageTypeData;
-
- /** Adds a_AddStyle to a_Style; overwrites the existing style if appropriate.
- If the style already contains something that a_AddStyle overrides, it is erased first. */
- void AddStyle(AString & a_Style, const AString & a_AddStyle);
} ; // tolua_export
diff --git a/src/Defines.h b/src/Defines.h
index bbe5d3d3df..ab0a639c49 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -314,6 +314,7 @@ enum eExplosionSource
esOther,
esPlugin,
esPrimedTNT,
+ esTNTMinecart,
esWitherBirth,
esWitherSkull,
esMax,
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 0718da06c5..c46f9e6446 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -1970,7 +1970,7 @@ void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
return;
}
- if (GetSpeed().SqrLength() > 0.001)
+ if (m_Speed.HasNonZeroLength())
{
// Movin'
m_World->BroadcastEntityVelocity(*this, a_Exclude);
@@ -1986,8 +1986,7 @@ void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
m_bHasSentNoSpeed = true;
}
- Vector3i Diff = (GetPosition() * 32.0).Floor() - (m_LastSentPosition * 32.0).Floor();
- if (Diff.HasNonZeroLength()) // Have we moved?
+ if ((m_Position - m_LastSentPosition).HasNonZeroLength()) // Have we moved?
{
m_World->BroadcastEntityPosition(*this, a_Exclude);
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index 50be91e4e3..d8dbc10c19 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -6,6 +6,8 @@
// Indiana Jones!
#include "Globals.h"
+#include "ChunkDef.h"
+#include "Defines.h"
#include "Minecart.h"
#include "../BlockInfo.h"
#include "../ClientHandle.h"
@@ -223,7 +225,7 @@ void cMinecart::HandlePhysics(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
switch (InsideType)
{
case E_BLOCK_RAIL: HandleRailPhysics(InsideMeta, a_Dt); break;
- case E_BLOCK_ACTIVATOR_RAIL: break;
+ case E_BLOCK_ACTIVATOR_RAIL: HandleActivatorRailPhysics(InsideMeta, a_Dt); break;
case E_BLOCK_POWERED_RAIL: HandlePoweredRailPhysics(InsideMeta); break;
case E_BLOCK_DETECTOR_RAIL:
{
@@ -678,6 +680,7 @@ void cMinecart::HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::mi
void cMinecart::HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt)
{
HandleRailPhysics(a_RailMeta & 0x07, a_Dt);
+ // TODO - shake minecart, throw entities out
}
@@ -1516,7 +1519,22 @@ cMinecartWithTNT::cMinecartWithTNT(Vector3d a_Pos):
{
}
-// TODO: Make it activate when passing over activator rail
+
+
+
+
+void cMinecartWithTNT::HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt)
+{
+ Super::HandleActivatorRailPhysics(a_RailMeta, a_Dt);
+
+ if ((a_RailMeta & 0x08) && !m_isTNTFused)
+ {
+ m_isTNTFused = true;
+ m_TNTFuseTicksLeft = 80;
+ m_World->BroadcastSoundEffect("entity.tnt.primed", GetPosition(), 1.0f, 1.0f);
+ m_World->BroadcastEntityAnimation(*this, EntityAnimation::MinecartTNTIgnites);
+ }
+}
@@ -1531,6 +1549,32 @@ void cMinecartWithTNT::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+void cMinecartWithTNT::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
+{
+ Super::Tick(a_Dt, a_Chunk);
+ if (!IsTicking())
+ {
+ return;
+ }
+
+ if (m_isTNTFused)
+ {
+ if (m_TNTFuseTicksLeft > 0)
+ {
+ --m_TNTFuseTicksLeft;
+ }
+ else
+ {
+ Destroy();
+ m_World->DoExplosionAt(4.0, GetPosX(), GetPosY() + GetHeight() / 2, GetPosZ(), true, esTNTMinecart, this);
+ }
+ }
+}
+
+
+
+
+
////////////////////////////////////////////////////////////////////////////////
// cMinecartWithHopper:
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index 0d62d98f1d..0e63363307 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -72,8 +72,8 @@ class cMinecart :
*/
void HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt);
- /** Handles activator rails - placeholder for future implementation */
- void HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt);
+ /** Handles activator rails */
+ virtual void HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt);
/** Snaps a mincecart to a rail's axis, resetting its speed
For curved rails, it changes the cart's direction as well as snapping it to axis */
@@ -89,7 +89,6 @@ class cMinecart :
/** Tests if this mincecart's bounding box is intersecting another entity's bounding box (collision) and pushes mincecart away if necessary */
bool TestEntityCollision(NIBBLETYPE a_RailMeta);
-
} ;
@@ -222,10 +221,14 @@ class cMinecartWithTNT final :
CLASS_PROTODEF(cMinecartWithTNT)
cMinecartWithTNT(Vector3d a_Pos);
+ void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
private:
+ int m_TNTFuseTicksLeft;
+ bool m_isTNTFused = false;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
+ void HandleActivatorRailPhysics(NIBBLETYPE a_RailMeta, std::chrono::milliseconds a_Dt) override;
} ;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 04a7f9be0d..9f4fcb971b 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -3156,8 +3156,6 @@ void cPlayer::SpawnOn(cClientHandle & a_Client)
void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
- m_ClientHandle->Tick(a_Dt);
-
if (m_ClientHandle->IsDestroyed())
{
Destroy();
@@ -3182,13 +3180,6 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
}
}
- if (!a_Chunk.IsValid())
- {
- // Players are ticked even if the parent chunk is invalid.
- // We've processed as much as we can, bail:
- return;
- }
-
ASSERT((GetParentChunk() != nullptr) && (GetParentChunk()->IsValid()));
ASSERT(a_Chunk.IsValid());
diff --git a/src/Protocol/MojangAPI.cpp b/src/Protocol/MojangAPI.cpp
index 6b89992166..d1914f4d30 100644
--- a/src/Protocol/MojangAPI.cpp
+++ b/src/Protocol/MojangAPI.cpp
@@ -43,103 +43,80 @@ const int MAX_PER_QUERY = 100;
static cX509CertPtr GetCACerts(void)
{
static const char CertString[] =
- // GeoTrust root CA cert
- // Currently used for signing *.mojang.com's cert
- // Exported from Mozilla Firefox's built-in CA repository
+ // DigiCert Global Root CA (sessionserver.mojang.com)
+ // Downloaded from https://www.digicert.com/kb/digicert-root-certificates.htm
"-----BEGIN CERTIFICATE-----\n"
- "MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n"
- "MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\n"
- "YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG\n"
- "EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg\n"
- "R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9\n"
- "9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq\n"
- "fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv\n"
- "iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU\n"
- "1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+\n"
- "bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW\n"
- "MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA\n"
- "ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l\n"
- "uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn\n"
- "Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS\n"
- "tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n"
- "PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un\n"
- "hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV\n"
- "5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==\n"
- "-----END CERTIFICATE-----\n\n"
-
- // Equifax root CA cert
- // Exported from Mozilla Firefox's built-in CA repository
- "-----BEGIN CERTIFICATE-----\n"
- "MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV\n"
- "UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy\n"
- "dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1\n"
- "MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx\n"
- "dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B\n"
- "AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f\n"
- "BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A\n"
- "cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC\n"
- "AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ\n"
- "MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm\n"
- "aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw\n"
- "ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj\n"
- "IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF\n"
- "MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA\n"
- "A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y\n"
- "7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh\n"
- "1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4\n"
- "-----END CERTIFICATE-----\n\n"
-
- // Starfield G2 cert
- // This is the data of the root certs for Starfield Technologies, the CA that used to sign sessionserver.mojang.com's cert
- // Downloaded from https://certs.starfieldtech.com/repository/
+ "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n"
+ "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
+ "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"
+ "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n"
+ "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
+ "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n"
+ "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n"
+ "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n"
+ "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n"
+ "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n"
+ "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n"
+ "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n"
+ "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n"
+ "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n"
+ "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n"
+ "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n"
+ "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n"
+ "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n"
+ "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n"
+ "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n"
+ "-----END CERTIFICATE-----\n"
+
+ // Amazon Root CA 1 (api.mojang.com)
+ // Downloaded from https://www.amazontrust.com/repository/
"-----BEGIN CERTIFICATE-----\n"
- "MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\n"
- "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n"
- "HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs\n"
- "ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw\n"
- "MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\n"
- "b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj\n"
- "aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp\n"
- "Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
- "ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\n"
- "nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1\n"
- "HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N\n"
- "Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN\n"
- "dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0\n"
- "HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\n"
- "BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G\n"
- "CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU\n"
- "sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3\n"
- "4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n"
- "8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\n"
- "pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\n"
- "mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n"
- "-----END CERTIFICATE-----\n\n"
-
- // Starfield original (G1) cert:
+ "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n"
+ "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n"
+ "b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n"
+ "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n"
+ "b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n"
+ "ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n"
+ "9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n"
+ "IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n"
+ "VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n"
+ "93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n"
+ "jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n"
+ "AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n"
+ "A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n"
+ "U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n"
+ "N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n"
+ "o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n"
+ "5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n"
+ "rqXRfboQnoZsG4q5WTP468SQvvG5\n"
+ "-----END CERTIFICATE-----\n"
+
+ // AAA Certificate Services (authserver.ely.by GH#4832)
+ // Downloaded from https://www.tbs-certificates.co.uk/FAQ/en/Comodo_AAA_Certificate_Services.html
"-----BEGIN CERTIFICATE-----\n"
- "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n"
- "MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n"
- "U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n"
- "NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n"
- "ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n"
- "ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n"
- "DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n"
- "8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n"
- "+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n"
- "X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n"
- "K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n"
- "1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n"
- "A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n"
- "zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n"
- "YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n"
- "bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n"
- "DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n"
- "L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n"
- "eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n"
- "xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n"
- "VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n"
- "WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n"
+ "MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb\n"
+ "MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow\n"
+ "GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj\n"
+ "YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL\n"
+ "MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n"
+ "BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM\n"
+ "GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP\n"
+ "ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua\n"
+ "BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe\n"
+ "3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4\n"
+ "YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR\n"
+ "rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm\n"
+ "ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU\n"
+ "oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\n"
+ "MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v\n"
+ "QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t\n"
+ "b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF\n"
+ "AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q\n"
+ "GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz\n"
+ "Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2\n"
+ "G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi\n"
+ "l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3\n"
+ "smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\n"
"-----END CERTIFICATE-----\n"
;
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index f1d85f0144..4bcbd4f1a4 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -330,7 +330,7 @@ class cProtocol
Pose
};
- // TODO: these constants should be in WebServer
+ /** The protocol version number, received from the client in the Handshake packet. */
enum class Version
{
v1_8_0 = 47,
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 7dbfbda8ca..ffe839dac9 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -146,8 +146,6 @@ void cMultiVersionProtocol::HandleIncomingDataInOldPingResponseStage(cClientHand
return;
}
- cByteBuffer OutPacketBuffer(6 KiB);
-
// Handle server list ping packets
for (;;)
{
@@ -166,11 +164,11 @@ void cMultiVersionProtocol::HandleIncomingDataInOldPingResponseStage(cClientHand
if ((PacketID == 0x00) && (PacketLen == 1)) // Request packet
{
- HandlePacketStatusRequest(a_Client, OutPacketBuffer);
+ HandlePacketStatusRequest(a_Client);
}
else if ((PacketID == 0x01) && (PacketLen == 9)) // Ping packet
{
- HandlePacketStatusPing(a_Client, OutPacketBuffer);
+ HandlePacketStatusPing(a_Client);
}
else
{
@@ -412,7 +410,7 @@ UInt32 cMultiVersionProtocol::GetPacketID(cProtocol::ePacketType a_PacketType)
-void cMultiVersionProtocol::HandlePacketStatusRequest(cClientHandle & a_Client, cByteBuffer & a_Out)
+void cMultiVersionProtocol::HandlePacketStatusRequest(cClientHandle & a_Client)
{
cServer * Server = cRoot::Get()->GetServer();
AString ServerDescription = Server->GetDescription();
@@ -445,20 +443,20 @@ void cMultiVersionProtocol::HandlePacketStatusRequest(cClientHandle & a_Client,
{
ResponseValue["favicon"] = Printf("data:image/png;base64,%s", Favicon.c_str());
}
-
AString Response = JsonUtils::WriteFastString(ResponseValue);
- VERIFY(a_Out.WriteVarInt32(GetPacketID(cProtocol::ePacketType::pktStatusResponse)));
- VERIFY(a_Out.WriteVarUTF8String(Response));
-
- SendPacket(a_Client, a_Out);
+ // Send the response in a packet:
+ cByteBuffer out(Response.size() + 12); // String + 2x VarInt + extra space for safety
+ VERIFY(out.WriteVarInt32(GetPacketID(cProtocol::ePacketType::pktStatusResponse)));
+ VERIFY(out.WriteVarUTF8String(Response));
+ SendPacket(a_Client, out);
}
-void cMultiVersionProtocol::HandlePacketStatusPing(cClientHandle & a_Client, cByteBuffer & a_Out)
+void cMultiVersionProtocol::HandlePacketStatusPing(cClientHandle & a_Client)
{
Int64 Timestamp;
if (!m_Buffer.ReadBEInt64(Timestamp))
@@ -466,8 +464,9 @@ void cMultiVersionProtocol::HandlePacketStatusPing(cClientHandle & a_Client, cBy
return;
}
- VERIFY(a_Out.WriteVarInt32(GetPacketID(cProtocol::ePacketType::pktPingResponse)));
- VERIFY(a_Out.WriteBEInt64(Timestamp));
-
- SendPacket(a_Client, a_Out);
+ // Send the ping response packet:
+ cByteBuffer out(16); // VarInt + Int64 + extra space for safety
+ VERIFY(out.WriteVarInt32(GetPacketID(cProtocol::ePacketType::pktPingResponse)));
+ VERIFY(out.WriteBEInt64(Timestamp));
+ SendPacket(a_Client, out);
}
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index 8b7848199d..4309ee8ba0 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -74,10 +74,10 @@ class cMultiVersionProtocol
static UInt32 GetPacketID(cProtocol::ePacketType a_PacketType);
/* Status handler for unrecognised versions. */
- void HandlePacketStatusRequest(cClientHandle & a_Client, cByteBuffer & a_Out);
+ void HandlePacketStatusRequest(cClientHandle & a_Client);
/* Ping handler for unrecognised versions. */
- void HandlePacketStatusPing(cClientHandle & a_Client, cByteBuffer & a_Out);
+ void HandlePacketStatusPing(cClientHandle & a_Client);
/** Buffer for received protocol data. */
cByteBuffer m_Buffer;
diff --git a/src/Protocol/Protocol_1_10.cpp b/src/Protocol/Protocol_1_10.cpp
index 4f89cf6bdf..2e0eb52a79 100644
--- a/src/Protocol/Protocol_1_10.cpp
+++ b/src/Protocol/Protocol_1_10.cpp
@@ -341,6 +341,7 @@ cProtocol::Version cProtocol_1_10_0::GetProtocolVersion() const
void cProtocol_1_10_0::HandlePacketResourcePackStatus(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status);
+ m_Client->HandleResourcePack(Status);
}
diff --git a/src/Protocol/Protocol_1_8.cpp b/src/Protocol/Protocol_1_8.cpp
index cbb13e68e4..d56375a8d8 100644
--- a/src/Protocol/Protocol_1_8.cpp
+++ b/src/Protocol/Protocol_1_8.cpp
@@ -579,12 +579,15 @@ void cProtocol_1_8_0::SendEntityPosition(const cEntity & a_Entity)
{
ASSERT(m_State == 3); // In game mode?
- const auto Delta = (a_Entity.GetPosition() - a_Entity.GetLastSentPosition()) * 32;
+ const auto Delta = (a_Entity.GetPosition() * 32).Floor() - (a_Entity.GetLastSentPosition() * 32).Floor();
- // Limitations of a byte
- static const auto Max = std::numeric_limits::max();
-
- if ((std::abs(Delta.x) <= Max) && (std::abs(Delta.y) <= Max) && (std::abs(Delta.z) <= Max))
+ // Ensure that the delta has enough precision and is within range of a BEInt8:
+ if (
+ Delta.HasNonZeroLength() &&
+ cByteBuffer::CanBEInt8Represent(Delta.x) &&
+ cByteBuffer::CanBEInt8Represent(Delta.y) &&
+ cByteBuffer::CanBEInt8Represent(Delta.z)
+ )
{
const auto Move = static_cast>(Delta);
@@ -613,8 +616,16 @@ void cProtocol_1_8_0::SendEntityPosition(const cEntity & a_Entity)
return;
}
- // Too big a movement, do a teleport
- SendEntityTeleport(a_Entity);
+ // Too big or small a movement, do a teleport.
+
+ cPacketizer Pkt(*this, pktTeleportEntity);
+ Pkt.WriteVarInt32(a_Entity.GetUniqueID());
+ Pkt.WriteFPInt(a_Entity.GetPosX());
+ Pkt.WriteFPInt(a_Entity.GetPosY());
+ Pkt.WriteFPInt(a_Entity.GetPosZ());
+ Pkt.WriteByteAngle(a_Entity.GetYaw());
+ Pkt.WriteByteAngle(a_Entity.GetPitch());
+ Pkt.WriteBool(a_Entity.IsOnGround());
}
@@ -2595,6 +2606,8 @@ void cProtocol_1_8_0::HandlePacketResourcePackStatus(cByteBuffer & a_ByteBuffer)
{
HANDLE_READ(a_ByteBuffer, ReadVarUTF8String, AString, Hash);
HANDLE_READ(a_ByteBuffer, ReadBEUInt8, UInt8, Status);
+
+ m_Client->HandleResourcePack(Status);
}
@@ -4200,22 +4213,6 @@ void cProtocol_1_8_0::HandlePacket(cByteBuffer & a_Buffer)
-void cProtocol_1_8_0::SendEntityTeleport(const cEntity & a_Entity)
-{
- cPacketizer Pkt(*this, pktTeleportEntity);
- Pkt.WriteVarInt32(a_Entity.GetUniqueID());
- Pkt.WriteFPInt(a_Entity.GetPosX());
- Pkt.WriteFPInt(a_Entity.GetPosY());
- Pkt.WriteFPInt(a_Entity.GetPosZ());
- Pkt.WriteByteAngle(a_Entity.GetYaw());
- Pkt.WriteByteAngle(a_Entity.GetPitch());
- Pkt.WriteBool(a_Entity.IsOnGround());
-}
-
-
-
-
-
void cProtocol_1_8_0::StartEncryption(const Byte * a_Key)
{
m_Encryptor.Init(a_Key, a_Key);
diff --git a/src/Protocol/Protocol_1_8.h b/src/Protocol/Protocol_1_8.h
index eaa8813beb..ed13399ef0 100644
--- a/src/Protocol/Protocol_1_8.h
+++ b/src/Protocol/Protocol_1_8.h
@@ -270,10 +270,5 @@ class cProtocol_1_8_0:
/** Handle a complete packet stored in the given buffer. */
void HandlePacket(cByteBuffer & a_Buffer);
- /** Sends an entity teleport packet.
- Mitigates a 1.8 bug where the position in the entity spawn packet is ignored,
- and so entities don't show up until a teleport is sent. */
- void SendEntityTeleport(const cEntity & a_Entity);
-
void StartEncryption(const Byte * a_Key);
} ;
diff --git a/src/Protocol/Protocol_1_9.cpp b/src/Protocol/Protocol_1_9.cpp
index dd2133f774..9a4bcdc4a0 100644
--- a/src/Protocol/Protocol_1_9.cpp
+++ b/src/Protocol/Protocol_1_9.cpp
@@ -307,12 +307,15 @@ void cProtocol_1_9_0::SendEntityPosition(const cEntity & a_Entity)
{
ASSERT(m_State == 3); // In game mode?
- const auto Delta = (a_Entity.GetPosition() - a_Entity.GetLastSentPosition()) * 32 * 128;
+ const auto Delta = (a_Entity.GetPosition() * 32 * 128).Floor() - (a_Entity.GetLastSentPosition() * 32 * 128).Floor();
- // Limitations of a short
- static const auto Max = std::numeric_limits::max();
-
- if ((std::abs(Delta.x) <= Max) && (std::abs(Delta.y) <= Max) && (std::abs(Delta.z) <= Max))
+ // Ensure that the delta has enough precision and is within range of a BEInt16:
+ if (
+ Delta.HasNonZeroLength() &&
+ cByteBuffer::CanBEInt16Represent(Delta.x) &&
+ cByteBuffer::CanBEInt16Represent(Delta.y) &&
+ cByteBuffer::CanBEInt16Represent(Delta.z)
+ )
{
const auto Move = static_cast>(Delta);
@@ -341,7 +344,8 @@ void cProtocol_1_9_0::SendEntityPosition(const cEntity & a_Entity)
return;
}
- // Too big a movement, do a teleport
+ // Too big or small a movement, do a teleport.
+
cPacketizer Pkt(*this, pktTeleportEntity);
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
Pkt.WriteBEDouble(a_Entity.GetPosX());
diff --git a/src/Server.cpp b/src/Server.cpp
index 880ed6c727..36964d41cd 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -157,6 +157,7 @@ bool cServer::InitServer(cSettingsRepositoryInterface & a_Settings, bool a_Shoul
m_MaxPlayers = static_cast(a_Settings.GetValueSetI("Server", "MaxPlayers", 100));
m_bIsHardcore = a_Settings.GetValueSetB("Server", "HardcoreEnabled", false);
m_bAllowMultiLogin = a_Settings.GetValueSetB("Server", "AllowMultiLogin", false);
+ m_RequireResourcePack = a_Settings.GetValueSetB("Server", "RequireResourcePack", false);
m_ResourcePackUrl = a_Settings.GetValueSet("Server", "ResourcePackUrl", "");
m_CustomRedirectUrl = a_Settings.GetValueSet("Server", "CustomRedirectUrl", "https://youtu.be/dQw4w9WgXcQ");
diff --git a/src/Server.h b/src/Server.h
index 479fbb8651..171d68d48c 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -94,6 +94,9 @@ class cServer
// tolua_end
+ /** Returns true if clients must accept resource pack. This is read from the settings. */
+ bool ShouldRequireResourcePack(void) { return m_RequireResourcePack; }
+
const AString & GetResourcePackUrl(void) { return m_ResourcePackUrl; }
std::string_view GetCustomRedirectUrl(void) { return m_CustomRedirectUrl; }
@@ -223,6 +226,7 @@ class cServer
AString m_FaviconData;
size_t m_MaxPlayers;
bool m_bIsHardcore;
+ bool m_RequireResourcePack;
AString m_ResourcePackUrl;
AString m_CustomRedirectUrl;
diff --git a/src/World.cpp b/src/World.cpp
index 57ba656e89..133458a8c2 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1033,6 +1033,7 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La
Player->GetClientHandle()->ProcessProtocolIn();
}
+ TickClients(a_Dt);
TickQueuedChunkDataSets();
TickQueuedBlocks();
m_ChunkMap.Tick(a_Dt);
@@ -1072,6 +1073,18 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La
+void cWorld::TickClients(const std::chrono::milliseconds a_Dt)
+{
+ for (const auto Player : m_Players)
+ {
+ Player->GetClientHandle()->Tick(a_Dt);
+ }
+}
+
+
+
+
+
void cWorld::TickWeather(float a_Dt)
{
UNUSED(a_Dt);
@@ -1382,6 +1395,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
case eExplosionSource::esGhastFireball:
case eExplosionSource::esMonster:
case eExplosionSource::esPrimedTNT:
+ case eExplosionSource::esTNTMinecart:
case eExplosionSource::esWitherBirth:
case eExplosionSource::esWitherSkull:
{
diff --git a/src/World.h b/src/World.h
index ea995ebdcf..b6511edf55 100644
--- a/src/World.h
+++ b/src/World.h
@@ -1107,6 +1107,9 @@ class cWorld // tolua_export
void Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_LastTickDurationMSec);
+ /** Ticks all clients that are in this world. */
+ void TickClients(std::chrono::milliseconds a_Dt);
+
/** Handles the weather in each tick */
void TickWeather(float a_Dt);
diff --git a/tests/CompositeChat/CompositeChatTest.cpp b/tests/CompositeChat/CompositeChatTest.cpp
index 636a5c95ae..ca05e79a2a 100644
--- a/tests/CompositeChat/CompositeChatTest.cpp
+++ b/tests/CompositeChat/CompositeChatTest.cpp
@@ -14,7 +14,7 @@
static void TestParser1(void)
{
cCompositeChat Msg;
- Msg.ParseText("Testing @2color codes and http://links parser");
+ Msg.ParseText("Testing &2color codes and http://links parser");
const auto & Parts = Msg.GetParts();
TEST_EQUAL(Parts.size(), 4);
@@ -22,13 +22,13 @@ static void TestParser1(void)
TEST_EQUAL(std::get(Parts[0]).Style, "");
TEST_TRUE(std::holds_alternative(Parts[1]));
- TEST_EQUAL(std::get(Parts[1]).Style, "@2");
+ TEST_EQUAL(std::get(Parts[1]).Style, "2");
TEST_TRUE(std::holds_alternative(Parts[2]));
- TEST_EQUAL(std::get(Parts[2]).Style, "@2");
+ TEST_EQUAL(std::get(Parts[2]).Style, "2");
TEST_TRUE(std::holds_alternative(Parts[3]));
- TEST_EQUAL(std::get(Parts[3]).Style, "@2");
+ TEST_EQUAL(std::get(Parts[3]).Style, "2");
}
@@ -38,21 +38,21 @@ static void TestParser1(void)
static void TestParser2(void)
{
cCompositeChat Msg;
- Msg.ParseText("@3Advanced stuff: @5overriding color codes and http://links.with/@4color-in-them handling");
+ Msg.ParseText("&3Advanced stuff: &5overriding color codes and http://links.with/&4color-in-them handling");
const auto & Parts = Msg.GetParts();
TEST_EQUAL(Parts.size(), 4);
TEST_TRUE(std::holds_alternative(Parts[0]));
- TEST_EQUAL(std::get(Parts[0]).Style, "@3");
+ TEST_EQUAL(std::get(Parts[0]).Style, "3");
TEST_TRUE(std::holds_alternative(Parts[1]));
- TEST_EQUAL(std::get(Parts[1]).Style, "@5");
+ TEST_EQUAL(std::get(Parts[1]).Style, "35");
TEST_TRUE(std::holds_alternative(Parts[2]));
- TEST_EQUAL(std::get(Parts[2]).Style, "@5");
+ TEST_EQUAL(std::get(Parts[2]).Style, "35");
TEST_TRUE(std::holds_alternative(Parts[3]));
- TEST_EQUAL(std::get(Parts[3]).Style, "@5");
+ TEST_EQUAL(std::get(Parts[3]).Style, "35");
}