mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-03-02 15:42:17 +00:00
added and adapted Zandronum's netID system for actors
This commit is contained in:
parent
8881ef52dc
commit
8d8d03d139
4 changed files with 252 additions and 0 deletions
|
@ -878,6 +878,7 @@ set (PCH_SOURCES
|
|||
d_net.cpp
|
||||
d_netsingle.cpp
|
||||
d_netserver.cpp
|
||||
d_netsync.cpp
|
||||
d_netclient.cpp
|
||||
d_netinfo.cpp
|
||||
d_protocol.cpp
|
||||
|
|
165
src/d_netsync.cpp
Normal file
165
src/d_netsync.cpp
Normal file
|
@ -0,0 +1,165 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright 2018 Benjamin Berkels
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see http://www.gnu.org/licenses/
|
||||
//
|
||||
|
||||
#include "d_player.h"
|
||||
#include "d_netsync.h"
|
||||
#include "c_dispatch.h"
|
||||
#include "actor.h"
|
||||
#include "doomstat.h"
|
||||
|
||||
extern bool netserver, netclient;
|
||||
|
||||
IDList<AActor> g_NetIDList;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
void NetSyncData::AssignNetID ( AActor *pActor )
|
||||
{
|
||||
if ( netserver )
|
||||
{
|
||||
NetID = g_NetIDList.getNewID( );
|
||||
g_NetIDList.useID ( NetID, pActor );
|
||||
}
|
||||
else
|
||||
NetID = -1;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
void NetSyncData::FreeNetID ( )
|
||||
{
|
||||
g_NetIDList.freeID ( NetID );
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
template <typename T>
|
||||
void IDList<T>::clear( void )
|
||||
{
|
||||
for ( unsigned int ulIdx = 0; ulIdx < MAX_NETID; ulIdx++ )
|
||||
freeID ( ulIdx );
|
||||
|
||||
_firstFreeID = 1;
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
template <typename T>
|
||||
void IDList<T>::rebuild( void )
|
||||
{
|
||||
clear();
|
||||
|
||||
T *pActor;
|
||||
|
||||
TThinkerIterator<T> it;
|
||||
|
||||
while ( (pActor = it.Next()) )
|
||||
{
|
||||
if (( pActor->syncdata.NetID > 0 ) && ( pActor->syncdata.NetID < MAX_NETID ))
|
||||
useID ( pActor->syncdata.NetID, pActor );
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
template <typename T>
|
||||
void IDList<T>::useID ( const int lNetID, T *pActor )
|
||||
{
|
||||
if ( isIndexValid ( lNetID ) )
|
||||
{
|
||||
if ( ( _entries[lNetID].bFree == false ) && ( _entries[lNetID].pActor != pActor ) )
|
||||
Printf ( "IDList<T>::useID is using an already used ID.\n" );
|
||||
|
||||
_entries[lNetID].bFree = false;
|
||||
_entries[lNetID].pActor = pActor;
|
||||
}
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
void CountActors ( )
|
||||
{
|
||||
TMap<FName, int> actorCountMap;
|
||||
AActor * mo;
|
||||
int numActors = 0;
|
||||
int numActorsWithNetID = 0;
|
||||
|
||||
TThinkerIterator<AActor> it;
|
||||
|
||||
while ( (mo = it.Next()) )
|
||||
{
|
||||
numActors++;
|
||||
if ( mo->syncdata.NetID > 0 )
|
||||
numActorsWithNetID++;
|
||||
const FName curName = mo->GetClass()->TypeName.GetChars();
|
||||
if ( actorCountMap.CheckKey( curName ) == NULL )
|
||||
actorCountMap.Insert( curName, 1 );
|
||||
else
|
||||
actorCountMap [ curName ] ++;
|
||||
}
|
||||
|
||||
const TMap<FName, int>::Pair *pair;
|
||||
|
||||
Printf ( "%d actors in total found, %d have a NetID. Detailed listing:\n", numActors, numActorsWithNetID );
|
||||
|
||||
TMap<FName, int>::ConstIterator mapit(actorCountMap);
|
||||
while (mapit.NextPair (pair))
|
||||
{
|
||||
Printf ( "%s %d\n", pair->Key.GetChars(), pair->Value );
|
||||
}
|
||||
}
|
||||
|
||||
CCMD(countactors)
|
||||
{
|
||||
CountActors ();
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
template <typename T>
|
||||
unsigned int IDList<T>::getNewID( void )
|
||||
{
|
||||
// Actor's network ID is the first availible net ID.
|
||||
unsigned int ulID = _firstFreeID;
|
||||
|
||||
do
|
||||
{
|
||||
_firstFreeID++;
|
||||
if ( _firstFreeID >= MAX_NETID )
|
||||
_firstFreeID = 1;
|
||||
|
||||
if ( _firstFreeID == ulID )
|
||||
{
|
||||
// [BB] In case there is no free netID, the server has to abort the current game.
|
||||
if ( netserver )
|
||||
{
|
||||
// [BB] We can only spawn (MAX_NETID-2) actors with netID, because ID zero is reserved and
|
||||
// we already check that a new ID for the next actor is available when assign a net ID.
|
||||
Printf( "ACTOR_GetNewNetID: Network ID limit reached (>=%d actors)\n", MAX_NETID - 1 );
|
||||
CountActors ( );
|
||||
I_Error ("Network ID limit reached (>=%d actors)!\n", MAX_NETID - 1 );
|
||||
}
|
||||
|
||||
return ( 0 );
|
||||
}
|
||||
} while ( _entries[_firstFreeID].bFree == false );
|
||||
|
||||
return ( ulID );
|
||||
}
|
||||
|
||||
template class IDList<AActor>;
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef __D_NETSYNC_H__
|
||||
#define __D_NETSYNC_H__
|
||||
|
||||
#include "vectors.h"
|
||||
#include "r_data/renderstyle.h"
|
||||
|
||||
struct NetSyncData {
|
||||
DVector3 Pos;
|
||||
DVector3 Vel;
|
||||
|
@ -27,7 +30,83 @@ struct NetSyncData {
|
|||
double CameraHeight; // Height of camera when used as such
|
||||
double CameraFOV;
|
||||
double StealthAlpha; // Minmum alpha for MF_STEALTH.
|
||||
int NetID;
|
||||
|
||||
void AssignNetID ( AActor *pActor );
|
||||
void FreeNetID ();
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// IDList
|
||||
//
|
||||
// Manages IDs to reference a certain type of objects over the network.
|
||||
// Since it still mimics the old Actor ID mechanism, 0 is never assigned as
|
||||
// ID.
|
||||
//
|
||||
// @author Benjamin Berkels
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
template <typename T>
|
||||
class IDList
|
||||
{
|
||||
public:
|
||||
const static int MAX_NETID = 32768;
|
||||
|
||||
private:
|
||||
// List of all possible network ID's for an actor. Slot is true if it available for use.
|
||||
typedef struct
|
||||
{
|
||||
// Is this node occupied, or free to be used by a new actor?
|
||||
bool bFree;
|
||||
|
||||
// If this node is occupied, this is the actor occupying it.
|
||||
T *pActor;
|
||||
|
||||
} IDNODE_t;
|
||||
|
||||
IDNODE_t _entries[MAX_NETID];
|
||||
unsigned int _firstFreeID;
|
||||
|
||||
inline bool isIndexValid ( const int lNetID ) const
|
||||
{
|
||||
return ( lNetID >= 0 ) && ( lNetID < MAX_NETID );
|
||||
}
|
||||
public:
|
||||
void clear ( );
|
||||
|
||||
// [BB] Rebuild the global list of used / free NetIDs from scratch.
|
||||
void rebuild ( );
|
||||
|
||||
IDList ( )
|
||||
{
|
||||
clear ( );
|
||||
}
|
||||
|
||||
void useID ( const int lNetID, T *pActor );
|
||||
|
||||
void freeID ( const int lNetID )
|
||||
{
|
||||
if ( isIndexValid ( lNetID ) )
|
||||
{
|
||||
_entries[lNetID].bFree = true;
|
||||
_entries[lNetID].pActor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int getNewID ( );
|
||||
|
||||
T* findPointerByID ( const int lNetID ) const
|
||||
{
|
||||
if ( isIndexValid ( lNetID ) == false )
|
||||
return ( NULL );
|
||||
|
||||
if (( _entries[lNetID].bFree == false ) && ( _entries[lNetID].pActor ))
|
||||
return ( _entries[lNetID].pActor );
|
||||
|
||||
return ( NULL );
|
||||
}
|
||||
};
|
||||
|
||||
#endif //__D_NETSYNC_H__
|
|
@ -5099,6 +5099,10 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a
|
|||
}
|
||||
// force scroller check in the first tic.
|
||||
actor->flags8 |= MF8_INSCROLLSEC;
|
||||
|
||||
// [BB] Give this actor a NetID so that we can sync it to the clients.
|
||||
actor->syncdata.AssignNetID( actor );
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
|
@ -5368,6 +5372,9 @@ void AActor::CallDeactivate(AActor *activator)
|
|||
|
||||
void AActor::OnDestroy ()
|
||||
{
|
||||
// [BB] Free it's network ID.
|
||||
syncdata.FreeNetID ();
|
||||
|
||||
// [ZZ] call destroy event hook.
|
||||
// note that this differs from ThingSpawned in that you can actually override OnDestroy to avoid calling the hook.
|
||||
// but you can't really do that without utterly breaking the game, so it's ok.
|
||||
|
|
Loading…
Reference in a new issue