Jump to content
Sign in to follow this  
boasfesta

Data Serialization (Network)

Recommended Posts

Objective: Serialize all object data through network

Difficulty: Advanced

 

This tutorial is a second part of serialization system, described on this tutorial, so if you did'nt added yet, do it before you continue.

In the past tutorial we learned how to serialize our objects for storage, so we don't need to update the structures fields every time we add a new one.

But storage systems is not the only methods we must to add structure fields one by one, we also need to update the Send and Receive object packets through network. The actual Orion+ communications steps are:

 

When someone login: Server send (some) game data on SendGameData sub and Client/Editor receive them on Packet_GameData

When a object is modified: Editor send its data on SendSaveObject sub and Server receive it on Packet_SaveObject. Also when this occurs, Server send the data update for other connected clients on methods SendObjectUpdateTo and SendObjectUpdateToAll, the Client/Editors receive them on a unique method Packet_UpdateObject.

 

Considering this, those methods is our target methods for every object we want to serialize.

 

Preparing to Serialize

First we must to create our Serialization class, but there is a important thing we must to know first.

Every time we use Serialization, the object is "assigned" with the solution, module and structure name, so we can't send it through the solutions without update our formatter binder, otherwise the VS will return us a exception.

Also, for structures that have his own modules (Like quests, pets, projectiles...) must have the SAME MODULE NAME, so you need to rename the ServerQuests to modQuests (Like the Editor and Client class) for example. Its important to note that this system is Sensitive Case, what mean that Upper and Lower cases makes difference. Some modules like modQuests starts with Uppercase on first letter (ModQuests) on Client, but starts with Lowercase on first letter (modQuests) on Editor (Thank you Damien666 you asshole i love you), so you need to check and rename those modules to have EXACTLY THE SAME NAME.

 

To resolve that "assign" problem, we must rewrite the formatter binder by creating our own binder and overriding its bind method.

  • So add ServerBinder.vb class on Server

 

Public Class ServerBinder
    Inherits Runtime.Serialization.SerializationBinder

    Overrides Function BindToType(assemblyName As String, typeName As String) As Type
        assemblyName = assemblyName.Replace("Orion+ Client", "Orion+ Server")
        assemblyName = assemblyName.Replace("Editors", "Orion+ Server")
        Return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName))
    End Function

End Class
  • Add EditorsBinder.vb class on Editor
Public Class EditorsBinder
    Inherits Runtime.Serialization.SerializationBinder

    Overrides Function BindToType(assemblyName As String, typeName As String) As Type
        assemblyName = assemblyName.Replace("Orion+ Server", "Editors")
        Return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName))
    End Function

End Class
  • Add ClientBinder.vb class on Client
Public Class ClientBinder
    Inherits Runtime.Serialization.SerializationBinder

    Overrides Function BindToType(assemblyName As String, typeName As String) As Type
        assemblyName = assemblyName.Replace("Orion+ Server", "Orion+ Client")
        Return Type.GetType(String.Format("{0}, {1}", typeName, assemblyName))
    End Function

End Class

Notes: If you changed your solutions Assembly Name on properties, you must replace them on this binder classes.

 

After that, you must create Serialization.vb class for every solution JUST CHANGING ITS BINDER.

Module Serialization
    Function Serialize(ByVal Entity As Object) As Byte()
        Dim formatter As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
        Using ms = New System.IO.MemoryStream()
            formatter.Serialize(ms, Entity)
            Return ms.GetBuffer()
        End Using
    End Function

    Public Sub Deserialize(ByRef Entity As Object, data As Byte())
        Dim formatter = New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
        Using ms = New System.IO.MemoryStream(data)
            formatter.Binder = New ClientBinder() 'CHANGE THIS BINDER FOR SERVER AND EDITOR
            Entity = formatter.Deserialize(ms)
        End Using
    End Sub

    Function SerializeData(Element As Object) As Byte()
        Dim buffer As New ASFW.ByteStream(4)
        Dim SerializedData As Byte() = Serialize(Element)
        buffer.WriteInt32(SerializedData.Length)
        buffer.WriteBlock(SerializedData)
        Return buffer.ToArray
    End Function

    Function DeserializeData(ByRef buffer As ASFW.ByteStream) As Object
        Dim byteCount As Integer = buffer.ReadInt32
        Dim element As Object
        Deserialize(element, buffer.ReadBlock(byteCount))
        Return element
    End Function
End Module

Serializing objects through network

Now lets update the Send and Receive methods to correspond for our serialization system, for a first example we will use the Skill object, but you must to do these steps for every object you want to serialize on your game (such like Quests, Items, Npcs...)

As i described about the methods order, the first method is SendGameData on Server, so lets begin our modifications.

SendGameData uses a function for get objects data, named like ObjectsData as default, in our case SkillsData. That function makes a "for" instruction writing every Skill data in the buffer calling the SkillData function. So we don't even need to access Sub SendGameData or SkillsData, just modify SkillData function.

For serialize our object on a buffer, we just need to call SerializeData(Object) function. Also you must remove whole old buffer code (leaving just skillnum in this case):

Function SkillData before serialization:

    Function SkillData(skillnum As Integer) As Byte()
        Dim buffer As New ByteStream(4)
        buffer.WriteInt32(skillnum)
        buffer.WriteInt32(Skill(skillnum).AccessReq)
        buffer.WriteInt32(Skill(skillnum).AoE)
        buffer.WriteInt32(Skill(skillnum).CastAnim)
        buffer.WriteInt32(Skill(skillnum).CastTime)
        buffer.WriteInt32(Skill(skillnum).CdTime)
        buffer.WriteInt32(Skill(skillnum).ClassReq)
        buffer.WriteInt32(Skill(skillnum).Dir)
        buffer.WriteInt32(Skill(skillnum).Duration)
        buffer.WriteInt32(Skill(skillnum).Icon)
        buffer.WriteInt32(Skill(skillnum).Interval)
        buffer.WriteInt32(Skill(skillnum).IsAoE)
        buffer.WriteInt32(Skill(skillnum).LevelReq)
        buffer.WriteInt32(Skill(skillnum).Map)
        buffer.WriteInt32(Skill(skillnum).MpCost)
        buffer.WriteString((Skill(skillnum).Name))
        buffer.WriteInt32(Skill(skillnum).Range)
        buffer.WriteInt32(Skill(skillnum).SkillAnim)
        buffer.WriteInt32(Skill(skillnum).StunDuration)
        buffer.WriteInt32(Skill(skillnum).Type)
        buffer.WriteInt32(Skill(skillnum).Vital)
        buffer.WriteInt32(Skill(skillnum).X)
        buffer.WriteInt32(Skill(skillnum).Y)
        buffer.WriteInt32(Skill(skillnum).IsProjectile)
        buffer.WriteInt32(Skill(skillnum).Projectile)
        buffer.WriteInt32(Skill(skillnum).KnockBack)
        buffer.WriteInt32(Skill(skillnum).KnockBackTiles)
        Return buffer.ToArray
    End Function

Function SkillData after serialization:

    Function SkillData(skillnum As Integer) As Byte()
        Dim buffer As New ByteStream(4)
        buffer.WriteInt32(skillnum)
        buffer.WriteBlock(SerializeData(Skill(skillnum)))
        Return buffer.ToArray
    End Function

Lets enjoy we are on Server now and just update the other methods too.

When we receive a object from editor, it reaches the Packet_SaveSkill on ServerNetworkReceive module. As we want to serialize that data too, lets make the Deserialize process on it.

To deserialize a object through network, just replace the old code by Object = DeserializeData(buffer)REMEMBER TO NOT REMOVE OBJECTNUM = BUFFER.READINT32

Packet_SaveSkill before serialization:

    Sub Packet_SaveSkill(index as integer, ByRef data() As Byte)
        Dim skillnum As Integer
        Dim buffer As New ByteStream(data)

        AddDebug("Recieved EMSG: SaveSkill")

        skillnum = Buffer.ReadInt32

        ' Prevent hacking
        If skillnum < 0 OrElse skillnum > MAX_SKILLS Then Exit Sub

        Skill(skillnum).AccessReq = Buffer.ReadInt32()
        Skill(skillnum).AoE = Buffer.ReadInt32()
        Skill(skillnum).CastAnim = Buffer.ReadInt32()
        Skill(skillnum).CastTime = Buffer.ReadInt32()
        Skill(skillnum).CdTime = Buffer.ReadInt32()
        Skill(skillnum).ClassReq = Buffer.ReadInt32()
        Skill(skillnum).Dir = Buffer.ReadInt32()
        Skill(skillnum).Duration = Buffer.ReadInt32()
        Skill(skillnum).Icon = Buffer.ReadInt32()
        Skill(skillnum).Interval = Buffer.ReadInt32()
        Skill(skillnum).IsAoE = Buffer.ReadInt32()
        Skill(skillnum).LevelReq = Buffer.ReadInt32()
        Skill(skillnum).Map = Buffer.ReadInt32()
        Skill(skillnum).MpCost = Buffer.ReadInt32()
        Skill(skillnum).Name = Buffer.ReadString()
        Skill(skillnum).Range = Buffer.ReadInt32()
        Skill(skillnum).SkillAnim = Buffer.ReadInt32()
        Skill(skillnum).StunDuration = Buffer.ReadInt32()
        Skill(skillnum).Type = Buffer.ReadInt32()
        Skill(skillnum).Vital = Buffer.ReadInt32()
        Skill(skillnum).X = Buffer.ReadInt32()
        Skill(skillnum).Y = Buffer.ReadInt32()

        'projectiles
        Skill(skillnum).IsProjectile = Buffer.ReadInt32()
        Skill(skillnum).Projectile = Buffer.ReadInt32()

        Skill(skillnum).KnockBack = Buffer.ReadInt32()
        Skill(skillnum).KnockBackTiles = Buffer.ReadInt32()

        ' Save it
        SendUpdateSkillToAll(skillnum)
        SaveSkill(skillnum)
        Addlog(GetPlayerLogin(Index) & " saved Skill #" & skillnum & ".", ADMIN_LOG)

        Buffer.Dispose()
    End Sub

Packet_SaveSkill after serialization

    Sub Packet_SaveSkill(index As Integer, ByRef data() As Byte)
        Dim skillnum As Integer
        Dim buffer As New ByteStream(data)

        AddDebug("Recieved EMSG: SaveSkill")

        skillnum = buffer.ReadInt32 ' <- Keep dat xit

        ' Prevent hacking
        If skillnum < 0 OrElse skillnum > MAX_SKILLS Then Exit Sub

        Skill(skillnum) = DeserializeData(buffer)

        ' Save it
        SendUpdateSkillToAll(skillnum)
        SaveSkill(skillnum)
        Addlog(GetPlayerLogin(index) & " saved Skill #" & skillnum & ".", ADMIN_LOG)

        buffer.Dispose()
    End Sub

As you can see, the Packet_SaveSkill calls the SendUpdateSkillToAll sub, also there is a SendUpdateSkillTo for send to a individual client, we must update those Subs too on ServerNetworkSend. For do that, you just need to replace the whole old code for buffer.WriteBlock(ObjectData(objectnum)). Since we already serialized the object on that function, we don't need to serialize it again. For our case, we use buffer.WriteBlock(SkillData(skillnum)). Remember to do that for both SendUpdateSkillTo and SendUpdateSkillToAll!.

 

SendUpdateSkillToAll and SendUpdateSkillTo before serialization

Sub SendUpdateSkillTo(index As Integer, skillnum As Integer)
        Dim buffer As ByteStream

        buffer = New ByteStream(4)

        buffer.WriteInt32(ServerPackets.SUpdateSkill)
        buffer.WriteInt32(skillnum)
        buffer.WriteInt32(Skill(skillnum).AccessReq)
        buffer.WriteInt32(Skill(skillnum).AoE)
        buffer.WriteInt32(Skill(skillnum).CastAnim)
        buffer.WriteInt32(Skill(skillnum).CastTime)
        buffer.WriteInt32(Skill(skillnum).CdTime)
        buffer.WriteInt32(Skill(skillnum).ClassReq)
        buffer.WriteInt32(Skill(skillnum).Dir)
        buffer.WriteInt32(Skill(skillnum).Duration)
        buffer.WriteInt32(Skill(skillnum).Icon)
        buffer.WriteInt32(Skill(skillnum).Interval)
        buffer.WriteInt32(Skill(skillnum).IsAoE)
        buffer.WriteInt32(Skill(skillnum).LevelReq)
        buffer.WriteInt32(Skill(skillnum).Map)
        buffer.WriteInt32(Skill(skillnum).MpCost)
        buffer.WriteString((Trim(Skill(skillnum).Name)))
        buffer.WriteInt32(Skill(skillnum).Range)
        buffer.WriteInt32(Skill(skillnum).SkillAnim)
        buffer.WriteInt32(Skill(skillnum).StunDuration)
        buffer.WriteInt32(Skill(skillnum).Type)
        buffer.WriteInt32(Skill(skillnum).Vital)
        buffer.WriteInt32(Skill(skillnum).X)
        buffer.WriteInt32(Skill(skillnum).Y)

        AddDebug("Sent SMSG: SUpdateSkill")

        'projectiles
        buffer.WriteInt32(Skill(skillnum).IsProjectile)
        buffer.WriteInt32(Skill(skillnum).Projectile)

        buffer.WriteInt32(Skill(skillnum).KnockBack)
        buffer.WriteInt32(Skill(skillnum).KnockBackTiles)

        Socket.SendDataTo(index, buffer.Data, buffer.Head)
        buffer.Dispose()
    End Sub

    Sub SendUpdateSkillToAll(skillnum As Integer)
        Dim buffer As ByteStream

        buffer = New ByteStream(4)

        buffer.WriteInt32(ServerPackets.SUpdateSkill)
        buffer.WriteInt32(skillnum)
        buffer.WriteInt32(Skill(skillnum).AccessReq)
        buffer.WriteInt32(Skill(skillnum).AoE)
        buffer.WriteInt32(Skill(skillnum).CastAnim)
        buffer.WriteInt32(Skill(skillnum).CastTime)
        buffer.WriteInt32(Skill(skillnum).CdTime)
        buffer.WriteInt32(Skill(skillnum).ClassReq)
        buffer.WriteInt32(Skill(skillnum).Dir)
        buffer.WriteInt32(Skill(skillnum).Duration)
        buffer.WriteInt32(Skill(skillnum).Icon)
        buffer.WriteInt32(Skill(skillnum).Interval)
        buffer.WriteInt32(Skill(skillnum).IsAoE)
        buffer.WriteInt32(Skill(skillnum).LevelReq)
        buffer.WriteInt32(Skill(skillnum).Map)
        buffer.WriteInt32(Skill(skillnum).MpCost)
        buffer.WriteString((Skill(skillnum).Name))
        buffer.WriteInt32(Skill(skillnum).Range)
        buffer.WriteInt32(Skill(skillnum).SkillAnim)
        buffer.WriteInt32(Skill(skillnum).StunDuration)
        buffer.WriteInt32(Skill(skillnum).Type)
        buffer.WriteInt32(Skill(skillnum).Vital)
        buffer.WriteInt32(Skill(skillnum).X)
        buffer.WriteInt32(Skill(skillnum).Y)

        AddDebug("Sent SMSG: SUpdateSkill To All")

        'projectiles
        buffer.WriteInt32(Skill(skillnum).IsProjectile)
        buffer.WriteInt32(Skill(skillnum).Projectile)

        buffer.WriteInt32(Skill(skillnum).KnockBack)
        buffer.WriteInt32(Skill(skillnum).KnockBackTiles)

        SendDataToAll(buffer.Data, buffer.Head)
        buffer.Dispose()
    End Sub

SendUpdateSkillToAll and SendUpdateSkillTo after serialization

    Sub SendUpdateSkillTo(index As Integer, skillnum As Integer)
        Dim buffer As ByteStream

        buffer = New ByteStream(4)
        buffer.WriteInt32(ServerPackets.SUpdateSkill)
        buffer.WriteBlock(SkillData(skillnum))

        Socket.SendDataTo(index, buffer.Data, buffer.Head)
        buffer.Dispose()
    End Sub

    Sub SendUpdateSkillToAll(skillnum As Integer)
        Dim buffer As ByteStream

        buffer = New ByteStream(4)
        buffer.WriteInt32(ServerPackets.SUpdateSkill)
        buffer.WriteBlock(SkillData(skillnum))

        SendDataToAll(buffer.Data, buffer.Head)
        buffer.Dispose()
    End Sub

Now we are done with de Server, lets begin the Editors process.

The difference between Editors and Client, is that we can send objects for Server. So lets start with the Editor Side by modifing the SendSaveSkill method on modNetworkSend.

To update that method, keep the "objectnum" buffer writing and just replace the whole old code for buffer.WriteBlock(SerializeData(Object(objectnum))). in our case is buffer.WriteBlock(SerializeData(Skill(skillnum))).

SendSaveSkill before serialization

    Friend Sub SendSaveSkill(skillnum As Integer)
        Dim buffer As New ByteStream(4)

        buffer.WriteInt32(EditorPackets.SaveSkill)
        buffer.WriteInt32(skillnum)

        buffer.WriteInt32(Skill(skillnum).AccessReq)
        buffer.WriteInt32(Skill(skillnum).AoE)
        buffer.WriteInt32(Skill(skillnum).CastAnim)
        buffer.WriteInt32(Skill(skillnum).CastTime)
        buffer.WriteInt32(Skill(skillnum).CdTime)
        buffer.WriteInt32(Skill(skillnum).ClassReq)
        buffer.WriteInt32(Skill(skillnum).Dir)
        buffer.WriteInt32(Skill(skillnum).Duration)
        buffer.WriteInt32(Skill(skillnum).Icon)
        buffer.WriteInt32(Skill(skillnum).Interval)
        buffer.WriteInt32(Skill(skillnum).IsAoE)
        buffer.WriteInt32(Skill(skillnum).LevelReq)
        buffer.WriteInt32(Skill(skillnum).Map)
        buffer.WriteInt32(Skill(skillnum).MpCost)
        buffer.WriteString((Skill(skillnum).Name))
        buffer.WriteInt32(Skill(skillnum).Range)
        buffer.WriteInt32(Skill(skillnum).SkillAnim)
        buffer.WriteInt32(Skill(skillnum).StunDuration)
        buffer.WriteInt32(Skill(skillnum).Type)
        buffer.WriteInt32(Skill(skillnum).Vital)
        buffer.WriteInt32(Skill(skillnum).X)
        buffer.WriteInt32(Skill(skillnum).Y)

        buffer.WriteInt32(Skill(skillnum).IsProjectile)
        buffer.WriteInt32(Skill(skillnum).Projectile)

        buffer.WriteInt32(Skill(skillnum).KnockBack)
        buffer.WriteInt32(Skill(skillnum).KnockBackTiles)

        Socket.SendData(buffer.Data, buffer.Head)

        buffer.Dispose()
    End Sub

SendSaveSkill after serialization

    Friend Sub SendSaveSkill(skillnum As Integer)
        Dim buffer As New ByteStream(4)

        buffer.WriteInt32(EditorPackets.SaveSkill)
        buffer.WriteInt32(skillnum) ' <- Keep dat xit
        buffer.WriteBlock(SerializeData(Skill(skillnum)))
        Socket.SendData(buffer.Data, buffer.Head)

        buffer.Dispose()
    End Sub

 

Now we must update the object receiving on GameData and UpdateObject methods. They're found on Client and Editors, so you must make these steps FOR BOTH.

Go to ClientNetworkReceive (or modNetworkReceive on Editors) and find Packet_GameData sub. After that, you must find you object specific data reading section. In our case, its Skills data:

'\\\Read Skills Data\\\\\\\\\\
        x = Buffer.ReadInt32

        For i = 1 To x
            n = Buffer.ReadInt32

            Skill(n).AccessReq = Buffer.ReadInt32()
            Skill(n).AoE = Buffer.ReadInt32()
            Skill(n).CastAnim = Buffer.ReadInt32()
            Skill(n).CastTime = Buffer.ReadInt32()
            Skill(n).CdTime = Buffer.ReadInt32()
            Skill(n).ClassReq = Buffer.ReadInt32()
            Skill(n).Dir = Buffer.ReadInt32()
            Skill(n).Duration = Buffer.ReadInt32()
            Skill(n).Icon = Buffer.ReadInt32()
            Skill(n).Interval = Buffer.ReadInt32()
            Skill(n).IsAoE = Buffer.ReadInt32()
            Skill(n).LevelReq = Buffer.ReadInt32()
            Skill(n).Map = Buffer.ReadInt32()
            Skill(n).MpCost = Buffer.ReadInt32()
            Skill(n).Name = Trim(Buffer.ReadString())
            Skill(n).Range = Buffer.ReadInt32()
            Skill(n).SkillAnim = Buffer.ReadInt32()
            Skill(n).StunDuration = Buffer.ReadInt32()
            Skill(n).Type = Buffer.ReadInt32()
            Skill(n).Vital = Buffer.ReadInt32()
            Skill(n).X = Buffer.ReadInt32()
            Skill(n).Y = Buffer.ReadInt32()

            Skill(n).IsProjectile = Buffer.ReadInt32()
            Skill(n).Projectile = Buffer.ReadInt32()

            Skill(n).KnockBack = Buffer.ReadInt32()
            Skill(n).KnockBackTiles = Buffer.ReadInt32()

            If Skill(n).Name Is Nothing Then Skill(n).Name = ""
        Next

Like other examples, just replace the whole old code setting by Object = DeserializeData(buffer), in our case is Skill(n) = DeserializeData(buffer).

 

        '\\\Read Skills Data\\\\\\\\\\
        x = buffer.ReadInt32

        For i = 1 To x
            n = buffer.ReadInt32 ' <- Dont forget to keep dat xit

            Skill(n) = DeserializeData(buffer)

            If Skill(n).Name Is Nothing Then Skill(n).Name = ""
        Next

        i = 0
        x = 0
        n = 0
        z = 0

        '\\\End Read Skills Data\\\\\\\\\\

And for last, we must update the Packet_UpdateSkill located on the same module. Just keep the same logic, you don't need to remove the objectnum = Buffer.ReadInt32 line, just the old code related to data reading. Like this:

 

Packet_UpdateSkill before serialization

    Private Sub Packet_UpdateSkill(ByRef data() As Byte)
        Dim skillnum As Integer
        dim buffer as New ByteStream(Data)
        skillnum = Buffer.ReadInt32

        Skill(skillnum).AccessReq = Buffer.ReadInt32()
        Skill(skillnum).AoE = Buffer.ReadInt32()
        Skill(skillnum).CastAnim = Buffer.ReadInt32()
        Skill(skillnum).CastTime = Buffer.ReadInt32()
        Skill(skillnum).CdTime = Buffer.ReadInt32()
        Skill(skillnum).ClassReq = Buffer.ReadInt32()
        Skill(skillnum).Dir = Buffer.ReadInt32()
        Skill(skillnum).Duration = Buffer.ReadInt32()
        Skill(skillnum).Icon = Buffer.ReadInt32()
        Skill(skillnum).Interval = Buffer.ReadInt32()
        Skill(skillnum).IsAoE = Buffer.ReadInt32()
        Skill(skillnum).LevelReq = Buffer.ReadInt32()
        Skill(skillnum).Map = Buffer.ReadInt32()
        Skill(skillnum).MpCost = Buffer.ReadInt32()
        Skill(skillnum).Name = Trim(Buffer.ReadString())
        Skill(skillnum).Range = Buffer.ReadInt32()
        Skill(skillnum).SkillAnim = Buffer.ReadInt32()
        Skill(skillnum).StunDuration = Buffer.ReadInt32()
        Skill(skillnum).Type = Buffer.ReadInt32()
        Skill(skillnum).Vital = Buffer.ReadInt32()
        Skill(skillnum).X = Buffer.ReadInt32()
        Skill(skillnum).Y = Buffer.ReadInt32()

        Skill(skillnum).IsProjectile = Buffer.ReadInt32()
        Skill(skillnum).Projectile = Buffer.ReadInt32()

        Skill(skillnum).KnockBack = Buffer.ReadInt32()
        Skill(skillnum).KnockBackTiles = Buffer.ReadInt32()

        If Skill(skillnum).Name Is Nothing Then Skill(skillnum).Name = ""

        Buffer.Dispose()

    End Sub

Packet_UpdateSkill after serialization

    Private Sub Packet_UpdateSkill(ByRef data() As Byte)
        Dim skillnum As Integer
        Dim buffer As New ByteStream(data)
        skillnum = buffer.ReadInt32 ' <- Keep dat xit again

        Skill(skillnum) = DeserializeData(buffer)

        If Skill(skillnum).Name Is Nothing Then Skill(skillnum).Name = ""

        buffer.Dispose()

    End Sub

WHOOOOOOOA THATS IT! WE'RE DONE!

Well, at this point all your Skills must be correctly serializated through network packets. As it only virtual communication, you don't need to erase your existing skills on database.

 

Notes:

  • As serialization allocate every field in bytes, your packets should get bigger than usual, but nothing so huge.

 

As always, any problems related or question you can send me a PM or leave a comment on this post.

Thank you and til next time!.

 

 

If i was useful, feel free to make a donation!

8-2-paypal-donate-button-high-quality-pn

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×