class Server (object): def __init__(self, port): self.port = port self.pending = {} self.players = {} self.last_pid = 0 self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.bind(('0.0.0.0', port)) self.socket.setblocking(0) self.world = World() @property def nextpid(self): self.last_pid += 1 return self.last_pid def tick(self, dt): # Read in any pending datagrams since last time. while True: try: data, address = self.socket.recvfrom(512) p = parse_packet(data) if address[0] in self.players: self.players[address[0]].handle(p) else: self.handle(p, address) except socket.error: break # Let all the Player objects handle writing out pending re-sends. for p in self.players.values(): p.tick(dt) # Update the world. self.world.tick(dt) # Send world updates. data = b'' updates = [] for obj in self.world.objects: if obj.moved: data += struct.pack('!L6d', obj.index, obj.position.x, obj.position.y, obj.position.z, obj.velocity.x, obj.velocity.y, obj.velocity.z) obj.moved = False if len(data) > 450: updates.append(Packet(KIND_WORLD_UPDATE, 0, payload=data)) data = b'' if data: updates.append(Packet(KIND_WORLD_UPDATE, 0, payload=data)) for p in updates: self.broadcast(p) def handle(self, packet, address): if packet.kind == KIND_PLAYER_JOIN: print('PLAYER JOIN FROM', address) p = Player(self, address, self.nextpid) self.players[address[0]] = p def broadcast(self, packet): for p in self.players.values(): p.write(packet)
def __init__(self, root, camera, audio3d=None): self.name = root['name'] or 'Untitled Map' self.author = root['author'] or 'Unknown Author' self.tagline = root['tagline'] self.description = root['description'] or 'No description.' self.preview_cam = (parse_vector(root['preview_cam_pos'], (0, 20, 40)), parse_vector(root['preview_cam_hp'], (0, 0))) self.world = World(camera, debug=parse_bool(root['debug']), audio3d=audio3d) self.process_children(root) if not self.has_celestials: self.world.add_celestial(math.radians(20), math.radians(45), (1, 1, 1, 1), 0.4, 30.0, False) self.world.add_celestial(math.radians(200), math.radians(20), (1, 1, 1, 1), 0.3, 30.0, False) self.world.create_celestial_node()
def __init__(self, port): self.port = port self.pending = {} self.players = {} self.last_pid = 0 self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.socket.bind(('0.0.0.0', port)) self.socket.setblocking(0) self.world = World()
def __init__(self, root, camera, audio3d=None): self.name = root['name'] or 'Untitled Map' self.author = root['author'] or 'Unknown Author' self.tagline = root['tagline'] self.description = root['description'] or 'No description.' self.preview_cam = (parse_vector(root['preview_cam_pos'], (0,20,40)), parse_vector(root['preview_cam_hp'], (0,0))) self.world = World(camera, debug=parse_bool(root['debug']), audio3d=audio3d) self.process_children(root) if not self.has_celestials: self.world.add_celestial(math.radians(20), math.radians(45), (1, 1, 1, 1), 0.4, 30.0, False) self.world.add_celestial(math.radians(200), math.radians(20), (1, 1, 1, 1), 0.3, 30.0, False) self.world.create_celestial_node()
class Map(object): """ Includes meta-information about a map, along with a World object containing all the objects. """ name = None author = None tagline = None description = None world = None has_celestials = False effects = [] def __init__(self, root, camera, audio3d=None): self.name = root['name'] or 'Untitled Map' self.author = root['author'] or 'Unknown Author' self.tagline = root['tagline'] self.description = root['description'] or 'No description.' self.preview_cam = (parse_vector(root['preview_cam_pos'], (0, 20, 40)), parse_vector(root['preview_cam_hp'], (0, 0))) self.world = World(camera, debug=parse_bool(root['debug']), audio3d=audio3d) self.process_children(root) if not self.has_celestials: self.world.add_celestial(math.radians(20), math.radians(45), (1, 1, 1, 1), 0.4, 30.0, False) self.world.add_celestial(math.radians(200), math.radians(20), (1, 1, 1, 1), 0.3, 30.0, False) self.world.create_celestial_node() def show(self, render): """ Reparents the root NodePath of this Map's World to the given NodePath. """ self.world.render.setColorOff() self.world.render.node().setAttrib(ColorAttrib.makeVertex()) self.world.render.reparent_to(render) def remove(self, render): self.world.sky.detach() self.world.render.detach_node() self.world.render.remove_node() def process_children(self, node): for child in node.children(): func_name = 'parse_%s' % child.tagname.lower() if hasattr(self, func_name): getattr(self, func_name)(child) def parse_static(self, node): world = self.world self.world = self.wrap_object(CompositeObject()) self.process_children(node) world.attach(self.world) self.world = world def parse_transparent(self, node): alpha = parse_float(node['alpha']) self.effects.append(lambda effected: Transparent(effected, alpha)) self.process_children(node) self.effects.pop() def parse_freesolid(self, node): mass = parse_float(node['mass']) self.effects.append(lambda effected: FreeSolid(effected, mass)) self.process_children(node) self.effects.pop() def parse_mortal(self, node): hp = parse_float(node['hp']) self.effects.append(lambda effected: Mortal(effected, hp)) self.process_children(node) self.effects.pop() def parse_hologram(self, node): self.effects.append(Hologram) self.process_children(node) self.effects.pop() def parse_hostile(self, node): self.effects.append(Hostile) self.process_children(node) self.effects.pop() def wrap_object(self, obj): for effect in reversed(self.effects): obj = effect(obj) return obj def parse_incarnator(self, node): pos = parse_vector(node['location']) heading = parse_float(node['heading']) incarn = self.world.attach( self.wrap_object(Incarnator(pos, heading, name=node['id']))) def parse_block(self, node): center = parse_vector(node['center']) size = parse_vector(node['size'], (4, 4, 4)) color = parse_color(node['color'], (1, 1, 1, 1)) mass = parse_float(node['mass']) yaw = parse_float(node['yaw']) pitch = parse_float(node['pitch']) roll = parse_float(node['roll']) block = self.world.attach( self.wrap_object( Block(size, color, mass, center, (yaw, pitch, roll), name=node['id']))) def parse_ramp(self, node): base = parse_vector(node['base']) top = parse_vector(node['top'], (0, 4, 4)) thickness = parse_float(node['thickness']) width = parse_float(node['width'], 8) color = parse_color(node['color'], (1, 1, 1, 1)) mass = parse_float(node['mass']) yaw = parse_float(node['yaw']) pitch = parse_float(node['pitch']) roll = parse_float(node['roll']) ramp = self.world.attach( self.wrap_object( Ramp(base, top, width, thickness, color, mass, (yaw, pitch, roll), name=node['id']))) def parse_wedge(self, node): base = parse_vector(node['base']) top = parse_vector(node['top'], (0, 4, 4)) width = parse_float(node['width'], 8) color = parse_color(node['color'], (1, 1, 1, 1)) mass = parse_float(node['mass']) yaw = parse_float(node['yaw']) pitch = parse_float(node['pitch']) roll = parse_float(node['roll']) wedge = self.world.attach( self.wrap_object( Wedge(base, top, width, color, mass, (yaw, pitch, roll), name=node['id']))) def parse_blockramp(self, node): base = parse_vector(node['base']) top = parse_vector(node['top'], (0, 4, 4)) thickness = parse_float(node['thickness']) width = parse_float(node['width'], 8) color = parse_color(node['color'], (1, 1, 1, 1)) mass = parse_float(node['mass']) yaw = parse_float(node['yaw']) pitch = parse_float(node['pitch']) roll = parse_float(node['roll']) ramp = self.world.attach( self.wrap_object( BlockRamp(base, top, width, thickness, color, mass, (yaw, pitch, roll), name=node['id']))) def parse_ground(self, node): color = parse_color(node['color'], (1, 1, 1, 1)) radius = parse_float(node['radius'], 1000) self.world.attach( self.wrap_object( Ground(radius, color, name=(node['id'] or 'ground')))) def parse_goody(self, node): model = node["model"] pos = parse_vector(node["location"]) grenades = parse_int(node["grenades"]) missles = parse_int(node["missles"]) boosters = parse_int(node["boosters"]) respawn = parse_float(node["respawn"], 8.0) # Default spawn time. spin = parse_vector(node['spin']) goody = self.world.attach( self.wrap_object( Goody(pos, model, (grenades, missles, boosters), respawn, spin))) def parse_dome(self, node): center = parse_vector(node['center']) radius = parse_float(node['radius'], 2.5) samples = parse_int(node['samples'], 8) planes = parse_int(node['planes'], 5) color = parse_color(node['color'], (1, 1, 1, 1)) mass = parse_float(node['mass']) yaw = parse_float(node['yaw']) pitch = parse_float(node['pitch']) roll = parse_float(node['roll']) dome = self.world.attach( self.wrap_object( Dome(radius, samples, planes, color, mass, center, (yaw, pitch, roll), name=node['id']))) def parse_sky(self, node): color = parse_color(node['color'], DEFAULT_SKY_COLOR) horizon = parse_color(node['horizon'], DEFAULT_HORIZON_COLOR) ambient = parse_color(node['ambient'], DEFAULT_AMBIENT_COLOR) scale = parse_float(node['horizonScale'], DEFAULT_HORIZON_SCALE) self.world.set_ambient(ambient) self.world.sky.set_color(color) self.world.sky.set_horizon(horizon) self.world.sky.set_scale(scale) for child in node.children('celestial'): azimuth = math.radians(parse_float(child['azimuth'], 30)) elevation = math.radians(parse_float(child['elevation'], 20)) color = parse_color(child['color'], (1, 1, 1, 1)) intensity = parse_float(child['intensity'], 0.6) visible = parse_bool(child['visible']) size = parse_float(child['size'], 30.0) self.world.add_celestial(azimuth, elevation, color, intensity, size, visible) self.has_celestials = True for child in node.children('starfield'): seed = parse_int(child['seed']) count = parse_int(child['count']) min_color = parse_color(child['minColor'], (1, 1, 1, 1)) max_color = parse_color(child['maxColor'], (1, 1, 1, 1)) min_size = parse_float(child['minSize'], 0.4) max_size = parse_float(child['maxSize'], 1.0) mode = child['mode'] or 'default' mode = mode.strip().lower() min_r = min_color[0] delta_r = max_color[0] - min_r min_g = min_color[1] delta_g = max_color[1] - min_g min_b = min_color[2] delta_b = max_color[2] - min_b delta_size = max_size - min_size two_pi = math.pi * 2 half_pi = math.pi / 2 if seed: random.seed(seed) for s in range(count): theta = two_pi * random.random() phi = abs(half_pi - math.acos(random.random())) if mode == 'realistic': star_type = random.randint(0, 2) if star_type == 0: # white star r = g = b = 1 elif star_type == 1: # orange/yellow r = 1 g = 0.5 + random.random() * 0.5 b = g / 2 elif star_type == 2: # blue b = 1 g = b * (1 - random.random() * 0.30) r = g * (1 - random.random() * 0.30) elif mode == 'monochrome': dice = random.random() r = min_r + dice * delta_r g = min_g + dice * delta_g b = min_b + dice * delta_b else: r = min_r + random.random() * delta_r g = min_g + random.random() * delta_g b = min_b + random.random() * delta_b color = (r, g, b, 1 - (1 - phi / math.pi)**6) size = min_size + random.random() * delta_size self.world.add_celestial(theta, phi, color, 0, size, True) # Reset the seed. random.seed()
class Map (object): """ Includes meta-information about a map, along with a World object containing all the objects. """ name = None author = None tagline = None description = None world = None has_celestials = False effects = [] def __init__(self, root, camera, audio3d=None): self.name = root['name'] or 'Untitled Map' self.author = root['author'] or 'Unknown Author' self.tagline = root['tagline'] self.description = root['description'] or 'No description.' self.preview_cam = (parse_vector(root['preview_cam_pos'], (0,20,40)), parse_vector(root['preview_cam_hp'], (0,0))) self.world = World(camera, debug=parse_bool(root['debug']), audio3d=audio3d) self.process_children(root) if not self.has_celestials: self.world.add_celestial(math.radians(20), math.radians(45), (1, 1, 1, 1), 0.4, 30.0, False) self.world.add_celestial(math.radians(200), math.radians(20), (1, 1, 1, 1), 0.3, 30.0, False) self.world.create_celestial_node() def show(self, render): """ Reparents the root NodePath of this Map's World to the given NodePath. """ self.world.render.setColorOff() self.world.render.node().setAttrib(ColorAttrib.makeVertex()) self.world.render.reparent_to(render) def remove(self, render): self.world.sky.detach() self.world.render.detach_node() self.world.render.remove_node() def process_children(self, node): for child in node.children(): func_name = 'parse_%s' % child.tagname.lower() if hasattr(self, func_name): getattr(self, func_name)(child) def parse_static(self, node): world = self.world self.world = self.wrap_object(CompositeObject()) self.process_children(node) world.attach(self.world) self.world = world def parse_transparent(self, node): alpha = parse_float(node['alpha']) self.effects.append(lambda effected: Transparent(effected, alpha)) self.process_children(node) self.effects.pop() def parse_freesolid(self, node): mass = parse_float(node['mass']) self.effects.append(lambda effected: FreeSolid(effected, mass)) self.process_children(node) self.effects.pop() def parse_mortal(self, node): hp = parse_float(node['hp']) self.effects.append(lambda effected: Mortal(effected, hp)) self.process_children(node) self.effects.pop() def parse_hologram(self, node): self.effects.append(Hologram) self.process_children(node) self.effects.pop() def parse_hostile(self, node): self.effects.append(Hostile) self.process_children(node) self.effects.pop() def wrap_object(self, obj): for effect in reversed(self.effects): obj = effect(obj) return obj def parse_incarnator(self, node): pos = parse_vector(node['location']) heading = parse_float(node['heading']) incarn = self.world.attach(self.wrap_object(Incarnator(pos, heading, name=node['id']))) def parse_block(self, node): center = parse_vector(node['center']) size = parse_vector(node['size'], (4, 4, 4)) color = parse_color(node['color'], (1, 1, 1, 1)) mass = parse_float(node['mass']) yaw = parse_float(node['yaw']) pitch = parse_float(node['pitch']) roll = parse_float(node['roll']) block = self.world.attach(self.wrap_object(Block(size, color, mass, center, (yaw, pitch, roll), name=node['id']))) def parse_ramp(self, node): base = parse_vector(node['base']) top = parse_vector(node['top'], (0, 4, 4)) thickness = parse_float(node['thickness']) width = parse_float(node['width'], 8) color = parse_color(node['color'], (1, 1, 1, 1)) mass = parse_float(node['mass']) yaw = parse_float(node['yaw']) pitch = parse_float(node['pitch']) roll = parse_float(node['roll']) ramp = self.world.attach(self.wrap_object(Ramp(base, top, width, thickness, color, mass, (yaw, pitch, roll), name=node['id']))) def parse_wedge(self, node): base = parse_vector(node['base']) top = parse_vector(node['top'], (0, 4, 4)) width = parse_float(node['width'], 8) color = parse_color(node['color'], (1, 1, 1, 1)) mass = parse_float(node['mass']) yaw = parse_float(node['yaw']) pitch = parse_float(node['pitch']) roll = parse_float(node['roll']) wedge = self.world.attach(self.wrap_object(Wedge(base, top, width, color, mass, (yaw, pitch, roll), name=node['id']))) def parse_blockramp(self, node): base = parse_vector(node['base']) top = parse_vector(node['top'], (0, 4, 4)) thickness = parse_float(node['thickness']) width = parse_float(node['width'], 8) color = parse_color(node['color'], (1, 1, 1, 1)) mass = parse_float(node['mass']) yaw = parse_float(node['yaw']) pitch = parse_float(node['pitch']) roll = parse_float(node['roll']) ramp = self.world.attach(self.wrap_object(BlockRamp(base, top, width, thickness, color, mass, (yaw, pitch, roll), name=node['id']))) def parse_ground(self, node): color = parse_color(node['color'], (1, 1, 1, 1)) radius = parse_float(node['radius'], 1000) self.world.attach(self.wrap_object(Ground(radius, color, name=(node['id'] or 'ground')))) def parse_goody(self, node): model = node["model"] pos = parse_vector(node["location"]) grenades = parse_int(node["grenades"]) missles = parse_int(node["missles"]) boosters = parse_int(node["boosters"]) respawn = parse_float(node["respawn"], 8.0) # Default spawn time. spin = parse_vector(node['spin']) goody = self.world.attach(self.wrap_object(Goody(pos, model, (grenades, missles, boosters), respawn, spin))) def parse_dome(self, node): center = parse_vector(node['center']) radius = parse_float(node['radius'], 2.5) samples = parse_int(node['samples'], 8) planes = parse_int(node['planes'], 5) color = parse_color(node['color'], (1, 1, 1, 1)) mass = parse_float(node['mass']) yaw = parse_float(node['yaw']) pitch = parse_float(node['pitch']) roll = parse_float(node['roll']) dome = self.world.attach(self.wrap_object(Dome(radius, samples, planes, color, mass, center, (yaw, pitch, roll), name=node['id']))) def parse_sky(self, node): color = parse_color(node['color'], DEFAULT_SKY_COLOR) horizon = parse_color(node['horizon'], DEFAULT_HORIZON_COLOR) ambient = parse_color(node['ambient'], DEFAULT_AMBIENT_COLOR) scale = parse_float(node['horizonScale'], DEFAULT_HORIZON_SCALE) self.world.set_ambient(ambient) self.world.sky.set_color(color) self.world.sky.set_horizon(horizon) self.world.sky.set_scale(scale) for child in node.children('celestial'): azimuth = math.radians(parse_float(child['azimuth'], 30)) elevation = math.radians(parse_float(child['elevation'], 20)) color = parse_color(child['color'], (1, 1, 1, 1)) intensity = parse_float(child['intensity'], 0.6) visible = parse_bool(child['visible']) size = parse_float(child['size'], 30.0) self.world.add_celestial(azimuth, elevation, color, intensity, size, visible) self.has_celestials = True for child in node.children('starfield'): seed = parse_int(child['seed']) count = parse_int(child['count']) min_color = parse_color(child['minColor'], (1, 1, 1, 1)) max_color = parse_color(child['maxColor'], (1, 1, 1, 1)) min_size = parse_float(child['minSize'], 0.4) max_size = parse_float(child['maxSize'], 1.0) mode = child['mode'] or 'default' mode = mode.strip().lower() min_r = min_color[0] delta_r = max_color[0] - min_r min_g = min_color[1] delta_g = max_color[1] - min_g min_b = min_color[2] delta_b = max_color[2] - min_b delta_size = max_size - min_size two_pi = math.pi * 2 half_pi = math.pi / 2 if seed: random.seed(seed) for s in range(count): theta = two_pi * random.random() phi = abs(half_pi - math.acos(random.random())) if mode == 'realistic': star_type = random.randint(0,2) if star_type == 0: # white star r = g = b = 1 elif star_type == 1: # orange/yellow r = 1 g = 0.5 + random.random() * 0.5 b = g / 2 elif star_type == 2: # blue b = 1 g = b * (1 - random.random() * 0.30) r = g * (1 - random.random() * 0.30) elif mode == 'monochrome': dice = random.random() r = min_r + dice * delta_r g = min_g + dice * delta_g b = min_b + dice * delta_b else: r = min_r + random.random() * delta_r g = min_g + random.random() * delta_g b = min_b + random.random() * delta_b color = (r, g, b, 1 - (1 - phi/math.pi)**6) size = min_size + random.random() * delta_size self.world.add_celestial(theta, phi, color, 0, size, True) # Reset the seed. random.seed()