mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-03-03 16:11:33 +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_net.cpp
|
||||||
d_netsingle.cpp
|
d_netsingle.cpp
|
||||||
d_netserver.cpp
|
d_netserver.cpp
|
||||||
|
d_netsync.cpp
|
||||||
d_netclient.cpp
|
d_netclient.cpp
|
||||||
d_netinfo.cpp
|
d_netinfo.cpp
|
||||||
d_protocol.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__
|
#ifndef __D_NETSYNC_H__
|
||||||
#define __D_NETSYNC_H__
|
#define __D_NETSYNC_H__
|
||||||
|
|
||||||
|
#include "vectors.h"
|
||||||
|
#include "r_data/renderstyle.h"
|
||||||
|
|
||||||
struct NetSyncData {
|
struct NetSyncData {
|
||||||
DVector3 Pos;
|
DVector3 Pos;
|
||||||
DVector3 Vel;
|
DVector3 Vel;
|
||||||
|
@ -27,7 +30,83 @@ struct NetSyncData {
|
||||||
double CameraHeight; // Height of camera when used as such
|
double CameraHeight; // Height of camera when used as such
|
||||||
double CameraFOV;
|
double CameraFOV;
|
||||||
double StealthAlpha; // Minmum alpha for MF_STEALTH.
|
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__
|
#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.
|
// force scroller check in the first tic.
|
||||||
actor->flags8 |= MF8_INSCROLLSEC;
|
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;
|
return actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5368,6 +5372,9 @@ void AActor::CallDeactivate(AActor *activator)
|
||||||
|
|
||||||
void AActor::OnDestroy ()
|
void AActor::OnDestroy ()
|
||||||
{
|
{
|
||||||
|
// [BB] Free it's network ID.
|
||||||
|
syncdata.FreeNetID ();
|
||||||
|
|
||||||
// [ZZ] call destroy event hook.
|
// [ZZ] call destroy event hook.
|
||||||
// note that this differs from ThingSpawned in that you can actually override OnDestroy to avoid calling the 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.
|
// but you can't really do that without utterly breaking the game, so it's ok.
|
||||||
|
|
Loading…
Reference in a new issue