i'm working on realtime mmo game, , have working tcp server (along game client), i'm considering using udp updating other player's postions(to reduce random game stuffer tcp congestion control!) i'd love people smarter me in stuff (i'm new python/twisted, , couldn't find info elsewhere ;) )
currently, server accepts connections simple twisted protocol. eg.
''' tcp reciever ''' class tcpprotocol(protocol): def connectionmade(self): #add list of connected clients factory.clients.append(self) def datareceived(self, data): pass #setup factory , tcp protocol class factory = factory() factory.protocol = tcpprotocol factory.clients = [] reactor.listentcp(1959, factory)
@@@@@@@@@@@@@@ update @@@@@@@@@@@@@ : how can implement congestion checking each protocol instance seperately? please start me off something, inside code sample below: (where says 'help here please'!) thinking of wrongly? guidance awesome, thanks!
from twisted.internet.protocol import datagramprotocol twisted.internet import reactor kserverip='127.0.0.1' kserverporttcp=8000 #kclientportudp=7055 ''' tcp reciever ''' class tcpprotocol(protocol): def connectionmade(self): #add list of connected clients factory.clients.append(self) #set client variables (simplified) self.pos_x=100 self.pos_y=100 #add game room (to recieve updates) maingameroom.clientsinroom.append(self) def datareceived(self, data): pass #send custom byte message client (i have special class read it) def sendmessagetoclient(self, message, isupdate): ''' @@@@@@@@@@@@@@@@@ here please! @@@@@@@@@@@ if isupdate , (check if client congested??? ) return (and send next update when not congested)''' '''@@@@@@@@@@@@@@@@@ here please! @@@@@@@@@@@ ''' #if not congested, write update! msglen = pack('!i', len(message.data)) self.transport.write(msglen) #add length before message self.transport.write(message.data) #simplified version of game room #this room runs game, , clients recieve pos updates #everyone in room (up 50 people) dt_gameloop=1.0/60 #loop time difference dt_sendclientupdate=0.1 #update intervar class gameroom(object): #room constants room_w=1000 room_h=1000 def __init__(self): super(gameroom, self).__init__() #schedule main game loop l=task.loopingcall(self.gameloop) l.start(dt_gameloop) # call every x seconds #schedule users update loop l=task.loopingcall(self.sendallclientsposupdate) l.start(dt_sendclientupdate) # call every x seconds def gameloop(self): #game logic runs here (60 times second), eg. anupdateclient in self.clientsinroom: anupdateclient.pos_x+=10 anupdateclient.pos_y+=10 #send position update every 0.1 seconds, #send player positions clients def sendallclientsposupdate(self): message = messagewriter() message.writebyte(messagegameloopupdate) #message type #create 1 byte message containing info players message.writeint(len(self.clientsinroom)) #num items read aclient in self.clientsinroom: message.writeint(aclient.id) message.writefloat( acell.pos_x )#pos message.writefloat( acell.pos_y ) #send message clients aclient in self.clientsinroom: aclient.sendmessagetoclient(message, true) #setup factory , tcp protocol class factory = factory() factory.protocol = tcpprotocol factory.clients = [] reactor.listentcp(kserverporttcp, factory) #simple example, 1 game room maingameroom=gameroom() print "server started..." reactor.run()
the first thing want "reduce network congestion ... tcp". not udp does. udp allows work around congestion control, increases network congestion. until you're aware of how implement own congestion control algorithms, udp traffic on high-latency connections going cause packet storms overwhelm server , flood users' network connections, making them unusable.
the important thing sending movement packets in real-time game want ensure don't waste time "catching up" old movement packets when new position available. in twisted, can use producer , consumer apis on tcp connection fine, so:
from zope.interface import implementer twisted.internet.protocol import protocol twisted.internet.interfaces import ipullproducer def serializeposition(position): "... take 'position', return bytes ..." @implementer(ipullproducer) class movementupdater(protocol, object): def updateposition(self, newposition): if newposition != self.currentposition: self.currentposition = newposition self.needtosendposition() waitingtosend = false def needtosendposition(self): if not self.waitingtosend: self.waitingtosend = true self.transport.registerproducer(self, false) def resumeproducing(self): self.transport.write(serializeposition(self.currentposition)) self.transport.unregisterproducer() self.waitingtosend = false def stopproducing(self): "nothing here"
every time game needs send new position, can call updateposition
update player's current position. updateposition
first updates current position, calls needtosendposition
marks connection needing send position update. registers protocol producer transport, cause resumeproducing
called each time write-buffer space available. resumeproducing
called, send whatever latest position - if updateposition
called 500 times while network congested, 1 update sent congestion alleviates.
this bit oversimplified, because each transport
can have 1 producer
@ time, , game server have lots of different position updates send clients, need multiplexor aggregates position updates multiple clients, , code order messages things other position updates still through position updates have priority.
this might seem work if you're going udp anyway, if you're going udp correctly , benefit it, need implement anyway, won't wasted.
Comments
Post a Comment