1
0
Fork 0

Refactored block-to-pickup conversion. (#4417)

This commit is contained in:
Mattes D 2019-10-16 10:06:34 +02:00 committed by GitHub
parent 241d97bbf9
commit 221cc4ec5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
121 changed files with 2496 additions and 1744 deletions

View File

@ -7909,6 +7909,17 @@ end
Notes = "Adds a new item to the end of the collection",
},
},
AddItemGrid =
{
Params =
{
{
Name = "ItemGrid",
Type = "cItemGrid",
},
},
Notes = "Adds a copy of each item in the specified {{cItemGrid|ItemGrid}}.",
},
Clear =
{
Notes = "Removes all items from the collection",
@ -7921,7 +7932,7 @@ end
Type = "cItems",
},
},
Notes = "Creates a new cItems object",
Notes = "Creates a new empty cItems object",
},
Contains =
{

View File

@ -562,7 +562,7 @@ function OnAllChunksAvailable()</pre> All return values from the callbacks are i
Type = "boolean",
},
},
Notes = "Replaces the specified block with air, without dropping the usual pickups for the block. Wakes up the simulators for the block and its neighbors. Returns true on success, or false if the chunk is not loaded or invalid coords.",
Notes = "Replaces the specified block with air, without dropping the usual pickups for the block. Wakes up the simulators for the block and its neighbors. Returns true on success, or false if the chunk is not loaded or invalid coords. See also DropBlockAsPickups() for the version that drops pickups.",
},
DoExplosionAt =
{
@ -1072,6 +1072,34 @@ function OnAllChunksAvailable()</pre> All return values from the callbacks are i
},
Notes = "If there is the player with the uuid, calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}})</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found.",
},
DropBlockAsPickups =
{
Params =
{
{
Name = "BlockPos",
Type = "Vector3i",
},
{
Name = "Digger",
Type = "cEntity",
IsOptional = true,
},
{
Name = "Tool",
Type = "cItem",
IsOptional = true,
},
},
Returns =
{
{
Name = "IsSuccess",
Type = "boolean",
}
},
Notes = "Digs up the specified block and spawns the appropriate pickups for it. The optional Digger parameter specifies the {{cEntity|entity}} who dug the block, usually a {{cPlayer|player}}. The optional Tool parameter specifies the tool used to dig the block, not present means an empty hand. Returns true on success, false if the chunk is not present. See also DigBlock() for the pickup-less version.",
},
FastSetBlock =
{
{
@ -2459,6 +2487,34 @@ function OnAllChunksAvailable()</pre> All return values from the callbacks are i
},
Notes = "Returns true if the specified location has wet weather (rain or storm), using the same logic as IsWeatherWetAt, except that any rain-blocking blocks above the specified position will block the precipitation and this function will return false.",
},
PickupsFromBlock =
{
Params =
{
{
Name = "BlockPos",
Type = "Vector3i",
},
{
Name = "Digger",
Type = "cEntity",
IsOptional = true,
},
{
Name = "Tool",
Type = "cItem",
IsOptional = true,
},
},
Returns =
{
{
Name = "Items",
Type = "cItems",
},
},
Notes = "Returns all the pickups that would result if the Digger dug up the block at BlockPos using Tool. Digger is usually a {{cPlayer}}, but can be nil for natural causes. Tool is usually the equipped {{cItem|item}}, can be nil for empty hand. Returns an empty {{cItems}} object if the chunk is not present."
},
PrepareChunk =
{
Params =
@ -2685,13 +2741,8 @@ function OnAllChunksAvailable()</pre> All return values from the callbacks are i
Name = "BlockMeta",
Type = "number",
},
{
Name = "ShouldSendToClients",
Type = "boolean",
IsOptional = true,
},
},
Notes = "Sets the block at the specified coords, replaces the block entities for the previous block type, creates a new block entity for the new block, if appropriate, and wakes up the simulators. This is the preferred way to set blocks, as opposed to FastSetBlock(), which is only to be used under special circumstances. If ShouldSendToClients is true (default), the change is broadcast to all players who have this chunk loaded; if false, the change is made server-side only.",
Notes = "Sets the block at the specified coords, replaces the block entities for the previous block type, creates a new block entity for the new block, if appropriate, and wakes up the simulators. This is the preferred way to set blocks, as opposed to FastSetBlock(), which is only to be used under special circumstances.",
},
SetBlockMeta =
{

View File

@ -44,7 +44,7 @@ public:
/** Calls the specified hook with the params given. Returns the bool that the hook callback returns. */
virtual bool OnBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0;
virtual bool OnBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0;
virtual bool OnBlockToPickups (cWorld & a_World, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, const cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool, cItems & a_Pickups) = 0;
virtual bool OnBrewingCompleting (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) = 0;
virtual bool OnBrewingCompleted (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) = 0;
virtual bool OnChat (cPlayer & a_Player, AString & a_Message) = 0;

View File

@ -227,9 +227,24 @@ bool cPluginLua::OnBlockSpread(cWorld & a_World, int a_BlockX, int a_BlockY, int
bool cPluginLua::OnBlockToPickups(cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups)
bool cPluginLua::OnBlockToPickups(
cWorld & a_World,
Vector3i a_BlockPos,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
const cBlockEntity * a_BlockEntity,
const cEntity * a_Digger,
const cItem * a_Tool,
cItems & a_Pickups
)
{
return CallSimpleHooks(cPluginManager::HOOK_BLOCK_TO_PICKUPS, &a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, &a_Pickups);
// TODO: Change the hook signature to reflect the real parameters to this function, once we are allowed to make breaking API changes
return CallSimpleHooks(
cPluginManager::HOOK_BLOCK_TO_PICKUPS,
&a_World,
a_Digger,
a_BlockPos.x, a_BlockPos.y, a_BlockPos.z,
a_BlockType, a_BlockMeta, &a_Pickups
);
}

View File

@ -66,7 +66,7 @@ public:
virtual void Tick(float a_Dt) override;
virtual bool OnBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) override;
virtual bool OnBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) override;
virtual bool OnBlockToPickups (cWorld & a_World, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, const cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool, cItems & a_Pickups) override;
virtual bool OnBrewingCompleting (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) override;
virtual bool OnBrewingCompleted (cWorld & a_World, cBrewingstandEntity & a_BrewingstandEntity) override;
virtual bool OnChat (cPlayer & a_Player, AString & a_Message) override;

View File

@ -248,14 +248,18 @@ bool cPluginManager::CallHookBlockSpread(cWorld & a_World, int a_BlockX, int a_B
bool cPluginManager::CallHookBlockToPickups(
cWorld & a_World, cEntity * a_Digger,
int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
cWorld & a_World,
Vector3i a_BlockPos,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
const cBlockEntity * a_BlockEntity,
const cEntity * a_Digger,
const cItem * a_Tool,
cItems & a_Pickups
)
{
return GenericCallHook(HOOK_BLOCK_TO_PICKUPS, [&](cPlugin * a_Plugin)
{
return a_Plugin->OnBlockToPickups(a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_Pickups);
return a_Plugin->OnBlockToPickups(a_World, a_BlockPos, a_BlockType, a_BlockMeta, a_BlockEntity, a_Digger, a_Tool, a_Pickups);
}
);
}

View File

@ -225,7 +225,7 @@ public:
// Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort
bool CallHookBlockSpread (cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source);
bool CallHookBlockToPickups (cWorld & a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups);
bool CallHookBlockToPickups (cWorld & a_World, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, const cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool, cItems & a_Pickups);
bool CallHookBrewingCompleting (cWorld & a_World, cBrewingstandEntity & a_Brewingstand);
bool CallHookBrewingCompleted (cWorld & a_World, cBrewingstandEntity & a_Brewingstand);
bool CallHookChat (cPlayer & a_Player, AString & a_Message);

View File

@ -14,6 +14,7 @@
#include "Blocks/BlockHandler.h"
#include "ChunkData.h"
#include "BlockEntities/BlockEntity.h"
#include "Item.h"
@ -2215,6 +2216,21 @@ bool cBlockArea::ForEachBlockEntity(cBlockEntityCallback a_Callback)
cItems cBlockArea::PickupsFromBlock(Vector3i a_AbsPos, const cEntity * a_Digger, const cItem * a_Tool)
{
auto relPos = a_AbsPos - m_Origin;
BLOCKTYPE blockType;
NIBBLETYPE blockMeta;
GetRelBlockTypeMeta(relPos.x, relPos.y, relPos.z, blockType, blockMeta);
auto blockEntity = GetBlockEntityRel(relPos);
auto handler = BlockHandler(blockType);
return handler->ConvertToPickups(blockMeta, blockEntity, a_Digger, a_Tool);
}
void cBlockArea::SetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array)
{
if (a_Array == nullptr)
@ -2710,6 +2726,20 @@ void cBlockArea::RemoveNonMatchingBlockEntities(void)
cBlockEntity * cBlockArea::GetBlockEntityRel(Vector3i a_RelPos)
{
if (!HasBlockEntities())
{
return nullptr;
}
auto itr = m_BlockEntities->find(MakeIndex(a_RelPos));
return (itr == m_BlockEntities->end()) ? nullptr : itr->second;
}
////////////////////////////////////////////////////////////////////////////////
// cBlockArea::sBlockEntityDeleter:

View File

@ -24,6 +24,7 @@
// fwd:
class cCuboid;
class cItems;
using cBlockEntityCallback = cFunctionRef<bool(cBlockEntity &)>;
@ -421,6 +422,9 @@ public:
/** Direct read-only access to block entities. */
const cBlockEntities & GetBlockEntities(void) const { ASSERT(HasBlockEntities()); return *m_BlockEntities; }
/** Returns the pickups that would result if the block at the specified position was mined by a_Digger, using a_Tool. */
cItems PickupsFromBlock(Vector3i a_AbsPos, const cEntity * a_Digger = nullptr, const cItem * a_Tool = nullptr);
protected:
@ -520,6 +524,9 @@ protected:
/** Removes from m_BlockEntities those BEs that no longer match the blocktype at their coords. */
void RemoveNonMatchingBlockEntities(void);
/** Returns the cBlockEntity at the specified coords, or nullptr if none. */
cBlockEntity * GetBlockEntityRel(Vector3i a_RelPos);
// tolua_begin
} ;
// tolua_end

View File

@ -27,11 +27,6 @@ public:
return cPluginManager::Get()->CallHookBlockSpread(m_World, a_BlockX, a_BlockY, a_BlockZ, a_Source);
}
virtual bool CallHookBlockToPickups(cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) override
{
return cPluginManager::Get()->CallHookBlockToPickups(m_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_Pickups);
}
virtual bool CallHookPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
{
return cPluginManager::Get()->CallHookPlayerBreakingBlock(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta);

View File

@ -18,11 +18,19 @@ public:
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2));
return cItem(m_BlockType, 1, a_BlockMeta >> 2);
}
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
cWindow * Window = new cAnvilWindow(a_BlockX, a_BlockY, a_BlockZ);

View File

@ -15,35 +15,33 @@
void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
void cBlockBedHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta)
{
Vector3i ThisPos(a_BlockX, a_BlockY, a_BlockZ);
NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(ThisPos);
Vector3i Direction = MetaDataToDirection(OldMeta & 0x3);
if (OldMeta & 0x8)
auto Direction = MetaDataToDirection(a_OldBlockMeta & 0x03);
if ((a_OldBlockMeta & 0x08) != 0)
{
// Was pillow
if (a_ChunkInterface.GetBlock(ThisPos - Direction) == E_BLOCK_BED)
if (a_ChunkInterface.GetBlock(a_BlockPos - Direction) == E_BLOCK_BED)
{
// First replace the bed with air
a_ChunkInterface.FastSetBlock(ThisPos - Direction, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockPos - Direction, E_BLOCK_AIR, 0);
// Then destroy the bed entity
Vector3i PillowPos(ThisPos - Direction);
a_ChunkInterface.SetBlock(PillowPos.x, PillowPos.y, PillowPos.z, E_BLOCK_AIR, 0);
Vector3i PillowPos(a_BlockPos - Direction);
a_ChunkInterface.SetBlock(PillowPos, E_BLOCK_AIR, 0);
}
}
else
{
// Was foot end
if (a_ChunkInterface.GetBlock(ThisPos + Direction) == E_BLOCK_BED)
if (a_ChunkInterface.GetBlock(a_BlockPos + Direction) == E_BLOCK_BED)
{
// First replace the bed with air
a_ChunkInterface.FastSetBlock(ThisPos + Direction, E_BLOCK_AIR, 0);
a_ChunkInterface.FastSetBlock(a_BlockPos + Direction, E_BLOCK_AIR, 0);
// Then destroy the bed entity
Vector3i FootPos(ThisPos + Direction);
a_ChunkInterface.SetBlock(FootPos.x, FootPos.y, FootPos.z, E_BLOCK_AIR, 0);
Vector3i FootPos(a_BlockPos + Direction);
a_ChunkInterface.SetBlock(FootPos, E_BLOCK_AIR, 0);
}
}
}
@ -155,14 +153,12 @@ void cBlockBedHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWor
void cBlockBedHandler::ConvertToPickups(cWorldInterface & a_WorldInterface, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
cItems cBlockBedHandler::ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool)
{
short Color = E_META_WOOL_RED;
a_WorldInterface.DoWithBedAt(a_BlockX, a_BlockY, a_BlockZ, [&](cBedEntity & a_Bed)
{
Color = a_Bed.GetColor();
return true;
}
);
a_Pickups.Add(cItem(E_ITEM_BED, 1, Color));
short color = E_META_WOOL_RED;
if (a_BlockEntity != nullptr)
{
color = reinterpret_cast<cBedEntity *>(a_BlockEntity)->GetColor();
}
return cItem(E_ITEM_BED, 1, color);
}

View File

@ -4,7 +4,7 @@
#pragma once
#include "BlockEntity.h"
#include "MetaRotator.h"
#include "Mixins.h"
#include "ChunkInterface.h"
@ -18,24 +18,28 @@ class cWorldInterface;
class cBlockBedHandler :
public cMetaRotator<cBlockEntityHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>
{
using super = cMetaRotator<cBlockEntityHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>;
public:
cBlockBedHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockEntityHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
cBlockBedHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
// Overrides:
virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override;
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override;
virtual void OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) override;
virtual bool IsUseable(void) override
{
return true;
}
virtual void ConvertToPickups(cItems & Pickups, NIBBLETYPE Meta) override {}
virtual void ConvertToPickups(cWorldInterface & a_WorldInterface, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ) override;
// Bed specific helper functions
static NIBBLETYPE RotationToMetaData(double a_Rotation)
@ -51,18 +55,26 @@ public:
return (static_cast<NIBBLETYPE>(a_Rotation + 2)) % 4;
}
static Vector3i MetaDataToDirection(NIBBLETYPE a_MetaData)
{
switch (a_MetaData)
{
case 0: return Vector3i(0, 0, 1);
case 1: return Vector3i(-1, 0, 0);
case 2: return Vector3i(0, 0, -1);
case 3: return Vector3i(1, 0, 0);
case 0: return Vector3i( 0, 0, 1);
case 1: return Vector3i(-1, 0, 0);
case 2: return Vector3i( 0, 0, -1);
case 3: return Vector3i( 1, 0, 0);
}
return Vector3i();
}
static void SetBedOccupationState(cChunkInterface & a_ChunkInterface, const Vector3i & a_BedPosition, bool a_IsOccupied)
{
auto Meta = a_ChunkInterface.GetBlockMeta(a_BedPosition);
@ -78,7 +90,9 @@ public:
a_ChunkInterface.SetBlockMeta(a_BedPosition.x, a_BedPosition.y, a_BedPosition.z, Meta);
}
virtual void OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) override;
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{

View File

@ -42,106 +42,53 @@ 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) override
{
Vector3i Pos(a_BlockX, a_BlockY, a_BlockZ);
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(Pos);
int AlternateY = a_BlockY;
int BottomY = a_BlockY;
if (Meta & 0x8)
{
--AlternateY;
--BottomY;
}
else
{
++AlternateY;
}
// also destroy the other block if it has a valid height and is a big flower
if (cChunkDef::IsValidHeight(AlternateY) && a_ChunkInterface.GetBlock({Pos.x, AlternateY, Pos.z}) == E_BLOCK_BIG_FLOWER)
{
super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, BottomY, a_BlockZ, a_CanDrop);
a_ChunkInterface.FastSetBlock(a_BlockX, AlternateY, a_BlockZ, E_BLOCK_AIR, 0);
}
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
if (IsMetaTopPart(a_BlockMeta))
{
return; // No way to tell flower type
return {}; // No drops from the top part
}
NIBBLETYPE Meta = a_BlockMeta & 0x7;
if (Meta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS)
// With shears, drop self (even tall grass and fern):
if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS))
{
// Bit 0x08 specifies whether this is a top part or bottom; cut it off from the pickup:
return cItem(m_BlockType, 1, a_BlockMeta & 0x07);
}
// Tall grass drops seeds, large fern drops nothing, others drop self:
auto flowerType = a_BlockMeta & 0x07;
if (flowerType == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS)
{
if (GetRandomProvider().RandBool(1.0 / 24.0))
{
a_Pickups.push_back(cItem(E_ITEM_SEEDS));
return cItem(E_ITEM_SEEDS);
}
}
else if (Meta != E_META_BIG_FLOWER_LARGE_FERN)
else if (flowerType != E_META_BIG_FLOWER_LARGE_FERN)
{
a_Pickups.push_back(cItem(E_BLOCK_BIG_FLOWER, 1, Meta));
return cItem(m_BlockType, 1, static_cast<short>(flowerType));
}
return {};
}
virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
{
Vector3i BlockPos(a_BlockX, a_BlockY, a_BlockZ);
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(BlockPos);
if (Meta & 0x8)
{
Meta = a_ChunkInterface.GetBlockMeta(BlockPos - Vector3i(0, 1, 0));
}
NIBBLETYPE FlowerMeta = Meta & 0x7;
if (!a_Player.IsGameModeCreative())
{
if (
(a_Player.GetEquippedItem().m_ItemType == E_ITEM_SHEARS) &&
(
(FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) ||
(FlowerMeta == E_META_BIG_FLOWER_LARGE_FERN)
)
)
{
if (GetRandomProvider().RandBool(0.10))
{
cItems Pickups;
if (FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS)
{
Pickups.Add(E_BLOCK_TALL_GRASS, 2, 1);
}
else if (FlowerMeta == E_META_BIG_FLOWER_LARGE_FERN)
{
Pickups.Add(E_BLOCK_TALL_GRASS, 2, 2);
}
a_WorldInterface.SpawnItemPickups(Pickups, BlockPos.x, BlockPos.y, BlockPos.z);
}
a_Player.UseEquippedItem();
}
}
if (
(a_Player.GetEquippedItem().m_ItemType != E_ITEM_SHEARS) &&
(
(FlowerMeta == E_META_BIG_FLOWER_DOUBLE_TALL_GRASS) ||
(FlowerMeta == E_META_BIG_FLOWER_LARGE_FERN)
)
)
{
a_ChunkInterface.SetBlock(BlockPos.x, BlockPos.y, BlockPos.z, 0, 0);
a_Player.UseEquippedItem(cItemHandler::dlaBreakBlockInstant);
}
}
bool IsMetaTopPart(NIBBLETYPE a_Meta)
{
return (a_Meta & 0x08) != 0;
return ((a_Meta & 0x08) != 0);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
if (a_RelY <= 0)
@ -155,31 +102,36 @@ public:
return IsBlockTypeOfDirt(BlockType) || ((BlockType == E_BLOCK_BIG_FLOWER) && !IsMetaTopPart(BlockMeta));
}
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override
{
Vector3i BlockPos(a_BlockX, a_BlockY, a_BlockZ);
NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(BlockPos);
if (OldMeta & 0x8)
virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override
{
if ((a_OldBlockMeta & 0x8) != 0)
{
// Was upper part of flower
Vector3i LowerPart = BlockPos - Vector3i(0, 1, 0);
if (a_ChunkInterface.GetBlock(LowerPart) == m_BlockType)
auto lowerPartPos = a_BlockPos - Vector3i(0, 1, 0);
if (a_ChunkInterface.GetBlock(lowerPartPos) == a_OldBlockType)
{
a_ChunkInterface.FastSetBlock(LowerPart, E_BLOCK_AIR, 0);
a_ChunkInterface.DropBlockAsPickups(lowerPartPos);
}
}
else
{
// Was lower part
Vector3i UpperPart = BlockPos + Vector3i(0, 1, 0);
if (a_ChunkInterface.GetBlock(UpperPart) == m_BlockType)
auto upperPartPos = a_BlockPos + Vector3i(0, 1, 0);
if (a_ChunkInterface.GetBlock(upperPartPos) == a_OldBlockType)
{
a_ChunkInterface.FastSetBlock(UpperPart, E_BLOCK_AIR, 0);
a_ChunkInterface.DropBlockAsPickups(upperPartPos);
}
}
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -2,28 +2,27 @@
#pragma once
#include "BlockEntity.h"
#include "MetaRotator.h"
#include "Mixins.h"
class cBlockBrewingStandHandler :
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
public cClearMetaOnDrop<cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>
{
using super = cClearMetaOnDrop<cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>;
public:
cBlockBrewingStandHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
cBlockBrewingStandHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_ITEM_BREWING_STAND, 1, 0));
}
virtual bool IsUseable() override
{
return true;
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{

View File

@ -2,20 +2,27 @@
#include "BlockHandler.h"
#include "../Chunk.h"
#include "MetaRotator.h"
#include "Mixins.h"
class cBlockButtonHandler :
public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>>
{
using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>>;
public:
cBlockButtonHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
cBlockButtonHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
Vector3i Pos(a_BlockX, a_BlockY, a_BlockZ);
@ -53,12 +60,6 @@ public:
return true;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
}
virtual bool IsUseable(void) override
{
return true;

View File

@ -8,21 +8,31 @@
class cBlockCactusHandler :
public cBlockPlant
public cBlockPlant<false>
{
typedef cBlockPlant Super;
using super = cBlockPlant<false>;
public:
cBlockCactusHandler(BLOCKTYPE a_BlockType)
: Super(a_BlockType, false)
cBlockCactusHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Reset meta to 0
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
return cItem(m_BlockType, 1, 0);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
if (a_RelY <= 0)
@ -88,7 +98,7 @@ protected:
auto Action = paStay;
if (((a_RelY + 1) < cChunkDef::Height) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR))
{
Action = Super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ);
Action = super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ);
}
return Action;

View File

@ -35,11 +35,20 @@ public:
return true;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Give nothing
return {};
}
virtual bool IsUseable(void) override
{
return true;

View File

@ -17,12 +17,19 @@
class cBlockCarpetHandler :
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockCarpetHandler(BLOCKTYPE a_BlockType) :
cBlockHandler(a_BlockType)
super(a_BlockType)
{
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -35,16 +42,19 @@ public:
return true;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_CARPET, 1, a_BlockMeta));
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
return (a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR);
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
switch (a_Meta)

View File

@ -8,17 +8,15 @@
class cBlockCauldronHandler :
public cBlockHandler
public cClearMetaOnDrop<cBlockHandler>
{
public:
cBlockCauldronHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
{
}
using super = cClearMetaOnDrop<cBlockHandler>;
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
public:
cBlockCauldronHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
a_Pickups.push_back(cItem(E_ITEM_CAULDRON, 1, 0));
}
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override

View File

@ -1,24 +1,31 @@
#pragma once
#include "BlockEntity.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockArea.h"
#include "../Entities/Player.h"
#include "MetaRotator.h"
#include "Mixins.h"
class cBlockChestHandler :
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
public cMetaRotator<cContainerEntityHandler<cBlockEntityHandler>, 0x07, 0x02, 0x05, 0x03, 0x04>
{
using super = cMetaRotator<cContainerEntityHandler<cBlockEntityHandler>, 0x07, 0x02, 0x05, 0x03, 0x04>;
public:
cBlockChestHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
cBlockChestHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -65,6 +72,10 @@ public:
return true;
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
@ -72,6 +83,10 @@ public:
return CanBeAt(a_ChunkInterface, BlockX, a_RelY, BlockZ);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{
cBlockArea Area;
@ -137,6 +152,10 @@ public:
return (NumChestNeighbors < 2);
}
/** Translates player yaw when placing a chest into the chest block metadata. Valid for single chests only */
static NIBBLETYPE PlayerYawToMetaData(double a_Yaw)
{
@ -164,6 +183,10 @@ public:
}
}
/** If there's a chest in the a_Area in the specified coords, modifies its meta to a_NewMeta and returns true. */
bool CheckAndAdjustNeighbor(cChunkInterface & a_ChunkInterface, const cBlockArea & a_Area, int a_RelX, int a_RelZ, NIBBLETYPE a_NewMeta)
{
@ -175,10 +198,9 @@ public:
return true;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{

View File

@ -18,11 +18,27 @@ public:
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(E_ITEM_STRING, 1, 0));
// Silk touch gives cobweb, anything else gives just string:
if (ToolHasSilkTouch(a_Tool))
{
return cItem(m_BlockType, 1, 0);
}
else
{
return cItem(E_ITEM_STRING, 1, 0);
}
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -44,12 +44,21 @@ public:
}
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
int GrowState = a_BlockMeta >> 2;
a_Pickups.Add(E_ITEM_DYE, ((GrowState >= 2) ? 3 : 1), E_META_DYE_BROWN);
// If fully grown, give 3 items, otherwise just one:
auto growState = a_BlockMeta >> 2;
return cItem(E_ITEM_DYE, ((growState >= 2) ? 3 : 1), E_META_DYE_BROWN);
}
static eBlockFace MetaToBlockFace(NIBBLETYPE a_Meta)
{
switch (a_Meta & 0x3)

View File

@ -10,17 +10,29 @@
class cBlockCommandBlockHandler :
public cBlockEntityHandler
{
using super = cBlockEntityHandler;
public:
cBlockCommandBlockHandler(BLOCKTYPE a_BlockType)
: cBlockEntityHandler(a_BlockType)
cBlockCommandBlockHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(E_BLOCK_AIR, 8, 0));
// Don't allow as a pickup:
return {};
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -3,18 +3,21 @@
#include "BlockHandler.h"
#include "BlockRedstoneRepeater.h"
#include "MetaRotator.h"
#include "Mixins.h"
class cBlockComparatorHandler :
public cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>>
{
using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>>;
public:
cBlockComparatorHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType)
cBlockComparatorHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
@ -32,12 +35,6 @@ public:
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
a_Pickups.push_back(cItem(E_ITEM_COMPARATOR, 1, 0));
}
virtual bool IsUseable(void) override
{
return true;

View File

@ -10,9 +10,12 @@
class cBlockConcretePowderHandler :
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockConcretePowderHandler(BLOCKTYPE a_BlockType):
cBlockHandler(a_BlockType)
super(a_BlockType)
{
}
@ -20,21 +23,25 @@ public:
virtual void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override
virtual void Check(
cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk
) override
{
if (GetSoaked(Vector3i(a_RelX, a_RelY, a_RelZ), a_Chunk))
if (GetSoaked(a_RelPos, a_Chunk))
{
return;
}
cBlockHandler::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk);
super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk);
}
/** Check blocks above and around to see if they are water. If one is, convert this into concrete block.
Returns TRUE if the block was changed. */
/** Check blocks above and around to see if they are water. If one is, converts this into concrete block.
Returns true if the block was changed. */
bool GetSoaked(Vector3i a_Rel, cChunk & a_Chunk)
{
static const std::array<Vector3i, 5> WaterCheck
@ -62,7 +69,7 @@ public:
{
NIBBLETYPE BlockMeta;
BlockMeta = a_Chunk.GetMeta(a_Rel.x, a_Rel.y, a_Rel.z);
a_Chunk.SetBlock(a_Rel.x, a_Rel.y, a_Rel.z, E_BLOCK_CONCRETE, BlockMeta);
a_Chunk.SetBlock(a_Rel, E_BLOCK_CONCRETE, BlockMeta);
return true;
}
return false;

View File

@ -10,71 +10,70 @@
/** Common class that takes care of beetroots, carrots, potatoes and wheat */
template <NIBBLETYPE RipeMeta>
class cBlockCropsHandler :
public cBlockPlant
class cBlockCropsHandler:
public cBlockPlant<true>
{
typedef cBlockPlant Super;
using super = cBlockPlant<true>;
public:
cBlockCropsHandler(BLOCKTYPE a_BlockType):
Super(a_BlockType, true)
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
auto & rand = GetRandomProvider();
// If not fully grown, drop the "seed" of whatever is growing:
if (a_Meta < RipeMeta)
if (a_BlockMeta < RipeMeta)
{
switch (m_BlockType)
{
case E_BLOCK_BEETROOTS: a_Pickups.push_back(cItem(E_ITEM_BEETROOT_SEEDS, 1, 0)); break;
case E_BLOCK_CROPS: a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1, 0)); break;
case E_BLOCK_CARROTS: a_Pickups.push_back(cItem(E_ITEM_CARROT, 1, 0)); break;
case E_BLOCK_POTATOES: a_Pickups.push_back(cItem(E_ITEM_POTATO, 1, 0)); break;
default:
{
ASSERT(!"Unhandled block type");
break;
}
case E_BLOCK_BEETROOTS: return cItem(E_ITEM_BEETROOT_SEEDS, 1, 0); break;
case E_BLOCK_CROPS: return cItem(E_ITEM_SEEDS, 1, 0); break;
case E_BLOCK_CARROTS: return cItem(E_ITEM_CARROT, 1, 0); break;
case E_BLOCK_POTATOES: return cItem(E_ITEM_POTATO, 1, 0); break;
}
return;
ASSERT(!"Unhandled block type");
return {};
}
// Fully grown, drop the crop's produce:
cItems res;
switch (m_BlockType)
{
case E_BLOCK_BEETROOTS:
{
char SeedCount = 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2); // [1 .. 3] with high preference of 2
a_Pickups.emplace_back(E_ITEM_BEETROOT_SEEDS, SeedCount, 0);
res.Add(E_ITEM_BEETROOT_SEEDS, SeedCount, 0);
char BeetrootCount = 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2); // [1 .. 3] with high preference of 2
a_Pickups.emplace_back(E_ITEM_BEETROOT, BeetrootCount, 0);
res.Add(E_ITEM_BEETROOT, BeetrootCount, 0);
break;
}
case E_BLOCK_CROPS:
{
a_Pickups.emplace_back(E_ITEM_WHEAT, 1, 0);
a_Pickups.emplace_back(E_ITEM_SEEDS, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2
res.Add(E_ITEM_WHEAT, 1, 0);
res.Add(E_ITEM_SEEDS, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2
break;
}
case E_BLOCK_CARROTS:
{
a_Pickups.emplace_back(E_ITEM_CARROT, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2
res.Add(E_ITEM_CARROT, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2
break;
}
case E_BLOCK_POTATOES:
{
a_Pickups.emplace_back(E_ITEM_POTATO, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2
res.Add(E_ITEM_POTATO, 1 + ((rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2), 0); // [1 .. 3] with high preference of 2
if (rand.RandBool(0.05))
{
// With a 5% chance, drop a poisonous potato as well
a_Pickups.emplace_back(E_ITEM_POISONOUS_POTATO, 1, 0);
res.emplace_back(E_ITEM_POISONOUS_POTATO, 1, 0);
}
break;
}
@ -84,10 +83,13 @@ public:
break;
}
} // switch (m_BlockType)
return res;
}
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);

View File

@ -43,57 +43,34 @@ public:
}
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Drop 0-3 sticks
char chance = GetRandomProvider().RandInt<char>(3);
if (chance != 0)
// If cutting down with shears, drop self:
if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS))
{
a_Pickups.emplace_back(E_ITEM_STICK, chance, 0);
return cItem(m_BlockType, 1, a_BlockMeta);
}
// Drop 0-3 sticks:
auto chance = GetRandomProvider().RandInt<char>(3);
if (chance > 0)
{
return cItem(E_ITEM_STICK, chance, 0);
}
return {};
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);
return 0;
}
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
{
if (a_CanDrop && (a_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_ItemType == E_ITEM_SHEARS))
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
cItems Drops;
Drops.Add(m_BlockType, 1, Meta);
// Allow plugins to modify the pickups:
a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Drops);
// Spawn the pickups:
if (!Drops.empty())
{
auto & r1 = GetRandomProvider();
// Mid-block position first
double MicroX, MicroY, MicroZ;
MicroX = a_BlockX + 0.5;
MicroY = a_BlockY + 0.5;
MicroZ = a_BlockZ + 0.5;
// Add random offset second
MicroX += r1.RandReal<double>(-0.5, 0.5);
MicroZ += r1.RandReal<double>(-0.5, 0.5);
a_WorldInterface.SpawnItemPickups(Drops, MicroX, MicroY, MicroZ);
}
return;
}
super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop);
}
} ;

View File

@ -20,19 +20,27 @@ public:
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
if (a_BlockMeta == E_META_DIRT_COARSE)
{
// Drop the coarse block (dirt, meta 1)
a_Pickups.Add(E_BLOCK_DIRT, 1, E_META_DIRT_COARSE);
return cItem(E_BLOCK_DIRT, 1, E_META_DIRT_COARSE);
}
else
{
a_Pickups.Add(E_BLOCK_DIRT, 1, E_META_DIRT_NORMAL);
return cItem(E_BLOCK_DIRT, 1, E_META_DIRT_NORMAL);
}
}
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
if (m_BlockType != E_BLOCK_GRASS)

View File

@ -7,8 +7,8 @@
cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType)
: super(a_BlockType)
cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
@ -16,24 +16,22 @@ cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType)
void cBlockDoorHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
void cBlockDoorHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta)
{
NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
if (OldMeta & 8)
if ((a_OldBlockMeta & 0x08) != 0)
{
// Was upper part of door
if (IsDoorBlockType(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY - 1, a_BlockZ})))
if ((a_BlockPos.y > 0) && IsDoorBlockType(a_ChunkInterface.GetBlock(a_BlockPos.addedY(-1))))
{
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.DropBlockAsPickups(a_BlockPos.addedY(-1));
}
}
else
{
// Was lower part
if (IsDoorBlockType(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY + 1, a_BlockZ})))
if ((a_BlockPos.y < cChunkDef::Height - 1) && IsDoorBlockType(a_ChunkInterface.GetBlock(a_BlockPos.addedY(1))))
{
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_AIR, 0);
a_ChunkInterface.DropBlockAsPickups(a_BlockPos.addedY(1));
}
}
}

View File

@ -4,7 +4,7 @@
#include "BlockHandler.h"
#include "../Entities/Player.h"
#include "../Chunk.h"
#include "MetaRotator.h"
#include "Mixins.h"
#include "ChunkInterface.h"
#include "BlockSlab.h"
@ -13,11 +13,13 @@
class cBlockDoorHandler :
public cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true>
{
typedef cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> super;
using super = cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true>;
public:
cBlockDoorHandler(BLOCKTYPE a_BlockType);
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta) override;
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override;
@ -54,57 +56,39 @@ public:
virtual cBoundingBox GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a_XP, BLOCKTYPE a_YM, BLOCKTYPE a_YP, BLOCKTYPE a_ZM, BLOCKTYPE a_ZP) override;
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
if ((a_BlockMeta & 0x08) != 0) // is top part of door
// Top part of a door doesn't drop anything:
if ((a_BlockMeta & 0x08) != 0)
{
return;
return {};
}
switch (m_BlockType)
{
case E_BLOCK_OAK_DOOR:
{
a_Pickups.Add(E_ITEM_WOODEN_DOOR);
break;
}
case E_BLOCK_ACACIA_DOOR:
{
a_Pickups.Add(E_ITEM_ACACIA_DOOR);
break;
}
case E_BLOCK_BIRCH_DOOR:
{
a_Pickups.Add(E_ITEM_BIRCH_DOOR);
break;
}
case E_BLOCK_DARK_OAK_DOOR:
{
a_Pickups.Add(E_ITEM_DARK_OAK_DOOR);
break;
}
case E_BLOCK_JUNGLE_DOOR:
{
a_Pickups.Add(E_ITEM_JUNGLE_DOOR);
break;
}
case E_BLOCK_SPRUCE_DOOR:
{
a_Pickups.Add(E_ITEM_SPRUCE_DOOR);
break;
}
case E_BLOCK_IRON_DOOR:
{
a_Pickups.Add(E_ITEM_IRON_DOOR);
break;
}
case E_BLOCK_OAK_DOOR: return cItem(E_ITEM_WOODEN_DOOR);
case E_BLOCK_ACACIA_DOOR: return cItem(E_ITEM_ACACIA_DOOR);
case E_BLOCK_BIRCH_DOOR: return cItem(E_ITEM_BIRCH_DOOR);
case E_BLOCK_DARK_OAK_DOOR: return cItem(E_ITEM_DARK_OAK_DOOR);
case E_BLOCK_JUNGLE_DOOR: return cItem(E_ITEM_JUNGLE_DOOR);
case E_BLOCK_SPRUCE_DOOR: return cItem(E_ITEM_SPRUCE_DOOR);
case E_BLOCK_IRON_DOOR: return cItem(E_ITEM_IRON_DOOR);
default:
{
ASSERT(!"Unhandled door type!");
break;
return {};
}
}
}
virtual bool IsUseable(void) override
{
return true;

View File

@ -6,7 +6,8 @@
#pragma once
#include "../Blocks/BlockPiston.h"
#include "MetaRotator.h"
#include "../BlockEntities/DropSpenserEntity.h"
#include "Mixins.h"
@ -15,12 +16,19 @@
class cBlockDropSpenserHandler :
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
using super = cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>;
public:
cBlockDropSpenserHandler(BLOCKTYPE a_BlockType) :
cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
cBlockDropSpenserHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -35,18 +43,30 @@ public:
return true;
}
/** Called when the drop / dispenser is convert into pickup, ignore meta data */
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
UNUSED(a_BlockMeta);
a_Pickups.push_back(cItem(m_BlockType, 1));
cItems res(cItem(m_BlockType, 1));
if (a_BlockEntity != nullptr)
{
auto be = static_cast<cDropSpenserEntity *>(a_BlockEntity);
res.AddItemGrid(be->GetContents());
}
return res;
}
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
{
// Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000
// Bit 0x08 is a flag. Lowest three bits are position.
NIBBLETYPE OtherMeta = a_Meta & 0x08;
// Mirrors defined by by a table. (Source, mincraft.gamepedia.com) 0x07 == 0111
// Mirrors defined by a table. (Source, minecraft.gamepedia.com)
switch (a_Meta & 0x07)
{
case 0x00: return 0x01 + OtherMeta; // Down -> Up
@ -56,6 +76,10 @@ public:
return a_Meta;
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -76,7 +76,7 @@ public:
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
{
// E_META_END_PORTAL_FRAME_EYE is the bit which signifies the eye of ender is in it.
// LOG("PortalPlaced, meta %d", a_BlockMeta);
@ -84,7 +84,7 @@ public:
{
// LOG("Location is %d %d %d", a_BlockX, a_BlockY, a_BlockZ);
// Direction is the first two bits, masked by 0x3
FindAndSetPortal(Vector3i(a_BlockX, a_BlockY, a_BlockZ), a_BlockMeta & 3, a_ChunkInterface, a_WorldInterface);
FindAndSetPortal(a_BlockPos, a_BlockMeta & 3, a_ChunkInterface, a_WorldInterface);
}
}

View File

@ -2,7 +2,7 @@
#pragma once
#include "BlockEntity.h"
#include "MetaRotator.h"
#include "Mixins.h"
@ -10,17 +10,44 @@
class cBlockEnderchestHandler :
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
using super = cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>;
public:
cBlockEnderchestHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
cBlockEnderchestHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(E_BLOCK_OBSIDIAN, 8, 0));
// Only drop something when mined with a pickaxe:
if (
(a_Tool != nullptr) &&
ItemCategory::IsPickaxe(a_Tool->m_ItemType)
)
{
// Only drop self when mined with a silk-touch pickaxe:
if (a_Tool->m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0)
{
return cItem(E_BLOCK_ENDER_CHEST, 1, 0);
}
else
{
return cItem(E_BLOCK_OBSIDIAN, 8, 0);
}
}
return {};
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,

View File

@ -3,23 +3,40 @@
#include "BlockHandler.h"
#include "ChunkInterface.h"
#include "../Item.h"
#include "../BlockEntities/BlockEntityWithItems.h"
class cBlockEntityHandler : public cBlockHandler
/** Wrapper for blocks that have a cBlockEntity descendant attached to them and can be "used" by the player.
Forwards the "use" event to the block entity. */
class cBlockEntityHandler:
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockEntityHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockEntityHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
return a_ChunkInterface.UseBlockEntity(&a_Player, a_BlockX, a_BlockY, a_BlockZ);
}
virtual bool IsUseable() override
{
return true;
@ -29,3 +46,35 @@ public:
/** Wrapper for blocks that have a cBlockEntityWithItems descendant attached to them.
When converting to pickups, drops self with meta reset to zero, and adds the container contents. */
template <typename Base = cBlockEntityHandler>
class cContainerEntityHandler:
public Base
{
public:
cContainerEntityHandler(BLOCKTYPE a_BlockType):
Base(a_BlockType)
{
}
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Reset meta to 0
cItems res(cItem(Base::m_BlockType, 1, 0));
// Drop the contents:
if (a_BlockEntity != nullptr)
{
auto container = static_cast<cBlockEntityWithItems *>(a_BlockEntity);
res.AddItemGrid(container->GetContents());
}
return res;
}
};

View File

@ -17,15 +17,21 @@
class cBlockFarmlandHandler :
public cBlockHandler
public cClearMetaOnDrop<cBlockHandler>
{
using super = cClearMetaOnDrop<cBlockHandler>;
public:
cBlockFarmlandHandler(BLOCKTYPE a_BlockType) :
cBlockHandler(a_BlockType)
cBlockFarmlandHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
NIBBLETYPE BlockMeta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
@ -60,14 +66,17 @@ public:
}
default:
{
a_Chunk.SetBlock(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, eBlockFace a_WhichNeighbor) override
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override
{
// Don't care about any neighbor but the one above us (fix recursion loop in #2213):
if (a_WhichNeighbor != BLOCK_FACE_YP)
@ -76,24 +85,21 @@ public:
}
// Don't care about anything if we're at the top of the world:
if (a_BlockY >= cChunkDef::Height)
if (a_BlockPos.y >= cChunkDef::Height)
{
return;
}
// Check whether we should revert to dirt:
BLOCKTYPE UpperBlock = a_ChunkInterface.GetBlock({a_BlockX, a_BlockY + 1, a_BlockZ});
if (cBlockInfo::FullyOccupiesVoxel(UpperBlock))
auto upperBlock = a_ChunkInterface.GetBlock(a_BlockPos.addedY(1));
if (cBlockInfo::FullyOccupiesVoxel(upperBlock))
{
a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DIRT, 0);
a_ChunkInterface.SetBlock(a_BlockPos, 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)

View File

@ -122,13 +122,21 @@ public:
return true;
}
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override
{
auto LeashKnot = cLeashKnot::FindKnotAtPos(a_WorldInterface, { a_BlockX, a_BlockY, a_BlockZ });
if (LeashKnot != nullptr)
virtual void OnBroken(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) override
{
// Destroy any leash knot tied to the fence:
auto leashKnot = cLeashKnot::FindKnotAtPos(a_WorldInterface, a_BlockPos);
if (leashKnot != nullptr)
{
LeashKnot->SetShouldSelfDestroy();
leashKnot->SetShouldSelfDestroy();
}
}

View File

@ -2,24 +2,22 @@
#pragma once
#include "BlockHandler.h"
#include "MetaRotator.h"
#include "Mixins.h"
#include "../EffectID.h"
class cBlockFenceGateHandler :
public cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>>
{
public:
cBlockFenceGateHandler(BLOCKTYPE a_BlockType) :
cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
{
}
using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>>;
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
public:
cBlockFenceGateHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
a_Pickups.Add(m_BlockType, 1, 0); // Reset meta to zero
}
virtual bool GetPlacementBlockTypeMeta(

View File

@ -18,11 +18,16 @@ public:
}
/** Portal boundary and direction variables */
// 2014_03_30 _X: What are these used for? Why do we need extra variables?
// TODO: These need to be removed, BlockHandler instances are shared for all blocks in all worlds on the server
// and are not supposed to have any data in them.
int XZP, XZM;
NIBBLETYPE Dir;
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
{
/*
PORTAL FINDING ALGORITH
@ -38,14 +43,23 @@ public:
*/
// a_BlockY - 1: Because we want the block below the fire
FindAndSetPortalFrame(a_BlockX, a_BlockY - 1, a_BlockZ, a_ChunkInterface, a_WorldInterface);
FindAndSetPortalFrame(a_BlockPos.x, a_BlockPos.y - 1, a_BlockPos.z, a_ChunkInterface, a_WorldInterface);
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// No pickups from this block
return {};
}
virtual bool IsClickedThrough(void) override
{
return true;
@ -102,6 +116,10 @@ public:
return true;
}
/** Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE) */
void FindAndSetPortalFrame(int X, int Y, int Z, cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface)
{

View File

@ -16,13 +16,20 @@ public:
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
NIBBLETYPE Meta = a_BlockMeta & 0x7;
a_Pickups.push_back(cItem(m_BlockType, 1, Meta));
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
NIBBLETYPE meta = a_BlockMeta & 0x7;
return cItem(m_BlockType, 1, meta);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ));

View File

@ -8,18 +8,20 @@
class cBlockFlowerPotHandler :
public cBlockEntityHandler
public cClearMetaOnDrop<cBlockEntityHandler>
{
using super = cClearMetaOnDrop<cBlockEntityHandler>;
public:
cBlockFlowerPotHandler(BLOCKTYPE a_BlockType) :
cBlockEntityHandler(a_BlockType)
cBlockFlowerPotHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_ITEM_FLOWER_POT, 1, 0));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{

View File

@ -19,34 +19,55 @@ public:
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// No pickups
return {};
}
virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override
{
return true;
}
virtual void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override
virtual void Check(
cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk
) override
{
switch (m_BlockType)
{
case E_BLOCK_STATIONARY_LAVA:
{
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_LAVA, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_LAVA, a_Chunk.GetMeta(a_RelPos));
break;
}
case E_BLOCK_STATIONARY_WATER:
{
a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_WATER, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
a_Chunk.FastSetBlock(a_RelPos, E_BLOCK_WATER, a_Chunk.GetMeta(a_RelPos));
break;
}
}
super::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk);
super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk);
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -3,24 +3,26 @@
#include "BlockEntity.h"
#include "../Blocks/BlockPiston.h"
#include "MetaRotator.h"
#include "Mixins.h"
class cBlockFurnaceHandler :
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
public cClearMetaOnDrop<cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>
{
using super = cClearMetaOnDrop<cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>;
public:
cBlockFurnaceHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
cBlockFurnaceHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_FURNACE, 1, 0));
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
@ -37,6 +39,10 @@ public:
return true;
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -16,10 +16,24 @@ public:
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Only drop self when mined with silk-touch:
if (ToolHasSilkTouch(a_Tool))
{
return cItem(m_BlockType, 1, a_BlockMeta);
}
return {};
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -16,12 +16,28 @@ public:
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Add more than one dust
a_Pickups.emplace_back(E_ITEM_GLOWSTONE_DUST, GetRandomProvider().RandInt<char>(2, 4), 0);
// Drop self only when using silk-touch:
if (ToolHasSilkTouch(a_Tool))
{
return cItem(E_BLOCK_GLOWSTONE, 1, 0);
}
else
{
// TODO: Handle the Fortune enchantment here
return cItem(E_ITEM_GLOWSTONE_DUST, GetRandomProvider().RandInt<char>(2, 4), 0);
}
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -16,18 +16,27 @@ public:
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// TODO: Handle the Fortune and Silk touch enchantments here
if (GetRandomProvider().RandBool(0.10))
{
a_Pickups.Add(E_ITEM_FLINT, 1, 0);
return cItem(E_ITEM_FLINT, 1, 0);
}
else
{
a_Pickups.Add(E_BLOCK_GRAVEL, 1, 0);
return cItem(E_BLOCK_GRAVEL, 1, 0);
}
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -189,6 +189,7 @@ static cBlockHandler * CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_ACACIA_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType);
case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
case E_BLOCK_AIR: return new cBlockWithNoDrops<> (a_BlockType);
case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType);
case E_BLOCK_BEACON: return new cBlockEntityHandler (a_BlockType);
case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType);
@ -401,185 +402,72 @@ void cBlockHandler::OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface
void cBlockHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange)
{
OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(), a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta);
OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockChange.GetPos(), a_BlockChange.m_BlockType, a_BlockChange.m_BlockMeta);
}
void cBlockHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
{
}
void cBlockHandler::OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
void cBlockHandler::OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
// Notify the neighbors
NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ, BLOCK_FACE_XP);
NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ, BLOCK_FACE_XM);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_YP);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_YM);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1, BLOCK_FACE_ZP);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ + 1, BLOCK_FACE_ZM);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedX(-1), BLOCK_FACE_XP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedX( 1), BLOCK_FACE_XM);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedY(-1), BLOCK_FACE_YP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedY( 1), BLOCK_FACE_YM);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ(-1), BLOCK_FACE_ZP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ( 1), BLOCK_FACE_ZM);
}
void cBlockHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
void cBlockHandler::OnBroken(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta)
{
// Notify the neighbors
NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ, BLOCK_FACE_XP);
NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ, BLOCK_FACE_XM);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ, BLOCK_FACE_YP);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ, BLOCK_FACE_YM);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1, BLOCK_FACE_ZP);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ + 1, BLOCK_FACE_ZM);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedX(-1), BLOCK_FACE_XP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedX( 1), BLOCK_FACE_XM);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedY(-1), BLOCK_FACE_YP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedY( 1), BLOCK_FACE_YM);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ(-1), BLOCK_FACE_ZP);
NeighborChanged(a_ChunkInterface, a_BlockPos.addedZ( 1), BLOCK_FACE_ZM);
}
void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_NeighborX, int a_NeighborY, int a_NeighborZ, eBlockFace a_WhichNeighbor)
void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_NeighborPos, eBlockFace a_WhichNeighbor)
{
if ((a_NeighborY >= 0) && (a_NeighborY < cChunkDef::Height))
if (!cChunkDef::IsValidHeight(a_NeighborPos.y))
{
cBlockInfo::GetHandler(a_ChunkInterface.GetBlock({a_NeighborX, a_NeighborY, a_NeighborZ}))->OnNeighborChanged(a_ChunkInterface, a_NeighborX, a_NeighborY, a_NeighborZ, a_WhichNeighbor);
return;
}
cBlockInfo::GetHandler(a_ChunkInterface.GetBlock(a_NeighborPos))->OnNeighborChanged(a_ChunkInterface, a_NeighborPos, a_WhichNeighbor);
}
void cBlockHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
cItems cBlockHandler::ConvertToPickups(
NIBBLETYPE a_BlockMeta,
cBlockEntity * a_BlockEntity,
const cEntity * a_Digger,
const cItem * a_Tool
)
{
// Setting the meta to a_BlockMeta keeps most textures. The few other blocks have to override this.
a_Pickups.push_back(cItem(m_BlockType, 1, a_BlockMeta));
}
UNUSED(a_BlockEntity);
UNUSED(a_Digger);
UNUSED(a_Tool);
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_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0))
{
switch (m_BlockType)
{
case E_BLOCK_ACACIA_DOOR:
case E_BLOCK_ACTIVE_COMPARATOR:
case E_BLOCK_BEETROOTS:
case E_BLOCK_BIRCH_DOOR:
case E_BLOCK_BREWING_STAND:
case E_BLOCK_CAKE:
case E_BLOCK_CARROTS:
case E_BLOCK_CAULDRON:
case E_BLOCK_COCOA_POD:
case E_BLOCK_CROPS:
case E_BLOCK_DARK_OAK_DOOR:
case E_BLOCK_DEAD_BUSH:
case E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB:
case E_BLOCK_DOUBLE_STONE_SLAB:
case E_BLOCK_DOUBLE_WOODEN_SLAB:
case E_BLOCK_FIRE:
case E_BLOCK_FARMLAND:
case E_BLOCK_FLOWER_POT:
case E_BLOCK_HEAD:
case E_BLOCK_INACTIVE_COMPARATOR:
case E_BLOCK_INVERTED_DAYLIGHT_SENSOR:
case E_BLOCK_IRON_DOOR:
case E_BLOCK_JUNGLE_DOOR:
case E_BLOCK_MELON_STEM:
case E_BLOCK_MOB_SPAWNER:
case E_BLOCK_NETHER_WART:
case E_BLOCK_OAK_DOOR:
case E_BLOCK_PISTON_EXTENSION:
case E_BLOCK_POTATOES:
case E_BLOCK_PUMPKIN_STEM:
case E_BLOCK_PURPUR_DOUBLE_SLAB:
case E_BLOCK_REDSTONE_ORE_GLOWING:
case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON:
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_WIRE:
case E_BLOCK_SIGN_POST:
case E_BLOCK_SNOW:
case E_BLOCK_SPRUCE_DOOR:
case E_BLOCK_STANDING_BANNER:
case E_BLOCK_SUGARCANE:
case E_BLOCK_TALL_GRASS:
case E_BLOCK_TRIPWIRE:
case E_BLOCK_WALL_BANNER:
case E_BLOCK_WALLSIGN:
{
// Silktouch can't be used for these blocks
ConvertToPickups(Pickups, Meta);
break;
}
case E_BLOCK_BED:
{
// Need to access the bed entity to get the color for the item damage
ConvertToPickups(a_WorldInterface, Pickups, Meta, a_BlockX, a_BlockY, a_BlockZ);
break;
}
case E_BLOCK_ENDER_CHEST:
{
// Reset meta to 0
Pickups.Add(m_BlockType, 1, 0);
break;
}
case E_BLOCK_LEAVES:
case E_BLOCK_NEW_LEAVES:
{
Pickups.Add(m_BlockType, 1, Meta & 0x03);
break;
}
default: Pickups.Add(m_BlockType, 1, Meta); break;
}
}
else if (m_BlockType == E_BLOCK_BED)
{
// Need to access the bed entity to get the color for the item damage
ConvertToPickups(a_WorldInterface, Pickups, Meta, a_BlockX, a_BlockY, a_BlockZ);
}
else
{
ConvertToPickups(Pickups, Meta);
}
}
// Allow plugins to modify the pickups:
a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Pickups);
if (!Pickups.empty())
{
auto & r1 = GetRandomProvider();
// Mid-block position first
double MicroX, MicroY, MicroZ;
MicroX = a_BlockX + 0.5;
MicroY = a_BlockY + 0.5;
MicroZ = a_BlockZ + 0.5;
// Add random offset second
MicroX += r1.RandReal<double>(-0.5, 0.5);
MicroZ += r1.RandReal<double>(-0.5, 0.5);
a_WorldInterface.SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ);
}
// Add self:
cItems res;
res.push_back(cItem(m_BlockType, 1, a_BlockMeta));
return res;
}
@ -655,25 +543,28 @@ cBoundingBox cBlockHandler::GetPlacementCollisionBox(BLOCKTYPE a_XM, BLOCKTYPE a
void cBlockHandler::Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk)
void cBlockHandler::Check(
cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk
)
{
if (!CanBeAt(a_ChunkInterface, a_RelX, a_RelY, a_RelZ, a_Chunk))
if (!CanBeAt(a_ChunkInterface, a_RelPos.x, a_RelPos.y, a_RelPos.z, a_Chunk))
{
if (DoesDropOnUnsuitable())
{
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ);
a_ChunkInterface.DropBlockAsPickups(a_Chunk.RelativeToAbsolute(a_RelPos));
}
else
{
a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0);
}
a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0);
}
else
{
// Wake up the simulators for this block:
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, &a_Chunk);
auto absPos = a_Chunk.RelativeToAbsolute(a_RelPos);
a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(absPos, &a_Chunk);
}
}
@ -691,6 +582,15 @@ ColourID cBlockHandler::GetMapBaseColourID(NIBBLETYPE a_Meta)
bool cBlockHandler::ToolHasSilkTouch(const cItem * a_Tool)
{
return ((a_Tool != nullptr) && (a_Tool->m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0));
}
cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE aBlockType)
{
return ::CreateBlockHandler(aBlockType);

View File

@ -50,30 +50,62 @@ public:
);
/** Called by cWorld::SetBlock() after the block has been set */
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
/** Called by cPlayer::PlaceBlocks() for each block after it has been set to the world. Called after OnPlaced(). */
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange
);
/** Called before the player has destroyed a block */
virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ);
/** Called just before the player breaks the block.
The block is still valid in the world.
By default does nothing special; descendants may provide further behavior. */
virtual void OnPlayerBreakingBlock(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
cPlayer & a_Player,
Vector3i a_BlockPos
) {}
/** Called before a block gets destroyed / replaced with air */
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ);
/** Called just after the player breaks the block.
The block is already dug up in the world, the original block type and meta is passed in a_OldBlockType and a_OldBlockMeta.
By default does nothing special, descendants may provide further behavior. */
virtual void OnPlayerBrokeBlock(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
cPlayer & a_Player,
Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) {}
/** Called when a direct neighbor of this block has been changed (The position is the block's own position, not the changing neighbor's position)
/** Called before a block gets broken (replaced with air), either by player or by natural means.
If by player, it is called after the OnPlayerBreakingBlock() callback.
By default does nothing. */
virtual void OnBreaking(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos
) {}
/** Called after a block gets broken (replaced with air), either by player or by natural means.
If by player, it is called before the OnPlayerBrokeBlock() callback.
The block is already dug up in the world, the original block type and meta is passed in a_OldBlockType and a_OldBlockMeta.
By default notifies all direct neighbors via their OnNeighborChanged() callbacks. */
virtual void OnBroken(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
);
/** Called when a direct neighbor of this block has been changed.
The position is the block's own position, NOT the changed neighbor's position.
a_WhichNeighbor indicates which neighbor has changed. For example, BLOCK_FACE_YP meant the neighbor above has changed.
BLOCK_FACE_NONE means that it is a neighbor not directly adjacent (diagonal, etc.) */
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) {}
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) {}
/** Notifies the specified neighbor that the current block has changed.
a_NeighborXYZ coords are the coords of the neighbor
a_WhichNeighbor specifies which neighbor (relative to a_NeighborXYZ) has changed.
a_NeighborPos are the coords of the neighbor to be notified
a_WhichNeighbor specifies which neighbor (relative to a_NeighborPos) has changed.
For example BLOCK_FACE_YP means that the block at {a_NeighborX, a_NeighborY + 1, a_NeighborZ} has changed.
BLOCK_FACE_NONE means that it is a neighbor not directly adjacent (diagonal, etc.) */
static void NeighborChanged(cChunkInterface & a_ChunkInterface, int a_NeighborX, int a_NeighborY, int a_NeighborZ, eBlockFace a_WhichNeighbor);
static void NeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_NeighborPos, eBlockFace a_WhichNeighbor);
/** Called when the player starts digging the block. */
virtual void OnDigging(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {}
@ -86,19 +118,18 @@ public:
It forces the server to send the real state of a block to the client to prevent client assuming the operation is successfull */
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) {}
/** Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents */
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta);
/** Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents.
Overloaded method with coords and world interface for blocks that needs to access the block entity, e.g. a bed. */
virtual void ConvertToPickups(cWorldInterface & a_WorldInterface, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ) {}
/** Handles the dropping, but not destruction, of a block based on what ConvertTo(Verbatim)Pickups() returns, including the spawning of pickups and alertion of plugins
@param a_Digger The entity causing the drop; it may be nullptr
@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);
/** Returns the pickups that would result if the block was mined by a_Digger using a_Tool.
Doesn't do any actual block change / mining, only calculates the pickups.
a_BlockEntity is the block entity present at the block, if any, nullptr if none.
a_Digger is the entity that caused the conversion, usually the player digging.
a_Tool is the tool used for the digging.
The default implementation drops a single item created from m_BlockType and the current meta. */
virtual cItems ConvertToPickups(
NIBBLETYPE a_BlockMeta,
cBlockEntity * a_BlockEntity,
const cEntity * a_Digger = nullptr,
const cItem * a_Tool = nullptr
);
/** 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);
@ -138,9 +169,13 @@ public:
virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta);
/** Called when one of the neighbors gets set; equivalent to MC block update.
By default drops if position no more suitable (CanBeAt(), DoesDropOnUnsuitable(), Drop()),
and wakes up all simulators on the block. */
virtual void Check(cChunkInterface & ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk);
By default drops (DropBlockAsPickup() / SetBlock()) if the position is no longer suitable (CanBeAt(), DoesDropOnUnsuitable()),
otherwise wakes up all simulators on the block. */
virtual void Check(
cChunkInterface & ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk
);
/** Returns the base colour ID of the block, as will be represented on a map, as per documentation: https://minecraft.gamepedia.com/Map_item_format */
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta);
@ -165,6 +200,11 @@ public:
Returns block meta following rotation */
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) { return a_Meta; }
/** Returns true if the specified tool is valid and has a non-zero silk-touch enchantment.
Helper used in many ConvertToPickups() implementations. */
static bool ToolHasSilkTouch(const cItem * a_Tool);
protected:
BLOCKTYPE m_BlockType;

View File

@ -3,19 +3,26 @@
// Declares the cBlockHopperHandler class representing the handler for the Hopper block
#include "MetaRotator.h"
#include "Mixins.h"
class cBlockHopperHandler :
public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
public cMetaRotator<cContainerEntityHandler<cBlockEntityHandler>, 0x07, 0x02, 0x05, 0x03, 0x04>
{
using super = cMetaRotator<cContainerEntityHandler<cBlockEntityHandler>, 0x07, 0x02, 0x05, 0x03, 0x04>;
public:
cBlockHopperHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
cBlockHopperHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -39,6 +46,10 @@ public:
return true;
}
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
{
// Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000
@ -53,11 +64,9 @@ public:
return a_Meta;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{

View File

@ -10,37 +10,58 @@
class cBlockIceHandler :
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockIceHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockIceHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// No pickups
// Only drop self when using silk-touch:
if (ToolHasSilkTouch(a_Tool))
{
return cItem(m_BlockType);
}
else
{
return {};
}
}
virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
virtual void OnBroken(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) override
{
if (a_Player.IsGameModeCreative() || (a_BlockY <= 0))
// If there's a solid block or a liquid underneath, convert to water, rather than air
if (a_BlockPos.y <= 0)
{
return;
}
cEnchantments Enchantments = a_Player.GetInventory().GetEquippedItem().m_Enchantments;
if (Enchantments.GetLevel(cEnchantments::enchSilkTouch) == 0)
auto blockTypeBelow = a_ChunkInterface.GetBlock(a_BlockPos.addedY(-1));
if (cBlockInfo::FullyOccupiesVoxel(blockTypeBelow) || IsBlockLiquid(blockTypeBelow))
{
BLOCKTYPE BlockBelow = a_ChunkInterface.GetBlock({a_BlockX, a_BlockY - 1, a_BlockZ});
if (!cBlockInfo::FullyOccupiesVoxel(BlockBelow) && !IsBlockLiquid(BlockBelow))
{
return;
}
a_ChunkInterface.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WATER, 0);
a_ChunkInterface.SetBlock(a_BlockPos, E_BLOCK_WATER, 0);
}
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
#include "ClearMetaOnDrop.h"
#include "Mixins.h"
@ -11,13 +11,19 @@
class cBlockLadderHandler :
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04> >
{
typedef cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04> > super;
using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04>>;
public:
cBlockLadderHandler(BLOCKTYPE a_BlockType)
: super(a_BlockType)
cBlockLadderHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -40,10 +46,9 @@ public:
return true;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.Add(m_BlockType, 1, 0); // Reset meta
}
static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction)
{
@ -63,6 +68,10 @@ public:
UNREACHABLE("Unsupported block face");
}
static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData)
{
switch (a_MetaData)
@ -75,6 +84,10 @@ public:
}
}
/** Finds a suitable Direction for the Ladder. Returns BLOCK_FACE_BOTTOM on failure */
static eBlockFace FindSuitableBlockFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{
@ -89,6 +102,10 @@ public:
return BLOCK_FACE_BOTTOM;
}
static bool LadderCanBePlacedAt(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
{
if ((a_BlockFace == BLOCK_FACE_BOTTOM) || (a_BlockFace == BLOCK_FACE_TOP))
@ -101,6 +118,10 @@ public:
return cBlockInfo::IsSolid(a_ChunkInterface.GetBlock({a_BlockX, a_BlockY, a_BlockZ}));
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
// TODO: Use AdjustCoordsByMeta(), then cChunk::UnboundedRelGetBlock() and finally some comparison
@ -110,6 +131,10 @@ public:
return LadderCanBePlacedAt(a_ChunkInterface, BlockX, a_RelY, BlockZ, BlockFace);
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -36,13 +36,25 @@ public:
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
auto & rand = GetRandomProvider();
// If breaking with shears, drop self:
if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS))
{
return cItem(m_BlockType, a_BlockMeta & 0x03);
}
// There is a chance to drop a sapling that varies depending on the type of leaf broken.
// Note: It is possible (though very rare) for a single leaves block to drop both a sapling and an apple
// TODO: Take into account fortune for sapling drops.
double chance = 0.0;
auto & rand = GetRandomProvider();
cItems res;
if ((m_BlockType == E_BLOCK_LEAVES) && ((a_BlockMeta & 0x03) == E_META_LEAVES_JUNGLE))
{
// Jungle leaves have a 2.5% chance of dropping a sapling.
@ -55,12 +67,10 @@ public:
}
if (rand.RandBool(chance))
{
a_Pickups.push_back(
cItem(
E_BLOCK_SAPLING,
1,
(m_BlockType == E_BLOCK_LEAVES) ? (a_BlockMeta & 0x03) : static_cast<short>(4 + (a_BlockMeta & 0x01))
)
res.Add(
E_BLOCK_SAPLING,
1,
(m_BlockType == E_BLOCK_LEAVES) ? (a_BlockMeta & 0x03) : static_cast<short>(4 + (a_BlockMeta & 0x01))
);
}
@ -69,22 +79,31 @@ public:
{
if (rand.RandBool(0.005))
{
a_Pickups.push_back(cItem(E_ITEM_RED_APPLE, 1, 0));
res.Add(E_ITEM_RED_APPLE, 1, 0);
}
}
return res;
}
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
// Set 0x8 bit so this block gets checked for decay:
if ((Meta & 0x08) == 0)
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override
{
auto meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
// Set bit 0x08, so this block gets checked for decay:
if ((meta & 0x08) == 0)
{
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta | 0x8, true, false);
a_ChunkInterface.SetBlockMeta(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, meta | 0x8, true, false);
}
}
virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
@ -119,15 +138,18 @@ public:
if (HasNearLog(Area, BlockX, a_RelY, BlockZ))
{
// Wood found, the leaves stay; unset the check bit
a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta ^ 0x8, true, false);
a_Chunk.SetMeta(a_RelX, a_RelY, a_RelZ, Meta ^ 0x08, true, false);
return;
}
// Decay the leaves:
DropBlock(a_ChunkInterface, a_WorldInterface, a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ);
a_ChunkInterface.DigBlock(a_WorldInterface, BlockX, a_RelY, BlockZ);
a_ChunkInterface.DropBlockAsPickups({BlockX, a_RelY, BlockZ});
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -2,21 +2,26 @@
#include "BlockHandler.h"
#include "../Chunk.h"
#include "MetaRotator.h"
#include "Mixins.h"
#include "BlockSlab.h"
class cBlockLeverHandler :
public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>
{
typedef cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false> super;
using super = cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>;
public:
cBlockLeverHandler(BLOCKTYPE a_BlockType) :
super(a_BlockType)
{
}
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
Vector3i Coords(a_BlockX, a_BlockY, a_BlockZ);
@ -29,17 +34,29 @@ public:
return true;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Reset meta to 0
a_Pickups.push_back(cItem(E_BLOCK_LEVER, 1, 0));
// Reset meta to zero:
return cItem(E_BLOCK_LEVER, 1, 0);
}
virtual bool IsUseable(void) override
{
return true;
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -52,6 +69,10 @@ public:
return true;
}
inline static NIBBLETYPE LeverDirectionToMetaData(eBlockFace a_Dir)
{
// Determine lever direction:
@ -68,6 +89,10 @@ public:
UNREACHABLE("Unsupported block face");
}
inline static eBlockFace BlockMetaDataToBlockFace(NIBBLETYPE a_Meta)
{
switch (a_Meta & 0x7)
@ -88,6 +113,10 @@ public:
}
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
@ -121,6 +150,10 @@ public:
return false;
}
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
{
switch (a_Meta)
@ -135,6 +168,10 @@ public:
}
}
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
{
switch (a_Meta)
@ -149,12 +186,20 @@ public:
}
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);
return 0;
}
/** Extracts the ON bit from metadata and returns if true if it is set */
static bool IsLeverOn(NIBBLETYPE a_BlockMeta)
{

View File

@ -10,17 +10,28 @@
class cBlockMelonHandler :
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockMelonHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockMelonHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.emplace_back(E_ITEM_MELON_SLICE, GetRandomProvider().RandInt<char>(3, 7), 0);
return cItem(E_ITEM_MELON_SLICE, GetRandomProvider().RandInt<char>(3, 7), 0);
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -11,53 +11,32 @@
class cBlockMobHeadHandler :
public cBlockEntityHandler
{
using super = cBlockEntityHandler;
public:
cBlockMobHeadHandler(BLOCKTYPE a_BlockType):
cBlockEntityHandler(a_BlockType)
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// The drop spawn is in the OnDestroyedByPlayer method
}
virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
if (a_Player.IsGameModeCreative())
if ((a_BlockEntity == nullptr) || (a_BlockEntity->GetBlockType() != E_BLOCK_HEAD))
{
// No drops in creative mode
return;
return {};
}
a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, [](cBlockEntity & a_BlockEntity)
{
if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD)
{
return false;
}
auto & MobHeadEntity = static_cast<cMobHeadEntity&>(a_BlockEntity);
cItems Pickups;
Pickups.Add(E_ITEM_HEAD, 1, static_cast<short>(MobHeadEntity.GetType()));
auto & r1 = GetRandomProvider();
// Mid-block position first
double MicroX, MicroY, MicroZ;
MicroX = MobHeadEntity.GetPosX() + 0.5;
MicroY = MobHeadEntity.GetPosY() + 0.5;
MicroZ = MobHeadEntity.GetPosZ() + 0.5;
// Add random offset second
MicroX += r1.RandReal<double>(-0.5, 0.5);
MicroZ += r1.RandReal<double>(-0.5, 0.5);
MobHeadEntity.GetWorld()->SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ);
return false;
}
);
auto mobHeadEntity = static_cast<cMobHeadEntity *>(a_BlockEntity);
return cItem(E_ITEM_HEAD, 1, static_cast<short>(mobHeadEntity->GetType()));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -30,22 +30,34 @@ public:
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// No pickups
return {};
}
virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
virtual void OnPlayerBrokeBlock(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
cPlayer & a_Player,
Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) override
{
cItemHandler * Handler = a_Player.GetEquippedItem().GetHandler();
if (a_Player.IsGameModeCreative() || !Handler->CanHarvestBlock(E_BLOCK_MOB_SPAWNER))
auto handler = a_Player.GetEquippedItem().GetHandler();
if (!a_Player.IsGameModeSurvival() || !handler->CanHarvestBlock(E_BLOCK_MOB_SPAWNER))
{
return;
}
auto & Random = GetRandomProvider();
int Reward = 15 + Random.RandInt(14) + Random.RandInt(14);
a_WorldInterface.SpawnSplitExperienceOrbs(static_cast<double>(a_BlockX), static_cast<double>(a_BlockY + 1), static_cast<double>(a_BlockZ), Reward);
auto & random = GetRandomProvider();
int reward = 15 + random.RandInt(14) + random.RandInt(14);
a_WorldInterface.SpawnSplitExperienceOrbs(Vector3d(0.5, 0.5, 0.5) + a_BlockPos, reward);
}
} ;

View File

@ -7,23 +7,20 @@
class cBlockMushroomHandler :
public cBlockHandler
class cBlockMushroomHandler:
public cClearMetaOnDrop<cBlockHandler>
{
using super = cClearMetaOnDrop<cBlockHandler>;
public:
cBlockMushroomHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockMushroomHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
// TODO: Add Mushroom Spread
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
if (a_RelY <= 0)

View File

@ -7,22 +7,30 @@
class cBlockMyceliumHandler :
class cBlockMyceliumHandler:
public cBlockHandler
{
public:
cBlockMyceliumHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockMyceliumHandler(BLOCKTYPE a_BlockType):
cBlockHandler(a_BlockType)
{
}
// TODO: Add Mycel Spread
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(E_BLOCK_DIRT, 1, 0));
return cItem(E_BLOCK_DIRT, 1, 0);
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -9,30 +9,39 @@
class cBlockNetherWartHandler :
public cBlockPlant
public cBlockPlant<false>
{
typedef cBlockPlant Super;
using super = cBlockPlant<false>;
public:
cBlockNetherWartHandler(BLOCKTYPE a_BlockType)
: Super(a_BlockType, false)
cBlockNetherWartHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override
{
auto & rand = GetRandomProvider();
if (a_Meta == 0x3)
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
if (a_BlockMeta == 0x03)
{
// Fully grown, drop the entire produce:
a_Pickups.emplace_back(E_ITEM_NETHER_WART, 1 + (rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2, 0);
auto & rand = GetRandomProvider();
return cItem(E_ITEM_NETHER_WART, 1 + (rand.RandInt<char>(2) + rand.RandInt<char>(2)) / 2, 0);
}
else
{
a_Pickups.push_back(cItem(E_ITEM_NETHER_WART));
return cItem(E_ITEM_NETHER_WART);
}
}
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
@ -46,12 +55,20 @@ public:
}
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
// Needs to be placed on top of a Soulsand block:
return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SOULSAND));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -17,63 +17,50 @@ public:
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
auto & Random = GetRandomProvider();
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// If using silk-touch, drop self rather than the resource:
if (ToolHasSilkTouch(a_Tool))
{
return cItem(m_BlockType);
}
// TODO: Handle the Fortune enchantment here
auto & random = GetRandomProvider();
switch (m_BlockType)
{
case E_BLOCK_LAPIS_ORE:
{
a_Pickups.emplace_back(E_ITEM_DYE, Random.RandInt<char>(4, 8), 4);
break;
}
case E_BLOCK_REDSTONE_ORE:
case E_BLOCK_REDSTONE_ORE_GLOWING:
{
a_Pickups.emplace_back(E_ITEM_REDSTONE_DUST, Random.RandInt<char>(4, 5), 0);
break;
}
case E_BLOCK_DIAMOND_ORE:
{
a_Pickups.push_back(cItem(E_ITEM_DIAMOND));
break;
}
case E_BLOCK_EMERALD_ORE:
{
a_Pickups.push_back(cItem(E_ITEM_EMERALD));
break;
}
case E_BLOCK_COAL_ORE:
{
a_Pickups.push_back(cItem(E_ITEM_COAL));
break;
}
case E_BLOCK_NETHER_QUARTZ_ORE:
{
a_Pickups.push_back(cItem(E_ITEM_NETHER_QUARTZ));
break;
}
case E_BLOCK_CLAY:
{
a_Pickups.push_back(cItem(E_ITEM_CLAY, 4));
break;
}
case E_BLOCK_LAPIS_ORE: return cItem(E_ITEM_DYE, random.RandInt<char>(4, 8), 4);
case E_BLOCK_REDSTONE_ORE: return cItem(E_ITEM_REDSTONE_DUST, random.RandInt<char>(4, 5), 0);
case E_BLOCK_REDSTONE_ORE_GLOWING: return cItem(E_ITEM_REDSTONE_DUST, random.RandInt<char>(4, 5), 0);
case E_BLOCK_DIAMOND_ORE: return cItem(E_ITEM_DIAMOND);
case E_BLOCK_EMERALD_ORE: return cItem(E_ITEM_EMERALD);
case E_BLOCK_COAL_ORE: return cItem(E_ITEM_COAL);
case E_BLOCK_NETHER_QUARTZ_ORE: return cItem(E_ITEM_NETHER_QUARTZ);
case E_BLOCK_CLAY: return cItem(E_ITEM_CLAY, 4);
default:
{
a_Pickups.push_back(cItem(m_BlockType));
break;
return cItem(m_BlockType);
}
}
}
virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override
{
super::OnDestroyedByPlayer(a_ChunkInterface, a_WorldInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ);
if (a_Player.IsGameModeCreative())
virtual void OnPlayerBrokeBlock(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
cPlayer & a_Player, Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) override
{
if (!a_Player.IsGameModeSurvival())
{
// Don't drop XP when the player is in creative mode.
// Don't drop XP unless the player is in survival mode.
return;
}
@ -83,45 +70,45 @@ public:
return;
}
auto & Random = GetRandomProvider();
int Reward = 0;
auto & random = GetRandomProvider();
int reward = 0;
switch (m_BlockType)
switch (a_OldBlockType)
{
case E_BLOCK_NETHER_QUARTZ_ORE:
case E_BLOCK_LAPIS_ORE:
{
// Lapis and nether quartz get 2 - 5 experience
Reward = Random.RandInt(2, 5);
reward = random.RandInt(2, 5);
break;
}
case E_BLOCK_REDSTONE_ORE:
case E_BLOCK_REDSTONE_ORE_GLOWING:
{
// Redstone gets 1 - 5 experience
Reward = Random.RandInt(1, 5);
reward = random.RandInt(1, 5);
break;
}
case E_BLOCK_DIAMOND_ORE:
case E_BLOCK_EMERALD_ORE:
{
// Diamond and emerald get 3 - 7 experience
Reward = Random.RandInt(3, 7);
reward = random.RandInt(3, 7);
break;
}
case E_BLOCK_COAL_ORE:
{
// Coal gets 0 - 2 experience
Reward = Random.RandInt(2);
reward = random.RandInt(2);
break;
}
default: break;
}
if (Reward != 0)
if (reward > 0)
{
a_WorldInterface.SpawnSplitExperienceOrbs(a_BlockX, a_BlockY, a_BlockZ, Reward);
a_WorldInterface.SpawnSplitExperienceOrbs(Vector3d(0.5, 0.5, 0.5) + a_BlockPos, reward);
}
}
} ;

View File

@ -16,8 +16,8 @@
cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
@ -25,20 +25,19 @@ cBlockPistonHandler::cBlockPistonHandler(BLOCKTYPE a_BlockType)
void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
void cBlockPistonHandler::OnBroken(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
)
{
Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ);
NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(blockPos);
// If the piston is extended, destroy the extension as well
if (IsExtended(OldMeta))
if (IsExtended(a_OldBlockMeta))
{
// Get the position of the extension
blockPos += MetadataToOffset(OldMeta);
if (a_ChunkInterface.GetBlock(blockPos) == E_BLOCK_PISTON_EXTENSION)
auto extPos = a_BlockPos + MetadataToOffset(a_OldBlockMeta);
if (a_ChunkInterface.GetBlock(extPos) == E_BLOCK_PISTON_EXTENSION)
{
a_ChunkInterface.SetBlock(blockPos.x, blockPos.y, blockPos.z, E_BLOCK_AIR, 0);
a_ChunkInterface.DropBlockAsPickups(extPos);
}
}
}
@ -47,16 +46,6 @@ void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorld
void cBlockPistonHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
{
// Returning Piston Item without Direction-Metavalue
a_Pickups.push_back(cItem(m_BlockType, 1));
}
bool cBlockPistonHandler::GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -106,7 +95,7 @@ void cBlockPistonHandler::PushBlocks(
std::vector<Vector3i> sortedBlocks(a_BlocksToPush.begin(), a_BlocksToPush.end());
std::sort(sortedBlocks.begin(), sortedBlocks.end(), [a_PushDir](const Vector3i & a, const Vector3i & b)
{
return a.Dot(a_PushDir) > b.Dot(a_PushDir);
return (a.Dot(a_PushDir) > b.Dot(a_PushDir));
});
// Move every block
@ -118,17 +107,8 @@ void cBlockPistonHandler::PushBlocks(
if (cBlockInfo::IsPistonBreakable(moveBlock))
{
// Block is breakable, drop it
cBlockHandler * Handler = BlockHandler(moveBlock);
if (Handler->DoesDropOnUnsuitable())
{
cChunkInterface ChunkInterface(a_World.GetChunkMap());
cBlockInServerPluginInterface PluginInterface(a_World);
Handler->DropBlock(ChunkInterface, a_World, PluginInterface, nullptr,
moveBlockPos.x, moveBlockPos.y, moveBlockPos.z
);
}
a_World.SetBlock(moveBlockPos.x, moveBlockPos.y, moveBlockPos.z, E_BLOCK_AIR, 0);
// Block is breakable, drop it:
a_World.DropBlockAsPickups(moveBlockPos, nullptr, nullptr);
}
else
{
@ -357,26 +337,17 @@ cBlockPistonHeadHandler::cBlockPistonHeadHandler(void) :
void cBlockPistonHeadHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
void cBlockPistonHeadHandler::OnBroken(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
)
{
Vector3i blockPos(a_BlockX, a_BlockY, a_BlockZ);
// Get the base of the piston
NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(blockPos);
blockPos -= cBlockPistonHandler::MetadataToOffset(OldMeta);
BLOCKTYPE Block = a_ChunkInterface.GetBlock(blockPos);
if ((Block == E_BLOCK_STICKY_PISTON) || (Block == E_BLOCK_PISTON))
// Drop the base of the piston:
auto basePos = a_BlockPos - cBlockPistonHandler::MetadataToOffset(a_OldBlockMeta);
if (cChunkDef::IsValidHeight(basePos.y))
{
a_ChunkInterface.DigBlock(a_WorldInterface, blockPos.x, blockPos.y, blockPos.z);
if (a_Player.IsGameModeCreative())
{
return; // No pickups if creative
}
cItems Pickups;
Pickups.push_back(cItem(Block, 1));
a_WorldInterface.SpawnItemPickups(Pickups, blockPos.x + 0.5, blockPos.y + 0.5, blockPos.z + 0.5);
a_ChunkInterface.DropBlockAsPickups(basePos);
}
}

View File

@ -2,22 +2,34 @@
#pragma once
#include "BlockHandler.h"
#include <unordered_set>
#include "Mixins.h"
#include "../Item.h"
// fwd:
class cWorld;
class cBlockPistonHandler :
public cBlockHandler
class cBlockPistonHandler:
public cClearMetaOnDrop<cBlockHandler>
{
using super = cClearMetaOnDrop<cBlockHandler>;
public:
cBlockPistonHandler(BLOCKTYPE a_BlockType);
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override;
virtual void OnBroken(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) override;
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
@ -174,23 +186,24 @@ private:
class cBlockPistonHeadHandler :
class cBlockPistonHeadHandler:
public cBlockHandler
{
typedef cBlockHandler super;
using super = cBlockHandler;
public:
cBlockPistonHeadHandler(void);
virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override;
virtual void OnBroken(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) override;
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// No pickups
// Also with 1.7, the item forms of these technical blocks have been removed, so giving someone this will crash their client...
return {};
}
} ;

View File

@ -1,25 +1,30 @@
// BlockPlant.h
// Base class for any growing block
#pragma once
#include "BlockHandler.h"
class cBlockPlant : public cBlockHandler
/** Base class for plants that use light values to decide whether to grow or not. */
template <bool NeedsLightToGrow>
class cBlockPlant:
public cBlockHandler
{
typedef cBlockHandler Super;
bool m_NeedLightToGrow;
using super = cBlockHandler;
public:
cBlockPlant(BLOCKTYPE a_BlockType, bool a_LightToGrow)
: Super(a_BlockType), m_NeedLightToGrow(a_LightToGrow){}
cBlockPlant(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
protected:
/** The action the plant can take on an update. */
enum PlantAction
{
paDeath,
@ -27,6 +32,10 @@ protected:
paStay
};
/** Checks whether there is enough light for the plant to grow.
If the plant doesn't require light to grow, then it returns paGrowth.
If the plant requires light to grow and there is enough light, it returns paGrowth.
@ -37,34 +46,37 @@ protected:
{
// If the plant requires light to grow, check to see if there is enough light
// Otherwise, return true
if (m_NeedLightToGrow)
if (!NeedsLightToGrow)
{
NIBBLETYPE Blocklight = a_Chunk.GetBlockLight(a_RelX, a_RelY, a_RelZ);
NIBBLETYPE SkyLight = a_Chunk.GetSkyLight (a_RelX, a_RelY, a_RelZ);
NIBBLETYPE Light = a_Chunk.GetTimeAlteredLight(SkyLight);
return paGrowth;
}
NIBBLETYPE Blocklight = a_Chunk.GetBlockLight(a_RelX, a_RelY, a_RelZ);
NIBBLETYPE SkyLight = a_Chunk.GetSkyLight (a_RelX, a_RelY, a_RelZ);
NIBBLETYPE Light = a_Chunk.GetTimeAlteredLight(SkyLight);
// If the amount of light provided by blocks is greater than the sky light, use it instead
if (Blocklight > Light)
{
Light = Blocklight;
}
// Based on light levels, decide between growth, stay and death:
if (Light > 8)
{
return paGrowth;
}
else if ((Blocklight < 9) && (SkyLight < 9))
{
return paDeath;
}
return paStay;
// If the amount of light provided by blocks is greater than the sky light, use it instead
if (Blocklight > Light)
{
Light = Blocklight;
}
return paGrowth;
// Based on light levels, decide between growth, stay and death:
if (Light > 8)
{
return paGrowth;
}
else if ((Blocklight < 9) && (SkyLight < 9))
{
return paDeath;
}
return paStay;
}
/** Checks whether a plant can grow grow, based on what is returned from cBlockPlant::HasEnoughLight
and a random check based on what is returned from cBlockPlant::GetGrowthChance.
Can return three values.
@ -84,6 +96,10 @@ protected:
return Action;
}
/** Generates a int value between 4 and 25 based on surrounding blocks that affect how quickly the plant grows.
The higher the value, the less likely the plant is to grow */
virtual int GetGrowthChance(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)

View File

@ -30,7 +30,6 @@ public:
virtual ~cBlockPluginInterface() {}
virtual bool CallHookBlockSpread(int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0;
virtual bool CallHookBlockToPickups(cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0;
virtual bool CallHookPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
virtual bool CallHookPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
};

View File

@ -32,11 +32,20 @@ public:
return true;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// No pickups
return {};
}
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
if (GetRandomProvider().RandBool(0.9995))

View File

@ -7,18 +7,15 @@
class cBlockPressurePlateHandler :
public cBlockHandler
public cClearMetaOnDrop<cBlockHandler>
{
public:
cBlockPressurePlateHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
{
}
using super = cClearMetaOnDrop<cBlockHandler>;
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
public:
cBlockPressurePlateHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
// Reset meta to zero
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override

View File

@ -1,7 +1,7 @@
#pragma once
#include "BlockHandler.h"
#include "MetaRotator.h"
#include "Mixins.h"

View File

@ -17,13 +17,14 @@ enum ENUM_PURE
class cBlockRailHandler :
public cBlockHandler
public cClearMetaOnDrop<cBlockHandler>
{
typedef cBlockHandler super;
using super = cClearMetaOnDrop<cBlockHandler>;
public:
cBlockRailHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockRailHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
@ -46,51 +47,69 @@ public:
);
}
virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
{
super::OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
// Alert diagonal rails
NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ + 1, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ - 1, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ + 1, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ - 1, BLOCK_FACE_NONE);
virtual void OnPlaced(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override
{
super::OnPlaced(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_BlockType, a_BlockMeta);
// Alert diagonal rails:
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE);
}
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override
{
super::OnDestroyed(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ);
// Alert diagonal rails
NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY + 1, a_BlockZ, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ + 1, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY + 1, a_BlockZ - 1, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX + 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX - 1, a_BlockY - 1, a_BlockZ, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ + 1, BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY - 1, a_BlockZ - 1, BLOCK_FACE_NONE);
virtual void OnBroken(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface,
Vector3i a_BlockPos,
BLOCKTYPE a_OldBlockType, NIBBLETYPE a_OldBlockMeta
) override
{
super::OnBroken(a_ChunkInterface, a_WorldInterface, a_BlockPos, a_OldBlockType, a_OldBlockMeta);
// Alert diagonal rails:
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, 1, 0), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, 1, 0), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, 1), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, +1, -1), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 1, -1, 0), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i(-1, -1, 0), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, 1), BLOCK_FACE_NONE);
NeighborChanged(a_ChunkInterface, a_BlockPos + Vector3i( 0, -1, -1), BLOCK_FACE_NONE);
}
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, Vector3i a_BlockPos, eBlockFace a_WhichNeighbor) override
{
Vector3i Pos(a_BlockX, a_BlockY, a_BlockZ);
auto Meta = a_ChunkInterface.GetBlockMeta(Pos);
auto NewMeta = FindMeta(a_ChunkInterface, Pos);
if (IsUnstable(a_ChunkInterface, Pos) && (Meta != NewMeta))
auto meta = a_ChunkInterface.GetBlockMeta(a_BlockPos);
auto newMeta = FindMeta(a_ChunkInterface, a_BlockPos);
if (IsUnstable(a_ChunkInterface, a_BlockPos) && (meta != newMeta))
{
a_ChunkInterface.FastSetBlock(Pos, m_BlockType, (m_BlockType == E_BLOCK_RAIL) ? NewMeta : NewMeta | (Meta & 0x08));
a_ChunkInterface.FastSetBlock(a_BlockPos, m_BlockType, (m_BlockType == E_BLOCK_RAIL) ? newMeta : newMeta | (meta & 0x08));
}
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
super::ConvertToPickups(a_Pickups, 0);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{

View File

@ -9,11 +9,14 @@
class cBlockRedstoneHandler :
public cBlockHandler
public cClearMetaOnDrop<cBlockHandler>
{
using super = cClearMetaOnDrop<cBlockHandler>;
public:
cBlockRedstoneHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockRedstoneHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
@ -43,12 +46,6 @@ public:
return false;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to zero
a_Pickups.push_back(cItem(E_ITEM_REDSTONE_DUST, 1, 0));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -7,20 +7,29 @@
class cBlockRedstoneLampHandler :
class cBlockRedstoneLampHandler:
public cBlockHandler
{
public:
cBlockRedstoneLampHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockRedstoneLampHandler(BLOCKTYPE a_BlockType):
cBlockHandler(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(E_BLOCK_REDSTONE_LAMP_OFF, 1, 0));
// Always drop the Off variant:
return(cItem(E_BLOCK_REDSTONE_LAMP_OFF, 1, 0));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -2,19 +2,24 @@
#pragma once
#include "BlockHandler.h"
#include "MetaRotator.h"
#include "Mixins.h"
#include "ChunkInterface.h"
#include "BlockSlab.h"
#include "../Chunk.h"
class cBlockRedstoneRepeaterHandler :
public cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>
class cBlockRedstoneRepeaterHandler:
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>>
{
using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>>;
public:
cBlockRedstoneRepeaterHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType)
cBlockRedstoneRepeaterHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
@ -42,12 +47,6 @@ public:
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to zero
a_Pickups.push_back(cItem(E_ITEM_REDSTONE_REPEATER, 1, 0));
}
virtual bool IsUseable(void) override
{
return true;

View File

@ -10,18 +10,29 @@
class cBlockRedstoneTorchHandler :
public cBlockTorchHandler
{
using super = cBlockTorchHandler;
public:
cBlockRedstoneTorchHandler(BLOCKTYPE a_BlockType)
: cBlockTorchHandler(a_BlockType)
cBlockRedstoneTorchHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Always drop the ON torch, meta 0
a_Pickups.push_back(cItem(E_BLOCK_REDSTONE_TORCH_ON, 1, 0));
return cItem(E_BLOCK_REDSTONE_TORCH_ON, 1, 0);
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -11,18 +11,29 @@
class cBlockSaplingHandler :
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockSaplingHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockSaplingHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Only the first 2 bits contain the display information and the 4th bit is for the growth indicator, but, we use 0x07 for forward compatibility
a_Pickups.push_back(cItem(E_BLOCK_SAPLING, 1, a_BlockMeta & 0x07));
// The low 3 bits store the sapling type; bit 0x08 is the growth timer (not used in pickups)
return cItem(m_BlockType, 1, a_BlockMeta & 0x07);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
return (a_RelY > 0) && IsBlockTypeOfDirt(a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ));

View File

@ -10,17 +10,24 @@
class cBlockSeaLanternHandler :
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockSeaLanternHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockSeaLanternHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Reset meta to 0
a_Pickups.emplace_back(E_ITEM_PRISMARINE_CRYSTALS, GetRandomProvider().RandInt<char>(2, 3), 0);
// TODO: Handle the Fortune enchantment
return cItem(E_ITEM_PRISMARINE_CRYSTALS, GetRandomProvider().RandInt<char>(2, 3), 0);
}
} ;

View File

@ -7,15 +7,25 @@
class cBlockSidewaysHandler : public cBlockHandler
/** Handler for blocks that have 3 orientations (hay bale, log), specified by the upper 2 bits in meta.
Handles setting the correct orientation on placement.
Additionally supports the metadata specifying block sub-type in its lower 2 bits. */
class cBlockSidewaysHandler:
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockSidewaysHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockSidewaysHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -30,12 +40,19 @@ public:
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.Add(m_BlockType, 1, a_BlockMeta & 0x3); // Reset meta
// Reset the orientation part of meta, keep the sub-type part of meta
return cItem(m_BlockType, 1, a_BlockMeta & 0x03);
}
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_Meta)
{
switch (a_BlockFace)

View File

@ -8,22 +8,30 @@
class cBlockSignPostHandler :
class cBlockSignPostHandler:
public cBlockHandler
{
typedef cBlockHandler super;
using super = cBlockHandler;
public:
cBlockSignPostHandler(BLOCKTYPE a_BlockType) :
cBlockSignPostHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(E_ITEM_SIGN, 1, 0));
return cItem(E_ITEM_SIGN, 1, 0);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
if (a_RelY <= 0)

View File

@ -18,17 +18,29 @@
class cBlockSlabHandler :
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockSlabHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockSlabHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(m_BlockType, 1, a_BlockMeta & 0x7));
// Reset the "top half" flag:
return cItem(m_BlockType, 1, a_BlockMeta & 0x07);
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -84,6 +96,10 @@ public:
return true;
}
/** Returns true if the specified blocktype is one of the slabs handled by this handler */
static bool IsAnySlabType(BLOCKTYPE a_BlockType)
{
@ -95,6 +111,10 @@ public:
);
}
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
{
if ((a_BlockFace == BLOCK_FACE_NONE) || (a_Player.GetEquippedItem().m_ItemType != static_cast<short>(m_BlockType)))
@ -106,6 +126,10 @@ public:
a_Player.GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
}
/** Converts the single-slab blocktype to its equivalent double-slab blocktype */
static BLOCKTYPE GetDoubleSlabType(BLOCKTYPE a_SingleSlabBlockType)
{
@ -120,12 +144,20 @@ public:
return E_BLOCK_AIR;
}
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
{
// Toggle the 4th bit - up / down:
return (a_Meta ^ 0x08);
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
a_Meta &= 0x7;
@ -184,6 +216,10 @@ public:
}
}
virtual bool IsInsideBlock(Vector3d a_Position, const BLOCKTYPE a_BlockType, const NIBBLETYPE a_BlockMeta) override
{
if (a_BlockMeta & 0x8) // top half
@ -201,31 +237,46 @@ public:
class cBlockDoubleSlabHandler :
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockDoubleSlabHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockDoubleSlabHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
BLOCKTYPE Block = GetSingleSlabType(m_BlockType);
a_Pickups.push_back(cItem(Block, 2, a_BlockMeta & 0x7));
return cItem(Block, 2, a_BlockMeta & 0x7);
}
inline static BLOCKTYPE GetSingleSlabType(BLOCKTYPE a_BlockType)
{
switch (a_BlockType)
{
case E_BLOCK_DOUBLE_STONE_SLAB: return E_BLOCK_STONE_SLAB;
case E_BLOCK_DOUBLE_WOODEN_SLAB: return E_BLOCK_WOODEN_SLAB;
case E_BLOCK_DOUBLE_STONE_SLAB: return E_BLOCK_STONE_SLAB;
case E_BLOCK_DOUBLE_WOODEN_SLAB: return E_BLOCK_WOODEN_SLAB;
case E_BLOCK_DOUBLE_RED_SANDSTONE_SLAB: return E_BLOCK_RED_SANDSTONE_SLAB;
case E_BLOCK_PURPUR_DOUBLE_SLAB: return E_BLOCK_PURPUR_SLAB;
case E_BLOCK_PURPUR_DOUBLE_SLAB: return E_BLOCK_PURPUR_SLAB;
}
ASSERT(!"Unhandled double slab type!");
return a_BlockType;
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
// For doule slabs, the meta values are the same. Only the meaning of the 4th bit changes, but that's ignored in the below handler

View File

@ -6,19 +6,21 @@
class cBlockSlimeHandler :
public cBlockHandler
class cBlockSlimeHandler:
public cClearMetaOnDrop<cBlockHandler>
{
using super = cClearMetaOnDrop<cBlockHandler>;
public:
cBlockSlimeHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockSlimeHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{

View File

@ -70,11 +70,33 @@ public:
return false;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(E_ITEM_SNOWBALL, 1, 0));
// No drop unless dug up with a shovel
if ((a_Tool == nullptr) || !ItemCategory::IsShovel(a_Tool->m_ItemType))
{
return {};
}
if (ToolHasSilkTouch(a_Tool))
{
return cItem(m_BlockType, 1, 0);
}
else
{
// Drop as many snowballs as there were "layers" of snow:
return cItem(E_ITEM_SNOWBALL, 1 + (a_BlockMeta & 0x07), 0);
}
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
if (a_RelY > 0)

View File

@ -10,9 +10,12 @@
class cBlockSpongeHandler :
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockSpongeHandler(BLOCKTYPE a_BlockType):
cBlockHandler(a_BlockType)
super(a_BlockType)
{
}
@ -20,13 +23,17 @@ public:
virtual void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override
virtual void Check(
cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk
) override
{
if (GetSoaked(Vector3i(a_RelX, a_RelY, a_RelZ), a_Chunk))
if (GetSoaked(a_RelPos, a_Chunk))
{
return;
}
cBlockHandler::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk);
super::Check(a_ChunkInterface, a_PluginInterface, a_RelPos, a_Chunk);
}
@ -115,7 +122,7 @@ public:
}
Seeds.pop();
}
a_Chunk.SetBlock(a_Rel.x, a_Rel.y, a_Rel.z, E_BLOCK_SPONGE, E_META_SPONGE_WET);
a_Chunk.SetBlock(a_Rel, E_BLOCK_SPONGE, E_META_SPONGE_WET);
return true;
}

View File

@ -2,17 +2,20 @@
#pragma once
#include "BlockHandler.h"
#include "MetaRotator.h"
#include "Mixins.h"
class cBlockStairsHandler :
public cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>>
{
using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>>;
public:
cBlockStairsHandler(BLOCKTYPE a_BlockType) :
cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>(a_BlockType)
cBlockStairsHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
@ -53,12 +56,6 @@ public:
return true;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to zero
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
}
static NIBBLETYPE RotationToMetaData(double a_Rotation)
{
a_Rotation += 90 + 45; // So its not aligned with axis

View File

@ -8,21 +8,31 @@
class cBlockStemsHandler :
public cBlockPlant
public cBlockPlant<true>
{
typedef cBlockPlant Super;
using super = cBlockPlant<true>;
public:
cBlockStemsHandler(BLOCKTYPE a_BlockType)
: Super(a_BlockType, true)
cBlockStemsHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
short ItemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS;
a_Pickups.push_back(cItem(ItemType, 1, 0));
auto itemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS;
return cItem(itemType, 1, 0);
}
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
auto Action = CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ);

View File

@ -6,25 +6,39 @@
class cBlockStoneHandler :
class cBlockStoneHandler:
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockStoneHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockStoneHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
if (a_BlockMeta == E_META_STONE_STONE)
// Convert stone to cobblestone, unless using silk-touch:
if (
(a_BlockMeta == E_META_STONE_STONE) &&
!ToolHasSilkTouch(a_Tool)
)
{
a_Pickups.push_back(cItem(E_BLOCK_COBBLESTONE, 1, 0));
return;
return cItem(E_BLOCK_COBBLESTONE, 1, 0);
}
a_Pickups.push_back(cItem(E_BLOCK_STONE, 1, a_BlockMeta));
return cItem(m_BlockType, 1, a_BlockMeta);
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -8,20 +8,30 @@
class cBlockSugarcaneHandler :
public cBlockPlant
public cBlockPlant<false>
{
typedef cBlockPlant Super;
using super = cBlockPlant<false>;
public:
cBlockSugarcaneHandler(BLOCKTYPE a_BlockType)
: Super(a_BlockType, false)
cBlockSugarcaneHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(E_ITEM_SUGARCANE, 1, 0));
return cItem(E_ITEM_SUGARCANE, 1, 0);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
if (a_RelY <= 0)
@ -86,6 +96,7 @@ public:
return 7;
}
protected:
virtual PlantAction CanGrow(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
@ -93,7 +104,7 @@ protected:
auto Action = paStay;
if (((a_RelY + 1) < cChunkDef::Height) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR))
{
Action = Super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ);
Action = super::CanGrow(a_Chunk, a_RelX, a_RelY, a_RelZ);
}
return Action;

View File

@ -8,63 +8,50 @@
class cBlockTallGrassHandler :
class cBlockTallGrassHandler:
public cBlockHandler
{
typedef cBlockHandler super;
using super = cBlockHandler;
public:
cBlockTallGrassHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockTallGrassHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override
{
return true;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Drop seeds, sometimes
// If using shears, drop self:
if ((a_Tool != nullptr) && (a_Tool->m_ItemType == E_ITEM_SHEARS))
{
return cItem(m_BlockType, 1, a_BlockMeta);
}
// Drop seeds, sometimes:
if (GetRandomProvider().RandBool(0.125))
{
a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1, 0));
return cItem(E_ITEM_SEEDS);
}
return {};
}
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
{
if (a_CanDrop && (a_Digger != nullptr) && (a_Digger->GetEquippedWeapon().m_ItemType == E_ITEM_SHEARS))
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta({a_BlockX, a_BlockY, a_BlockZ});
cItems Drops;
Drops.Add(m_BlockType, 1, Meta);
// Allow plugins to modify the pickups:
a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Drops);
// Spawn the pickups:
if (!Drops.empty())
{
auto & r1 = GetRandomProvider();
// Mid-block position first
double MicroX, MicroY, MicroZ;
MicroX = a_BlockX + 0.5;
MicroY = a_BlockY + 0.5;
MicroZ = a_BlockZ + 0.5;
// Add random offset second
MicroX += r1.RandReal<double>(-0.5, 0.5);
MicroZ += r1.RandReal<double>(-0.5, 0.5);
a_WorldInterface.SpawnItemPickups(Drops, MicroX, MicroY, MicroZ);
}
return;
}
super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_CanDrop);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
@ -77,6 +64,10 @@ public:
return IsBlockTypeOfDirt(BelowBlock);
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -3,17 +3,20 @@
#include "BlockHandler.h"
#include "../Chunk.h"
#include "ChunkInterface.h"
#include "MetaRotator.h"
#include "Mixins.h"
class cBlockTorchHandler :
public cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>>
{
using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>>;
public:
cBlockTorchHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>(a_BlockType)
cBlockTorchHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
@ -182,12 +185,6 @@ public:
return CanBePlacedOn(BlockInQuestion, BlockInQuestionMeta, Face);
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Always drop meta = 0
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -2,32 +2,36 @@
#pragma once
#include "BlockHandler.h"
#include "MetaRotator.h"
#include "Mixins.h"
#include "../EffectID.h"
class cBlockTrapdoorHandler :
public cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>
public cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>>
{
using super = cClearMetaOnDrop<cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>>;
public:
cBlockTrapdoorHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>(a_BlockType)
cBlockTrapdoorHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to zero
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
}
virtual bool IsUseable(void) override
{
return true;
}
virtual bool OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
if (m_BlockType == E_BLOCK_IRON_TRAPDOOR)

View File

@ -10,17 +10,28 @@
class cBlockTripwireHandler :
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockTripwireHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockTripwireHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(E_ITEM_STRING, 1, 0));
return cItem(E_ITEM_STRING, 1, 0);
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -1,21 +1,28 @@
#pragma once
#include "BlockHandler.h"
#include "MetaRotator.h"
#include "Mixins.h"
class cBlockTripwireHookHandler :
public cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01>
public cMetaRotator<cClearMetaOnDrop<cBlockHandler>, 0x03, 0x02, 0x03, 0x00, 0x01>
{
using super = cMetaRotator<cClearMetaOnDrop<cBlockHandler>, 0x03, 0x02, 0x03, 0x00, 0x01>;
public:
cBlockTripwireHookHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01>(a_BlockType)
cBlockTripwireHookHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -29,6 +36,10 @@ public:
return true;
}
inline static NIBBLETYPE DirectionToMetadata(eBlockFace a_Direction)
{
switch (a_Direction)
@ -48,6 +59,10 @@ public:
UNREACHABLE("Unsupported block face");
}
inline static eBlockFace MetadataToDirection(NIBBLETYPE a_Meta)
{
switch (a_Meta & 0x03)
@ -60,11 +75,9 @@ public:
}
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to zero
a_Pickups.push_back(cItem(E_BLOCK_TRIPWIRE_HOOK, 1, 0));
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
@ -78,6 +91,10 @@ public:
return ((a_RelY > 0) && cBlockInfo::FullyOccupiesVoxel(BlockIsOn));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -9,12 +9,19 @@
class cBlockVineHandler :
public cBlockHandler
{
using super = cBlockHandler;
public:
cBlockVineHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
cBlockVineHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer & a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@ -38,12 +45,24 @@ public:
return true;
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Reset meta to zero
a_Pickups.push_back(cItem(E_BLOCK_VINES, 1, 0));
// Only drops self when using shears, otherwise drops nothing:
if ((a_Tool == nullptr) || (a_Tool->m_ItemType != E_ITEM_SHEARS))
{
return {};
}
return cItem(E_BLOCK_VINES, 1, 0);
}
static NIBBLETYPE DirectionToMetaData(char a_BlockFace)
{
switch (a_BlockFace)
@ -56,6 +75,10 @@ public:
}
}
static char MetaDataToDirection(NIBBLETYPE a_MetaData)
{
switch (a_MetaData)
@ -68,6 +91,10 @@ public:
}
}
/** Returns true if the specified block type is good for vines to attach to */
static bool IsBlockAttachable(BLOCKTYPE a_BlockType)
{
@ -94,8 +121,12 @@ public:
}
}
/** Returns the meta that has the maximum allowable sides of the vine, given the surroundings */
NIBBLETYPE GetMaxMeta(cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
NIBBLETYPE GetMaxMeta(cChunk & a_Chunk, Vector3i a_RelPos)
{
static const struct
{
@ -113,8 +144,9 @@ public:
{
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
auto checkPos = a_RelPos.addedXZ(Coord.x, Coord.z);
if (
a_Chunk.UnboundedRelGetBlock(a_RelX + Coord.x, a_RelY, a_RelZ + Coord.z, BlockType, BlockMeta) &&
a_Chunk.UnboundedRelGetBlock(checkPos.x, checkPos.y, checkPos.z, BlockType, BlockMeta) &&
IsBlockAttachable(BlockType)
)
{
@ -124,55 +156,71 @@ public:
return res;
}
void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override
virtual void Check(
cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface,
Vector3i a_RelPos,
cChunk & a_Chunk
) override
{
NIBBLETYPE CurMeta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ);
NIBBLETYPE MaxMeta = GetMaxMeta(a_Chunk, a_RelX, a_RelY, a_RelZ);
NIBBLETYPE CurMeta = a_Chunk.GetMeta(a_RelPos);
NIBBLETYPE MaxMeta = GetMaxMeta(a_Chunk, a_RelPos);
// Check if vine above us, add its meta to MaxMeta
if ((a_RelY < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == m_BlockType))
if ((a_RelPos.y < cChunkDef::Height - 1) && (a_Chunk.GetBlock(a_RelPos.addedY(1)) == m_BlockType))
{
MaxMeta |= a_Chunk.GetMeta(a_RelX, a_RelY + 1, a_RelZ);
MaxMeta |= a_Chunk.GetMeta(a_RelPos.addedY(1));
}
NIBBLETYPE Common = CurMeta & MaxMeta; // Neighbors that we have and are legal
if (Common != CurMeta)
{
// There is a neighbor missing, need to update the meta or even destroy the block
bool HasTop = (a_RelY < cChunkDef::Height - 1) && IsBlockAttachable(a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ));
bool HasTop = (a_RelPos.y < cChunkDef::Height - 1) && IsBlockAttachable(a_Chunk.GetBlock(a_RelPos.addedY(1)));
if ((Common == 0) && !HasTop)
{
// The vine just lost all its support, destroy the block:
if (DoesDropOnUnsuitable())
{
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
DropBlock(a_ChunkInterface, *a_Chunk.GetWorld(), a_PluginInterface, nullptr, BlockX, a_RelY, BlockZ);
a_ChunkInterface.DropBlockAsPickups(a_Chunk.RelativeToAbsolute(a_RelPos));
}
a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_AIR, 0);
a_Chunk.SetBlock(a_RelPos, E_BLOCK_AIR, 0);
return;
}
a_Chunk.SetBlock(a_RelX, a_RelY, a_RelZ, m_BlockType, Common);
a_Chunk.SetBlock(a_RelPos, m_BlockType, Common);
}
else
{
// Wake up the simulators for this block:
int BlockX = a_RelX + a_Chunk.GetPosX() * cChunkDef::Width;
int BlockZ = a_RelZ + a_Chunk.GetPosZ() * cChunkDef::Width;
a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp({BlockX, a_RelY, BlockZ}, &a_Chunk);
auto absPos = a_Chunk.RelativeToAbsolute(a_RelPos);
a_Chunk.GetWorld()->GetSimulatorManager()->WakeUp(absPos, &a_Chunk);
}
}
virtual bool DoesIgnoreBuildCollision(cChunkInterface & a_ChunkInterface, Vector3i a_Pos, cPlayer & a_Player, NIBBLETYPE a_Meta) override
{
return true;
}
virtual bool DoesDropOnUnsuitable(void) override
{
return false;
}
virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
{
UNUSED(a_ChunkInterface);
@ -196,34 +244,53 @@ public:
}
}
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
{
return ((a_Meta >> 1) | (a_Meta << 3)) & 0x0f; // Rotate bits to the right
}
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
{
return ((a_Meta << 1) | (a_Meta >> 3)) & 0x0f; // Rotate bits to the left
}
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
{
// Bits 2 and 4 stay, bits 1 and 3 swap
return static_cast<NIBBLETYPE>((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2));
}
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
{
// Bits 1 and 3 stay, bits 2 and 4 swap
return static_cast<NIBBLETYPE>((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2));
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);
return 7;
}
} ;

View File

@ -8,22 +8,31 @@
class cBlockWallSignHandler :
class cBlockWallSignHandler:
public cBlockHandler
{
typedef cBlockHandler super;
using super = cBlockHandler;
public:
cBlockWallSignHandler(BLOCKTYPE a_BlockType) :
cBlockWallSignHandler(BLOCKTYPE a_BlockType):
super(a_BlockType)
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
a_Pickups.push_back(cItem(E_ITEM_SIGN, 1, 0));
return cItem(E_ITEM_SIGN, 1, 0);
}
virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
int BlockX = (a_Chunk.GetPosX() * cChunkDef::Width) + a_RelX;
@ -34,6 +43,10 @@ public:
return ((Type == E_BLOCK_WALLSIGN) || (Type == E_BLOCK_SIGN_POST) || cBlockInfo::IsSolid(Type));
}
static void GetBlockCoordsBehindTheSign(NIBBLETYPE a_BlockMeta, int & a_BlockX, int & a_BlockZ)
{
switch (a_BlockMeta)
@ -46,14 +59,18 @@ public:
}
}
static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction)
{
switch (a_Direction)
{
case BLOCK_FACE_ZM: return 0x2;
case BLOCK_FACE_ZP: return 0x3;
case BLOCK_FACE_XM: return 0x4;
case BLOCK_FACE_XP: return 0x5;
case BLOCK_FACE_ZM: return 0x02;
case BLOCK_FACE_ZP: return 0x03;
case BLOCK_FACE_XM: return 0x04;
case BLOCK_FACE_XP: return 0x05;
case BLOCK_FACE_NONE:
case BLOCK_FACE_YP:
case BLOCK_FACE_YM:
@ -61,9 +78,13 @@ public:
break;
}
}
return 0x2;
return 0x02;
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);

View File

@ -97,9 +97,8 @@ SET (HDRS
BlockWorkbench.h
BroadcastInterface.h
ChunkInterface.h
ClearMetaOnDrop.h
GetHandlerCompileTimeTemplate.h
MetaRotator.h
Mixins.h
WorldInterface.h
)

View File

@ -5,6 +5,7 @@
#include "BlockHandler.h"
#include "WorldInterface.h"
#include "../ChunkMap.h"
#include "../World.h"
@ -30,19 +31,16 @@ NIBBLETYPE cChunkInterface::GetBlockMeta(Vector3i a_Pos)
bool cChunkInterface::GetBlockTypeMeta(Vector3i a_Pos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta)
{
return m_ChunkMap->GetBlockTypeMeta(a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta);
return m_ChunkMap->GetBlockTypeMeta(a_Pos, a_BlockType, a_BlockMeta);
}
/** Sets the block at the specified coords to the specified value.
Full processing, incl. updating neighbors, is performed.
*/
void cChunkInterface::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
void cChunkInterface::SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
m_ChunkMap->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
m_ChunkMap->SetBlock(a_BlockPos, a_BlockType, a_BlockMeta);
}
@ -106,10 +104,26 @@ bool cChunkInterface::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a
bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, int a_X, int a_Y, int a_Z)
bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos)
{
cBlockHandler * Handler = cBlockInfo::GetHandler(GetBlock({a_X, a_Y, a_Z}));
Handler->OnDestroyed(*this, a_WorldInterface, a_X, a_Y, a_Z);
return m_ChunkMap->DigBlock(a_X, a_Y, a_Z);
BLOCKTYPE blockType;
NIBBLETYPE blockMeta;
GetBlockTypeMeta(a_BlockPos, blockType, blockMeta);
auto handler = cBlockInfo::GetHandler(blockType);
handler->OnBreaking(*this, a_WorldInterface, a_BlockPos);
if (!m_ChunkMap->DigBlock(a_BlockPos))
{
return false;
}
handler->OnBroken(*this, a_WorldInterface, a_BlockPos, blockType, blockMeta);
return true;
}
void cChunkInterface::DropBlockAsPickups(Vector3i a_BlockPos, const cEntity * a_Digger, const cItem * a_Tool)
{
m_ChunkMap->GetWorld()->DropBlockAsPickups(a_BlockPos, a_Digger, a_Tool);
}

View File

@ -22,9 +22,16 @@ public:
bool GetBlockTypeMeta(Vector3i a_Pos, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
/** Sets the block at the specified coords to the specified value.
Full processing, incl. updating neighbors, is performed.
*/
void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
Full processing, incl. updating neighbors, is performed. */
void SetBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
/** OBSOLETE, use the Vector3i-based overload instead.
Sets the block at the specified coords to the specified value.
Full processing, incl. updating neighbors, is performed. */
void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
return 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, bool a_ShouldMarkDirty = true, bool a_ShouldInformClient = true);
@ -44,7 +51,11 @@ public:
virtual bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes) override;
bool DigBlock(cWorldInterface & a_WorldInterface, int a_X, int a_Y, int a_Z);
bool DigBlock(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos);
/** Digs the block and spawns the relevant pickups, as if a_Digger used a_Tool to dig the block. */
void DropBlockAsPickups(Vector3i a_BlockPos, const cEntity * a_Digger = nullptr, const cItem * a_Tool = nullptr);
private:
cChunkMap * m_ChunkMap;

View File

@ -1,24 +0,0 @@
#pragma once
// mixin for use to clear meta values when the block is converted to a pickup
// Usage: inherit from this class, passing the parent class as the parameter Base
// For example to use in class Foo which should inherit Bar use
// class Foo : public cClearMetaOnDrop<Bar>;
template <class Base>
class cClearMetaOnDrop : public Base
{
public:
cClearMetaOnDrop(BLOCKTYPE a_BlockType) :
Base(a_BlockType)
{}
virtual ~cClearMetaOnDrop() override {}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(this->m_BlockType));
}
};

View File

@ -1,120 +0,0 @@
// MetaRotator.h
// Provides a mixin for rotations and reflections
#pragma once
// MSVC generates warnings for the templated AssertIfNotMatched parameter conditions, so disable it:
#ifdef _MSC_VER
#pragma warning(disable: 4127) // Conditional expression is constant
#endif
/*
Provides a mixin for rotations and reflections following the standard pattern of apply mask then use case.
Usage:
Inherit from this class providing your base class as Base, the BitMask for the direction bits in bitmask and the masked value for the directions in North, East, South, West. There is also an aptional parameter AssertIfNotMatched. Set this if it is invalid for a block to exist in any other state.
*/
template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched = false>
class cMetaRotator : public Base
{
public:
cMetaRotator(BLOCKTYPE a_BlockType) :
Base(a_BlockType)
{}
virtual ~cMetaRotator() override {}
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override;
};
template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCW(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case South: return West | OtherMeta;
case West: return North | OtherMeta;
case North: return East | OtherMeta;
case East: return South | OtherMeta;
}
if (AssertIfNotMatched)
{
ASSERT(!"Invalid Meta value");
}
return a_Meta;
}
template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCCW(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case South: return East | OtherMeta;
case East: return North | OtherMeta;
case North: return West | OtherMeta;
case West: return South | OtherMeta;
}
if (AssertIfNotMatched)
{
ASSERT(!"Invalid Meta value");
}
return a_Meta;
}
template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorXY(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case South: return North | OtherMeta;
case North: return South | OtherMeta;
}
// Not Facing North or South; No change.
return a_Meta;
}
template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorYZ(NIBBLETYPE a_Meta)
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case West: return East | OtherMeta;
case East: return West | OtherMeta;
}
// Not Facing East or West; No change.
return a_Meta;
}

166
src/Blocks/Mixins.h Normal file
View File

@ -0,0 +1,166 @@
// Mixins.h
// Provides various mixins for easier cBlockHandler descendant implementations
/* The general use case is to derive a handler from these mixins, providing a suitable base to them:
class cBlockAir: public cBlockWithNoDrops<cBlockHandler>;
class cBlockLadder: public cMetaRotator<cClearMetaOnDrop, ...>
*/
#pragma once
#include "../Item.h"
// MSVC generates warnings for the templated AssertIfNotMatched parameter conditions, so disable it:
#ifdef _MSC_VER
#pragma warning(disable: 4127) // Conditional expression is constant
#endif
template <class Base = cBlockHandler>
class cBlockWithNoDrops:
public Base
{
public:
cBlockWithNoDrops(BLOCKTYPE a_BlockType):
Base(a_BlockType)
{
}
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Don't drop anything:
return {};
}
};
/** Mixin to clear the block's meta value when converting to a pickup. */
template <class Base>
class cClearMetaOnDrop:
public Base
{
public:
cClearMetaOnDrop(BLOCKTYPE a_BlockType):
Base(a_BlockType)
{
}
virtual cItems ConvertToPickups(NIBBLETYPE a_BlockMeta, cBlockEntity * a_BlockEntity, const cEntity * a_Digger, const cItem * a_Tool) override
{
// Reset the meta to zero:
return cItem(this->m_BlockType);
}
};
/** Mixin for rotations and reflections following the standard pattern of "apply mask, then use a switch".
Inherit from this class providing your base class as Base, the BitMask for the direction bits in bitmask and the masked value for the directions in North, East, South, West.
There is also an aptional parameter AssertIfNotMatched, set this if it is invalid for a block to exist in any other state. */
template <class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched = false>
class cMetaRotator:
public Base
{
public:
cMetaRotator(BLOCKTYPE a_BlockType):
Base(a_BlockType)
{}
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case South: return East | OtherMeta;
case East: return North | OtherMeta;
case North: return West | OtherMeta;
case West: return South | OtherMeta;
}
if (AssertIfNotMatched)
{
ASSERT(!"Invalid Meta value");
}
return a_Meta;
}
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case South: return West | OtherMeta;
case West: return North | OtherMeta;
case North: return East | OtherMeta;
case East: return South | OtherMeta;
}
if (AssertIfNotMatched)
{
ASSERT(!"Invalid Meta value");
}
return a_Meta;
}
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case South: return North | OtherMeta;
case North: return South | OtherMeta;
}
// Not Facing North or South; No change.
return a_Meta;
}
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
{
NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
switch (a_Meta & BitMask)
{
case West: return East | OtherMeta;
case East: return West | OtherMeta;
}
// Not Facing East or West; No change.
return a_Meta;
}
};

View File

@ -55,7 +55,7 @@ public:
/** Spawns experience orbs of the specified total value at the given location. The orbs' values are split according to regular Minecraft rules.
Returns an vector of UniqueID of all the orbs. */
virtual std::vector<UInt32> SpawnSplitExperienceOrbs(double a_X, double a_Y, double a_Z, int a_Reward) = 0;
virtual std::vector<UInt32> SpawnSplitExperienceOrbs(Vector3d a_Pos, int a_Reward) = 0;
/** Sends the block on those coords to the player */
virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer & a_Player) = 0;

View File

@ -821,7 +821,7 @@ void cChunk::CheckBlocks()
Vector3i Pos = (*itr);
cBlockHandler * Handler = BlockHandler(GetBlock(Pos));
Handler->Check(ChunkInterface, PluginInterface, Pos.x, Pos.y, Pos.z, *this);
Handler->Check(ChunkInterface, PluginInterface, Pos, *this);
} // for itr - ToTickBlocks[]
}
@ -943,11 +943,11 @@ void cChunk::ApplyWeatherToTop()
}
else if (cBlockInfo::IsSnowable(TopBlock) && (Height < cChunkDef::Height - 1))
{
SetBlock(X, Height + 1, Z, E_BLOCK_SNOW, 0);
SetBlock({X, Height + 1, Z}, E_BLOCK_SNOW, 0);
}
else if (IsBlockWater(TopBlock) && (TopMeta == 0))
{
SetBlock(X, Height, Z, E_BLOCK_ICE, 0);
SetBlock({X, Height, Z}, E_BLOCK_ICE, 0);
}
else if (
(m_World->IsDeepSnowEnabled()) &&
@ -959,7 +959,7 @@ void cChunk::ApplyWeatherToTop()
)
)
{
SetBlock(X, Height, Z, E_BLOCK_SNOW, 0);
SetBlock({X, Height, Z}, E_BLOCK_SNOW, 0);
}
}
@ -967,6 +967,23 @@ void cChunk::ApplyWeatherToTop()
cItems cChunk::PickupsFromBlock(Vector3i a_RelPos, const cEntity * a_Digger, const cItem * a_Tool)
{
BLOCKTYPE blockType;
NIBBLETYPE blockMeta;
GetBlockTypeMeta(a_RelPos, blockType, blockMeta);
auto blockHandler = cBlockInfo::GetHandler(blockType);
auto blockEntity = GetBlockEntityRel(a_RelPos);
auto pickups = blockHandler->ConvertToPickups(blockMeta, blockEntity, a_Digger, a_Tool);
auto absPos = RelativeToAbsolute(a_RelPos);
cRoot::Get()->GetPluginManager()->CallHookBlockToPickups(*m_World, absPos, blockType, blockMeta, blockEntity, a_Digger, a_Tool, pickups);
return pickups;
}
bool cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType)
{
auto & Random = GetRandomProvider();
@ -1047,9 +1064,9 @@ bool cChunk::GrowMelonPumpkin(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl
Meta
);
VERIFY(UnboundedRelFastSetBlock(a_RelX + x, a_RelY, a_RelZ + z, ProduceType, Meta));
auto Absolute = RelativeToAbsolute(Vector3i{a_RelX + x, a_RelY, a_RelZ + z});
auto absolute = RelativeToAbsolute(Vector3i{a_RelX + x, a_RelY, a_RelZ + z});
cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap());
cBlockHandler::NeighborChanged(ChunkInterface, Absolute.x, Absolute.y - 1, Absolute.z, BLOCK_FACE_YP);
cBlockHandler::NeighborChanged(ChunkInterface, absolute.addedY(-1), BLOCK_FACE_YP);
break;
}
}
@ -1154,21 +1171,7 @@ int cChunk::GrowCactus(int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks)
)
{
// Remove the cactus
GetWorld()->DigBlock(a_RelX + GetPosX() * cChunkDef::Width, Top + i, a_RelZ + GetPosZ() * cChunkDef::Width);
// Drop the cactus on the other side of the blocking block
cBlockHandler * Handler = BlockHandler(E_BLOCK_CACTUS);
cChunkInterface ChunkInterface(GetWorld()->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*GetWorld());
Handler->DropBlock(
ChunkInterface,
*GetWorld(),
PluginInterface,
nullptr,
a_RelX + GetPosX() * cChunkDef::Width - Coord.x,
Top + i,
a_RelZ + GetPosZ() * cChunkDef::Width - Coord.z
);
GetWorld()->DropBlockAsPickups(RelativeToAbsolute({a_RelX, a_RelY, a_RelZ}), nullptr, nullptr);
return false;
}
} // for i - Coords[]
@ -1356,7 +1359,7 @@ bool cChunk::UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE
// The chunk is not available, bail out
return false;
}
Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta);
Chunk->SetBlock({a_RelX, a_RelY, a_RelZ}, a_BlockType, a_BlockMeta);
return true;
}
@ -1385,17 +1388,17 @@ bool cChunk::UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKT
void cChunk::UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ)
void cChunk::UnboundedQueueTickBlock(Vector3i a_RelPos)
{
if (!cChunkDef::IsValidHeight(a_RelY))
if (!cChunkDef::IsValidHeight(a_RelPos.y))
{
// Outside of chunkmap
return;
}
cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ);
if ((Chunk != nullptr) && Chunk->IsValid())
auto chunk = GetRelNeighborChunkAdjustCoords(a_RelPos.x, a_RelPos.z);
if ((chunk != nullptr) && chunk->IsValid())
{
Chunk->QueueTickBlock(a_RelX, a_RelY, a_RelZ);
chunk->QueueTickBlock(a_RelPos);
}
}
@ -1533,17 +1536,16 @@ void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes)
void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
void cChunk::SetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta, a_SendToClients);
FastSetBlock(a_RelPos, a_BlockType, a_BlockMeta);
// Tick this block and its neighbors:
m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
QueueTickBlockNeighbors(a_RelX, a_RelY, a_RelZ);
m_ToTickBlocks.push_back(a_RelPos);
QueueTickBlockNeighbors(a_RelPos);
// If there was a block entity, remove it:
Vector3i WorldPos = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ);
cBlockEntity * BlockEntity = GetBlockEntity(WorldPos);
cBlockEntity * BlockEntity = GetBlockEntityRel(a_RelPos);
if (BlockEntity != nullptr)
{
BlockEntity->Destroy();
@ -1576,7 +1578,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
case E_BLOCK_BREWING_STAND:
{
// Fast set block has already marked dirty
AddBlockEntityClean(cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, WorldPos, m_World));
AddBlockEntityClean(cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, RelativeToAbsolute(a_RelPos), m_World));
break;
}
} // switch (a_BlockType)
@ -1586,33 +1588,25 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
void cChunk::QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ)
void cChunk::QueueTickBlock(Vector3i a_RelPos)
{
ASSERT (
(a_RelX >= 0) && (a_RelX < Width) &&
(a_RelY >= 0) && (a_RelY < Height) &&
(a_RelZ >= 0) && (a_RelZ < Width)
); // Coords need to be valid
ASSERT (IsValidRelPos(a_RelPos));
if (!IsValid())
{
return;
}
m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ));
m_ToTickBlocks.push_back(a_RelPos);
}
void cChunk::QueueTickBlockNeighbors(int a_RelX, int a_RelY, int a_RelZ)
void cChunk::QueueTickBlockNeighbors(Vector3i a_RelPos)
{
struct
{
int x, y, z;
}
Coords[] =
static const Vector3i neighborCoords[] =
{
{ 1, 0, 0},
{-1, 0, 0},
@ -1621,9 +1615,9 @@ void cChunk::QueueTickBlockNeighbors(int a_RelX, int a_RelY, int a_RelZ)
{ 0, 0, 1},
{ 0, 0, -1},
} ;
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
for (const auto & neighbor: neighborCoords)
{
UnboundedQueueTickBlock(a_RelX + Coords[i].x, a_RelY + Coords[i].y, a_RelZ + Coords[i].z);
UnboundedQueueTickBlock(a_RelPos + neighbor);
} // for i - Coords[]
}
@ -1759,22 +1753,28 @@ void cChunk::AddBlockEntityClean(cBlockEntity * a_BlockEntity)
cBlockEntity * cChunk::GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ)
cBlockEntity * cChunk::GetBlockEntity(Vector3i a_AbsPos)
{
int RelX = a_BlockX - m_PosX * cChunkDef::Width;
int RelZ = a_BlockZ - m_PosZ * cChunkDef::Width;
auto relPos = AbsoluteToRelative(a_AbsPos);
if (
!IsValidWidth (RelX) ||
!IsValidHeight(a_BlockY) ||
!IsValidWidth (RelZ)
)
if (!IsValidRelPos(relPos))
{
// Coordinates are outside outside the world, no block entities here
// Coordinates are outside outside this chunk, no block entities here
return nullptr;
}
auto itr = m_BlockEntities.find(static_cast<size_t>(MakeIndexNoCheck(RelX, a_BlockY, RelZ)));
auto itr = m_BlockEntities.find(static_cast<size_t>(MakeIndexNoCheck(relPos)));
return (itr == m_BlockEntities.end()) ? nullptr : itr->second;
}
cBlockEntity * cChunk::GetBlockEntityRel(Vector3i a_RelPos)
{
ASSERT(IsValidRelPos(a_RelPos));
auto itr = m_BlockEntities.find(static_cast<size_t>(MakeIndexNoCheck(a_RelPos)));
return (itr == m_BlockEntities.end()) ? nullptr : itr->second;
}

View File

@ -152,15 +152,21 @@ public:
cWorld * GetWorld(void) const { return m_World; }
void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true);
void SetBlock(Vector3i a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
// SetBlock() does a lot of work (heightmap, tickblocks, blockentities) so a BlockIdx version doesn't make sense
void SetBlock(Vector3i a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { SetBlock( a_RelBlockPos.x, a_RelBlockPos.y, a_RelBlockPos.z, a_BlockType, a_BlockMeta); }
/** Queues block for ticking (m_ToTickQueue) */
void QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ);
void QueueTickBlock(Vector3i a_RelPos);
/** OBSOLETE, use the Vector3i-based overload instead.
Queues block for ticking (m_ToTickQueue) */
void QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ)
{
return QueueTickBlock({a_RelX, a_RelY, a_RelZ});
}
/** Queues all 6 neighbors of the specified block for ticking (m_ToTickQueue). If any are outside the chunk, relays the checking to the proper neighboring chunk */
void QueueTickBlockNeighbors(int a_RelX, int a_RelY, int a_RelZ);
void QueueTickBlockNeighbors(Vector3i a_RelPos);
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
void FastSetBlock(Vector3i a_RelPos, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true)
@ -447,7 +453,7 @@ public:
bool UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
/** Same as QueueTickBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s in such a case), ignores unsuccessful attempts */
void UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ);
void UnboundedQueueTickBlock(Vector3i a_RelPos);
@ -460,8 +466,19 @@ public:
cRedstoneSimulatorChunkData * GetRedstoneSimulatorData(void) { return m_RedstoneSimulatorData; }
void SetRedstoneSimulatorData(cRedstoneSimulatorChunkData * a_Data) { m_RedstoneSimulatorData = a_Data; }
cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ);
cBlockEntity * GetBlockEntity(const Vector3i & a_BlockPos) { return GetBlockEntity(a_BlockPos.x, a_BlockPos.y, a_BlockPos.z); }
/** OBSOLETE, use the Vector3i-based overload isntead.
Returns the block entity at the specified (absolute) coords.
Returns nullptr if no such BE or outside this chunk. */
cBlockEntity * GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ) { return GetBlockEntity({a_BlockX, a_BlockY, a_BlockZ}); }
/** Returns the block entity at the specified (absolute) coords.
Returns nullptr if no such BE or outside this chunk. */
cBlockEntity * GetBlockEntity(Vector3i a_AbsPos);
/** Returns the block entity at the specified (relative) coords.
Returns nullptr if no such BE.
Asserts that the position is a valid relative position. */
cBlockEntity * GetBlockEntityRel(Vector3i a_RelPos);
/** Returns true if the chunk should be ticked in the tick-thread.
Checks if there are any clients and if the always-tick flag is set */
@ -587,6 +604,10 @@ private:
/** Adds snow to the top of snowy biomes and hydrates farmland / fills cauldrons in rainy biomes */
void ApplyWeatherToTop(void);
/** Returns the pickups that would be produced, if the specified block was dug up by a_Digger using a_Tool.
Doesn't dig the block, only queries the block handlers and then plugins for the pickups. */
cItems PickupsFromBlock(Vector3i a_RelPos, const cEntity * a_Digger, const cItem * a_Tool);
/** Grows sugarcane by the specified number of blocks, but no more than 3 blocks high (used by both bonemeal and ticking); returns the amount of blocks the sugarcane grew inside this call */
int GrowSugarcane (int a_RelX, int a_RelY, int a_RelZ, int a_NumBlocks);

Some files were not shown because too many files have changed in this diff Show More