Hello,
i’m new to programming and panda, but some inner force is driving me here to realize some of my game-design ideas.
so i will study and learn…
i started playing with python ~ a week ago and jumped into a script i know i will use often in prototyping and game-design-evaluation:
as many of my ideas make use of networking (and also communication between several processes that run the game) i wanted a very quick-and-simple to use messaging system. i choose a publisher-subscriber-system based on raknet (using pyraknet).
it works so far for testing purposes, but is nowhere near application-ready…
i’ll work on it
i know, this is dirty programming, but it works and is of great use for me, so i want to share it. (also i hope to get some feedback from you guys who DO know how to program ,-) )
if you have any questions or suggestion pls post
thanks for now,
trux
## intercom.py by Trux
## rough pre-version, yet to be cleaned and fixed!!!
##
## intercom.py provides networking as easy as it gets:
## perfectly for prototyping and development. future versions to be application-ready!
##
## to run the server: simply run this script standalone.
## commandline-arguments: port (default = 5555), max allowed peers/clients (default = 100), thread-sleep-time (default = 1 ms)
##
## in your application simply instance Channel('name','format').
## 'name' is the channels name, 'format' (default = 'B') is a string defining the user-message-format (according to struct.py documentation).
## optionally you can set priority[1..3], reliability[1..5] and ordering-channel[1..32], (according to raknet documentation) and host/port.
## if a channel with the given 'name' is already running at the server, all arguments will be ignored. the active 'format' (and other settings) will be used
## by the Channel() instance.
## methods of Channel():
## broadcast(msg): sends msg to all other members of the channel, according to 'format'
## receive(): receives one message at a time
## leave(): leaves the channel. currently the only way to leave the server without traces.
##
## ToDo: cleaning, testing, comments, doc, fixing traces from brute disconnects, extend functionality, etc..
##
## Thanks to raknet and pyraknet :-)
##
## have fun!!
import sys
import time
import struct
import pyraknet
from pyraknet import PlayerAddress
### SERVERCODE:
class Server():
def __init__(self, port = 5555, maxpeers = 100, sleep = 1):
self.port = port
self.net = pyraknet.Peer()#
self.net.init(peers=maxpeers, port=self.port, thread_sleep_timer=sleep)#
self.net.set_max_connections(maxpeers)#
self.priority = 2
self.reliability = 3
self.orderCh = 0
print 'Running, Waiting for connections..'
self.channelNames = {} # {name:ID}
self.channels = {} #{ID:(name, fmt, [memberIDs], pri, rel, och}
def loop(self):
while True:
time.sleep(0.01)
packet = self.net.receive()
if packet:
print 'received packet, type: ', ord(packet.data[0])
self.handlePacket(packet)
def handlePacket(self, packet):
packetType = ord(packet.data[0])
if packetType == 90: # channel request (90, name, fmt)
response = self.onChRequest(packet)
if(response):
self.net.send(response, len(response), self.priority, self.reliability, self.orderCh, packet.address)
elif packetType == 100: #userMsg (100, chID, (tuple from channel fmt))
response = self.onChMsg(packet)
if(response):
self.net.send(response, len(response), self.priority, self.reliability, self.orderCh, packet.address)
elif packetType == 98: #disconnect notification
response = self.onLeave(packet)
if(response):
self.net.send(response, len(response), self.priority, self.reliability, self.orderCh, packet.address)
elif packetType == 21:
print packet.address
print self.net.get_id_from_address(packet.address)
print 'BRUTE DISCONECTED USERS AND POLLUTED CHANNELS WILL NOT BE DELETED IN THIS VERSION!!!'
print
def onLeave(self, packet):
print 'Leave channel request by ', self.net.get_id_from_address(packet.address)
message = struct.unpack('B B',packet.data)
listIndex = self.channels[message[1]][2].index(self.net.get_id_from_address(packet.address))
del self.channels[message[1]][2][listIndex]
print 'member removed'
if not self.channels[message[1]][2]:
print 'Channel empty..'
ID = message[1]
name = self.channels[ID][0]
del self.channels[ID]
del self.channelNames[name]
print 'Channel deleted'
def onChMsg(self, packet):
channel = packet.data[1]
print packet.address
ID = struct.unpack('B', channel)[0]
for i in self.channels[ID][2]:
print i
if (i) != self.net.get_id_from_address(packet.address):
self.net.send(packet.data, len(packet.data), self.channels[ID][3], self.channels[ID][4], self.channels[ID][5], self.net.get_address_from_id(i))
def onChRequest(self, packet):
message = struct.unpack('B 16s 16s B B B', packet.data)
memberID = self.net.get_id_from_address(packet.address)
print memberID
if message[1] not in self.channelNames:
self.newChannel(message[1],message[2], message[3], message[4], message[5])
ID = self.channelNames[message[1]]
fmt = self.channels[ID][1]
pri = self.channels[ID][3]
rel = self.channels[ID][4]
och = self.channels[ID][5]
self.channels[ID][2].append(memberID)
response = struct.pack('B B 16s B B B', 91, ID, fmt, pri, rel, och)
return(response)
def newChannel(self, name, fmt, pri, rel, och):
IDs = self.channels.keys()
for i in range(len(IDs)+2):
if i not in IDs:
newID = i
break
self.channelNames[name] = newID
self.channels[newID] = (name, fmt, [], pri, rel, och)
print 'New Channel: ', self.channelNames[name], self.channels[newID]
### CLIENTCODE:
class Channel():
def __init__(self, name, format = 'B', pri = 2, rel = 4, och = 0, host = 'localhost', port = 5555):
self.name = name
self.format = format
self.ID = None
self.priority = pri
self.reliability = rel
self.orderCh = och
self.host = host
self.port = port
self.connect(self.host, self.port)
self.requestServerChannel()
def connect(self, host, port):
self.net = pyraknet.Peer()
self.net.init(thread_sleep_timer=1)
self.net.connect(host, port)
connected = False
while not connected:
print 'Trying to connect to server.. ', host, port
packet = self.net.receive()
if packet:
print 'received packet, type: ', ord(packet.data[0])
if ord(packet.data[0]) == 16:
self.serverAddress = packet.address
connected = True
time.sleep(1)
print 'Connection to server established'
print
def requestServerChannel(self):
print 'rsc'
chName = self.name
chFormat = self.format
chPri = self.priority
chRel = self.reliability
chOch = self.orderCh
packet = struct.pack('B 16s 16s B B B', 90, chName, chFormat, chPri, chRel, chOch) # 90: channel request
self.net.send(packet, len(packet), 2, 3, 0, self.serverAddress)
access = False
while not access:
print 'requesting channel.. '
packet = self.net.receive()
if packet:
print 'received packet, type: ', ord(packet.data[0])
if ord(packet.data[0]) == 91:
access = True
time.sleep(0.1)
message = struct.unpack('B B 16s B B B', packet.data)
self.ID = message[1]
self.format = message[2]
self.priority = message[3]
self.reliability = message[4]
self.orderCh = message[5]
print 'Access to channel ', message[1], '. Format: ', message[2]
print
def leave(self):
packet = struct.pack('B B',98, self.ID) # 98: disconnect
self.net.send(packet, len(packet), 3, 3, 0, self.serverAddress)
time.sleep(3)
self.net.disconnect()
print 'Disconnected..'
print
def broadcast(self, msg, msgTyp = 100): # msg is tuple, must fit chFormat
chMsg = struct.pack(self.format, msg)
msgType = struct.pack('B', msgTyp)
chID = struct.pack('B', self.ID)
packet = msgType+chID+chMsg
if self.serverAddress:
self.net.send(packet, len(packet), self.priority, self.reliability, self.orderCh, self.serverAddress)
else:
print 'Missing Server Address'
def receive(self):
while True:
packet = self.net.receive()
if packet:
print 'got something'
packetType = ord(packet.data[0])
if packetType == 13: # 13: raknet-system: connection accepted
self.serverAddress = packet.address
elif packetType == 100: # 100: channel-message
chID = ord(packet.data[1])
chMsg = struct.unpack(self.format, packet.data[2:len(packet.data)])
return(chMsg)
else:
print 'Unknown Packet Type! :', ord(packet.data[0]) # see raknet documentation for raknet system types..
return(packetType, None, None)
else:
break
### commandline args: port, maximum number of peers allowed, threadsleeptime (ms)
if __name__ == '__main__':
a = []
for i in sys.argv[1:len(sys.argv)]:
a.append(int(i))
args = tuple(a)
s = Server(*args)
s.loop()