Spectators added (#2852)
This commit is contained in:
parent
4e33569110
commit
cb640ffea4
@ -2220,6 +2220,24 @@ return
|
||||
},
|
||||
Notes = "Returns whether the specified block is transparent.",
|
||||
},
|
||||
IsUseableBySpectator =
|
||||
{
|
||||
IsStatic = true,
|
||||
Params =
|
||||
{
|
||||
{
|
||||
Name = "BlockType",
|
||||
Type = "number",
|
||||
},
|
||||
},
|
||||
Returns =
|
||||
{
|
||||
{
|
||||
Type = "boolean",
|
||||
},
|
||||
},
|
||||
Notes = "Returns whether a spectator can interact with the specified block.",
|
||||
},
|
||||
RequiresSpecialTool =
|
||||
{
|
||||
IsStatic = true,
|
||||
@ -10949,6 +10967,16 @@ a_Player:OpenWindow(Window);
|
||||
},
|
||||
Notes = "Returns if the player is able to fly.",
|
||||
},
|
||||
CanMobsTarget =
|
||||
{
|
||||
Returns =
|
||||
{
|
||||
{
|
||||
Type = "boolean",
|
||||
},
|
||||
},
|
||||
Notes = "Returns if the player can be targeted by mobs.",
|
||||
},
|
||||
CloseWindow =
|
||||
{
|
||||
Params =
|
||||
|
@ -492,6 +492,15 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
|
||||
a_Info[E_BLOCK_WOODEN_PRESSURE_PLATE].m_IsSolid = false;
|
||||
|
||||
|
||||
// Blocks, which a spectator is allowed to interact with
|
||||
a_Info[E_BLOCK_BEACON ].m_UseableBySpectator = true;
|
||||
a_Info[E_BLOCK_BREWING_STAND ].m_UseableBySpectator = true;
|
||||
a_Info[E_BLOCK_CHEST ].m_UseableBySpectator = true;
|
||||
a_Info[E_BLOCK_DISPENSER ].m_UseableBySpectator = true;
|
||||
a_Info[E_BLOCK_DROPPER ].m_UseableBySpectator = true;
|
||||
a_Info[E_BLOCK_HOPPER ].m_UseableBySpectator = true;
|
||||
|
||||
|
||||
// Blocks that fully occupy their voxel - used as a guide for torch placeable blocks, amongst other things:
|
||||
a_Info[E_BLOCK_BARRIER ].m_FullyOccupiesVoxel = true;
|
||||
a_Info[E_BLOCK_BEDROCK ].m_FullyOccupiesVoxel = true;
|
||||
|
@ -55,6 +55,9 @@ public:
|
||||
/** Is this block solid (player cannot walk through)? */
|
||||
bool m_IsSolid;
|
||||
|
||||
/** Can a spectator interact with this block */
|
||||
bool m_UseableBySpectator;
|
||||
|
||||
/** Does this block fully occupy its voxel - is it a 'full' block? */
|
||||
bool m_FullyOccupiesVoxel;
|
||||
|
||||
@ -81,6 +84,7 @@ public:
|
||||
inline static bool IsPistonBreakable (BLOCKTYPE a_Type) { return Get(a_Type).m_PistonBreakable; }
|
||||
inline static bool IsSnowable (BLOCKTYPE a_Type) { return Get(a_Type).m_IsSnowable; }
|
||||
inline static bool IsSolid (BLOCKTYPE a_Type) { return Get(a_Type).m_IsSolid; }
|
||||
inline static bool IsUseableBySpectator (BLOCKTYPE a_Type) { return Get(a_Type).m_UseableBySpectator; }
|
||||
inline static bool FullyOccupiesVoxel (BLOCKTYPE a_Type) { return Get(a_Type).m_FullyOccupiesVoxel; }
|
||||
inline static bool CanBeTerraformed (BLOCKTYPE a_Type) { return Get(a_Type).m_CanBeTerraformed; }
|
||||
inline static float GetBlockHeight (BLOCKTYPE a_Type) { return Get(a_Type).m_BlockHeight; }
|
||||
@ -103,6 +107,7 @@ protected:
|
||||
, m_PistonBreakable(false)
|
||||
, m_IsSnowable(false)
|
||||
, m_IsSolid(true)
|
||||
, m_UseableBySpectator(false)
|
||||
, m_FullyOccupiesVoxel(false)
|
||||
, m_CanBeTerraformed(false)
|
||||
, m_BlockHeight(1.0)
|
||||
|
@ -53,6 +53,16 @@ Unfortunately it is very slow, so it is disabled even for regular DEBUG builds.
|
||||
|
||||
|
||||
|
||||
static char ValueToHexDigit(UInt8 digit)
|
||||
{
|
||||
ASSERT(digit < 16);
|
||||
return "0123456789abcdef"[digit];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG_SINGLE_THREAD_ACCESS
|
||||
|
||||
/** Simple RAII class that is used for checking that no two threads are using an object simultanously.
|
||||
@ -517,6 +527,29 @@ bool cByteBuffer::ReadPosition64(int & a_BlockX, int & a_BlockY, int & a_BlockZ)
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::ReadUUID(AString & a_Value)
|
||||
{
|
||||
CHECK_THREAD
|
||||
|
||||
if (!ReadString(a_Value, 16))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
a_Value.resize(32);
|
||||
for (unsigned int i = 15; i < 16; i--)
|
||||
{
|
||||
a_Value[i * 2 + 1] = ValueToHexDigit(a_Value[i] & 0xf);
|
||||
a_Value[i * 2] = ValueToHexDigit(static_cast<UInt8>(a_Value[i]) >> 4);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cByteBuffer::WriteBEInt8(Int8 a_Value)
|
||||
{
|
||||
CHECK_THREAD
|
||||
|
@ -68,6 +68,7 @@ public:
|
||||
bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8
|
||||
bool ReadLEInt (int & a_Value);
|
||||
bool ReadPosition64 (int & a_BlockX, int & a_BlockY, int & a_BlockZ);
|
||||
bool ReadUUID (AString & a_Value); // UUID without dashes
|
||||
|
||||
/** Reads VarInt, assigns it to anything that can be assigned from an UInt64 (unsigned short, char, Byte, double, ...) */
|
||||
template <typename T> bool ReadVarInt(T & a_Value)
|
||||
|
@ -2051,13 +2051,22 @@ bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_
|
||||
|
||||
|
||||
bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult)
|
||||
{
|
||||
return DoWithEntityByID(a_EntityID, std::bind(&cEntityCallback::Item, &a_Callback, std::placeholders::_1), a_CallbackResult);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cLambdaEntityCallback a_Callback, bool & a_CallbackResult)
|
||||
{
|
||||
// The entity list is locked by the parent chunkmap's CS
|
||||
for (cEntityList::iterator itr = m_Entities.begin(), end = m_Entities.end(); itr != end; ++itr)
|
||||
{
|
||||
if (((*itr)->GetUniqueID() == a_EntityID) && ((*itr)->IsTicking()))
|
||||
{
|
||||
a_CallbackResult = a_Callback.Item(*itr);
|
||||
a_CallbackResult = a_Callback(*itr);
|
||||
return true;
|
||||
}
|
||||
} // for itr - m_Entitites[]
|
||||
|
@ -274,6 +274,7 @@ public:
|
||||
|
||||
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. */
|
||||
bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible
|
||||
bool DoWithEntityByID(UInt32 a_EntityID, cLambdaEntityCallback a_Callback, bool & a_CallbackResult); // Lambda version
|
||||
|
||||
/** Calls the callback for each block entity; returns true if all block entities processed, false if the callback aborted by returning true */
|
||||
bool ForEachBlockEntity(cBlockEntityCallback & a_Callback); // Lua-accessible
|
||||
|
@ -1873,6 +1873,15 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
||||
|
||||
|
||||
bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback)
|
||||
{
|
||||
return DoWithEntityByID(a_UniqueID, std::bind(&cEntityCallback::Item, &a_Callback, std::placeholders::_1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, cLambdaEntityCallback a_Callback)
|
||||
{
|
||||
cCSLock Lock(m_CSChunks);
|
||||
bool res = false;
|
||||
|
@ -56,6 +56,8 @@ typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
|
||||
typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
|
||||
typedef cItemCallback<cChunk> cChunkCallback;
|
||||
|
||||
typedef std::function<bool (cEntity *)> cLambdaEntityCallback;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -237,6 +239,7 @@ public:
|
||||
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param.
|
||||
Returns true if entity found and callback returned false. */
|
||||
bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback); // Lua-accessible
|
||||
bool DoWithEntityByID(UInt32 a_EntityID, cLambdaEntityCallback a_Callback); // Lambda version
|
||||
|
||||
/** Calls the callback for each block entity in the specified chunk.
|
||||
Returns true if all block entities processed, false if the callback aborted by returning true. */
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "Entities/Pickup.h"
|
||||
#include "Bindings/PluginManager.h"
|
||||
#include "Entities/Player.h"
|
||||
#include "Entities/Minecart.h"
|
||||
#include "Inventory.h"
|
||||
#include "EffectID.h"
|
||||
#include "BlockEntities/BeaconEntity.h"
|
||||
@ -1412,7 +1413,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
|
||||
cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
|
||||
|
||||
if (BlockHandler->IsUseable() && !m_Player->IsCrouched())
|
||||
if (BlockHandler->IsUseable() && !m_Player->IsCrouched() && (!m_Player->IsGameModeSpectator() || cBlockInfo::IsUseableBySpectator(BlockType)))
|
||||
{
|
||||
if (!PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
|
||||
{
|
||||
@ -1427,6 +1428,12 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
}
|
||||
}
|
||||
|
||||
// Players, who spectate cannot use their items
|
||||
if (m_Player->IsGameModeSpectator())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
short EquippedDamage = Equipped.m_ItemDamage;
|
||||
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemType);
|
||||
|
||||
@ -1557,6 +1564,19 @@ void cClientHandle::HandleSlotSelected(Int16 a_SlotNum)
|
||||
|
||||
|
||||
|
||||
void cClientHandle::HandleSpectate(const AString & a_PlayerUUID)
|
||||
{
|
||||
m_Player->GetWorld()->DoWithPlayerByUUID(a_PlayerUUID, [=](cPlayer * a_ToSpectate)
|
||||
{
|
||||
m_Player->TeleportToEntity(*a_ToSpectate);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::HandleSteerVehicle(float a_Forward, float a_Sideways)
|
||||
{
|
||||
m_Player->SteerVehicle(a_Forward, a_Sideways);
|
||||
@ -1617,6 +1637,17 @@ void cClientHandle::HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick)
|
||||
{
|
||||
// TODO: Let plugins interfere via a hook
|
||||
|
||||
// If the player is a spectator, let him spectate
|
||||
if (m_Player->IsGameModeSpectator() && a_IsLeftClick)
|
||||
{
|
||||
m_Player->GetWorld()->DoWithEntityByID(a_TargetEntityID, [=](cEntity * a_Entity)
|
||||
{
|
||||
m_Player->AttachTo(a_Entity);
|
||||
return true;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// If it is a right click, call the entity's OnRightClicked() handler:
|
||||
if (!a_IsLeftClick)
|
||||
{
|
||||
@ -1625,7 +1656,19 @@ void cClientHandle::HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick)
|
||||
cPlayer & m_Player;
|
||||
virtual bool Item(cEntity * a_Entity) override
|
||||
{
|
||||
if (cPluginManager::Get()->CallHookPlayerRightClickingEntity(m_Player, *a_Entity))
|
||||
if (
|
||||
cPluginManager::Get()->CallHookPlayerRightClickingEntity(m_Player, *a_Entity) ||
|
||||
(
|
||||
m_Player.IsGameModeSpectator() && // Spectators cannot interact with every entity
|
||||
(
|
||||
!a_Entity->IsMinecart() || // They can only interact with minecarts
|
||||
(
|
||||
(reinterpret_cast<cMinecart *>(a_Entity)->GetPayload() != cMinecart::mpChest) && // And only if the type matches a minecart with a chest or
|
||||
(reinterpret_cast<cMinecart *>(a_Entity)->GetPayload() != cMinecart::mpHopper) // a minecart with a hopper
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -2178,6 +2221,15 @@ void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlock
|
||||
|
||||
|
||||
|
||||
void cClientHandle::SendCameraSetTo(const cEntity & a_Entity)
|
||||
{
|
||||
m_Protocol->SendCameraSetTo(a_Entity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData)
|
||||
{
|
||||
cWorld * World = GetPlayer()->GetWorld();
|
||||
|
@ -150,6 +150,7 @@ public: // tolua_export
|
||||
void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage);
|
||||
void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); // tolua_export
|
||||
void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes);
|
||||
void SendCameraSetTo (const cEntity & a_Entity);
|
||||
void SendChat (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = "");
|
||||
void SendChat (const cCompositeChat & a_Message);
|
||||
void SendChatAboveActionBar (const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData = "");
|
||||
@ -336,6 +337,7 @@ public: // tolua_export
|
||||
void HandleRespawn (void);
|
||||
void HandleRightClick (int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem);
|
||||
void HandleSlotSelected (Int16 a_SlotNum);
|
||||
void HandleSpectate (const AString & a_PlayerUUID);
|
||||
void HandleSteerVehicle (float Forward, float Sideways);
|
||||
void HandleTabCompletion (const AString & a_Text);
|
||||
void HandleUpdateSign (
|
||||
|
@ -429,7 +429,7 @@ public:
|
||||
cEntity * GetAttached();
|
||||
|
||||
/** Attaches to the specified entity; detaches from any previous one first */
|
||||
void AttachTo(cEntity * a_AttachTo);
|
||||
virtual void AttachTo(cEntity * a_AttachTo);
|
||||
|
||||
/** Detaches from the currently attached entity, if any */
|
||||
virtual void Detach(void);
|
||||
|
@ -45,7 +45,7 @@ void cExpOrb::SpawnOn(cClientHandle & a_Client)
|
||||
void cExpOrb::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
cPlayer * a_ClosestPlayer(m_World->FindClosestPlayer(Vector3f(GetPosition()), 5));
|
||||
if (a_ClosestPlayer != nullptr)
|
||||
if ((a_ClosestPlayer != nullptr) && (!a_ClosestPlayer->IsGameModeSpectator()))
|
||||
{
|
||||
Vector3f a_PlayerPos(a_ClosestPlayer->GetPosition());
|
||||
a_PlayerPos.y++;
|
||||
|
@ -39,7 +39,15 @@ public:
|
||||
{
|
||||
ASSERT(a_Entity != nullptr);
|
||||
|
||||
if (!a_Entity->IsPlayer() && !a_Entity->IsMob() && !a_Entity->IsMinecart() && !a_Entity->IsBoat())
|
||||
if (
|
||||
(
|
||||
!a_Entity->IsPlayer() ||
|
||||
reinterpret_cast<cPlayer *>(a_Entity)->IsGameModeSpectator() // Spectators doesn't collide with anything
|
||||
) &&
|
||||
!a_Entity->IsMob() &&
|
||||
!a_Entity->IsMinecart() &&
|
||||
!a_Entity->IsBoat()
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -108,7 +108,11 @@ void cPawn::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
} Callback(this);
|
||||
|
||||
// Spectators cannot push entities around
|
||||
if ((!IsPlayer()) || (!reinterpret_cast<cPlayer *>(this)->IsGameModeSpectator()))
|
||||
{
|
||||
m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), GetWidth(), GetHeight()), Callback);
|
||||
}
|
||||
|
||||
super::Tick(a_Dt, a_Chunk);
|
||||
if (!IsTicking())
|
||||
|
@ -208,6 +208,12 @@ bool cPickup::CollectedBy(cPlayer & a_Dest)
|
||||
return false; // Not old enough
|
||||
}
|
||||
|
||||
// If the player is a spectator, he cannot collect anything
|
||||
if (a_Dest.IsGameModeSpectator())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cRoot::Get()->GetPluginManager()->CallHookCollectingPickup(a_Dest, *this))
|
||||
{
|
||||
// LOG("Pickup %d cannot be collected by \"%s\", because a plugin has said no.", m_UniqueID, a_Dest->GetName().c_str());
|
||||
|
@ -250,6 +250,20 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
|
||||
m_Stats.AddValue(statMinutesPlayed, 1);
|
||||
|
||||
// Handle the player detach, when the player is in spectator mode
|
||||
if (
|
||||
(IsGameModeSpectator()) &&
|
||||
(m_AttachedTo != nullptr) &&
|
||||
(
|
||||
(m_AttachedTo->IsDestroyed()) || // Watching entity destruction
|
||||
(m_AttachedTo->GetHealth() <= 0) || // Watching entity dead
|
||||
(IsCrouched()) // Or the player wants to be detached
|
||||
)
|
||||
)
|
||||
{
|
||||
Detach();
|
||||
}
|
||||
|
||||
// Handle a frozen player
|
||||
TickFreezeCode();
|
||||
if (m_IsFrozen)
|
||||
@ -1233,6 +1247,16 @@ bool cPlayer::IsGameModeSpectator(void) const
|
||||
|
||||
|
||||
|
||||
|
||||
bool cPlayer::CanMobsTarget(void) const
|
||||
{
|
||||
return IsGameModeSurvival() || IsGameModeAdventure();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetTeam(cTeam * a_Team)
|
||||
{
|
||||
if (m_Team == a_Team)
|
||||
@ -1344,6 +1368,12 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
|
||||
return;
|
||||
}
|
||||
|
||||
// Detach, if the player is switching from or to the spectator mode
|
||||
if ((m_GameMode == gmSpectator) || (a_GameMode == gmSpectator))
|
||||
{
|
||||
Detach();
|
||||
}
|
||||
|
||||
m_GameMode = a_GameMode;
|
||||
m_ClientHandle->SendGameMode(a_GameMode);
|
||||
|
||||
@ -1379,6 +1409,13 @@ void cPlayer::SetCapabilities()
|
||||
{
|
||||
SetVisible(false);
|
||||
SetCanFly(true);
|
||||
|
||||
// Clear the current dragging item of the player
|
||||
if (GetWindow() != nullptr)
|
||||
{
|
||||
m_DraggingItem.Empty();
|
||||
GetClientHandle()->SendInventorySlot(-1, -1, m_DraggingItem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2476,8 +2513,40 @@ bool cPlayer::PlaceBlocks(const sSetBlockVector & a_Blocks)
|
||||
|
||||
|
||||
|
||||
void cPlayer::AttachTo(cEntity * a_AttachTo)
|
||||
{
|
||||
// Different attach, if this is a spectator
|
||||
if (IsGameModeSpectator())
|
||||
{
|
||||
m_AttachedTo = a_AttachTo;
|
||||
GetClientHandle()->SendCameraSetTo(*m_AttachedTo);
|
||||
return;
|
||||
}
|
||||
|
||||
super::AttachTo(a_AttachTo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::Detach()
|
||||
{
|
||||
if (m_AttachedTo == nullptr)
|
||||
{
|
||||
// The player is not attached to anything. Bail out.
|
||||
return;
|
||||
}
|
||||
|
||||
// Different detach, if this is a spectator
|
||||
if (IsGameModeSpectator())
|
||||
{
|
||||
GetClientHandle()->SendCameraSetTo(*this);
|
||||
TeleportToEntity(*m_AttachedTo);
|
||||
m_AttachedTo = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
super::Detach();
|
||||
int PosX = POSX_TOINT;
|
||||
int PosY = POSY_TOINT;
|
||||
|
@ -193,6 +193,9 @@ public:
|
||||
/** Returns true if the player is in Spectator mode, either explicitly, or by inheriting from current world */
|
||||
bool IsGameModeSpectator(void) const;
|
||||
|
||||
/** Returns true if the player can be targeted by Mobs */
|
||||
bool CanMobsTarget(void) const;
|
||||
|
||||
AString GetIP(void) const { return m_IP; } // tolua_export
|
||||
|
||||
/** Returns the associated team, nullptr if none */
|
||||
@ -518,6 +521,7 @@ public:
|
||||
virtual bool IsSprinting(void) const override { return m_IsSprinting; }
|
||||
virtual bool IsRclking (void) const override { return IsEating() || IsChargingBow(); }
|
||||
|
||||
virtual void AttachTo(cEntity * a_AttachTo) override;
|
||||
virtual void Detach(void) override;
|
||||
|
||||
/** Called by cClientHandle when the client is being destroyed.
|
||||
|
@ -167,7 +167,15 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!a_Entity->IsMob() && !a_Entity->IsMinecart() && !a_Entity->IsPlayer() && !a_Entity->IsBoat())
|
||||
if (
|
||||
!a_Entity->IsMob() &&
|
||||
!a_Entity->IsMinecart() &&
|
||||
(
|
||||
!a_Entity->IsPlayer() ||
|
||||
static_cast<cPlayer *>(a_Entity)->IsGameModeSpectator()
|
||||
) &&
|
||||
!a_Entity->IsBoat()
|
||||
)
|
||||
{
|
||||
// Not an entity that interacts with a projectile
|
||||
return false;
|
||||
|
@ -36,13 +36,16 @@ void cAggressiveMonster::InStateChasing(std::chrono::milliseconds a_Dt, cChunk &
|
||||
|
||||
|
||||
|
||||
void cAggressiveMonster::EventSeePlayer(cEntity * a_Entity, cChunk & a_Chunk)
|
||||
|
||||
void cAggressiveMonster::EventSeePlayer(cPlayer * a_Player, cChunk & a_Chunk)
|
||||
{
|
||||
if (!static_cast<cPlayer *>(a_Entity)->IsGameModeCreative())
|
||||
if (!a_Player->CanMobsTarget())
|
||||
{
|
||||
super::EventSeePlayer(a_Entity, a_Chunk);
|
||||
m_EMState = CHASING;
|
||||
return;
|
||||
}
|
||||
|
||||
super::EventSeePlayer(a_Player, a_Chunk);
|
||||
m_EMState = CHASING;
|
||||
}
|
||||
|
||||
|
||||
|
@ -19,7 +19,8 @@ public:
|
||||
virtual void Tick (std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void InStateChasing(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
virtual void EventSeePlayer(cEntity * a_Player, cChunk & a_Chunk) override;
|
||||
|
||||
virtual void EventSeePlayer(cPlayer * a_Player, cChunk & a_Chunk) override;
|
||||
|
||||
/** Try to perform attack
|
||||
returns true if attack was deemed successful (hit player, fired projectile, creeper exploded, etc.) even if it didn't actually do damage
|
||||
|
@ -23,8 +23,8 @@ public:
|
||||
|
||||
virtual bool Item(cPlayer * a_Player) override
|
||||
{
|
||||
// Don't check players who are in creative gamemode
|
||||
if (a_Player->IsGameModeCreative())
|
||||
// Don't check players who cannot be targeted
|
||||
if (!a_Player->CanMobsTarget())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -124,13 +124,16 @@ void cEnderman::CheckEventSeePlayer(cChunk & a_Chunk)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Callback.GetPlayer()->IsGameModeCreative())
|
||||
if (!Callback.GetPlayer()->CanMobsTarget())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Target the player
|
||||
cMonster::EventSeePlayer(Callback.GetPlayer(), a_Chunk);
|
||||
m_EMState = CHASING;
|
||||
m_bIsScreaming = true;
|
||||
GetWorld()->BroadcastEntityMetadata(*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -265,7 +265,7 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
|
||||
|
||||
if (GetTarget()->IsPlayer())
|
||||
{
|
||||
if (static_cast<cPlayer *>(GetTarget())->IsGameModeCreative())
|
||||
if (!static_cast<cPlayer *>(GetTarget())->CanMobsTarget())
|
||||
{
|
||||
SetTarget(nullptr);
|
||||
m_EMState = IDLE;
|
||||
@ -470,8 +470,14 @@ bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
}
|
||||
|
||||
if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPawn())
|
||||
{
|
||||
if (
|
||||
(!a_TDI.Attacker->IsPlayer()) ||
|
||||
(static_cast<cPlayer *>(a_TDI.Attacker)->CanMobsTarget())
|
||||
)
|
||||
{
|
||||
SetTarget(static_cast<cPawn*>(a_TDI.Attacker));
|
||||
}
|
||||
m_TicksSinceLastDamaged = 0;
|
||||
}
|
||||
return true;
|
||||
@ -617,11 +623,10 @@ void cMonster::CheckEventLostPlayer(void)
|
||||
|
||||
// What to do if player is seen
|
||||
// default to change state to chasing
|
||||
void cMonster::EventSeePlayer(cEntity * a_SeenPlayer, cChunk & a_Chunk)
|
||||
void cMonster::EventSeePlayer(cPlayer * a_SeenPlayer, cChunk & a_Chunk)
|
||||
{
|
||||
UNUSED(a_Chunk);
|
||||
ASSERT(a_SeenPlayer->IsPlayer());
|
||||
SetTarget(static_cast<cPawn*>(a_SeenPlayer));
|
||||
SetTarget(a_SeenPlayer);
|
||||
}
|
||||
|
||||
|
||||
|
@ -72,7 +72,7 @@ public:
|
||||
// tolua_end
|
||||
|
||||
virtual void CheckEventSeePlayer(cChunk & a_Chunk);
|
||||
virtual void EventSeePlayer(cEntity * a_Entity, cChunk & a_Chunk);
|
||||
virtual void EventSeePlayer(cPlayer * a_Player, cChunk & a_Chunk);
|
||||
|
||||
/** Reads the monster configuration for the specified monster name and assigns it to this object. */
|
||||
void GetMonsterConfig(const AString & a_Name);
|
||||
|
@ -28,7 +28,7 @@ bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
|
||||
if ((GetTarget() != nullptr) && (GetTarget()->IsPlayer()))
|
||||
{
|
||||
if (!static_cast<cPlayer *>(GetTarget())->IsGameModeCreative())
|
||||
if (static_cast<cPlayer *>(GetTarget())->CanMobsTarget())
|
||||
{
|
||||
m_EMState = CHASING;
|
||||
}
|
||||
@ -39,7 +39,8 @@ bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
|
||||
|
||||
|
||||
void cPassiveAggressiveMonster::EventSeePlayer(cEntity *, cChunk & a_Chunk)
|
||||
|
||||
void cPassiveAggressiveMonster::EventSeePlayer(cPlayer *, cChunk & a_Chunk)
|
||||
{
|
||||
// don't do anything, neutral mobs don't react to just seeing the player
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ public:
|
||||
cPassiveAggressiveMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
|
||||
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
virtual void EventSeePlayer(cEntity *, cChunk & a_Chunk) override;
|
||||
virtual void EventSeePlayer(cPlayer *, cChunk & a_Chunk) override;
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -35,7 +35,7 @@ void cSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
||||
|
||||
|
||||
|
||||
void cSpider::EventSeePlayer(cEntity * a_Entity, cChunk & a_Chunk)
|
||||
void cSpider::EventSeePlayer(cPlayer * a_Player, cChunk & a_Chunk)
|
||||
{
|
||||
if (!GetWorld()->IsChunkLighted(GetChunkX(), GetChunkZ()))
|
||||
{
|
||||
@ -48,9 +48,9 @@ void cSpider::EventSeePlayer(cEntity * a_Entity, cChunk & a_Chunk)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!static_cast<cPlayer *>(a_Entity)->IsGameModeCreative() && (Chunk->GetSkyLightAltered(Rel.x, Rel.y, Rel.z) <= 9))
|
||||
if (a_Player->CanMobsTarget() && (Chunk->GetSkyLightAltered(Rel.x, Rel.y, Rel.z) <= 9))
|
||||
{
|
||||
super::EventSeePlayer(a_Entity, a_Chunk);
|
||||
super::EventSeePlayer(a_Player, a_Chunk);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
CLASS_PROTODEF(cSpider)
|
||||
|
||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
|
||||
virtual void EventSeePlayer(cEntity *, cChunk & a_Chunk) override;
|
||||
virtual void EventSeePlayer(cPlayer *, cChunk & a_Chunk) override;
|
||||
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||
} ;
|
||||
|
||||
|
@ -69,6 +69,7 @@ public:
|
||||
virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) = 0;
|
||||
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
|
||||
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) = 0;
|
||||
virtual void SendCameraSetTo (const cEntity & a_Entity) = 0;
|
||||
virtual void SendChat (const AString & a_Message, eChatType a_Type) = 0;
|
||||
virtual void SendChat (const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) = 0;
|
||||
virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) = 0;
|
||||
|
@ -246,6 +246,16 @@ void cProtocol180::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV
|
||||
|
||||
|
||||
|
||||
void cProtocol180::SendCameraSetTo(const cEntity & a_Entity)
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x43); // Camera Packet (Attach the camera of a player at another entity in spectator mode)
|
||||
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol180::SendChat(const AString & a_Message, eChatType a_Type)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
@ -2038,6 +2048,7 @@ bool cProtocol180::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
|
||||
case 0x15: HandlePacketClientSettings (a_ByteBuffer); return true;
|
||||
case 0x16: HandlePacketClientStatus (a_ByteBuffer); return true;
|
||||
case 0x17: HandlePacketPluginMessage (a_ByteBuffer); return true;
|
||||
case 0x18: HandlePacketSpectate (a_ByteBuffer); return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2495,6 +2506,21 @@ void cProtocol180::HandlePacketSlotSelect(cByteBuffer & a_ByteBuffer)
|
||||
|
||||
|
||||
|
||||
void cProtocol180::HandlePacketSpectate(cByteBuffer &a_ByteBuffer)
|
||||
{
|
||||
AString playerUUID;
|
||||
if (!a_ByteBuffer.ReadUUID(playerUUID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Client->HandleSpectate(playerUUID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol180::HandlePacketSteerVehicle(cByteBuffer & a_ByteBuffer)
|
||||
{
|
||||
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Sideways);
|
||||
|
@ -65,6 +65,7 @@ public:
|
||||
virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
|
||||
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
|
||||
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
|
||||
virtual void SendCameraSetTo (const cEntity & a_Entity) override;
|
||||
virtual void SendChat (const AString & a_Message, eChatType a_Type) override;
|
||||
virtual void SendChat (const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) override;
|
||||
virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override;
|
||||
@ -210,6 +211,7 @@ protected:
|
||||
void HandlePacketPlayerPosLook (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketPluginMessage (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketSlotSelect (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketSpectate (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketSteerVehicle (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketTabComplete (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketUpdateSign (cByteBuffer & a_ByteBuffer);
|
||||
|
@ -255,6 +255,16 @@ void cProtocol190::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV
|
||||
|
||||
|
||||
|
||||
void cProtocol190::SendCameraSetTo(const cEntity & a_Entity)
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x36); // Camera Packet (Attach the camera of a player at another entity in spectator mode)
|
||||
Pkt.WriteVarInt32(a_Entity.GetUniqueID());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol190::SendChat(const AString & a_Message, eChatType a_Type)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
@ -2058,7 +2068,7 @@ bool cProtocol190::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
|
||||
case 0x18: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true;
|
||||
case 0x19: HandlePacketUpdateSign (a_ByteBuffer); return true;
|
||||
case 0x1a: HandlePacketAnimation (a_ByteBuffer); return true;
|
||||
case 0x1b: break; // Spectate?
|
||||
case 0x1b: HandlePacketSpectate (a_ByteBuffer); return true;
|
||||
case 0x1c: HandlePacketBlockPlace (a_ByteBuffer); return true;
|
||||
case 0x1d: HandlePacketUseItem (a_ByteBuffer); return true;
|
||||
}
|
||||
@ -2551,6 +2561,21 @@ void cProtocol190::HandlePacketSlotSelect(cByteBuffer & a_ByteBuffer)
|
||||
|
||||
|
||||
|
||||
void cProtocol190::HandlePacketSpectate(cByteBuffer & a_ByteBuffer)
|
||||
{
|
||||
AString playerUUID;
|
||||
if (!a_ByteBuffer.ReadUUID(playerUUID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Client->HandleSpectate(playerUUID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol190::HandlePacketSteerVehicle(cByteBuffer & a_ByteBuffer)
|
||||
{
|
||||
HANDLE_READ(a_ByteBuffer, ReadBEFloat, float, Sideways);
|
||||
|
@ -71,6 +71,7 @@ public:
|
||||
virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
|
||||
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
|
||||
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
|
||||
virtual void SendCameraSetTo (const cEntity & a_Entity) override;
|
||||
virtual void SendChat (const AString & a_Message, eChatType a_Type) override;
|
||||
virtual void SendChat (const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) override;
|
||||
virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override;
|
||||
@ -219,6 +220,7 @@ protected:
|
||||
void HandlePacketPluginMessage (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketSlotSelect (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketSteerVehicle (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketSpectate (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketTabComplete (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketUpdateSign (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketUseEntity (cByteBuffer & a_ByteBuffer);
|
||||
|
@ -170,6 +170,15 @@ void cProtocolRecognizer::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSe
|
||||
|
||||
|
||||
|
||||
void cProtocolRecognizer::SendCameraSetTo(const cEntity & a_Entity)
|
||||
{
|
||||
ASSERT(m_Protocol != nullptr);
|
||||
m_Protocol->SendCameraSetTo(a_Entity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocolRecognizer::SendChat(const AString & a_Message, eChatType a_Type)
|
||||
{
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
virtual void SendBlockBreakAnim (UInt32 a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) override;
|
||||
virtual void SendBlockChange (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override;
|
||||
virtual void SendBlockChanges (int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) override;
|
||||
virtual void SendCameraSetTo (const cEntity & a_Entity) override;
|
||||
virtual void SendChat (const AString & a_Message, eChatType a_Type) override;
|
||||
virtual void SendChat (const cCompositeChat & a_Message, eChatType a_Type, bool a_ShouldUseChatPrefixes) override;
|
||||
virtual void SendChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) override;
|
||||
|
@ -58,6 +58,14 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA
|
||||
return;
|
||||
}
|
||||
|
||||
if (a_Player.IsGameModeSpectator())
|
||||
{
|
||||
// Block the action of the player and make sure, the inventory doesn't get out of sync
|
||||
a_Player.GetClientHandle()->SendInventorySlot(-1, -1, cItem()); // Reset the dragged item
|
||||
SetSlot(a_SlotNum, a_Player, *GetSlot(a_SlotNum, a_Player)); // Update the current slot
|
||||
return;
|
||||
}
|
||||
|
||||
switch (a_ClickAction)
|
||||
{
|
||||
case caShiftLeftClick:
|
||||
|
@ -3132,6 +3132,15 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCa
|
||||
|
||||
|
||||
bool cWorld::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback)
|
||||
{
|
||||
return DoWithPlayerByUUID(a_PlayerUUID, std::bind(&cPlayerListCallback::Item, &a_Callback, std::placeholders::_1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWorld::DoWithPlayerByUUID(const AString & a_PlayerUUID, cLambdaPlayerCallback a_Callback)
|
||||
{
|
||||
cCSLock Lock(m_CSPlayers);
|
||||
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
|
||||
@ -3142,7 +3151,7 @@ bool cWorld::DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallbac
|
||||
}
|
||||
if ((*itr)->GetUUID() == a_PlayerUUID)
|
||||
{
|
||||
return a_Callback.Item(*itr);
|
||||
return a_Callback(*itr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -3240,6 +3249,15 @@ bool cWorld::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_
|
||||
|
||||
|
||||
bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback)
|
||||
{
|
||||
return DoWithEntityByID(a_UniqueID, std::bind(&cEntityCallback::Item, &a_Callback, std::placeholders::_1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, cLambdaEntityCallback a_Callback)
|
||||
{
|
||||
// First check the entities-to-add:
|
||||
{
|
||||
@ -3248,7 +3266,7 @@ bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback)
|
||||
{
|
||||
if (ent->GetUniqueID() == a_UniqueID)
|
||||
{
|
||||
a_Callback.Item(ent);
|
||||
a_Callback(ent);
|
||||
return true;
|
||||
}
|
||||
} // for ent - m_EntitiesToAdd[]
|
||||
|
@ -78,6 +78,8 @@ typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
|
||||
typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
|
||||
typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
|
||||
|
||||
typedef std::function<bool (cPlayer *)> cLambdaPlayerCallback;
|
||||
typedef std::function<bool (cEntity *)> cLambdaEntityCallback;
|
||||
|
||||
|
||||
|
||||
@ -288,6 +290,7 @@ public:
|
||||
|
||||
/** Finds the player over his uuid and calls the callback */
|
||||
bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
|
||||
bool DoWithPlayerByUUID(const AString & a_PlayerUUID, cLambdaPlayerCallback a_Callback); // Lambda version
|
||||
|
||||
void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player
|
||||
|
||||
@ -313,6 +316,7 @@ public:
|
||||
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param.
|
||||
Returns true if entity found and callback returned false. */
|
||||
bool DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
|
||||
bool DoWithEntityByID(UInt32 a_UniqueID, cLambdaEntityCallback a_Callback); // Lambda version
|
||||
|
||||
/** Compares clients of two chunks, calls the callback accordingly */
|
||||
void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback);
|
||||
|
Loading…
Reference in New Issue
Block a user