KF1 mod 开发教程
网络变量复制
在多人游戏中有一个关键字叫做 replication“复制”, 该关键字用来将 服务端变量同步到客户端中。

如果某些变量需要 服务端、客户端 保持同步,就需要在 replication{} 语句块中加入变量名; 以下代码参考自:PlayerReplicationInfo.uc
replication
{
	if( Role==ROLE_Authority )
	    Score;
}
这里同步的是 Score 变量,并且前面有一个条件判断 Role==ROLE_Authority 表示该变量由“服务端”发送,客户端将接收到该变量的远程副本。

同步条件是为了应付各种“特殊情况”指定要同步的变量,虚幻官方文档中会有介绍。 如果要在一个条件下同步多个变量 可用逗号隔开;这些变量应该都是类成员变量。
replication
{
	if( Role==ROLE_Authority )
	    Score, Deaths, bHasFlag;
}
颜色值示例
为了更方便的说明多人游戏中的“变量复制”,我们将获得随机的“颜色值”。 前提是将原来的插件代码清理一下,改成如下
var color TrailColor;

function PostBeginPlay()
{
	// 设置计时器,每一秒执行一次
	SetTimer(1, true);
}

function Timer()
{
	local PlayerController PC;
	local string color_str;

	// 得到“随机颜色值”
	TrailColor = class'Canvas'.static.MakeColor(rand(255),rand(255),rand(255),255);

	PC = Level.GetLocalPlayerController();
	if (PC != none)
	{
	    // 在玩家控制台输出:颜色值
	    color_str = "TrailColor: " $ string(TrailColor.r) $ ", "
	                               $ string(TrailColor.g) $ ", "
	                               $ string(TrailColor.b);
		
	    PC.Player.Console.Message(color_str, 0);
	}

}
代码编写流程如下:
  1. 定义类成员变量 TrailColor 用于存储“颜色值”
  2. 游戏开始后,设置好“每秒执行一次”的计时器
  3. 在计时器中获取随机颜色值,并将其格式化输出到“玩家控制台”
在 Canvas 类中正好有一个制作颜色值的静态函数,所以直接拿来用; 访问类的静态函数 这里暂不做解释。

由于颜色值是一个“结构体”有 r、g、b 三个整数成员, 需要使用强制类型转换 string() 才能拼接成字符串输出。 符号 $ 可用来拼接两个字符串。

这里的颜色值是随机产生的,如果只用模拟函数 客户端也产生的随机数, 将产生不同的数字,即 服务器端的颜色 和 客户端的颜色 不可能相同。

为了保持变量值的同步,我们需要“复制声明”和“处理接收”。
变量同步
这里将需要同步的变量 TrailColor 写入“复制声明”中
replication
{
	unreliable if (Role == ROLE_Authority)
	    TrailColor;
}
条件 if 前面又加了一个关键字 unreliable 表示“不可靠复制”, 所谓不可靠是为了节省宽带,不用检测变量值的完全同步。

默认情况是可靠同步,为了预防掉帧等问题 可靠同步需要多次确定变量值,会占用更多网络资源。


变量值是同步之后 还需要一个函数在接收到同步数据后进行处理, 客户端在接收到同步数据后 会调用函数 PostNetReceive() 进行后续处理

最终我们在接收到变量复制后,将颜色值应用到“路径提示”上
simulated function PostNetReceive()
{
	local RedWhisp RW;

	// 更改“商店路线”的颜色
	foreach DynamicActors(class'KFMod.RedWhisp', RW)
	{
	    RW.mColorRange[0] = TrailColor;
	    RW.mColorRange[1] = TrailColor;
	}
}
该函数不需要接收参数,因为 TrailColor 是类成员变量,可直接在函数中访问; 并且函数前面还有一个 simulated 模拟关键字,用于让客户端模拟执行。

并且还要在“默认属性”中设置 bNetNotify=true 表示允许网络通知
defaultproperties
{
	GroupName="KF-ABCMutator"
	FriendlyName="ABCMutator"
	Description="..."

	RemoteRole=ROLE_SimulatedProxy
	bAlwaysRelevant=true
	bAddToServerPackages=true

	bNetNotify=true
}
用 VM 启动游戏进入房间,在商店时间提示路径时 会发现路径颜色发生改变; 服务端 只是负责发送数据 而没有接收数据,所以“服务端”不会执行 PostNetReceive() 函数。

提示:不建议用正版与破解版测试,破解版进不了正版的监听房间。 使用正版用于编译插件,然后扔到破解版上创建房间即可。


如果想让服务器端也执行“路径换颜色”效果,可以单独在 Timer 函数内执行替换颜色。 或将颜色替换 另写成一个函数,可供多处调用(实际上就是让服务端单独执行一次换颜色)。

完整的插件代码:
// 插件类
class ABCMutator extends Mutator;

var color TrailColor;

function PostBeginPlay()
{
	// 设置计时器,每一秒执行一次
	SetTimer(1, true);
}

function Timer()
{
	// 得到“随机颜色值”
	TrailColor = class'Canvas'.static.MakeColor(rand(255),rand(255),rand(255),255);

	// 服务端单独执行 路径颜色替换
	ReplacePathColor();
}

replication
{
	unreliable if (Role == ROLE_Authority)
	    TrailColor;
}

// 路径颜色替换
simulated function ReplacePathColor()
{
	local RedWhisp RW;

	// 更改“商店路线”的颜色
	foreach DynamicActors(class'KFMod.RedWhisp', RW)
	{
	    RW.mColorRange[0] = TrailColor;
	    RW.mColorRange[1] = TrailColor;
	}
}

// 处理数据同步
simulated function PostNetReceive()
{
	local PlayerController PC;
	local string color_str;

	// 访问 路径颜色替换
	ReplacePathColor();

	PC = Level.GetLocalPlayerController();
	if (PC != none)
	{
	    // 在玩家控制台输出:颜色值
	    color_str = "TrailColor: " $ string(TrailColor.r) $ ", "
	                               $ string(TrailColor.g) $ ", "
	                               $ string(TrailColor.b);
	    
	    PC.Player.Console.Message(color_str, 0);
	}
}


defaultproperties
{
	GroupName="KF-ABCMutator"
	FriendlyName="ABCMutator"
	Description="..."

	RemoteRole=ROLE_SimulatedProxy
	bAlwaysRelevant=true
	bAddToServerPackages=true

	bNetNotify=true
}
更多关于网络复制的参考资料,请查看虚幻官方文档:
https://docs.unrealengine.com/udk/Three/NetworkingOverviewCH.html