Modding:Network API: Difference between revisions

From Vintage Story Wiki
m
Updated navbox to new code navbox.
m (Updated navbox to new code navbox.)
 
(15 intermediate revisions by 8 users not shown)
Line 1: Line 1:
__FORCETOC__
__FORCETOC__
 
{{GameVersion|1.19.3}}
<languages/><translate>
<!--T:1-->
Before starting, you should have a development environment set up. If you don't have one already you should read the tutorial [[Setting up your Development Environment]]. Furthermore, we assume that you have a basic understanding of the C# language and Object Oriented Programming. Let's get started!
Before starting, you should have a development environment set up. If you don't have one already you should read the tutorial [[Setting up your Development Environment]]. Furthermore, we assume that you have a basic understanding of the C# language and Object Oriented Programming. Let's get started!


<!--T:2-->
'''Hint''': If you need to send data for Entities or BlockEntities, it may be more appropriate to use the inbuilt network methods for these. Check out the [http://apidocs.vintagestory.at/api/Vintagestory.API.Server.IServerNetworkAPI.html IServerNetworkAPI] and [http://apidocs.vintagestory.at/api/Vintagestory.API.Client.IClientNetworkAPI.html IClientNetworkAPI] interfaces for more information.
'''Hint''': If you need to send data for Entities or BlockEntities, it may be more appropriate to use the inbuilt network methods for these. Check out the [http://apidocs.vintagestory.at/api/Vintagestory.API.Server.IServerNetworkAPI.html IServerNetworkAPI] and [http://apidocs.vintagestory.at/api/Vintagestory.API.Client.IClientNetworkAPI.html IClientNetworkAPI] interfaces for more information.


== Introduction ==
== Introduction == <!--T:3-->


<!--T:4-->
In this example mod we will show you how to send custom data back and forth between the Server and the Client. To do this, we will set up a network channel through which string messages will be sent in a network channel.
In this example mod we will show you how to send custom data back and forth between the Server and the Client. To do this, we will set up a network channel through which string messages will be sent in a network channel.


<!--T:5-->
We will create a server command that will send out a message to all clients, and if a client receives this, it will send a response back to the server; upon receiving this response, the server will display it along with the responding client's player name.
We will create a server command that will send out a message to all clients, and if a client receives this, it will send a response back to the server; upon receiving this response, the server will display it along with the responding client's player name.


== Preparation ==
If something goes wrong, Wireshark with the [https://github.com/bluelightning32/vs-protocol vs-protocol] dissector is a helpful debug tool.


== Preparation == <!--T:6-->
<!--T:7-->
Let's start by creating a new .cs file for this mod, and adding our imports and the namespace in which we'll wrap all of our classes:
Let's start by creating a new .cs file for this mod, and adding our imports and the namespace in which we'll wrap all of our classes:
 
</translate>
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
using System;
using System;
Line 32: Line 40:
== ProtoContracts ==
== ProtoContracts ==


VintageStory uses the [https://github.com/protobuf-net/protobuf-net Protobuf-net] library to serialize classes declared with the <code>ProtoContract</code> attribute.  
VintageStory uses multiple [[Modding:Serialization_Formats|serialization formats]]. This tutorial uses the protobuf format. The [https://github.com/protobuf-net/protobuf-net Protobuf-net] library can serialize classes declared with the <code>ProtoContract</code> attribute.  


Inside our namespace block, let's create our <code>ProtoContract</code> classes:
Inside our namespace block, let's create our <code>ProtoContract</code> classes:


<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
    [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
     public class NetworkApiTestMessage
     public class NetworkApiTestMessage
     {
     {
Line 52: Line 60:
The argument we pass to <code>ProtoContract</code> makes it so all <code>public</code> fields will be serialized; without this, we'd declare fields for serialization by using <code>ProtoMember</code> attributes. If we chose this approach, we'd write our classes like so:
The argument we pass to <code>ProtoContract</code> makes it so all <code>public</code> fields will be serialized; without this, we'd declare fields for serialization by using <code>ProtoMember</code> attributes. If we chose this approach, we'd write our classes like so:
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
[ProtoContract]
    [ProtoContract]
     public class NetworkApiTestMessage
     public class NetworkApiTestMessage
     {
     {
Line 59: Line 67:
     }
     }


     [ProtoContract()]
     [ProtoContract]
     public class NetworkApiTestResponse
     public class NetworkApiTestResponse
     {
     {
Line 71: Line 79:
The fields in these classes hold the data we wish to send through our channel. We'll use <code>NetworkApiTestMessage</code> to encase the initial message from the server, while <code>NetWorkApiTestResponse</code> will be used by the Client to send its response.
The fields in these classes hold the data we wish to send through our channel. We'll use <code>NetworkApiTestMessage</code> to encase the initial message from the server, while <code>NetWorkApiTestResponse</code> will be used by the Client to send its response.


== NetWorkApiTest ==  
== NetworkApiTest ==  


Now we will create our main class that inherits from the <code>ModSystem</code> class, which is the base class for mod systems. You can read more about this [http://apidocs.vintagestory.at/api/Vintagestory.API.Common.ModSystem.html here]. Moreover, we'll be separating our Client and Server sides within the class with region blocks for readability purposes.
Now we will create our main class that inherits from the <code>ModSystem</code> class, which is the base class for mod systems. You can read more about this [http://apidocs.vintagestory.at/api/Vintagestory.API.Common.ModSystem.html here]. Moreover, we'll be separating our Client and Server sides within the class with region blocks for readability purposes.


<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
public class NetworkApiTest : ModSystem
    public class NetworkApiTest : ModSystem
     {
     {
         #region Client
         #region Client
Line 110: Line 118:
             ;
             ;


             api.RegisterCommand("nwtest", "Send a test network message", "", OnNwTestCmd, Privilege.controlserver);
             api.ChatCommands.Create("nwtest")
                .WithDescription("Send a test network message")
                .RequiresPrivilege(Privilege.controlserver)
                .HandleWith(new OnCommandDelegate(OnNwTestCmd));
         }
         }
#endregion
#endregion
</syntaxhighlight>
</syntaxhighlight>


The Core Server API contains the Network member, which provides us with the RegisterChannel method. We pass this method a string containing the name we choose for our channel, in this case we'll call our channel "networkapitest". A channel with this exact name will be registered on the Client side.
The Core Server API contains the Network member, which provides us with the <code>RegisterChannel</code> method. We pass this method a string containing the name we choose for our channel, in this case we'll call our channel "networkapitest". A channel with this exact name will be registered on the Client side.


We then register the ProtoContract classes that we'll be using to this channel with the <code>RegisterMessageType</code> method.
We then register the ProtoContract classes that we'll be using to this channel with the <code>RegisterMessageType</code> method.


Finally, we call <code>SetMessageHandler<T></code>, which takes a delegate that will be called every time a ProtoContract of type <code>T</code> is received from a client, in this case <code>NetworkApiTestResponse</code> will be handled by <code>OnClientMessage</code> which we'll declare later.
Finally, we call <code>SetMessageHandler<T></code>, which takes a delegate that will be called every time a <code>ProtoContract</code> of type <code>T</code> is received from a client, in this case <code>NetworkApiTestResponse</code> will be handled by <code>OnClientMessage</code> which we'll declare later.


Now that our channel is set up on the Server side, we'll want to register a server command that will broadcast a network message to all the clients listening to our "networkapitest" channel.
Now that our channel is set up on the Server side, we'll want to register a server command that will broadcast a network message to all the clients listening to our "networkapitest" channel.
Line 130: Line 141:
         public override void StartServerSide(ICoreServerAPI api)...
         public override void StartServerSide(ICoreServerAPI api)...


         private void OnNwTestCmd(IServerPlayer player, int groupId, CmdArgs args)
         private TextCommandResult OnNwTestCmd(TextCommandCallingArgs args)
         {
         {
             serverChannel.BroadcastPacket(new NetworkApiTestMessage()
             serverChannel.BroadcastPacket(new NetworkApiTestMessage()
Line 136: Line 147:
                 message = "Hello World!",
                 message = "Hello World!",
             });
             });
            return TextCommandResult.Success();
         }
         }
#endregion
#endregion
</syntaxhighlight>
</syntaxhighlight>


The server channel gives us the BroadcastPacket method which we'll use to send out a <code>NetworkApiTestMessage</code> instance to all clients listening to the "networkapitest" channel, in this case we send "Hello World!" as the message.
The server channel gives us the <code>BroadcastPacket</code> method which we'll use to send out a <code>NetworkApiTestMessage</code> instance to all clients listening to the "networkapitest" channel, in this case we send "Hello World!" as the message.


== Client Setup ==
== Client Setup ==
Line 254: Line 266:
     public class NetworkApiTest : ModSystem
     public class NetworkApiTest : ModSystem
     {
     {
        #region Client
        IClientNetworkChannel clientChannel;
        ICoreClientAPI clientApi;
        public override void StartClientSide(ICoreClientAPI api)
        {
            clientApi = api;
            clientChannel =
                api.Network.RegisterChannel("networkapitest")
                .RegisterMessageType(typeof(NetworkApiTestMessage))
                .RegisterMessageType(typeof(NetworkApiTestResponse))
                .SetMessageHandler<NetworkApiTestMessage>(OnServerMessage)
            ;
        }
        private void OnServerMessage(NetworkApiTestMessage networkMessage)
        {
            clientApi.ShowChatMessage("Received following message from server: " + networkMessage.message);
            clientApi.ShowChatMessage("Sending response.");
            clientChannel.SendPacket(new NetworkApiTestResponse()
            {
                response = "RE: Hello World!"
            });
        }
        #endregion
         #region Server
         #region Server
         IServerNetworkChannel serverChannel;
         IServerNetworkChannel serverChannel;
Line 297: Line 281:
             ;
             ;


             api.RegisterCommand("nwtest", "Send a test network message", "", OnNwTestCmd, Privilege.controlserver);
             api.ChatCommands.Create("nwtest")
                .WithDescription("Send a test network message")
                .RequiresPrivilege(Privilege.controlserver)
                .HandleWith(new OnCommandDelegate(OnNwTestCmd));
         }
         }


         private void OnNwTestCmd(IServerPlayer player, int groupId, CmdArgs args)
         private TextCommandResult OnNwTestCmd(TextCommandCallingArgs args)
         {
         {
             serverChannel.BroadcastPacket(new NetworkApiTestMessage()
             serverChannel.BroadcastPacket(new NetworkApiTestMessage()
Line 306: Line 293:
                 message = "Hello World!",
                 message = "Hello World!",
             });
             });
            return TextCommandResult.Success();
         }
         }


Line 317: Line 305:
         }
         }


          
         #endregion
        #region Client
        IClientNetworkChannel clientChannel;
        ICoreClientAPI clientApi;
 
        public override void StartClientSide(ICoreClientAPI api)
        {
            clientApi = api;
 
            clientChannel =
                api.Network.RegisterChannel("networkapitest")
                .RegisterMessageType(typeof(NetworkApiTestMessage))
                .RegisterMessageType(typeof(NetworkApiTestResponse))
                .SetMessageHandler<NetworkApiTestMessage>(OnServerMessage)
            ;
        }
 
        private void OnServerMessage(NetworkApiTestMessage networkMessage)
        {
            clientApi.ShowChatMessage("Received following message from server: " + networkMessage.message);
            clientApi.ShowChatMessage("Sending response.");
            clientChannel.SendPacket(new NetworkApiTestResponse()
            {
                response = "RE: Hello World!"
            });
        }
 
         #endregion
         #endregion
     }
     }
Line 327: Line 341:
Let's run the mod now! Once you're ingame, try entering <code>/nwtest</code>. You should be met with an initial "Hello World!" message as well as a confirmation message that the server received the response from the Client!
Let's run the mod now! Once you're ingame, try entering <code>/nwtest</code>. You should be met with an initial "Hello World!" message as well as a confirmation message that the server received the response from the Client!


 
{{Navbox/codemodding}}
 
== Distribution ==
 
To distribute this mod, you may run the following command in the modtools cli <code>pack <your mod id></code>, then copy the .zip file into your VintageStory mods folder.
 
Here are the official versions:
* for VS v1.10-rc.4: [https://wiki.vintagestory.at/images/7/73/NetworkApiTest_vs1.10-rc.4_v1.0.0.zip NetworkApiTest_vs1.10-rc.4_v1.0.0.zip]
 
{{Navbox/modding|Vintage Story}}
Confirmedusers
637

edits