当前位置:网站首页>Mlapi series - 04 - network variables and network serialization [network synchronization]
Mlapi series - 04 - network variables and network serialization [network synchronization]
2022-07-06 04:08:00 【Feilang era [fwc – fe]】
MLAPI series - 04 - Network variables and network serialization 【 Network synchronization 】
- One 、 Overview of network synchronization
- Two 、 Network variables
- 3、 ... and 、 About framework built-in serialization
- Four 、 Network variables use
- 5、 ... and 、 MLAPI pre-10 Some changes in the version
One 、 Overview of network synchronization
Netcode There are two main means of network synchronization : The first is the RPC Mechanism , The remote invocation , The second is to use network variables .
Two 、 Network variables
Network variables belong to Netcode Unique network type , Package maintenance one Value, If you want to encapsulate multiple fields or arrays, you need to encapsulate them yourself .
3、 ... and 、 About framework built-in serialization
1 Network variables are defined as generic classes
NetworkVariable
, Support C# Basic types 、Unity Basic types 、 Custom enumeration .2 RPC Pass message parameters , You need to use serializable types , The following serializable types and inherited serialization interfaces are supported
INetworkSerializable
Custom serialization type of .
1 C# The base type
C# The base type will be serialized by the built-in serialization code .
These types include :bool, char, sbyte, byte, short, ushort, int, uint, long, ulong, float, double, and string.
[ServerRpc]
void FooServerRpc(int somenumber, string sometext) {
/* ... */ }
void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
// Client -> Server
FooServerRpc(Time.frameCount, "hello, world");
}
}
2 Unity The base type
Unity The base type Color, Color32, Vector2, Vector3, Vector4, Quaternion, Ray, Ray2D The type will be serialized by the built-in serialization code .
[ClientRpc]
void BarClientRpc(Color somecolor) {
/* ... */ }
void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
BarClientRpc(Color.red); // Server -> Client
}
}
3 Enumeration type
User defined enumeration types will be serialized by built-in serialization code ( Use the base integer type )
enum SmallEnum : byte // 0-255 Limited length
{
A,
B,
C
}
enum NormalEnum // default -> int
{
X,
Y,
Z
}
[ServerRpc]
void ConfigServerRpc(SmallEnum smallEnum, NormalEnum normalEnum)
{
/* ... */ }
void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
ConfigServerRpc(SmallEnum.A, NormalEnum.X); // Client -> Server
}
}
4 Array
image int[] Such an array Serialized by built-in serialization code :
If their base type is one of the types that support serialization ( Such as Vector3) perhaps Whether they realize INetworkSerializable Interface .
[ServerRpc]
void HelloServerRpc(int[] scores, Color[] colors) {
/* ... */ }
[ClientRpc]
void WorldClientRpc(MyComplexType[] values) {
/* ... */ }
5 INetworkSerializable Interface
INetworkSerializable
Interface can be used to define custom serializable types .
struct MyComplexStruct : INetworkSerializable
{
public Vector3 Position;
public Quaternion Rotation;
// INetworkSerializable
void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref Position);
serializer.SerializeValue(ref Rotation);
}
// ~INetworkSerializable
}
// Implementation types INetworkSerializable, And be NetworkSerializer, RPCs and NetworkVariable Support
[ServerRpc]
void MyServerRpc(MyComplexStruct myStruct) {
/* ... */ }
void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
MyServerRpc(
new MyComplexStruct
{
Position = transform.position,
Rotation = transform.rotation
}); // Client -> Server
}
}
5.1 Nested sequence type
Nested sequence types will be null Unless you initialize in one of the following ways :
- Manually before calling SerializeValue If serializer.IsReader( Or something like that )
- Initialize in the default constructor
This is intentional . Before initializing correctly , You may see that these values are null. The serializer did not deserialize them , therefore null Values are simply applied before serialization .
5.2 Conditional serialization
Because there is more control over the serialization of structures , So you can implement conditional serialization at run time .
Example : Array
public struct MyCustomStruct : INetworkSerializable
{
public int[] Array;
void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
// Length
int length = 0;
if (!serializer.IsReader)
{
length = Array.Length;
}
serializer.SerializeValue(ref length);
// Array
if (serializer.IsReader)
{
Array = new int[length];
}
for (int n = 0; n < length; ++n)
{
serializer.SerializeValue(ref Array[n]);
}
}
}
Read :
serialize ( Deserialization )length Flow back from
iteration Array member n=length times Serialize the value ( Deserialization ) Back to array [n] Elements in the streamwrite in :
Serialization length = Array Length of the write stream
Iterate over array members n = Length times Serialize the values in the array [n] Element is added to the stream
this BufferSerializer.IsReader Flags are used here to determine whether to set length value , Then we use it to determine whether to create a new int[] Examples and length Size to set Array Before reading the value from the stream .
There is another equivalent but opposite BufferSerializer.IsWriting
Example : Move
public struct MyMoveStruct : INetworkSerializable
{
public Vector3 Position;
public Quaternion Rotation;
public bool SyncVelocity;
public Vector3 LinearVelocity;
public Vector3 AngularVelocity;
void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
// Position & Rotation
serializer.SerializeValue(ref Position);
serializer.SerializeValue(ref Rotation);
// LinearVelocity & AngularVelocity
serializer.SerializeValue(ref SyncVelocity);
if (SyncVelocity)
{
serializer.SerializeValue(ref LinearVelocity);
serializer.SerializeValue(ref AngularVelocity);
}
}
}
Read :
serialize ( Deserialization )Position Flow back from
serialize ( Deserialization )Rotation Flow back from
serialize ( Deserialization )SyncVelocity Flow back from
Check whether the SyncVelocity Set to true, If so :
serialize ( Deserialization )LinearVelocity Flow back from
serialize ( Deserialization )AngularVelocity Flow back from
write in :
load Position Into the stream
load Rotation Into the stream
load SyncVelocity Into the stream
Check whether the SyncVelocity Set to true, If so :
load LinearVelocity Into the stream
load AngularVelocity Into the stream
Different from the arrangement in the above example , We didn't use BufferSerializer.IsReader Flag to change the serialization logic , But change the value of the serialization flag itself .If SyncVelocity Flag set to true , be LinearVelocity and AngularVelocity Will be serialized into the stream
When SyncVelocity Flag set to false, We will leave LinearVelocity and AngularVelocity Use the default value .
5.3 Recursive nested serialization
Nested members can be serialized recursively INetworkSerializable Interfaces in the hierarchical tree .
Example :
public struct MyStructA : INetworkSerializable
{
public Vector3 Position;
public Quaternion Rotation;
void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref Position);
serializer.SerializeValue(ref Rotation);
}
}
public struct MyStructB : INetworkSerializable
{
public int SomeNumber;
public string SomeText;
public MyStructA StructA;
void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref SomeNumber);
serializer.SerializeValue(ref SomeText);
StructA.NetworkSerialize(serializer);
}
}
If we want to load separately MyStructA, It will use NetworkSerializer load Position and Rotation Inflow ,.
However , If we want to serialize MyStructB, It serializes SomeNumber and SomeText Into the stream , Then serialize StructA adopt Call -
MyStructA void
NetworkSerialize(NetworkSerializer) Method , This method serializes Position and Rotation Enter the same first-class .
Be careful
Technically speaking , There is no hard limit to the number INetworkSerializable Fields that can be serialized along the tree hierarchy . In practice , Consider memory and bandwidth boundaries for best performance .
You can conditionally serialize in a recursive nested serialization scenario , And use these two functions .
6 Custom Serialization
When using RPCs,NetworkVariable Or any other game object network code that needs to be serialized (Netcode) Related tasks .Netcode Use the default serialization pipeline , As shown below :
Custom Types => Built In Types => INetworkSerializable
in other words , When Netcode The first time you get a type , It will check any custom types that the user has registered for serialization , Then it will check whether it is a built-in type , Such as Vector3、float etc. . These are handled by default . If not , It will check whether the type inherits INetworkSerializable If there is , It will call its write Method .
By default , Any satisfaction unmanaged Generic constraints can be automatically serialized as RPC Parameters . This includes all basic types (bool、byte、int、float、enum etc. ) And any structure that contains only these basic types .
Through this process , You can override all serialization types , Even built into types , And use the provided API, It can even be done with types that you don't define yourself , Those types behind the third-party wall , for example . Network type .
To register a custom type or override a processed type , Need to be for FastBufferReader.ReadValueSafe() and FastBufferWriter.WriteValueSafe():
// tell Netcode How to serialize and deserialize in the future Url.
// The class name doesn't matter here .
public static class SerializationExtensions
{
public static void ReadValueSafe(this FastBufferReader reader, out Url value)
{
reader.ReadValueSafe(out string val);
value = new Url(val);
}
public static void WriteValueSafe(this FastBufferWriter writer, in Url value)
{
writer.WriteValueSafe(instance.Value);
}
}
RPC
The code generation of will be directly through FastBufferWriter
and FastBufferReader
Get and use these functions automatically .
You can also choose to use the same method to add pairs BufferSerializer<TReaderWriter>.SerializeValue()
, If you will , This will make this type in INetworkSerializable
type :
// The class name doesn't matter here .
public static class SerializationExtensions
{
public static void SerializeValue<TReaderWriter>(this BufferSerializer<TReaderWriter> serializer, ref Url value) where TReaderWriter: IReaderWriter
{
if (serializer.IsReader)
{
value = new Url();
}
serializer.SerializeValue(ref value.Value);
}
}
7 Network objects and network behavior
GameObjects
, NetworkObjects
and NetworkBehaviour
Not a serializable type , So it can't be in RPC
perhaps NetworkVariables
By default .
There are two convenient wrappers
【 Wrappers 】 Can be used to send pairs NetworkObject
Or a NetworkBehaviour
adopt RPC
or NetworkVariables
.
7.1 NetworkObjectReference Network object reference type
NetworkObjectReference
Can be used to serialize pairs NetworkObject
. It can only be used on already generated NetworkObjects
.
Here is a use NetworkObject
Reference of sending target NetworkObject
adopt RPC
:
public class Weapon : NetworkBehaviour
{
public void ShootTarget(GameObject target)
{
var targetObject = target.GetComponent<NetworkObject>();
ShootTargetServerRpc(targetObject);
}
[ServerRpc]
public void ShootTargetServerRpc(NetworkObjectReference target)
{
if (target.TryGet(out NetworkObject targetObject))
{
// deal damage or something to target object.
}
else
{
// Target not found on server, likely because it already has been destroyed/despawned.
}
}
}
7.2 Implicit Operators Implicit operation
And from / Implicit operator to transform NetworkObject
/GameObject
This can be used to simplify code . for example , The above example can also be written in the following way :
NetworkObjectReference -> NetworkObject
GameObject -> NetworkObjectReference
public class Weapon : NetworkBehaviour
{
public void ShootTarget(GameObject target)
{
ShootTargetServerRpc(target);
}
[ServerRpc]
public void ShootTargetServerRpc(NetworkObjectReference target)
{
NetworkObject targetObject = target;
}
}
Be careful : If the reference is not found , To
NetworkObject
/GameObject
The implicit conversion of will result in Null.
7.3 NetworkBehaviourReference Network behavior reference
NetworkBehaviourReference
Work in a way similar to NetworkObjectReference
It is used to refer to specific NetworkBehaviour
Derived components on NetworkObject
.
public class Health : NetworkBehaviour
{
public NetworkVariable<int> Health = new NetworkVariable<int>();
}
public class Weapon : NetworkBehaviour
{
public void ShootTarget(GameObject target)
{
var health = target.GetComponent<Health>();
ShootTargetServerRpc(health, 10);
}
[ServerRpc]
public void ShootTargetServerRpc(NetworkBehaviourReference health, int damage)
{
if (health.TryGet(out Health healthComponent))
{
healthComponent.Health.Value -= damage;
}
}
}
7.4 Network object reference 、 How network behavior references work
NetworkObjectReference
and NetworkBehaviourReference
It's convenient wrappers
Wrappers , It serializes NetworkObject When sending , Retrieve the corresponding Use that id.NetworkBehaviourReference
Send an additional index , Used to find the correct NetworkBehaviour
In which NetworkObject
On .
They all achieve INetworkSerializable
Interface .
Four 、 Network variables use
Network variable generic class NetworkVariable
, Support C# Basic types and Unity Basic types .
1 bool Network variables of type use
When NetworkVariable<T>
Of Value
change , OnValueChanged
Callback the parameter with old and new values , The callback function should constantly poll for the latest value in response to value changes .
public class Door : NetworkBehaviour
{
public NetworkVariable<bool> State = new NetworkVariable<bool>();
public override void OnNetworkSpawn()
{
State.OnValueChanged += OnStateChanged;
}
public override void OnNetworkDespawn()
{
State.OnValueChanged -= OnStateChanged;
}
public void OnStateChanged(bool previous, bool current)
{
// note: `State.Value` will be equal to `current` here
if (State.Value)
{
// door is open:
// - rotate door transform
// - play animations, sound etc.
}
else
{
// door is closed:
// - rotate door transform
// - play animations, sound etc.
}
}
[ServerRpc(RequireOwnership = false)]
public void ToggleServerRpc()
{
// this will cause a replication over the network
// and ultimately invoke `OnValueChanged` on receivers
State.Value = !State.Value;
}
}
2 Read and write permissions of network variables
By default ,NetworkVariable<T>
It can only be written by the server and can be read by anyone . These permissions can be changed through the constructor .
// A snippet from the Netcode SDK
public abstract class NetworkVariableBase
{
// ...
public const NetworkVariableReadPermission DefaultReadPerm =
NetworkVariableReadPermission.Everyone;
public const NetworkVariableWritePermission DefaultWritePerm =
NetworkVariableWritePermission.Server;
// ...
}
public class NetworkVariable<T> : NetworkVariableBase
{
// ...
public NetworkVariable(T value = default,
NetworkVariableReadPermission readPerm = DefaultReadPerm,
NetworkVariableWritePermission writePerm = DefaultWritePerm)
{
// ...
}
// ...
}
2.1 Read
public enum NetworkVariableReadPermission
{
Everyone,
Owner
}
Everyone → All clients and server will get value updates.
Owner → Only server and the owner client will get value updates.
2.2 Write
public enum NetworkVariableWritePermission
{
Server,
Owner
}
Server → Only the server can write to the value.
Owner → Only the owner client can write to the value, server can’t write to the value.
3. Sample code integration
public class Cube : NetworkBehaviour
{
// everyone can read, only owner can write
public NetworkVariable<Vector3> NetPosition = new NetworkVariable<Vector3>(
default,
NetworkVariableBase.DefaultReadPerm, // Everyone
NetworkVariableWritePermission.Owner);
private void FixedUpdate()
{
// owner writes, others read & apply
if (IsOwner)
{
NetPosition.Value = transform.position;
}
else
{
transform.position = NetPosition.Value;
}
}
// everyone can read, only server can write
public NetworkVariable<Color> NetColor = new NetworkVariable<Color>(
default,
NetworkVariableBase.DefaultReadPerm, // Everyone
NetworkVariableWritePermission.Server);
public override void OnNetworkSpawn()
{
NetColor.OnValueChanged += OnColorChanged;
}
public override void OnNetworkDespawn()
{
NetColor.OnValueChanged -= OnColorChanged;
}
public void OnColorChanged(Color previous, Color current)
{
// update materials etc.
}
[ServerRpc(RequireOwnership = false)]
public void ChangeColorServerRpc()
{
NetColor.Value = Random.ColorHSV();
}
}
5、 ... and 、 MLAPI pre-10 Some changes in the version
0.0 Upgrade instructions
lately Netcode The upgrade pre-10 edition , The official repaired some bug, Will the blogger provide from pre-6 Version of the custom generic network variable compilation caused the editor to crash bug Repair the , There are other changes .
1 Fix array generic crash
Fixed NetworkAnimator issue where it was not always disposing the NativeArray that is allocated when spawned. (#1946)
2 ClientNetworkTransform Base class function name OnIsServerAuthoritatitive change
Before the change :
// Overwrite this value and return false To follow the owner's permissions , otherwise , The default is server permission
protected override bool OnIsServerAuthoritatitive()
{
return false;
}
After modification :
// Overwrite this value and return false To follow the owner's permissions , otherwise , The default is server permission
protected override bool OnIsServerAuthoritative()
{
return false;
}
3 Base class changes :NetworkVariableSerialization It is amended as follows NetworkVariableBase
After upgrading , Partial inheritance NetworkVariableSerialization
Of Custom network variable script There may be an error .
The reason for the error is that the base class used in the transition phase is used NetworkVariableSerialization
May be ready to abandon .
3.1 Error reason
1 Before version upgrade , It belongs to excessive script , Same as network variables , Inherits the network variable base class
NetworkVariableBase
, rewriteReadDelta
And other base class methods can use encapsulatedRead
andWrite
Static methods
1.1 Easy to use
----------------------------------------------------------------------------------------【pre-9】
2 After version upgrade , Removed base class 、Read
andWrite
Static method, etc
2.1 The custom network variable returns to the base class of the network variableNetworkVariableBase
that will do
----------------------------------------------------------------------------------------【pre-10】
3.2 Example of script modification
Before modification :
Read(reader, out Value.Array[i]);
After the changes :
reader.ReadValueSafe(out Value.Array[i]);
边栏推荐
- C#(二十八)之C#鼠标事件、键盘事件
- Ipv4中的A 、B、C类网络及子网掩码
- Thread sleep, thread sleep application scenarios
- [introduction to Django] 11 web page associated MySQL single field table (add, modify, delete)
- TCP/IP协议里面的网关地址和ip地址有什么区别?
- 10个 Istio 流量管理 最常用的例子,你知道几个?
- Fundamentals of SQL database operation
- In Net 6 CS more concise method
- Global and Chinese markets for patent hole oval devices 2022-2028: Research Report on technology, participants, trends, market size and share
- How can programmers resist the "three poisons" of "greed, anger and ignorance"?
猜你喜欢
lora网关以太网传输
C form application of C (27)
Path of class file generated by idea compiling JSP page
Ipv4中的A 、B、C类网络及子网掩码
[disassembly] a visual air fryer. By the way, analyze the internal circuit
[PSO] Based on PSO particle swarm optimization, matlab simulation of the calculation of the lowest transportation cost of goods at material points, including transportation costs, agent conversion cos
颠覆你的认知?get和post请求的本质
【可调延时网络】基于FPGA的可调延时网络系统verilog开发
Facebook等大廠超十億用戶數據遭泄露,早該關注DID了
MySQL reads missing data from a table in a continuous period of time
随机推荐
Facebook等大厂超十亿用户数据遭泄露,早该关注DID了
Alibaba testers use UI automated testing to achieve element positioning
asp. Core is compatible with both JWT authentication and cookies authentication
No qualifying bean of type ‘......‘ available
Practical development of member management applet 06 introduction to life cycle function and user-defined method
The global and Chinese market of negative pressure wound therapy unit (npwtu) 2022-2028: Research Report on technology, participants, trends, market size and share
Yyds dry goods inventory hcie security Day11: preliminary study of firewall dual machine hot standby and vgmp concepts
Several important classes in unity
Codeforces Round #770 (Div. 2) B. Fortune Telling
DM8 backup set deletion
Determine which week of the month the day is
Scalpel like analysis of JVM -- this article takes you to peek into the secrets of JVM
Benefits of automated testing
判断当天是当月的第几周
Global and Chinese markets for MRI safe implants 2022-2028: technology, participants, trends, market size and share Research Report
SSTI template injection explanation and real problem practice
MySQL about self growth
【FPGA教程案例11】基于vivado核的除法器设计与实现
阿里测试师用UI自动化测试实现元素定位
Exchange bottles (graph theory + thinking)