1
0

Merge branch 'master' into potions

This commit is contained in:
madmaxoft 2014-07-15 09:01:32 +02:00
commit 8e946da8ac
72 changed files with 700 additions and 444 deletions

View File

@ -22,6 +22,8 @@ function Initialize(Plugin)
Plugin:SetVersion(1);
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_USED_ITEM, OnPlayerUsedItem);
LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion());
return true;
end
@ -36,8 +38,8 @@ function OnPlayerUsedItem(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, Cu
return false;
end;
if (Player:HasPermission("diamondmover.move") == false) then
return true;
if (not Player:HasPermission("diamondmover.move")) then
return false;
end;
-- Rclk with a diamond to push in the direction the player is facing
@ -56,7 +58,7 @@ function OnPlayerUsedItem(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, Cu
if (PlayerPitch > 70) then -- looking down
BlockY = BlockY - 1;
else
local PlayerRot = Player:GetRotation() + 180; -- Convert [-180, 180] into [0, 360] for simpler conditions
local PlayerRot = Player:GetYaw() + 180; -- Convert [-180, 180] into [0, 360] for simpler conditions
if ((PlayerRot < 45) or (PlayerRot > 315)) then
BlockZ = BlockZ - 1;
else

@ -1 +1 @@
Subproject commit 1ed82759c68f92c4acc7e3f33b850cf9f01c8aba
Subproject commit 784b04ff9afd5faeaeb15c3fa159ff98adf55182

View File

@ -6,21 +6,21 @@ if mobdebugfound then mobdebug.start() end
-- The list of valid arguments that the ToLua scripts can process:
local KnownArgs = {
['v'] = true,
['h'] = true,
['p'] = true,
['P'] = true,
['o'] = true,
['n'] = true,
['H'] = true,
['S'] = true,
['1'] = true,
['L'] = true,
['D'] = true,
['W'] = true,
['C'] = true,
['E'] = true,
['t'] = true,
['q'] = true,
['h'] = true,
['p'] = true,
['P'] = true,
['o'] = true,
['n'] = true,
['H'] = true,
['S'] = true,
['1'] = true,
['L'] = true,
['D'] = true,
['W'] = true,
['C'] = true,
['E'] = true,
['t'] = true,
['q'] = true,
}

View File

@ -59,7 +59,7 @@ void InternalMergeBlocks(
}
else
{
BLOCKTYPE FakeDestMeta = 0;
NIBBLETYPE FakeDestMeta = 0;
Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], FakeDestMeta, (NIBBLETYPE)0);
}
++DstIdx;

View File

@ -28,24 +28,26 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
switch (a_BlockType)
{
case E_BLOCK_BEACON: return new cBeaconEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World, a_BlockType);
case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_TRAPPED_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World, a_BlockType);
case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
}
LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)",
__FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str()
);
ASSERT(!"Requesting creation of an unknown block entity");
return NULL;
}

View File

@ -11,8 +11,9 @@
cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
super(E_BLOCK_CHEST, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World)
cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type) :
super(a_Type, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
m_NumActivePlayers(0)
{
cBlockEntityWindowOwner::SetBlockEntity(this);
}
@ -113,7 +114,7 @@ void cChestEntity::UsedBy(cPlayer * a_Player)
// The few false positives aren't much to worry about
int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(m_PosX, m_PosZ, ChunkX, ChunkZ);
m_World->MarkChunkDirty(ChunkX, ChunkZ);
m_World->MarkChunkDirty(ChunkX, ChunkZ, true);
}

View File

@ -34,8 +34,8 @@ public:
// tolua_end
/// Constructor used for normal operation
cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
/** Constructor used for normal operation */
cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type);
virtual ~cChestEntity();
@ -48,8 +48,20 @@ public:
virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) override;
/// Opens a new chest window for this chest. Scans for neighbors to open a double chest window, if appropriate.
/** Opens a new chest window for this chest.
Scans for neighbors to open a double chest window, if appropriate. */
void OpenNewWindow(void);
/** Gets the number of players who currently have this chest open */
int GetNumberOfPlayers(void) const { return m_NumActivePlayers; }
/** Sets the number of players who currently have this chest open */
void SetNumberOfPlayers(int a_NumActivePlayers) { m_NumActivePlayers = a_NumActivePlayers; }
private:
/** Number of players who currently have this chest open */
int m_NumActivePlayers;
} ; // tolua_export

View File

@ -53,7 +53,7 @@ public:
cItem GetItem(void) const { return m_Item; }
/** Set the item in the flower pot */
void SetItem(const cItem a_Item) { m_Item = a_Item; }
void SetItem(const cItem & a_Item) { m_Item = a_Item; }
// tolua_end

View File

@ -157,6 +157,7 @@ bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
bool res = false;
switch (a_Chunk.GetBlock(m_RelX, m_PosY + 1, m_RelZ))
{
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST:
{
// Chests have special handling because of double-chests
@ -322,6 +323,7 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
bool res = false;
switch (DestChunk->GetBlock(OutRelX, OutY, OutRelZ))
{
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST:
{
// Chests have special handling because of double-chests
@ -366,19 +368,19 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
/// Moves items from a chest (dblchest) above the hopper into this hopper. Returns true if contents have changed.
bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
{
cChestEntity * Chest = (cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ);
if (Chest == NULL)
cChestEntity * MainChest = (cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ);
if (MainChest == NULL)
{
LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX, m_PosY + 1, m_PosZ);
return false;
}
if (MoveItemsFromGrid(*Chest))
if (MoveItemsFromGrid(*MainChest))
{
// Moved the item from the chest directly above the hopper
return true;
}
// Check if the chest is a double-chest, if so, try to move from there:
// Check if the chest is a double-chest (chest directly above was empty), if so, try to move from there:
static const struct
{
int x, z;
@ -395,21 +397,26 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
int x = m_RelX + Coords[i].x;
int z = m_RelZ + Coords[i].z;
cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
if (
(Neighbor == NULL) ||
(Neighbor->GetBlock(x, m_PosY + 1, z) != E_BLOCK_CHEST)
)
if (Neighbor == NULL)
{
continue;
}
Chest = (cChestEntity *)Neighbor->GetBlockEntity(m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z);
if (Chest == NULL)
BLOCKTYPE Block = Neighbor->GetBlock(x, m_PosY + 1, z);
if (Block != MainChest->GetBlockType())
{
// Not the same kind of chest
continue;
}
cChestEntity * SideChest = (cChestEntity *)Neighbor->GetBlockEntity(m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z);
if (SideChest == NULL)
{
LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z);
}
else
{
if (MoveItemsFromGrid(*Chest))
if (MoveItemsFromGrid(*SideChest))
{
return true;
}
@ -550,10 +557,11 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block
}
if (MoveItemsToGrid(*Chest))
{
// Chest block directly connected was not full
return true;
}
// Check if the chest is a double-chest, if so, try to move into the other half:
// Check if the chest is a double-chest (chest block directly connected was full), if so, try to move into the other half:
static const struct
{
int x, z;
@ -572,13 +580,18 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block
int x = RelX + Coords[i].x;
int z = RelZ + Coords[i].z;
cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
if (
(Neighbor == NULL) ||
(Neighbor->GetBlock(x, a_BlockY, z) != E_BLOCK_CHEST)
)
if (Neighbor == NULL)
{
continue;
}
BLOCKTYPE Block = Neighbor->GetBlock(x, a_BlockY, z);
if (Block != Chest->GetBlockType())
{
// Not the same kind of chest
continue;
}
Chest = (cChestEntity *)Neighbor->GetBlockEntity(a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z);
if (Chest == NULL)
{

View File

@ -91,7 +91,7 @@ void cNoteEntity::MakeSound(void)
// TODO: instead of calculating the power function over and over, make a precalculated table - there's only 24 pitches after all
float calcPitch = pow(2.0f, ((float)m_Pitch - 12.0f) / 12.0f);
m_World->BroadcastSoundEffect(sampleName, m_PosX * 8, m_PosY * 8, m_PosZ * 8, 3.0f, calcPitch);
m_World->BroadcastSoundEffect(sampleName, (double)m_PosX, (double)m_PosY, (double)m_PosZ, 3.0f, calcPitch);
}

View File

@ -101,6 +101,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_NEW_LEAVES ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_TORCH ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_TRAPPED_CHEST ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_TRIPWIRE ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1;
@ -162,6 +163,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_STATIONARY_WATER ].m_Transparent = true;
a_Info[E_BLOCK_STONE_BUTTON ].m_Transparent = true;
a_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_Transparent = true;
a_Info[E_BLOCK_TRAPPED_CHEST ].m_Transparent = true;
a_Info[E_BLOCK_TRIPWIRE ].m_Transparent = true;
a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_Transparent = true;
a_Info[E_BLOCK_TALL_GRASS ].m_Transparent = true;
@ -287,6 +289,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_TALL_GRASS ].m_IsSnowable = false;
a_Info[E_BLOCK_TNT ].m_IsSnowable = false;
a_Info[E_BLOCK_TORCH ].m_IsSnowable = false;
a_Info[E_BLOCK_TRAPPED_CHEST ].m_IsSnowable = false;
a_Info[E_BLOCK_TRIPWIRE ].m_IsSnowable = false;
a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_IsSnowable = false;
a_Info[E_BLOCK_VINES ].m_IsSnowable = false;

View File

@ -24,7 +24,7 @@ public:
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
a_WorldInterface.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("random.click", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
// Queue a button reset (unpress)
a_ChunkInterface.QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07), m_BlockType == E_BLOCK_STONE_BUTTON ? 20 : 30, m_BlockType, a_WorldInterface);

View File

@ -44,16 +44,16 @@ public:
}
double yaw = a_Player->GetYaw();
if (
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
(Area.GetRelBlockType(0, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(2, 0, 1) == m_BlockType)
)
{
a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3;
return true;
}
if (
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
(Area.GetRelBlockType(0, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(2, 0, 1) == m_BlockType)
)
{
// FIXME: This is unreachable, as the condition is the same as the above one
@ -130,12 +130,12 @@ public:
}
int NumChestNeighbors = 0;
if (Area.GetRelBlockType(1, 0, 2) == E_BLOCK_CHEST)
if (Area.GetRelBlockType(1, 0, 2) == m_BlockType)
{
if (
(Area.GetRelBlockType(0, 0, 2) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(1, 0, 1) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(1, 0, 3) == E_BLOCK_CHEST)
(Area.GetRelBlockType(0, 0, 2) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 3) == m_BlockType)
)
{
// Already a doublechest neighbor, disallow:
@ -143,12 +143,12 @@ public:
}
NumChestNeighbors += 1;
}
if (Area.GetRelBlockType(3, 0, 2) == E_BLOCK_CHEST)
if (Area.GetRelBlockType(3, 0, 2) == m_BlockType)
{
if (
(Area.GetRelBlockType(4, 0, 2) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(3, 0, 1) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(3, 0, 3) == E_BLOCK_CHEST)
(Area.GetRelBlockType(4, 0, 2) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 3) == m_BlockType)
)
{
// Already a doublechest neighbor, disallow:
@ -156,12 +156,12 @@ public:
}
NumChestNeighbors += 1;
}
if (Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
if (Area.GetRelBlockType(2, 0, 1) == m_BlockType)
{
if (
(Area.GetRelBlockType(2, 0, 0) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(1, 0, 1) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(3, 0, 1) == E_BLOCK_CHEST)
(Area.GetRelBlockType(2, 0, 0) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 1) == m_BlockType)
)
{
// Already a doublechest neighbor, disallow:
@ -169,12 +169,12 @@ public:
}
NumChestNeighbors += 1;
}
if (Area.GetRelBlockType(2, 0, 3) == E_BLOCK_CHEST)
if (Area.GetRelBlockType(2, 0, 3) == m_BlockType)
{
if (
(Area.GetRelBlockType(2, 0, 4) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(1, 0, 3) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(3, 0, 3) == E_BLOCK_CHEST)
(Area.GetRelBlockType(2, 0, 4) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 3) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 3) == m_BlockType)
)
{
// Already a doublechest neighbor, disallow:
@ -217,7 +217,7 @@ 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)
{
if (a_Area.GetRelBlockType(a_RelX, 0, a_RelZ) != E_BLOCK_CHEST)
if (a_Area.GetRelBlockType(a_RelX, 0, a_RelZ) != m_BlockType)
{
return false;
}
@ -228,7 +228,7 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_CHEST, 1, 0));
a_Pickups.push_back(cItem(m_BlockType, 1, 0));
}
} ;

View File

@ -16,13 +16,6 @@ public:
{
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_WOOL, 1, a_BlockMeta));
}
virtual const char * GetStepSound(void) override
{
return "step.cloth";

View File

@ -19,15 +19,13 @@
class cBlockFarmlandHandler :
public cBlockHandler
{
typedef cBlockHandler super;
public:
cBlockFarmlandHandler(void) :
super(E_BLOCK_FARMLAND)
cBlockFarmlandHandler(BLOCKTYPE a_BlockType) :
cBlockHandler(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
{
bool Found = false;
@ -105,6 +103,11 @@ public:
}
}
}
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.Add(E_BLOCK_DIRT, 1, 0); // Reset meta
}
} ;

View File

@ -176,7 +176,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
{
switch(a_BlockType)
{
// Block handlers, alphabetically sorted:
// Block handlers, alphabetically sorted:
case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType);
@ -211,7 +211,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_EMERALD_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_ENCHANTMENT_TABLE: return new cBlockEnchantmentTableHandler(a_BlockType);
case E_BLOCK_ENDER_CHEST: return new cBlockEnderchestHandler (a_BlockType);
case E_BLOCK_FARMLAND: return new cBlockFarmlandHandler ( );
case E_BLOCK_FARMLAND: return new cBlockFarmlandHandler (a_BlockType);
case E_BLOCK_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType);
case E_BLOCK_FIRE: return new cBlockFireHandler (a_BlockType);
case E_BLOCK_FLOWER_POT: return new cBlockFlowerPotHandler (a_BlockType);
@ -238,9 +238,9 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_LAPIS_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_LAVA: return new cBlockLavaHandler (a_BlockType);
case E_BLOCK_LEAVES: return new cBlockLeavesHandler (a_BlockType);
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return new cBlockPressurePlateHandler(a_BlockType);
case E_BLOCK_LILY_PAD: return new cBlockLilypadHandler (a_BlockType);
case E_BLOCK_LIT_FURNACE: return new cBlockFurnaceHandler (a_BlockType);
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return new cBlockPressurePlateHandler(a_BlockType);
case E_BLOCK_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_MELON: return new cBlockMelonHandler (a_BlockType);
case E_BLOCK_MELON_STEM: return new cBlockStemsHandler (a_BlockType);
@ -293,6 +293,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_TORCH: return new cBlockTorchHandler (a_BlockType);
case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType);
case E_BLOCK_TNT: return new cBlockTNTHandler (a_BlockType);
case E_BLOCK_TRAPPED_CHEST: return new cBlockChestHandler (a_BlockType);
case E_BLOCK_TRIPWIRE: return new cBlockTripwireHandler (a_BlockType);
case E_BLOCK_TRIPWIRE_HOOK: return new cBlockTripwireHookHandler (a_BlockType);
case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType);

View File

@ -1,7 +1,6 @@
#pragma once
#include "BlockHandler.h"
#include "BlockSideways.h"

View File

@ -41,21 +41,27 @@ public:
}
static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction) // tolua_export
{ // tolua_export
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)
{
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;
default: return 0x2;
default: return 0x2;
}
} // tolua_export
}
static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData) // tolua_export
{ // tolua_export
static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData)
{
switch (a_MetaData)
{
case 0x2: return BLOCK_FACE_ZM;
@ -64,10 +70,10 @@ public:
case 0x5: return BLOCK_FACE_XP;
default: return BLOCK_FACE_ZM;
}
} // tolua_export
}
/// Finds a suitable Direction for the Ladder. Returns BLOCK_FACE_BOTTOM on failure
/** 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)
{
for (int FaceInt = BLOCK_FACE_ZM; FaceInt <= BLOCK_FACE_XP; FaceInt++)

View File

@ -24,7 +24,7 @@ public:
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
a_WorldInterface.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("random.click", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
}

View File

@ -85,7 +85,7 @@ int cBlockPistonHandler::FirstPassthroughBlock(int a_PistonX, int a_PistonY, int
NIBBLETYPE currMeta;
AddPistonDir(a_PistonX, a_PistonY, a_PistonZ, pistonmeta, 1);
a_World->GetBlockTypeMeta(a_PistonX, a_PistonY, a_PistonZ, currBlock, currMeta);
if (CanBreakPush(currBlock))
if (cBlockInfo::IsPistonBreakable(currBlock))
{
// This block breaks when pushed, extend up to here
return ret;
@ -124,7 +124,7 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ,
}
a_World->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, 0, pistonMeta, pistonBlock);
a_World->BroadcastSoundEffect("tile.piston.out", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.7f);
a_World->BroadcastSoundEffect("tile.piston.out", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 0.5f, 0.7f);
// Drop the breakable block in the line, if appropriate:
AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, dist + 1); // "a_Block" now at the breakable / empty block
@ -198,7 +198,7 @@ void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ
AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1);
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta & ~(8));
a_World->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, 1, pistonMeta & ~(8), pistonBlock);
a_World->BroadcastSoundEffect("tile.piston.in", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.7f);
a_World->BroadcastSoundEffect("tile.piston.in", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 0.5f, 0.7f);
AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, 1);
// Retract the extension, pull block if appropriate

View File

@ -104,6 +104,7 @@ private:
case E_BLOCK_ENCHANTMENT_TABLE:
case E_BLOCK_END_PORTAL:
case E_BLOCK_END_PORTAL_FRAME:
// Notice the lack of an E_BLOCK_ENDER_CHEST here; its because ender chests can totally be pushed/pulled in MCS :)
case E_BLOCK_FURNACE:
case E_BLOCK_LIT_FURNACE:
case E_BLOCK_HOPPER:
@ -113,6 +114,7 @@ private:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_OBSIDIAN:
case E_BLOCK_PISTON_EXTENSION:
case E_BLOCK_TRAPPED_CHEST:
{
return false;
}
@ -126,24 +128,10 @@ private:
return true;
}
/// Returns true if the specified block can be pushed by a piston and broken / replaced
static inline bool CanBreakPush(BLOCKTYPE a_BlockType) { return cBlockInfo::IsPistonBreakable(a_BlockType); }
/// Returns true if the specified block can be pulled by a sticky piston
static inline bool CanPull(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
switch (a_BlockType)
{
case E_BLOCK_LAVA:
case E_BLOCK_STATIONARY_LAVA:
case E_BLOCK_STATIONARY_WATER:
case E_BLOCK_WATER:
{
return false;
}
}
if (CanBreakPush(a_BlockType))
if (cBlockInfo::IsPistonBreakable(a_BlockType))
{
return false; // CanBreakPush returns true, but we need false to prevent pulling
}

View File

@ -32,36 +32,36 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.Add(m_BlockType, 1, a_BlockMeta & 0x3);
a_Pickups.Add(m_BlockType, 1, a_BlockMeta & 0x3); // Reset meta
}
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_WoodMeta)
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_Meta)
{
switch (a_BlockFace)
{
case BLOCK_FACE_YM:
case BLOCK_FACE_YP:
{
return a_WoodMeta; // Top or bottom, just return original
return a_Meta; // Top or bottom, just return original
}
case BLOCK_FACE_ZP:
case BLOCK_FACE_ZM:
{
return a_WoodMeta | 0x8; // North or south
return a_Meta | 0x8; // North or south
}
case BLOCK_FACE_XP:
case BLOCK_FACE_XM:
{
return a_WoodMeta | 0x4; // East or west
return a_Meta | 0x4; // East or west
}
default:
{
ASSERT(!"Unhandled block face!");
return a_WoodMeta | 0xC; // No idea, give a special meta (all sides bark)
return a_Meta | 0xC; // No idea, give a special meta
}
}
}

View File

@ -7,6 +7,6 @@ public:
virtual ~cBroadcastInterface() {}
virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
virtual void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
virtual void BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) = 0;
};

View File

@ -1301,6 +1301,7 @@ void cChunk::CreateBlockEntities(void)
switch (BlockType)
{
case E_BLOCK_BEACON:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER:
@ -1431,6 +1432,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
switch (a_BlockType)
{
case E_BLOCK_BEACON:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER:
@ -2150,7 +2152,7 @@ bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallb
{
continue;
}
if ((*itr)->GetBlockType() != E_BLOCK_CHEST)
if (((*itr)->GetBlockType() != E_BLOCK_CHEST) && ((*itr)->GetBlockType() != E_BLOCK_TRAPPED_CHEST)) // Trapped chests use normal chests' handlers
{
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false;
@ -2530,8 +2532,8 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ)
{
int BlockX = m_PosX * cChunkDef::Width + a_RelX;
int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ;
int BlockY, ChunkX, ChunkZ;
AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
int ChunkX, ChunkZ;
BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
return m_ChunkMap->GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ);
}
@ -2954,7 +2956,7 @@ void cChunk::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_EffectI
void cChunk::BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
void cChunk::BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
{
for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr )
{
@ -2962,7 +2964,7 @@ void cChunk::BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a
{
continue;
}
(*itr)->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch);
(*itr)->SendSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch);
} // for itr - LoadedByClient[]
}

View File

@ -298,7 +298,7 @@ public:
void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL);
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8
void BroadcastSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL);
void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL);
void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);

View File

@ -647,19 +647,19 @@ void cChunkMap::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_Effe
void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
{
cCSLock Lock(m_CSLayers);
int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(a_SrcX / 8, a_SrcZ / 8, ChunkX, ChunkZ);
cChunkDef::BlockToChunk((int)std::floor(a_X), (int)std::floor(a_Z), ChunkX, ChunkZ);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ);
if (Chunk == NULL)
{
return;
}
// It's perfectly legal to broadcast packets even to invalid chunks!
Chunk->BroadcastSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch, a_Exclude);
Chunk->BroadcastSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch, a_Exclude);
}
@ -847,7 +847,22 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M
void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkZ)
void cChunkMap::MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
if ((Chunk == NULL) || !Chunk->IsValid())
{
return;
}
Chunk->SetIsRedstoneDirty(true);
}
void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDirty)
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
@ -856,6 +871,10 @@ void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkZ)
return;
}
Chunk->MarkDirty();
if (a_MarkRedstoneDirty)
{
Chunk->SetIsRedstoneDirty(true);
}
}
@ -1259,7 +1278,7 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP
void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients)
void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
{
cChunkInterface ChunkInterface(this);
if (a_BlockType == E_BLOCK_AIR)
@ -1284,7 +1303,7 @@ void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a
void cChunkMap::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType)
void cChunkMap::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType)
{
int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
@ -1530,7 +1549,7 @@ void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player)
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if (Chunk->IsValid())
if ((Chunk != NULL) && (Chunk->IsValid()))
{
Chunk->SendBlockTo(a_X, a_Y, a_Z, a_Player->GetClientHandle());
}

View File

@ -85,7 +85,7 @@ public:
void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
void BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL);
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8
void BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL);
void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL);
void BroadcastSpawnEntity(cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
@ -106,7 +106,8 @@ public:
/** Wakes up the simulators for the specified area of blocks */
void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ);
void MarkChunkDirty (int a_ChunkX, int a_ChunkZ);
void MarkRedstoneDirty (int a_ChunkX, int a_ChunkZ);
void MarkChunkDirty (int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDirty = false);
void MarkChunkSaving (int a_ChunkX, int a_ChunkZ);
void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
@ -153,9 +154,9 @@ public:
NIBBLETYPE GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ);
NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ);
NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ);
void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockMeta);
void SetBlock (cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true);
void QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR);
void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta);
void SetBlock (cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true);
void QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR);
bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);

View File

@ -40,9 +40,6 @@
/** Maximum number of block change interactions a player can perform per tick - exceeding this causes a kick */
#define MAX_BLOCK_CHANGE_INTERACTIONS 20
/** How many ticks before the socket is closed after the client is destroyed (#31) */
static const int TICKS_BEFORE_CLOSE = 20;
@ -79,7 +76,6 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
m_PingID(1),
m_BlockDigAnimStage(-1),
m_HasStartedDigging(false),
m_TicksSinceDestruction(0),
m_State(csConnected),
m_ShouldCheckDownloaded(false),
m_NumExplosionsThisTick(0),
@ -104,7 +100,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
cClientHandle::~cClientHandle()
{
ASSERT(m_State >= csDestroyedWaiting); // Has Destroy() been called?
ASSERT(m_State == csDestroyed); // Has Destroy() been called?
LOGD("Deleting client \"%s\" at %p", GetUsername().c_str(), this);
@ -169,7 +165,7 @@ void cClientHandle::Destroy(void)
RemoveFromAllChunks();
m_Player->GetWorld()->RemoveClientFromChunkSender(this);
}
m_State = csDestroyedWaiting;
m_State = csDestroyed;
}
@ -1366,7 +1362,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
NewBlock->OnPlacedByPlayer(ChunkInterface,*World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
// Step sound with 0.8f pitch is used as block placement sound
World->BroadcastSoundEffect(NewBlock->GetStepSound(), a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 0.8f);
World->BroadcastSoundEffect(NewBlock->GetStepSound(), (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.8f);
cRoot::Get()->GetPluginManager()->CallHookPlayerPlacedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
}
@ -1824,18 +1820,7 @@ bool cClientHandle::CheckBlockInteractionsRate(void)
void cClientHandle::Tick(float a_Dt)
{
// Handle clients that are waiting for final close while destroyed:
if (m_State == csDestroyedWaiting)
{
m_TicksSinceDestruction += 1; // This field is misused for the timeout counting
if (m_TicksSinceDestruction > TICKS_BEFORE_CLOSE)
{
m_State = csDestroyed;
}
return;
}
{
// Process received network data:
AString IncomingData;
{
@ -1901,15 +1886,7 @@ void cClientHandle::Tick(float a_Dt)
void cClientHandle::ServerTick(float a_Dt)
{
// Handle clients that are waiting for final close while destroyed:
if (m_State == csDestroyedWaiting)
{
// Do not wait while the client is not in the world, simply cut them off.
m_State = csDestroyed;
return;
}
{
// Process received network data:
AString IncomingData;
{
@ -2450,9 +2427,9 @@ void cClientHandle::SendDisplayObjective(const AString & a_Objective, cScoreboar
void cClientHandle::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
void cClientHandle::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
{
m_Protocol->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch);
m_Protocol->SendSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch);
}

View File

@ -162,7 +162,7 @@ public:
void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode);
void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode);
void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display);
void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch); // a_Src coords are Block * 8
void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch); // tolua_export
void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data);
void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock);
void SendSpawnMob (const cMonster & a_Mob);
@ -325,9 +325,6 @@ private:
int m_LastDigBlockX;
int m_LastDigBlockY;
int m_LastDigBlockZ;
/** Used while csDestroyedWaiting for counting the ticks until the connection is closed */
int m_TicksSinceDestruction;
enum eState
{
@ -338,7 +335,6 @@ private:
csConfirmingPos, ///< The client has been sent the position packet, waiting for them to repeat the position back
csPlaying, ///< Normal gameplay
csDestroying, ///< The client is being destroyed, don't queue any more packets / don't add to chunks
csDestroyedWaiting, ///< The client has been destroyed, but is still kept so that the Kick packet is delivered (#31)
csDestroyed, ///< The client has been destroyed, the destructor is to be called from the owner thread
// TODO: Add Kicking here as well

View File

@ -79,8 +79,8 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa
}
Vector3d Hit = a_HitPos;
Vector3d SinkMovement = (GetSpeed() / 800);
Hit += (SinkMovement * 0.01) / SinkMovement.Length(); // Make arrow sink into block a centimetre so it lodges (but not to far so it goes black clientside)
Vector3d SinkMovement = (GetSpeed() / 1000);
Hit += SinkMovement * (0.0005 / SinkMovement.Length()); // Make arrow sink into block a centimetre so it lodges (but not to far so it goes black clientside)
super::OnHitSolidBlock(Hit, a_HitFace);
Vector3i BlockHit = Hit.Floor();
@ -89,7 +89,7 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa
m_HitBlockPos = Vector3i(X, Y, Z);
// Broadcast arrow hit sound
m_World->BroadcastSoundEffect("random.bowhit", X * 8, Y * 8, Z * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_World->BroadcastSoundEffect("random.bowhit", (double)X, (double)Y, (double)Z, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
}
@ -106,7 +106,7 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
// Broadcast successful hit sound
GetWorld()->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
GetWorld()->BroadcastSoundEffect("random.successful_hit", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
Destroy();
}
@ -131,7 +131,7 @@ void cArrowEntity::CollectedBy(cPlayer * a_Dest)
}
GetWorld()->BroadcastCollectEntity(*this, *a_Dest);
GetWorld()->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
GetWorld()->BroadcastSoundEffect("random.pop", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_bIsCollected = true;
}
}

View File

@ -56,7 +56,7 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
LOGD("Player %s picked up an ExpOrb. His reward is %i", a_ClosestPlayer->GetName().c_str(), m_Reward);
a_ClosestPlayer->DeltaExperience(m_Reward);
m_World->BroadcastSoundEffect("random.orb", (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_World->BroadcastSoundEffect("random.orb", GetPosX(), GetPosY(), GetPosZ(), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
Destroy();
}

View File

@ -11,7 +11,7 @@
class cExpOrb :
public cEntity
{
typedef cExpOrb super;
typedef cEntity super;
public:
// tolua_end

View File

@ -134,7 +134,7 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
{
if (m_CountDownTime <= 0)
{
m_World->BroadcastSoundEffect("random.splash", (int) floor(GetPosX() * 8), (int) floor(GetPosY() * 8), (int) floor(GetPosZ() * 8), 1, 1);
m_World->BroadcastSoundEffect("random.splash", GetPosX(), GetPosY(), GetPosZ(), 1, 1);
SetPosY(GetPosY() - 1);
m_CanPickupItem = true;
m_PickupCountDown = 20;

View File

@ -226,7 +226,7 @@ bool cPickup::CollectedBy(cPlayer * a_Dest)
m_Item.m_ItemCount -= NumAdded;
m_World->BroadcastCollectEntity(*this, *a_Dest);
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
m_World->BroadcastSoundEffect("random.pop",(int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_World->BroadcastSoundEffect("random.pop", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
if (m_Item.m_ItemCount <= 0)
{
// All of the pickup has been collected, schedule the pickup for destroying

View File

@ -1917,7 +1917,7 @@ void cPlayer::UseEquippedItem(void)
if (GetInventory().DamageEquippedItem())
{
m_World->BroadcastSoundEffect("random.break", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_World->BroadcastSoundEffect("random.break", GetPosX(), GetPosY(), GetPosZ(), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
}
}

View File

@ -244,7 +244,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed)
cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed)
{
Vector3d Speed;
if (a_Speed != NULL)
@ -264,12 +264,13 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
case pkWitherSkull: return new cWitherSkullEntity (a_Creator, a_X, a_Y, a_Z, Speed);
case pkFirework:
{
if (a_Item.m_FireworkItem.m_Colours.empty())
ASSERT(a_Item != NULL);
if (a_Item->m_FireworkItem.m_Colours.empty())
{
return NULL;
}
return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, a_Item);
return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, *a_Item);
}
}

View File

@ -46,7 +46,7 @@ public:
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height);
static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed = NULL);
static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed = NULL);
/// Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace);

View File

@ -290,7 +290,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
LOGWARNING("%s: MaxRelX less than zero, adjusting to zero", __FUNCTION__);
a_MaxRelX = 0;
}
else if (a_MinRelX >= cChunkDef::Width)
else if (a_MaxRelX >= cChunkDef::Width)
{
LOGWARNING("%s: MaxRelX more than chunk width, adjusting to chunk width", __FUNCTION__);
a_MaxRelX = cChunkDef::Width - 1;
@ -311,7 +311,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
LOGWARNING("%s: MaxRelY less than zero, adjusting to zero", __FUNCTION__);
a_MaxRelY = 0;
}
else if (a_MinRelY >= cChunkDef::Height)
else if (a_MaxRelY >= cChunkDef::Height)
{
LOGWARNING("%s: MaxRelY more than chunk height, adjusting to chunk height", __FUNCTION__);
a_MaxRelY = cChunkDef::Height - 1;
@ -332,7 +332,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
LOGWARNING("%s: MaxRelZ less than zero, adjusting to zero", __FUNCTION__);
a_MaxRelZ = 0;
}
else if (a_MinRelZ >= cChunkDef::Width)
else if (a_MaxRelZ >= cChunkDef::Width)
{
LOGWARNING("%s: MaxRelZ more than chunk width, adjusting to chunk width", __FUNCTION__);
a_MaxRelZ = cChunkDef::Width - 1;

View File

@ -44,6 +44,7 @@ cGridStructGen::cGridStructGen(
int a_MaxStructureSizeX, int a_MaxStructureSizeZ,
size_t a_MaxCacheSize
) :
m_Seed(a_Seed),
m_Noise(a_Seed),
m_GridSizeX(a_GridSizeX),
m_GridSizeZ(a_GridSizeZ),
@ -53,6 +54,16 @@ cGridStructGen::cGridStructGen(
m_MaxStructureSizeZ(a_MaxStructureSizeZ),
m_MaxCacheSize(a_MaxCacheSize)
{
if (m_GridSizeX == 0)
{
LOG("Grid Size cannot be zero, setting to 1");
m_GridSizeX = 1;
}
if (m_GridSizeZ == 0)
{
LOG("Grid Size cannot be zero, setting to 1");
m_GridSizeZ = 1;
}
size_t NumStructuresPerQuery = (size_t)(((m_MaxStructureSizeX + m_MaxOffsetX) / m_GridSizeX + 1) * ((m_MaxStructureSizeZ + m_MaxOffsetZ) / m_GridSizeZ + 1));
if (NumStructuresPerQuery > m_MaxCacheSize)
{

View File

@ -70,7 +70,7 @@ public:
return;
}
a_Player->GetWorld()->BroadcastSoundEffect("random.bow", (int)a_Player->GetPosX() * 8, (int)a_Player->GetPosY() * 8, (int)a_Player->GetPosZ() * 8, 0.5, (float)Force);
a_Player->GetWorld()->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY(), a_Player->GetPosZ(), 0.5, (float)Force);
if (!a_Player->IsGameModeCreative())
{
a_Player->UseEquippedItem();

View File

@ -41,7 +41,7 @@ public:
bool ScoopUpFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
{
if (a_BlockFace > 0)
if (a_BlockFace != BLOCK_FACE_NONE)
{
return false;
}
@ -95,29 +95,15 @@ public:
bool PlaceFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock)
{
if (a_BlockFace < 0)
if (a_BlockFace != BLOCK_FACE_NONE)
{
return false;
}
BLOCKTYPE CurrentBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
bool CanWashAway = cFluidSimulator::CanWashAway(CurrentBlock);
if (!CanWashAway)
BLOCKTYPE CurrentBlock;
Vector3i BlockPos;
if (!GetPlacementCoordsFromTrace(a_World, a_Player, BlockPos, CurrentBlock))
{
// The block pointed at cannot be washed away, so put fluid on top of it / on its sides
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
CurrentBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
}
if (
!CanWashAway &&
(CurrentBlock != E_BLOCK_AIR) &&
(CurrentBlock != E_BLOCK_WATER) &&
(CurrentBlock != E_BLOCK_STATIONARY_WATER) &&
(CurrentBlock != E_BLOCK_LAVA) &&
(CurrentBlock != E_BLOCK_STATIONARY_LAVA)
)
{
// Cannot place water here
return false;
}
@ -138,7 +124,7 @@ public:
}
// Wash away anything that was there prior to placing:
if (CanWashAway)
if (cFluidSimulator::CanWashAway(CurrentBlock))
{
cBlockHandler * Handler = BlockHandler(CurrentBlock);
if (Handler->DoesDropOnUnsuitable())
@ -149,13 +135,13 @@ public:
}
}
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FluidBlock, 0);
a_World->SetBlock(BlockPos.x, BlockPos.y, BlockPos.z, a_FluidBlock, 0);
return true;
}
bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & BlockPos)
bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos)
{
class cCallbacks :
public cBlockTracer::cCallbacks
@ -198,8 +184,49 @@ public:
}
BlockPos.Set(Callbacks.m_Pos.x, Callbacks.m_Pos.y, Callbacks.m_Pos.z);
a_BlockPos = Callbacks.m_Pos;
return true;
}
bool GetPlacementCoordsFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos, BLOCKTYPE & a_BlockType)
{
class cCallbacks :
public cBlockTracer::cCallbacks
{
public:
Vector3i m_Pos;
BLOCKTYPE m_ReplacedBlock;
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
{
if (a_BlockType != E_BLOCK_AIR)
{
m_ReplacedBlock = a_BlockType;
if (!cFluidSimulator::CanWashAway(a_BlockType) && !IsBlockLiquid(a_BlockType))
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, (eBlockFace)a_EntryFace); // Was an unwashawayable block, can't overwrite it!
}
m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ); // (Block could be washed away, replace it)
return true; // Abort tracing
}
return false;
}
} Callbacks;
cLineBlockTracer Tracer(*a_World, Callbacks);
Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
// cTracer::Trace returns true when whole line was traversed. By returning true when we hit something, we ensure that this never happens if liquid could be placed
// Use this to judge whether the position is valid
if (!Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z))
{
a_BlockPos = Callbacks.m_Pos;
a_BlockType = Callbacks.m_ReplacedBlock;
return true;
}
return false;
}
};

View File

@ -52,8 +52,8 @@ public:
case E_BLOCK_TNT:
{
// Activate the TNT:
a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 1.0f);
a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0);
a_World->BroadcastSoundEffect("game.tnt.primed", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 1.0f);
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
break;
}
@ -68,7 +68,7 @@ public:
if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
{
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0);
a_World->BroadcastSoundEffect("fire.ignite", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0F, 1.04F);
a_World->BroadcastSoundEffect("fire.ignite", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0F, 1.04F);
break;
}
}

View File

@ -33,16 +33,9 @@ public:
// Play sound
cFastRandom Random;
a_World->BroadcastSoundEffect(
"random.bow",
(int)std::floor(a_Player->GetPosX() * 8.0),
(int)std::floor((a_Player->GetPosY() - a_Player->GetHeight()) * 8.0),
(int)std::floor(a_Player->GetPosZ() * 8.0),
0.5F,
0.4F / (Random.NextFloat(1.0F) * 0.4F + 0.8F)
);
a_World->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY() - a_Player->GetHeight(), a_Player->GetPosZ(), 0.5f, 0.4f / (Random.NextFloat(1.0f) * 0.4f + 0.8f));
if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed) < 0)
if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem(), &Speed) < 0)
{
return false;
}
@ -142,7 +135,7 @@ public:
return false;
}
if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem()) < 0)
if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) < 0)
{
return false;
}

View File

@ -200,8 +200,8 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
int BlockX = m_CenterX + ((a_X - (m_Width / 2)) * PixelWidth);
int BlockZ = m_CenterZ + ((a_Z - (m_Height / 2)) * PixelWidth);
int ChunkX, ChunkY, ChunkZ;
m_World->BlockToChunk(BlockX, 0, BlockZ, ChunkX, ChunkY, ChunkZ);
int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
int RelX = BlockX - (ChunkX * cChunkDef::Width);
int RelZ = BlockZ - (ChunkZ * cChunkDef::Width);

View File

@ -125,7 +125,7 @@ void cCreeper::Attack(float a_Dt)
if (!m_bIsBlowing)
{
m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_bIsBlowing = true;
m_World->BroadcastEntityMetadata(*this);
}
@ -143,7 +143,7 @@ void cCreeper::OnRightClicked(cPlayer & a_Player)
{
a_Player.UseEquippedItem();
}
m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_bIsBlowing = true;
m_World->BroadcastEntityMetadata(*this);
m_BurnedWithFlintAndSteel = true;

View File

@ -479,7 +479,7 @@ bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
if (!m_SoundHurt.empty() && (m_Health > 0))
{
m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
m_World->BroadcastSoundEffect(m_SoundHurt, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f);
}
if (a_TDI.Attacker != NULL)
@ -498,7 +498,7 @@ void cMonster::KilledBy(cEntity * a_Killer)
super::KilledBy(a_Killer);
if (m_SoundHurt != "")
{
m_World->BroadcastSoundEffect(m_SoundDeath, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
m_World->BroadcastSoundEffect(m_SoundDeath, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f);
}
int Reward;
switch (m_MobType)
@ -920,7 +920,7 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
case mtMooshroom: toReturn = new cMooshroom(); break;
case mtOcelot: toReturn = new cOcelot(); break;
case mtPig: toReturn = new cPig(); break;
case mtSheep: toReturn = new cSheep (Random.NextInt(15)); break; // Colour parameter
case mtSheep: toReturn = new cSheep(); break;
case mtSilverfish: toReturn = new cSilverfish(); break;
case mtSnowGolem: toReturn = new cSnowGolem(); break;
case mtSpider: toReturn = new cSpider(); break;

View File

@ -5,6 +5,7 @@
#include "../BlockID.h"
#include "../Entities/Player.h"
#include "../World.h"
#include "FastRandom.h"
@ -16,6 +17,16 @@ cSheep::cSheep(int a_Color) :
m_WoolColor(a_Color),
m_TimeToStopEating(-1)
{
// Generate random wool color.
if (m_WoolColor == -1)
{
m_WoolColor = GenerateNaturalRandomColor();
}
if ((m_WoolColor < 0) || (m_WoolColor > 15))
{
m_WoolColor = 0;
}
}
@ -37,7 +48,7 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSheep::OnRightClicked(cPlayer & a_Player)
{
const cItem & EquippedItem = a_Player.GetEquippedItem();
if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared))
if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && !IsSheared() && !IsBaby())
{
m_IsSheared = true;
m_World->BroadcastEntityMetadata(*this);
@ -51,6 +62,7 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
int NumDrops = m_World->GetTickRandomNumber(2) + 1;
Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor));
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
m_World->BroadcastSoundEffect("mob.sheep.shear", GetPosX(), GetPosY(), GetPosZ(), 1.0f, 1.0f);
}
else if ((EquippedItem.m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - EquippedItem.m_ItemDamage))
{
@ -109,3 +121,38 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
}
}
NIBBLETYPE cSheep::GenerateNaturalRandomColor(void)
{
cFastRandom Random;
int Chance = Random.NextInt(101);
if (Chance <= 81)
{
return E_META_WOOL_WHITE;
}
else if (Chance <= 86)
{
return E_META_WOOL_BLACK;
}
else if (Chance <= 91)
{
return E_META_WOOL_GRAY;
}
else if (Chance <= 96)
{
return E_META_WOOL_LIGHTGRAY;
}
else if (Chance <= 99)
{
return E_META_WOOL_BROWN;
}
else
{
return E_META_WOOL_PINK;
}
}

View File

@ -13,21 +13,32 @@ class cSheep :
typedef cPassiveMonster super;
public:
cSheep(int a_Color);
/** The number is the color of the sheep.
Use E_META_WOOL_* constants for the wool color.
If you type -1, the server will generate a random color
with the GenerateNaturalRandomColor() function. */
cSheep(int a_Color = -1);
CLASS_PROTODEF(cSheep);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); }
/** Generates a random color for the sheep like the vanilla server.
The percent's where used are from the wiki: http://minecraft.gamepedia.com/Sheep#Breeding */
static NIBBLETYPE GenerateNaturalRandomColor(void);
bool IsSheared(void) const { return m_IsSheared; }
void SetSheared(bool a_IsSheared) { m_IsSheared = a_IsSheared; }
int GetFurColor(void) const { return m_WoolColor; }
void SetFurColor(int a_WoolColor) { m_WoolColor = a_WoolColor; }
private:
bool m_IsSheared;
int m_WoolColor;
int m_TimeToStopEating;

View File

@ -262,7 +262,7 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
AString HexDump;
if (Response.compare(0, prefix.size(), prefix))
{
LOGINFO("User \"%s\" failed to auth, bad http status line received", a_UserName.c_str());
LOGINFO("User %s failed to auth, bad http status line received", a_UserName.c_str());
LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return false;
}
@ -271,7 +271,7 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
size_t idxHeadersEnd = Response.find("\r\n\r\n");
if (idxHeadersEnd == AString::npos)
{
LOGINFO("User \"%s\" failed to authenticate, bad http response header received", a_UserName.c_str());
LOGINFO("User %s failed to authenticate, bad http response header received", a_UserName.c_str());
LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return false;
}

View File

@ -106,7 +106,7 @@ public:
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) = 0;
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) = 0;
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) = 0;
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) = 0; // a_Src coords are Block * 8
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) = 0;
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) = 0;
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0;
virtual void SendSpawnMob (const cMonster & a_Mob) = 0;

View File

@ -899,7 +899,7 @@ void cProtocol125::SendScoreboardObjective(const AString & a_Name, const AString
void cProtocol125::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
void cProtocol125::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
{
// Not needed in this protocol version
}

View File

@ -78,7 +78,7 @@ public:
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
virtual void SendSpawnMob (const cMonster & a_Mob) override;

View File

@ -195,13 +195,6 @@ void cProtocol132::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a
WriteInt (a_Entity.GetUniqueID());
WriteInt (a_Player.GetUniqueID());
Flush();
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
SendSoundEffect(
"random.pop",
(int)(a_Entity.GetPosX() * 8), (int)(a_Entity.GetPosY() * 8), (int)(a_Entity.GetPosZ() * 8),
0.5, (float)(0.75 + ((float)((a_Entity.GetUniqueID() * 23) % 32)) / 64)
);
}
@ -285,14 +278,14 @@ void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player)
void cProtocol132::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
void cProtocol132::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
{
cCSLock Lock(m_CSPacket);
WriteByte (PACKET_SOUND_EFFECT);
WriteString (a_SoundName);
WriteInt (a_SrcX);
WriteInt (a_SrcY);
WriteInt (a_SrcZ);
WriteInt ((int)(a_X * 8.0));
WriteInt ((int)(a_Y * 8.0));
WriteInt ((int)(a_Z * 8.0));
WriteFloat (a_Volume);
WriteChar ((char)(a_Pitch * 63.0f));
Flush();

View File

@ -53,7 +53,7 @@ public:
virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
virtual void SendSpawnMob (const cMonster & a_Mob) override;
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;

View File

@ -1084,15 +1084,15 @@ void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard
void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8
void cProtocol172::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
{
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x29); // Sound Effect packet
Pkt.WriteString(a_SoundName);
Pkt.WriteInt(a_SrcX);
Pkt.WriteInt(a_SrcY);
Pkt.WriteInt(a_SrcZ);
Pkt.WriteInt((int)(a_X * 8.0));
Pkt.WriteInt((int)(a_Y * 8.0));
Pkt.WriteInt((int)(a_Z * 8.0));
Pkt.WriteFloat(a_Volume);
Pkt.WriteByte((Byte)(a_Pitch * 63));
}

View File

@ -105,7 +105,7 @@ public:
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
virtual void SendRespawn (const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks = false) override;
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;

View File

@ -616,10 +616,10 @@ void cProtocolRecognizer::SendDisplayObjective(const AString & a_Objective, cSco
void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
{
ASSERT(m_Protocol != NULL);
m_Protocol->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch);
m_Protocol->SendSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch);
}

View File

@ -113,7 +113,7 @@ public:
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override;
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override;
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override;
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
virtual void SendSpawnMob (const cMonster & a_Mob) override;

View File

@ -221,14 +221,12 @@ bool cServer::InitServer(cIniFile & a_SettingsIni)
bool HasAnyPorts = false;
AString Ports = a_SettingsIni.GetValueSet("Server", "Port", "25565");
m_ListenThreadIPv4.SetReuseAddr(true);
if (m_ListenThreadIPv4.Initialize(Ports))
{
HasAnyPorts = true;
}
Ports = a_SettingsIni.GetValueSet("Server", "PortsIPv6", "25565");
m_ListenThreadIPv6.SetReuseAddr(true);
if (m_ListenThreadIPv6.Initialize(Ports))
{
HasAnyPorts = true;

View File

@ -254,7 +254,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i
);
a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0);
a_NearChunk->BroadcastSoundEffect("random.fizz", BlockX * 8, a_RelY * 8, BlockZ * 8, 0.5f, 1.5f);
a_NearChunk->BroadcastSoundEffect("random.fizz", (double)BlockX, (double)a_RelY, (double)BlockZ, 0.5f, 1.5f);
return;
}
}
@ -269,7 +269,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i
);
a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0);
a_NearChunk->BroadcastSoundEffect("random.fizz", BlockX * 8, a_RelY * 8, BlockZ * 8, 0.5f, 1.5f);
a_NearChunk->BroadcastSoundEffect("random.fizz", (double)BlockX, (double)a_RelY, (double)BlockZ, 0.5f, 1.5f);
return;
}
}

View File

@ -5,6 +5,7 @@
#include "BoundingBox.h"
#include "../BlockEntities/DropSpenserEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../Entities/TNTEntity.h"
#include "../Entities/Pickup.h"
@ -15,8 +16,6 @@
#include "../Blocks/BlockPiston.h"
#include "../Blocks/BlockTripwireHook.h"
#define WAKE_SIMULATOR_IF_DIRTY(a_Chunk, a_BlockX, a_BlockY, a_BlockZ) if (a_Chunk->IsRedstoneDirty()) WakeUp(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
@ -63,14 +62,16 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
int RelZ = 0;
BLOCKTYPE Block;
NIBBLETYPE Meta;
cChunk * OtherChunk = a_Chunk;
if (a_OtherChunk != NULL)
{
RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width;
RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width;
a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
OtherChunk = a_OtherChunk;
// If a_OtherChunk is passed (not NULL), it is the chunk that had a block change, and a_Chunk will be the neighbouring chunk of that block
// Because said neighbouring chunk does not know of this change but still needs to update its redstone, we set it to dirty
a_Chunk->SetIsRedstoneDirty(true);
}
else
{
@ -95,8 +96,6 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = PoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
else if (
@ -105,34 +104,13 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
((Block == E_BLOCK_DETECTOR_RAIL) && ((Meta & 0x08) == 0)) ||
(((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ||
(((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0)) ||
(((Block == E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE) || (Block == E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE)) && (Meta == 0)) ||
((Block == E_BLOCK_TRIPWIRE_HOOK) && ((Meta & 0x08) == 0))
)
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = PoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
else if (Block == E_BLOCK_DAYLIGHT_SENSOR)
{
if (!m_World.IsChunkLighted(OtherChunk->GetPosX(), OtherChunk->GetPosZ()))
{
m_World.QueueLightChunk(OtherChunk->GetPosX(), OtherChunk->GetPosZ());
}
else
{
if (OtherChunk->GetTimeAlteredLight(OtherChunk->GetSkyLight(RelX, a_BlockY + 1, RelZ)) <= 7)
{
itr = PoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
}
}
++itr;
}
@ -146,23 +124,17 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = LinkedPoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
else if (
// Things that can send power through a block but which depends on meta
((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
(((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ||
(((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0)) ||
(((Block == E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE) || (Block == E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE)) && (Meta == 0))
(((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta)))
)
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = LinkedPoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
}
@ -172,8 +144,6 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer powered through a valid middle block", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = LinkedPoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
}
@ -320,6 +290,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int
case E_BLOCK_FENCE_GATE: HandleFenceGate(dataitr->x, dataitr->y, dataitr->z); break;
case E_BLOCK_TNT: HandleTNT(dataitr->x, dataitr->y, dataitr->z); break;
case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break;
case E_BLOCK_TRAPPED_CHEST: HandleTrappedChest(dataitr->x, dataitr->y, dataitr->z); break;
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_DETECTOR_RAIL:
@ -382,18 +353,13 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int
void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
{
if (
((a_BlockX % cChunkDef::Width) <= 1) ||
((a_BlockX % cChunkDef::Width) >= 14) ||
((a_BlockZ % cChunkDef::Width) <= 1) ||
((a_BlockZ % cChunkDef::Width) >= 14)
) // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks
if (AreCoordsOnChunkBoundary(a_BlockX, a_BlockY, a_BlockZ))
{
// On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk)
AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
// Pass the original coordinates, because when adding things to our simulator lists, we get the chunk that they are in, and therefore any updates need to preseve their position
// RedstoneAddBlock to pass both the neighbouring chunk and the chunk which the coordiantes are in and +- 2 in GetNeighbour() to accomodate for LinkedPowered blocks being 2 away from chunk boundaries
// RedstoneAddBlock to pass both the neighbouring chunk and the chunk which the coordinates are in and +- 2 in GetNeighbour() to accomodate for LinkedPowered blocks being 2 away from chunk boundaries
RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 2, a_BlockZ), a_Chunk);
RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 2, a_BlockZ), a_Chunk);
RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 2), a_Chunk);
@ -430,7 +396,13 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R
int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ;
AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on
if (AreCoordsDirectlyPowered(X, Y, Z))
cChunk * Neighbour = m_Chunk->GetRelNeighborChunk(X, Z);
if ((Neighbour == NULL) || !Neighbour->IsValid())
{
return;
}
if (AreCoordsDirectlyPowered(X, Y, Z, Neighbour))
{
// There was a match, torch goes off
m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
@ -448,7 +420,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R
if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last)
{
if (
((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc.
IsMechanism(Type) && // Is it a mechanism? Not block/other torch etc.
(!Vector3i(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on
)
{
@ -468,7 +440,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R
{
BLOCKTYPE Type = m_Chunk->GetBlock(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ);
if ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) // Still can't make a normal block powered though!
if (IsMechanism(Type)) // Still can't make a normal block powered though!
{
SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
}
@ -479,9 +451,15 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R
// Check if the block the torch is on is powered
int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ;
AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on
cChunk * Neighbour = m_Chunk->GetRelNeighborChunk(X, Z);
if ((Neighbour == NULL) || !Neighbour->IsValid())
{
return;
}
// See if off state torch can be turned on again
if (AreCoordsDirectlyPowered(X, Y, Z))
if (AreCoordsDirectlyPowered(X, Y, Z, Neighbour))
{
return; // Something matches, torch still powered
}
@ -780,17 +758,20 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
{
for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end();)
{
if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks?
{
int RelBlockX = itr->a_RelBlockPos.x;
int RelBlockY = itr->a_RelBlockPos.y;
int RelBlockZ = itr->a_RelBlockPos.z;
NIBBLETYPE Meta = m_Chunk->GetMeta(RelBlockX, RelBlockY, RelBlockZ);
BLOCKTYPE Block;
NIBBLETYPE Meta;
m_Chunk->GetBlockTypeMeta(RelBlockX, RelBlockY, RelBlockZ, Block, Meta);
if (itr->ShouldPowerOn)
{
m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta); // For performance
if (Block != E_BLOCK_REDSTONE_REPEATER_ON) // For performance
{
m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta);
}
switch (Meta & 0x3) // We only want the direction (bottom) bits
{
@ -820,17 +801,14 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
}
}
}
else
else if (Block != E_BLOCK_REDSTONE_REPEATER_OFF)
{
m_Chunk->SetBlock(RelBlockX, RelBlockY, RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, Meta);
m_Chunk->SetBlock(RelBlockX, RelBlockY, RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, Meta);
}
itr = m_RepeatersDelayList->erase(itr);
}
else
{
// Apparently, incrementing ticks only works reliably here, and not in SimChunk;
// With a world with lots of redstone, the repeaters simply do not delay
// I am confounded to say why. Perhaps optimisation failure.
LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
itr->a_ElapsedTicks++;
itr++;
@ -915,7 +893,7 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_RelBlockX, int a_RelBlockY,
if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
{
m_Chunk->BroadcastSoundEffect("game.tnt.primed", BlockX * 8, a_RelBlockY * 8, BlockZ * 8, 0.5f, 0.6f);
m_Chunk->BroadcastSoundEffect("game.tnt.primed", (double)BlockX, (double)a_RelBlockY, (double)BlockZ, 0.5f, 0.6f);
m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_AIR, 0);
m_World.SpawnPrimedTNT(BlockX + 0.5, a_RelBlockY + 0.5, BlockZ + 0.5); // 80 ticks to boom
}
@ -1139,7 +1117,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
else
{
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ);
SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
}
break;
}
@ -1193,7 +1171,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
{
if (Meta == E_META_PRESSURE_PLATE_RAISED)
{
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.5F);
}
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power);
@ -1203,10 +1181,10 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
{
if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
{
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.6F);
}
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ);
SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
}
break;
@ -1261,7 +1239,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
{
if (Meta == E_META_PRESSURE_PLATE_RAISED)
{
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.5F);
}
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power);
@ -1271,10 +1249,10 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
{
if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
{
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.6F);
}
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ);
SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
}
break;
@ -1328,7 +1306,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
{
if (Meta == E_META_PRESSURE_PLATE_RAISED)
{
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.5F);
}
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
@ -1338,10 +1316,10 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
{
if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
{
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.6F);
}
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ);
SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
}
break;
}
@ -1384,14 +1362,14 @@ void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_Re
{
if (ReverseBlockFace(cBlockTripwireHookHandler::MetadataToDirection(Meta)) == FaceToGoTowards)
{
// Other hook not facing in opposite direction
// Other hook facing in opposite direction - circuit completed!
break;
}
else
{
// Tripwire hook not connected at all, AND away all the power state bits
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ);
SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
return;
}
}
@ -1399,7 +1377,7 @@ void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_Re
{
// Tripwire hook not connected at all, AND away all the power state bits
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ);
SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
return;
}
}
@ -1414,7 +1392,51 @@ void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_Re
{
// Connected but not activated, AND away the highest bit
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7) | 0x4);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ);
SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
}
}
void cIncrementalRedstoneSimulator::HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
class cGetTrappedChestPlayers :
public cChestCallback
{
public:
cGetTrappedChestPlayers(void) :
m_NumberOfPlayers(0)
{
}
virtual bool Item(cChestEntity * a_Chest) override
{
ASSERT(a_Chest->GetBlockType() == E_BLOCK_TRAPPED_CHEST);
m_NumberOfPlayers = a_Chest->GetNumberOfPlayers();
return (m_NumberOfPlayers <= 0);
}
unsigned char GetPowerLevel(void) const
{
return std::min(m_NumberOfPlayers, MAX_POWER_LEVEL);
}
private:
int m_NumberOfPlayers;
} GTCP;
int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX;
int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ;
if (m_Chunk->DoWithChestAt(BlockX, a_RelBlockY, BlockZ, GTCP))
{
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, GTCP.GetPowerLevel());
}
else
{
SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
}
}
@ -1482,13 +1504,14 @@ void cIncrementalRedstoneSimulator::HandleTripwire(int a_RelBlockX, int a_RelBlo
bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk)
{
// Torches want to access neighbour's data when on a wall, hence the extra chunk parameter
int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); // Torches want to access neighbour's data when on a wall
for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
for (PoweredBlocksList::const_iterator itr = a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->begin(); itr != a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->end(); ++itr) // Check powered list
{
if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)))
{
@ -1691,8 +1714,8 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBl
bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel)
{
a_PowerLevel = 0;
int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX;
int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ;
for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list
{
@ -1709,6 +1732,14 @@ bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBloc
{
continue;
}
BLOCKTYPE Type = E_BLOCK_AIR;
int RelSourceX = itr->a_SourcePos.x - m_Chunk->GetPosX() * cChunkDef::Width;
int RelSourceZ = itr->a_SourcePos.z - m_Chunk->GetPosZ() * cChunkDef::Width;
if (!m_Chunk->UnboundedRelGetBlockType(RelSourceX, itr->a_SourcePos.y, RelSourceZ, Type) || (Type == E_BLOCK_REDSTONE_WIRE))
{
continue;
}
a_PowerLevel = std::max(itr->a_PowerLevel, a_PowerLevel);
}
@ -1881,20 +1912,14 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBl
int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ;
BLOCKTYPE Block = 0;
if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block))
cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ); // Adjust coordinates for the later call using these values
if ((Neighbour == NULL) || !Neighbour->IsValid())
{
return;
}
if (Block == E_BLOCK_AIR)
{
// Don't set air, fixes some bugs (wires powering themselves)
return;
}
cChunk * Neighbour = m_Chunk->GetNeighborChunk(BlockX, BlockZ);
PoweredBlocksList * Powered = Neighbour->GetRedstoneSimulatorPoweredBlocksList();
for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
PoweredBlocksList * Powered = Neighbour->GetRedstoneSimulatorPoweredBlocksList(); // We need to insert the value into the chunk who owns the block position
for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr)
{
if (
itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) &&
@ -1907,16 +1932,33 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBl
}
}
PoweredBlocksList * OtherPowered = m_Chunk->GetNeighborChunk(SourceX, SourceZ)->GetRedstoneSimulatorPoweredBlocksList();
for (PoweredBlocksList::const_iterator itr = OtherPowered->begin(); itr != OtherPowered->end(); ++itr) // Check powered list
// No need to get neighbouring chunk as we can guarantee that when something is powering us, the entry will be in our chunk
// TODO: on C++11 support, change this to a llama function pased to a std::remove_if
for (PoweredBlocksList::iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr)
{
if (
itr->a_BlockPos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) &&
itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))
itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) &&
(m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE)
)
{
// Powered wires try to power their source - don't let them!
return;
BLOCKTYPE Block;
NIBBLETYPE Meta;
Neighbour->GetBlockTypeMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block, Meta);
if (Block == E_BLOCK_REDSTONE_WIRE)
{
if (Meta < a_PowerLevel)
{
m_PoweredBlocks->erase(itr); // Powering source with higher power level, allow it
break;
}
else
{
// Powered wires try to power their source - don't let them!
return;
}
}
}
}
@ -1947,26 +1989,17 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ;
BLOCKTYPE DestBlock = 0;
if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, DestBlock))
{
return;
}
if (DestBlock == E_BLOCK_AIR)
{
// Don't set air, fixes some bugs (wires powering themselves)
return;
}
if ((DestBlock == E_BLOCK_REDSTONE_WIRE) && (m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE))
{
return;
}
if (!IsViableMiddleBlock(a_MiddleBlock))
{
return;
}
cChunk * Neighbour = m_Chunk->GetNeighborChunk(BlockX, BlockZ);
if ((Neighbour == NULL) || !Neighbour->IsValid())
{
return;
}
LinkedBlocksList * Linked = Neighbour->GetRedstoneSimulatorLinkedBlocksList();
for (LinkedBlocksList::iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list
{
@ -2066,6 +2099,45 @@ bool cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, in
void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_SourceX, int a_SourceY, int a_SourceZ, cChunk * a_Chunk, bool a_IsFirstCall)
{
// TODO: on C++11 support, change both of these to llama functions pased to a std::remove_if
for (PoweredBlocksList::iterator itr = a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->begin(); itr != a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->end();)
{
if (itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)))
{
itr = a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
continue;
}
++itr;
}
for (LinkedBlocksList::iterator itr = a_Chunk->GetRedstoneSimulatorLinkedBlocksList()->begin(); itr != a_Chunk->GetRedstoneSimulatorLinkedBlocksList()->end();)
{
if (itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)))
{
itr = a_Chunk->GetRedstoneSimulatorLinkedBlocksList()->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
continue;
}
++itr;
}
if (a_IsFirstCall && AreCoordsOnChunkBoundary(a_SourceX, a_SourceY, a_SourceZ))
{
// +- 2 to accomodate linked powered blocks
SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX - 2, a_SourceZ), false);
SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX + 2, a_SourceZ), false);
SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX, a_SourceZ - 2), false);
SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX, a_SourceZ + 2), false);
}
}
cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
int Dir = REDSTONE_NONE;

View File

@ -107,6 +107,8 @@ private:
If this line is complete, it verifies that at least on wire reports an entity is on top (via its meta), and performs its task
*/
void HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles trapped chests */
void HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/* ==================== */
/* ====== CARRIERS ====== */
@ -114,8 +116,6 @@ private:
void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles repeaters */
void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
/** Handles delayed updates to Repeaters **/
void HandleRedstoneRepeaterDelays();
/* ====================== */
/* ====== DEVICES ====== */
@ -156,11 +156,15 @@ private:
void SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
/** Queues a repeater to be powered or unpowered and returns if the m_RepeatersDelayList iterators were invalidated */
bool QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn);
/** Removes a block from the Powered and LinkedPowered lists
Used for variable sources such as tripwire hooks, daylight sensors, and trapped chests
*/
void SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk, bool a_IsFirstCall = true);
/** Returns if a coordinate is powered or linked powered */
bool AreCoordsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { return AreCoordsDirectlyPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }
bool AreCoordsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { return AreCoordsDirectlyPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }
/** Returns if a coordinate is in the directly powered blocks list */
bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk);
/** Returns if a coordinate is in the indirectly powered blocks list */
bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */
@ -174,7 +178,8 @@ private:
/** Returns if a wire is powered
The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire */
bool IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel);
/** Handles delayed updates to repeaters **/
void HandleRedstoneRepeaterDelays(void);
/** Returns if lever metadata marks it as emitting power */
bool IsLeverOn(NIBBLETYPE a_BlockMeta);
@ -186,7 +191,9 @@ private:
/** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */
inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return cBlockInfo::FullyOccupiesVoxel(Block); }
/** Returns if a block is a mechanism (something that accepts power and does something) */
/** Returns if a block is a mechanism (something that accepts power and does something)
Used by torches to determine if they power a block whilst not standing on the ground
*/
inline static bool IsMechanism(BLOCKTYPE Block)
{
switch (Block)
@ -209,6 +216,7 @@ private:
case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON:
case E_BLOCK_POWERED_RAIL:
case E_BLOCK_REDSTONE_WIRE:
{
return true;
}
@ -235,6 +243,7 @@ private:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_WOODEN_PRESSURE_PLATE:
case E_BLOCK_TRAPPED_CHEST:
{
return true;
}
@ -277,6 +286,7 @@ private:
case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_TNT:
case E_BLOCK_TRAPDOOR:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_TRIPWIRE_HOOK:
case E_BLOCK_TRIPWIRE:
case E_BLOCK_WOODEN_BUTTON:
@ -289,6 +299,16 @@ private:
default: return false;
}
}
inline static bool AreCoordsOnChunkBoundary(int a_BlockX, int a_BlockY, int a_BlockZ)
{
return ( // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks
((a_BlockX % cChunkDef::Width) <= 1) ||
((a_BlockX % cChunkDef::Width) >= 14) ||
((a_BlockZ % cChunkDef::Width) <= 1) ||
((a_BlockZ % cChunkDef::Width) >= 14)
);
}
};

View File

@ -35,7 +35,7 @@ void cVaporizeFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ,
)
{
a_Chunk->SetBlock(RelX, a_BlockY, RelZ, E_BLOCK_AIR, 0);
a_Chunk->BroadcastSoundEffect("random.fizz", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 0.6f);
a_Chunk->BroadcastSoundEffect("random.fizz", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.6f);
}
}

View File

@ -905,21 +905,23 @@ void cEnchantingWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
// cChestWindow:
cChestWindow::cChestWindow(cChestEntity * a_Chest) :
cWindow(wtChest, "Chest"),
cWindow(wtChest, (a_Chest->GetBlockType() == E_BLOCK_CHEST) ? "Chest" : "Trapped Chest"),
m_World(a_Chest->GetWorld()),
m_BlockX(a_Chest->GetPosX()),
m_BlockY(a_Chest->GetPosY()),
m_BlockZ(a_Chest->GetPosZ())
m_BlockZ(a_Chest->GetPosZ()),
m_PrimaryChest(a_Chest),
m_SecondaryChest(NULL)
{
m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this));
m_SlotAreas.push_back(new cSlotAreaInventory(*this));
m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
// Play the opening sound:
m_World->BroadcastSoundEffect("random.chestopen", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
// Send out the chest-open packet:
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_CHEST);
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_Chest->GetBlockType());
}
@ -927,11 +929,13 @@ cChestWindow::cChestWindow(cChestEntity * a_Chest) :
cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest) :
cWindow(wtChest, "Double Chest"),
cWindow(wtChest, (a_PrimaryChest->GetBlockType() == E_BLOCK_CHEST) ? "Double Chest" : "Double Trapped Chest"),
m_World(a_PrimaryChest->GetWorld()),
m_BlockX(a_PrimaryChest->GetPosX()),
m_BlockY(a_PrimaryChest->GetPosY()),
m_BlockZ(a_PrimaryChest->GetPosZ())
m_BlockZ(a_PrimaryChest->GetPosZ()),
m_PrimaryChest(a_PrimaryChest),
m_SecondaryChest(a_SecondaryChest)
{
m_SlotAreas.push_back(new cSlotAreaDoubleChest(a_PrimaryChest, a_SecondaryChest, *this));
m_SlotAreas.push_back(new cSlotAreaInventory(*this));
@ -940,10 +944,55 @@ cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_Secon
m_ShouldDistributeToHotbarFirst = false;
// Play the opening sound:
m_World->BroadcastSoundEffect("random.chestopen", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
// Send out the chest-open packet:
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_CHEST);
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_PrimaryChest->GetBlockType());
}
void cChestWindow::OpenedByPlayer(cPlayer & a_Player)
{
int ChunkX, ChunkZ;
m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() + 1);
cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
if (m_SecondaryChest != NULL)
{
m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1);
cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
}
cWindow::OpenedByPlayer(a_Player);
}
bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
{
int ChunkX, ChunkZ;
m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() - 1);
cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
if (m_SecondaryChest != NULL)
{
m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1);
cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
}
cWindow::ClosedByPlayer(a_Player, a_CanRefuse);
return true;
}
@ -953,9 +1002,9 @@ cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_Secon
cChestWindow::~cChestWindow()
{
// Send out the chest-close packet:
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_CHEST);
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, m_PrimaryChest->GetBlockType());
m_World->BroadcastSoundEffect("random.chestclosed", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
}
@ -966,7 +1015,7 @@ cChestWindow::~cChestWindow()
// cDropSpenserWindow:
cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) :
cWindow(wtDropSpenser, "Dropspenser")
cWindow(wtDropSpenser, (a_DropSpenser->GetBlockType() == E_BLOCK_DISPENSER) ? "Dispenser" : "Dropper")
{
m_ShouldDistributeToHotbarFirst = false;
m_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this));
@ -993,7 +1042,7 @@ cEnderChestWindow::cEnderChestWindow(cEnderChestEntity * a_EnderChest) :
m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
// Play the opening sound:
m_World->BroadcastSoundEffect("random.chestopen", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
// Send out the chest-open packet:
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_ENDER_CHEST);
@ -1009,7 +1058,7 @@ cEnderChestWindow::~cEnderChestWindow()
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_ENDER_CHEST);
// Play the closing sound
m_World->BroadcastSoundEffect("random.chestclosed", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
}

View File

@ -114,7 +114,7 @@ public:
const cItem & a_ClickedItem
);
void OpenedByPlayer(cPlayer & a_Player);
virtual void OpenedByPlayer(cPlayer & a_Player);
/// Called when a player closes this window; notifies all slot areas. Returns true if close accepted
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse);
@ -327,10 +327,15 @@ public:
cChestWindow(cChestEntity * a_Chest);
cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest);
~cChestWindow();
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
virtual void OpenedByPlayer(cPlayer & a_Player) override;
protected:
cWorld * m_World;
int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet
cChestEntity * m_PrimaryChest;
cChestEntity * m_SecondaryChest;
} ;

View File

@ -389,8 +389,8 @@ void cWorld::InitializeSpawn(void)
IniFile.WriteFile(m_IniFileName);
}
int ChunkX = 0, ChunkY = 0, ChunkZ = 0;
BlockToChunk((int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ);
int ChunkX = 0, ChunkZ = 0;
cChunkDef::BlockToChunk((int)m_SpawnX, (int)m_SpawnZ, ChunkX, ChunkZ);
// For the debugging builds, don't make the server build too much world upon start:
#if defined(_DEBUG) || defined(ANDROID_NDK)
@ -1088,7 +1088,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
cVector3iArray BlocksAffected;
m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected);
BroadcastSoundEffect("random.explode", (int)floor(a_BlockX * 8), (int)floor(a_BlockY * 8), (int)floor(a_BlockZ * 8), 1.0f, 0.6f);
BroadcastSoundEffect("random.explode", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.6f);
{
cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
@ -2074,9 +2074,9 @@ void cWorld::BroadcastDisplayObjective(const AString & a_Objective, cScoreboard:
void cWorld::BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
void cWorld::BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
{
m_ChunkMap->BroadcastSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch, a_Exclude);
m_ChunkMap->BroadcastSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch, a_Exclude);
}
@ -2182,9 +2182,18 @@ void cWorld::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHa
void cWorld::MarkChunkDirty (int a_ChunkX, int a_ChunkZ)
void cWorld::MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ)
{
m_ChunkMap->MarkChunkDirty (a_ChunkX, a_ChunkZ);
m_ChunkMap->MarkRedstoneDirty(a_ChunkX, a_ChunkZ);
}
void cWorld::MarkChunkDirty(int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDirty)
{
m_ChunkMap->MarkChunkDirty(a_ChunkX, a_ChunkZ, a_MarkRedstoneDirty);
}
@ -2989,7 +2998,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem & a_Item, const Vector3d * a_Speed)
int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed)
{
cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed);
if (Projectile == NULL)

View File

@ -224,7 +224,7 @@ public:
void BroadcastScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode);
void BroadcastScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode);
void BroadcastDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display);
void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8
void BroadcastSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export
void BroadcastSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); // tolua_export
void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
@ -241,7 +241,8 @@ public:
/** If there is a block entity at the specified coords, sends it to the client specified */
void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client);
void MarkChunkDirty (int a_ChunkX, int a_ChunkZ);
void MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ);
void MarkChunkDirty (int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDirty = false);
void MarkChunkSaving(int a_ChunkX, int a_ChunkZ);
void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
@ -634,18 +635,6 @@ public:
// tolua_end
inline static void BlockToChunk( int a_X, int a_Y, int a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
{
// TODO: Use floor() instead of weird if statements
// Also fix Y
(void)a_Y; // not unused anymore
a_ChunkX = a_X/cChunkDef::Width;
if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--;
a_ChunkY = 0;
a_ChunkZ = a_Z/cChunkDef::Width;
if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
}
/** Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead */
void SaveAllChunks(void);
@ -762,7 +751,7 @@ public:
/** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise
Item parameter used currently for Fireworks to correctly set entity metadata based on item metadata
*/
int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem & a_Item, const Vector3d * a_Speed = NULL); // tolua_export
int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed = NULL); // tolua_export
/** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */
int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }

View File

@ -176,10 +176,10 @@ void cNBTChunkSerializer::AddBasicTileEntity(cBlockEntity * a_Entity, const char
void cNBTChunkSerializer::AddChestEntity(cChestEntity * a_Entity)
void cNBTChunkSerializer::AddChestEntity(cChestEntity * a_Entity, BLOCKTYPE a_ChestType)
{
m_Writer.BeginCompound("");
AddBasicTileEntity(a_Entity, "Chest");
AddBasicTileEntity(a_Entity, (a_ChestType == E_BLOCK_CHEST) ? "Chest" : "TrappedChest");
m_Writer.BeginList("Items", TAG_Compound);
AddItemGrid(a_Entity->GetContents());
m_Writer.EndList();
@ -824,19 +824,21 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
// Add tile-entity into NBT:
switch (a_Entity->GetBlockType())
{
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break;
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break;
case E_BLOCK_ENDER_CHEST: /* No need to be saved */ break;
case E_BLOCK_FLOWER_POT: AddFlowerPotEntity ((cFlowerPotEntity *) a_Entity); break;
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
case E_BLOCK_SIGN_POST:
case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break;
case E_BLOCK_HEAD: AddMobHeadEntity ((cMobHeadEntity *) a_Entity); break;
case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break;
case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break;
case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *) a_Entity); break;
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity, a_Entity->GetBlockType()); break;
case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *)a_Entity); break;
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break;
case E_BLOCK_ENDER_CHEST: /* No data to be saved */ break;
case E_BLOCK_FLOWER_POT: AddFlowerPotEntity ((cFlowerPotEntity *) a_Entity); break;
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_HEAD: AddMobHeadEntity ((cMobHeadEntity *) a_Entity); break;
case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break;
case E_BLOCK_LIT_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break;
case E_BLOCK_SIGN_POST: AddSignEntity ((cSignEntity *) a_Entity); break;
case E_BLOCK_TRAPPED_CHEST: AddChestEntity ((cChestEntity *) a_Entity, a_Entity->GetBlockType()); break;
case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break;
default:
{

View File

@ -93,7 +93,7 @@ protected:
// Block entities:
void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID);
void AddChestEntity (cChestEntity * a_Entity);
void AddChestEntity (cChestEntity * a_Entity, BLOCKTYPE a_ChestType);
void AddDispenserEntity(cDispenserEntity * a_Entity);
void AddDropperEntity (cDropperEntity * a_Entity);
void AddFurnaceEntity (cFurnaceEntity * a_Furnace);

View File

@ -583,7 +583,7 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
}
if (strncmp(a_NBT.GetData(sID), "Chest", a_NBT.GetDataLength(sID)) == 0)
{
LoadChestFromNBT(a_BlockEntities, a_NBT, Child);
LoadChestFromNBT(a_BlockEntities, a_NBT, Child, E_BLOCK_CHEST);
}
else if (strncmp(a_NBT.GetData(sID), "Control", a_NBT.GetDataLength(sID)) == 0)
{
@ -625,6 +625,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
{
LoadDispenserFromNBT(a_BlockEntities, a_NBT, Child);
}
else if (strncmp(a_NBT.GetData(sID), "TrappedChest", a_NBT.GetDataLength(sID)) == 0)
{
LoadChestFromNBT(a_BlockEntities, a_NBT, Child, E_BLOCK_TRAPPED_CHEST);
}
// TODO: Other block entities
} // for Child - tag children
}
@ -741,7 +745,7 @@ void cWSSAnvil::LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a
void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_ChestType)
{
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
int x, y, z;
@ -754,7 +758,7 @@ void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cPars
{
return; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this
}
std::auto_ptr<cChestEntity> Chest(new cChestEntity(x, y, z, m_World));
std::auto_ptr<cChestEntity> Chest(new cChestEntity(x, y, z, m_World, a_ChestType));
LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items);
a_BlockEntities.push_back(Chest.release());
}
@ -2110,10 +2114,11 @@ void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB
void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
int ColorIdx = a_NBT.FindChildByName(a_TagIdx, "Color");
if (ColorIdx < 0) { return; }
int Color = (int)a_NBT.GetByte(ColorIdx);
int Color = -1;
if (ColorIdx > 0)
{
Color = (int)a_NBT.GetByte(ColorIdx);
}
std::auto_ptr<cSheep> Monster(new cSheep(Color));
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
@ -2126,6 +2131,12 @@ void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
return;
}
int ShearedIdx = a_NBT.FindChildByName(a_TagIdx, "Sheared");
if (ShearedIdx > 0)
{
Monster->SetSheared(a_NBT.GetByte(ShearedIdx) != 0);
}
a_Entities.push_back(Monster.release());
}

View File

@ -133,7 +133,7 @@ protected:
*/
void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0);
void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_ChestType);
void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFlowerPotFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);

View File

@ -273,7 +273,7 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
{
for (Json::Value::iterator itr = AllChests.begin(); itr != AllChests.end(); ++itr )
{
std::auto_ptr<cChestEntity> ChestEntity(new cChestEntity(0, 0, 0, a_World));
std::auto_ptr<cChestEntity> ChestEntity(new cChestEntity(0, 0, 0, a_World, E_BLOCK_CHEST));
if (!ChestEntity->LoadFromJson(*itr))
{
LOGWARNING("ERROR READING CHEST FROM JSON!" );