Unity-Technologies / com.unity.netcode.gameobjects

Netcode for GameObjects is a high-level netcode SDK that provides networking capabilities to GameObject/MonoBehaviour workflows within Unity and sits on top of underlying transport layer.
MIT License
2.15k stars 435 forks source link

ApprovalCheck function might need update on your Wiki #131

Closed IoannisKaragiannis closed 6 years ago

IoannisKaragiannis commented 6 years ago

Question

Description

I have downloaded your latest release and try to create a server and a client from scratch based on your Wiki.

    private void ApprovalCheck(byte[] connectionData, uint clientId, Action<uint, bool, Vector3, Quaternion> callback)
    {
        //Your logic here
        bool approve = true;
        //If approve is true, the connection gets added. If it's false. The client gets disconnected
        callback(clientId, approve, new Vector3(0,0,0), Quaternion.identity);
    }

However, the following line

NetworkingManager.singleton.ConnectionApprovalCallback = ApprovalCheck;

complains that "No overload for ApprovalCheck matches delegate 'Action<byte[], uint, NetworkingManager.ConnectionApprovedDelegate>"

Could you give me some hint how to resolve this issue?

Your Environment

TwoTenPvP commented 6 years ago

Right, the overload changed from being an action to its own delegate type.

IoannisKaragiannis commented 6 years ago

Ok. I do it like this now instead and it seems to be working

    private void ApprovalCheck(byte[] data, uint clientId, ConnectionApprovedDelegate connectionApprovedDeligate)
    {
        connectionApprovedDeligate(clientId, 0, true, new Vector3(0,0.5f,0), Quaternion.identity);
    }

However, although the client is spawned at the right place, the server does not keep track of how it moves. Should I introduce some message handlers and a dedicated channel for them in the NetworkConfig? I thought that your NetworkedTransform was handling that automatically.

Thanks

TwoTenPvP commented 6 years ago

I think something is broken with the NetworkedTransform. I will have to look into it when I have time.

IoannisKaragiannis commented 6 years ago

Ok, I see. Thanks

IoannisKaragiannis commented 6 years ago

Btw, I tried to use your wiki example to send and receive a random integer from and to the server but I get the following exception

NullReferenceException: Object reference not set to an instance of an object
MLAPI.NetworkedBehaviour.get_networkId () (at <84778170b09d402bb1d84ca28ebe735f>:0)
MLAPI.NetworkedBehaviour.SendServerRPCPerformance (System.UInt64 hash, System.IO.Stream messageStream) (at <84778170b09d402bb1d84ca28ebe735f>:0)
MLAPI.NetworkedBehaviour.InvokeServerRpc (MLAPI.RpcDelegate method, System.IO.Stream stream) (at <84778170b09d402bb1d84ca28ebe735f>:0)
NetManagerHud.OnGUI () (at Assets/Scripts/NetManagerHud.cs:58)

I used the performance mode example.

Thanks

IoannisKaragiannis commented 6 years ago

Ok, I cracked it. I should attach the respective script onto a networked object. I was erroneously doing it on the NetManagerHud which is a component of my NetworkManager, which is not a networked object, and has therefore no netID.

IoannisKaragiannis commented 6 years ago

Hej I have a more generic question. Other than introducing certain things like networkedVar, networkedDict, etc, how is the newest mlapi better in terms of performance. Have you reduced the bandwidth? What about the latency? What would you describe as the major improvement from v1.3.0 to v2.1.1? Btw I really like the new messaging system with RPCs. Way cleaner. And not having to insert the name of the messages or the channel in the networkConfig of the network manager makes things much easier. Nice job!!!

TwoTenPvP commented 6 years ago

CPU performance is always being improved. As for bandwidth. The new RPC system comes with a penalty of half a byte extra on average. But the general MLAPI headers have been reduced. Thus, overall bandwidth should be lower

IoannisKaragiannis commented 6 years ago

Fair enough. I will test the RTT soon. By the way, I tried to use the NetworkedTransform from v2.1.0 and it was working fine. Didn't go through the details but it should be at some commit between these two releases that it broke. If I find it I will let you know.

IoannisKaragiannis commented 6 years ago

Hi again,

I need some help on the SendTickrate, ReceiveTickrate and EventTickrate. Assuming we have an update loop of 60Hz, how should I set the above-mentioned variables in a reasonable manner? Should they all have the same value, e.g.: 50? Does the network manager need to be configured in the exact same way with respect to those variables for the server and the client? How did you come up with the default 64?

Thanks

IoannisKaragiannis commented 6 years ago

Still need some help. I'm trying to send a message from the client to the server using the following code:

using MLAPI;
using MLAPI.Serialization;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class TestRPCSystem : NetworkedBehaviour
{
    private int msgID = 0;

    private void OnGUI()
    {
        if (GUI.Button(new Rect(130, 160, 80, 20), "SendRandomInt"))
        {
            if (isServer)
            {
                using (PooledBitStream stream = PooledBitStream.Get())
                {
                    BitWriter writer = new BitWriter(stream);
                    writer.WriteInt32Packed(Random.Range(-50, 50));

                    InvokeClientRpcOnEveryone(MyClientRPC, stream);
                }
            }
            else
            {
                using (PooledBitStream stream = PooledBitStream.Get())
                {
                    BitWriter writer = new BitWriter(stream);
                    writer.WriteInt32Packed(Random.Range(-50, 50));

                    InvokeServerRpc(MyServerRPC, stream);
                }
            }
        }
    }

    [ServerRPC]
    private void MyServerRPC(uint clientId, Stream stream) //This signature is REQUIRED for the performance mode
    {
        BitReader reader = new BitReader(stream);
        int number = reader.ReadInt32Packed();
        Debug.Log("The number recieved was: " + number);
        Debug.Log("This method ran on the server upon the request of a client");
    }

    [ClientRPC]
    private void MyClientRPC(uint clientId, Stream stream) //This signature is REQUIRED for the performance mode
    {
        BitReader reader = new BitReader(stream);
        int number = reader.ReadInt32Packed();
        Debug.Log("The number recieved was: " + number);
        Debug.Log("This method ran on the client upon the request of the server");
    }
}

which is attached on my player. When I send a message from the client to the server, I get the following error on the server's side

ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
System.ThrowHelper.ThrowArgumentOutOfRangeException (System.ExceptionArgument argument, System.ExceptionResource resource) (at <f2e6809acb14476a81f399aeb800f8f2>:0)
System.ThrowHelper.ThrowArgumentOutOfRangeException () (at <f2e6809acb14476a81f399aeb800f8f2>:0)
System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <f2e6809acb14476a81f399aeb800f8f2>:0)
MLAPI.NetworkedObject.GetBehaviourAtOrderIndex (System.UInt16 index) (at <84778170b09d402bb1d84ca28ebe735f>:0)
MLAPI.Internal.InternalMessageHandler.HandleServerRPC (System.UInt32 clientId, System.IO.Stream stream, System.Int32 channelId) (at <84778170b09d402bb1d84ca28ebe735f>:0)
MLAPI.NetworkingManager.HandleIncomingData (System.UInt32 clientId, System.Byte[] data, System.Int32 channelId, System.Int32 totalSize) (at <84778170b09d402bb1d84ca28ebe735f>:0)
MLAPI.NetworkingManager.Update () (at <84778170b09d402bb1d84ca28ebe735f>:0)

And when I send a message from the server to the client, I get the following warning on the client's side:

[MLAPI] ClientRPC request method not found
UnityEngine.Debug:LogWarning(Object)
MLAPI.Logging.LogHelper:LogWarning(String)
MLAPI.NetworkedBehaviour:OnRemoteClientRPC(UInt64, UInt32, Stream)
MLAPI.Internal.InternalMessageHandler:HandleClientRPC(UInt32, Stream, Int32)
MLAPI.NetworkingManager:HandleIncomingData(UInt32, Byte[], Int32, Int32)
MLAPI.NetworkingManager:Update()

What am I doing wrong?

Thanks

TwoTenPvP commented 6 years ago

Is the object where the NetworkedBehaviour sits spawned and properly replicated on both ends?

IoannisKaragiannis commented 6 years ago

Yes. It is. It's my player (PlayerPrefab). And based on the NetworkedTransform I attached on it from v2.1.0 I can move the player on the client's side and it's position gets updated correctly on the server. This means that the RPC system works fine. However, when I add the above-mentioned script which I call TestRPCSystem.cs and press the button I get the errors I mentioned before.

TwoTenPvP commented 6 years ago

Does the convenience versions of the messaging work?

IoannisKaragiannis commented 6 years ago

So, this is how I manage to work around the problem.

My player prefab consists of the following components: a) NetworkedObject b) NetworkedTransform

in both the server and the client. On the client side I also add a PlayerController.cs to move my player.

When I add the TestRPCSystem.cs in both the client and the server, I start getting the above-mentioned errors and not even the NetworkedTransform works anymore. If I remove the TestRPCSystem.cs the NetworkedTransform is still not working. I need to remove all the components and add them again to make it work and for some strange reason NetworkedTransform and TestRPCSystem cannot co-exist. No clue what kind of Unity-magic or MLAPI-magic is happening here.

TwoTenPvP commented 6 years ago

Did the components have the same order?

IoannisKaragiannis commented 6 years ago

Hmm. I don't think so. Does the ordering matter?

TwoTenPvP commented 6 years ago

I think this is if you have it like this: Client:

Server:

Ordering is what makes the MLAPI know what behaviour to send a message to.

TwoTenPvP commented 6 years ago

Actually nvm, the MLAPI already ignores non NetworkedBehaviours. This must be a case of your order not matching up.

IoannisKaragiannis commented 6 years ago

Ok. I got it working. You're absolutely right. The RandomScript you're having there was actually inheriting from NetworkedBehaviours because I wanted to change the color of the player if isLocalPlayer is true. So, that is what was messing things up. I had no clue the ordering was important. Thanks

TwoTenPvP commented 6 years ago

I will add checks for this.

IoannisKaragiannis commented 6 years ago

I'm sorry for bothering you, but I'm trying to evaluate the new MLAPI in terms of latency. I need some help on the SendTickrate, ReceiveTickrate and EventTickrate. Assuming we have an update loop of 60Hz, how should I set the above-mentioned variables in a reasonable manner? Should they all have the same value, e.g.: 50? Does the network manager need to be configured in the exact same way with respect to those variables for the server and the client? How did you come up with the default 64?

Thanks

TwoTenPvP commented 6 years ago

I pulled the default of 64 out of my arse. You can set it to 1 if you want. Lower numbers process messages in larger batches. (Ex: set it to 1, and it will process ALL pending messages once a second). Higher rates will spread the load over frames. Lower numbers thus give higher latency.

64 is nice because it high enough to have low latency and will spread the messages out quite nicley. But it's also not absurdly high, thus not wasting frame cycles. If your server runs at 1000 fps. There is no point doing network IO in every frame. 64 is still really good in that case.

Just remember, having a high value is only effective up to the framerate. The tickrate becomes this: Math.Min(FRAMERATE, TICKRATE);

Thus, if you run 1 FPS and set the tickrate to 1000. It will still work as if you set the tickrate to 1.

The reason the tickrate option exists is to be able to control the rate without changing the framerate. Changing the framerate could mess with drawing, physics and other things.

Also, the server and client can have different values.