diff options
Diffstat (limited to 'src')
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); |