UPDATE:
Due to the requests, I have created a DEMO project for you guys. Simply change the IP & Port in the server & client scripts and try it out. Build the server scene into an exe, and run it. Then run the client code in the editor and watch the console. ENSURE YOU SET THE PLAYER SETTINGS TO RUN IN BACKGROUND
Download: Dropbox - Error - Simplify your life
So I noticed Unity’s network system is a bit… useless in certain situations. It’s great for a first person shooter type game, but from what I’ve seen most people use a 3rd party network server that is entirely outside of unity.
I needed a networking system for my game, so I created one for myself that actually uses only Unity. I used this for my mmorpg, and think others might find some use out of. I don’t see why I shouldn’t share and help out other people. Royalty free. Feel free to discuss this system with me too.
So here’s how it works. I have a server and a client (in my case, an authoritative server) and they need to communicate back and forth, a large variety of things. I use a total of 2 RPC Functions, 1 on the server, 1 on the client, and they are both identical in ways they work. That’s it! That’s the only real Unity network functions that are used. All the data is sent through those RPC functions and understood by the receiver. Now this is a very efficient system, but due to the rpc function not being able to accept byte[ ] as a parameter, the data being sent back and forth is slightly larger than if it did accept byte[ ] parameters. Nonetheless… let’s get to the actual code!
We’ve got two classes. The PacketWriter, and the PacketReader. Self explanatory, one class builds a packet and the other takes the received packet apart!
Here are the two classes: (MAKE SURE TO CHANGE YOUR_NETWORK_VIEW TO A REFERENCE TO YOUR NETWORK VIEW COMPONENT IN PACKETWRITER.CS)
PacketWriter.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
public class PacketWriter {
private static int packetId;
private static byte[] packetBytes;
public static void BuildPacket(int i) {
packetId = i;
packetBytes = null;
}
public static void AddInt(int i) {
byte[] newBytes = ByteConverter.getBytes(i);
if(packetBytes != null) {
List<byte> list1 = new List<byte>(packetBytes);
List<byte> list2 = new List<byte>(newBytes);
list1.AddRange(list2);
packetBytes = list1.ToArray();
} else
packetBytes = newBytes;
}
public static void AddFloat(float f) {
byte[] newBytes = ByteConverter.getBytes(f);
if(packetBytes != null) {
List<byte> list1 = new List<byte>(packetBytes);
List<byte> list2 = new List<byte>(newBytes);
list1.AddRange(list2);
packetBytes = list1.ToArray();
} else
packetBytes = newBytes;
}
public static void AddString(string s) {
byte[] newBytes = ByteConverter.getBytes(s);
AddInt(s.Length);
if(packetBytes != null) {
List<byte> list1 = new List<byte>(packetBytes);
List<byte> list2 = new List<byte>(newBytes);
list1.AddRange(list2);
packetBytes = list1.ToArray();
} else
packetBytes = newBytes;
}
public static void SendPacketToClient(NetworkPlayer c) {
YOUR_NETWORK_VIEW.RPC("TransferData", c, packetId, packetBytes);
}
public static void SendPacketToServer() {
YOUR_NETWORK_VIEW.RPC("TransferData", RPCMode.Server, packetId, packetBytes);
}
}
PacketReader.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
public class PacketReader {
private static byte[] packetBytes;
public static void ReadPacket(byte[] packet) {
packetBytes = packet;
}
public static int ReadInt() {
byte[] intBytes = packetBytes;
Array.Copy(packetBytes, 0, intBytes, 0, 4);
int intFromBytes = ByteConverter.getInt(intBytes);
int bytesToEliminate = 4;
int newLength = packetBytes.Length - bytesToEliminate; //you may need to check if this positive
byte[] newArray = new byte[newLength];
Array.Copy(packetBytes, bytesToEliminate, newArray, 0, newLength);
packetBytes = newArray;
return intFromBytes;
}
public static float ReadFloat() {
byte[] intBytes = packetBytes;
Array.Copy(packetBytes, 0, intBytes, 0, 4);
float floatFromBytes = ByteConverter.getFloat(intBytes);
int bytesToEliminate = 4;
int newLength = packetBytes.Length - bytesToEliminate; //you may need to check if this positive
byte[] newArray = new byte[newLength];
Array.Copy(packetBytes, bytesToEliminate, newArray, 0, newLength);
packetBytes = newArray;
return floatFromBytes;
}
public static string ReadString() {
int stringLength = ReadInt();
List<byte> list1 = new List<byte>(packetBytes);
byte[] stringBytes = list1.GetRange(0, stringLength).ToArray();
string stringFromBytes = ByteConverter.getString(stringBytes);
int bytesToEliminate = stringLength;
int newLength = packetBytes.Length - bytesToEliminate; //you may need to check if this positive
byte[] newArray = new byte[newLength];
Array.Copy(packetBytes, bytesToEliminate, newArray, 0, newLength);
packetBytes = newArray;
return stringFromBytes;
}
}
There’s another class you’ll need… this converts variables to byte arrays (byte[ ]) and back. More on this in a minute, here’s the class:
ByteConverter.cs
using UnityEngine;
using System.Collections;
using System;
public class ByteConverter {
public static byte[] getBytes(string s) {
return System.Text.Encoding.UTF8.GetBytes(s);
}
public static string getString(byte[] bytes) {
return new string(System.Text.Encoding.UTF8.GetChars(bytes));
}
public static byte[] getBytes(int I32) {
return BitConverter.GetBytes(I32);
}
public static int getInt(byte[] b) {
return BitConverter.ToInt32(b, 0);
}
public static float getFloat(byte[] b) {
return BitConverter.ToSingle(b, 0);
}
public static byte[] getBytes(float f) {
return BitConverter.GetBytes(f);
}
}
Ok. So we got all of our static classes down. So let’s get the set up going, and the rpc functions.
We will use the same RPC function in both the client and the server. The only thing different is deciding what to do with the data. This would be up to the developer using the system.
So firstly, you’ll need a network view of course… So you add that to an object. Make sure to reference the networkview somehow through the script containing the RPC function. This applies to both the server and the client.
In your server script attached to the object with a network view, you can use this as an example:
[RPC]
private void TransferData(int packetType, byte[] bytesInString) {
if(packetType == 1) {
PacketReader.ReadPacket(bytesInString);
string chatbox_Input = PacketReader.ReadString();
string receivedString = PacketReader.ReadString();
int receivedInt = PacketReader.ReadInt();
float receivedFloat = PacketReader.ReadFloat();
Debug.Log("received string:"+receivedString+" received int:"+receivedInt+" received float:"+receivedFloat);
}
}
You would use the same exact rpc function on the server as well. I just assume you’ll do different things with the received data. Packet #s don’t have to match up server to client. You could use packet 1 to send a single string to the client, and use packet #1 to send 2 integers to the server. Simply the rpc function on the receiving end has to know what it’s expecting. If you wanted to receive two integers for packet #2, you’d use this code (within the rpc)
if(packetType == 2) {
PacketReader.ReadPacket(bytesInString);
float receivedint1 = PacketReader.ReadInt();
float receivedint2 = PacketReader.ReadInt();
Debug.Log("Received int1:"+receivedint1+" Received int2:"+receivedint2);
}
Ok. So now we got to get into SENDING a packet. This can go in any class!
Here’s an example on how to send the packet #2, two integer, packet mentioned just above. This is going to be from the CLIENT, and the code above receiving the packet will be in the SERVER. To reverse it, simply change PacketWriter.SendPacketToClient() to PacketWriter.SendPacketToServer(YOUR NETWORK PLAYER).
PacketWriter.BuildPacket(2);
PacketWriter.AddInt(1337);
PacketWriter.AddInt(2015);
PacketWriter.SendPacketToClient();
So we know how to send packets back and forth now. To send floats/strings/etc, just look at the PacketWriter class for the functions. If you want to send other types of variables that aren’t already in the code, feel free to add some more. It’s not too complicated… just PM me/post a reply quoting me and I’ll tell you how to.
So how does this all work? Let me explain.
The packetwriter will convert your variables into byte[ ] arrays and combine them all into one byte array. The byte array is sent over the RPC function, and the packet reader interprets the byte array and gives you the variables. Only one RPC function, it’s easy stuff.
So that’s everything you need! Of course make sure you connect to the server using the network class before sending any packets. If you have any questions/suggestions please let me know. Put a lot of work into making this thread. Hope you guys use this system!
I use this system in my MMORPG, and it can be used for really any type of data transferring. An MMORPG requires a LOT of data sending back and forth, to tons of players, and this system can handle it, despite how basic it really is. It’s also so easy to just say, buildpacket,addstring,sendpacket. It’s that simple.
This also works perfectly in Unity Free. It is just as fast as unity’s rpc calls, but there’s NO HASSLE! It’s so easy to send data back and forth, and you don’t have to create constant RPC methods in the server and client. This is ideal for any project, and almost necessary if you have advanced networking needs as in an mmorpg.