Add framework for entity serialization
This commit is contained in:
parent
d400883be1
commit
61e15cff47
58
Jormungand.py
Normal file
58
Jormungand.py
Normal file
@ -0,0 +1,58 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from util.Util import logout
|
||||
|
||||
class Jormungand():
|
||||
def __init__(self, argv):
|
||||
command = argv[1] if len(argv) >= 2 else "help"
|
||||
registry = defaultdict(lambda: Jormungand.help, {
|
||||
"help": Jormungand.help,
|
||||
"run": Jormungand.run,
|
||||
"send": Jormungand.send
|
||||
})
|
||||
exec_func = registry[command]
|
||||
self.execute = lambda: exec_func(argv)
|
||||
|
||||
@staticmethod
|
||||
def help(argv):
|
||||
print("Hello, world!")
|
||||
|
||||
@staticmethod
|
||||
def run(argv):
|
||||
if len(argv) < 3:
|
||||
print("run requires a port")
|
||||
sys.exit(-1)
|
||||
port = int(argv[2])
|
||||
from world.Server import Server
|
||||
server = Server(port)
|
||||
logout("Launching server on port {}".format(port), "Jormungand run")
|
||||
server.run(argv[3:])
|
||||
|
||||
@staticmethod
|
||||
def send(argv):
|
||||
if len(argv) < 4:
|
||||
print("send requires a target and payload")
|
||||
sys.exit(-1)
|
||||
address = argv[2]
|
||||
import zmq, json, pygame
|
||||
pygame.display.set_mode((1,1), pygame.NOFRAME)
|
||||
context = zmq.Context()
|
||||
socket = context.socket(zmq.REQ)
|
||||
socket.connect("tcp://{}".format(address))
|
||||
for i in range(3, len(argv)):
|
||||
if argv[i] == "-ball":
|
||||
from entity.dummy.DebugBall import DebugBall
|
||||
e = DebugBall()
|
||||
s = json.dumps(e.serialize())
|
||||
print("Sending {}".format(str(e)))
|
||||
for i in range(100):
|
||||
socket.send_string(s)
|
||||
message = socket.recv()
|
||||
print("Reply: {}".format(message))
|
||||
|
||||
def main():
|
||||
j = Jormungand(sys.argv)
|
||||
j.execute()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
BIN
assets/ball64.png
Normal file
BIN
assets/ball64.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 632 B |
BIN
assets/tube.png
Normal file
BIN
assets/tube.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
83
entity/Entity.py
Normal file
83
entity/Entity.py
Normal file
@ -0,0 +1,83 @@
|
||||
import sys
|
||||
from random import randrange
|
||||
|
||||
class Entity(object):
|
||||
"""
|
||||
An Entity is something that exists in the Fishtank entities list. The Entity class provides
|
||||
some basic structure to the behavior of entities, including position and velocity,
|
||||
serialization, and update and draw. Each entity has a random 8-digit hex id for identification
|
||||
purposes.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.fishtank = None
|
||||
self.id = randrange(16**8)
|
||||
self.x = 0
|
||||
self.y = 0
|
||||
self.z = 0
|
||||
self.vx = 0
|
||||
self.vy = 0
|
||||
|
||||
def __repr__(self):
|
||||
return "[{}#{:8x} p{},{} z{} v{},{}]".format(type(self).__name__,
|
||||
self.id, self.x, self.y, self.z, self.vx, self.vy)
|
||||
|
||||
def __str__(self):
|
||||
return "[{}#{:8x}]".format(type(self).__name__, self.id)
|
||||
|
||||
def serialize(self):
|
||||
"""
|
||||
Returns a JSON-compatbible representation of the current state of this entity.
|
||||
Subclasses should override this method, call it from their superclass, then update the
|
||||
returned representation with its own information, including the subclass's module and
|
||||
class and any idiomatic fields of that class.
|
||||
Output: serialized representation of this entity
|
||||
"""
|
||||
return {
|
||||
"module":"entity.Entity",
|
||||
"class":"Entity",
|
||||
"id":"{:8x}".format(self.id),
|
||||
"p":[self.x,self.y],
|
||||
"z":self.z,
|
||||
"v":[self.vx,self.vy]
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def deserialize(serial):
|
||||
"""
|
||||
Reconstructs an Entity from a serialized representation as returned by Entity.serialize().
|
||||
Subclasses should reimplement this method with e as their own class.
|
||||
Input: serial, a serialized representation of an entity
|
||||
Output: an entity reproducing the state represented in serial
|
||||
"""
|
||||
e = Entity()
|
||||
return Entity.rebuild(e, serial)
|
||||
|
||||
@staticmethod
|
||||
def rebuild(e, serial):
|
||||
"""
|
||||
Helper function for Entity.deserialize().
|
||||
Subclasses should override this method, call it from their superclass, then add
|
||||
deserialization for their idiomatic fields.
|
||||
Input: e, a newly initialized entity
|
||||
serial, a serialized representation of an entity as passed to deserialize()
|
||||
Output: an entity reproducing the state represented in serial
|
||||
"""
|
||||
e.id = int(serial['id'], 16)
|
||||
e.x, e.y = serial['p']
|
||||
e.z = serial['z']
|
||||
e.vx, e.vy = serial['v']
|
||||
return e
|
||||
|
||||
def update(self, delta):
|
||||
"""
|
||||
Updates this entity during the update pass of the game loop.
|
||||
Input: delta, the number of seconds since the last tick
|
||||
"""
|
||||
pass
|
||||
|
||||
def draw(self, screen):
|
||||
"""
|
||||
Draws this entity during the draw pass of the game loop.
|
||||
Input: screen, a Surface object to draw this entity on.
|
||||
"""
|
||||
pass
|
32
entity/Tube.py
Normal file
32
entity/Tube.py
Normal file
@ -0,0 +1,32 @@
|
||||
import sys
|
||||
from entity.Entity import Entity
|
||||
from util.Util import logout, load_image
|
||||
|
||||
class Tube(Entity):
|
||||
def __init__(self, network_gate):
|
||||
Entity.__init__(self)
|
||||
self.gate = network_gate
|
||||
self.inbox = []
|
||||
self.texture = load_image("tube.png")
|
||||
self.x, self.y = 200, 200
|
||||
self.z = -1
|
||||
|
||||
def __repr__(self):
|
||||
return "[Tube gate={} inbox={}]".format(repr(self.gate), repr(self.inbox))
|
||||
|
||||
def accept(self, entity):
|
||||
self.fishtank.remove_entity(entity)
|
||||
self.inbox.append(entity)
|
||||
logout("Accepted: {}".format(str(entity), "Tube#{}".format(self.id)))
|
||||
|
||||
def update(self, delta):
|
||||
Entity.update(self, delta)
|
||||
if self.inbox:
|
||||
entity = self.inbox.pop(0)
|
||||
self.gate.transmit(entity.serialize())
|
||||
|
||||
def draw(self, screen):
|
||||
Entity.draw(self, screen)
|
||||
rect = self.texture.get_rect()
|
||||
rect.center = (int(self.x), int(self.y))
|
||||
screen.blit(self.texture, rect)
|
62
entity/dummy/DebugBall.py
Normal file
62
entity/dummy/DebugBall.py
Normal file
@ -0,0 +1,62 @@
|
||||
import sys
|
||||
import random
|
||||
import pygame
|
||||
from entity.Entity import Entity
|
||||
from entity.Tube import Tube
|
||||
from util.Util import load_image
|
||||
|
||||
class DebugBall(Entity):
|
||||
"""
|
||||
A debug entity that bounces around and jumps through network tubes.
|
||||
"""
|
||||
def __init__(self):
|
||||
Entity.__init__(self)
|
||||
self.vx = 32
|
||||
self.vy = 128
|
||||
self.dummy = "DUMMY"
|
||||
self.texture = load_image("ball64.png")
|
||||
self.texture = pygame.transform.smoothscale(self.texture, (16,16))
|
||||
self.rect = pygame.Rect(0, 0, 16, 16)
|
||||
|
||||
def serialize(self):
|
||||
e = Entity.serialize(self)
|
||||
e.update({
|
||||
"module":"entity.dummy.DebugBall",
|
||||
"class":"DebugBall",
|
||||
"dummy":self.dummy
|
||||
})
|
||||
return e
|
||||
|
||||
@staticmethod
|
||||
def deserialize(serial):
|
||||
e = DebugBall()
|
||||
return DebugBall.rebuild(e, serial)
|
||||
|
||||
@staticmethod
|
||||
def rebuild(e, serial):
|
||||
Entity.rebuild(e, serial)
|
||||
e.dummy = serial["dummy"]
|
||||
return e
|
||||
|
||||
def update(self, delta):
|
||||
Entity.update(self, delta)
|
||||
self.x += self.vx * delta
|
||||
self.y += self.vy * delta
|
||||
if self.x < 0 or self.x > self.fishtank.size[0]:
|
||||
self.vx = -self.vx
|
||||
self.x = 0 if self.x < 0 else self.fishtank.size[0] if self.x > self.fishtank.size[0] else self.x
|
||||
if self.y < 0 or self.y > self.fishtank.size[1]:
|
||||
self.vy = -self.vy
|
||||
self.y = 0 if self.y < 0 else self.fishtank.size[1] if self.y > self.fishtank.size[1] else self.y
|
||||
|
||||
for entity in self.fishtank.entities:
|
||||
if type(entity) is Tube and abs(self.x - entity.x) < 64 and abs(self.y - entity.y) < 64:
|
||||
entity.accept(self)
|
||||
break
|
||||
|
||||
def draw(self, screen):
|
||||
Entity.draw(self, screen)
|
||||
#rect = self.texture.get_rect()
|
||||
self.rect.center = (int(self.x), int(self.y))
|
||||
screen.blit(self.texture, self.rect)
|
||||
|
@ -1,41 +1,41 @@
|
||||
import sys
|
||||
from entity.Entity import Entity
|
||||
from entity.Tube import Tube
|
||||
|
||||
class DebugJumper(Entity):
|
||||
def __init__(self, message):
|
||||
Entity.__init__(self)
|
||||
self._message = message
|
||||
self._counter = 0
|
||||
|
||||
def __repr__(self):
|
||||
return "[DebugJumper message='{}' counter={}]".format(self._message, self._counter)
|
||||
|
||||
def serialize(self):
|
||||
sup = Entity.serialize(self)
|
||||
sup.update({
|
||||
"module":"entity.dummy.DebugJumper",
|
||||
"class":"DebugJumper",
|
||||
"message":self._message,
|
||||
"counter":self._counter
|
||||
})
|
||||
return sup
|
||||
|
||||
@staticmethod
|
||||
def deserialize(serial):
|
||||
e = DebugJumper(serial["message"])
|
||||
e._counter = serial["counter"]
|
||||
return e
|
||||
|
||||
def update(self):
|
||||
Entity.update(self)
|
||||
self._counter += 1
|
||||
if self._counter % 5 == 0:
|
||||
for entity in self._fishtank._entities:
|
||||
if type(entity) is Tube:
|
||||
entity.accept(self)
|
||||
break
|
||||
|
||||
def draw(self):
|
||||
Entity.draw(self)
|
||||
sys.stdout.write(self._message + " ({})\n".format(self._counter))
|
||||
import sys
|
||||
from entity.Entity import Entity
|
||||
from entity.Tube import Tube
|
||||
|
||||
class DebugJumper(Entity):
|
||||
def __init__(self, message):
|
||||
Entity.__init__(self)
|
||||
self.message = message
|
||||
self.counter = 0
|
||||
|
||||
def __repr__(self):
|
||||
return "[DebugJumper @{},{} message='{}' counter={}]".format(self.x, self.y, self.message, self.counter)
|
||||
|
||||
def serialize(self):
|
||||
sup = Entity.serialize(self)
|
||||
sup.update({
|
||||
"module":"entity.dummy.DebugJumper",
|
||||
"class":"DebugJumper",
|
||||
"message":self.message,
|
||||
"counter":self.counter
|
||||
})
|
||||
return sup
|
||||
|
||||
@staticmethod
|
||||
def deserialize(serial):
|
||||
e = DebugJumper(serial["message"])
|
||||
e.counter = serial["counter"]
|
||||
return e
|
||||
|
||||
def update(self, delta):
|
||||
Entity.update(self)
|
||||
self.counter += 1
|
||||
if self.counter % 5 == 0:
|
||||
for entity in self.fishtank.entities:
|
||||
if type(entity) is Tube:
|
||||
entity.accept(self)
|
||||
break
|
||||
|
||||
def draw(self, screen):
|
||||
Entity.draw(self)
|
||||
sys.stdout.write(self.message + " ({})\n".format(self.counter))
|
@ -1,43 +0,0 @@
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
|
||||
class Fishtank():
|
||||
def __init__(self, recv_queue):
|
||||
self._entities = []
|
||||
self._to_remove = []
|
||||
self._recv_queue = recv_queue
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
# Delete flagged entities
|
||||
if self._to_remove:
|
||||
for entity in self._to_remove:
|
||||
self._entities.remove(entity)
|
||||
self._to_remove = []
|
||||
# Update and draw
|
||||
for entity in self._entities:
|
||||
entity.update()
|
||||
for entity in self._entities:
|
||||
entity.draw()
|
||||
#time.sleep(1)
|
||||
# Intake queue
|
||||
if not self._recv_queue.empty():
|
||||
serial = self._recv_queue.get(False)
|
||||
sys.stdout.write("Fishtank dequeued a {}\n".format(serial["class"]))
|
||||
mod = __import__(serial["module"], fromlist=[serial["class"]])
|
||||
klass = getattr(mod, serial["class"])
|
||||
e = klass.deserialize(serial)
|
||||
self.add_entity(e)
|
||||
|
||||
def add_entity(self, entity):
|
||||
entity._fishtank = self
|
||||
self._entities.append(entity)
|
||||
sys.stdout.write("Added: {}\n".format(repr(entity)))
|
||||
|
||||
def remove_entity(self, entity):
|
||||
if entity not in self._entities:
|
||||
sys.stderr.write(
|
||||
"WARN: remove called for entity '{}', but it isn't in the eneityt list\n".format(entity.__name__))
|
||||
return
|
||||
self._to_remove.append(entity)
|
@ -1,25 +0,0 @@
|
||||
import sys
|
||||
|
||||
class Entity(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __repr__(self):
|
||||
return "[Entity]"
|
||||
|
||||
def serialize(self):
|
||||
return {
|
||||
"module":"entity.Entity",
|
||||
"class":"Entity"
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def deserialize(serial):
|
||||
e = Entity()
|
||||
return e
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
def draw(self):
|
||||
pass
|
@ -1,22 +0,0 @@
|
||||
import sys
|
||||
from entity.Entity import Entity
|
||||
|
||||
class Tube(Entity):
|
||||
def __init__(self, network_gate):
|
||||
Entity.__init__(self)
|
||||
self._gate = network_gate
|
||||
self._inbox = []
|
||||
|
||||
def __repr__(self):
|
||||
return "[Tube gate={} inbox={}]".format(repr(self._gate), repr(self._inbox))
|
||||
|
||||
def accept(self, entity):
|
||||
self._fishtank.remove_entity(entity)
|
||||
self._inbox.append(entity)
|
||||
|
||||
def update(self):
|
||||
Entity.update(self)
|
||||
if self._inbox:
|
||||
entity = self._inbox.pop(0)
|
||||
sys.stdout.write("Sending: {}\n".format(repr(entity)))
|
||||
self._gate.transmit(entity.serialize())
|
@ -1,19 +0,0 @@
|
||||
import sys
|
||||
from entity.Entity import Entity
|
||||
|
||||
class DebugWaiter(Entity):
|
||||
def __init__(self, message):
|
||||
Entity.__init__(self)
|
||||
self._message = message
|
||||
self._counter = 0
|
||||
|
||||
def __repr__(self):
|
||||
return "[DebugWaiter message='{}' counter={}]".format(self._message, self._counter)
|
||||
|
||||
def update(self):
|
||||
Entity.update(self)
|
||||
self._counter += 1
|
||||
|
||||
def draw(self):
|
||||
Entity.draw(self)
|
||||
sys.stdout.write(self._message + " ({})\n".format(self._counter))
|
@ -1,19 +0,0 @@
|
||||
import sys
|
||||
import zmq
|
||||
import json
|
||||
|
||||
class NetworkGate():
|
||||
def __init__(self, address, port):
|
||||
self._address = address
|
||||
self._port = port
|
||||
context = zmq.Context()
|
||||
self._socket = context.socket(zmq.REQ)
|
||||
self._socket.connect("tcp://{}:{}".format(address, port))
|
||||
|
||||
def __repr__(self):
|
||||
return "[NetworkGate {}:{}]".format(self._address, self._port)
|
||||
|
||||
def transmit(self, serial):
|
||||
s = json.dumps(serial)
|
||||
self._socket.send_string(s)
|
||||
message = self._socket.recv()
|
@ -1,54 +0,0 @@
|
||||
import sys
|
||||
import zmq
|
||||
import json
|
||||
import time
|
||||
from multiprocessing import Process, Queue
|
||||
from Fishtank import Fishtank
|
||||
|
||||
def socket_listener(port, recv_queue):
|
||||
sys.stdout.write("Socket listener starting...\n")
|
||||
context = zmq.Context()
|
||||
socket = context.socket(zmq.REP)
|
||||
socket.bind("tcp://*:{}".format(port))
|
||||
|
||||
while True:
|
||||
message = socket.recv()
|
||||
response = b"Undefined response"
|
||||
try:
|
||||
serial = json.loads(message)
|
||||
if "class" in serial:
|
||||
sys.stdout.write("Listener received a {}\n".format(serial["class"]))
|
||||
recv_queue.put(serial, False)
|
||||
response = b"Received"
|
||||
except:
|
||||
response = b"Error"
|
||||
socket.send(response)
|
||||
|
||||
def main():
|
||||
port = int(sys.argv[1])
|
||||
sys.stdout.write("Launching on port {}\n".format(port))
|
||||
# Spawn the socket thread
|
||||
q = Queue()
|
||||
socket_proc = Process(target=socket_listener, args=(port,q))
|
||||
socket_proc.start()
|
||||
sys.stdout.write("Socket thread started\n")
|
||||
time.sleep(1)
|
||||
# Build the world
|
||||
fishtank = Fishtank(q)
|
||||
for i in range(1, len(sys.argv)):
|
||||
if sys.argv[i] == "-w":
|
||||
from entity.dummy.DebugWaiter import DebugWaiter
|
||||
fishtank.add_entity(DebugWaiter("DebugWaiter"))
|
||||
if sys.argv[i] == "-j":
|
||||
from entity.dummy.DebugJumper import DebugJumper
|
||||
fishtank.add_entity(DebugJumper("DebugJumper"))
|
||||
if sys.argv[i] == "-t":
|
||||
pipe_port = int(sys.argv[i+1])
|
||||
from network.NetworkGate import NetworkGate
|
||||
network_gate = NetworkGate("localhost", pipe_port)
|
||||
from entity.Tube import Tube
|
||||
fishtank.add_entity(Tube(network_gate))
|
||||
fishtank.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
26
util/Util.py
Normal file
26
util/Util.py
Normal file
@ -0,0 +1,26 @@
|
||||
import datetime
|
||||
from os.path import join
|
||||
import sys
|
||||
import pygame
|
||||
|
||||
def logout(s, tag=""):
|
||||
sys.stdout.write("[{:%Y-%m-%d %H:%M:%S} {}] {}\n".format(datetime.datetime.now(), tag, s))
|
||||
|
||||
def logerr(s, tag=""):
|
||||
sys.stderr.write("[{:%Y-%m-%d %H:%M:%S} {}] {}\n".format(datetime.datetime.now(), tag, s))
|
||||
|
||||
def load_image(filename):
|
||||
path = join("assets", filename)
|
||||
try:
|
||||
image = pygame.image.load(path)
|
||||
except:
|
||||
logerr("ERROR: Image '{}' not found".format(filename), "load_image")
|
||||
sys.exit(-1)
|
||||
#try:
|
||||
if image.get_alpha() is None:
|
||||
image = image.convert()
|
||||
else:
|
||||
image = image.convert_alpha()
|
||||
#except:
|
||||
# logerr("ERROR: Image '{}' not converted".format(filename))
|
||||
return image
|
71
world/Fishtank.py
Normal file
71
world/Fishtank.py
Normal file
@ -0,0 +1,71 @@
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
import pygame
|
||||
from util.Util import logout, logerr
|
||||
|
||||
class Fishtank():
|
||||
def __init__(self, recv_queue):
|
||||
self.entities = []
|
||||
self.to_remove = []
|
||||
self.recv_queue = recv_queue
|
||||
|
||||
self.size = (480, 360)
|
||||
self.screen = pygame.display.set_mode(self.size)
|
||||
|
||||
def run(self):
|
||||
"""Begins the game loop. Does not return."""
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
while True:
|
||||
# Upkeep
|
||||
milli = clock.tick(60) / 1000
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
sys.exit(0)
|
||||
|
||||
# Delete flagged entities
|
||||
if self.to_remove:
|
||||
for entity in self.to_remove:
|
||||
self.entities.remove(entity)
|
||||
self.to_remove = []
|
||||
|
||||
# Update
|
||||
for entity in self.entities:
|
||||
entity.update(milli)
|
||||
|
||||
# Intake queue
|
||||
if not self.recv_queue.empty():
|
||||
serial = self.recv_queue.get(False)
|
||||
logout("Dequeued: {}".format(serial["class"]), "Fishtank")
|
||||
mod = __import__(serial["module"], fromlist=[serial["class"]])
|
||||
klass = getattr(mod, serial["class"])
|
||||
e = klass.deserialize(serial)
|
||||
self.add_entity(e)
|
||||
|
||||
# Draw
|
||||
self.screen.fill((100, 149, 237))
|
||||
for entity in sorted(self.entities, key=lambda e:e.z):
|
||||
entity.draw(self.screen)
|
||||
pygame.display.flip()
|
||||
|
||||
def add_entity(self, entity):
|
||||
"""
|
||||
Adds an entity to the entity list and sets its fishtank property to this.
|
||||
Input: entity, the entity to add
|
||||
"""
|
||||
entity.fishtank = self
|
||||
self.entities.append(entity)
|
||||
logout("Added: {}".format(repr(entity)), "Fishtank")
|
||||
|
||||
def remove_entity(self, entity):
|
||||
"""
|
||||
Marks an entity to be removed before the next update pass.
|
||||
Input: entity, the entity to remove
|
||||
"""
|
||||
if entity not in self.entities:
|
||||
logerr("WARN: remove called for entity '{}',"\
|
||||
"but it isn't in the entity list".format(entity.__name__), "Fishtank")
|
||||
return
|
||||
self.to_remove.append(entity)
|
21
world/NetworkGate.py
Normal file
21
world/NetworkGate.py
Normal file
@ -0,0 +1,21 @@
|
||||
import sys
|
||||
import zmq
|
||||
import json
|
||||
from util.Util import logout
|
||||
|
||||
class NetworkGate():
|
||||
def __init__(self, address, port):
|
||||
self.address = address
|
||||
self.port = port
|
||||
context = zmq.Context()
|
||||
self.socket = context.socket(zmq.REQ)
|
||||
self.socket.connect("tcp://{}:{}".format(address, port))
|
||||
|
||||
def __repr__(self):
|
||||
return "[NetworkGate {}:{}]".format(self.address, self.port)
|
||||
|
||||
def transmit(self, serial):
|
||||
s = json.dumps(serial)
|
||||
logout("Sending: {}".format(serial["class"]))
|
||||
self.socket.send_string(s)
|
||||
message = self.socket.recv()
|
54
world/Server.py
Normal file
54
world/Server.py
Normal file
@ -0,0 +1,54 @@
|
||||
import zmq
|
||||
import json
|
||||
import time
|
||||
from multiprocessing import Process, Queue
|
||||
from world.Fishtank import Fishtank
|
||||
from util.Util import logout
|
||||
|
||||
class Server(object):
|
||||
def __init__(self, recv_port):
|
||||
self.recv_port = recv_port
|
||||
self.recv_queue = Queue()
|
||||
self.recv_proc = Process(
|
||||
target=self.socket_listener,
|
||||
args=(self.recv_port, self.recv_queue))
|
||||
|
||||
def socket_listener(self, port, recv_queue):
|
||||
logout("Socket thread starting", "Server.socket_listener")
|
||||
context = zmq.Context()
|
||||
socket = context.socket(zmq.REP)
|
||||
socket.bind("tcp://*:{}".format(port))
|
||||
|
||||
while True:
|
||||
message = socket.recv()
|
||||
response = b"Undefined response"
|
||||
try:
|
||||
serial = json.loads(message)
|
||||
if "class" in serial:
|
||||
logout("Received: {}".format(serial["class"]), "Server.socket_listener")
|
||||
recv_queue.put(serial, False)
|
||||
response = b"Received"
|
||||
except:
|
||||
response = b"Error"
|
||||
socket.send(response)
|
||||
|
||||
def run(self, argv):
|
||||
# Launch the recv process
|
||||
self.recv_proc.start()
|
||||
logout("Socket thread launched", "Server")
|
||||
time.sleep(0.2)
|
||||
|
||||
# Build the world
|
||||
fishtank = Fishtank(self.recv_queue)
|
||||
|
||||
for i in range(len(argv)):
|
||||
if argv[i] == "-ball":
|
||||
from entity.dummy.DebugBall import DebugBall
|
||||
fishtank.add_entity(DebugBall())
|
||||
if argv[i] == "-tube":
|
||||
tube_port = int(argv[i+1])
|
||||
from world.NetworkGate import NetworkGate
|
||||
network_gate = NetworkGate("localhost", tube_port)
|
||||
from entity.Tube import Tube
|
||||
fishtank.add_entity(Tube(network_gate))
|
||||
fishtank.run()
|
0
world/__init__.py
Normal file
0
world/__init__.py
Normal file
Loading…
Reference in New Issue
Block a user