GameServer programming, fast with thread for every player.

Everything else that doesn't fall into one of the other PB categories.
DarkDragon
Addict
Addict
Posts: 2347
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

GameServer programming, fast with thread for every player.

Post 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.
bye,
Daniel
Dreglor
Enthusiast
Enthusiast
Posts: 759
Joined: Sat Aug 02, 2003 11:22 pm
Location: OR, USA

Post 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
~Dreglor
DarkDragon
Addict
Addict
Posts: 2347
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Post by DarkDragon »

Thx for the fast answer but which librarys do you mean?
bye,
Daniel
Dreglor
Enthusiast
Enthusiast
Posts: 759
Joined: Sat Aug 02, 2003 11:22 pm
Location: OR, USA

Post by Dreglor »

~Dreglor
DarkDragon
Addict
Addict
Posts: 2347
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Post 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
bye,
Daniel
Dreglor
Enthusiast
Enthusiast
Posts: 759
Joined: Sat Aug 02, 2003 11:22 pm
Location: OR, USA

Post by Dreglor »

well what ever solves it :)
~Dreglor
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6172
Joined: Sat May 17, 2003 11:31 am
Contact:

Post 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?
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB - upgrade incoming...)
( The path to enlightenment and the PureBasic Survival Guide right here... )
DarkDragon
Addict
Addict
Posts: 2347
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Post by DarkDragon »

Uhm the threads are faster, because they run all at the same time. So no player plays slower than another.
bye,
Daniel
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6172
Joined: Sat May 17, 2003 11:31 am
Contact:

Post 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?
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB - upgrade incoming...)
( The path to enlightenment and the PureBasic Survival Guide right here... )
DarkDragon
Addict
Addict
Posts: 2347
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Post by DarkDragon »

thats what I wanted and what I reached.
bye,
Daniel
Nelligan
User
User
Posts: 13
Joined: Sat May 10, 2003 6:04 am

Post 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
Post Reply