Variables
Variable
Share a value on the network. The value type can be a primitive value or a class. You can share complexe classes with arrays, dictionaries or other classes.
Initialize a float
NetVar<float> _testA;
void Awake() {
_testA = this.NetVar<float>();
}
Change value and update it
_testA.Value = 4.2f; // thats it
Events
_testA.OnHandle += newValue => {}; // On value updated (receive from server)
_testA.OnEmit += newValue => {}; // On value updated (is emitter)
_testA.OnUpdate += newValue => {}; // On value updated (always)
_testA.OnNetworkInit += () => {}; // When this variable become shared on network. (IsNetworked becomes true)
Use getter
_testA.GetterValue = true;
Now, the value uses a lambda to send its value. The value is not sent immediatly, so with this conf, the value sent will always be the last set. (but it is a little more heavy to run)
Priority Changes batch priority
_testA.Priority = PacketsBatcher.Priority.immediate;
Status
_testA.IsNetworked // client is connected and this variable is shared
_testA.IsEmitter // true if this client is the emitter of this variable
_testA.IsActive // !IsNetworked || IsEmitter
This example moves randomly an object on x.
using EODE.Wonderland.SimpleNet;
[RequireComponent(typeof(NetworkedObject))]
public class TestScript : MonoBehaviour {
NetVar<float> _testA;
void Awake() {
_testA = this.NetVar<float>();
}
void Start() {
StartCoroutine(TestRoutine());
}
IEnumerator TestRoutine() {
while (true) {
_testA.Value = Random.Range(-4f, 4f);
yield return new WaitForSeconds(1f);
}
}
void Update() {
transform.position = Vector3.Lerp(transform.position, new Vector3(_testA.Value, transform.position.y, transform.position.z), 0.01f);
}
}
Securize
In host mode, you can add a variable.Securize
function to check entering values.
_text = this.NetVar<int>();
_text.Securize += value => {
return true/false;
};
Event
Event allows you to trigger events on all players.
NetEvent _testB;
void Awake() {
_testB = this.NetEvent();
_testB.OnCall += delay => {
Debug.Log("Call with delay = " + delay);
};
}
void Update() {
if (_testB.IsActive) {
if (Input.GetKeyDown(KeyCode.Keypad0)) {
_testB.Launch(); // trigger event
}
if (Input.GetKeyDown(KeyCode.Keypad1)) {
_testB.Launch(1f); // 1 sec delay
}
if (Input.GetKeyDown(KeyCode.Keypad2)) {
_testB.Launch(2f); // 2 sec delay
}
if (Input.GetKeyDown(KeyCode.Keypad3)) {
_testB.Launch(3f); // 3 sec delay
}
}
}
Delay is updated to try to trigger events at same time on all clients. For example, if client1 has 0.02s delay with the server and client2 has 0.03s; if client1 sends and waits 1s to trigger the event locally, client2 waits 0.95s.
Action
Like NetEvent with values
NetAction _testC;
void Awake() {
_testC = this.NetAction();
_testC.OnCall += (packet, delay) => {
Debug.Log(packet.Read<string>() + ": " + packet.Read<int>());
};
}
void Update() {
if (_testB.IsActive) {
if (Input.GetKeyDown(KeyCode.Keypad0)) {
_testC.Launch("Random value", Random.Range(1, 100), 0f); // trigger event
}
if (Input.GetKeyDown(KeyCode.Keypad1)) {
_testC.Launch("Random value 2", Random.Range(1, 100), 1f); // 1 sec delay
}
}
}
Syncronizer
NetSyncVector2
and NetSyncVector3
includes a synchronizer to manage movements with predictions.
There are 2 methods to use this variable.
Manually
Usefull to follow the movement of an object without physic.
Be sure you understand this point: This method cannot take the value of your local character movement. You must update the synchronizer and after, take the value to move your character. If you only try to pass on the movement of an already scripted entity, it will never result in something usable.
Very simple example of a controlled object with keyboard arrows
using EODE.Wonderland.SimpleNet;
using UnityEngine;
[RequireComponent(typeof(NetworkedObject))]
public class SimpleNetTestSync : MonoBehaviour {
public float Speed = 5f;
NetSyncVector3 _sync = new NetSyncVector3();
void Awake() {
_sync.Init(this, transform.position);
}
void Update() {
if (_sync.IsActive) {
var axis = GetAxis();
if (_prevAxis != axis) {
_prevAxis = axis;
_sync.Move(new Vector3(axis.x, 0f, axis.y));
}
}
transform.localPosition = _sync.Value;
_sync.Forward(transform);
}
public Vector2 GetAxis() {
Vector2 axis = new Vector2(
(Input.GetKey(KeyCode.RightArrow) ? 1f : 0f) + (Input.GetKey(KeyCode.LeftArrow) ? -1f : 0f),
(Input.GetKey(KeyCode.UpArrow) ? 1f : 0f) + (Input.GetKey(KeyCode.DownArrow) ? -1f : 0f)
);
if (Mathf.Abs(axis.x) + Mathf.Abs(axis.y) > 1f) {
axis.x *= 0.68f;
axis.y *= 0.68f;
}
return axis * Speed;
}
Vector2 _prevAxis = Vector2.zero;
}
Automatically
This version can be used to follow a physical object. But there is a latency on the movement.
NetSyncVector3 _sync = new NetSyncVector3();
void Awake() {
_sync.Init(this, transform.position);
}
void FixedUpdate() {
if (_sync.PhysicUpdate()) return;
_body.velocity = ...;
}
void Update() {
if (!_sync.IsActive) {
_sync.Forward(transform);
_body.velocity = _body.velocity * 0.8f; // reduce velocity impact
return;
}
...
}
KinematicCharacterController
simple implementation.
public class KCCPlayer : MonoBehaviour, ICharacterController {
public KinematicCharacterMotor Motor;
NetSyncVector3 _sync = new NetSyncVector3();
Rigidbody _body;
void Awake() {
_sync.Init(this, transform.position);
...
}
private void Start() {
Motor.CharacterController = this;
...
if (!_sync.IsActive) {
Motor.enabled = false;
_body = gameObject.AddComponent<Rigidbody>();
_body.constraints = RigidbodyConstraints.FreezeRotation;
var cc = gameObject.AddComponent<CapsuleCollider>();
cc.height = Motor.Capsule.height;
cc.center = Motor.Capsule.center;
}
...
}
void FixedUpdate() {
if (_sync.PhysicUpdate()) return;
}
void Update() {
if (!_sync.IsActive) {
_sync.Forward(transform);
_body.velocity = _body.velocity * 0.8f;
return;
}
}
...
public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime) {
if (InputsPlayer == null) return;
...
}
Animator
NetAnimator
synchronizes animator parameters.
Manually
NetAnimator _netAnim = new NetAnimator();
void Awake() {
_netAnim.Init(this, GetComponent<Animator>());
// _netAnim.Init(this, GetComponent<Animator>(), 1f); => with delay, try to synchronize animations on network.
}
...
_netAnim.SetFloat("myParam", 4f); // applied to all (online and local)
_netAnim.Play("myAnim");
...
Automatically
Check and share parameters.
NetAnimator _netAnim = new NetAnimator();
void Awake() {
_netAnim.Init(this, GetComponent<Animator>());
_netAnim.Auto = true;
}
You can call
Play
,SetTrigger
,SetBool
,SetInt
,SetFloat
in auto mode