summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/BlockInfo.cpp26
-rw-r--r--src/Blocks/BlockBed.cpp2
-rw-r--r--src/Blocks/BlockBigFlower.h6
-rw-r--r--src/Blocks/BlockDoor.cpp2
-rw-r--r--src/Blocks/BlockFarmland.h99
-rw-r--r--src/Blocks/BlockFenceGate.h6
-rw-r--r--src/Blocks/BlockFire.h4
-rw-r--r--src/Blocks/BlockGravel.h13
-rw-r--r--src/Blocks/BlockHandler.cpp70
-rw-r--r--src/Blocks/BlockHandler.h2
-rw-r--r--src/Blocks/BlockMobHead.h12
-rw-r--r--src/Blocks/BlockMobSpawner.h40
-rw-r--r--src/Blocks/BlockOre.h3
-rw-r--r--src/Blocks/BlockPiston.cpp2
-rw-r--r--src/Blocks/ChunkInterface.cpp4
-rw-r--r--src/Blocks/ChunkInterface.h2
-rw-r--r--src/Blocks/WorldInterface.h3
-rw-r--r--src/Chunk.cpp2
-rw-r--r--src/ChunkMap.cpp6
-rw-r--r--src/ChunkMap.h4
-rw-r--r--src/ClientHandle.cpp36
-rw-r--r--src/ClientHandle.h14
-rw-r--r--src/Entities/Entity.cpp41
-rw-r--r--src/Entities/Entity.h6
-rw-r--r--src/Entities/EntityEffect.cpp86
-rw-r--r--src/Entities/EntityEffect.h8
-rw-r--r--src/Entities/Player.cpp9
-rw-r--r--src/Items/ItemFood.h2
-rw-r--r--src/Items/ItemGoldenApple.h1
-rw-r--r--src/Items/ItemHandler.cpp10
-rw-r--r--src/Items/ItemHoe.h8
-rw-r--r--src/Items/ItemMilk.h8
-rw-r--r--src/Items/ItemMushroomSoup.h53
-rw-r--r--src/Items/ItemPickaxe.h1
-rw-r--r--src/Items/ItemPotion.h8
-rw-r--r--src/Mobs/Monster.cpp6
-rw-r--r--src/Mobs/Monster.h5
-rw-r--r--src/OSSupport/File.cpp14
-rw-r--r--src/OSSupport/IsThread.h2
-rw-r--r--src/Protocol/Protocol17x.cpp19
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp2
-rw-r--r--src/StringUtils.cpp28
-rw-r--r--src/StringUtils.h5
-rw-r--r--src/VoronoiMap.cpp35
-rw-r--r--src/VoronoiMap.h31
-rw-r--r--src/World.cpp2
-rw-r--r--src/World.h2
47 files changed, 564 insertions, 186 deletions
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index 12eeceba2..99bf36d66 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -548,7 +548,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_LOG ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_LEAVES ].m_PlaceSound = "dig.grass";
a_Info[E_BLOCK_SPONGE ].m_PlaceSound = "dig.grass";
- a_Info[E_BLOCK_GLASS ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_GLASS ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_LAPIS_ORE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_LAPIS_BLOCK ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_DISPENSER ].m_PlaceSound = "dig.stone";
@@ -605,7 +605,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_REDSTONE_TORCH_ON ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_STONE_BUTTON ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_SNOW ].m_PlaceSound = "dig.snow";
- a_Info[E_BLOCK_ICE ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_ICE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_SNOW_BLOCK ].m_PlaceSound = "dig.snow";
a_Info[E_BLOCK_CACTUS ].m_PlaceSound = "dig.cloth";
a_Info[E_BLOCK_CLAY ].m_PlaceSound = "dig.gravel";
@@ -615,20 +615,20 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_PUMPKIN ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_NETHERRACK ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_SOULSAND ].m_PlaceSound = "dig.sand";
- a_Info[E_BLOCK_GLOWSTONE ].m_PlaceSound = "dig.glass";
- a_Info[E_BLOCK_NETHER_PORTAL ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_GLOWSTONE ].m_PlaceSound = "dig.stone";
+ a_Info[E_BLOCK_NETHER_PORTAL ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_JACK_O_LANTERN ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_CAKE ].m_PlaceSound = "dig.snow";
a_Info[E_BLOCK_REDSTONE_REPEATER_OFF ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_REDSTONE_REPEATER_ON ].m_PlaceSound = "dig.wood";
- a_Info[E_BLOCK_STAINED_GLASS ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_STAINED_GLASS ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_TRAPDOOR ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_SILVERFISH_EGG ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_STONE_BRICKS ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_HUGE_BROWN_MUSHROOM ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_HUGE_RED_MUSHROOM ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_IRON_BARS ].m_PlaceSound = "dig.metal";
- a_Info[E_BLOCK_GLASS_PANE ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_GLASS_PANE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_MELON ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_PUMPKIN_STEM ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_MELON_STEM ].m_PlaceSound = "dig.wood";
@@ -645,12 +645,12 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_ENCHANTMENT_TABLE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_BREWING_STAND ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_CAULDRON ].m_PlaceSound = "dig.stone";
- a_Info[E_BLOCK_END_PORTAL ].m_PlaceSound = "dig.glass";
- a_Info[E_BLOCK_END_PORTAL_FRAME ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_END_PORTAL ].m_PlaceSound = "dig.stone";
+ a_Info[E_BLOCK_END_PORTAL_FRAME ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_END_STONE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_DRAGON_EGG ].m_PlaceSound = "dig.stone";
- a_Info[E_BLOCK_REDSTONE_LAMP_OFF ].m_PlaceSound = "dig.glass";
- a_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_REDSTONE_LAMP_OFF ].m_PlaceSound = "dig.stone";
+ a_Info[E_BLOCK_REDSTONE_LAMP_ON ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_DOUBLE_WOODEN_SLAB ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_WOODEN_SLAB ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_COCOA_POD ].m_PlaceSound = "dig.wood";
@@ -670,7 +670,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_CARROTS ].m_PlaceSound = "dig.grass";
a_Info[E_BLOCK_POTATOES ].m_PlaceSound = "dig.grass";
a_Info[E_BLOCK_HEAD ].m_PlaceSound = "dig.stone";
- a_Info[E_BLOCK_ANVIL ].m_PlaceSound = "dig.anvil";
+ a_Info[E_BLOCK_ANVIL ].m_PlaceSound = "random.anvil_land";
a_Info[E_BLOCK_TRAPPED_CHEST ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE ].m_PlaceSound = "dig.wood";
@@ -685,7 +685,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_ACTIVATOR_RAIL ].m_PlaceSound = "dig.metal";
a_Info[E_BLOCK_DROPPER ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_STAINED_CLAY ].m_PlaceSound = "dig.stone";
- a_Info[E_BLOCK_STAINED_GLASS_PANE ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_STAINED_GLASS_PANE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_NEW_LEAVES ].m_PlaceSound = "dig.grass";
a_Info[E_BLOCK_NEW_LOG ].m_PlaceSound = "dig.wood";
a_Info[E_BLOCK_ACACIA_WOOD_STAIRS ].m_PlaceSound = "dig.wood";
@@ -694,7 +694,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_CARPET ].m_PlaceSound = "dig.cloth";
a_Info[E_BLOCK_HARDENED_CLAY ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_BLOCK_OF_COAL ].m_PlaceSound = "dig.stone";
- a_Info[E_BLOCK_PACKED_ICE ].m_PlaceSound = "dig.glass";
+ a_Info[E_BLOCK_PACKED_ICE ].m_PlaceSound = "dig.stone";
a_Info[E_BLOCK_BIG_FLOWER ].m_PlaceSound = "dig.grass";
}
diff --git a/src/Blocks/BlockBed.cpp b/src/Blocks/BlockBed.cpp
index cd5783f58..cd1cc2a5f 100644
--- a/src/Blocks/BlockBed.cpp
+++ b/src/Blocks/BlockBed.cpp
@@ -15,7 +15,7 @@ void cBlockBedHandler::OnPlacedByPlayer(
if (a_BlockMeta < 8)
{
Vector3i Direction = MetaDataToDirection(a_BlockMeta);
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z, E_BLOCK_BED, a_BlockMeta | 0x8);
+ a_ChunkInterface.SetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z, E_BLOCK_BED, a_BlockMeta | 0x8);
}
}
diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h
index 646980634..89ffc864d 100644
--- a/src/Blocks/BlockBigFlower.h
+++ b/src/Blocks/BlockBigFlower.h
@@ -19,16 +19,16 @@ public:
}
- virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop, bool a_DropVerbatim) override
+ virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop) override
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (Meta & 0x8)
{
- super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY - 1, a_BlockZ, a_CanDrop, a_DropVerbatim);
+ super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY - 1, a_BlockZ, a_CanDrop);
}
else
{
- super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop, a_DropVerbatim);
+ super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop);
}
}
diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp
index 1204debab..1a277f071 100644
--- a/src/Blocks/BlockDoor.cpp
+++ b/src/Blocks/BlockDoor.cpp
@@ -102,7 +102,7 @@ void cBlockDoorHandler::OnPlacedByPlayer(
{
a_TopBlockMeta = 9;
}
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY + 1, a_BlockZ, m_BlockType, a_TopBlockMeta);
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, m_BlockType, a_TopBlockMeta);
}
diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h
index bb624e54f..02a48a4af 100644
--- a/src/Blocks/BlockFarmland.h
+++ b/src/Blocks/BlockFarmland.h
@@ -28,49 +28,12 @@ public:
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
- bool Found = false;
-
- EMCSBiome Biome = a_Chunk.GetBiomeAt(a_RelX, a_RelZ);
- if (a_Chunk.GetWorld()->IsWeatherWet() && !IsBiomeNoDownfall(Biome))
- {
- // Rain hydrates farmland, too, except in Desert biomes.
- Found = true;
- }
- else
- {
- // Search for water in a close proximity:
- // Ref.: http://www.minecraftwiki.net/wiki/Farmland#Hydrated_Farmland_Tiles
- // TODO: Rewrite this to use the chunk and its neighbors directly
- cBlockArea Area;
- int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
- int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
- if (!Area.Read(a_Chunk.GetWorld(), BlockX - 4, BlockX + 4, a_RelY, a_RelY + 1, BlockZ - 4, BlockZ + 4))
- {
- // Too close to the world edge, cannot check surroundings; don't tick at all
- return;
- }
-
- size_t NumBlocks = Area.GetBlockCount();
- BLOCKTYPE * BlockTypes = Area.GetBlockTypes();
- for (size_t i = 0; i < NumBlocks; i++)
- {
- if (IsBlockWater(BlockTypes[i]))
- {
- Found = true;
- break;
- }
- } // for i - BlockTypes[]
- }
-
NIBBLETYPE BlockMeta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
-
- if (Found)
+
+ if (IsWaterInNear(a_Chunk, a_RelX, a_RelY, a_RelZ))
{
- // Water was found, hydrate the block until hydration reaches 7:
- if (BlockMeta < 7)
- {
- a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, ++BlockMeta);
- }
+ // Water was found, set block meta to 7
+ a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, 7);
return;
}
@@ -80,9 +43,10 @@ public:
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_FARMLAND, --BlockMeta);
return;
}
-
+
// Farmland too dry. If nothing is growing on top, turn back to dirt:
- switch (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ))
+ BLOCKTYPE UpperBlock = (a_RelY >= cChunkDef::Height) ? E_BLOCK_AIR : a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ);
+ switch (UpperBlock)
{
case E_BLOCK_CROPS:
case E_BLOCK_POTATOES:
@@ -95,16 +59,63 @@ public:
}
default:
{
- a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, 0);
+ a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, 0);
break;
}
}
}
+ virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override
+ {
+ if (a_BlockY >= cChunkDef::Height)
+ {
+ return;
+ }
+
+ BLOCKTYPE UpperBlock = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
+ if (cBlockInfo::FullyOccupiesVoxel(UpperBlock))
+ {
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DIRT, 0);
+ }
+ }
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.Add(E_BLOCK_DIRT, 1, 0); // Reset meta
}
+
+ bool IsWaterInNear(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
+ {
+ if (a_Chunk.GetWorld()->IsWeatherWetAt(a_RelX, a_RelZ))
+ {
+ // Rain hydrates farmland, too, except in Desert biomes.
+ return true;
+ }
+
+ // Search for water in a close proximity:
+ // Ref.: http://www.minecraftwiki.net/wiki/Farmland#Hydrated_Farmland_Tiles
+ // TODO: Rewrite this to use the chunk and its neighbors directly
+ cBlockArea Area;
+ int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
+ int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
+ if (!Area.Read(a_Chunk.GetWorld(), BlockX - 4, BlockX + 4, a_RelY, a_RelY + 1, BlockZ - 4, BlockZ + 4))
+ {
+ // Too close to the world edge, cannot check surroundings
+ return false;
+ }
+
+ size_t NumBlocks = Area.GetBlockCount();
+ BLOCKTYPE * BlockTypes = Area.GetBlockTypes();
+ for (size_t i = 0; i < NumBlocks; i++)
+ {
+ if (IsBlockWater(BlockTypes[i]))
+ {
+ return true;
+ }
+ } // for i - BlockTypes[]
+
+ return false;
+ }
} ;
diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h
index ae99a4f94..3041dd46c 100644
--- a/src/Blocks/BlockFenceGate.h
+++ b/src/Blocks/BlockFenceGate.h
@@ -17,6 +17,12 @@ public:
}
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ a_Pickups.Add(E_BLOCK_FENCE_GATE, 1, 0); // Reset meta to zero
+ }
+
+
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h
index b6d1d95f2..07fcefe16 100644
--- a/src/Blocks/BlockFire.h
+++ b/src/Blocks/BlockFire.h
@@ -126,11 +126,11 @@ public:
{
if (Dir == 1)
{
- a_ChunkInterface.SetBlock(a_WorldInterface, Width, Height, Z, E_BLOCK_NETHER_PORTAL, Dir);
+ a_ChunkInterface.SetBlock(Width, Height, Z, E_BLOCK_NETHER_PORTAL, Dir);
}
else
{
- a_ChunkInterface.SetBlock(a_WorldInterface, X, Height, Width, E_BLOCK_NETHER_PORTAL, Dir);
+ a_ChunkInterface.SetBlock(X, Height, Width, E_BLOCK_NETHER_PORTAL, Dir);
}
}
}
diff --git a/src/Blocks/BlockGravel.h b/src/Blocks/BlockGravel.h
index 717bd5f5f..d076306fb 100644
--- a/src/Blocks/BlockGravel.h
+++ b/src/Blocks/BlockGravel.h
@@ -15,6 +15,19 @@ public:
: cBlockHandler(a_BlockType)
{
}
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ cFastRandom Random;
+ if (Random.NextInt(30) == 0)
+ {
+ a_Pickups.Add(E_ITEM_FLINT, 1, 0);
+ }
+ else
+ {
+ a_Pickups.Add(E_BLOCK_GRAVEL, 1, 0);
+ }
+ }
} ;
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 34925a252..cee2f4b99 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -47,6 +47,7 @@
#include "BlockLilypad.h"
#include "BlockLever.h"
#include "BlockMelon.h"
+#include "BlockMobSpawner.h"
#include "BlockMushroom.h"
#include "BlockMycelium.h"
#include "BlockNetherWart.h"
@@ -244,6 +245,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_MELON: return new cBlockMelonHandler (a_BlockType);
case E_BLOCK_MELON_STEM: return new cBlockStemsHandler (a_BlockType);
+ case E_BLOCK_MOB_SPAWNER: return new cBlockMobSpawnerHandler (a_BlockType);
case E_BLOCK_MYCELIUM: return new cBlockMyceliumHandler (a_BlockType);
case E_BLOCK_NETHER_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (a_BlockType);
@@ -417,57 +419,45 @@ void cBlockHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
-void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop, bool a_DropVerbatim)
+void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop)
{
cItems Pickups;
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (a_CanDrop)
{
- if (!a_DropVerbatim)
- {
- ConvertToPickups(Pickups, Meta);
- }
- else
- {
- // TODO: Add a proper overridable function for this
- if (a_Digger != NULL)
+ if ((a_Digger != NULL) && (a_Digger->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0))
+ {
+ switch (m_BlockType)
{
- cEnchantments Enchantments = a_Digger->GetEquippedWeapon().m_Enchantments;
- if ((Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) && a_Digger->IsPlayer())
+ case E_BLOCK_CAKE:
+ case E_BLOCK_CARROTS:
+ case E_BLOCK_COCOA_POD:
+ case E_BLOCK_DOUBLE_STONE_SLAB:
+ case E_BLOCK_DOUBLE_WOODEN_SLAB:
+ case E_BLOCK_FIRE:
+ case E_BLOCK_FARMLAND:
+ case E_BLOCK_MELON_STEM:
+ case E_BLOCK_MOB_SPAWNER:
+ case E_BLOCK_NETHER_WART:
+ case E_BLOCK_POTATOES:
+ case E_BLOCK_PUMPKIN_STEM:
+ case E_BLOCK_SNOW:
+ case E_BLOCK_SUGARCANE:
+ case E_BLOCK_TALL_GRASS:
+ case E_BLOCK_CROPS:
{
- switch (m_BlockType)
- {
- case E_BLOCK_CAKE:
- case E_BLOCK_CARROTS:
- case E_BLOCK_COCOA_POD:
- case E_BLOCK_DOUBLE_STONE_SLAB:
- case E_BLOCK_DOUBLE_WOODEN_SLAB:
- case E_BLOCK_FIRE:
- case E_BLOCK_FARMLAND:
- case E_BLOCK_MELON_STEM:
- case E_BLOCK_MOB_SPAWNER:
- case E_BLOCK_NETHER_WART:
- case E_BLOCK_POTATOES:
- case E_BLOCK_PUMPKIN_STEM:
- case E_BLOCK_SNOW:
- case E_BLOCK_SUGARCANE:
- case E_BLOCK_TALL_GRASS:
- case E_BLOCK_CROPS:
- {
- // Silktouch can't be used for this blocks
- ConvertToPickups(Pickups, Meta);
- break;
- };
- default: Pickups.Add(m_BlockType, 1, Meta);
- }
- }
- else
- {
- Pickups.Add(m_BlockType, 1, Meta);
+ // Silktouch can't be used for these blocks
+ ConvertToPickups(Pickups, Meta);
+ break;
}
+ default: Pickups.Add(m_BlockType, 1, Meta); break;
}
}
+ else
+ {
+ ConvertToPickups(Pickups, Meta);
+ }
}
// Allow plugins to modify the pickups:
diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h
index b3ada279c..3a8115da0 100644
--- a/src/Blocks/BlockHandler.h
+++ b/src/Blocks/BlockHandler.h
@@ -82,7 +82,7 @@ public:
@param a_CanDrop Informs the handler whether the block should be dropped at all. One example when this is false is when stone is destroyed by hand
@param a_DropVerbatim Calls ConvertToVerbatimPickups() instead of its counterpart, meaning the block itself is dropped by default (due to a speical tool or enchantment)
*/
- virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop = true, bool a_DropVerbatim = false);
+ virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_CanDrop = true);
/// Checks if the block can stay at the specified relative coords in the chunk
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk);
diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h
index f19c78694..e21e42334 100644
--- a/src/Blocks/BlockMobHead.h
+++ b/src/Blocks/BlockMobHead.h
@@ -146,9 +146,9 @@ public:
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Block entities
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
// Spawn the wither:
a_WorldInterface.SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, mtWither);
@@ -176,9 +176,9 @@ public:
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0);
// Block entities
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0);
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
- a_ChunkInterface.SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0);
// Spawn the wither:
a_WorldInterface.SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, mtWither);
diff --git a/src/Blocks/BlockMobSpawner.h b/src/Blocks/BlockMobSpawner.h
new file mode 100644
index 000000000..a51fbaafc
--- /dev/null
+++ b/src/Blocks/BlockMobSpawner.h
@@ -0,0 +1,40 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+#include "../World.h"
+#include "../Items/ItemHandler.h"
+
+
+
+
+
+class cBlockMobSpawnerHandler :
+ public cBlockHandler
+{
+public:
+ cBlockMobSpawnerHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ // No pickups
+ }
+
+
+ virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
+ {
+ cItemHandler * Handler = a_Player->GetEquippedItem().GetHandler();
+ if (a_Player->IsGameModeCreative() || !Handler->CanHarvestBlock(E_BLOCK_MOB_SPAWNER))
+ {
+ return;
+ }
+
+ cFastRandom Random;
+ int Reward = 15 + Random.NextInt(15) + Random.NextInt(15);
+ a_WorldInterface.SpawnExperienceOrb((double)a_BlockX, (double)a_BlockY + 1, (double)a_BlockZ, Reward);
+ }
+} ;
diff --git a/src/Blocks/BlockOre.h b/src/Blocks/BlockOre.h
index 0067d475f..f6ea3aa3c 100644
--- a/src/Blocks/BlockOre.h
+++ b/src/Blocks/BlockOre.h
@@ -51,7 +51,8 @@ public:
}
default:
{
- ASSERT(!"Unhandled ore!");
+ a_Pickups.push_back(cItem(m_BlockType));
+ break;
}
}
}
diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp
index 164967621..0169fb266 100644
--- a/src/Blocks/BlockPiston.cpp
+++ b/src/Blocks/BlockPiston.cpp
@@ -52,7 +52,7 @@ void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorld
if (a_ChunkInterface.GetBlock(newX, newY, newZ) == E_BLOCK_PISTON_EXTENSION)
{
- a_ChunkInterface.SetBlock(a_WorldInterface, newX, newY, newZ, E_BLOCK_AIR, 0);
+ a_ChunkInterface.SetBlock(newX, newY, newZ, E_BLOCK_AIR, 0);
}
}
diff --git a/src/Blocks/ChunkInterface.cpp b/src/Blocks/ChunkInterface.cpp
index 809c24635..a4c96a478 100644
--- a/src/Blocks/ChunkInterface.cpp
+++ b/src/Blocks/ChunkInterface.cpp
@@ -26,9 +26,9 @@ bool cChunkInterface::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ,
/** Sets the block at the specified coords to the specified value.
Full processing, incl. updating neighbors, is performed.
*/
-void cChunkInterface::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
+void cChunkInterface::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
- m_ChunkMap->SetBlock(a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
+ m_ChunkMap->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
}
void cChunkInterface::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData)
diff --git a/src/Blocks/ChunkInterface.h b/src/Blocks/ChunkInterface.h
index dff30a6ee..51647dc04 100644
--- a/src/Blocks/ChunkInterface.h
+++ b/src/Blocks/ChunkInterface.h
@@ -24,7 +24,7 @@ public:
/** Sets the block at the specified coords to the specified value.
Full processing, incl. updating neighbors, is performed.
*/
- void SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
+ void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
void SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData);
diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h
index 27e06fff3..106c314e7 100644
--- a/src/Blocks/WorldInterface.h
+++ b/src/Blocks/WorldInterface.h
@@ -36,6 +36,9 @@ public:
/** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */
virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, eMonsterType a_MonsterType) = 0;
+ /** Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. */
+ virtual int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) = 0;
+
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) = 0;
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 46520eb56..7f00ee190 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -2215,7 +2215,7 @@ bool cChunk::DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_Blo
}
}
- if (a_Callback.Item((cRedstonePoweredEntity *)*itr))
+ if (a_Callback.Item(dynamic_cast<cRedstonePoweredEntity *>(*itr))) // Needs dynamic_cast due to multiple inheritance
{
return false;
}
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 9c105c5af..e8728091f 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -1287,12 +1287,12 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP
-void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
+void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
{
cChunkInterface ChunkInterface(this);
if (a_BlockType == E_BLOCK_AIR)
{
- BlockHandler(GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnDestroyed(ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ);
+ BlockHandler(GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnDestroyed(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ);
}
int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
@@ -1305,7 +1305,7 @@ void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a
Chunk->SetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_SendToClients);
m_World->GetSimulatorManager()->WakeUp(a_BlockX, a_BlockY, a_BlockZ, Chunk);
}
- BlockHandler(a_BlockType)->OnPlaced(ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
+ BlockHandler(a_BlockType)->OnPlaced(ChunkInterface, *m_World, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
}
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index 7354536d4..dfa1a57b4 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -151,8 +151,8 @@ public:
NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ);
NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ);
void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta);
- void SetBlock (cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true);
- void QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR);
+ void SetBlock (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true);
+ void QueueSetBlock (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR);
bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index a6d7c3066..4a3a3c250 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -312,8 +312,16 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID,
ASSERT(m_Player == NULL);
m_Username = a_Name;
- m_UUID = a_UUID;
- m_Properties = a_Properties;
+
+ // Only assign UUID and properties if not already pre-assigned (BungeeCord sends those in the Handshake packet):
+ if (m_UUID.empty())
+ {
+ m_UUID = a_UUID;
+ }
+ if (m_Properties.empty())
+ {
+ m_Properties = a_Properties;
+ }
// Send login success (if the protocol supports it):
m_Protocol->SendLoginSuccess();
@@ -1063,7 +1071,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
(m_Player->GetWorld()->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_FIRE)
)
{
- // Players can't destroy blocks with a Sword in the hand.
+ // Players can't destroy blocks with a sword in the hand.
return;
}
@@ -1134,6 +1142,12 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
FinishDigAnimation();
+ if (!m_Player->IsGameModeCreative() && (a_OldBlock == E_BLOCK_BEDROCK))
+ {
+ Kick("You can't break a bedrock!");
+ return;
+ }
+
cWorld * World = m_Player->GetWorld();
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
@@ -1447,8 +1461,20 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
cChunkInterface ChunkInterface(World->GetChunkMap());
NewBlock->OnPlacedByPlayer(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
- // Step sound with 0.8f pitch is used as block placement sound
- World->BroadcastSoundEffect(cBlockInfo::GetPlaceSound(BlockType), (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.8f);
+ AString PlaceSound = cBlockInfo::GetPlaceSound(BlockType);
+ float Volume = 1.0f, Pitch = 0.8f;
+ if (PlaceSound == "dig.metal")
+ {
+ Pitch = 1.2f;
+ PlaceSound = "dig.stone";
+ }
+ else if (PlaceSound == "random.anvil_land")
+ {
+ Volume = 0.65f;
+ }
+
+ World->BroadcastSoundEffect(PlaceSound, a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, Volume, Pitch);
+
cRoot::Get()->GetPluginManager()->CallHookPlayerPlacedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 74e89deee..3d0995636 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -64,15 +64,27 @@ public:
const AString & GetIPString(void) const { return m_IPString; } // tolua_export
+ /** Sets the IP string that the client is using. Overrides the IP string that was read from the socket.
+ Used mainly by BungeeCord compatibility code. */
+ void SetIPString(const AString & a_IPString) { m_IPString = a_IPString; }
+
cPlayer * GetPlayer(void) { return m_Player; } // tolua_export
/** Returns the player's UUID, as used by the protocol, in the short form (no dashes) */
const AString & GetUUID(void) const { return m_UUID; } // tolua_export
- void SetUUID(const AString & a_UUID) { m_UUID = a_UUID; }
+ /** Sets the player's UUID, as used by the protocol. Short UUID form (no dashes) is expected.
+ Used mainly by BungeeCord compatibility code - when authenticating is done on the BungeeCord server
+ and the results are passed to MCS running in offline mode. */
+ void SetUUID(const AString & a_UUID) { ASSERT(a_UUID.size() == 32); m_UUID = a_UUID; }
const Json::Value & GetProperties(void) const { return m_Properties; }
+ /** Sets the player's properties, such as skin image and signature.
+ Used mainly by BungeeCord compatibility code - property querying is done on the BungeeCord server
+ and the results are passed to MCS running in offline mode. */
+ void SetProperties(const Json::Value & a_Properties) { m_Properties = a_Properties; }
+
/** Generates an UUID based on the username stored for this client, and stores it in the m_UUID member.
This is used for the offline (non-auth) mode, when there's no UUID source.
Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same.
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 4581eeda8..398922ef7 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -927,12 +927,13 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
float fallspeed;
if (IsBlockWater(BlockIn))
{
- fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water.
+ fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water
+ ApplyFriction(NextSpeed, 0.7, a_Dt);
}
else if (BlockIn == E_BLOCK_COBWEB)
{
NextSpeed.y *= 0.05; // Reduce overall falling speed
- fallspeed = 0; // No falling.
+ fallspeed = 0; // No falling
}
else
{
@@ -941,20 +942,9 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
NextSpeed.y += fallspeed;
}
-
- // Friction
- if (NextSpeed.SqrLength() > 0.0004f)
+ else
{
- NextSpeed.x *= 0.7f / (1 + a_Dt);
- if (fabs(NextSpeed.x) < 0.05)
- {
- NextSpeed.x = 0;
- }
- NextSpeed.z *= 0.7f / (1 + a_Dt);
- if (fabs(NextSpeed.z) < 0.05)
- {
- NextSpeed.z = 0;
- }
+ ApplyFriction(NextSpeed, 0.7, a_Dt);
}
// Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we
@@ -1060,6 +1050,27 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
+void cEntity::ApplyFriction(Vector3d & a_Speed, double a_SlowdownMultiplier, float a_Dt)
+{
+ if (a_Speed.SqrLength() > 0.0004f)
+ {
+ a_Speed.x *= a_SlowdownMultiplier / (1 + a_Dt);
+ if (fabs(a_Speed.x) < 0.05)
+ {
+ a_Speed.x = 0;
+ }
+ a_Speed.z *= a_SlowdownMultiplier / (1 + a_Dt);
+ if (fabs(a_Speed.z) < 0.05)
+ {
+ a_Speed.z = 0;
+ }
+ }
+}
+
+
+
+
+
void cEntity::TickBurning(cChunk & a_Chunk)
{
// Remember the current burning state:
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index b9c280b6b..6bc070dcc 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -535,6 +535,12 @@ protected:
virtual void Destroyed(void) {} // Called after the entity has been destroyed
+ /** Applies friction to an entity
+ @param a_Speed The speed vector to apply changes to
+ @param a_SlowdownMultiplier The factor to reduce the speed by
+ */
+ static void ApplyFriction(Vector3d & a_Speed, double a_SlowdownMultiplier, float a_Dt);
+
/** Called in each tick to handle air-related processing i.e. drowning */
virtual void HandleAir(void);
diff --git a/src/Entities/EntityEffect.cpp b/src/Entities/EntityEffect.cpp
index 8235275a6..d8fa130c0 100644
--- a/src/Entities/EntityEffect.cpp
+++ b/src/Entities/EntityEffect.cpp
@@ -233,6 +233,92 @@ void cEntityEffect::OnTick(cPawn & a_Target)
////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectSpeed:
+
+void cEntityEffectSpeed::OnActivate(cPawn & a_Target)
+{
+ if (a_Target.IsMob())
+ {
+ cMonster * Mob = (cMonster*) &a_Target;
+ Mob->SetRelativeWalkSpeed(Mob->GetRelativeWalkSpeed() + 0.2 * m_Intensity);
+ }
+ else if (a_Target.IsPlayer())
+ {
+ cPlayer * Player = (cPlayer*) &a_Target;
+ Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() + 0.2 * m_Intensity);
+ Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() + 0.26 * m_Intensity);
+ Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() + 0.2 * m_Intensity);
+ }
+}
+
+
+
+
+
+void cEntityEffectSpeed::OnDeactivate(cPawn & a_Target)
+{
+ if (a_Target.IsMob())
+ {
+ cMonster * Mob = (cMonster*) &a_Target;
+ Mob->SetRelativeWalkSpeed(Mob->GetRelativeWalkSpeed() - 0.2 * m_Intensity);
+ }
+ else if (a_Target.IsPlayer())
+ {
+ cPlayer * Player = (cPlayer*) &a_Target;
+ Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() - 0.2 * m_Intensity);
+ Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() - 0.26 * m_Intensity);
+ Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() - 0.2 * m_Intensity);
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectSlowness:
+
+void cEntityEffectSlowness::OnActivate(cPawn & a_Target)
+{
+ if (a_Target.IsMob())
+ {
+ cMonster * Mob = (cMonster*) &a_Target;
+ Mob->SetRelativeWalkSpeed(Mob->GetRelativeWalkSpeed() - 0.15 * m_Intensity);
+ }
+ else if (a_Target.IsPlayer())
+ {
+ cPlayer * Player = (cPlayer*) &a_Target;
+ Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() - 0.15 * m_Intensity);
+ Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() - 0.195 * m_Intensity);
+ Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() - 0.15 * m_Intensity);
+ }
+}
+
+
+
+
+
+void cEntityEffectSlowness::OnDeactivate(cPawn & a_Target)
+{
+ if (a_Target.IsMob())
+ {
+ cMonster * Mob = (cMonster*) &a_Target;
+ Mob->SetRelativeWalkSpeed(Mob->GetRelativeWalkSpeed() + 0.15 * m_Intensity);
+ }
+ else if (a_Target.IsPlayer())
+ {
+ cPlayer * Player = (cPlayer*) &a_Target;
+ Player->SetNormalMaxSpeed(Player->GetNormalMaxSpeed() + 0.15 * m_Intensity);
+ Player->SetSprintingMaxSpeed(Player->GetSprintingMaxSpeed() + 0.195 * m_Intensity);
+ Player->SetFlyingMaxSpeed(Player->GetFlyingMaxSpeed() + 0.15 * m_Intensity);
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
// cEntityEffectInstantHealth:
void cEntityEffectInstantHealth::OnActivate(cPawn & a_Target)
diff --git a/src/Entities/EntityEffect.h b/src/Entities/EntityEffect.h
index 47c298f57..7cf9cd3d5 100644
--- a/src/Entities/EntityEffect.h
+++ b/src/Entities/EntityEffect.h
@@ -137,6 +137,10 @@ public:
super(a_Duration, a_Intensity, a_DistanceModifier)
{
}
+
+ virtual void OnActivate(cPawn & a_Target) override;
+
+ virtual void OnDeactivate(cPawn & a_Target) override;
};
@@ -152,6 +156,10 @@ public:
super(a_Duration, a_Intensity, a_DistanceModifier)
{
}
+
+ virtual void OnActivate(cPawn & a_Target) override;
+
+ virtual void OnDeactivate(cPawn & a_Target) override;
};
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 4458cd32f..9e373d2c2 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -627,15 +627,6 @@ void cPlayer::FinishEating(void)
return;
}
ItemHandler->OnFoodEaten(m_World, this, &Item);
-
- GetInventory().RemoveOneEquippedItem();
-
- // if the food is mushroom soup, return a bowl to the inventory
- if (Item.m_ItemType == E_ITEM_MUSHROOM_SOUP)
- {
- cItem EmptyBowl(E_ITEM_BOWL);
- GetInventory().AddItem(EmptyBowl, true, true);
- }
}
diff --git a/src/Items/ItemFood.h b/src/Items/ItemFood.h
index 9035344df..1af6e21e8 100644
--- a/src/Items/ItemFood.h
+++ b/src/Items/ItemFood.h
@@ -1,3 +1,4 @@
+
#pragma once
#include "ItemHandler.h"
@@ -39,7 +40,6 @@ public:
// Golden apple handled in ItemGoldenApple
case E_ITEM_GOLDEN_CARROT: return FoodInfo(6, 14.4);
case E_ITEM_MELON_SLICE: return FoodInfo(2, 1.2);
- case E_ITEM_MUSHROOM_SOUP: return FoodInfo(6, 7.2);
case E_ITEM_POISONOUS_POTATO: return FoodInfo(2, 1.2);
// Potatoes handled in ItemSeeds
case E_ITEM_PUMPKIN_PIE: return FoodInfo(8, 4.8);
diff --git a/src/Items/ItemGoldenApple.h b/src/Items/ItemGoldenApple.h
index 02ac0202c..5f6f1de6c 100644
--- a/src/Items/ItemGoldenApple.h
+++ b/src/Items/ItemGoldenApple.h
@@ -36,6 +36,7 @@ public:
a_Player->AddEntityEffect(cEntityEffect::effFireResistance, 6000, 0);
}
+ a_Player->GetInventory().RemoveOneEquippedItem();
return true;
}
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index 67c945ce4..8c3f28c74 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -33,6 +33,7 @@
#include "ItemLilypad.h"
#include "ItemMap.h"
#include "ItemMinecart.h"
+#include "ItemMushroomSoup.h"
#include "ItemNetherWart.h"
#include "ItemPainting.h"
#include "ItemPickaxe.h"
@@ -125,6 +126,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType);
case E_ITEM_MAP: return new cItemMapHandler();
case E_ITEM_MILK: return new cItemMilkHandler();
+ case E_ITEM_MUSHROOM_SOUP: return new cItemMushroomSoupHandler(a_ItemType);
case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType);
case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType);
case E_ITEM_PAINTING: return new cItemPaintingHandler(a_ItemType);
@@ -216,7 +218,6 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_COOKIE:
case E_ITEM_GOLDEN_CARROT:
case E_ITEM_MELON_SLICE:
- case E_ITEM_MUSHROOM_SOUP:
case E_ITEM_MUTTON:
case E_ITEM_POISONOUS_POTATO:
case E_ITEM_PUMPKIN_PIE:
@@ -333,7 +334,7 @@ void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const
{
cChunkInterface ChunkInterface(a_World->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*a_World);
- Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, CanHarvestBlock(Block), a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0);
+ Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, CanHarvestBlock(Block));
}
if (!cBlockInfo::IsOneHitDig(Block))
@@ -582,6 +583,7 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
case E_BLOCK_SNOW:
case E_BLOCK_VINES:
case E_BLOCK_PACKED_ICE:
+ case E_BLOCK_MOB_SPAWNER:
{
return false;
}
@@ -634,6 +636,10 @@ bool cItemHandler::GetEatEffect(cEntityEffect::eType & a_EffectType, int & a_Eff
bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
{
UNUSED(a_Item);
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
FoodInfo Info = GetFoodInfo();
if ((Info.FoodLevel > 0) || (Info.Saturation > 0.f))
diff --git a/src/Items/ItemHoe.h b/src/Items/ItemHoe.h
index 8d0b71478..8e63536d4 100644
--- a/src/Items/ItemHoe.h
+++ b/src/Items/ItemHoe.h
@@ -20,11 +20,17 @@ public:
virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
{
+ if ((a_Dir == BLOCK_FACE_NONE) || (a_BlockY >= cChunkDef::Height))
+ {
+ return false;
+ }
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ BLOCKTYPE UpperBlock = a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
- if ((Block == E_BLOCK_DIRT) || (Block == E_BLOCK_GRASS))
+ if (((Block == E_BLOCK_DIRT) || (Block == E_BLOCK_GRASS)) && (UpperBlock == E_BLOCK_AIR))
{
a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FARMLAND, 0);
+ a_World->BroadcastSoundEffect("dig.gravel", a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 1.0f, 0.8f);
a_Player->UseEquippedItem();
return true;
}
diff --git a/src/Items/ItemMilk.h b/src/Items/ItemMilk.h
index db7bc13be..c9a90865a 100644
--- a/src/Items/ItemMilk.h
+++ b/src/Items/ItemMilk.h
@@ -21,8 +21,12 @@ public:
{
UNUSED(a_Item);
a_Player->ClearEntityEffects();
- a_Player->GetInventory().RemoveOneEquippedItem();
- a_Player->GetInventory().AddItem(E_ITEM_BUCKET);
+
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ a_Player->GetInventory().AddItem(E_ITEM_BUCKET);
+ }
return true;
}
};
diff --git a/src/Items/ItemMushroomSoup.h b/src/Items/ItemMushroomSoup.h
new file mode 100644
index 000000000..dba313ec5
--- /dev/null
+++ b/src/Items/ItemMushroomSoup.h
@@ -0,0 +1,53 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemMushroomSoupHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemMushroomSoupHandler(int a_ItemType)
+ : super(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsFood(void) override
+ {
+ return true;
+ }
+
+
+ virtual FoodInfo GetFoodInfo(void) override
+ {
+ return FoodInfo(6, 7.2);
+ }
+
+
+ virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override
+ {
+ if (!super::EatItem(a_Player, a_Item))
+ {
+ return false;
+ }
+
+ // Return a bowl to the inventory
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().AddItem(cItem(E_ITEM_BOWL), true, true);
+ }
+ return true;
+ }
+
+};
+
+
+
+
diff --git a/src/Items/ItemPickaxe.h b/src/Items/ItemPickaxe.h
index 17fd96822..e0cf5d711 100644
--- a/src/Items/ItemPickaxe.h
+++ b/src/Items/ItemPickaxe.h
@@ -81,6 +81,7 @@ public:
case E_BLOCK_STONE_BRICK_STAIRS:
case E_BLOCK_NETHER_BRICK_STAIRS:
case E_BLOCK_CAULDRON:
+ case E_BLOCK_MOB_SPAWNER:
{
return PickaxeLevel() >= 1;
}
diff --git a/src/Items/ItemPotion.h b/src/Items/ItemPotion.h
index 24614cd8a..398ef6805 100644
--- a/src/Items/ItemPotion.h
+++ b/src/Items/ItemPotion.h
@@ -68,8 +68,12 @@ public:
cEntityEffect::GetPotionEffectDuration(PotionDamage),
cEntityEffect::GetPotionEffectIntensity(PotionDamage)
);
- a_Player->GetInventory().RemoveOneEquippedItem();
- a_Player->GetInventory().AddItem(E_ITEM_GLASS_BOTTLE);
+
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ a_Player->GetInventory().AddItem(E_ITEM_GLASS_BOTTLE);
+ }
return true;
}
};
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index b6e22c0ee..8c93fea2a 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -89,6 +89,7 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A
, m_DropChanceBoots(0.085f)
, m_CanPickUpLoot(true)
, m_BurnsInDaylight(false)
+ , m_RelativeWalkSpeed(1.0)
{
if (!a_ConfigName.empty())
{
@@ -282,7 +283,7 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
}
}
- Vector3f Distance = m_Destination - GetPosition();
+ Vector3d Distance = m_Destination - GetPosition();
if (!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
{
Distance.y = 0;
@@ -302,6 +303,9 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
Distance *= 0.25f;
}
+ // Apply walk speed:
+ Distance *= m_RelativeWalkSpeed;
+
AddSpeedX(Distance.x);
AddSpeedZ(Distance.z);
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index 60bf36c7a..ef94262f6 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -102,6 +102,9 @@ public:
/// Sets whether the mob burns in daylight. Only evaluated at next burn-decision tick
void SetBurnsInDaylight(bool a_BurnsInDaylight) { m_BurnsInDaylight = a_BurnsInDaylight; }
+ double GetRelativeWalkSpeed(void) const { return m_RelativeWalkSpeed; } // tolua_export
+ void SetRelativeWalkSpeed(double a_WalkSpeed) { m_RelativeWalkSpeed = a_WalkSpeed; } // tolua_export
+
// Overridables to handle ageable mobs
virtual bool IsBaby (void) const { return false; }
virtual bool IsTame (void) const { return false; }
@@ -212,6 +215,8 @@ protected:
void HandleDaylightBurning(cChunk & a_Chunk);
bool m_BurnsInDaylight;
+ double m_RelativeWalkSpeed;
+
/** Adds a random number of a_Item between a_Min and a_Max to itemdrops a_Drops*/
void AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth = 0);
diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp
index 2194c46ee..cb6031da6 100644
--- a/src/OSSupport/File.cpp
+++ b/src/OSSupport/File.cpp
@@ -298,7 +298,7 @@ bool cFile::Rename(const AString & a_OrigFileName, const AString & a_NewFileName
bool cFile::Copy(const AString & a_SrcFileName, const AString & a_DstFileName)
{
#ifdef _WIN32
- return (CopyFile(a_SrcFileName.c_str(), a_DstFileName.c_str(), true) != 0);
+ return (CopyFileA(a_SrcFileName.c_str(), a_DstFileName.c_str(), true) != 0);
#else
// Other OSs don't have a direct CopyFile equivalent, do it the harder way:
std::ifstream src(a_SrcFileName.c_str(), std::ios::binary);
@@ -322,7 +322,7 @@ bool cFile::Copy(const AString & a_SrcFileName, const AString & a_DstFileName)
bool cFile::IsFolder(const AString & a_Path)
{
#ifdef _WIN32
- DWORD FileAttrib = GetFileAttributes(a_Path.c_str());
+ DWORD FileAttrib = GetFileAttributesA(a_Path.c_str());
return ((FileAttrib != INVALID_FILE_ATTRIBUTES) && ((FileAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0));
#else
struct stat st;
@@ -337,7 +337,7 @@ bool cFile::IsFolder(const AString & a_Path)
bool cFile::IsFile(const AString & a_Path)
{
#ifdef _WIN32
- DWORD FileAttrib = GetFileAttributes(a_Path.c_str());
+ DWORD FileAttrib = GetFileAttributesA(a_Path.c_str());
return ((FileAttrib != INVALID_FILE_ATTRIBUTES) && ((FileAttrib & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0));
#else
struct stat st;
@@ -366,7 +366,7 @@ int cFile::GetSize(const AString & a_FileName)
bool cFile::CreateFolder(const AString & a_FolderPath)
{
#ifdef _WIN32
- return (CreateDirectory(a_FolderPath.c_str(), NULL) != 0);
+ return (CreateDirectoryA(a_FolderPath.c_str(), NULL) != 0);
#else
return (mkdir(a_FolderPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0);
#endif
@@ -396,13 +396,13 @@ AStringVector cFile::GetFolderContents(const AString & a_Folder)
// Find all files / folders:
FileFilter.append("*.*");
HANDLE hFind;
- WIN32_FIND_DATA FindFileData;
- if ((hFind = FindFirstFile(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE)
+ WIN32_FIND_DATAA FindFileData;
+ if ((hFind = FindFirstFileA(FileFilter.c_str(), &FindFileData)) != INVALID_HANDLE_VALUE)
{
do
{
AllFiles.push_back(FindFileData.cFileName);
- } while (FindNextFile(hFind, &FindFileData));
+ } while (FindNextFileA(hFind, &FindFileData));
FindClose(hFind);
}
diff --git a/src/OSSupport/IsThread.h b/src/OSSupport/IsThread.h
index c20fc3e7e..5de5f31c4 100644
--- a/src/OSSupport/IsThread.h
+++ b/src/OSSupport/IsThread.h
@@ -69,7 +69,7 @@ protected:
static DWORD __stdcall thrExecute(LPVOID a_Param)
{
// Create a window so that the thread can be identified by 3rd party tools:
- HWND IdentificationWnd = CreateWindow("STATIC", ((cIsThread *)a_Param)->m_ThreadName.c_str(), 0, 0, 0, 0, WS_OVERLAPPED, NULL, NULL, NULL, NULL);
+ HWND IdentificationWnd = CreateWindowA("STATIC", ((cIsThread *)a_Param)->m_ThreadName.c_str(), 0, 0, 0, 0, WS_OVERLAPPED, NULL, NULL, NULL, NULL);
// Run the thread:
((cIsThread *)a_Param)->Execute();
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index ac7a180d4..3b8800867 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -100,6 +100,19 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
m_IsEncrypted(false),
m_LastSentDimension(dimNotSet)
{
+ // BungeeCord handling:
+ // If BC is setup with ip_forward == true, it sends additional data in the login packet's ServerAddress field:
+ // hostname\00ip-address\00uuid\00profile-properties-as-json
+ AStringVector Params;
+ if (SplitZeroTerminatedStrings(a_ServerAddress, Params) && (Params.size() == 4))
+ {
+ LOGD("Player at %s connected via BungeeCord", Params[1].c_str());
+ m_ServerAddress = Params[0];
+ m_Client->SetIPString(Params[1]);
+ m_Client->SetUUID(cMojangAPI::MakeUUIDShort(Params[2]));
+ m_Client->SetProperties(Params[3]);
+ }
+
// Create the comm log file, if so requested:
if (g_ShouldLogCommIn || g_ShouldLogCommOut)
{
@@ -1033,9 +1046,9 @@ void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb)
cPacketizer Pkt(*this, 0x11);
Pkt.WriteVarInt(a_ExpOrb.GetUniqueID());
- Pkt.WriteInt((int) a_ExpOrb.GetPosX());
- Pkt.WriteInt((int) a_ExpOrb.GetPosY());
- Pkt.WriteInt((int) a_ExpOrb.GetPosZ());
+ Pkt.WriteFPInt(a_ExpOrb.GetPosX());
+ Pkt.WriteFPInt(a_ExpOrb.GetPosY());
+ Pkt.WriteFPInt(a_ExpOrb.GetPosZ());
Pkt.WriteShort(a_ExpOrb.GetReward());
}
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 8b395230a..d836291c3 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -27,7 +27,7 @@
cProtocolRecognizer::cProtocolRecognizer(cClientHandle * a_Client) :
super(a_Client),
m_Protocol(NULL),
- m_Buffer(512)
+ m_Buffer(8192) // We need a larger buffer to support BungeeCord - it sends one huge packet at the start
{
}
diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp
index 5f88cbf64..73147eebc 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -869,3 +869,31 @@ void SetBEInt(char * a_Mem, Int32 a_Value)
+
+bool SplitZeroTerminatedStrings(const AString & a_Strings, AStringVector & a_Output)
+{
+ a_Output.clear();
+ size_t size = a_Strings.size();
+ size_t start = 0;
+ bool res = false;
+ for (size_t i = 0; i < size; i++)
+ {
+ if (a_Strings[i] == 0)
+ {
+ a_Output.push_back(a_Strings.substr(start, i - start));
+ start = i + 1;
+ res = true;
+ }
+ }
+ if (start < size)
+ {
+ a_Output.push_back(a_Strings.substr(start, size - start));
+ res = true;
+ }
+
+ return res;
+}
+
+
+
+
diff --git a/src/StringUtils.h b/src/StringUtils.h
index 72a90a8c2..a76894d05 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -99,6 +99,11 @@ extern int GetBEInt(const char * a_Mem);
/// Writes four bytes to the specified memory location so that they interpret as BigEndian int
extern void SetBEInt(char * a_Mem, Int32 a_Value);
+/** Splits a string that has embedded \0 characters, on those characters.
+a_Output is first cleared and then each separate string is pushed back into a_Output.
+Returns true if there are at least two strings in a_Output (there was at least one \0 separator). */
+extern bool SplitZeroTerminatedStrings(const AString & a_Strings, AStringVector & a_Output);
+
/// Parses any integer type. Checks bounds and returns errors out of band.
template <class T>
bool StringToInteger(const AString & a_str, T & a_Num)
diff --git a/src/VoronoiMap.cpp b/src/VoronoiMap.cpp
index 5efd09c01..68147ebfc 100644
--- a/src/VoronoiMap.cpp
+++ b/src/VoronoiMap.cpp
@@ -10,11 +10,13 @@
-cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize) :
+cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize, int a_JitterSize) :
m_Noise1(a_Seed + 1),
m_Noise2(a_Seed + 2),
m_Noise3(a_Seed + 3),
- m_CellSize(a_CellSize),
+ m_CellSize(std::max(a_CellSize, 2)),
+ m_JitterSize(Clamp(a_JitterSize, 1, a_CellSize)),
+ m_OddRowOffset(0),
m_CurrentCellX(9999999), // Cell coords that are definitely out of the range for normal generator, so that the first query will overwrite them
m_CurrentCellZ(9999999)
{
@@ -26,7 +28,29 @@ cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize) :
void cVoronoiMap::SetCellSize(int a_CellSize)
{
+ a_CellSize = std::max(a_CellSize, 2); // Cell size must be at least 2
m_CellSize = a_CellSize;
+
+ // For compatibility with previous version, which didn't have the jitter, we set jitter here as well.
+ m_JitterSize = a_CellSize;
+}
+
+
+
+
+
+void cVoronoiMap::SetJitterSize(int a_JitterSize)
+{
+ m_JitterSize = Clamp(a_JitterSize, 1, m_CellSize);
+}
+
+
+
+
+
+void cVoronoiMap::SetOddRowOffset(int a_OddRowOffset)
+{
+ m_OddRowOffset = Clamp(a_OddRowOffset, -m_CellSize, m_CellSize);
}
@@ -111,12 +135,13 @@ void cVoronoiMap::UpdateCell(int a_CellX, int a_CellZ)
for (int x = 0; x < 5; x++)
{
int BaseX = (NoiseBaseX + x) * m_CellSize;
+ int OddRowOffset = ((NoiseBaseX + x) & 0x01) * m_OddRowOffset;
for (int z = 0; z < 5; z++)
{
- int OffsetX = (m_Noise1.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_CellSize;
- int OffsetZ = (m_Noise2.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_CellSize;
+ int OffsetX = (m_Noise1.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_JitterSize;
+ int OffsetZ = (m_Noise2.IntNoise2DInt(NoiseBaseX + x, NoiseBaseZ + z) / 8) % m_JitterSize;
m_SeedX[x][z] = BaseX + OffsetX;
- m_SeedZ[x][z] = (NoiseBaseZ + z) * m_CellSize + OffsetZ;
+ m_SeedZ[x][z] = (NoiseBaseZ + z) * m_CellSize + OddRowOffset + OffsetZ;
} // for z
} // for x
m_CurrentCellX = a_CellX;
diff --git a/src/VoronoiMap.h b/src/VoronoiMap.h
index 84cf206e9..49f6c1da1 100644
--- a/src/VoronoiMap.h
+++ b/src/VoronoiMap.h
@@ -18,18 +18,28 @@
class cVoronoiMap
{
public:
- cVoronoiMap(int a_Seed, int a_CellSize = 128);
+ cVoronoiMap(int a_Seed, int a_CellSize = 128, int a_JitterSize = 128);
- /// Sets the cell size used for generating the Voronoi seeds
+ /** Sets both the cell size and jitter size used for generating the Voronoi seeds. */
void SetCellSize(int a_CellSize);
+
+ /** Sets the jitter size. Clamps it to current cell size. */
+ void SetJitterSize(int a_JitterSize);
+
+ /** Sets the offset that is added to each odd row of cells.
+ This offset makes the voronoi cells align to a non-grid.
+ Clamps the value to [-m_CellSize, +m_CellSize]. */
+ void SetOddRowOffset(int a_OddRowOffset);
- /// Returns the value in the cell into which the specified point lies
+ /** Returns the value in the cell into which the specified point lies. */
int GetValueAt(int a_X, int a_Y);
- /// Returns the value in the cell into which the specified point lies, and the distance to the nearest Voronoi seed
+ /** Returns the value in the cell into which the specified point lies,
+ and the distance to the nearest Voronoi seed. */
int GetValueAt(int a_X, int a_Y, int & a_MinDistance);
- /// Returns the value in the cell into which the specified point lies, and the distances to the 2 nearest Voronoi seeds. Uses a cache
+ /** Returns the value in the cell into which the specified point lies,
+ and the distances to the 2 nearest Voronoi seeds. Uses a cache. */
int GetValueAt(int a_X, int a_Y, int & a_MinDistance1, int & a_MinDistance2);
protected:
@@ -38,8 +48,17 @@ protected:
cNoise m_Noise2;
cNoise m_Noise3;
- /// Size of the Voronoi cells (avg X/Y distance between the seeds)
+ /** Size of the Voronoi cells (avg X/Y distance between the seeds). Expected to be at least 2. */
int m_CellSize;
+
+ /** The amount that the cell seeds may be offset from the grid.
+ Expected to be at least 1 and less than m_CellSize. */
+ int m_JitterSize;
+
+ /** The constant amount that the cell seeds of every odd row will be offset from the grid.
+ This allows us to have non-rectangular grids.
+ Expected to be between -m_CellSize and +m_CellSize. */
+ int m_OddRowOffset;
/** The X coordinate of the currently cached cell neighborhood */
int m_CurrentCellX;
diff --git a/src/World.cpp b/src/World.cpp
index 43f7faf94..1de158b5f 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1727,7 +1727,7 @@ bool cWorld::SetAreaBiome(const cCuboid & a_Area, EMCSBiome a_Biome)
void cWorld::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
{
- m_ChunkMap->SetBlock(*this, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_SendToClients);
+ m_ChunkMap->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_SendToClients);
}
diff --git a/src/World.h b/src/World.h
index 44bf13b03..b07e90818 100644
--- a/src/World.h
+++ b/src/World.h
@@ -470,7 +470,7 @@ public:
int SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1);
/** Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. */
- int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward);
+ virtual int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) override;
/** Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided */
void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec = 80, double a_InitialVelocityCoeff = 1);