logo
Main

Forums

Downloads

Unreal-Netiquette

Donate for Oldunreal:
Donate

borderline

Links to our wiki:
Wiki

Walkthrough

Links

Tutorials

Unreal Reference

Usermaps

borderline

Contact us:
Submit News
Page Index Toggle Pages: 1 Send TopicPrint
Normal Topic [Snippet] Native replication (Read 614 times)
han
Global Moderator
Unreal Rendering Guru
Developer Team
*****
Offline


Oldunreal member

Posts: 565
Location: Germany
Joined: Dec 10th, 2014
Gender: Male
[Snippet] Native replication
Nov 6th, 2015 at 2:50pm
Print Post  
In the UT2004 script source were some snippets of C++, which also included the native replication statements. This works in DeusEx, and likely other UE1 games. These are slightly modified compared to UT2004 script (See below).

Code
Select All
/*=============================================================================
	RevNet.h: Revision networking.
	Copyright 2015 Sebastian Kaufel. All Rights Reserved.

	Revision history:
		* Created by Sebastian Kaufel
=============================================================================*/

/*-----------------------------------------------------------------------------
	Replication (based on ut2004scripts3369).
-----------------------------------------------------------------------------*/

inline UBOOL NEQ( BITFIELD A, BITFIELD B, UPackageMap* Map )
{
	return A!=B;
}
inline UBOOL NEQ( BYTE A, BYTE B, UPackageMap* Map )
{
	return A!=B;
}
inline UBOOL NEQ( INT A, INT B, UPackageMap* Map )
{
	return A!=B;
}
inline UBOOL NEQ( FLOAT& A, FLOAT& B, UPackageMap* Map)
{
	return *(INT*)&A!=*(INT*)&B;
}
inline UBOOL NEQ( FVector& A, FVector& B, UPackageMap* Map)
{
	return ((INT*)&A)[0]!=((INT*)&B)[0]
			|| ((INT*)&A)[1]!=((INT*)&B)[1]
			|| ((INT*)&A)[2]!=((INT*)&B)[2];
}
inline UBOOL NEQ( FRotator& A, FRotator& B, UPackageMap* Map)
{
	return A.Pitch!=B.Pitch
			|| A.Yaw  !=B.Yaw
			|| A.Roll !=B.Roll;
}
inline UBOOL NEQ( UObject* A, UObject* B, UPackageMap* Map)
{
	return (Map->CanSerializeObject(A) ? A : NULL)!=B;
}
inline UBOOL NEQ( FName& A, FName B, UPackageMap* Map)
{
	return *(INT*)&A!=*(INT*)&B;
}
inline UBOOL NEQ( FColor& A, FColor& B, UPackageMap* Map)
{
	return *(INT*)&A!=*(INT*)&B;
}
inline UBOOL NEQ( FPlane& A, FPlane& B, UPackageMap* Map)
{
	return ((INT*)&A)[0]!=((INT*)&B)[0]
			|| ((INT*)&A)[1]!=((INT*)&B)[1]
			|| ((INT*)&A)[2]!=((INT*)&B)[2]
			|| ((INT*)&A)[3]!=((INT*)&B)[3];
}
inline UBOOL NEQ( const FString& A, const FString& B, UPackageMap* Map )
{
	return A!=B;
}

#define DOREP(c,v) \
	if( NEQ(v,((A##c*)Recent)->v,Map) ) \
	{ \
		static UProperty* sp##v = FindObjectChecked<UProperty>(A##c::StaticClass(),TEXT(#v)); \
		*Ptr++ = sp##v->RepIndex; \
	}
#define DOREPARRAY(c,v) \
	{static UProperty* sp##v = FindObjectChecked<UProperty>(A##c::StaticClass(),TEXT(#v)); \
	for( INT i=0; i<ARRAY_COUNT(v); i++ ) \
		if( NEQ(v[i],((A##c*)Recent)->v[i],Map) ) \
				*Ptr++ = sp##v->RepIndex+i;}

// Useful to replicate single BlendAnim slots.
#define DOREPARRAYINDEX(c,v,i) \
	{static UProperty* sp##v = FindObjectChecked<UProperty>(A##c::StaticClass(),TEXT(#v)); \
	if( NEQ(v[i],((A##c*)Recent)->v[i],Map) ) \
			*Ptr++ = sp##v->RepIndex+i;}

/*-----------------------------------------------------------------------------
	The End.
-----------------------------------------------------------------------------*/
 



The cool thing about native replication is, that you can override the whole native replication of the parent classes. In fact you can even disable the script replication. However, for native replication you *still* need a replication index, which gets created when loading the class. Thats on of the reason why there is an unrealscript replication statement in a nativereplication class. The other reason is that, when you replicate stuff to the server, the server switches netroles and runs the uc replication statement to see if he "wants" it. Another thing worth to mention is that native replication is just for variables, *never* for functions.

For nativer replication basically four major functions which are important:
Code
Select All
	// AActor interface.
	INT* GetOptimizedRepList( BYTE* InDefault, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map );
	void PreNetReceive();
	void PostNetReceive();
	INT* GetOptimizedRepList( BYTE* InDefault, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map );
 



GetOptimizedRepList() basically is where the main magic happens, and you decide which properties you want to replicate or not. It's not much different compared to the unrealscript replication statements.

Example:
Code
Select All
INT* AHXPlayerPawn::GetOptimizedRepList( BYTE* Recent, FPropertyRetirement* Retire, INT* Ptr, UPackageMap* Map )
{
	guard(AHXPlayerPawn::GetOptimizedRepList)

	Ptr = AActor::GetOptimizedRepList( Recent, Retire, Ptr, Map );

	// Actor Overrides.
	if ( Role==ROLE_Authority )
	{
		if( DrawType==DT_Mesh && ((RemoteRole<=ROLE_SimulatedProxy && (!bNetOwner || !bClientAnim)) || bDemoRecording) )
		{
			// Head Movement.
			DOREPARRAYINDEX(Actor,BlendAnimSequence,3);
			DOREPARRAYINDEX(Actor,SimBlendAnim,3);
			DOREPARRAYINDEX(Actor,BlendAnimMinRate,3);
		}
	}

	// [...]


	// Check if native replication keyword is that. That way you can easily toggle by setting the uc nativereplication keyword to toggle between native and script replication.
	if ( StaticClass()->ClassFlags & CLASS_NativeReplication )
	{
	}

	return Ptr;
	unguard;
}
 



So the above snippet basically just adds replication for some blend animation variables, ion luckily left inside the replication statement, but took out (or never implemented) the native one. So the next two suckers are PreNetReceive()/PostNetReceive(). They will be called before and after a property receives a network update. So I could use that in HX to catch the change of the properties and control the animations, and it turned out that network replication for that one blendanimation slot was really helpful.

Code
Select All
FPlane PreSimBlendAnim[4];

// NetReceive.
void AHXPlayerPawn::PreNetReceive()
{
	guard(AHXPlayerPawn::PreNetReceive);

	Super::PreNetReceive();

	// Head Movement only.
	PreSimBlendAnim[3] = SimBlendAnim[3];

	unguard;
}
void AHXPlayerPawn::PostNetReceive()
{
	guard(AHXPlayerPawn::PostNetReceive);

	Super::PostNetReceive();

	// Head Movement only.
	if ( SimBlendAnim[3]!=PreSimBlendAnim[3] )
	{
		BlendAnimFrame[3] = SimBlendAnim[3].X * 0.0001;
		BlendAnimRate[3]  = SimBlendAnim[3].Y * 0.0001;
		BlendTweenRate[3] = SimBlendAnim[3].Z * 0.001;
		BlendAnimLast[3]  = SimBlendAnim[3].W * 0.0001;

		if ( BlendAnimLast[3]<0.0 )
		{
			BlendAnimLast[3] *= -1.0;
			if ( BlendAnimMinRate[3]<0.5 )
				BlendAnimMinRate[3] = 0.5;
		}
	}
	unguard;
}
 



The forth function, ShouldDoScriptReplication() basically dictates whether script replication should be run at all. This is infamously used by Inventory class to cause some weired behaviour I still have trouble with. Keep in mind, if you disable script replication, it affects *ALL* subclasses, and if they are unreal script only, they have no way to enable it again.
  

HX on Mod DB. Revision on Steam.
Back to top
 
IP Logged
 
Page Index Toggle Pages: 1
Send TopicPrint
Bookmarks: del.icio.us Digg Facebook Google Google+ Linked in reddit StumbleUpon Twitter Yahoo