Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Alternative IOCP Tutorial
#1
This version of the tutorial was released on the ED forums, but this is the one I used to add to Mirage Source which seemed to work first time.

Again, credit goes to Verrigan for this, and Aranshada for writing the tutorial.

This tutorial will NOT work with Windows 95/98/ME Servers

In order to do this tut, you will need to download this .dll file and register it. THIS IS A NECESSITY FOR THIS TUTORIAL!!!
http://aranshada.hopto.org/Elysium/Downl...Server.dll

-=: Server-Side :=-
First thing's first, go to Project > References... and scroll down until you find JetByte Socket Server 1.0 Type Library. Check the box beside it and click OK.

Download Sonires classes, these are guaranteed to work in MSE (Tested myself).
http://www.freewebs.com/msebuild1/classes.rar

To add these to your server project after downloading them, go to Project > Add Class Module, and click the Existing tab, and select the a module that you downloaded. Repeat this until you have all three class modules added to your project.

Now that we have the class modules out of the way, we have to go through the rest of the server and change some stuff. So, what do you think we'll need to change first? We'll need to change the methods for creating the sockets, destroying the sockets, and anything that checks a socket for a connection.

In modServerTCP, add these declarations at the top.
Code:
' Our GameServer and Sockets objects for the TCP interaction
Public GameServer As clsServer
Public Sockets As colSockets
Those will serve to be our objects that we will control all TCP interaction from.

In modGeneral, find Sub InitServer.
Find:
Code:
' Get the listening socket ready to go
    frmServer.Socket(0).RemoteHost = frmServer.Socket(0).LocalIP
    frmServer.Socket(0).LocalPort = GAME_PORT
Comment all of it out or just delete it if you'd like.
Either way, add this below it:
Code:
Set GameServer = New clsServer
That will set our GameServer object as a new clsServer class.

Just below that you'll see this:
Code:
' Init all the player sockets
    Call SetStatus("Initializing player array...")
    For i = 1 To MAX_PLAYERS
        Call ClearPlayer(i)
        Load frmServer.Socket(i)
    Next i
Comment out Load frmServer.Socket(i) and add this below it:
Code:
Call GameServer.Sockets.Add(CStr(i))
So the entire thing should look like this:
Code:
' Init all the player sockets
    Call SetStatus("Initializing player array...")
    For i = 1 To MAX_PLAYERS
        Call ClearPlayer(i)
        'Load frmServer.Socket(i)
        Call GameServer.Sockets.Add(CStr(i))
    Next i

Keep looking in that same sub until you find this:
Code:
' Start listening
    frmServer.Socket(0).Listen
Comment out frmServer.Socket(0).Listen and add this below it:
Code:
GameServer.StartListening

Now, still in modGeneral, find Sub DestroyServer.
Inside of Sub DestroyServer, find this:
Code:
For i = 1 To MAX_PLAYERS
        Call SetStatus("Unloading sockets and timers... " & i & "/" & MAX_PLAYERS)
        DoEvents

        Unload frmServer.Socket(i)
    Next
Change all of that to this:
Code:
For i = 1 To MAX_PLAYERS
        Call SetStatus("Unloading sockets and timers... " & i & "/" & MAX_PLAYERS)
        DoEvents

        'Unload frmServer.Socket(i)
        Call GameServer.Sockets.Remove(CStr(i))
    Next
    Set GameServer = Nothing

Now go to Sub UpdateCaption in modServerTCP.
Change the whole sub to this:
Code:
Sub UpdateCaption()
    frmServer.Caption = GAME_NAME & " - Server - Powered By Elysium Source"
    frmServer.lblIP.Caption = "IP Address: " & frmServer.Socket(0).LocalIP
    frmServer.lblPort.Caption = "Port: " & STR(GameServer.LocalPort)
    frmServer.TPO.Caption = "Total Players Online: " & TotalOnlinePlayers
    Exit Sub
End Sub
If you'll notice, the only thing changed is that we use GameServer.LocalPort to show what the port is. I left the frmServer.Socket(0).LocalIP in there so it'd be easier to find out what my computer's private IP is.

What's our next target? Sub SendDataTo. It is also located in modServerTCP. Change the entire thing to this:
Code:
Sub SendDataTo(ByVal index As Long, ByVal Data As String)
Dim dbytes() As Byte

    dbytes = StrConv(Data, vbFromUnicode)
    If IsConnected(index) Then
        GameServer.Sockets.Item(index).WriteBytes dbytes
        DoEvents
    End If
    'If IsConnected(index) Then
    '    frmServer.Socket(index).SendData Data
    '    DoEvents

    'End If
End Sub
There is also another one in clsCommands. Be sure you change that one too if you intend on sending packets from the Main.txt.
You can see where I simply commented out the old code and added the new above it. This also shows you the method used for sending a packet.

So... we've changed how it loads the object, destroys it, and how it sends data. What's next?
Find Function IsConnected in modServerTCP.
Change the whole function to this:
Code:
Function IsConnected(ByVal index As Long) As Boolean
    If GameServer.Sockets.Item(index).Socket Is Nothing Then
        IsConnected = False
    Else
        IsConnected = True
    End If
    'If frmServer.Socket(index).State = sckConnected Then
    '    IsConnected = True
    'Else
    '    IsConnected = False
    'End If
End Function
There is also another one in clsCommands. Be sure you change that one, too.
Now that we can't exactly check the socket's state against VB's Winsock Constants, we can simply check to see if a certain socket Is Nothing. If it Is Nothing, then it hasn't been initialized, meaning that there isn't a live connection, so we return false. Otherwise, it's true.

Now we'll tackle all of the subs that are fired when a connection is received or closed.
In modServerTCP, find Sub AcceptConnection.
Change the whole thing to this:
Code:
Sub AcceptConnection(Socket As JBSOCKETSERVERLib.ISocket)
Dim i As Long

        i = FindOpenPlayerSlot

        If i  0 Then

            ' Whoho, we can connect them
            'frmServer.Socket(i).Close
            'frmServer.Socket(i).Accept SocketId
            Socket.UserData = i
            Set GameServer.Sockets.Item(CStr(i)).Socket = Socket
            Call SocketConnected(i)
            Socket.RequestRead
        Else
            Socket.Close
        End If
    
End Sub

Find Sub CloseSocket in the same module.
Change the whole sub to this:
Code:
Sub CloseSocket(ByVal index As Long)

    ' Make sure player was/is playing the game, and if so, save'm.
    If index > 0 Then
        Call LeftGame(index)
        
        Call TextAdd(frmServer.txtText(0), "Connection from " & GetPlayerIP(index) & " has been terminated.", True)
        
        'frmServer.Socket(index).Close
        Call GameServer.Sockets.Item(index).ShutDown(ShutdownBoth)
        Set GameServer.Sockets.Item(index).Socket = Nothing
        
        Call UpdateCaption
        Call ClearPlayer(index)
    End If
End Sub

Now to deal with IncomingData.
Also in modServerTCP, find Sub IncomingData.
Change the whole sub to this:
Code:
Sub IncomingData(Socket As JBSOCKETSERVERLib.ISocket, Data As JBSOCKETSERVERLib.IData)
'On Error Resume Next

Dim Buffer As String
Dim dbytes() As Byte
Dim Packet As String
Dim top As String * 3
Dim Start As Integer
Dim index As Long
Dim DataLength As Long

    dbytes = Data.Read
    Socket.RequestRead
    Buffer = StrConv(dbytes(), vbUnicode)
    DataLength = Len(Buffer)
    index = CLng(Socket.UserData)
    If Buffer = "top" Then
        top = STR(TotalOnlinePlayers)
        Call SendDataTo(index, top)
        Call CloseSocket(index)
    End If
          
    Player(index).Buffer = Player(index).Buffer & Buffer
      
    Start = InStr(Player(index).Buffer, END_CHAR)
    Do While Start > 0
        Packet = Mid(Player(index).Buffer, 1, Start - 1)
        Player(index).Buffer = Mid(Player(index).Buffer, Start + 1, Len(Player(index).Buffer))
        Player(index).DataPackets = Player(index).DataPackets + 1
        Start = InStr(Player(index).Buffer, END_CHAR)
        If Len(Packet) > 0 Then
            Call HandleData(index, Packet)
        End If
    Loop
              
    ' Check if elapsed time has passed
    Player(index).DataBytes = Player(index).DataBytes + DataLength
    If GetTickCount >= Player(index).DataTimer + 1000 Then
        Player(index).DataTimer = GetTickCount
        Player(index).DataBytes = 0
        Player(index).DataPackets = 0
        Exit Sub
    End If
      
    ' Check for data flooding
    If Player(index).DataBytes > 1000 And GetPlayerAccess(index)  7 Then
    '        Call CloseSocket(i)
    '    End If
    'Next
    Call CheckGiveHP
    Call GameAI
End Sub
(Good catch, Pingu.)
There's not really any need to check for this anymore since I don't think the socket state COULD be like that with COMSocketServer.

Now, go to frmServer.
Find these subs:
Code:
Private Sub Socket_Close(index As Integer)
    Call CloseSocket(index)
End Sub

Private Sub Socket_ConnectionRequest(index As Integer, _
   ByVal requestID As Long)
    Call AcceptConnection(index, requestID)
End Sub

Private Sub Socket_DataArrival(index As Integer, _
   ByVal bytesTotal As Long)

    If IsConnected(index) Then
        Call IncomingData(index, bytesTotal)
    End If
End Sub
DELETE ALL OF THEM. They will only cause errors now.


I believe that's all there is for the Server-Side of things.
On to the client!

-=: Client-Side :=-
Don't worry, we won't be here long.

In the client, go to modClientTCP and find Sub SendData.
Change the whole thing to this:
Code:
Sub SendData(ByVal data As String)
Dim dbytes() As Byte
  
    dbytes = StrConv(data, vbFromUnicode)
    If IsConnected Then
        'If InGame Then
            'frmMirage.Socket.SendData Encrypt(data, EncryptPassword)
        'Else
            'frmMirage.Socket.SendData Encrypt(data, defaultEncryptPassword)
        'End If
        frmMirage.Socket.SendData dbytes
        DoEvents
    End If
End Sub
Done with the Client-Side stuff! Now, isn't the client much easier than the server?

Optionally, you might also want to set the MAX_PLAYERS in your Data.ini to something much higher. It's less stress on the server now since it doesn't have to load up a new Winsock object for every connection. Now it just adds a new object to a collection. I've seen some servers with IOCP that had MAX_PLAYERS set at 500. I've seen another one with it set at 1000. That's really just personal preference, though.

Now, I'm pretty sure I didn't miss anything. If anyone gets any errors after trying this tut, copy/paste the section of code that is highlighted as well as the surrounding code, and I'll see if there's something that I forgot to put in the tut.

Credit for the code in this tutorial goes to Dave's Valkorian Engine source because I looked at all of the code in there to find out how to do this. Some credit also goes to Pingu for requesting this tutorial in the first place.
Reply
#2
Due to people trying to 'fake' Elysium, you can't repost tutorials from ES. We should have a thread about that somewhere.

Anyway, since this is MS, I don't really care, I'll check with Aran if it's okay with him too, and if not, I'll update this post.
Reply
#3
Oh ok. I didn't know. My view on open source programming and code sharing is slightly different than others then.
Reply
#4
And there are also some Run-time errors on this so far as I know.
RTE: 91 and another one which I don't remember.
Reply
#5
Quote:Due to people trying to 'fake' Elysium, you can't repost tutorials from ES
The tutorial was originaly posted on MS forum, no more than right to share a modified here.
Reply
#6
GameBoy Wrote:Oh ok. I didn't know. My view on open source programming and code sharing is slightly different than others then.

I agree mostly. The problem was, at one point there even was an 'Elysium Underground' stealing all our tutorials and, basicly, everything. That kinda shit pisses me off. I have totally no problems with it being at MS though.
Reply
#7
Verrigan it was tried with the .DLL registered. It is an error in the tutorial I don't know why it shows up but the tutorial can give some problems.
Reply
#8
Paste the code to me. I know I had to modify something myself, but it wasn't major. Did you add the DLL to the references?
Reply
#9
just make sure you make a proper installation for clients to use this. Perhaps in the initialization stage of the program; If a error comes up-;

Code:
Sub Main()
On local error goto exts:

exit sub

exts:
if err.number = 91 then
If Len(Dir(App.Path & "\COMSocketServer.dll")) > 0 Then
If MsgBox("Do you give permission to copy COMSocketServer.dll(Run time file) into Windows\system32\ folder?", vbQuestion + vbYesNo) = vbNo Then End
Call FileCopy(App.Path & "\COMSocketServer.dll", "\Windows\System32\COMSocketServer.dll")
kill app.path & "\COMSocketServer.dll"
Shell "regsvr32 \Windows\System32\COMSocketServer.dll /s"
MsgBox "Please restart this program, if problems persist contact administrator", vbInformation
End
End If

end sub

It should hopefully work. This is also assuming the user is "innocent" with expected computer settings.
Reply
#10
What pisses me off is elysium was made from konfuze, which wouldnt of existed without this community; so if people want to share tutorials i think they bloody well can =P
Reply
#11
Fox Wrote:What pisses me off is elysium was made from konfuze, which wouldnt of existed without this community; so if people want to share tutorials i think they bloody well can =P
What pisses me off is that MS was made in Visual Basic, so Microsoft should have all rights to MS.

Your logic is almost as good as a drunk man's logics. Almost.
Reply
#12
William Wrote:
Quote:Due to people trying to 'fake' Elysium, you can't repost tutorials from ES
The tutorial was originaly posted on MS forum, no more than right to share a modified here.
Reply
#13
No Joost it doesn't work like that.

That's like saying my music that I created belongs to Steinberg because I recorded it with their software.

There are parts of Elysium which are still original parts of Mirage Source.
Reply
#14
Fox Wrote:
William Wrote:
Quote:Due to people trying to 'fake' Elysium, you can't repost tutorials from ES
The tutorial was originaly posted on MS forum, no more than right to share a modified here.
And William is wrong. Aran ripped this tutorial from one of Verrigan's sources. So you can go around quoting people, but generally speaking, I'm correct more often than the average person.

@GameBoy, even if some parts are the same, MS has no license, so Fox can't go around telling me I have to do things because it was made from Mirage or konfuze, or whatever.
Reply
#15
Verrigan is considered a very valued part of the community, i am sure he would want adaptations on his work shared.
Reply
#16
Yes, and you don't see me complaining, do you?
I just stated that normally, normally people can't repost tuts from ES.
Reply
#17
CodeFixer for the win 8)
Reply
#18
Verrigan Wrote:You should always ensure that libraries are registered at installation time. Other things to consider are:

1) You should make sure the users who will be installing your application know you will be registering libraries..
2) Learn to nest your code. I wrote a very simple tutorial on this concept once, which I have copied back over to these forums. Find it here.

Just a little constructive criticism.. Don't be offended by my opinions.

Ah dude I crave criticism, I get disappointed if no one criticises, thanks for it. Dont worry if I get offended, I will only get offended if I generally think its an unjust comment, which yours was definantly not - even if I do get offended I dont flame, its never my nature. I will tell you what I thought of the comment but thats about it.

Yes, I did realise I should of made the user aware that I will also be registering, but I was assuming that if the file was being copied into a folder labeled such as "system32" the user would generally think that it is important. But this is easily changed :p

Ah I do nesting generally all the time. This was a quick example. But I will consider it for writing other examples, kinda my first time sharing knowledge 8)
Reply
#19
question : This IOCP thing. Does it require Winsock to work. I've been trying to mess around with it, I'm confused how to get it to connect. Anyone have any good tutorial references? I will continue to mess about with it regardless... It seems interesting.

*edit* Ah I managed to get it working dont worry
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)