1
0

Merge branch 'master' of https://github.com/mc-server/MCServer into portals

This commit is contained in:
Tiger Wang 2014-06-24 21:15:48 +01:00
commit bd5df3d3b9
20 changed files with 297 additions and 102 deletions

View File

@ -1,6 +1,6 @@
Many people have contributed to MCServer, and this list attempts to broadcast at least some of them.
BasedDoge - Donated AlchemistVillage prefabs
BasedDoge (Donated AlchemistVillage prefabs)
bearbin (Alexander Harkness)
derouinw
Diusrex
@ -27,6 +27,6 @@ tonibm19
UltraCoderRU
worktycho
xoft
Yeeeeezus - Donated AlchemistVillage prefabs
Yeeeeezus (Donated AlchemistVillage prefabs)
Please add yourself to this list if you contribute to MCServer.

View File

@ -523,13 +523,16 @@ end
Functions =
{
GenerateOfflineUUID = { Params = "Username", Return = "string", Notes = "(STATIC) Generates an UUID based on the player name provided. This is used for the offline (non-auth) mode, when there's no UUID source. Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. Returns a 36-char UUID (with dashes)." },
GetLocale = { Params = "", Return = "Locale", Notes = "Returns the locale string that the client sends as part of the protocol handshake. Can be used to provide localized strings." },
GetPing = { Params = "", Return = "number", Notes = "Returns the ping time, in ms" },
GetPlayer = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player object connected to this client. Note that this may be nil, for example if the player object is not yet spawned." },
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" },
GetUUID = { Params = "", Return = "string", Notes = "Returns the authentication-based UUID of the client. This UUID should be used to identify the player when persisting any player-related data." },
GetUsername = { Params = "", Return = "string", Notes = "Returns the username that the client has provided" },
GetViewDistance = { Params = "", Return = "number", Notes = "Returns the viewdistance (number of chunks loaded for the player in each direction)" },
HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." },
IsUUIDOnline = { Params = "UUID", Return = "bool", Notes = "(STATIC) Returns true if the UUID is generated by online auth, false if it is an offline-generated UUID. We use Version-3 UUIDs for offline UUIDs, online UUIDs are Version-4, thus we can tell them apart. Accepts both 32-char and 36-char UUIDs (with and without dashes). If the string given is not a valid UUID, returns false."},
Kick = { Params = "Reason", Return = "", Notes = "Kicks the user with the specified reason" },
SendPluginMessage = { Params = "Channel, Message", Return = "", Notes = "Sends the plugin message on the specified channel." },
SetLocale = { Params = "Locale", Return = "", Notes = "Sets the locale that MCServer keeps on record. Initially the locale is initialized in protocol handshake, this function allows plugins to override the stored value (but only server-side and only until the user disconnects)." },

View File

@ -346,7 +346,7 @@ end
function OnUsingBlazeRod(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, CursorY, CursorZ)
-- Magic rod of query: show block types and metas for both neighbors of the pointed face
local Type, Meta, Valid = Player:GetWorld():GetBlockTypeMeta(BlockX, BlockY, BlockZ, Type, Meta);
local Valid, Type, Meta = Player:GetWorld():GetBlockTypeMeta(BlockX, BlockY, BlockZ);
if (Type == E_BLOCK_AIR) then
Player:SendMessage(cChatColor.LightGray .. "Block {" .. BlockX .. ", " .. BlockY .. ", " .. BlockZ .. "}: air:" .. Meta);
@ -356,7 +356,7 @@ function OnUsingBlazeRod(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, Cur
end
local X, Y, Z = AddFaceDirection(BlockX, BlockY, BlockZ, BlockFace);
Valid, Type, Meta = Player:GetWorld():GetBlockTypeMeta(X, Y, Z, Type, Meta);
Valid, Type, Meta = Player:GetWorld():GetBlockTypeMeta(X, Y, Z);
if (Type == E_BLOCK_AIR) then
Player:SendMessage(cChatColor.LightGray .. "Block {" .. X .. ", " .. Y .. ", " .. Z .. "}: air:" .. Meta);
else

View File

@ -122,6 +122,13 @@ void cChestEntity::UsedBy(cPlayer * a_Player)
void cChestEntity::OpenNewWindow(void)
{
// TODO: cats are an obstruction
if ((GetPosY() + 1 < cChunkDef::Height) && cBlockInfo::IsSolid(GetWorld()->GetBlock(GetPosX(), GetPosY() + 1, GetPosZ())))
{
// Obstruction, don't open
return;
}
// Callback for opening together with neighbor chest:
class cOpenDouble :
public cChestCallback
@ -135,6 +142,12 @@ void cChestEntity::OpenNewWindow(void)
virtual bool Item(cChestEntity * a_Chest) override
{
if ((a_Chest->GetPosY() + 1 < cChunkDef::Height) && cBlockInfo::IsSolid(a_Chest->GetWorld()->GetBlock(a_Chest->GetPosX(), a_Chest->GetPosY() + 1, a_Chest->GetPosZ())))
{
// Obstruction, don't open
return false;
}
// The primary chest should eb the one with lesser X or Z coord:
cChestEntity * Primary = a_Chest;
cChestEntity * Secondary = m_ThisChest;

View File

@ -294,23 +294,24 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
return false;
}
int bx, by, bz;
// Get the coords of the block where to output items:
int OutX, OutY, OutZ;
NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ);
if (!GetOutputBlockPos(Meta, bx, by, bz))
if (!GetOutputBlockPos(Meta, OutX, OutY, OutZ))
{
// Not attached to another container
return false;
}
if (by < 0)
if (OutY < 0)
{
// Cannot output below the zero-th block level
return false;
}
// Convert coords to relative:
int rx = bx - a_Chunk.GetPosX() * cChunkDef::Width;
int rz = bz - a_Chunk.GetPosZ() * cChunkDef::Width;
cChunk * DestChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(rx, rz);
int OutRelX = OutX - a_Chunk.GetPosX() * cChunkDef::Width;
int OutRelZ = OutZ - a_Chunk.GetPosZ() * cChunkDef::Width;
cChunk * DestChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(OutRelX, OutRelZ);
if (DestChunk == NULL)
{
// The destination chunk has been unloaded, don't tick
@ -319,26 +320,32 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
// Call proper moving function, based on the blocktype present at the coords:
bool res = false;
switch (DestChunk->GetBlock(rx, by, rz))
switch (DestChunk->GetBlock(OutRelX, OutY, OutRelZ))
{
case E_BLOCK_CHEST:
{
// Chests have special handling because of double-chests
res = MoveItemsToChest(*DestChunk, bx, by, bz);
res = MoveItemsToChest(*DestChunk, OutX, OutY, OutZ);
break;
}
case E_BLOCK_LIT_FURNACE:
case E_BLOCK_FURNACE:
{
// Furnaces have special handling because of the direction-to-slot relation
res = MoveItemsToFurnace(*DestChunk, bx, by, bz, Meta);
res = MoveItemsToFurnace(*DestChunk, OutX, OutY, OutZ, Meta);
break;
}
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_HOPPER:
{
res = MoveItemsToGrid(*(cBlockEntityWithItems *)DestChunk->GetBlockEntity(bx, by, bz));
cBlockEntityWithItems * BlockEntity = (cBlockEntityWithItems *)DestChunk->GetBlockEntity(OutX, OutY, OutZ);
if (BlockEntity == NULL)
{
LOGWARNING("%s: A block entity was not found where expected at {%d, %d, %d}", __FUNCTION__, OutX, OutY, OutZ);
return false;
}
res = MoveItemsToGrid(*BlockEntity);
break;
}
}
@ -359,7 +366,13 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
/// Moves items from a chest (dblchest) above the hopper into this hopper. Returns true if contents have changed.
bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
{
if (MoveItemsFromGrid(*(cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ)))
cChestEntity * Chest = (cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ);
if (Chest == NULL)
{
LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX, m_PosY + 1, m_PosZ);
return false;
}
if (MoveItemsFromGrid(*Chest))
{
// Moved the item from the chest directly above the hopper
return true;
@ -389,9 +402,17 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
{
continue;
}
if (MoveItemsFromGrid(*(cChestEntity *)Neighbor->GetBlockEntity(x, m_PosY, z)))
Chest = (cChestEntity *)Neighbor->GetBlockEntity(m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z);
if (Chest == NULL)
{
return true;
LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z);
}
else
{
if (MoveItemsFromGrid(*Chest))
{
return true;
}
}
return false;
}
@ -408,7 +429,11 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
bool cHopperEntity::MoveItemsFromFurnace(cChunk & a_Chunk)
{
cFurnaceEntity * Furnace = (cFurnaceEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ);
ASSERT(Furnace != NULL);
if (Furnace == NULL)
{
LOGWARNING("%s: A furnace entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX, m_PosY + 1, m_PosZ);
return false;
}
// Try move from the output slot:
if (MoveItemsFromSlot(*Furnace, cFurnaceEntity::fsOutput, true))
@ -517,7 +542,13 @@ bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_Sl
bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ)
{
// Try the chest directly connected to the hopper:
if (MoveItemsToGrid(*(cChestEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ)))
cChestEntity * Chest = (cChestEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ);
if (Chest == NULL)
{
LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, a_BlockX, a_BlockY, a_BlockZ);
return false;
}
if (MoveItemsToGrid(*Chest))
{
return true;
}
@ -534,19 +565,27 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block
{0, 1},
{0, -1},
} ;
int RelX = a_BlockX - a_Chunk.GetPosX() * cChunkDef::Width;
int RelZ = a_BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width;
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
{
int x = m_RelX + Coords[i].x;
int z = m_RelZ + Coords[i].z;
int x = RelX + Coords[i].x;
int z = RelZ + Coords[i].z;
cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
if (
(Neighbor == NULL) ||
(Neighbor->GetBlock(x, m_PosY + 1, z) != E_BLOCK_CHEST)
(Neighbor->GetBlock(x, a_BlockY, z) != E_BLOCK_CHEST)
)
{
continue;
}
if (MoveItemsToGrid(*(cChestEntity *)Neighbor->GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ)))
Chest = (cChestEntity *)Neighbor->GetBlockEntity(a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z);
if (Chest == NULL)
{
LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d} (%d, %d)", __FUNCTION__, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z, x, z);
continue;
}
if (MoveItemsToGrid(*Chest))
{
return true;
}

View File

@ -9,6 +9,7 @@
cBlockInfo cBlockInfo::ms_Info[256];
static bool g_IsBlockInfoInitialized = false;
@ -43,6 +44,11 @@ cBlockInfo::~cBlockInfo()
cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type)
{
if (!g_IsBlockInfoInitialized)
{
cBlockInfo::Initialize();
g_IsBlockInfoInitialized = true;
}
return ms_Info[a_Type];
}
@ -448,18 +454,3 @@ void cBlockInfo::Initialize(void)
// This is actually just some code that needs to run at program startup, so it is wrapped into a global var's constructor:
class cBlockInfoInitializer
{
public:
cBlockInfoInitializer(void)
{
cBlockInfo::Initialize();
}
} BlockInfoInitializer;

View File

@ -45,9 +45,16 @@ void cBlockDoorHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldIn
void cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
{
UNUSED(a_WorldInterface);
UNUSED(a_BlockFace);
UNUSED(a_CursorX);
UNUSED(a_CursorY);
UNUSED(a_CursorZ);
if (a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_WOODEN_DOOR)
{
ChangeDoor(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
a_Player->GetWorld()->BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0, a_Player->GetClientHandle());
}
}

View File

@ -45,6 +45,7 @@ public:
// Standing aside - use last direction
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, OldMetaData);
}
a_Player->GetWorld()->BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0, a_Player->GetClientHandle());
}

View File

@ -85,6 +85,91 @@
/*
// Tests the meta rotation and mirroring.
// Note that the cMetaRotator needs to have its assert paths disabled for this test to work!
static class cBlockHandlerRotationTester
{
public:
cBlockHandlerRotationTester(void)
{
printf("Performing block handlers test...\n");
for (BLOCKTYPE Type = 0; Type < E_BLOCK_MAX_TYPE_ID; Type++)
{
cBlockHandler * Handler = cBlockInfo::GetHandler(Type);
if (Handler == NULL)
{
printf("NULL handler for block type %d!\n", Type);
continue;
}
AString BlockName = ItemTypeToString(Type);
for (NIBBLETYPE Meta = 0; Meta < 16; Meta++)
{
// Test the CW / CCW rotations:
NIBBLETYPE TestMeta;
TestMeta = Handler->MetaRotateCW(Handler->MetaRotateCW(Handler->MetaRotateCW(Handler->MetaRotateCW(Meta))));
if (TestMeta != Meta)
{
// 4 CW rotations should produce no change in the meta
printf("Handler for blocktype %d (%s) fails CW 4-rotation test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
}
TestMeta = Handler->MetaRotateCCW(Handler->MetaRotateCCW(Handler->MetaRotateCCW(Handler->MetaRotateCCW(Meta))));
if (TestMeta != Meta)
{
// 4 CCW rotations should produce no change in the meta
printf("Handler for blocktype %d (%s) fails CCW 4-rotation test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
}
TestMeta = Handler->MetaRotateCCW(Handler->MetaRotateCW(Meta));
if (TestMeta != Meta)
{
// CCW rotation of a CW rotation should produce no change in the meta
printf("Handler for blocktype %d (%s) fails CCW(CW) rotation test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
}
TestMeta = Handler->MetaRotateCW(Handler->MetaRotateCCW(Meta));
if (TestMeta != Meta)
{
// CW rotation of a CCW rotation should produce no change in the meta
printf("Handler for blocktype %d (%s) fails CW(CCW) rotation test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
}
// Test the mirroring:
TestMeta = Handler->MetaMirrorXY(Handler->MetaMirrorXY(Meta));
if (TestMeta != Meta)
{
// Double-mirroring should produce the same meta:
printf("Handler for blocktype %d (%s) fails XY mirror test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
}
TestMeta = Handler->MetaMirrorXZ(Handler->MetaMirrorXZ(Meta));
if (TestMeta != Meta)
{
// Double-mirroring should produce the same meta:
printf("Handler for blocktype %d (%s) fails XZ mirror test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
}
TestMeta = Handler->MetaMirrorYZ(Handler->MetaMirrorYZ(Meta));
if (TestMeta != Meta)
{
// Double-mirroring should produce the same meta:
printf("Handler for blocktype %d (%s) fails YZ mirror test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
}
// Test mirror-rotating:
TestMeta = Handler->MetaRotateCW(Handler->MetaRotateCW(Handler->MetaMirrorXY(Handler->MetaMirrorYZ(Meta))));
if (TestMeta != Meta)
{
// 2 CW rotations should be the same as XY, YZ mirroring:
printf("Handler for blocktype %d (%s) fails rotation-mirror test for meta %d: got back %d\n", Type, BlockName.c_str(), Meta, TestMeta);
}
}
} // for Type
printf("Block handlers test complete.\n");
}
} g_BlockHandlerRotationTester;
//*/
cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
{
switch(a_BlockType)
@ -175,7 +260,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_QUARTZ_BLOCK: return new cBlockQuartzHandler (a_BlockType);
case E_BLOCK_QUARTZ_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_RAIL: return new cBlockRailHandler (a_BlockType);
case E_BLOCK_REDSTONE_LAMP_ON: return new cBlockRedstoneLampHandler (a_BlockType); // We need this to change pickups to an off lamp; else 1.7+ clients crash
case E_BLOCK_REDSTONE_LAMP_ON: return new cBlockRedstoneLampHandler (a_BlockType);
case E_BLOCK_REDSTONE_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_REDSTONE_ORE_GLOWING: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_REDSTONE_REPEATER_OFF: return new cBlockRedstoneRepeaterHandler(a_BlockType);
@ -207,7 +292,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType);
case E_BLOCK_TNT: return new cBlockTNTHandler (a_BlockType);
case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType);
case E_BLOCK_WALLSIGN: return new cBlockSignHandler (a_BlockType);
case E_BLOCK_WALLSIGN: return new cBlockSignHandler (a_BlockType); // TODO: This needs a special handler
case E_BLOCK_WATER: return new cBlockFluidHandler (a_BlockType);
case E_BLOCK_WOODEN_BUTTON: return new cBlockButtonHandler (a_BlockType);
case E_BLOCK_WOODEN_DOOR: return new cBlockDoorHandler (a_BlockType);

View File

@ -7,12 +7,13 @@
class cBlockLeverHandler :
public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false>
public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false>
{
typedef cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false> super;
typedef cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, false> super;
public:
cBlockLeverHandler(BLOCKTYPE a_BlockType)
: cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false>(a_BlockType)
cBlockLeverHandler(BLOCKTYPE a_BlockType) :
super(a_BlockType)
{
}
@ -132,7 +133,7 @@ public:
case 0x05: return 0x06; // Ground rotation
case 0x06: return 0x05;
default: return super::MetaRotateCCW(a_Meta); // Wall Rotation
default: return super::MetaRotateCW(a_Meta); // Wall Rotation
}
}
} ;

View File

@ -75,13 +75,13 @@ public:
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
{
return (++a_Meta) & 0x0F;
return (a_Meta + 4) & 0x0f;
}
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
{
return (--a_Meta) & 0x0F;
return (a_Meta + 12) & 0x0f;
}
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
@ -90,7 +90,7 @@ public:
// There are 16 meta values which correspond to different directions.
// These values are equated to angles on a circle; 0x08 = 180 degrees.
return (a_Meta < 0x08) ? 0x08 + a_Meta : 0x08 - a_Meta;
return (a_Meta < 0x08) ? (0x08 + a_Meta) : (0x08 - a_Meta);
}

View File

@ -124,6 +124,12 @@ public:
return E_BLOCK_AIR;
}
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
{
// Toggle the 4th bit - up / down:
return (a_Meta ^ 0x08);
}
} ;
@ -167,15 +173,6 @@ public:
ASSERT(!"Unhandled double slab type!");
return "";
}
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
{
NIBBLETYPE OtherMeta = a_Meta & 0x07; // Contains unrelated meta data.
// 8th bit is up/down. 1 right-side-up, 0 is up-side-down.
return (a_Meta & 0x08) ? 0x00 + OtherMeta : 0x01 + OtherMeta;
}
} ;

View File

@ -1616,6 +1616,12 @@ void cChunk::AddBlockEntity(cBlockEntity * a_BlockEntity)
cBlockEntity * cChunk::GetBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ)
{
// Check that the query coords are within chunk bounds:
ASSERT(a_BlockX >= m_PosX * cChunkDef::Width);
ASSERT(a_BlockX < m_PosX * cChunkDef::Width + cChunkDef::Width);
ASSERT(a_BlockZ >= m_PosZ * cChunkDef::Width);
ASSERT(a_BlockZ < m_PosZ * cChunkDef::Width + cChunkDef::Width);
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
{
if (

View File

@ -231,6 +231,9 @@ AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessage
AString cClientHandle::GenerateOfflineUUID(const AString & a_Username)
{
// Online UUIDs are always version 4 (random)
// We use Version 3 (MD5 hash) UUIDs for the offline UUIDs
// This guarantees that they will never collide with an online UUID and can be distinguished.
// Proper format for a version 3 UUID is:
// xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B
@ -253,6 +256,32 @@ AString cClientHandle::GenerateOfflineUUID(const AString & a_Username)
bool cClientHandle::IsUUIDOnline(const AString & a_UUID)
{
// Online UUIDs are always version 4 (random)
// We use Version 3 (MD5 hash) UUIDs for the offline UUIDs
// This guarantees that they will never collide with an online UUID and can be distinguished.
// The version-specifying char is at pos #12 of raw UUID, pos #14 in dashed-UUID.
switch (a_UUID.size())
{
case 32:
{
// This is the UUID format without dashes, the version char is at pos #12:
return (a_UUID[12] == '4');
}
case 36:
{
// This is the UUID format with dashes, the version char is at pos #14:
return (a_UUID[14] == '4');
}
}
return false;
}
void cClientHandle::Kick(const AString & a_Reason)
{
if (m_State >= csAuthenticating) // Don't log pings

View File

@ -63,7 +63,7 @@ public:
const AString & GetIPString(void) const { return m_IPString; }
cPlayer* GetPlayer() { return m_Player; } // tolua_export
cPlayer * GetPlayer(void) { return m_Player; } // tolua_export
const AString & GetUUID(void) const { return m_UUID; } // tolua_export
void SetUUID(const AString & a_UUID) { m_UUID = a_UUID; }
@ -76,9 +76,16 @@ public:
/** Generates an UUID based on the player name provided.
This is used for the offline (non-auth) mode, when there's no UUID source.
Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. */
Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same.
Returns a 36-char UUID (with dashes). */
static AString GenerateOfflineUUID(const AString & a_Username); // tolua_export
/** Returns true if the UUID is generated by online auth, false if it is an offline-generated UUID.
We use Version-3 UUIDs for offline UUIDs, online UUIDs are Version-4, thus we can tell them apart.
Accepts both 32-char and 36-char UUIDs (with and without dashes).
If the string given is not a valid UUID, returns false. */
static bool IsUUIDOnline(const AString & a_UUID); // tolua_export
/** Formats the type of message with the proper color and prefix for sending to the client. **/
static AString FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString & a_AdditionalData);

View File

@ -211,6 +211,17 @@ void cPrefab::Draw(cChunkDesc & a_Dest, const Vector3i & a_Placement, int a_NumR
int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width;
Placement.Move(-ChunkStartX, 0, -ChunkStartZ);
const cBlockArea & Image = m_BlockArea[a_NumRotations];
// If the placement is outside this chunk, bail out:
if (
(Placement.x > cChunkDef::Width) || (Placement.x + Image.GetSizeX() < 0) ||
(Placement.z > cChunkDef::Width) || (Placement.z + Image.GetSizeZ() < 0)
)
{
return;
}
// Write the image:
a_Dest.WriteBlockArea(Image, Placement.x, Placement.y, Placement.z, m_MergeStrategy);
// If requested, draw the floor (from the bottom of the prefab down to the nearest non-air)

View File

@ -59,21 +59,20 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
int RelZ = 0;
BLOCKTYPE Block;
NIBBLETYPE Meta;
cChunk * Chunk;
cChunk * OtherChunk = a_Chunk;
if (a_OtherChunk != NULL)
{
RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width;
RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width;
a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
Chunk = a_OtherChunk;
OtherChunk = a_OtherChunk;
}
else
{
RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
Chunk = a_Chunk;
}
// Every time a block is changed (AddBlock called), we want to go through all lists and check to see if the coordiantes stored within are still valid
@ -92,7 +91,8 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = PoweredBlocks->erase(itr);
Chunk->SetIsRedstoneDirty(true);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
else if (
@ -107,21 +107,23 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
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);
Chunk->SetIsRedstoneDirty(true);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
else if (Block == E_BLOCK_DAYLIGHT_SENSOR)
{
if (!m_World.IsChunkLighted(Chunk->GetPosX(), Chunk->GetPosZ()))
if (!m_World.IsChunkLighted(OtherChunk->GetPosX(), OtherChunk->GetPosZ()))
{
m_World.QueueLightChunk(Chunk->GetPosX(), Chunk->GetPosZ());
m_World.QueueLightChunk(OtherChunk->GetPosX(), OtherChunk->GetPosZ());
}
else
{
if (Chunk->GetTimeAlteredLight(Chunk->GetSkyLight(RelX, a_BlockY + 1, RelZ)) <= 7)
if (OtherChunk->GetTimeAlteredLight(OtherChunk->GetSkyLight(RelX, a_BlockY + 1, RelZ)) <= 7)
{
itr = PoweredBlocks->erase(itr);
Chunk->SetIsRedstoneDirty(true);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
}
@ -139,7 +141,8 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = LinkedPoweredBlocks->erase(itr);
Chunk->SetIsRedstoneDirty(true);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
else if (
@ -153,7 +156,8 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
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);
Chunk->SetIsRedstoneDirty(true);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
}
@ -163,7 +167,8 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer powered through a valid middle block", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = LinkedPoweredBlocks->erase(itr);
Chunk->SetIsRedstoneDirty(true);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
}
@ -343,6 +348,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int
case E_BLOCK_REDSTONE_REPEATER_ON:
{
HandleRedstoneRepeater(dataitr->x, dataitr->y, dataitr->z, dataitr->Data);
break;
}
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
@ -520,8 +526,11 @@ void cIncrementalRedstoneSimulator::HandleFenceGate(int a_RelBlockX, int a_RelBl
{
if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true))
{
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData | 0x4);
m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
if ((MetaData & 0x4) == 0)
{
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData | 0x4);
m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
}
SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true);
}
}
@ -529,8 +538,11 @@ void cIncrementalRedstoneSimulator::HandleFenceGate(int a_RelBlockX, int a_RelBl
{
if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false))
{
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData & 0xFFFFFFFB);
m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
if ((MetaData & 0x4) != 0)
{
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData & ~0x04);
m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0);
}
SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false);
}
}
@ -758,7 +770,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int
void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
{
for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); itr++)
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?
@ -804,7 +816,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
{
m_Chunk->SetBlock(RelBlockX, RelBlockY, RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, Meta);
}
m_RepeatersDelayList->erase(itr);
itr = m_RepeatersDelayList->erase(itr);
}
else
{
@ -813,6 +825,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
// I am confounded to say why. Perhaps optimisation failure.
LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
itr->a_ElapsedTicks++;
itr++;
}
}
}
@ -1072,19 +1085,17 @@ void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_RelBlockX, int a_RelBl
void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
int a_ChunkX, a_ChunkZ;
cChunkDef::BlockToChunk(a_RelBlockX, a_RelBlockZ, a_ChunkX, a_ChunkZ);
int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX, BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ))
if (!m_World.IsChunkLighted(ChunkX, ChunkZ))
{
m_World.QueueLightChunk(a_ChunkX, a_ChunkZ);
m_World.QueueLightChunk(ChunkX, ChunkZ);
}
else
{
int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
NIBBLETYPE SkyLight = m_Chunk->GetTimeAlteredLight(m_World.GetBlockSkyLight(BlockX, a_RelBlockY + 1, BlockZ));
if (SkyLight > 8)
if (m_Chunk->GetTimeAlteredLight(m_World.GetBlockSkyLight(BlockX, a_RelBlockY + 1, BlockZ)) > 8)
{
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
}

View File

@ -14,7 +14,9 @@ cVoronoiMap::cVoronoiMap(int a_Seed, int a_CellSize) :
m_Noise1(a_Seed + 1),
m_Noise2(a_Seed + 2),
m_Noise3(a_Seed + 3),
m_CellSize(a_CellSize)
m_CellSize(a_CellSize),
m_CurrentCellX(9999999), // Cell coords that are definitely out of the range for normal generator, so that the first query will overwrite them
m_CurrentCellZ(9999999)
{
}

View File

@ -345,6 +345,7 @@ void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_C
m_Writer.AddDouble("", a_Entity->GetYaw());
m_Writer.AddDouble("", a_Entity->GetPitch());
m_Writer.EndList();
m_Writer.AddShort("Health", a_Entity->GetHealth());
}
@ -576,7 +577,6 @@ void cNBTChunkSerializer::AddPickupEntity(cPickup * a_Pickup)
m_Writer.BeginCompound("");
AddBasicEntity(a_Pickup, "Item");
AddItem(a_Pickup->GetItem(), -1, "Item");
m_Writer.AddShort("Health", (Int16)(unsigned char)a_Pickup->GetHealth());
m_Writer.AddShort("Age", (Int16)a_Pickup->GetAge());
m_Writer.EndCompound();
}
@ -679,7 +679,6 @@ void cNBTChunkSerializer::AddExpOrbEntity(cExpOrb * a_ExpOrb)
{
m_Writer.BeginCompound("");
AddBasicEntity(a_ExpOrb, "XPOrb");
m_Writer.AddShort("Health", (Int16)(unsigned char)a_ExpOrb->GetHealth());
m_Writer.AddShort("Age", (Int16)a_ExpOrb->GetAge());
m_Writer.AddShort("Value", (Int16)a_ExpOrb->GetReward());
m_Writer.EndCompound();

View File

@ -1461,13 +1461,6 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
return;
}
// Load health:
int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
if (Health > 0)
{
Pickup->SetHealth((int) (a_NBT.GetShort(Health) & 0xFF));
}
// Load age:
int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
@ -1513,13 +1506,6 @@ void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a
return;
}
// Load Health:
int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
if (Health > 0)
{
ExpOrb->SetHealth((int) (a_NBT.GetShort(Health) & 0xFF));
}
// Load Age:
int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
if (Age > 0)
@ -2437,6 +2423,13 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N
}
a_Entity.SetYaw(Rotation[0]);
a_Entity.SetRoll(Rotation[1]);
// Load health:
int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
if (Health > 0)
{
a_Entity.SetHealth(a_NBT.GetShort(Health));
}
return true;
}