diff options
-rw-r--r-- | MCServer/Plugins/APIDump/APIDesc.lua | 8 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | src/BlockInfo.cpp | 26 | ||||
-rw-r--r-- | src/Blocks/BlockBed.cpp | 2 | ||||
-rw-r--r-- | src/Blocks/BlockDoor.cpp | 2 | ||||
-rw-r--r-- | src/Blocks/BlockFarmland.h | 99 | ||||
-rw-r--r-- | src/Blocks/BlockFire.h | 4 | ||||
-rw-r--r-- | src/Blocks/BlockGravel.h | 6 | ||||
-rw-r--r-- | src/Blocks/BlockHandler.cpp | 2 | ||||
-rw-r--r-- | src/Blocks/BlockMobHead.h | 12 | ||||
-rw-r--r-- | src/Blocks/BlockMobSpawner.h | 40 | ||||
-rw-r--r-- | src/Blocks/BlockPiston.cpp | 2 | ||||
-rw-r--r-- | src/Blocks/ChunkInterface.h | 4 | ||||
-rw-r--r-- | src/Blocks/WorldInterface.h | 3 | ||||
-rw-r--r-- | src/ChunkMap.cpp | 6 | ||||
-rw-r--r-- | src/ChunkMap.h | 4 | ||||
-rw-r--r-- | src/ClientHandle.cpp | 22 | ||||
-rw-r--r-- | src/Entities/Entity.cpp | 24 | ||||
-rw-r--r-- | src/Items/ItemHandler.cpp | 1 | ||||
-rw-r--r-- | src/Items/ItemHoe.h | 8 | ||||
-rw-r--r-- | src/Items/ItemPickaxe.h | 1 | ||||
-rw-r--r-- | src/Protocol/Protocol17x.cpp | 6 | ||||
-rw-r--r-- | src/World.cpp | 2 | ||||
-rw-r--r-- | src/World.h | 2 |
24 files changed, 189 insertions, 103 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index dae586ea8..2f791293d 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1887,13 +1887,13 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); }, BindCommand = { - { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." }, - { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." }, + { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split, {{cPlayer|Player}})</pre> The Split parameter contains an array-table of the words that the player has sent, Player is the {{cPlayer}} object representing the player who sent the command. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server sends a warning to the player that the command is unknown (this is so that subcommands can be implemented)." }, + { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split, {{cPlayer|Player}})</pre> The Split parameter contains an array-table of the words that the player has sent, Player is the {{cPlayer}} object representing the player who sent the command. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server sends a warning to the player that the command is unknown (this is so that subcommands can be implemented)." }, }, BindConsoleCommand = { - { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." }, - { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." }, + { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split)</pre> The Split parameter contains an array-table of the words that the admin has typed. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server issues a warning to the console that the command is unknown (this is so that subcommands can be implemented)." }, + { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error. The callback uses the following signature: <pre class=\"prettyprint lang-lua\">function(Split)</pre> The Split parameter contains an array-table of the words that the admin has typed. If the callback returns true, the command is assumed to have executed successfully; in all other cases the server issues a warning to the console that the command is unknown (this is so that subcommands can be implemented)." }, }, CallPlugin = { Params = "PluginName, FunctionName, [FunctionArgs...]", Return = "[FunctionRets]", Notes = "(STATIC) Calls the specified function in the specified plugin, passing all the given arguments to it. If it succeeds, it returns all the values returned by that function. If it fails, returns no value at all. Note that only strings, numbers, bools, nils and classes can be used for parameters and return values; tables and functions cannot be copied across plugins." }, DisablePlugin = { Params = "PluginName", Return = "bool", Notes = "Disables a plugin specified by its name. Returns true if the plugin was disabled, false if it wasn't found or wasn't active." }, @@ -12,8 +12,8 @@ Installation Normally, you will want to download a pre-compiled version of MCServer from one of the buildservers: - * [Linux and Raspberry Pi](http://ci.bearbin.net) (Bearbin's CI Server) - * [Windows](http://mc-server.xoft.cz) (xoft's nightly build service) + * [Windows and Linux](http://builds.mc-server.org) + * [Raspberry Pi](http://ci.bearbin.net) You simply need to download and extract these files before you can use the server. @@ -33,7 +33,7 @@ For other stuff, including plugins and discussion, check the [forums](http://for Earn bitcoins for commits or donate to reward the MCServer developers: [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74) -Support Us on Gittip: [![Support via Gittip](http://img.shields.io/gittip/mcs_team.svg)](https://www.gittip.com/mcs_team) +Support Us on Gratipay: [![Support via Gittip](http://img.shields.io/gittip/mcs_team.svg)](https://www.gittip.com/mcs_team) Travis CI: [![Build Status](http://img.shields.io/travis/mc-server/MCServer.svg)](https://travis-ci.org/mc-server/MCServer) diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index 9ac66d35d..0324cabf5 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -590,7 +590,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"; @@ -647,7 +647,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"; @@ -657,20 +657,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"; @@ -687,12 +687,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"; @@ -712,7 +712,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"; @@ -727,7 +727,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"; @@ -736,7 +736,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/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/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 3a9fbd170..d076306fb 100644 --- a/src/Blocks/BlockGravel.h +++ b/src/Blocks/BlockGravel.h @@ -18,13 +18,15 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - a_Pickups.Add(E_BLOCK_GRAVEL, 1, 0); - 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..8a8bdd3c8 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); diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h index ff1ef97bf..b51155802 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, cMonster::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, cMonster::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/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.h b/src/Blocks/ChunkInterface.h index dea9d7c7e..d5f1f1273 100644 --- a/src/Blocks/ChunkInterface.h +++ b/src/Blocks/ChunkInterface.h @@ -37,9 +37,9 @@ 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) { - 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 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 b43d011d8..889ef1d87 100644 --- a/src/Blocks/WorldInterface.h +++ b/src/Blocks/WorldInterface.h @@ -35,6 +35,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, cMonster::eType 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/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 ce77967db..170498037 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1134,6 +1134,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 +1453,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/Entities/Entity.cpp b/src/Entities/Entity.cpp index 9bcdcffeb..6969501a3 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -941,19 +941,21 @@ 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) + // Friction on ground + if (NextSpeed.SqrLength() > 0.0004f) { - NextSpeed.z = 0; + 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; + } } } diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 8dc346e53..f7882a50f 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -583,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; } 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/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/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index f24ef320d..f07f6a928 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -1033,9 +1033,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/World.cpp b/src/World.cpp index fdc0aebad..fe0be00ae 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 274bd2dcf..0c57e6611 100644 --- a/src/World.h +++ b/src/World.h @@ -469,7 +469,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); |