Clients are now ticked in cServer first, then in cWorld once they get assigned a world.
This commit is contained in:
parent
27d0c9aef2
commit
9020dc9932
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
** Lua binding: AllToLua
|
** Lua binding: AllToLua
|
||||||
** Generated automatically by tolua++-1.0.92 on 08/12/13 08:16:46.
|
** Generated automatically by tolua++-1.0.92 on 08/12/13 21:48:05.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
@ -8237,40 +8237,6 @@ static int tolua_AllToLua_Lua__cEntity_cEntity__IsRclking00(lua_State* tolua_S)
|
|||||||
}
|
}
|
||||||
#endif //#ifndef TOLUA_DISABLE
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
/* method: Initialize of class cPlayer */
|
|
||||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_Initialize00
|
|
||||||
static int tolua_AllToLua_cPlayer_Initialize00(lua_State* tolua_S)
|
|
||||||
{
|
|
||||||
#ifndef TOLUA_RELEASE
|
|
||||||
tolua_Error tolua_err;
|
|
||||||
if (
|
|
||||||
!tolua_isusertype(tolua_S,1,"cPlayer",0,&tolua_err) ||
|
|
||||||
!tolua_isusertype(tolua_S,2,"cWorld",0,&tolua_err) ||
|
|
||||||
!tolua_isnoobj(tolua_S,3,&tolua_err)
|
|
||||||
)
|
|
||||||
goto tolua_lerror;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0);
|
|
||||||
cWorld* a_World = ((cWorld*) tolua_tousertype(tolua_S,2,0));
|
|
||||||
#ifndef TOLUA_RELEASE
|
|
||||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Initialize'", NULL);
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
bool tolua_ret = (bool) self->Initialize(a_World);
|
|
||||||
tolua_pushboolean(tolua_S,(bool)tolua_ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
#ifndef TOLUA_RELEASE
|
|
||||||
tolua_lerror:
|
|
||||||
tolua_error(tolua_S,"#ferror in function 'Initialize'.",&tolua_err);
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif //#ifndef TOLUA_DISABLE
|
|
||||||
|
|
||||||
/* method: GetEyeHeight of class cPlayer */
|
/* method: GetEyeHeight of class cPlayer */
|
||||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetEyeHeight00
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetEyeHeight00
|
||||||
static int tolua_AllToLua_cPlayer_GetEyeHeight00(lua_State* tolua_S)
|
static int tolua_AllToLua_cPlayer_GetEyeHeight00(lua_State* tolua_S)
|
||||||
@ -10186,17 +10152,6 @@ static int tolua_AllToLua_cPlayer_IsSubmerged00(lua_State* tolua_S)
|
|||||||
|
|
||||||
class Lua__cPlayer : public cPlayer, public ToluaBase {
|
class Lua__cPlayer : public cPlayer, public ToluaBase {
|
||||||
public:
|
public:
|
||||||
bool Initialize( cWorld* a_World) {
|
|
||||||
if (push_method("Initialize", tolua_AllToLua_cPlayer_Initialize00)) {
|
|
||||||
tolua_pushusertype(lua_state, (void*)a_World, "cWorld");
|
|
||||||
ToluaBase::dbcall(lua_state, 2, 1);
|
|
||||||
bool tolua_ret = ( bool )tolua_toboolean(lua_state, -1, 0);
|
|
||||||
lua_pop(lua_state, 1);
|
|
||||||
return tolua_ret;
|
|
||||||
} else {
|
|
||||||
return ( bool ) cPlayer:: Initialize(a_World);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
void MoveTo( const Vector3d& a_NewPos) {
|
void MoveTo( const Vector3d& a_NewPos) {
|
||||||
if (push_method("MoveTo", tolua_AllToLua_cPlayer_MoveTo00)) {
|
if (push_method("MoveTo", tolua_AllToLua_cPlayer_MoveTo00)) {
|
||||||
tolua_pushusertype(lua_state, (void*)&a_NewPos, "const Vector3d");
|
tolua_pushusertype(lua_state, (void*)&a_NewPos, "const Vector3d");
|
||||||
@ -10418,9 +10373,6 @@ public:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
bool cPlayer__Initialize( cWorld* a_World) {
|
|
||||||
return ( bool )cPlayer::Initialize(a_World);
|
|
||||||
};
|
|
||||||
void cPlayer__MoveTo( const Vector3d& a_NewPos) {
|
void cPlayer__MoveTo( const Vector3d& a_NewPos) {
|
||||||
return ( void )cPlayer::MoveTo(a_NewPos);
|
return ( void )cPlayer::MoveTo(a_NewPos);
|
||||||
};
|
};
|
||||||
@ -10522,40 +10474,6 @@ static int tolua_AllToLua_Lua__cPlayer_tolua__set_instance00(lua_State* tolua_S)
|
|||||||
}
|
}
|
||||||
#endif //#ifndef TOLUA_DISABLE
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
/* method: cPlayer__Initialize of class Lua__cPlayer */
|
|
||||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_Lua__cPlayer_cPlayer__Initialize00
|
|
||||||
static int tolua_AllToLua_Lua__cPlayer_cPlayer__Initialize00(lua_State* tolua_S)
|
|
||||||
{
|
|
||||||
#ifndef TOLUA_RELEASE
|
|
||||||
tolua_Error tolua_err;
|
|
||||||
if (
|
|
||||||
!tolua_isusertype(tolua_S,1,"Lua__cPlayer",0,&tolua_err) ||
|
|
||||||
!tolua_isusertype(tolua_S,2,"cWorld",0,&tolua_err) ||
|
|
||||||
!tolua_isnoobj(tolua_S,3,&tolua_err)
|
|
||||||
)
|
|
||||||
goto tolua_lerror;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
Lua__cPlayer* self = (Lua__cPlayer*) tolua_tousertype(tolua_S,1,0);
|
|
||||||
cWorld* a_World = ((cWorld*) tolua_tousertype(tolua_S,2,0));
|
|
||||||
#ifndef TOLUA_RELEASE
|
|
||||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'cPlayer__Initialize'", NULL);
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
bool tolua_ret = (bool) self->cPlayer__Initialize(a_World);
|
|
||||||
tolua_pushboolean(tolua_S,(bool)tolua_ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
#ifndef TOLUA_RELEASE
|
|
||||||
tolua_lerror:
|
|
||||||
tolua_error(tolua_S,"#ferror in function 'cPlayer__Initialize'.",&tolua_err);
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif //#ifndef TOLUA_DISABLE
|
|
||||||
|
|
||||||
/* method: cPlayer__MoveTo of class Lua__cPlayer */
|
/* method: cPlayer__MoveTo of class Lua__cPlayer */
|
||||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_Lua__cPlayer_cPlayer__MoveTo00
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_Lua__cPlayer_cPlayer__MoveTo00
|
||||||
static int tolua_AllToLua_Lua__cPlayer_cPlayer__MoveTo00(lua_State* tolua_S)
|
static int tolua_AllToLua_Lua__cPlayer_cPlayer__MoveTo00(lua_State* tolua_S)
|
||||||
@ -29625,7 +29543,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
|||||||
tolua_constant(tolua_S,"EATING_TICKS",cPlayer::EATING_TICKS);
|
tolua_constant(tolua_S,"EATING_TICKS",cPlayer::EATING_TICKS);
|
||||||
tolua_constant(tolua_S,"MAX_AIR_LEVEL",cPlayer::MAX_AIR_LEVEL);
|
tolua_constant(tolua_S,"MAX_AIR_LEVEL",cPlayer::MAX_AIR_LEVEL);
|
||||||
tolua_constant(tolua_S,"DROWNING_TICKS",cPlayer::DROWNING_TICKS);
|
tolua_constant(tolua_S,"DROWNING_TICKS",cPlayer::DROWNING_TICKS);
|
||||||
tolua_function(tolua_S,"Initialize",tolua_AllToLua_cPlayer_Initialize00);
|
|
||||||
tolua_function(tolua_S,"GetEyeHeight",tolua_AllToLua_cPlayer_GetEyeHeight00);
|
tolua_function(tolua_S,"GetEyeHeight",tolua_AllToLua_cPlayer_GetEyeHeight00);
|
||||||
tolua_function(tolua_S,"GetEyePosition",tolua_AllToLua_cPlayer_GetEyePosition00);
|
tolua_function(tolua_S,"GetEyePosition",tolua_AllToLua_cPlayer_GetEyePosition00);
|
||||||
tolua_function(tolua_S,"IsOnGround",tolua_AllToLua_cPlayer_IsOnGround00);
|
tolua_function(tolua_S,"IsOnGround",tolua_AllToLua_cPlayer_IsOnGround00);
|
||||||
@ -29688,7 +29605,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
|||||||
tolua_cclass(tolua_S,"Lua__cPlayer","Lua__cPlayer","cPlayer",NULL);
|
tolua_cclass(tolua_S,"Lua__cPlayer","Lua__cPlayer","cPlayer",NULL);
|
||||||
tolua_beginmodule(tolua_S,"Lua__cPlayer");
|
tolua_beginmodule(tolua_S,"Lua__cPlayer");
|
||||||
tolua_function(tolua_S,"tolua__set_instance",tolua_AllToLua_Lua__cPlayer_tolua__set_instance00);
|
tolua_function(tolua_S,"tolua__set_instance",tolua_AllToLua_Lua__cPlayer_tolua__set_instance00);
|
||||||
tolua_function(tolua_S,"cPlayer__Initialize",tolua_AllToLua_Lua__cPlayer_cPlayer__Initialize00);
|
|
||||||
tolua_function(tolua_S,"cPlayer__MoveTo",tolua_AllToLua_Lua__cPlayer_cPlayer__MoveTo00);
|
tolua_function(tolua_S,"cPlayer__MoveTo",tolua_AllToLua_Lua__cPlayer_cPlayer__MoveTo00);
|
||||||
tolua_function(tolua_S,"cPlayer__IsSwimming",tolua_AllToLua_Lua__cPlayer_cPlayer__IsSwimming00);
|
tolua_function(tolua_S,"cPlayer__IsSwimming",tolua_AllToLua_Lua__cPlayer_cPlayer__IsSwimming00);
|
||||||
tolua_function(tolua_S,"cPlayer__IsSubmerged",tolua_AllToLua_Lua__cPlayer_cPlayer__IsSubmerged00);
|
tolua_function(tolua_S,"cPlayer__IsSubmerged",tolua_AllToLua_Lua__cPlayer_cPlayer__IsSubmerged00);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
** Lua binding: AllToLua
|
** Lua binding: AllToLua
|
||||||
** Generated automatically by tolua++-1.0.92 on 08/12/13 08:16:46.
|
** Generated automatically by tolua++-1.0.92 on 08/12/13 21:48:06.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Exported function */
|
/* Exported function */
|
||||||
|
@ -170,13 +170,21 @@ cClientHandle::~cClientHandle()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cClientHandle::Destroy()
|
void cClientHandle::Destroy(void)
|
||||||
{
|
{
|
||||||
// Setting m_bDestroyed was moved to the bottom of Destroy(),
|
{
|
||||||
// otherwise the destructor may be called within another thread before the client is removed from chunks
|
cCSLock Lock(m_CSDestroyingState);
|
||||||
// http://forum.mc-server.org/showthread.php?tid=366
|
if (m_State >= csDestroying)
|
||||||
|
{
|
||||||
|
// Already called
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_State = csDestroying;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG:
|
||||||
|
LOGD("%s: client %p, \"%s\"", __FUNCTION__, this, m_Username.c_str());
|
||||||
|
|
||||||
m_State = csDestroying;
|
|
||||||
if ((m_Player != NULL) && (m_Player->GetWorld() != NULL))
|
if ((m_Player != NULL) && (m_Player->GetWorld() != NULL))
|
||||||
{
|
{
|
||||||
RemoveFromAllChunks();
|
RemoveFromAllChunks();
|
||||||
@ -253,9 +261,8 @@ void cClientHandle::Authenticate(void)
|
|||||||
SendGameMode(m_Player->GetGameMode());
|
SendGameMode(m_Player->GetGameMode());
|
||||||
|
|
||||||
m_Player->Initialize(World);
|
m_Player->Initialize(World);
|
||||||
StreamChunks();
|
m_State = csAuthenticated;
|
||||||
m_State = csDownloadingWorld;
|
|
||||||
|
|
||||||
// Broadcast this player's spawning to all other players in the same chunk
|
// Broadcast this player's spawning to all other players in the same chunk
|
||||||
m_Player->GetWorld()->BroadcastSpawnEntity(*m_Player, this);
|
m_Player->GetWorld()->BroadcastSpawnEntity(*m_Player, this);
|
||||||
|
|
||||||
@ -1342,6 +1349,20 @@ bool cClientHandle::CheckBlockInteractionsRate(void)
|
|||||||
|
|
||||||
void cClientHandle::Tick(float a_Dt)
|
void cClientHandle::Tick(float a_Dt)
|
||||||
{
|
{
|
||||||
|
// Process received network data:
|
||||||
|
AString IncomingData;
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSIncomingData);
|
||||||
|
std::swap(IncomingData, m_IncomingData);
|
||||||
|
}
|
||||||
|
m_Protocol->DataReceived(IncomingData.data(), IncomingData.size());
|
||||||
|
|
||||||
|
if (m_State == csAuthenticated)
|
||||||
|
{
|
||||||
|
StreamChunks();
|
||||||
|
m_State = csDownloadingWorld;
|
||||||
|
}
|
||||||
|
|
||||||
m_TimeSinceLastPacket += a_Dt;
|
m_TimeSinceLastPacket += a_Dt;
|
||||||
if (m_TimeSinceLastPacket > 30000.f) // 30 seconds time-out
|
if (m_TimeSinceLastPacket > 30000.f) // 30 seconds time-out
|
||||||
{
|
{
|
||||||
@ -2118,30 +2139,10 @@ void cClientHandle::PacketError(unsigned char a_PacketType)
|
|||||||
|
|
||||||
void cClientHandle::DataReceived(const char * a_Data, int a_Size)
|
void cClientHandle::DataReceived(const char * a_Data, int a_Size)
|
||||||
{
|
{
|
||||||
// Data is received from the client, hand it off to the protocol:
|
// Data is received from the client, store it in the buffer to be processed by the Tick thread:
|
||||||
if ((m_Player != NULL) && (m_Player->GetWorld() != NULL))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
_X: Lock the world, so that plugins reacting to protocol events have already the chunkmap locked.
|
|
||||||
There was a possibility of a deadlock between SocketThreads and TickThreads, resulting from each
|
|
||||||
holding one CS an requesting the other one (ChunkMap CS vs Plugin CS) (FS #375). To break this, it's
|
|
||||||
sufficient to break any of the four Coffman conditions for a deadlock. We'll solve this by requiring
|
|
||||||
the ChunkMap CS for all SocketThreads operations before they lock the PluginCS - thus creating a kind
|
|
||||||
of a lock hierarchy. However, this incurs a performance penalty, we're de facto locking the chunkmap
|
|
||||||
for each incoming packet. A better, but more involved solutin would be to lock the chunkmap only when
|
|
||||||
the incoming packet really has a plugin CS lock request.
|
|
||||||
Also, it is still possible for a packet to slip through - when a player still doesn't have their world
|
|
||||||
assigned and several packets arrive at once.
|
|
||||||
*/
|
|
||||||
cWorld::cLock(*m_Player->GetWorld());
|
|
||||||
|
|
||||||
m_Protocol->DataReceived(a_Data, a_Size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_Protocol->DataReceived(a_Data, a_Size);
|
|
||||||
}
|
|
||||||
m_TimeSinceLastPacket = 0;
|
m_TimeSinceLastPacket = 0;
|
||||||
|
cCSLock Lock(m_CSIncomingData);
|
||||||
|
m_IncomingData.append(a_Data, a_Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -212,11 +212,12 @@ private:
|
|||||||
|
|
||||||
cProtocol * m_Protocol;
|
cProtocol * m_Protocol;
|
||||||
|
|
||||||
|
cCriticalSection m_CSIncomingData;
|
||||||
|
AString m_IncomingData;
|
||||||
|
|
||||||
cCriticalSection m_CSOutgoingData;
|
cCriticalSection m_CSOutgoingData;
|
||||||
cByteBuffer m_OutgoingData;
|
cByteBuffer m_OutgoingData;
|
||||||
AString m_OutgoingDataOverflow; //< For data that didn't fit into the m_OutgoingData ringbuffer temporarily
|
AString m_OutgoingDataOverflow; ///< For data that didn't fit into the m_OutgoingData ringbuffer temporarily
|
||||||
|
|
||||||
cCriticalSection m_CriticalSection;
|
|
||||||
|
|
||||||
Vector3d m_ConfirmPosition;
|
Vector3d m_ConfirmPosition;
|
||||||
|
|
||||||
@ -252,18 +253,22 @@ private:
|
|||||||
|
|
||||||
enum eState
|
enum eState
|
||||||
{
|
{
|
||||||
csConnected, // The client has just connected, waiting for their handshake / login
|
csConnected, ///< The client has just connected, waiting for their handshake / login
|
||||||
csAuthenticating, // The client has logged in, waiting for external authentication
|
csAuthenticating, ///< The client has logged in, waiting for external authentication
|
||||||
csDownloadingWorld, // The client is waiting for chunks, we're waiting for the loader to provide and send them
|
csAuthenticated, ///< The client has been authenticated, will start streaming chunks in the next tick
|
||||||
csConfirmingPos, // The client has been sent the position packet, waiting for them to repeat the position back
|
csDownloadingWorld, ///< The client is waiting for chunks, we're waiting for the loader to provide and send them
|
||||||
csPlaying, // Normal gameplay
|
csConfirmingPos, ///< The client has been sent the position packet, waiting for them to repeat the position back
|
||||||
csDestroying, // The client is being destroyed, don't queue any more packets / don't add to chunks
|
csPlaying, ///< Normal gameplay
|
||||||
csDestroyed, // The client has been destroyed, the destructor is to be called from the owner thread
|
csDestroying, ///< The client is being destroyed, don't queue any more packets / don't add to chunks
|
||||||
|
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
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
eState m_State;
|
eState m_State;
|
||||||
|
|
||||||
|
/// m_State needs to be locked in the Destroy() function so that the destruction code doesn't run twice on two different threads
|
||||||
|
cCriticalSection m_CSDestroyingState;
|
||||||
|
|
||||||
bool m_bKeepThreadGoing;
|
bool m_bKeepThreadGoing;
|
||||||
|
|
||||||
|
@ -127,6 +127,8 @@ cPlayer::~cPlayer(void)
|
|||||||
|
|
||||||
bool cPlayer::Initialize(cWorld * a_World)
|
bool cPlayer::Initialize(cWorld * a_World)
|
||||||
{
|
{
|
||||||
|
ASSERT(a_World != NULL);
|
||||||
|
|
||||||
if (super::Initialize(a_World))
|
if (super::Initialize(a_World))
|
||||||
{
|
{
|
||||||
// Remove the client handle from the server, it will be ticked from this object from now on
|
// Remove the client handle from the server, it will be ticked from this object from now on
|
||||||
@ -148,6 +150,7 @@ bool cPlayer::Initialize(cWorld * a_World)
|
|||||||
void cPlayer::Destroyed()
|
void cPlayer::Destroyed()
|
||||||
{
|
{
|
||||||
CloseWindow(false);
|
CloseWindow(false);
|
||||||
|
|
||||||
m_ClientHandle = NULL;
|
m_ClientHandle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,22 +160,17 @@ void cPlayer::Destroyed()
|
|||||||
|
|
||||||
void cPlayer::SpawnOn(cClientHandle & a_Client)
|
void cPlayer::SpawnOn(cClientHandle & a_Client)
|
||||||
{
|
{
|
||||||
/*
|
if (!m_bVisible || (m_ClientHandle == (&a_Client)))
|
||||||
LOGD("cPlayer::SpawnOn(%s) for \"%s\" at pos {%.2f, %.2f, %.2f}",
|
|
||||||
a_Client.GetUsername().c_str(), m_PlayerName.c_str(), m_Pos.x, m_Pos.y, m_Pos.z
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (m_bVisible && (m_ClientHandle != (&a_Client)))
|
|
||||||
{
|
{
|
||||||
a_Client.SendPlayerSpawn(*this);
|
return;
|
||||||
a_Client.SendEntityHeadLook(*this);
|
|
||||||
a_Client.SendEntityEquipment(*this, 0, m_Inventory.GetEquippedItem() );
|
|
||||||
a_Client.SendEntityEquipment(*this, 1, m_Inventory.GetEquippedBoots() );
|
|
||||||
a_Client.SendEntityEquipment(*this, 2, m_Inventory.GetEquippedLeggings() );
|
|
||||||
a_Client.SendEntityEquipment(*this, 3, m_Inventory.GetEquippedChestplate() );
|
|
||||||
a_Client.SendEntityEquipment(*this, 4, m_Inventory.GetEquippedHelmet() );
|
|
||||||
}
|
}
|
||||||
|
a_Client.SendPlayerSpawn(*this);
|
||||||
|
a_Client.SendEntityHeadLook(*this);
|
||||||
|
a_Client.SendEntityEquipment(*this, 0, m_Inventory.GetEquippedItem() );
|
||||||
|
a_Client.SendEntityEquipment(*this, 1, m_Inventory.GetEquippedBoots() );
|
||||||
|
a_Client.SendEntityEquipment(*this, 2, m_Inventory.GetEquippedLeggings() );
|
||||||
|
a_Client.SendEntityEquipment(*this, 3, m_Inventory.GetEquippedChestplate() );
|
||||||
|
a_Client.SendEntityEquipment(*this, 4, m_Inventory.GetEquippedHelmet() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -183,12 +181,18 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
{
|
{
|
||||||
if (m_ClientHandle != NULL)
|
if (m_ClientHandle != NULL)
|
||||||
{
|
{
|
||||||
|
if (m_ClientHandle->IsDestroyed())
|
||||||
|
{
|
||||||
|
// This should not happen, because destroying a client will remove it from the world, but just in case
|
||||||
|
m_ClientHandle = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_ClientHandle->IsPlaying())
|
if (!m_ClientHandle->IsPlaying())
|
||||||
{
|
{
|
||||||
// We're not yet in the game, ignore everything
|
// We're not yet in the game, ignore everything
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_ClientHandle->Tick(a_Dt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
super::Tick(a_Dt, a_Chunk);
|
super::Tick(a_Dt, a_Chunk);
|
||||||
|
@ -40,7 +40,7 @@ public:
|
|||||||
cPlayer(cClientHandle * a_Client, const AString & a_PlayerName);
|
cPlayer(cClientHandle * a_Client, const AString & a_PlayerName);
|
||||||
virtual ~cPlayer();
|
virtual ~cPlayer();
|
||||||
|
|
||||||
virtual bool Initialize(cWorld * a_World); // tolua_export
|
virtual bool Initialize(cWorld * a_World) override;
|
||||||
|
|
||||||
virtual void SpawnOn(cClientHandle & a_Client) override;
|
virtual void SpawnOn(cClientHandle & a_Client) override;
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ void cServer::RemoveClient(const cClientHandle * a_Client)
|
|||||||
void cServer::ClientMovedToWorld(const cClientHandle * a_Client)
|
void cServer::ClientMovedToWorld(const cClientHandle * a_Client)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSClients);
|
cCSLock Lock(m_CSClients);
|
||||||
m_Clients.remove(const_cast<cClientHandle *>(a_Client));
|
m_ClientsToRemove.push_back(const_cast<cClientHandle *>(a_Client));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -312,25 +312,7 @@ bool cServer::Tick(float a_Dt)
|
|||||||
{
|
{
|
||||||
cRoot::Get()->TickCommands();
|
cRoot::Get()->TickCommands();
|
||||||
|
|
||||||
cClientHandleList RemoveClients;
|
TickClients(a_Dt);
|
||||||
{
|
|
||||||
cCSLock Lock(m_CSClients);
|
|
||||||
for (cClientHandleList::iterator itr = m_Clients.begin(); itr != m_Clients.end();)
|
|
||||||
{
|
|
||||||
if ((*itr)->IsDestroyed())
|
|
||||||
{
|
|
||||||
RemoveClients.push_back(*itr); // Remove the client later, when CS is not held, to avoid deadlock ( http://forum.mc-server.org/showthread.php?tid=374 )
|
|
||||||
itr = m_Clients.erase(itr);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
(*itr)->Tick(a_Dt);
|
|
||||||
++itr;
|
|
||||||
} // for itr - m_Clients[]
|
|
||||||
}
|
|
||||||
for (cClientHandleList::iterator itr = RemoveClients.begin(); itr != RemoveClients.end(); ++itr)
|
|
||||||
{
|
|
||||||
delete *itr;
|
|
||||||
} // for itr - RemoveClients[]
|
|
||||||
|
|
||||||
if (!m_bRestarting)
|
if (!m_bRestarting)
|
||||||
{
|
{
|
||||||
@ -348,6 +330,45 @@ bool cServer::Tick(float a_Dt)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cServer::TickClients(float a_Dt)
|
||||||
|
{
|
||||||
|
cClientHandleList RemoveClients;
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSClients);
|
||||||
|
|
||||||
|
// Remove clients that have moved to a world (the world will be ticking them from now on)
|
||||||
|
for (cClientHandleList::const_iterator itr = m_ClientsToRemove.begin(), end = m_ClientsToRemove.end(); itr != end; ++itr)
|
||||||
|
{
|
||||||
|
m_Clients.remove(*itr);
|
||||||
|
} // for itr - m_ClientsToRemove[]
|
||||||
|
m_ClientsToRemove.clear();
|
||||||
|
|
||||||
|
// Tick the remaining clients, take out those that have been destroyed into RemoveClients
|
||||||
|
for (cClientHandleList::iterator itr = m_Clients.begin(); itr != m_Clients.end();)
|
||||||
|
{
|
||||||
|
if ((*itr)->IsDestroyed())
|
||||||
|
{
|
||||||
|
// Remove the client later, when CS is not held, to avoid deadlock ( http://forum.mc-server.org/showthread.php?tid=374 )
|
||||||
|
RemoveClients.push_back(*itr);
|
||||||
|
itr = m_Clients.erase(itr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(*itr)->Tick(a_Dt);
|
||||||
|
++itr;
|
||||||
|
} // for itr - m_Clients[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the clients that have been destroyed
|
||||||
|
for (cClientHandleList::iterator itr = RemoveClients.begin(); itr != RemoveClients.end(); ++itr)
|
||||||
|
{
|
||||||
|
delete *itr;
|
||||||
|
} // for itr - RemoveClients[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cServer::Start(void)
|
bool cServer::Start(void)
|
||||||
{
|
{
|
||||||
if (!m_ListenThreadIPv4.Start())
|
if (!m_ListenThreadIPv4.Start())
|
||||||
@ -492,6 +513,7 @@ void cServer::AuthenticateUser(int a_ClientID)
|
|||||||
if ((*itr)->GetUniqueID() == a_ClientID)
|
if ((*itr)->GetUniqueID() == a_ClientID)
|
||||||
{
|
{
|
||||||
(*itr)->Authenticate();
|
(*itr)->Authenticate();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} // for itr - m_Clients[]
|
} // for itr - m_Clients[]
|
||||||
}
|
}
|
||||||
|
@ -131,8 +131,9 @@ private:
|
|||||||
cListenThread m_ListenThreadIPv4;
|
cListenThread m_ListenThreadIPv4;
|
||||||
cListenThread m_ListenThreadIPv6;
|
cListenThread m_ListenThreadIPv6;
|
||||||
|
|
||||||
cCriticalSection m_CSClients; ///< Locks client list
|
cCriticalSection m_CSClients; ///< Locks client lists
|
||||||
cClientHandleList m_Clients; ///< Clients that are connected to the server and not yet assigned to a cWorld
|
cClientHandleList m_Clients; ///< Clients that are connected to the server and not yet assigned to a cWorld
|
||||||
|
cClientHandleList m_ClientsToRemove; ///< Clients that have just been moved into a world and are to be removed from m_Clients in the next Tick()
|
||||||
|
|
||||||
cSocketThreads m_SocketThreads;
|
cSocketThreads m_SocketThreads;
|
||||||
|
|
||||||
@ -164,6 +165,9 @@ private:
|
|||||||
void PrepareKeys(void);
|
void PrepareKeys(void);
|
||||||
|
|
||||||
bool Tick(float a_Dt);
|
bool Tick(float a_Dt);
|
||||||
|
|
||||||
|
/// Ticks the clients in m_Clients, manages the list in respect to removing clients
|
||||||
|
void TickClients(float a_Dt);
|
||||||
|
|
||||||
// cListenThread::cCallback overrides:
|
// cListenThread::cCallback overrides:
|
||||||
virtual void OnConnectionAccepted(cSocket & a_Socket) override;
|
virtual void OnConnectionAccepted(cSocket & a_Socket) override;
|
||||||
|
@ -587,6 +587,7 @@ void cWorld::Tick(float a_Dt)
|
|||||||
|
|
||||||
m_ChunkMap->Tick(a_Dt);
|
m_ChunkMap->Tick(a_Dt);
|
||||||
|
|
||||||
|
TickClients(a_Dt);
|
||||||
TickQueuedBlocks(a_Dt);
|
TickQueuedBlocks(a_Dt);
|
||||||
TickQueuedTasks();
|
TickQueuedTasks();
|
||||||
|
|
||||||
@ -811,6 +812,37 @@ void cWorld::TickQueuedTasks(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::TickClients(float a_Dt)
|
||||||
|
{
|
||||||
|
cClientHandleList RemoveClients;
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSClients);
|
||||||
|
// Tick the clients, take out those that have been destroyed into RemoveClients
|
||||||
|
for (cClientHandleList::iterator itr = m_Clients.begin(); itr != m_Clients.end();)
|
||||||
|
{
|
||||||
|
if ((*itr)->IsDestroyed())
|
||||||
|
{
|
||||||
|
// Remove the client later, when CS is not held, to avoid deadlock
|
||||||
|
RemoveClients.push_back(*itr);
|
||||||
|
itr = m_Clients.erase(itr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
(*itr)->Tick(a_Dt);
|
||||||
|
++itr;
|
||||||
|
} // for itr - m_Clients[]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the clients that have been destroyed
|
||||||
|
for (cClientHandleList::iterator itr = RemoveClients.begin(); itr != RemoveClients.end(); ++itr)
|
||||||
|
{
|
||||||
|
delete *itr;
|
||||||
|
} // for itr - RemoveClients[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ)
|
void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||||
{
|
{
|
||||||
return m_ChunkMap->WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
|
return m_ChunkMap->WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
|
||||||
@ -1973,13 +2005,22 @@ void cWorld::CollectPickupsByPlayer(cPlayer * a_Player)
|
|||||||
|
|
||||||
void cWorld::AddPlayer(cPlayer * a_Player)
|
void cWorld::AddPlayer(cPlayer * a_Player)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSPlayers);
|
{
|
||||||
|
cCSLock Lock(m_CSPlayers);
|
||||||
ASSERT(std::find(m_Players.begin(), m_Players.end(), a_Player) == m_Players.end()); // Is it already in the list? HOW?
|
|
||||||
|
ASSERT(std::find(m_Players.begin(), m_Players.end(), a_Player) == m_Players.end()); // Is it already in the list? HOW?
|
||||||
m_Players.remove(a_Player); // Make sure the player is registered only once
|
|
||||||
m_Players.push_back(a_Player);
|
m_Players.remove(a_Player); // Make sure the player is registered only once
|
||||||
|
m_Players.push_back(a_Player);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the player's client to the list of clients to be ticked:
|
||||||
|
if (a_Player->GetClientHandle() != NULL)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSClients);
|
||||||
|
m_Clients.push_back(a_Player->GetClientHandle());
|
||||||
|
}
|
||||||
|
|
||||||
// The player has already been added to the chunkmap as the entity, do NOT add again!
|
// The player has already been added to the chunkmap as the entity, do NOT add again!
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1990,8 +2031,17 @@ void cWorld::AddPlayer(cPlayer * a_Player)
|
|||||||
void cWorld::RemovePlayer(cPlayer * a_Player)
|
void cWorld::RemovePlayer(cPlayer * a_Player)
|
||||||
{
|
{
|
||||||
m_ChunkMap->RemoveEntity(a_Player);
|
m_ChunkMap->RemoveEntity(a_Player);
|
||||||
cCSLock Lock(m_CSPlayers);
|
{
|
||||||
m_Players.remove(a_Player);
|
cCSLock Lock(m_CSPlayers);
|
||||||
|
m_Players.remove(a_Player);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the player's client from the list of clients to be ticked:
|
||||||
|
if (a_Player->GetClientHandle() != NULL)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSClients);
|
||||||
|
m_Clients.remove(a_Player->GetClientHandle());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -660,6 +660,12 @@ private:
|
|||||||
|
|
||||||
/// Tasks that have been queued onto the tick thread; guarded by m_CSTasks
|
/// Tasks that have been queued onto the tick thread; guarded by m_CSTasks
|
||||||
cTasks m_Tasks;
|
cTasks m_Tasks;
|
||||||
|
|
||||||
|
/// Guards m_Clients
|
||||||
|
cCriticalSection m_CSClients;
|
||||||
|
|
||||||
|
/// List of clients in this world, these will be ticked by this world
|
||||||
|
cClientHandleList m_Clients;
|
||||||
|
|
||||||
|
|
||||||
cWorld(const AString & a_WorldName);
|
cWorld(const AString & a_WorldName);
|
||||||
@ -667,12 +673,18 @@ private:
|
|||||||
|
|
||||||
void Tick(float a_Dt);
|
void Tick(float a_Dt);
|
||||||
|
|
||||||
void TickWeather(float a_Dt); // Handles weather each tick
|
/// Handles the weather in each tick
|
||||||
void TickSpawnMobs(float a_Dt); // Handles mob spawning each tick
|
void TickWeather(float a_Dt);
|
||||||
|
|
||||||
|
/// Handles the mob spawning each tick
|
||||||
|
void TickSpawnMobs(float a_Dt);
|
||||||
|
|
||||||
/// Executes all tasks queued onto the tick thread
|
/// Executes all tasks queued onto the tick thread
|
||||||
void TickQueuedTasks(void);
|
void TickQueuedTasks(void);
|
||||||
|
|
||||||
|
/// Ticks all clients that are in this world
|
||||||
|
void TickClients(float a_Dt);
|
||||||
|
|
||||||
/// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section)
|
/// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section)
|
||||||
cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);
|
cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);
|
||||||
}; // tolua_export
|
}; // tolua_export
|
||||||
|
Loading…
Reference in New Issue
Block a user