Search Unity

NetCode Simpler Sample.

Discussion in 'Data Oriented Technology Stack' started by Opeth001, Aug 21, 2019.

  1. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    294
    hi everyone,

    im trying to understand how the Asteroids Sample works, and i personally found it harder to understand than the NetCode itself.

    Can anyone provide any Simple example for the new netcode features.

    1) how to establish a connection between client & server.
    2) how to send & Handle Received RPCs.( reliable messages ).
    3) how to send & Handle Received Streams ( unreliable messages ).

    Thank you.
     
    wobes likes this.
  2. pal_trefall

    pal_trefall

    Joined:
    Feb 5, 2019
    Posts:
    40
    I've dabbled a bit with the Netcode the past couple of weeks, and I'm starting to get some results. I'll try to provide some insight I've gathered through the process, but I'm sure we'll have a lot more information come Unite in a month.

    1) This is fairly straight forward. You use the ClientServerBootstrap to get at the server world and client worlds. How many client worlds are present is determined by your settings in the Netcode's settings menu. You need to get the NetworkStreamReceiveSystem and Listen on the server world, and Connect on each client world. It's handy to deal with this in a component system, because on update you also want to catch any entity with NetworkStreamConnection, that does not have a NetworkStreamInGame, and add that component. These are the steps to establish a connection. I've yet to look into handling disconnect detection, but the Asteroids example checks the existence of the client's player entity on the server (which among other things has CommandTargetComponent, and probably the existence of NetworkStreamDisconnected component).

    From here its a good idea to look at the InputSystem in the Asteroids example, to see how they spawn a "player" and a "ship" that the player controls.

    2) I started from the InputSystem to get on top of this. First you need to write a struct that implements IRpcCommand. On Execute you get the request entity from the command buffer (using the provided jobIndex), and add a special Request component to it. This is basically the payload you want to go through the RPC command. I typically add an Entity entry I call Connection, and add the connection entity parameter from the Execute method in there. If you need more parameters you add those into this request component too, but you need to then also have them in the IRpcCommand struct you're writing, as a public variable/property, and write the Serialize and Deserialize for it (and inject it into the request component on Execute.

    When this is done you're ready to generate the RpcCollection. This will generate everything Netcode needs to deal with the logic of sending your new Rpc command over the wire, and on the opposite side (whether its a server or a client), will get an entity made (the request entity), with your request component on it. To catch this entity as it is instantiated, you need to write a system that handles it, and then deletes the request entity. Look at SpawnSystem in Asteroids example.

    To create this new Rpc Command, you need an RpcQueue (look at InputSystem again). When you hit RpcCollection generation, that generated a new RpcSystem for you that uses the name of your project. So MyProject would generate a MyProjectRpcSystem. It doesn't trim whitespaces yet, so you might need to fix this manually after generation. From this system you can GetRpcQueue on the new RpcCommand you defined. When you have this, you're ready to start sending rpc commands.

    You need to find all entities that has a CommandTargetComponent, but has not a NetworkStreamDisconnected. I "believe" there is only one per client. From this entity, get the OutgoingRpcDataStreamBufferComponent buffer, use this as input to the RpcQueue Schedule and instantiate your Rpc Command into it, and BAM! you've sent it.

    3) This topic is slightly more complex, but I think the prefab convertion pipeline is probably the most straight forward approach to do this. In the asteroids example they have a lot of these "Authoring" monobehaviors, that convert to a given ECS component. I suggest you embrace that to start with. Add the Ghost Authroing Component to your prefab, and hit its Update Component List button (the Netcode Quickstart readme examplain this fairly well). Once you hit the generate button, after tuning the settings, it generates a SnapshotData struct/file that implements ISnapshotData. I looked at the way the ship prefab was set up in the Asteroids example to get to grips with this. E.g. notice how its PlayerId component adds a PlayerId field to the Ghost Authoring Component, and how that adds an entry into the generated snapshot data. Notice how you also generated a GhostSpawnSystem, GhostUpdateSystem and GhostSerializer, and that GhostSpawnSystem is a partial class. This system is meant for you to extend, and you just have to look at the Asteroids sample how they extended the spawn systems. I'm sure there's someone else on here that can explain this process better than me, though.

    Now you're ready to generate the GhostCollection, and from here you should start getting snapshots. Note that you'll have to go through some of these generated files and add the using reference dependencies yourself manually, these generated files are semi-meant to be tweaked it looks like.

    I hope that at least can nudge you in the right direction, and the big disclaimer is that this is all my reasoning on Netcode and some of my reasoning might not be 100% correct. I'm sure we'll see improved documentation and usage examples soon. Feels like something is brewing for Unite.
     
    Last edited: Aug 22, 2019
    Creepgin, thelebaron, GilCat and 2 others like this.
  3. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    294
    Thank you Very much !!!
    it's enought clear now for me to start.
     
    pal_trefall likes this.