Difficulty: Medium 3/5
This tutorial is designed to show you how to put a buffer system in your game. Why would you want to do that? Think about it. When a player connects, there are a series of messages sent to that player, and in Mirage, they are sent one right after the other.. If you have large maps, or you have a bunch of items/npcs/spells/etc., the server will send all that data to a user who is connecting.. For small games with small sized maps, this isn't a problem.. Lag is minimal. However, for games with tons of items, spells, etc., you will experience lag when another player connects.
Okay, now introduce a buffering (queue) system.. The server form has a timer that calls a subroutine that is solely responsible for dropping the size of the queue. How does the queue get filled? Instead of immediately sending any data to a player, you make the server add it to the queue. The server then hits the timer's interval, calls the subroutine to drop the queue, which sends messages to each user that is waiting for those messages. The subroutine will go through all connections, check the queue, and deliver messages to each user up to a predefined size limit for each user.. (This tutorial limits that size to 32K per user, per loop, but you can easily customize that limit.)
All that said, I must say that I have only tested this buffer system with one connection, so it might need some work, which is why I set the difficulty at 3.. Some of you might think the difficulty should be 5, but that's why I'm going to tell you this: BACKUP YOUR SERVER BEFORE ADDING THIS TUTORIAL.
Now, on with the tutorial..
Files to Modify[*]frmServer.frm [*]modGeneral.bas [*]modServerTCP.bas [*]modTypes.bas[/list:u]*** In addition to the above files, you will need to change any line from:
Call CloseSocket(<whatever variable is used... Index, i, etc.>) to:
QueueDisconnect(<same variable name... Index, i, etc.>) = True
[size=18px]frmServer.frm FrmServer is where timers and sockets are stored.. I don't like to do this, but my tutorials are based on the already existing code in the Mirage Source, not redoing the whole thing.. :P So...
Add a timer to the form named: tmrStartMsgQueue with an interval of 100. Then, in the code of frmServer, add the following code:
Private Sub tmrStartMsgQueue_Timer() Call SendQueuedData End Sub
[size=18px]modGeneral.bas ModGeneral is where general stuff happens.. The server is initialized here, the AI is in here, etc.
Add the following code somewhere:
Sub SendQueuedData() Dim i As Integer, n As Long Dim TmpStr As String For i = 1 To MAX_PLAYERS
TmpStr = "" With ConQueues(i) If Not .Lock Then If frmServer.Socket(i).State <> 7 Then .Lines = "" End If If Len(.Lines) = 0 And QueueDisconnect(i) = True Then Call CloseSocket(i) QueueDisconnect(i) = False Else If Len(.Lines) > 0 Then If Len(.Lines) < MAX_PACKETLEN Then TmpStr = .Lines Else TmpStr = Left(.Lines, MAX_PACKETLEN) End If .Lines = Right(.Lines, Len(.Lines) - Len(TmpStr)) End If End If If Len(TmpStr) > 0 Then Call frmServer.Socket(i).SendData(TmpStr) End If End If End With Next DoEvents End Sub
In Sub InitServer After this code:
' Init all the player sockets For i = 1 To MAX_PLAYERS Call SetStatus("Initializing player array...") Call ClearPlayer(i) Load frmServer.Socket(i) add this code:
ConQueues(i).Lines = "" 'Initialize the lines.
[size=18px]modServerTCP.bas ModServerTCP handles the data being sent from/received to the server.
In Sub SendDataTo() Change this code:
If IsConnected(Index) Then frmServer.Socket(Index).SendData Data DoEvents End If to this code:
If IsConnected(Index) Then With ConQueues(Index) .Lock = True .Lines = .Lines & Data .Lock = False End With 'DoEvents End If
[size=18px]modTypes.bas ModTypes is where all the data types are stored, and other stuff...
Under this code:
Type GuildRec Name As String * NAME_LENGTH Founder As String * NAME_LENGTH Member(1 To MAX_GUILD_MEMBERS) As String * NAME_LENGTH End Type add this code:
Type ConDataQueue Lock As Boolean Lines As String End Type
Public ConQueues(MAX_PLAYERS) As ConDataQueue Public Const MAX_PACKETLEN As Long = 32768 'About 32K Public QueueDisconnect(MAX_PLAYERS) As Boolean
This was tested in a vanilla Mirage Source 3.0.3. So, if you add this to your game, and I only tested this with one player connected.. (I don't have a bunch of users, cause I don't run a Mirage server.. :P) Anyways.. Just like any other tutorials on here... BACKUP YOUR SOURCE!!! I said it twice, now... Hopefully you will take my advice..
It is also possible that I failed to put something in here.. In the event that you find that I forgot something, or you tried this in a vanilla server and it didn't work.. Please post here, but I'm pretty sure I remembered everything.. :)
|