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); Plugin:SetVersion(1);
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_USED_ITEM, OnPlayerUsedItem); cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_USED_ITEM, OnPlayerUsedItem);
LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion());
return true; return true;
end end
@ -36,8 +38,8 @@ function OnPlayerUsedItem(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, Cu
return false; return false;
end; end;
if (Player:HasPermission("diamondmover.move") == false) then if (not Player:HasPermission("diamondmover.move")) then
return true; return false;
end; end;
-- Rclk with a diamond to push in the direction the player is facing -- 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 if (PlayerPitch > 70) then -- looking down
BlockY = BlockY - 1; BlockY = BlockY - 1;
else 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 if ((PlayerRot < 45) or (PlayerRot > 315)) then
BlockZ = BlockZ - 1; BlockZ = BlockZ - 1;
else 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: -- The list of valid arguments that the ToLua scripts can process:
local KnownArgs = { local KnownArgs = {
['v'] = true, ['v'] = true,
['h'] = true, ['h'] = true,
['p'] = true, ['p'] = true,
['P'] = true, ['P'] = true,
['o'] = true, ['o'] = true,
['n'] = true, ['n'] = true,
['H'] = true, ['H'] = true,
['S'] = true, ['S'] = true,
['1'] = true, ['1'] = true,
['L'] = true, ['L'] = true,
['D'] = true, ['D'] = true,
['W'] = true, ['W'] = true,
['C'] = true, ['C'] = true,
['E'] = true, ['E'] = true,
['t'] = true, ['t'] = true,
['q'] = true, ['q'] = true,
} }

View File

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

View File

@ -28,24 +28,26 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
switch (a_BlockType) switch (a_BlockType)
{ {
case E_BLOCK_BEACON: return new cBeaconEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); 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_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_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_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_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_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_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_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_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_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_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)", LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)",
__FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str() __FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str()
); );
ASSERT(!"Requesting creation of an unknown block entity");
return NULL; return NULL;
} }

View File

@ -11,8 +11,9 @@
cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type) :
super(E_BLOCK_CHEST, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World) super(a_Type, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
m_NumActivePlayers(0)
{ {
cBlockEntityWindowOwner::SetBlockEntity(this); cBlockEntityWindowOwner::SetBlockEntity(this);
} }
@ -113,7 +114,7 @@ void cChestEntity::UsedBy(cPlayer * a_Player)
// The few false positives aren't much to worry about // The few false positives aren't much to worry about
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(m_PosX, m_PosZ, 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 // tolua_end
/// Constructor used for normal operation /** Constructor used for normal operation */
cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type);
virtual ~cChestEntity(); virtual ~cChestEntity();
@ -48,8 +48,20 @@ public:
virtual void SendTo(cClientHandle & a_Client) override; virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) 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); 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 } ; // tolua_export

View File

@ -53,7 +53,7 @@ public:
cItem GetItem(void) const { return m_Item; } cItem GetItem(void) const { return m_Item; }
/** Set the item in the flower pot */ /** 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 // tolua_end

View File

@ -157,6 +157,7 @@ bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
bool res = false; bool res = false;
switch (a_Chunk.GetBlock(m_RelX, m_PosY + 1, m_RelZ)) switch (a_Chunk.GetBlock(m_RelX, m_PosY + 1, m_RelZ))
{ {
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST: case E_BLOCK_CHEST:
{ {
// Chests have special handling because of double-chests // Chests have special handling because of double-chests
@ -322,6 +323,7 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
bool res = false; bool res = false;
switch (DestChunk->GetBlock(OutRelX, OutY, OutRelZ)) switch (DestChunk->GetBlock(OutRelX, OutY, OutRelZ))
{ {
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST: case E_BLOCK_CHEST:
{ {
// Chests have special handling because of double-chests // 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. /// Moves items from a chest (dblchest) above the hopper into this hopper. Returns true if contents have changed.
bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk) bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
{ {
cChestEntity * Chest = (cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ); cChestEntity * MainChest = (cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ);
if (Chest == NULL) 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); LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX, m_PosY + 1, m_PosZ);
return false; return false;
} }
if (MoveItemsFromGrid(*Chest)) if (MoveItemsFromGrid(*MainChest))
{ {
// Moved the item from the chest directly above the hopper // Moved the item from the chest directly above the hopper
return true; 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 static const struct
{ {
int x, z; int x, z;
@ -395,21 +397,26 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
int x = m_RelX + Coords[i].x; int x = m_RelX + Coords[i].x;
int z = m_RelZ + Coords[i].z; int z = m_RelZ + Coords[i].z;
cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z); cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
if ( if (Neighbor == NULL)
(Neighbor == NULL) ||
(Neighbor->GetBlock(x, m_PosY + 1, z) != E_BLOCK_CHEST)
)
{ {
continue; 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); 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 else
{ {
if (MoveItemsFromGrid(*Chest)) if (MoveItemsFromGrid(*SideChest))
{ {
return true; return true;
} }
@ -550,10 +557,11 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block
} }
if (MoveItemsToGrid(*Chest)) if (MoveItemsToGrid(*Chest))
{ {
// Chest block directly connected was not full
return true; 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 static const struct
{ {
int x, z; 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 x = RelX + Coords[i].x;
int z = RelZ + Coords[i].z; int z = RelZ + Coords[i].z;
cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z); cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
if ( if (Neighbor == NULL)
(Neighbor == NULL) ||
(Neighbor->GetBlock(x, a_BlockY, z) != E_BLOCK_CHEST)
)
{ {
continue; 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); Chest = (cChestEntity *)Neighbor->GetBlockEntity(a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z);
if (Chest == NULL) 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 // 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); 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_NEW_LEAVES ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_TORCH ].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 ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_VINES ].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_STATIONARY_WATER ].m_Transparent = true;
a_Info[E_BLOCK_STONE_BUTTON ].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_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 ].m_Transparent = true;
a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_Transparent = true; a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_Transparent = true;
a_Info[E_BLOCK_TALL_GRASS ].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_TALL_GRASS ].m_IsSnowable = false;
a_Info[E_BLOCK_TNT ].m_IsSnowable = false; a_Info[E_BLOCK_TNT ].m_IsSnowable = false;
a_Info[E_BLOCK_TORCH ].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 ].m_IsSnowable = false;
a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_IsSnowable = false; a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_IsSnowable = false;
a_Info[E_BLOCK_VINES ].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_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
a_WorldInterface.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); 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) // 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); 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(); double yaw = a_Player->GetYaw();
if ( if (
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) || (Area.GetRelBlockType(0, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST) (Area.GetRelBlockType(2, 0, 1) == m_BlockType)
) )
{ {
a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3; a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3;
return true; return true;
} }
if ( if (
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) || (Area.GetRelBlockType(0, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST) (Area.GetRelBlockType(2, 0, 1) == m_BlockType)
) )
{ {
// FIXME: This is unreachable, as the condition is the same as the above one // FIXME: This is unreachable, as the condition is the same as the above one
@ -130,12 +130,12 @@ public:
} }
int NumChestNeighbors = 0; int NumChestNeighbors = 0;
if (Area.GetRelBlockType(1, 0, 2) == E_BLOCK_CHEST) if (Area.GetRelBlockType(1, 0, 2) == m_BlockType)
{ {
if ( if (
(Area.GetRelBlockType(0, 0, 2) == E_BLOCK_CHEST) || (Area.GetRelBlockType(0, 0, 2) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 1) == E_BLOCK_CHEST) || (Area.GetRelBlockType(1, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 3) == E_BLOCK_CHEST) (Area.GetRelBlockType(1, 0, 3) == m_BlockType)
) )
{ {
// Already a doublechest neighbor, disallow: // Already a doublechest neighbor, disallow:
@ -143,12 +143,12 @@ public:
} }
NumChestNeighbors += 1; NumChestNeighbors += 1;
} }
if (Area.GetRelBlockType(3, 0, 2) == E_BLOCK_CHEST) if (Area.GetRelBlockType(3, 0, 2) == m_BlockType)
{ {
if ( if (
(Area.GetRelBlockType(4, 0, 2) == E_BLOCK_CHEST) || (Area.GetRelBlockType(4, 0, 2) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 1) == E_BLOCK_CHEST) || (Area.GetRelBlockType(3, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 3) == E_BLOCK_CHEST) (Area.GetRelBlockType(3, 0, 3) == m_BlockType)
) )
{ {
// Already a doublechest neighbor, disallow: // Already a doublechest neighbor, disallow:
@ -156,12 +156,12 @@ public:
} }
NumChestNeighbors += 1; NumChestNeighbors += 1;
} }
if (Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST) if (Area.GetRelBlockType(2, 0, 1) == m_BlockType)
{ {
if ( if (
(Area.GetRelBlockType(2, 0, 0) == E_BLOCK_CHEST) || (Area.GetRelBlockType(2, 0, 0) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 1) == E_BLOCK_CHEST) || (Area.GetRelBlockType(1, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 1) == E_BLOCK_CHEST) (Area.GetRelBlockType(3, 0, 1) == m_BlockType)
) )
{ {
// Already a doublechest neighbor, disallow: // Already a doublechest neighbor, disallow:
@ -169,12 +169,12 @@ public:
} }
NumChestNeighbors += 1; NumChestNeighbors += 1;
} }
if (Area.GetRelBlockType(2, 0, 3) == E_BLOCK_CHEST) if (Area.GetRelBlockType(2, 0, 3) == m_BlockType)
{ {
if ( if (
(Area.GetRelBlockType(2, 0, 4) == E_BLOCK_CHEST) || (Area.GetRelBlockType(2, 0, 4) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 3) == E_BLOCK_CHEST) || (Area.GetRelBlockType(1, 0, 3) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 3) == E_BLOCK_CHEST) (Area.GetRelBlockType(3, 0, 3) == m_BlockType)
) )
{ {
// Already a doublechest neighbor, disallow: // 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. /// 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) 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; return false;
} }
@ -228,7 +228,7 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override 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 virtual const char * GetStepSound(void) override
{ {
return "step.cloth"; return "step.cloth";

View File

@ -19,15 +19,13 @@
class cBlockFarmlandHandler : class cBlockFarmlandHandler :
public cBlockHandler public cBlockHandler
{ {
typedef cBlockHandler super;
public: public:
cBlockFarmlandHandler(void) : cBlockFarmlandHandler(BLOCKTYPE a_BlockType) :
super(E_BLOCK_FARMLAND) 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 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; 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) 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_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType); case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
case E_BLOCK_ANVIL: return new cBlockAnvilHandler (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_EMERALD_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_ENCHANTMENT_TABLE: return new cBlockEnchantmentTableHandler(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_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_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType);
case E_BLOCK_FIRE: return new cBlockFireHandler (a_BlockType); case E_BLOCK_FIRE: return new cBlockFireHandler (a_BlockType);
case E_BLOCK_FLOWER_POT: return new cBlockFlowerPotHandler (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_LAPIS_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_LAVA: return new cBlockLavaHandler (a_BlockType); case E_BLOCK_LAVA: return new cBlockLavaHandler (a_BlockType);
case E_BLOCK_LEAVES: return new cBlockLeavesHandler (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_LILY_PAD: return new cBlockLilypadHandler (a_BlockType);
case E_BLOCK_LIT_FURNACE: return new cBlockFurnaceHandler (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_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_MELON: return new cBlockMelonHandler (a_BlockType); case E_BLOCK_MELON: return new cBlockMelonHandler (a_BlockType);
case E_BLOCK_MELON_STEM: return new cBlockStemsHandler (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_TORCH: return new cBlockTorchHandler (a_BlockType);
case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType); case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType);
case E_BLOCK_TNT: return new cBlockTNTHandler (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: return new cBlockTripwireHandler (a_BlockType);
case E_BLOCK_TRIPWIRE_HOOK: return new cBlockTripwireHookHandler (a_BlockType); case E_BLOCK_TRIPWIRE_HOOK: return new cBlockTripwireHookHandler (a_BlockType);
case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType); case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType);

View File

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

View File

@ -41,21 +41,27 @@ public:
} }
static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction) // tolua_export virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{ // tolua_export {
a_Pickups.Add(m_BlockType, 1, 0); // Reset meta
}
static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction)
{
switch (a_Direction) switch (a_Direction)
{ {
case BLOCK_FACE_ZM: return 0x2; case BLOCK_FACE_ZM: return 0x2;
case BLOCK_FACE_ZP: return 0x3; case BLOCK_FACE_ZP: return 0x3;
case BLOCK_FACE_XM: return 0x4; case BLOCK_FACE_XM: return 0x4;
case BLOCK_FACE_XP: return 0x5; case BLOCK_FACE_XP: return 0x5;
default: return 0x2; default: return 0x2;
} }
} // tolua_export }
static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData) // tolua_export static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData)
{ // tolua_export {
switch (a_MetaData) switch (a_MetaData)
{ {
case 0x2: return BLOCK_FACE_ZM; case 0x2: return BLOCK_FACE_ZM;
@ -64,10 +70,10 @@ public:
case 0x5: return BLOCK_FACE_XP; case 0x5: return BLOCK_FACE_XP;
default: return BLOCK_FACE_ZM; 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) 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++) 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_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
a_WorldInterface.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); 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; NIBBLETYPE currMeta;
AddPistonDir(a_PistonX, a_PistonY, a_PistonZ, pistonmeta, 1); AddPistonDir(a_PistonX, a_PistonY, a_PistonZ, pistonmeta, 1);
a_World->GetBlockTypeMeta(a_PistonX, a_PistonY, a_PistonZ, currBlock, currMeta); 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 // This block breaks when pushed, extend up to here
return ret; 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->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: // 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 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); AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1);
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta & ~(8)); 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->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); AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, 1);
// Retract the extension, pull block if appropriate // Retract the extension, pull block if appropriate

View File

@ -104,6 +104,7 @@ private:
case E_BLOCK_ENCHANTMENT_TABLE: case E_BLOCK_ENCHANTMENT_TABLE:
case E_BLOCK_END_PORTAL: case E_BLOCK_END_PORTAL:
case E_BLOCK_END_PORTAL_FRAME: 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_FURNACE:
case E_BLOCK_LIT_FURNACE: case E_BLOCK_LIT_FURNACE:
case E_BLOCK_HOPPER: case E_BLOCK_HOPPER:
@ -113,6 +114,7 @@ private:
case E_BLOCK_NOTE_BLOCK: case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_OBSIDIAN: case E_BLOCK_OBSIDIAN:
case E_BLOCK_PISTON_EXTENSION: case E_BLOCK_PISTON_EXTENSION:
case E_BLOCK_TRAPPED_CHEST:
{ {
return false; return false;
} }
@ -126,24 +128,10 @@ private:
return true; 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 /// Returns true if the specified block can be pulled by a sticky piston
static inline bool CanPull(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) static inline bool CanPull(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{ {
switch (a_BlockType) if (cBlockInfo::IsPistonBreakable(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))
{ {
return false; // CanBreakPush returns true, but we need false to prevent pulling 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 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) switch (a_BlockFace)
{ {
case BLOCK_FACE_YM: case BLOCK_FACE_YM:
case BLOCK_FACE_YP: 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_ZP:
case BLOCK_FACE_ZM: 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_XP:
case BLOCK_FACE_XM: case BLOCK_FACE_XM:
{ {
return a_WoodMeta | 0x4; // East or west return a_Meta | 0x4; // East or west
} }
default: default:
{ {
ASSERT(!"Unhandled block face!"); 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 ~cBroadcastInterface() {}
virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0; 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; 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) switch (BlockType)
{ {
case E_BLOCK_BEACON: case E_BLOCK_BEACON:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST: case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER: 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) switch (a_BlockType)
{ {
case E_BLOCK_BEACON: case E_BLOCK_BEACON:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST: case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER: case E_BLOCK_DISPENSER:
@ -2150,7 +2152,7 @@ bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallb
{ {
continue; 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 // 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; return false;
@ -2530,8 +2532,8 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ)
{ {
int BlockX = m_PosX * cChunkDef::Width + a_RelX; int BlockX = m_PosX * cChunkDef::Width + a_RelX;
int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ; int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ;
int BlockY, ChunkX, ChunkZ; int ChunkX, ChunkZ;
AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
return m_ChunkMap->GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, 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 ) 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; 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[] } // 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 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 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 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 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 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); 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); cCSLock Lock(m_CSLayers);
int ChunkX, ChunkZ; 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); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ);
if (Chunk == NULL) if (Chunk == NULL)
{ {
return; return;
} }
// It's perfectly legal to broadcast packets even to invalid chunks! // 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); cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
@ -856,6 +871,10 @@ void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkZ)
return; return;
} }
Chunk->MarkDirty(); 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); cChunkInterface ChunkInterface(this);
if (a_BlockType == E_BLOCK_AIR) 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; int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); 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); cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ); 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()); 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 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 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 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 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 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); 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 */ /** 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 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 MarkChunkSaving (int a_ChunkX, int a_ChunkZ);
void MarkChunkSaved (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 GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ);
NIBBLETYPE GetBlockSkyLight (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); 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 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, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true); 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, BLOCKTYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR); 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 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); 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 */ /** Maximum number of block change interactions a player can perform per tick - exceeding this causes a kick */
#define MAX_BLOCK_CHANGE_INTERACTIONS 20 #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_PingID(1),
m_BlockDigAnimStage(-1), m_BlockDigAnimStage(-1),
m_HasStartedDigging(false), m_HasStartedDigging(false),
m_TicksSinceDestruction(0),
m_State(csConnected), m_State(csConnected),
m_ShouldCheckDownloaded(false), m_ShouldCheckDownloaded(false),
m_NumExplosionsThisTick(0), m_NumExplosionsThisTick(0),
@ -104,7 +100,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
cClientHandle::~cClientHandle() 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); LOGD("Deleting client \"%s\" at %p", GetUsername().c_str(), this);
@ -169,7 +165,7 @@ void cClientHandle::Destroy(void)
RemoveFromAllChunks(); RemoveFromAllChunks();
m_Player->GetWorld()->RemoveClientFromChunkSender(this); 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); 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 // 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); 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) 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: // Process received network data:
AString IncomingData; AString IncomingData;
{ {
@ -1901,15 +1886,7 @@ void cClientHandle::Tick(float a_Dt)
void cClientHandle::ServerTick(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: // Process received network data:
AString IncomingData; 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 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 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 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 SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data);
void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock); void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock);
void SendSpawnMob (const cMonster & a_Mob); void SendSpawnMob (const cMonster & a_Mob);
@ -325,9 +325,6 @@ private:
int m_LastDigBlockX; int m_LastDigBlockX;
int m_LastDigBlockY; int m_LastDigBlockY;
int m_LastDigBlockZ; int m_LastDigBlockZ;
/** Used while csDestroyedWaiting for counting the ticks until the connection is closed */
int m_TicksSinceDestruction;
enum eState enum eState
{ {
@ -338,7 +335,6 @@ private:
csConfirmingPos, ///< The client has been sent the position packet, waiting for them to repeat the position back csConfirmingPos, ///< The client has been sent the position packet, waiting for them to repeat the position back
csPlaying, ///< Normal gameplay csPlaying, ///< Normal gameplay
csDestroying, ///< The client is being destroyed, don't queue any more packets / don't add to chunks 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 csDestroyed, ///< The client has been destroyed, the destructor is to be called from the owner thread
// TODO: Add Kicking here as well // 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 Hit = a_HitPos;
Vector3d SinkMovement = (GetSpeed() / 800); Vector3d SinkMovement = (GetSpeed() / 1000);
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) 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); super::OnHitSolidBlock(Hit, a_HitFace);
Vector3i BlockHit = Hit.Floor(); Vector3i BlockHit = Hit.Floor();
@ -89,7 +89,7 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa
m_HitBlockPos = Vector3i(X, Y, Z); m_HitBlockPos = Vector3i(X, Y, Z);
// Broadcast arrow hit sound // 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); a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
// Broadcast successful hit sound // 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(); Destroy();
} }
@ -131,7 +131,7 @@ void cArrowEntity::CollectedBy(cPlayer * a_Dest)
} }
GetWorld()->BroadcastCollectEntity(*this, *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; 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); LOGD("Player %s picked up an ExpOrb. His reward is %i", a_ClosestPlayer->GetName().c_str(), m_Reward);
a_ClosestPlayer->DeltaExperience(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(); Destroy();
} }

View File

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

View File

@ -134,7 +134,7 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
{ {
if (m_CountDownTime <= 0) 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); SetPosY(GetPosY() - 1);
m_CanPickupItem = true; m_CanPickupItem = true;
m_PickupCountDown = 20; m_PickupCountDown = 20;

View File

@ -226,7 +226,7 @@ bool cPickup::CollectedBy(cPlayer * a_Dest)
m_Item.m_ItemCount -= NumAdded; m_Item.m_ItemCount -= NumAdded;
m_World->BroadcastCollectEntity(*this, *a_Dest); m_World->BroadcastCollectEntity(*this, *a_Dest);
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) // 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) if (m_Item.m_ItemCount <= 0)
{ {
// All of the pickup has been collected, schedule the pickup for destroying // 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()) 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; Vector3d Speed;
if (a_Speed != NULL) 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 pkWitherSkull: return new cWitherSkullEntity (a_Creator, a_X, a_Y, a_Z, Speed);
case pkFirework: 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 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, 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); 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 /// 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); 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__); LOGWARNING("%s: MaxRelX less than zero, adjusting to zero", __FUNCTION__);
a_MaxRelX = 0; 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__); LOGWARNING("%s: MaxRelX more than chunk width, adjusting to chunk width", __FUNCTION__);
a_MaxRelX = cChunkDef::Width - 1; 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__); LOGWARNING("%s: MaxRelY less than zero, adjusting to zero", __FUNCTION__);
a_MaxRelY = 0; 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__); LOGWARNING("%s: MaxRelY more than chunk height, adjusting to chunk height", __FUNCTION__);
a_MaxRelY = cChunkDef::Height - 1; 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__); LOGWARNING("%s: MaxRelZ less than zero, adjusting to zero", __FUNCTION__);
a_MaxRelZ = 0; 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__); LOGWARNING("%s: MaxRelZ more than chunk width, adjusting to chunk width", __FUNCTION__);
a_MaxRelZ = cChunkDef::Width - 1; a_MaxRelZ = cChunkDef::Width - 1;

View File

@ -44,6 +44,7 @@ cGridStructGen::cGridStructGen(
int a_MaxStructureSizeX, int a_MaxStructureSizeZ, int a_MaxStructureSizeX, int a_MaxStructureSizeZ,
size_t a_MaxCacheSize size_t a_MaxCacheSize
) : ) :
m_Seed(a_Seed),
m_Noise(a_Seed), m_Noise(a_Seed),
m_GridSizeX(a_GridSizeX), m_GridSizeX(a_GridSizeX),
m_GridSizeZ(a_GridSizeZ), m_GridSizeZ(a_GridSizeZ),
@ -53,6 +54,16 @@ cGridStructGen::cGridStructGen(
m_MaxStructureSizeZ(a_MaxStructureSizeZ), m_MaxStructureSizeZ(a_MaxStructureSizeZ),
m_MaxCacheSize(a_MaxCacheSize) 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)); size_t NumStructuresPerQuery = (size_t)(((m_MaxStructureSizeX + m_MaxOffsetX) / m_GridSizeX + 1) * ((m_MaxStructureSizeZ + m_MaxOffsetZ) / m_GridSizeZ + 1));
if (NumStructuresPerQuery > m_MaxCacheSize) if (NumStructuresPerQuery > m_MaxCacheSize)
{ {

View File

@ -70,7 +70,7 @@ public:
return; 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()) if (!a_Player->IsGameModeCreative())
{ {
a_Player->UseEquippedItem(); 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) 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; 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) 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; return false;
} }
BLOCKTYPE CurrentBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); BLOCKTYPE CurrentBlock;
bool CanWashAway = cFluidSimulator::CanWashAway(CurrentBlock); Vector3i BlockPos;
if (!CanWashAway) 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; return false;
} }
@ -138,7 +124,7 @@ public:
} }
// Wash away anything that was there prior to placing: // Wash away anything that was there prior to placing:
if (CanWashAway) if (cFluidSimulator::CanWashAway(CurrentBlock))
{ {
cBlockHandler * Handler = BlockHandler(CurrentBlock); cBlockHandler * Handler = BlockHandler(CurrentBlock);
if (Handler->DoesDropOnUnsuitable()) 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; 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 : class cCallbacks :
public cBlockTracer::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; 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: case E_BLOCK_TNT:
{ {
// Activate the 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->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->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 a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
break; break;
} }
@ -68,7 +68,7 @@ public:
if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) 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->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; break;
} }
} }

View File

@ -33,16 +33,9 @@ public:
// Play sound // Play sound
cFastRandom Random; cFastRandom Random;
a_World->BroadcastSoundEffect( 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));
"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)
);
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; return false;
} }
@ -142,7 +135,7 @@ public:
return false; 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; 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 BlockX = m_CenterX + ((a_X - (m_Width / 2)) * PixelWidth);
int BlockZ = m_CenterZ + ((a_Z - (m_Height / 2)) * PixelWidth); int BlockZ = m_CenterZ + ((a_Z - (m_Height / 2)) * PixelWidth);
int ChunkX, ChunkY, ChunkZ; int ChunkX, ChunkZ;
m_World->BlockToChunk(BlockX, 0, BlockZ, ChunkX, ChunkY, ChunkZ); cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
int RelX = BlockX - (ChunkX * cChunkDef::Width); int RelX = BlockX - (ChunkX * cChunkDef::Width);
int RelZ = BlockZ - (ChunkZ * cChunkDef::Width); int RelZ = BlockZ - (ChunkZ * cChunkDef::Width);

View File

@ -125,7 +125,7 @@ void cCreeper::Attack(float a_Dt)
if (!m_bIsBlowing) 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_bIsBlowing = true;
m_World->BroadcastEntityMetadata(*this); m_World->BroadcastEntityMetadata(*this);
} }
@ -143,7 +143,7 @@ void cCreeper::OnRightClicked(cPlayer & a_Player)
{ {
a_Player.UseEquippedItem(); 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_bIsBlowing = true;
m_World->BroadcastEntityMetadata(*this); m_World->BroadcastEntityMetadata(*this);
m_BurnedWithFlintAndSteel = true; m_BurnedWithFlintAndSteel = true;

View File

@ -479,7 +479,7 @@ bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
if (!m_SoundHurt.empty() && (m_Health > 0)) 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) if (a_TDI.Attacker != NULL)
@ -498,7 +498,7 @@ void cMonster::KilledBy(cEntity * a_Killer)
super::KilledBy(a_Killer); super::KilledBy(a_Killer);
if (m_SoundHurt != "") 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; int Reward;
switch (m_MobType) switch (m_MobType)
@ -920,7 +920,7 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
case mtMooshroom: toReturn = new cMooshroom(); break; case mtMooshroom: toReturn = new cMooshroom(); break;
case mtOcelot: toReturn = new cOcelot(); break; case mtOcelot: toReturn = new cOcelot(); break;
case mtPig: toReturn = new cPig(); 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 mtSilverfish: toReturn = new cSilverfish(); break;
case mtSnowGolem: toReturn = new cSnowGolem(); break; case mtSnowGolem: toReturn = new cSnowGolem(); break;
case mtSpider: toReturn = new cSpider(); break; case mtSpider: toReturn = new cSpider(); break;

View File

@ -5,6 +5,7 @@
#include "../BlockID.h" #include "../BlockID.h"
#include "../Entities/Player.h" #include "../Entities/Player.h"
#include "../World.h" #include "../World.h"
#include "FastRandom.h"
@ -16,6 +17,16 @@ cSheep::cSheep(int a_Color) :
m_WoolColor(a_Color), m_WoolColor(a_Color),
m_TimeToStopEating(-1) 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) void cSheep::OnRightClicked(cPlayer & a_Player)
{ {
const cItem & EquippedItem = a_Player.GetEquippedItem(); 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_IsSheared = true;
m_World->BroadcastEntityMetadata(*this); m_World->BroadcastEntityMetadata(*this);
@ -51,6 +62,7 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
int NumDrops = m_World->GetTickRandomNumber(2) + 1; int NumDrops = m_World->GetTickRandomNumber(2) + 1;
Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor)); Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor));
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10); 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)) 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; typedef cPassiveMonster super;
public: 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); CLASS_PROTODEF(cSheep);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void OnRightClicked(cPlayer & a_Player) override; virtual void OnRightClicked(cPlayer & a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); } 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; } bool IsSheared(void) const { return m_IsSheared; }
void SetSheared(bool a_IsSheared) { m_IsSheared = a_IsSheared; }
int GetFurColor(void) const { return m_WoolColor; } int GetFurColor(void) const { return m_WoolColor; }
void SetFurColor(int a_WoolColor) { m_WoolColor = a_WoolColor; }
private: private:
bool m_IsSheared; bool m_IsSheared;
int m_WoolColor; int m_WoolColor;
int m_TimeToStopEating; int m_TimeToStopEating;

View File

@ -262,7 +262,7 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
AString HexDump; AString HexDump;
if (Response.compare(0, prefix.size(), prefix)) 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()); LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return false; 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"); size_t idxHeadersEnd = Response.find("\r\n\r\n");
if (idxHeadersEnd == AString::npos) 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()); LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return false; 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 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 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 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 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 SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0;
virtual void SendSpawnMob (const cMonster & a_Mob) = 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 // 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 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 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 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 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 SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
virtual void SendSpawnMob (const cMonster & a_Mob) 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_Entity.GetUniqueID());
WriteInt (a_Player.GetUniqueID()); WriteInt (a_Player.GetUniqueID());
Flush(); 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); cCSLock Lock(m_CSPacket);
WriteByte (PACKET_SOUND_EFFECT); WriteByte (PACKET_SOUND_EFFECT);
WriteString (a_SoundName); WriteString (a_SoundName);
WriteInt (a_SrcX); WriteInt ((int)(a_X * 8.0));
WriteInt (a_SrcY); WriteInt ((int)(a_Y * 8.0));
WriteInt (a_SrcZ); WriteInt ((int)(a_Z * 8.0));
WriteFloat (a_Volume); WriteFloat (a_Volume);
WriteChar ((char)(a_Pitch * 63.0f)); WriteChar ((char)(a_Pitch * 63.0f));
Flush(); 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 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 SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
virtual void SendPlayerSpawn (const cPlayer & a_Player) 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 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 SendSpawnMob (const cMonster & a_Mob) override;
virtual void SendTabCompletionResults(const AStringVector & a_Results) 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? ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x29); // Sound Effect packet cPacketizer Pkt(*this, 0x29); // Sound Effect packet
Pkt.WriteString(a_SoundName); Pkt.WriteString(a_SoundName);
Pkt.WriteInt(a_SrcX); Pkt.WriteInt((int)(a_X * 8.0));
Pkt.WriteInt(a_SrcY); Pkt.WriteInt((int)(a_Y * 8.0));
Pkt.WriteInt(a_SrcZ); Pkt.WriteInt((int)(a_Z * 8.0));
Pkt.WriteFloat(a_Volume); Pkt.WriteFloat(a_Volume);
Pkt.WriteByte((Byte)(a_Pitch * 63)); 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 SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) 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 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 SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) 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); 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 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 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 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 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 SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
virtual void SendSpawnMob (const cMonster & a_Mob) override; virtual void SendSpawnMob (const cMonster & a_Mob) override;

View File

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

View File

@ -5,6 +5,7 @@
#include "BoundingBox.h" #include "BoundingBox.h"
#include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/DropSpenserEntity.h"
#include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/CommandBlockEntity.h"
#include "../Entities/TNTEntity.h" #include "../Entities/TNTEntity.h"
#include "../Entities/Pickup.h" #include "../Entities/Pickup.h"
@ -15,8 +16,6 @@
#include "../Blocks/BlockPiston.h" #include "../Blocks/BlockPiston.h"
#include "../Blocks/BlockTripwireHook.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; int RelZ = 0;
BLOCKTYPE Block; BLOCKTYPE Block;
NIBBLETYPE Meta; NIBBLETYPE Meta;
cChunk * OtherChunk = a_Chunk;
if (a_OtherChunk != NULL) if (a_OtherChunk != NULL)
{ {
RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width; RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width;
RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width; RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width;
a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); 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 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); 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); itr = PoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue; continue;
} }
else if ( else if (
@ -105,34 +104,13 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) || ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
((Block == E_BLOCK_DETECTOR_RAIL) && ((Meta & 0x08) == 0)) || ((Block == E_BLOCK_DETECTOR_RAIL) && ((Meta & 0x08) == 0)) ||
(((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(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_TRIPWIRE_HOOK) && ((Meta & 0x08) == 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); 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); itr = PoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue; 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; ++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); 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); itr = LinkedPoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue; continue;
} }
else if ( else if (
// Things that can send power through a block but which depends on meta // Things that can send power through a block but which depends on meta
((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) || ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) || ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
(((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(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))
) )
{ {
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); 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); itr = LinkedPoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue; 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); 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); itr = LinkedPoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue; 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_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_TNT: HandleTNT(dataitr->x, dataitr->y, dataitr->z); break;
case E_BLOCK_TRAPDOOR: HandleTrapdoor(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_ACTIVATOR_RAIL:
case E_BLOCK_DETECTOR_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) void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
{ {
if ( if (AreCoordsOnChunkBoundary(a_BlockX, a_BlockY, a_BlockZ))
((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
{ {
// On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk) // On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk)
AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_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 // 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 + 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); 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; 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 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 // 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)); 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 (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last)
{ {
if ( 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 (!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); 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); 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 // Check if the block the torch is on is powered
int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ; 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 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 // 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 return; // Something matches, torch still powered
} }
@ -780,17 +758,20 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
{ {
for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end();) 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? if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks?
{ {
int RelBlockX = itr->a_RelBlockPos.x; int RelBlockX = itr->a_RelBlockPos.x;
int RelBlockY = itr->a_RelBlockPos.y; int RelBlockY = itr->a_RelBlockPos.y;
int RelBlockZ = itr->a_RelBlockPos.z; 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) if (itr->ShouldPowerOn)
{ {
if (Block != E_BLOCK_REDSTONE_REPEATER_ON) // For performance
m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta); // For performance {
m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta);
}
switch (Meta & 0x3) // We only want the direction (bottom) bits 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); itr = m_RepeatersDelayList->erase(itr);
} }
else 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); 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->a_ElapsedTicks++;
itr++; itr++;
@ -915,7 +893,7 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_RelBlockX, int a_RelBlockY,
if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) 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_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 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 else
{ {
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); 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; break;
} }
@ -1193,7 +1171,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
{ {
if (Meta == E_META_PRESSURE_PLATE_RAISED) 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); m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); 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) 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); 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; break;
@ -1261,7 +1239,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
{ {
if (Meta == E_META_PRESSURE_PLATE_RAISED) 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); m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); 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) 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); 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; break;
@ -1328,7 +1306,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
{ {
if (Meta == E_META_PRESSURE_PLATE_RAISED) 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); m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); 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) 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); 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; break;
} }
@ -1384,14 +1362,14 @@ void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_Re
{ {
if (ReverseBlockFace(cBlockTripwireHookHandler::MetadataToDirection(Meta)) == FaceToGoTowards) if (ReverseBlockFace(cBlockTripwireHookHandler::MetadataToDirection(Meta)) == FaceToGoTowards)
{ {
// Other hook not facing in opposite direction // Other hook facing in opposite direction - circuit completed!
break; break;
} }
else else
{ {
// Tripwire hook not connected at all, AND away all the power state bits // 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); 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; 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 // 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); 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; return;
} }
} }
@ -1414,7 +1392,51 @@ void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_Re
{ {
// Connected but not activated, AND away the highest bit // 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); 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 BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; 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 = a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->begin(); itr != a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->end(); ++itr) // Check powered list
for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
{ {
if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) 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) bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel)
{ {
a_PowerLevel = 0; a_PowerLevel = 0;
int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX;
int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; 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 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; 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); 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 SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ; int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ;
BLOCKTYPE Block = 0; cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ); // Adjust coordinates for the later call using these values
if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block)) if ((Neighbour == NULL) || !Neighbour->IsValid())
{ {
return; 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(); // We need to insert the value into the chunk who owns the block position
PoweredBlocksList * Powered = Neighbour->GetRedstoneSimulatorPoweredBlocksList(); for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr)
for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
{ {
if ( if (
itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) && 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(); // No need to get neighbouring chunk as we can guarantee that when something is powering us, the entry will be in our chunk
for (PoweredBlocksList::const_iterator itr = OtherPowered->begin(); itr != OtherPowered->end(); ++itr) // Check powered list // 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 ( if (
itr->a_BlockPos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) && 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! BLOCKTYPE Block;
return; 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 SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ; 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)) if (!IsViableMiddleBlock(a_MiddleBlock))
{ {
return; return;
} }
cChunk * Neighbour = m_Chunk->GetNeighborChunk(BlockX, BlockZ); cChunk * Neighbour = m_Chunk->GetNeighborChunk(BlockX, BlockZ);
if ((Neighbour == NULL) || !Neighbour->IsValid())
{
return;
}
LinkedBlocksList * Linked = Neighbour->GetRedstoneSimulatorLinkedBlocksList(); LinkedBlocksList * Linked = Neighbour->GetRedstoneSimulatorLinkedBlocksList();
for (LinkedBlocksList::iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list 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) cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{ {
int Dir = REDSTONE_NONE; 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 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); 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 ====== */ /* ====== CARRIERS ====== */
@ -114,8 +116,6 @@ private:
void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles repeaters */ /** Handles repeaters */
void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
/** Handles delayed updates to Repeaters **/
void HandleRedstoneRepeaterDelays();
/* ====================== */ /* ====================== */
/* ====== DEVICES ====== */ /* ====== DEVICES ====== */
@ -156,11 +156,15 @@ private:
void SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL); 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 */ /** 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); 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 */ /** 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 */ /** 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 */ /** Returns if a coordinate is in the indirectly powered blocks list */
bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */ /** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */
@ -174,7 +178,8 @@ private:
/** Returns if a wire is powered /** 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 */ 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); 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 */ /** Returns if lever metadata marks it as emitting power */
bool IsLeverOn(NIBBLETYPE a_BlockMeta); bool IsLeverOn(NIBBLETYPE a_BlockMeta);
@ -186,7 +191,9 @@ private:
/** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */ /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */
inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return cBlockInfo::FullyOccupiesVoxel(Block); } 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) inline static bool IsMechanism(BLOCKTYPE Block)
{ {
switch (Block) switch (Block)
@ -209,6 +216,7 @@ private:
case E_BLOCK_REDSTONE_REPEATER_OFF: case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON: case E_BLOCK_REDSTONE_REPEATER_ON:
case E_BLOCK_POWERED_RAIL: case E_BLOCK_POWERED_RAIL:
case E_BLOCK_REDSTONE_WIRE:
{ {
return true; return true;
} }
@ -235,6 +243,7 @@ private:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_WOODEN_PRESSURE_PLATE: case E_BLOCK_WOODEN_PRESSURE_PLATE:
case E_BLOCK_TRAPPED_CHEST:
{ {
return true; return true;
} }
@ -277,6 +286,7 @@ private:
case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_TNT: case E_BLOCK_TNT:
case E_BLOCK_TRAPDOOR: case E_BLOCK_TRAPDOOR:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_TRIPWIRE_HOOK: case E_BLOCK_TRIPWIRE_HOOK:
case E_BLOCK_TRIPWIRE: case E_BLOCK_TRIPWIRE:
case E_BLOCK_WOODEN_BUTTON: case E_BLOCK_WOODEN_BUTTON:
@ -289,6 +299,16 @@ private:
default: return false; 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->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::cChestWindow(cChestEntity * a_Chest) : 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_World(a_Chest->GetWorld()),
m_BlockX(a_Chest->GetPosX()), m_BlockX(a_Chest->GetPosX()),
m_BlockY(a_Chest->GetPosY()), 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 cSlotAreaChest(a_Chest, *this));
m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this));
m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
// Play the opening sound: // 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: // 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) : 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_World(a_PrimaryChest->GetWorld()),
m_BlockX(a_PrimaryChest->GetPosX()), m_BlockX(a_PrimaryChest->GetPosX()),
m_BlockY(a_PrimaryChest->GetPosY()), 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 cSlotAreaDoubleChest(a_PrimaryChest, a_SecondaryChest, *this));
m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this));
@ -940,10 +944,55 @@ cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_Secon
m_ShouldDistributeToHotbarFirst = false; m_ShouldDistributeToHotbarFirst = false;
// Play the opening sound: // 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: // 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() cChestWindow::~cChestWindow()
{ {
// Send out the chest-close packet: // 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::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) : 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_ShouldDistributeToHotbarFirst = false;
m_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this)); 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)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
// Play the opening sound: // 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: // Send out the chest-open packet:
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_ENDER_CHEST); 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); m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_ENDER_CHEST);
// Play the closing sound // 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 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 /// 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); virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse);
@ -327,10 +327,15 @@ public:
cChestWindow(cChestEntity * a_Chest); cChestWindow(cChestEntity * a_Chest);
cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest); cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest);
~cChestWindow(); ~cChestWindow();
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
virtual void OpenedByPlayer(cPlayer & a_Player) override;
protected: protected:
cWorld * m_World; cWorld * m_World;
int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet 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); IniFile.WriteFile(m_IniFileName);
} }
int ChunkX = 0, ChunkY = 0, ChunkZ = 0; int ChunkX = 0, ChunkZ = 0;
BlockToChunk((int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ); 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: // For the debugging builds, don't make the server build too much world upon start:
#if defined(_DEBUG) || defined(ANDROID_NDK) #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); Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
cVector3iArray BlocksAffected; cVector3iArray BlocksAffected;
m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, 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); cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) 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); cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed);
if (Projectile == NULL) if (Projectile == NULL)

View File

@ -224,7 +224,7 @@ public:
void BroadcastScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode); 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 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 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 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 BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
void BroadcastTeleportEntity (const 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 */ /** 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 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 MarkChunkSaving(int a_ChunkX, int a_ChunkZ);
void MarkChunkSaved (int a_ChunkX, int a_ChunkZ); void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
@ -634,18 +635,6 @@ public:
// tolua_end // 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 */ /** Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead */
void SaveAllChunks(void); void SaveAllChunks(void);
@ -762,7 +751,7 @@ public:
/** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise /** 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 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! */ /** 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)); } 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(""); m_Writer.BeginCompound("");
AddBasicTileEntity(a_Entity, "Chest"); AddBasicTileEntity(a_Entity, (a_ChestType == E_BLOCK_CHEST) ? "Chest" : "TrappedChest");
m_Writer.BeginList("Items", TAG_Compound); m_Writer.BeginList("Items", TAG_Compound);
AddItemGrid(a_Entity->GetContents()); AddItemGrid(a_Entity->GetContents());
m_Writer.EndList(); m_Writer.EndList();
@ -824,19 +824,21 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
// Add tile-entity into NBT: // Add tile-entity into NBT:
switch (a_Entity->GetBlockType()) switch (a_Entity->GetBlockType())
{ {
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break; case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity, a_Entity->GetBlockType()); break;
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *)a_Entity); break;
case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break; case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
case E_BLOCK_ENDER_CHEST: /* No need to be saved */ break; case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break;
case E_BLOCK_FLOWER_POT: AddFlowerPotEntity ((cFlowerPotEntity *) a_Entity); break; case E_BLOCK_ENDER_CHEST: /* No data to be saved */ break;
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break; case E_BLOCK_FLOWER_POT: AddFlowerPotEntity ((cFlowerPotEntity *) a_Entity); break;
case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break; case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_SIGN_POST: case E_BLOCK_HEAD: AddMobHeadEntity ((cMobHeadEntity *) a_Entity); break;
case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break; case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
case E_BLOCK_HEAD: AddMobHeadEntity ((cMobHeadEntity *) a_Entity); break; case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break;
case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break; case E_BLOCK_LIT_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break; case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break;
case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *) 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: default:
{ {

View File

@ -93,7 +93,7 @@ protected:
// Block entities: // Block entities:
void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID); 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 AddDispenserEntity(cDispenserEntity * a_Entity);
void AddDropperEntity (cDropperEntity * a_Entity); void AddDropperEntity (cDropperEntity * a_Entity);
void AddFurnaceEntity (cFurnaceEntity * a_Furnace); 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) 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) 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); 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 // TODO: Other block entities
} // for Child - tag children } // 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); ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
int x, y, z; 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 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); LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items);
a_BlockEntities.push_back(Chest.release()); 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) void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{ {
int ColorIdx = a_NBT.FindChildByName(a_TagIdx, "Color"); int ColorIdx = a_NBT.FindChildByName(a_TagIdx, "Color");
int Color = -1;
if (ColorIdx < 0) { return; } if (ColorIdx > 0)
{
int Color = (int)a_NBT.GetByte(ColorIdx); Color = (int)a_NBT.GetByte(ColorIdx);
}
std::auto_ptr<cSheep> Monster(new cSheep(Color)); std::auto_ptr<cSheep> Monster(new cSheep(Color));
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
@ -2126,6 +2131,12 @@ void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
return; 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()); 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 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 LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDropperFromNBT (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); 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 ) 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)) if (!ChestEntity->LoadFromJson(*itr))
{ {
LOGWARNING("ERROR READING CHEST FROM JSON!" ); LOGWARNING("ERROR READING CHEST FROM JSON!" );