added and adapted Zandronum's netID system for actors

This commit is contained in:
Benjamin Berkels 2018-07-21 17:41:35 +02:00
parent 8881ef52dc
commit 8d8d03d139
4 changed files with 252 additions and 0 deletions

View file

@ -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
View 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>;

View file

@ -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__

View file

@ -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.