Skip to content

Commit

Permalink
SiegeNative #2
Browse files Browse the repository at this point in the history
Tested on v436, XCGE_17-grid5.2

Replication code:
- Macros rewritten for greater flexibility, it's possible to hotswitch
between supported Siege versions (not tested).
- Failure to find a Net property won't crash the server.

sgPRI:
- CountryPrefix now also checked every 8 times.

sgCategoryInfo hook implemented:
- All Actor superclass properties replicated ONLY if bNetInitial (once).
- All variables are only checked if:
-- Sent to corresponding team.
--- bNetInitial (first time)
--- bNetOwner (every player gets this once around every second)
--- Every 32 checks (3.2 seconds).
  • Loading branch information
CacoFFF committed Apr 7, 2016
1 parent 1121e81 commit 5eefd3c
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 44 deletions.
63 changes: 51 additions & 12 deletions SiegeNative/Src/SiegeNative.cpp
Expand Up @@ -54,26 +54,45 @@ UBOOL NEQ(FPlane& A,FPlane& B,UPackageMap* Map) {return
((INT*)&A)[2]!=((INT*)&B)[2] || ((INT*)&A)[3]!=((INT*)&B)[3];}
UBOOL NEQ(FString A,FString B,UPackageMap* Map) {return A!=B;}

//nc = c++ hack class
//cc = UScript class
//nc = Class name
//v = variable name (identical in both classes)
#define DOREP(nc,cc,v) \
if( NEQ(v,((nc*)Recent)->v,Map) ) \
#define DOREP(nc,v) \
if( nc::ST_##v && NEQ(v,((nc*)Recent)->v,Map) ) \
{ \
static UProperty* sp##v = FindObjectChecked<UProperty>(cc,TEXT(#v)); \
*Ptr++ = sp##v->RepIndex; \
*Ptr++ = nc::ST_##v->RepIndex; \
}
#define DOREPARRAY(nc,cc,v) \
static UProperty* sp##v = FindObjectChecked<UProperty>(cc,TEXT(#v)); \
for( INT i=0; i<ARRAY_COUNT(v); i++ ) \
if( NEQ(v[i],((nc*)Recent)->v[i],Map) ) \
*Ptr++ = sp##v->RepIndex+i;
#define DOREPARRAY(nc,v) \
if (nc::ST_##v) \
{ for( INT i=0; i<ARRAY_COUNT(v); i++ ) \
if( NEQ(v[i],((nc*)Recent)->v[i],Map) ) \
*Ptr++ = nc::ST_##v->RepIndex+i; }

/*-----------------------------------------------------------------------------
Entry point methods.
-----------------------------------------------------------------------------*/

#define LOAD_STATIC_PROPERTY(prop,onclass) ST_##prop = FindObject<UProperty>(onclass,TEXT(#prop))

//Macro: find a class in a package, store in static variable: [classname]_class
#define FIND_PRELOADED_CLASS(clname,onpackage) \
{for ( TObjectIterator<UClass> It; It; ++It ) \
if ( (It->GetOuter() == onpackage) && !appStricmp(It->GetName(),TEXT(#clname)) ) \
{ \
clname##_class = *It; \
break; \
} }

//Macro: Make class able to use NativeReplication features
#define SETUP_CLASS_NATIVEREP(clname) \
if ( clname##_class->ClassConstructor != clname::InternalConstructor ) \
{ \
clname##_class->ClassConstructor = clname::InternalConstructor; \
clname##_class->ClassFlags |= CLASS_NativeReplication; \
}


#include "sgPRI.h"
#include "sgCategoryInfo.h"

//
// First function called upon actor spawn.
Expand All @@ -84,6 +103,12 @@ void ASiegeNativeActor::InitExecution()

AActor::InitExecution(); //Validate that actor has been properly spawned in a level

if ( Level->bBegunPlay )
{
debugf( NAME_SiegeNative, TEXT("[ERROR] This actor will only apply the hook if spawned via ServerActors!!!"));
return;
}

if ( Level->Game && ((Level->NetMode == NM_DedicatedServer) || (Level->NetMode == NM_ListenServer)) )
{
RegisterNames();
Expand All @@ -96,8 +121,22 @@ void ASiegeNativeActor::InitExecution()
if ( SiegeClass )
{
debugf( NAME_SiegeNative, TEXT("Siege gametype found: %s, prefetching and validating assets..."), Level->Game->GetClass()->GetFullName() );

//Let main SiegeIV hold a reference to our class to prevent elimination via garbage collector
{for( TFieldIterator<UObjectProperty> It(SiegeClass); It && It->GetOwnerClass()==SiegeClass; ++It )
if ( appStricmp( It->GetName(), TEXT("GCBind")) == 0 )
{
//Register in both gameinfo and defaults (SiegeGI.GCBind = class'SiegeNativeActor';)
*((UObject**) (((DWORD)Level->Game) + It->Offset)) = GetClass();
*((UObject**) (((DWORD)Level->Game->GetClass()->GetDefaultObject()) + It->Offset)) = GetClass();
break;
}
}

//Setup individual classes
UPackage* SiegePackage = (UPackage*) SiegeClass->GetOuter();
Setup_sgPRI( SiegePackage);
Setup_sgPRI ( SiegePackage, GetLevel());
Setup_sgCategoryInfo ( SiegePackage, GetLevel());
}
}

Expand Down
113 changes: 113 additions & 0 deletions SiegeNative/Src/sgCategoryInfo.h
@@ -0,0 +1,113 @@
//Utilitary file for all sgCategoryInfo hooks

class sgCategoryInfo : public AReplicationInfo
{
public:
BYTE Team;
APlayerPawn* PList[32];
INT iSize;
INT pPosition;
FLOAT SwitchTimer;
UClass* NetBuild[128];
BYTE NetCategory[128];
class sgBaseBuildRule* NetRules[128];
INT NetCost[128];
FStringNoInit NetCategories[17];
FStringNoInit Netlocalized[17];
INT iCat;
FStringNoInit NetProperties[128];
BYTE iBuilds;
FLOAT PriorityTimer;
BYTE CurPriItem;
BYTE PossiblePriorities[128];
FStringNoInit NewBuild;
FStringNoInit NewCategory;
class sgBaseBuildRule* RuleList;
class SiegeCategoryRules* CatObject;


//AActor interface, native netcode
virtual INT* GetOptimizedRepList( BYTE* InDefault, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map, INT NumReps );
// virtual UBOOL ShouldDoScriptReplication() {return 1;}

NO_DEFAULT_CONSTRUCTOR(sgCategoryInfo);

static void InternalConstructor( void* X )
{ new( (EInternal*)X )sgCategoryInfo(); }

static UProperty* ST_iBuilds;
static UProperty* ST_Team;
static UProperty* ST_iCat;
static UProperty* ST_NetBuild;
static UProperty* ST_NetCategory;
static UProperty* ST_NetCost;
static UProperty* ST_NetCategories;
static void ReloadStatics( UClass* LoadFrom)
{
LOAD_STATIC_PROPERTY(iBuilds, LoadFrom);
LOAD_STATIC_PROPERTY(Team, LoadFrom);
LOAD_STATIC_PROPERTY(iCat, LoadFrom);
LOAD_STATIC_PROPERTY(NetBuild, LoadFrom);
LOAD_STATIC_PROPERTY(NetCategory, LoadFrom);
LOAD_STATIC_PROPERTY(NetCost, LoadFrom);
LOAD_STATIC_PROPERTY(NetCategories, LoadFrom);
}
};

UProperty* sgCategoryInfo::ST_iBuilds = NULL;
UProperty* sgCategoryInfo::ST_Team = NULL;
UProperty* sgCategoryInfo::ST_iCat = NULL;
UProperty* sgCategoryInfo::ST_NetBuild = NULL;
UProperty* sgCategoryInfo::ST_NetCategory = NULL;
UProperty* sgCategoryInfo::ST_NetCost = NULL;
UProperty* sgCategoryInfo::ST_NetCategories = NULL;


static UClass* sgCategoryInfo_class = NULL;

//sgCategoryInfo is preloaded by SiegeGI, finding it is enough
static void Setup_sgCategoryInfo( UPackage* SiegePackage, ULevel* MyLevel)
{
sgCategoryInfo_class = NULL;

FIND_PRELOADED_CLASS(sgCategoryInfo,SiegePackage);
check( sgCategoryInfo_class != NULL);
SETUP_CLASS_NATIVEREP(sgCategoryInfo);
sgCategoryInfo::ReloadStatics( sgCategoryInfo_class);
}


INT* sgCategoryInfo::GetOptimizedRepList( BYTE* Recent, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map, INT NumReps )
{
guard(sgCategoryInfo::GetOptimizedRepList);
if ( bNetInitial )
Ptr = AReplicationInfo::GetOptimizedRepList(Recent,Retire,Ptr,Map,NumReps);
check(sgCategoryInfo_class != NULL);
if( sgCategoryInfo_class->ClassFlags & CLASS_NativeReplication )
{
if( Role==ROLE_Authority )
{
UNetConnection* Conn = ((UPackageMapLevel*)Map)->Connection;
//Only same team
if ( Conn->Actor && Conn->Actor->PlayerReplicationInfo && (Conn->Actor->PlayerReplicationInfo->Team == Team) )
{
if ( bNetInitial || bNetOwner || (NumReps % 32 == 0) ) //Avoid heavy polling
{
DOREP(sgCategoryInfo,iBuilds);
DOREP(sgCategoryInfo,Team);
DOREP(sgCategoryInfo,iCat);
DOREPARRAY(sgCategoryInfo,NetBuild);
DOREPARRAY(sgCategoryInfo,NetCategory);
DOREPARRAY(sgCategoryInfo,NetCost);
DOREPARRAY(sgCategoryInfo,NetCategories);
}
}
}
}
return Ptr;
unguard;
}




102 changes: 70 additions & 32 deletions SiegeNative/Src/sgPRI.h
Expand Up @@ -53,30 +53,70 @@ class sgPRI : public APlayerReplicationInfo

static void InternalConstructor( void* X )
{ new( (EInternal*)X )sgPRI(); }

static UProperty* ST_sgInfoCoreKiller;
static UProperty* ST_sgInfoCoreRepair;
static UProperty* ST_sgInfoBuildingHurt;
static UProperty* ST_sgInfoUpgradeRepair;
static UProperty* ST_sgInfoKiller;
static UProperty* ST_sgInfoBuildingMaker;
static UProperty* ST_sgInfoWarheadMaker;
static UProperty* ST_sgInfoWarheadKiller;
static UProperty* ST_sgInfoSpreeCount;
static UProperty* ST_CountryPrefix;
static UProperty* ST_bReadyToPlay;
static UProperty* ST_XC_Orb;
static UProperty* ST_Orders;
static UProperty* ST_RU;
static UProperty* ST_bHideIdentify;
static void ReloadStatics( UClass* LoadFrom)
{
LOAD_STATIC_PROPERTY(sgInfoCoreKiller, LoadFrom);
LOAD_STATIC_PROPERTY(sgInfoCoreRepair, LoadFrom);
LOAD_STATIC_PROPERTY(sgInfoBuildingHurt, LoadFrom);
LOAD_STATIC_PROPERTY(sgInfoUpgradeRepair, LoadFrom);
LOAD_STATIC_PROPERTY(sgInfoKiller, LoadFrom);
LOAD_STATIC_PROPERTY(sgInfoBuildingMaker, LoadFrom);
LOAD_STATIC_PROPERTY(sgInfoWarheadMaker, LoadFrom);
LOAD_STATIC_PROPERTY(sgInfoWarheadKiller, LoadFrom);
LOAD_STATIC_PROPERTY(sgInfoSpreeCount, LoadFrom);
LOAD_STATIC_PROPERTY(CountryPrefix, LoadFrom);
LOAD_STATIC_PROPERTY(bReadyToPlay, LoadFrom);
LOAD_STATIC_PROPERTY(XC_Orb, LoadFrom);
LOAD_STATIC_PROPERTY(Orders, LoadFrom);
LOAD_STATIC_PROPERTY(RU, LoadFrom);
LOAD_STATIC_PROPERTY(bHideIdentify, LoadFrom);
}
};

UProperty* sgPRI::ST_sgInfoCoreKiller = NULL;
UProperty* sgPRI::ST_sgInfoCoreRepair = NULL;
UProperty* sgPRI::ST_sgInfoBuildingHurt = NULL;
UProperty* sgPRI::ST_sgInfoUpgradeRepair = NULL;
UProperty* sgPRI::ST_sgInfoKiller = NULL;
UProperty* sgPRI::ST_sgInfoBuildingMaker = NULL;
UProperty* sgPRI::ST_sgInfoWarheadMaker = NULL;
UProperty* sgPRI::ST_sgInfoWarheadKiller = NULL;
UProperty* sgPRI::ST_sgInfoSpreeCount = NULL;
UProperty* sgPRI::ST_CountryPrefix = NULL;
UProperty* sgPRI::ST_bReadyToPlay = NULL;
UProperty* sgPRI::ST_XC_Orb = NULL;
UProperty* sgPRI::ST_Orders = NULL;
UProperty* sgPRI::ST_RU = NULL;
UProperty* sgPRI::ST_bHideIdentify = NULL;


static UClass* sgPRI_class = NULL;

//sgPRI is preloaded by SiegeGI, finding it is enough
static void Setup_sgPRI( UPackage* SiegePackage)
static void Setup_sgPRI( UPackage* SiegePackage, ULevel* MyLevel)
{
sgPRI_class = NULL;

{for ( TObjectIterator<UClass> It; It; ++It )
if ( (It->GetOuter() == SiegePackage) && !appStricmp(It->GetName(),TEXT("sgPRI")) )
{
sgPRI_class = *It;
break;
} }
FIND_PRELOADED_CLASS(sgPRI,SiegePackage);
check( sgPRI_class != NULL);

//Perform verification (?)
if ( false )
return;

//Modify the sgPRI class to allow native replication
sgPRI_class->ClassConstructor = sgPRI::InternalConstructor;
sgPRI_class->ClassFlags |= CLASS_NativeReplication;
SETUP_CLASS_NATIVEREP(sgPRI);
sgPRI::ReloadStatics( sgPRI_class);
}

INT* sgPRI::GetOptimizedRepList( BYTE* Recent, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map, INT NumReps )
Expand All @@ -88,24 +128,22 @@ INT* sgPRI::GetOptimizedRepList( BYTE* Recent, FPropertyRetirement* Retire, INT*
{
if( Role==ROLE_Authority )
{
DOREP(sgPRI,sgPRI_class,bReadyToPlay);
DOREP(sgPRI,bReadyToPlay);
if ( bNetOwner || NumReps % 8 == 0 ) //Stats, don't perform heavy polling (every 2 secs?)
{
DOREP(sgPRI,sgPRI_class,sgInfoCoreKiller);
DOREP(sgPRI,sgPRI_class,sgInfoBuildingHurt);
DOREP(sgPRI,sgPRI_class,sgInfoCoreRepair);
DOREP(sgPRI,sgPRI_class,sgInfoUpgradeRepair);
DOREP(sgPRI,sgPRI_class,sgInfoKiller);
DOREP(sgPRI,sgPRI_class,sgInfoBuildingMaker);
DOREP(sgPRI,sgPRI_class,sgInfoWarheadMaker);
DOREP(sgPRI,sgPRI_class,sgInfoWarheadKiller);
DOREP(sgPRI,sgInfoCoreKiller);
DOREP(sgPRI,sgInfoBuildingHurt);
DOREP(sgPRI,sgInfoCoreRepair);
DOREP(sgPRI,sgInfoUpgradeRepair);
DOREP(sgPRI,sgInfoKiller);
DOREP(sgPRI,sgInfoBuildingMaker);
DOREP(sgPRI,sgInfoWarheadMaker);
DOREP(sgPRI,sgInfoWarheadKiller);
if ( IpToCountry )
DOREP(sgPRI,CountryPrefix);
}
if ( bNetOwner )
DOREP(sgPRI,sgPRI_class,XC_Orb);

//Don't bother evaluating country prefix if IpToCountry mutator hasn't been located
if ( IpToCountry )
DOREP(sgPRI,sgPRI_class,CountryPrefix);
DOREP(sgPRI,XC_Orb);

UNetConnection* Conn = ((UPackageMapLevel*)Map)->Connection;
if ( Conn->Actor && Conn->Actor->PlayerReplicationInfo )
Expand All @@ -114,12 +152,12 @@ INT* sgPRI::GetOptimizedRepList( BYTE* Recent, FPropertyRetirement* Retire, INT*
{
if ( bNetOwner || NumReps % 4 == 0 ) //No need to spam RU updates if core is simulating
{
DOREP(sgPRI,sgPRI_class,Orders);
DOREP(sgPRI,sgPRI_class,RU);
DOREP(sgPRI,Orders);
DOREP(sgPRI,RU);
}
}
else
DOREP(sgPRI,sgPRI_class,bHideIdentify);
DOREP(sgPRI,bHideIdentify);
}
}
}
Expand Down

0 comments on commit 5eefd3c

Please sign in to comment.