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: - - - - - - + + + + + + +
StringStyle
bBold text
iItalic text
uUnderlined text
sStrikethrough text
oObfuscated text
@Xcolor [0–9a–f], same as dye meta
lBold text
oItalic text
nUnderlined text
mStrikethrough text
kObfuscated text
rReset 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"); }