Page 1 of 1

GameServer programming, fast with thread for every player.

Posted: Wed Jun 02, 2004 6:24 am
by DarkDragon
Hello,

I tried to make a GameServer, without threads, but then it was slow for the second, third, ... player, but not for the first.

Then Kooky told me I should create a thread for every player. I have done this, but I'm using a LinkedList. And if many threads are using the LinkedList at the same time, it will crash(I think this is the problem) :cry: .

Here is the source:
http://mitglied.lycos.de/dani008/index.php?down=gam.zip

In the clientfile, I made 2 jumpcomments:
> Bullets network
> Refresh networkdata

They are showing you, where the networklines are.

Please help me with this problem.

Posted: Wed Jun 02, 2004 6:55 am
by Dreglor
having them all synced (there are libs out there that do that)
and have each player a diffrent offset on the timing so that no 2 threads will read the list

Posted: Wed Jun 02, 2004 7:21 am
by DarkDragon
Thx for the fast answer but which librarys do you mean?

Posted: Wed Jun 02, 2004 7:45 am
by Dreglor

Posted: Wed Jun 02, 2004 8:08 am
by DarkDragon
LOL, I made it with Global variables:

Code: Select all

InitNetwork()

Structure Client ;Playerdata
  CData.l
  Size.l
  ID.l
  Thread.l
EndStructure

Structure Object ;Bullets of the guns
  ID.l
  SX.l
  SY.l
  X.l
  Y.l
  CData.l
  Size.l
EndStructure

OpenConsole() ;Open a primitive console

;Linked Lists for the bullets and the players
NewList Client.Client()
NewList OBJ.Object()

Global Port, Clients, Mode, ToSend, List, Stop.s, Threadmode

Port = 80

Stop.s  = "STOP"

Procedure Player(ClientID)
  Repeat
    OldList = List
    Select Mode
      Case 0
        If ClientID <> Client()\ID
          SendNetworkData(ClientID, Client()\CData, Client()\Size)
        EndIf
      Case 1
        SendNetworkData(ClientID, OBJ()\CData, OBJ()\Size)
      Case 3
        SendNetworkData(ClientID, @Stop, 4)
    EndSelect
    ToSend - 1
    While ToSend > 0 And OldList = List
    Delay(1)
    Wend
    Delay(15)
  Until Quit = 1
EndProcedure

Procedure Thread()
  Repeat
    If Threadmode = 1
    Mode = 0
    ForEach Client()
      List = ListIndex(Client())
      ToSend = CountList(Client())
      While ToSend > 0
      Delay(1)
      Wend
    Next
    Mode = 1
    ForEach OBJ()
      List = ListIndex(OBJ())
      ToSend = CountList(OBJ())
      While ToSend > 0
      Delay(1)
      Wend
    Next
    Mode = 3
    Threadmode = 0
    EndIf
    Delay(15)
  ForEver
EndProcedure

CreateNetworkServer(Port) ;Create the server

MainThread = CreateThread(@Thread(), 0)

Repeat
  If Threadmode = 0
  ForEach OBJ() ;moving the bullets
    OBJ()\X + OBJ()\SX
    OBJ()\Y + OBJ()\SY
    KString.s = Str(OBJ()\X)+" "+Str(OBJ()\Y)+" "+Str(OBJ()\ID)+Chr(10)
    OBJ()\CData = ReAllocateMemory(OBJ()\CData, Len(KString.s))
    CopyMemory(@KString, OBJ()\CData, Len(KString))
    OBJ()\Size  = Len(KString)
  Next
  Select NetworkServerEvent()
    Case 1 ;new client
      AddElement(Client())
      Client()\ID = NetworkClientID()
      Client()\CData = AllocateMemory(1000)
      Client()\Thread = CreateThread(@Player(), Client()\ID)
      PrintN("Client: Login")
      Clients + 1
    Case 2
      ClientID = NetworkClientID()
      String.s = Space(1000)
      Size.l   = ReceiveNetworkData(ClientID, @String.s, 1000) ;Receiving the data
      String   = Left(String, Size)
      For k=1 To CountString(String, Chr(10))
      Text.s = StringField(String, k, Chr(10))
      Select LCase(StringField(Text, 1, " "))
        Case "del"  ;Delete bullet
          PauseThread(MainThread)
          SelectElement(OBJ(), Val(StringField(Text, 2, " ")))
          FreeMemory(OBJ()\CData)
          DeleteElement(OBJ())
        Case "new"  ;New bullet
          AddElement(OBJ())
          KString.s = StringField(Text, 2, " ")+" "+StringField(Text, 3, " ")+" "+StringField(Text, 4, " ")+Chr(10)
          OBJ()\CData = AllocateMemory(Len(KString.s))
          CopyMemory(@KString, OBJ()\CData, Len(KString))
          OBJ()\Size  = Len(KString)
          OBJ()\X     = Val(StringField(Text, 2, " "))
          OBJ()\Y     = Val(StringField(Text, 3, " "))
          OBJ()\ID    = Val(StringField(Text, 4, " "))
          OBJ()\SX    = Val(StringField(Text, 5, " "))
          OBJ()\SY    = Val(StringField(Text, 6, " "))
        Case "set"  ;Playerposition
          ForEach Client()
            If Client()\ID = ClientID
              Break
            EndIf
          Next
          MText.s = Right(Text.s, Len(Text)-4)+Chr(10) ;Text without the command to do
          Client()\CData = ReAllocateMemory(Client()\CData, Len(MText))
          Client()\Size  = Len(MText)
          CopyMemory(@MText, Client()\CData, Len(MText))
      EndSelect
      Next
    Case 4 ;Client disconnected
      Clients - 1
      ClientID = NetworkClientID()
      ForEach Client()
        If Client()\ID = ClientID
        KillThread(Client()\Thread)
        FreeMemory(Client()\CData)
        DeleteElement(Client())
        PrintN("Client: Logout")
        Break
        EndIf
      Next
  EndSelect
  Threadmode = 1
  EndIf
  Delay(10)
ForEver
Then the client should have a new refresh proc:

Code: Select all

Procedure Refresh()
  String.s = "SET "
  String.s + Str(Player\X) + " "
  String.s + Str(Player\Y) + " "
  String.s + Str(Player\Skill[0]) + " "
  String.s + Str(Player\Skill[1]) + " "
  String.s + Str(Player\Skill[2]) + " "
  String.s + Str(Player\Skill[3]) + " "
  String.s + Str(Player\Skill[4]) + " "
  SendNetworkString(ConnectionID, String.s+Chr(10))
  
  t = 0
  While NetworkClientEvent(ConnectionID) <> 2 And t <= 200 : WindowEvent() : t + 1 : Delay(1) : Wend
  
  If t <= 200
  String.s = Space(10000)
  Size.l   = ReceiveNetworkData(ConnectionID, @String.s, 10000)
  String = Left(String, Size)
  
  If CountString(String, Chr(10)) <> 0 ;Is there any data?
  
  ClearList(Player())
  ClearList(Bullet())
  For k=1 To CountString(String, Chr(10))
    Text.s = StringField(String, k, Chr(10))
    If Val(StringField(Text, 3, " ")) <= #TEAM4
    AddElement(Player())
    Player()\X = Val(StringField(Text, 1, " "))
    Player()\Y = Val(StringField(Text, 2, " "))
    Player()\Skill[0] = Val(StringField(Text, 3, " "))
    Player()\Skill[1] = Val(StringField(Text, 4, " "))
    Player()\Skill[2] = Val(StringField(Text, 5, " "))
    Player()\Skill[3] = Val(StringField(Text, 6, " "))
    Player()\Skill[4] = Val(StringField(Text, 7, " "))
    ElseIf Val(StringField(Text, 3, " ")) = #BULLET
    AddElement(Bullet())
    Bullet()\X = Val(StringField(Text, 1, " "))
    Bullet()\Y = Val(StringField(Text, 2, " "))
    Else : Break : EndIf
  Next
  
  EndIf
  EndIf
EndProcedure

Posted: Wed Jun 02, 2004 8:16 am
by Dreglor
well what ever solves it :)

Posted: Wed Jun 02, 2004 11:49 am
by blueznl
just for my understanding, why would threads be faster?

i mean, a cpu has only so much processing power, or am i missing the point?

Posted: Wed Jun 02, 2004 11:54 am
by DarkDragon
Uhm the threads are faster, because they run all at the same time. So no player plays slower than another.

Posted: Wed Jun 02, 2004 12:02 pm
by blueznl
9 players, 0 is idle time

computing in one thread:

123456789

computing in 9 threads:

100000000
020000000
003000000
000400000
000050000
000006000
000000700
000000080
000000009

although cpu power is spread over the different players, each thread runs slower, effectively giving the same speed per player, unless your point is that you want to synchronize the players actions, ie. all players must have completed their actions before the first one can continue

is that the case?

Posted: Wed Jun 02, 2004 12:40 pm
by DarkDragon
thats what I wanted and what I reached.

Posted: Sat Sep 04, 2004 8:13 pm
by Nelligan
I'm toying with my mmorpg project network code. I first built upon a simple chat server and I was having lag and coordinates inconsistencies with just two players.

Then I saw this thread on threads :) and I tested it with a friend. I run the server localy and me and my friend connect on it.

Is this code supposed to work well, because we don't see the same thing on our screens. The players positions are off and my friend sees my player at two places on the screen.

I'm searching for a simple working implementation of multiplayer code. I found a mmorpg in blitz basic but it's a little compicated to me.

Any suggestion would be appreciated. Thanks