def __init__(self, server): self.server = server self.client_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_handler = PacketHandler(SC_PACKETS, self.on_server_packet) self.relay_packets = [] self.print_stats()
def __init__(self, loop): self.loop = loop self.start_time = self.loop.time() self.client_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_handler = PacketHandler(SC_PACKETS, self.on_server_packet) self.entities = {} self.relay_packets = [] self.print_stats() self.times = []
def __init__(self, server): self.server = server self.start_time = reactor.seconds() self.client_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_handler = PacketHandler(SC_PACKETS, self.on_server_packet) self.entities = {} self.relay_packets = [] self.print_stats() self.times = []
def __init__(self, server): self.server = server self.start_time = reactor.seconds() self.client_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_handler = PacketHandler(SC_PACKETS, self.on_server_packet) self.entities = {} self.relay_packets = [] self.print_stats()
def connectionMade(self): if self.connection_state != 0: self.disconnect('Unexpected data') return self.connection_state = 1 server = self.server if len(server.connections) >= server.config.base.max_players: # For being able to allow joining by external scritps although server is full ret = self.scripts.call('on_join_full_server').result if ret is not True: self.send_packet(server_full_packet) self.disconnect() self.connection_state = -1 print '[INFO] %s tried to join full server' % self.address.host return self.packet_handlers = { ClientVersion.packet_id: self.on_version_packet, EntityUpdate.packet_id: self.on_entity_packet, ClientChatMessage.packet_id: self.on_chat_packet, InteractPacket.packet_id: self.on_interact_packet, HitPacket.packet_id: self.on_hit_packet, ShootPacket.packet_id: self.on_shoot_packet } self.packet_handler = PacketHandler(CS_PACKETS, self.on_packet) server.connections.add(self) self.rights = AttributeSet() self.scripts = ScriptManager() server.scripts.call('on_new_connection', connection=self)
def connectionMade(self): self.transport.setTcpNoDelay(True) server = self.server self.client_packet_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_packet_handler = PacketHandler(SC_PACKETS, self.on_server_packet) server.connections.add(self) self.rights = AttributeSet() self.scripts = ScriptManager() server.scripts.call('on_new_connection', connection=self) point = TCP4ClientEndpoint(reactor, self.server.config.base.mitm_ip, self.server.config.base.mitm_port) d = point.connect(RelayFactory(self)) d.addCallback(self.got_relay_client)
def connectionMade(self): self.packet_handlers = { ClientVersion.packet_id : self.on_version_packet, EntityUpdate.packet_id : self.on_entity_packet, ClientChatMessage.packet_id : self.on_chat_packet, InteractPacket.packet_id : self.on_interact_packet, HitPacket.packet_id : self.on_hit_packet } self.scripts = [] self.factory.call_scripts('on_new_connection', self) self.packet_handler = PacketHandler(CS_PACKETS, self.on_packet) self.rights = AttributeSet()
def connectionMade(self): server = self.server if len(server.connections) >= server.config.base.max_players: self.send_packet(server_full_packet) self.disconnect() return self.packet_handlers = { ClientVersion.packet_id: self.on_version_packet, EntityUpdate.packet_id: self.on_entity_packet, ClientChatMessage.packet_id: self.on_chat_packet, InteractPacket.packet_id: self.on_interact_packet, HitPacket.packet_id: self.on_hit_packet, ShootPacket.packet_id: self.on_shoot_packet } self.packet_handler = PacketHandler(CS_PACKETS, self.on_packet) server.connections.add(self) self.rights = AttributeSet() self.scripts = ScriptManager() server.scripts.call('on_new_connection', connection=self)
def connectionMade(self): server = self.server if len(server.connections) >= server.config.base.max_players: self.send_packet(server_full_packet) self.disconnect() return self.packet_handlers = { ClientVersion.packet_id: self.on_version_packet, EntityUpdate.packet_id: self.on_entity_packet, ClientChatMessage.packet_id: self.on_chat_packet, InteractPacket.packet_id: self.on_interact_packet, HitPacket.packet_id: self.on_hit_packet, ShootPacket.packet_id: self.on_shoot_packet } server.connections.add(self) self.scripts = [] self.server.call_scripts('on_new_connection', self) self.packet_handler = PacketHandler(CS_PACKETS, self.on_packet) self.rights = AttributeSet()
class FrontendProtocol(asyncio.Protocol): relay_client = None relay_packets = None entity_id = None disconnected = False update_index = 0 def __init__(self, loop): self.loop = loop self.start_time = self.loop.time() self.client_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_handler = PacketHandler(SC_PACKETS, self.on_server_packet) self.entities = {} self.relay_packets = [] self.print_stats() self.times = [] def print_stats(self): if self.disconnected: return self.loop.call_later(15, self.print_stats) if self.entity_id is None: return entity = self.entities[self.entity_id] print('Info:') print('Pos:', entity.pos.x, entity.pos.y, entity.pos.z) def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.transport.write(write_packet(packet)) def send_client_chat(self, value): packet = ClientChatMessage() packet.value = value self.relay_client.transport.write(write_packet(packet)) def on_entity_update(self, packet): if packet.entity_id not in self.entities: entity = entitydata.EntityData() self.entities[packet.entity_id] = entity print('Created new entity:', packet.entity_id) else: entity = self.entities[packet.entity_id] packet.update_entity(entity) def on_server_update(self, packet): pass # for static_entity in packet.static_entities: # print(vars(static_entity.header)) def on_client_packet(self, packet): if packet.packet_id == EntityUpdate.packet_id: self.on_entity_update(packet) if self.relay_client is None: self.relay_packets.append(write_packet(packet)) return if packet.packet_id == InteractPacket.packet_id: print(vars(packet)) self.relay_client.transport.write(write_packet(packet)) if packet.packet_id not in (0, ): print('Got client packet:', packet.packet_id) def on_server_packet(self, packet): if packet.packet_id == EntityUpdate.packet_id: self.on_entity_update(packet) elif packet.packet_id == JoinPacket.packet_id: self.entity_id = packet.entity_id elif packet.packet_id == CurrentTime.packet_id: # I hate darkness packet.time = constants.MAX_TIME / 2 elif packet.packet_id == ServerUpdate.packet_id: self.on_server_update(packet) self.transport.write(write_packet(packet)) if packet.packet_id not in (EntityUpdate.packet_id, UpdateFinished.packet_id, CurrentTime.packet_id, ServerUpdate.packet_id): print('Got server packet:', packet.packet_id) def got_relay_client(self): for data in self.relay_packets: self.relay_client.transport.write(data) self.relay_packets = None def connection_made(self, transport): self.transport = transport print('On connection') co = self.loop.create_connection(lambda: BackendProtocol(self), '127.0.0.1', 12346) self.loop.create_task(co) def connection_lost(self, reason): self.disconnected = True print('Lost connection') if self.relay_client is not None: self.relay_client.transport.close() def server_data_received(self, data): # self.transport.write(data) self.server_handler.feed(data) def data_received(self, data): # if self.relay_client is None: # self.relay_packets.append(data) # return # self.relay_client.transport.write(data) self.client_handler.feed(data)
class CubeWorldProtocol(Protocol): has_joined = False entity_id = None entity_data = None disconnected = False def __init__(self, factory): self.factory = factory def send_packet(self, packet): self.transport.write(write_packet(packet)) def on_packet(self, packet): packet_id = packet.packet_id if packet_id == ClientVersion.packet_id: if packet.version != constants.CLIENT_VERSION: self.disconnect() return self.entity_id = self.factory.entity_ids.pop() self.entity_data = create_entity_data() self.factory.entities[self.entity_id] = self.entity_data self.factory.connections[(self.entity_id,)] = self server_data.entity_id = self.entity_id self.send_packet(server_data) seed_data.seed = self.factory.config.seed self.send_packet(seed_data) elif packet_id == EntityUpdate.packet_id: if packet.entity_id != self.entity_id: raise NotImplementedError() packet.update_entity(self.entity_data) if not self.has_joined and self.entity_data.name: self.on_join() self.has_joined = True self.factory.broadcast_packet(packet) elif packet_id == ClientChatMessage.packet_id: message = packet.value if self.on_chat(message) is False: return chat_message.entity_id = self.entity_id chat_message.value = message self.factory.broadcast_packet(chat_message) else: print 'Got client packet:', packet.packet_id def on_join(self): print 'Player %r joined' % self.entity_data.name for connection in self.factory.connections.values(): if not connection.has_joined: continue entity_update.set_entity(connection.entity_data, connection.entity_id) self.send_packet(entity_update) self.call_scripts('on_join') def on_command(self, command, parameters): self.call_scripts('on_command', command, parameters) def on_chat(self, message): if message.startswith('/'): try: splitted = shlex.split(message[1:]) except ValueError: # shlex failed. let's just split per space splitted = value.split(' ') if splitted: command = splitted.pop(0) else: command = '' self.on_command(command, splitted) return False return self.call_scripts('on_chat', message) def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.send_packet(packet) def send_lines(self, lines): current_time = 0 for line in lines: reactor.callLater(current_time, self.send_chat, line) current_time += 2 def disconnect(self): self.transport.loseConnection() self.connectionLost('Kicked by server') def connectionMade(self): self.scripts = [] self.factory.call_scripts('on_new_connection', self) self.packet_handler = PacketHandler(CS_PACKETS, self.on_packet) self.rights = AttributeSet() def connectionLost(self, reason): if self.disconnected: return self.disconnected = True try: del self.factory.connections[self] except KeyError: pass if self.entity_data is not None: del self.factory.entities[self.entity_id] self.call_scripts('on_disconnect') def kick(self): self.send_chat('You have been kicked') self.disconnect() self.factory.send_chat('%s has been kicked' % self.get_name()) def dataReceived(self, data): self.packet_handler.feed(data) def call_scripts(self, name, *arg, **kw): for script in self.scripts: if call_handler(script, name, *arg, **kw) is False: return False return True def get_name(self): if self.entity_data is None: return None return self.entity_data.name
def connectionMade(self): self.scripts = [] self.factory.call_scripts('on_new_connection', self) self.packet_handler = PacketHandler(CS_PACKETS, self.on_packet) self.rights = AttributeSet()
class FrontendProtocol(asyncio.Protocol): relay_client = None relay_packets = None entity_id = None disconnected = False update_index = 0 def __init__(self, loop): self.loop = loop self.start_time = self.loop.time() self.client_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_handler = PacketHandler(SC_PACKETS, self.on_server_packet) self.entities = {} self.relay_packets = [] self.print_stats() self.times = [] def print_stats(self): if self.disconnected: return self.loop.call_later(15, self.print_stats) if self.entity_id is None: return entity = self.entities[self.entity_id] print('Info:') print('Pos:', entity.pos.x, entity.pos.y, entity.pos.z) def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.transport.write(write_packet(packet)) def send_client_chat(self, value): packet = ClientChatMessage() packet.value = value self.relay_client.transport.write(write_packet(packet)) def on_entity_update(self, packet): return if packet.entity_id not in self.entities: entity = entitydata.EntityData() self.entities[packet.entity_id] = entity print('Created new entity:', packet.entity_id) else: entity = self.entities[packet.entity_id] packet.update_entity(entity) def on_server_update(self, packet): if packet.items_8: print(packet.items_8) if packet.missions: print(packet.missions) packet.missions = [] # for static_entity in packet.static_entities: # print(vars(static_entity.header)) def on_client_packet(self, packet): if packet.packet_id == EntityUpdate.packet_id: self.on_entity_update(packet) if self.relay_client is None: self.relay_packets.append(write_packet(packet)) return if packet.packet_id == InteractPacket.packet_id: print(vars(packet)) self.relay_client.transport.write(write_packet(packet)) if packet.packet_id not in (0,): print('Got client packet:', packet.packet_id) def on_server_packet(self, packet): if packet.packet_id == EntityUpdate.packet_id: self.on_entity_update(packet) elif packet.packet_id == JoinPacket.packet_id: self.entity_id = packet.entity_id elif packet.packet_id == CurrentTime.packet_id: # I hate darkness packet.time = constants.MAX_TIME / 2 elif packet.packet_id == ServerUpdate.packet_id: self.on_server_update(packet) self.transport.write(write_packet(packet)) if packet.packet_id not in (EntityUpdate.packet_id, UpdateFinished.packet_id, CurrentTime.packet_id, ServerUpdate.packet_id): print('Got server packet:', packet.packet_id) def got_relay_client(self): for data in self.relay_packets: self.relay_client.transport.write(data) self.relay_packets = None def connection_made(self, transport): self.transport = transport print('On connection') co = self.loop.create_connection(lambda: BackendProtocol(self), '127.0.0.1', 12346) self.loop.create_task(co) def connection_lost(self, reason): self.disconnected = True print('Lost connection') if self.relay_client is not None: self.relay_client.transport.close() def server_data_received(self, data): # self.transport.write(data) self.server_handler.feed(data) def data_received(self, data): # if self.relay_client is None: # self.relay_packets.append(data) # return # self.relay_client.transport.write(data) self.client_handler.feed(data)
class CubeWorldConnection(Protocol): """ Protocol used for players """ has_joined = False entity_id = None entity_data = None disconnected = False scripts = None def __init__(self, server, addr): self.address = addr self.server = server # connection methods def connectionMade(self): server = self.server if len(server.connections) >= server.config.base.max_players: self.send_packet(server_full_packet) self.disconnect() return self.packet_handlers = { ClientVersion.packet_id: self.on_version_packet, EntityUpdate.packet_id: self.on_entity_packet, ClientChatMessage.packet_id: self.on_chat_packet, InteractPacket.packet_id: self.on_interact_packet, HitPacket.packet_id: self.on_hit_packet, ShootPacket.packet_id: self.on_shoot_packet } self.packet_handler = PacketHandler(CS_PACKETS, self.on_packet) server.connections.add(self) self.rights = AttributeSet() self.scripts = ScriptManager() server.scripts.call('on_new_connection', connection=self) def dataReceived(self, data): self.packet_handler.feed(data) def disconnect(self, reason=None): self.transport.loseConnection() self.connectionLost(reason) def connectionLost(self, reason): if self.disconnected: return self.disconnected = True self.server.connections.discard(self) if self.has_joined: del self.server.players[self] print 'Player %s left' % self.name if self.entity_data is not None: del self.server.entities[self.entity_id] if self.entity_id is not None: self.server.entity_ids.put_back(self.entity_id) if self.scripts is not None: self.scripts.unload() # packet methods def send_packet(self, packet): self.transport.write(write_packet(packet)) def on_packet(self, packet): if self.disconnected: return if packet is None: print 'Invalid packet received' self.disconnect() raise StopIteration() handler = self.packet_handlers.get(packet.packet_id, None) if handler is None: # print 'Unhandled client packet: %s' % packet.packet_id return handler(packet) def on_version_packet(self, packet): if packet.version != constants.CLIENT_VERSION: mismatch_packet.version = constants.CLIENT_VERSION self.send_packet(mismatch_packet) self.disconnect() return server = self.server self.entity_id = server.entity_ids.pop() join_packet.entity_id = self.entity_id self.send_packet(join_packet) seed_packet.seed = server.config.base.seed self.send_packet(seed_packet) def on_entity_packet(self, packet): if self.entity_data is None: self.entity_data = create_entity_data() self.server.entities[self.entity_id] = self.entity_data mask = packet.update_entity(self.entity_data) self.entity_data.mask |= mask if not self.has_joined and getattr(self.entity_data, 'name', None): self.on_join() return self.scripts.call('on_entity_update', mask=mask) # XXX clean this up if entity.is_pos_set(mask): self.scripts.call('on_pos_update') if entity.is_mode_set(mask): self.scripts.call('on_mode_update') if entity.is_class_set(mask): self.scripts.call('on_class_update') if entity.is_name_set(mask): self.scripts.call('on_name_update') if entity.is_multiplier_set(mask): self.scripts.call('on_multiplier_update') if entity.is_level_set(mask): self.scripts.call('on_level_update') if entity.is_equipment_set(mask): self.scripts.call('on_equipment_update') if entity.is_skill_set(mask): self.scripts.call('on_skill_update') if entity.is_appearance_set(mask): self.scripts.call('on_appearance_update') if entity.is_charged_mp_set(mask): self.scripts.call('on_charged_mp_update') if entity.is_flags_set(mask): self.scripts.call('on_flags_update') if entity.is_consumable_set(mask): self.scripts.call('on_consumable_update') def on_chat_packet(self, packet): message = filter_string(packet.value).strip() if not message: return message = self.on_chat(message) if not message: return chat_packet.entity_id = self.entity_id chat_packet.value = message self.server.broadcast_packet(chat_packet) print '%s: %s' % (self.name, message) def on_interact_packet(self, packet): interact_type = packet.interact_type item = packet.item_data if interact_type == INTERACT_DROP: pos = self.position.copy() pos.z -= constants.BLOCK_SCALE if self.scripts.call('on_drop', item=item, pos=pos).result is False: return self.server.drop_item(packet.item_data, pos) elif interact_type == INTERACT_PICKUP: chunk = (packet.chunk_x, packet.chunk_y) try: item = self.server.remove_item(chunk, packet.item_index) except IndexError: return self.give_item(item) def on_hit_packet(self, packet): try: target = self.server.entities[packet.target_id] except KeyError: return if self.scripts.call('on_hit', target=target, packet=packet).result is False: return self.server.update_packet.player_hits.append(packet) if target.hp <= 0: return target.hp -= packet.damage if target.hp <= 0: self.scripts.call('on_kill', target=target) def on_shoot_packet(self, packet): self.server.update_packet.shoot_actions.append(packet) # handlers def on_join(self): if self.scripts.call('on_join').result is False: return print 'Player %s joined' % self.name for player in self.server.players.values(): entity_packet.set_entity(player.entity_data, player.entity_id) self.send_packet(entity_packet) self.server.players[(self.entity_id, )] = self self.has_joined = True def on_command(self, command, parameters): self.scripts.call('on_command', command=command, args=parameters) def on_chat(self, message): if message.startswith('/'): command, args = parse_command(message[1:]) self.on_command(command, args) return event = self.scripts.call('on_chat', message=message) if event.result is False: return return event.message # other methods def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.send_packet(packet) def give_item(self, item): action = PickupAction() action.entity_id = self.entity_id action.item_data = item self.server.update_packet.pickups.append(action) def send_lines(self, lines): current_time = 0 for line in lines: reactor.callLater(current_time, self.send_chat, line) current_time += 2 def kick(self): self.send_chat('You have been kicked') self.disconnect() self.server.send_chat('%s has been kicked' % self.name) # convienience methods @property def position(self): if self.entity_data is None: return None return self.entity_data.pos @property def name(self): if self.entity_data is None: return None return self.entity_data.name
class CubeWorldConnection(Protocol): """ Protocol used for players """ has_joined = False entity_id = None entity_data = None disconnected = False def __init__(self, server, addr): self.address = addr self.server = server # connection methods def connectionMade(self): self.packet_handlers = { ClientVersion.packet_id: self.on_version_packet, EntityUpdate.packet_id: self.on_entity_packet, ClientChatMessage.packet_id: self.on_chat_packet, InteractPacket.packet_id: self.on_interact_packet, HitPacket.packet_id: self.on_hit_packet, ShootPacket.packet_id: self.on_shoot_packet } self.scripts = [] self.server.call_scripts('on_new_connection', self) self.packet_handler = PacketHandler(CS_PACKETS, self.on_packet) self.rights = AttributeSet() def dataReceived(self, data): self.packet_handler.feed(data) def disconnect(self, reason=None): self.transport.loseConnection() self.connectionLost(reason) def connectionLost(self, reason): if self.disconnected: return self.disconnected = True try: del self.server.connections[self] except KeyError: pass if self.has_joined: print 'Player %s left' % self.name if self.entity_data is not None: del self.server.entities[self.entity_id] if self.entity_id is not None: self.server.entity_ids.put_back(self.entity_id) for script in self.scripts[:]: script.unload() # packet methods def send_packet(self, packet): self.transport.write(write_packet(packet)) def on_packet(self, packet): handler = self.packet_handlers.get(packet.packet_id, None) if handler is None: # print 'Unhandled client packet: %s' % packet.packet_id return handler(packet) def on_version_packet(self, packet): if packet.version != constants.CLIENT_VERSION: mismatch_packet.version = constants.CLIENT_VERSION self.send_packet(mismatch_packet) self.disconnect() return server = self.server if len(server.connections) >= server.config.base.max_players: self.send_packet(server_full_packet) self.disconnect() return self.entity_id = server.entity_ids.pop() server.connections[(self.entity_id,)] = self join_packet.entity_id = self.entity_id self.send_packet(join_packet) seed_packet.seed = server.config.base.seed self.send_packet(seed_packet) def on_entity_packet(self, packet): if self.entity_data is None: self.entity_data = create_entity_data() self.server.entities[self.entity_id] = self.entity_data self.entity_data.mask |= packet.update_entity(self.entity_data) if not self.has_joined and getattr(self.entity_data, 'name', None): self.on_join() self.has_joined = True def on_chat_packet(self, packet): message = filter_string(packet.value).strip() if not message: return if self.on_chat(message) is False: return chat_packet.entity_id = self.entity_id chat_packet.value = message self.server.broadcast_packet(chat_packet) print '%s: %s' % (self.name, message) def on_interact_packet(self, packet): interact_type = packet.interact_type if interact_type == INTERACT_DROP: pos = self.position.copy() pos.z -= constants.BLOCK_SCALE self.server.drop_item(packet.item_data, pos) elif interact_type == INTERACT_PICKUP: chunk = (packet.chunk_x, packet.chunk_y) try: item = self.server.remove_item(chunk, packet.item_index) except IndexError: return self.give_item(item) def on_hit_packet(self, packet): try: target = self.server.entities[packet.target_id] except KeyError: return self.server.update_packet.player_hits.append(packet) if target.hp <= 0: return target.hp -= packet.damage if target.hp <= 0: self.call_scripts('on_kill', target) def on_shoot_packet(self, packet): self.server.update_packet.shoot_actions.append(packet) # handlers def on_join(self): print 'Player %s joined (IP %s)' % (self.name, self.address.host) for connection in self.server.connections.values(): if not connection.has_joined: continue entity_packet.set_entity(connection.entity_data, connection.entity_id) self.send_packet(entity_packet) self.call_scripts('on_join') def on_command(self, command, parameters): self.call_scripts('on_command', command, parameters) def on_chat(self, message): if message.startswith('/'): command, args = parse_command(message[1:]) self.on_command(command, args) return False self.call_scripts('on_chat', message) # other methods def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.send_packet(packet) def give_item(self, item): action = PickupAction() action.entity_id = self.entity_id action.item_data = item self.server.update_packet.pickups.append(action) def send_lines(self, lines): current_time = 0 for line in lines: reactor.callLater(current_time, self.send_chat, line) current_time += 2 def kick(self): self.send_chat('You have been kicked') self.disconnect() self.server.send_chat('%s has been kicked' % self.name) def call_scripts(self, name, *arg, **kw): return call_scripts(self.scripts, name, *arg, **kw) # convienience methods @property def position(self): if self.entity_data is None: return None return Vector3(self.entity_data.x, self.entity_data.y, self.entity_data.z) @property def name(self): if self.entity_data is None: return None return self.entity_data.name
class CubeWorldConnection(Protocol): """ Protocol used for players """ connection_state = 0 entity_id = None entity_data = None login_id = None change_index = -1 scripts = None chunk = None old_name = None old_pos = None old_health = None old_level = None old_xp = None # used for anti chat spamming time_last_chat = 0 chat_messages_burst = 0 # used for detecting dead connections time_last_packet = 0 time_last_rate = 0 packet_count = 0 packet_rate = 0 # used for basic DoS protection packet_burst = 0 def __init__(self, server, addr): self.address = addr self.server = server # connection methods def connectionMade(self): if self.connection_state != 0: self.disconnect('Unexpected data') return self.connection_state = 1 server = self.server if len(server.connections) >= server.config.base.max_players: # For being able to allow joining by external scritps although server is full ret = self.scripts.call('on_join_full_server').result if ret is not True: self.send_packet(server_full_packet) self.disconnect() self.connection_state = -1 print '[INFO] %s tried to join full server' % self.address.host return self.packet_handlers = { ClientVersion.packet_id: self.on_version_packet, EntityUpdate.packet_id: self.on_entity_packet, ClientChatMessage.packet_id: self.on_chat_packet, InteractPacket.packet_id: self.on_interact_packet, HitPacket.packet_id: self.on_hit_packet, ShootPacket.packet_id: self.on_shoot_packet } self.packet_handler = PacketHandler(CS_PACKETS, self.on_packet) server.connections.add(self) self.rights = AttributeSet() self.scripts = ScriptManager() server.scripts.call('on_new_connection', connection=self) def dataReceived(self, data): self.packet_handler.feed(data) def disconnect(self, reason=None): self.transport.loseConnection() self.connectionLost(reason) def connectionLost(self, reason): if self.connection_state < 0: return self.server.connections.discard(self) if self.connection_state >= 3: del self.server.players[self] print '[INFO] Player %s #%s left the game.' % (self.name, self.entity_id) self.server.send_chat('<<< %s #%s left the game' % (self.name, self.entity_id)) self.connection_state = -1 if self.entity_id is not None: self.server.world.unregister(self.entity_id) self.server.entity_ids.put_back(self.entity_id) if self.scripts is not None: self.scripts.unload() # packet methods def send_packet(self, packet): self.transport.write(write_packet(packet)) def on_packet(self, packet): if self.connection_state < 0: return if packet is None: print 'Invalid packet received' self.disconnect() raise StopIteration() handler = self.packet_handlers.get(packet.packet_id, None) if handler is None: # print 'Unhandled client packet: %s' % packet.packet_id return handler(packet) def on_version_packet(self, packet): if packet.version != constants.CLIENT_VERSION: mismatch_packet.version = constants.CLIENT_VERSION self.send_packet(mismatch_packet) self.disconnect(None) return server = self.server self.entity_id = server.entity_ids.pop() join_packet.entity_id = self.entity_id self.connection_state = 2 self.send_packet(join_packet) seed_packet.seed = server.config.base.seed self.send_packet(seed_packet) def on_entity_packet(self, packet): if self.entity_data is None: self.entity_data = create_entity_data() mask = packet.update_entity(self.entity_data) self.entity_data.mask |= mask if self.connection_state==2 and getattr(self.entity_data, 'name', None): self.on_join() return self.scripts.call('on_entity_update', mask=mask) # XXX clean this up if entity.is_pos_set(mask): self.on_pos_update() if entity.is_mode_set(mask): self.scripts.call('on_mode_update') if entity.is_class_set(mask): self.scripts.call('on_class_update') if entity.is_name_set(mask): self.scripts.call('on_name_update') if entity.is_multiplier_set(mask): self.scripts.call('on_multiplier_update') if entity.is_level_set(mask): self.scripts.call('on_level_update') if entity.is_equipment_set(mask): self.scripts.call('on_equipment_update') if entity.is_skill_set(mask): self.scripts.call('on_skill_update') if entity.is_appearance_set(mask): self.scripts.call('on_appearance_update') if entity.is_charged_mp_set(mask): self.scripts.call('on_charged_mp_update') if entity.is_flags_set(mask): self.scripts.call('on_flags_update') if entity.is_consumable_set(mask): self.scripts.call('on_consumable_update') def on_chunk(self, data): self.chunk = data def on_pos_update(self): if self.server.world: chunk = self.server.world.get_chunk_scaled(self.position.x, self.position.y) if chunk != self.chunk: self.chunk = chunk self.scripts.call('on_chunk_update') self.scripts.call('on_pos_update') def on_chat_packet(self, packet): message = filter_string(packet.value).strip() if not message: return message = self.on_chat(message) if not message: return chat_packet.entity_id = self.entity_id chat_packet.value = message self.server.broadcast_packet(chat_packet) print '[CHAT] %s: %s' % (self.name, message) def on_interact_packet(self, packet): interact_type = packet.interact_type item = packet.item_data if interact_type == INTERACT_DROP: pos = self.position.copy() pos.z -= constants.BLOCK_SCALE if self.scripts.call('on_drop', item=item, pos=pos).result is False: return self.server.drop_item(packet.item_data, pos) elif interact_type == INTERACT_PICKUP: try: item = self.server.remove_item(packet.chunk_x, packet.chunk_y, packet.item_index) except IndexError: return self.give_item(item) def on_hit_packet(self, packet): try: target = self.server.entities[packet.target_id] except KeyError: return if constants.MAX_DISTANCE > 0: edist = get_distance_3d(self.position.x, self.position.y, self.position.z, target.entity_data.pos.x, target.entity_data.pos.y, target.entity_data.pos.z) if edist > constants.MAX_DISTANCE: print '[ANTICHEAT BASE] Player %s tried to attack target that is %s away!' % (self.name, edist) self.kick('Range error') return if self.scripts.call('on_hit', target=target, packet=packet).result is False: return self.server.update_packet.player_hits.append(packet) if packet.damage <= 0: return if packet.damage > 1000: packet.damage = 1000 if target.hp > packet.damage: if self.scripts.call('on_damage', target=target, packet=packet).result is False: return target.hp -= packet.damage else: target.hp = 0 self.scripts.call('on_kill', target=target) def on_shoot_packet(self, packet): self.server.update_packet.shoot_actions.append(packet) def do_anticheat_actions(self): if not self.server.config.base.cheat_prevention: return False if not self.check_name(): return True if not self.check_pos(): return True self.last_pos = self.position if self.entity_data.entity_type < constants.ENTITY_TYPE_PLAYER_MIN_ID or self.entity_data.entity_type > constants.ENTITY_TYPE_PLAYER_MAX_ID: print '[ANTICHEAT BASE] Player %s tried to join with invalid entity type id: %s!' % (self.name, self.entity_data.entity_type) self.kick('Invalid entity type submitted') return True if self.entity_data.class_type < constants.ENTITY_CLASS_PLAYER_MIN_ID or self.entity_data.class_type > constants.ENTITY_CLASS_PLAYER_MAX_ID : self.kick('Invalid character class submitted') print '[ANTICHEAT BASE] Player %s tried to join with an invalid character class! Kicked.' % self.name return True if self.entity_data.hp > 1000: self.kick('Abnormal health points submitted') print '[ANTICHEAT BASE] Player %s tried to join with an abnormal health points! Kicked.' % self.name return True if self.entity_data.level < 1 or self.entity_data.level > constants.PLAYER_MAX_LEVEL: self.kick('Abnormal level submitted') print '[ANTICHEAT BASE] Player %s tried to join with an abnormal character level! Kicked.' % self.name return True # This seems to filter prevent cheaters from joining needed_xp = get_needed_total_xp(self.entity_data.level) if needed_xp > self.entity_data.current_xp: self.kick('Invalid character level') print '[ANTICHEAT BASE] Player %s tried to join with character level %s that is higher than total xp needed (%s/%s)! Kicked.' % (self.name, self.entity_data.level, self.entity_data.current_xp, needed_xp) return True #if self.entity_data.inventory...... in constants.FORBIDDEN_ITEMS_POSSESSION return False # handlers def on_join(self): if self.connection_state < 0: print '[WARNING] Connection of %s [%s] already has been invalidated before!' % (self.name, self.address.host) self.kick('Blocked join') return if self.connection_state != 2: print '[WARNING] Player %s [%s] tried to join in invalid state!' % (self.name, self.address.host) self.kick('Invalid state') return if self.check_name() is False: self.kick('Bad name') return # Call join script res = self.scripts.call('on_join').result if res is False: self.kick('Blocked join') print '[WARNING] Joining client %s blocked by script!' % self.address.host return if self.entity_data.level < self.server.config.base.join_level_min: print '[WARNING] Level of player %s [%s] is lower than minimum of %s' % (self.name, self.address.host, self.server.config.base.join_level_min) self.kick('Your level has to be at least %s' % self.server.config.base.join_level_min) return if self.entity_data.level > self.server.config.base.join_level_max: print '[WARNING] Level of player %s [%s] is higher than maximum of %s' % (self.name, self.address.host, self.server.config.base.join_level_max) self.kick('Your level has to be lower than %s' % self.server.config.base.join_level_max) return self.last_pos = self.position # we dont want cheaters being able joining the server if self.do_anticheat_actions(): self.server.send_chat('[ANTICHEAT] Player %s (%s) has been kicked for cheating.' % (self.name, get_entity_type_level_str(self.entity_data))) return print '>>> Player %s %s #%s [%s] joined the game' % (self.name, get_entity_type_level_str(self.entity_data), self.entity_id, self.address.host) self.server.send_chat('>>> %s #%s (%s) joined the game' % (self.name, self.entity_id, get_entity_type_level_str(self.entity_data))) # connection successful -> continue for player in self.server.players.values(): entity_packet.set_entity(player.entity_data, player.entity_id) self.send_packet(entity_packet) self.server.players[(self.entity_id,)] = self self.connection_state = 3 def on_command(self, command, parameters): self.scripts.call('on_command', command=command, args=parameters) if ( (not parameters) or (command == 'register') or (command == 'login') ): print '[COMMAND] %s: /%s' % (self.name, command) else: print '[COMMAND] %s: /%s %s' % (self.name, command, ' '.join(parameters)) def on_chat(self, message): if self.time_last_chat < int(reactor.seconds() - constants.ANTISPAM_LIMIT_CHAT): self.chat_messages_burst = 0 else: if self.chat_messages_burst < constants.ANTISPAM_BURST_CHAT: self.chat_messages_burst += 1 else: self.time_last_chat = reactor.seconds() res = self.scripts.call('on_spamming_chat').result if not res: # As we do not want to spam back only do this when # burst limit is reached for the first time if self.chat_messages_burst == constants.ANTISPAM_BURST_CHAT: if self.server.config.base.auto_kick_spam: self.kick('Kicked for chat spamming') else: self.send_chat('[ANTISPAM] Please do not spam in chat!') return if message.startswith('/'): command, args = parse_command(message[1:]) self.on_command(command, args) return event = self.scripts.call('on_chat', message=message) if event.result is False: return return event.message # other methods def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.send_packet(packet) def give_item(self, item): action = PickupAction() action.entity_id = self.entity_id action.item_data = item self.server.update_packet.pickups.append(action) def send_lines(self, lines): current_time = 0 for line in lines: reactor.callLater(current_time, self.send_chat, line) current_time += 2 def heal(self, amount=None, reason=None): if (amount is not None and amount <= 0) or (hp >= constants.PLAYER_MAX_HEALTH): return False if self.scripts.call('on_heal', amount, reason).result is False: return False if amount is None or amount + hp > constants.PLAYER_MAX_HEALTH: self.entity_data.hp = constants.PLAYER_MAX_HEALTH else: self.entity_data.hp += amount self.entity_data.changed = True for connection in self.server.connections.values(): entity_packet.set_entity(self.entity_data, self.entity_id) connection.send_packet(entity_packet) if reason is None: self.send_chat('[INFO] You have been healed.') elif reason is not False: self.send_chat(reason) def damage(self, damage=0, critical=0, stun_duration=0, reason=None): if self.scripts.call('on_damage', damage, critical, stun_duration, reason).result is False: return False packet = HitPacket() packet.entity_id = self.entity_id packet.target_id = self.entity_id packet.hit_type = HIT_NORMAL packet.damage = damage packet.critical = critical packet.stun_duration = stun_duration packet.something8 = 0 packet.pos = self.position packet.hit_dir = Vector3() packet.skill_hit = 0 packet.show_light = 0 # Processed by the server and clients in next update task run self.server.update_packet.player_hits.append(packet) self.entity_data.changed = True if reason: self.send_chat(reason) return True def kill(self, killer=None, reason=None): if not damage(self.entity_data.hp + 100, 1, 0): return False if self.scripts.call('on_kill', killer=killer, reason=reason).result is False: return False packet = KillAction() if killer is None: packet.entity_id = self.entity_id else: packet.entity_id = killer.entity_id packet.target_id = self.entity_id packet.xp_gained = 0 # Processed by the server and clients in next update task run self.server.update_packet.kill_actions.append(packet) self.entity_data.changed = True if reason is None: if killer is self: self.send_chat('You commited suicide') else: self.send_chat('You have been killed by %s' % killer.entity_data.name) elif reason is not False: self.send_chat(reason) return True def kick(self, reason=None): res = self.scripts.call('on_kick', reason=reason) if res is False: return if reason is None: self.send_chat('You have been kicked') elif reason is not False: self.send_chat(reason) self.disconnect() if self.entity_data.name: self.server.send_chat('<<< %s has been kicked' % self.entity_data.name) def teleport(self, to_x, to_y, to_z): res = self.scripts.call('on_teleport', pos=self.position) if res is False: return self.entity_data.pos.x = to_x self.entity_data.pos.y = to_y self.entity_data.pos.z = to_z # To not confuse anti cheating system self.last_pos = self.position self.entity_data.changed = True for connection in self.server.connections.values(): entity_packet.set_entity(self.entity_data, self.entity_id) connection.send_packet(entity_packet) self.send_chat('[INFO] You have been teleported.') def check_name(self): if self.old_name is None: return True if not self.name: self.kick('No name') print '[WARNING] %s had no name! Kicked.' % self.address.host return False if len(self.name) > constants.NAME_LENGTH_MAX: self.kick('Name to long') print '[WARNING] %s had name longer than %s characters! Kicked.' % (self.address.host, constants.NAME_LENGTH_MAX) return False self.entity_data.name = self.name.strip() if len(self.name) < constants.NAME_LENGTH_MIN: self.kick('Name to short') print '[WARNING] %s had name shorter than %s characters! Kicked.' % (self.address.host, constants.NAME_LENGTH_MIN) return False if re.search(self.server.config.base.name_filter, self.name) is None: self.kick('Illegal name') print '[WARNING] %s had illegal name! Kicked.' % self.address.host return False return True def check_pos(self): if self.old_pos is not None: if (self.position.x == self.old_pos.x) and (self.position.y == self.old_pos.y) and (self.position.z == self.old_pos.z): return True server = self.server cpres = self.scripts.call('on_pos_update').result if cpres is False: self.entity_data.x = self.old_pos.x self.entity_data.y = self.old_pos.y return True # check new coordinates and distances edist = get_distance_3d(self.old_pos.x, self.old_pos.y, self.old_pos.z, self.position.x, self.position.y, self.position.z) if edist > (reactor.seconds() * constants.MAX_MOVE_DISTANCE): self.entity_data.x = self.old_pos.x self.entity_data.y = self.old_pos.y self.entity_data.z = self.old_pos.z print 'Player %s moved to fast!' % self.name return False cxo = math.floor(self.old_pos.x / constants.CHUNK_SCALE) cyo = math.floor(self.old_pos.y / constants.CHUNK_SCALE) cxn = math.ceil(self.position.x / constants.CHUNK_SCALE) cyn = math.ceil(self.position.y / constants.CHUNK_SCALE) if (cxo != cxn) or (cyo != cyn): self.server.world.move_locatable(self.entity_id, self.position.x, self.position.y, self.position.z) print '%s entered chunk (%s,%s)' % (self.name, cxn, cyn) self.old_pos = self.position return True def check_items(self): server = self.server for slotindex in range(13): item = entity_data.equipment[slotindex] if not item or item.type == 0: continue if item.level < 0: self.kick('Illegal item') print '[INFO] Player %s #%s (%s) [%s] had item with level lover than 0' % (self.entity_data.name, self.entity_id, get_entity_type_level_str(self.entity_data), self.address.host) return False if item.material in self.server.config.base.forbid_item_possession: self.kick('Forbidden item') print '[INFO] Player %s #%s (%s) [%s] had forbidden item #%s' % (self.entity_data.name, self.entity_id, get_entity_type_level_str(self.entity_data), self.address.host, item.material) return False return True # convienience methods @property def position(self): if not self.entity_data.pos: return Vector3() return Vector3(self.entity_data.pos.x, self.entity_data.pos.y, self.entity_data.pos.z) @property def name(self): if not self.entity_data.name: return None return self.entity_data.name
class CubeWorldConnection(Protocol): """ Protocol used for players """ relay_client = None relay_packets = None has_joined = False entity_id = None entity_data = None login_id = None rank = None disconnected = False scripts = None chunk = None old_pos = None old_health = None old_level = None old_xp = None def __init__(self, server, addr): self.address = addr self.server = server self.relay_packets = [] # connection methods def got_relay_client(self, p): self.relay_client = p for data in self.relay_packets: self.relay_client.transport.write(data) self.relay_packets = None print 'Relaying Client Packets.' def connectionMade(self): self.transport.setTcpNoDelay(True) server = self.server self.client_packet_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_packet_handler = PacketHandler(SC_PACKETS, self.on_server_packet) server.connections.add(self) self.rights = AttributeSet() self.scripts = ScriptManager() server.scripts.call('on_new_connection', connection=self) point = TCP4ClientEndpoint(reactor, self.server.config.base.mitm_ip, self.server.config.base.mitm_port) d = point.connect(RelayFactory(self)) d.addCallback(self.got_relay_client) def serverDataReceived(self, data): self.server_packet_handler.feed(data) def dataReceived(self, data): self.client_packet_handler.feed(data) def disconnect(self, reason=None): self.transport.loseConnection() self.connectionLost(reason) def connectionLost(self, reason): if self.relay_client is not None: self.relay_client.transport.loseConnection() if self.disconnected: return self.disconnected = True if self.login_id is not None: database.update_online_seconds(self.server.db_con, self.login_id) self.server.connections.discard(self) if self.has_joined: del self.server.players[self] print '[INFO] Player %s #%s left the game.' % (self.name, self.entity_id) self.server.send_chat('<<< %s #%s left the game' % (self.name, self.entity_id)) if self.entity_data is not None: del self.server.entities[self.entity_id] if self.scripts is not None: self.scripts.unload() # packet methods def send_packet(self, packet): self.transport.write(write_packet(packet)) def relay_packet(self, packet): if self.relay_client is None: self.relay_packets.append(write_packet(packet)) else: self.relay_client.transport.write(write_packet(packet)) def on_server_packet(self, packet): if packet.packet_id == EntityUpdate.packet_id: if packet.entity_id == self.entity_id: self.on_entity_packet(packet) elif packet.packet_id == JoinPacket.packet_id: self.entity_id = packet.entity_id self.send_packet(packet) def on_client_packet(self, packet): if self.disconnected: return if packet is None: print 'Invalid packet received' self.disconnect() raise StopIteration() if packet.packet_id == EntityUpdate.packet_id: if self.on_entity_packet(packet) is True: self.relay_packet(packet) elif packet.packet_id == ClientChatMessage.packet_id: self.on_chat_packet(packet) elif packet.packet_id == InteractPacket.packet_id: self.on_interact_packet(packet) elif packet.packet_id == HitPacket.packet_id: self.on_hit_packet(packet) elif packet.packet_id == ShootPacket.packet_id: self.on_shoot_packet(packet) else: self.relay_packet(packet) def on_entity_packet(self, packet): if self.entity_id is None: return True if self.entity_data is None: self.entity_data = create_entity_data() self.server.entities[self.entity_id] = self.entity_data mask = packet.update_entity(self.entity_data) self.entity_data.mask |= mask if not self.has_joined and getattr(self.entity_data, 'name', None): self.on_join() return True result = True self.scripts.call('on_entity_update', mask=mask) # XXX clean this up if entity.is_pos_set(mask): if self.on_pos_update() is False: result = False if entity.is_mode_set(mask): self.scripts.call('on_mode_update') if entity.is_class_set(mask): self.scripts.call('on_class_update') if entity.is_name_set(mask): self.scripts.call('on_name_update') if entity.is_multiplier_set(mask): self.scripts.call('on_multiplier_update') if entity.is_level_set(mask): self.scripts.call('on_level_update') if entity.is_equipment_set(mask): self.scripts.call('on_equipment_update') if entity.is_skill_set(mask): self.scripts.call('on_skill_update') if entity.is_appearance_set(mask): self.scripts.call('on_appearance_update') if entity.is_charged_mp_set(mask): self.scripts.call('on_charged_mp_update') if entity.is_flags_set(mask): self.scripts.call('on_flags_update') if entity.is_consumable_set(mask): self.scripts.call('on_consumable_update') return result def on_pos_update(self): chunk = get_chunk(self.position) if self.chunk is None: self.chunk = chunk elif chunk != self.chunk: # Distance check if (abs(chunk[0]-self.chunk[0]) > 1) or (abs(chunk[1]-self.chunk[1]) > 1): self.disconnect('[ANTICHEAT] Traveled distance to large') print '[ANTICHEAT] Traveled distance of %s was to large' % self.name return False if abs(chunk[0]) < 2 or abs(chunk[1]) < 2: self.disconnect('[ANTICHEAT] Out of world border') self.teleport(550301073408, 550301073408, 1000000) print '[ANTICHEAT] %s was out of world border' % self.name return False self.chunk = chunk self.scripts.call('on_pos_update') return True def on_chat_packet(self, packet): message = filter_string(packet.value).strip() if not message: return message = self.on_chat(message) if not message: return chat_packet.entity_id = self.entity_id chat_packet.value = message self.server.broadcast_packet(chat_packet) print '[CHAT] %s: %s' % (self.name, message) def on_interact_packet(self, packet): interact_type = packet.interact_type item = packet.item_data if interact_type == INTERACT_DROP: pos = self.position.copy() if self.scripts.call('on_drop', item=item, pos=pos).result is False: return elif interact_type == INTERACT_PICKUP: pos = self.position.copy() if self.scripts.call('on_pickup', item=item, pos=pos).result is False: return self.relay_packet(packet) def on_hit_packet(self, packet): self.relay_packet(packet) try: target = self.server.entities[packet.target_id] except KeyError: return if self.scripts.call('on_hit', target=target, packet=packet).result is False: return #self.server.update_packet.player_hits.append(packet) if target.hp <= 0: return target.hp -= packet.damage if target.hp <= 0: self.scripts.call('on_kill', target=target) def on_shoot_packet(self, packet): self.relay_packet(packet) # handlers def on_join(self): if self.scripts.call('on_join').result is False: return False print '[INFO] Player %s joined the game at %s' % (self.name, self.position) self.server.send_chat('>>> %s #%s joined the game' % (self.name, self.entity_id)) self.server.players[(self.entity_id,)] = self self.has_joined = True return True def on_command(self, command, parameters): self.scripts.call('on_command', command=command, args=parameters) if ((not parameters) or (command == 'register') or (command == 'login')): print '[COMMAND] %s: /%s' % (self.name, command) else: print '[COMMAND] %s: /%s %s' % (self.name, command, ' '.join(parameters)) def on_chat(self, message): if message.startswith('/'): command, args = parse_command(message[1:]) self.on_command(command, args) return event = self.scripts.call('on_chat', message=message) if event.result is False: return return event.message # other methods def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.send_packet(packet) def give_item(self, item): action = PickupAction() action.entity_id = self.entity_id action.item_data = item self.server.update_packet.pickups.append(action) def send_lines(self, lines): current_time = 0 for line in lines: reactor.callLater(current_time, self.send_chat, line) current_time += 2 def heal(self, amount=None): if amount is not None and amount <= 0: return False packet = EntityUpdate() if amount is None or amount + self.entity_data.hp > 1000: self.entity_data.hp = 1000 else: self.entity_data.hp += amount packet.set_entity(self.entity_data, self.entity_id) self.relay_packet(packet) packet.set_entity(self.entity_data, 0) self.send_packet(packet) def kick(self): self.send_chat('You have been kicked') self.disconnect() self.server.send_chat('[INFO] %s has been kicked' % self.name) def teleport(self, to_x, to_y, to_z): packet = EntityUpdate() self.entity_data.pos.x = to_x self.entity_data.pos.y = to_y self.entity_data.pos.z = to_z self.chunk = get_chunk(self.entity_data.pos) self.old_pos = self.entity_data.pos packet.set_entity(self.entity_data, 0) self.send_packet(packet) packet.set_entity(self.entity_data, self.entity_id) self.relay_packet(packet) # convienience methods @property def position(self): if self.entity_data is None: return None return self.entity_data.pos @property def name(self): if self.entity_data is None: return None return self.entity_data.name
class CubeWorldProtocol(Protocol): relay_client = None relay_packets = None def __init__(self, server): self.server = server self.client_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_handler = PacketHandler(SC_PACKETS, self.on_server_packet) self.relay_packets = [] self.print_stats() def print_stats(self): return reactor.callLater(3, self.print_stats) print 'Server packets:', server_ids print 'Client packets:', client_ids def send_welcome(self): lines = [u'Hello %s! Welcome to the server!' % self.name, u'(server powered by cuwo)'] for line in reversed(lines): self.send_chat(line) def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.transport.write(write_packet(packet)) def on_client_packet(self, packet): if packet.packet_id in (12, 11): return if self.relay_client is None: self.relay_packets.append(write_packet(packet)) return self.relay_client.transport.write(write_packet(packet)) client_ids[packet.packet_id] += 1 if packet.packet_id == EntityUpdate.packet_id: try: name = packet.entity.name if not name: return self.name = name reactor.callLater(10, self.send_welcome) except AttributeError: pass return print 'Got client packet:', packet.packet_id def on_server_packet(self, packet): self.transport.write(write_packet(packet)) server_ids[packet.packet_id] += 1 if packet.packet_id in (0, 2, 4, 5): return print 'Got server packet:', packet.packet_id def got_relay_client(self, p): self.relay_client = p for data in self.relay_packets: self.relay_client.transport.write(data) self.relay_packets = None def connectionMade(self): point = TCP4ClientEndpoint(reactor, "127.0.0.1", 12346) d = point.connect(RelayFactory(self)) d.addCallback(self.got_relay_client) print 'Connected' def connectionLost(self, reason): print 'Lost connection' if self.relay_client is not None: self.relay_client.transport.loseConnection() def serverDataReceived(self, data): self.server_handler.feed(data) def dataReceived(self, data): self.client_handler.feed(data)
class CubeWorldProtocol(Protocol): relay_client = None relay_packets = None entity_id = None disconnected = True def __init__(self, server): self.server = server self.start_time = reactor.seconds() self.client_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_handler = PacketHandler(SC_PACKETS, self.on_server_packet) self.entities = {} self.relay_packets = [] self.print_stats() def print_stats(self): if self.disconnected: return reactor.callLater(4, self.print_stats) if self.entity_id is None: return entity = self.entities[self.entity_id] print 'Info:' print 'Pos:', entity.x, entity.y, entity.z def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.transport.write(write_packet(packet)) def on_entity_update(self, packet): if packet.entity_id not in self.entities: entity = create_entity_data() self.entities[packet.entity_id] = entity else: entity = self.entities[packet.entity_id] packet.update_entity(entity) def on_client_packet(self, packet): if packet.packet_id == EntityUpdate.packet_id: self.on_entity_update(packet) if self.relay_client is None: self.relay_packets.append(write_packet(packet)) return self.relay_client.transport.write(write_packet(packet)) if packet.packet_id not in (0,): print 'Got client packet:', packet.packet_id def on_server_packet(self, packet): if packet.packet_id == EntityUpdate.packet_id: self.on_entity_update(packet) elif packet.packet_id == ServerData.packet_id: self.entity_id = packet.entity_id elif packet.packet_id == CurrentTime.packet_id: # I hate darkness packet.time = constants.MAX_TIME / 2 self.transport.write(write_packet(packet)) if packet.packet_id not in (0, 2, 4, 5): print 'Got server packet:', packet.packet_id def got_relay_client(self, p): self.relay_client = p for data in self.relay_packets: self.relay_client.transport.write(data) self.relay_packets = None def connectionMade(self): point = TCP4ClientEndpoint(reactor, "127.0.0.1", 12346) d = point.connect(RelayFactory(self)) d.addCallback(self.got_relay_client) print 'Connected' def connectionLost(self, reason): self.disconnected = True print 'Lost connection' if self.relay_client is not None: self.relay_client.transport.loseConnection() def serverDataReceived(self, data): self.server_handler.feed(data) def dataReceived(self, data): self.client_handler.feed(data)
class CubeWorldProtocol(Protocol): relay_client = None relay_packets = None entity_id = None disconnected = False def __init__(self, server): self.server = server self.start_time = reactor.seconds() self.client_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_handler = PacketHandler(SC_PACKETS, self.on_server_packet) self.entities = {} self.relay_packets = [] self.print_stats() self.times = [] def print_stats(self): if self.disconnected: return reactor.callLater(15, self.print_stats) if self.entity_id is None: return entity = self.entities[self.entity_id] print 'Info:' print 'Pos:', entity.pos.x, entity.pos.y, entity.pos.z def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.transport.write(write_packet(packet)) def on_entity_update(self, packet): if packet.entity_id not in self.entities: entity = create_entity_data() self.entities[packet.entity_id] = entity else: entity = self.entities[packet.entity_id] packet.update_entity(entity) def on_client_packet(self, packet): if packet.packet_id == EntityUpdate.packet_id: self.on_entity_update(packet) if self.relay_client is None: self.relay_packets.append(write_packet(packet)) return self.relay_client.transport.write(write_packet(packet)) if packet.packet_id not in (0, ): print 'Got client packet:', packet.packet_id def on_server_packet(self, packet): if packet.packet_id == EntityUpdate.packet_id: self.on_entity_update(packet) elif packet.packet_id == JoinPacket.packet_id: self.entity_id = packet.entity_id elif packet.packet_id == CurrentTime.packet_id: # I hate darkness packet.time = constants.MAX_TIME / 2 self.transport.write(write_packet(packet)) if packet.packet_id not in (0, 2, 4, 5): print 'Got server packet:', packet.packet_id def got_relay_client(self, p): self.relay_client = p for data in self.relay_packets: self.relay_client.transport.write(data) self.relay_packets = None def connectionMade(self): point = TCP4ClientEndpoint(reactor, "127.0.0.1", 12346) d = point.connect(RelayFactory(self)) d.addCallback(self.got_relay_client) print 'Connected' def connectionLost(self, reason): self.disconnected = True print 'Lost connection' if self.relay_client is not None: self.relay_client.transport.loseConnection() def serverDataReceived(self, data): self.server_handler.feed(data) def dataReceived(self, data): self.client_handler.feed(data)
class CubeWorldConnection(Protocol): """ Protocol used for players """ has_joined = False entity_id = None entity_data = None disconnected = False scripts = None def __init__(self, server, addr): self.address = addr self.server = server # connection methods def connectionMade(self): server = self.server if len(server.connections) >= server.config.base.max_players: self.send_packet(server_full_packet) self.disconnect() return self.packet_handlers = { ClientVersion.packet_id: self.on_version_packet, EntityUpdate.packet_id: self.on_entity_packet, ClientChatMessage.packet_id: self.on_chat_packet, InteractPacket.packet_id: self.on_interact_packet, HitPacket.packet_id: self.on_hit_packet, ShootPacket.packet_id: self.on_shoot_packet } self.packet_handler = PacketHandler(CS_PACKETS, self.on_packet) server.connections.add(self) self.rights = AttributeSet() self.scripts = ScriptManager() server.scripts.call('on_new_connection', connection=self) def dataReceived(self, data): self.packet_handler.feed(data) def disconnect(self, reason=None): self.transport.loseConnection() self.connectionLost(reason) def connectionLost(self, reason): if self.disconnected: return self.disconnected = True self.server.connections.discard(self) if self.has_joined: del self.server.players[self] print 'Player %s left' % self.name if self.entity_data is not None: del self.server.entities[self.entity_id] if self.entity_id is not None: self.server.entity_ids.put_back(self.entity_id) if self.scripts is not None: self.scripts.unload() # packet methods def send_packet(self, packet): self.transport.write(write_packet(packet)) def on_packet(self, packet): if self.disconnected: return if packet is None: print 'Invalid packet received' self.disconnect() raise StopIteration() handler = self.packet_handlers.get(packet.packet_id, None) if handler is None: # print 'Unhandled client packet: %s' % packet.packet_id return handler(packet) def on_version_packet(self, packet): if packet.version != constants.CLIENT_VERSION: mismatch_packet.version = constants.CLIENT_VERSION self.send_packet(mismatch_packet) self.disconnect() return server = self.server self.entity_id = server.entity_ids.pop() join_packet.entity_id = self.entity_id self.send_packet(join_packet) seed_packet.seed = server.config.base.seed self.send_packet(seed_packet) def on_entity_packet(self, packet): if self.entity_data is None: self.entity_data = create_entity_data() self.server.entities[self.entity_id] = self.entity_data mask = packet.update_entity(self.entity_data) self.entity_data.mask |= mask if not self.has_joined and getattr(self.entity_data, 'name', None): self.on_join() return self.scripts.call('on_entity_update', mask=mask) # XXX clean this up if entity.is_pos_set(mask): self.scripts.call('on_pos_update') if entity.is_mode_set(mask): self.scripts.call('on_mode_update') if entity.is_class_set(mask): self.scripts.call('on_class_update') if entity.is_name_set(mask): self.scripts.call('on_name_update') if entity.is_multiplier_set(mask): self.scripts.call('on_multiplier_update') if entity.is_level_set(mask): self.scripts.call('on_level_update') if entity.is_equipment_set(mask): self.scripts.call('on_equipment_update') if entity.is_skill_set(mask): self.scripts.call('on_skill_update') if entity.is_appearance_set(mask): self.scripts.call('on_appearance_update') if entity.is_charged_mp_set(mask): self.scripts.call('on_charged_mp_update') if entity.is_flags_set(mask): self.scripts.call('on_flags_update') if entity.is_consumable_set(mask): self.scripts.call('on_consumable_update') def on_chat_packet(self, packet): message = filter_string(packet.value).strip() if not message: return message = self.on_chat(message) if not message: return chat_packet.entity_id = self.entity_id chat_packet.value = message self.server.broadcast_packet(chat_packet) print '%s: %s' % (self.name, message) def on_interact_packet(self, packet): interact_type = packet.interact_type item = packet.item_data if interact_type == INTERACT_DROP: pos = self.position.copy() pos.z -= constants.BLOCK_SCALE if self.scripts.call('on_drop', item=item, pos=pos).result is False: return self.server.drop_item(packet.item_data, pos) elif interact_type == INTERACT_PICKUP: chunk = (packet.chunk_x, packet.chunk_y) try: item = self.server.remove_item(chunk, packet.item_index) except IndexError: return self.give_item(item) def on_hit_packet(self, packet): try: target = self.server.entities[packet.target_id] except KeyError: return if self.scripts.call('on_hit', target=target, packet=packet) is False: return self.server.update_packet.player_hits.append(packet) if target.hp <= 0: return target.hp -= packet.damage if target.hp <= 0: self.scripts.call('on_kill', target=target) def on_shoot_packet(self, packet): self.server.update_packet.shoot_actions.append(packet) # handlers def on_join(self): if self.scripts.call('on_join').result is False: return print 'Player %s joined' % self.name for player in self.server.players.values(): entity_packet.set_entity(player.entity_data, player.entity_id) self.send_packet(entity_packet) self.server.players[(self.entity_id,)] = self self.has_joined = True def on_command(self, command, parameters): self.scripts.call('on_command', command=command, args=parameters) def on_chat(self, message): if message.startswith('/'): command, args = parse_command(message[1:]) self.on_command(command, args) return event = self.scripts.call('on_chat', message=message) if event.result is False: return return event.message # other methods def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.send_packet(packet) def give_item(self, item): action = PickupAction() action.entity_id = self.entity_id action.item_data = item self.server.update_packet.pickups.append(action) def send_lines(self, lines): current_time = 0 for line in lines: reactor.callLater(current_time, self.send_chat, line) current_time += 2 def kick(self): self.send_chat('You have been kicked') self.disconnect() self.server.send_chat('%s has been kicked' % self.name) # convienience methods @property def position(self): if self.entity_data is None: return None return self.entity_data.pos @property def name(self): if self.entity_data is None: return None return self.entity_data.name
class CubeWorldProtocol(Protocol): relay_client = None relay_packets = None entity_id = None def __init__(self, server): self.server = server self.start_time = reactor.seconds() self.client_handler = PacketHandler(CS_PACKETS, self.on_client_packet) self.server_handler = PacketHandler(SC_PACKETS, self.on_server_packet) self.entities = {} self.relay_packets = [] self.print_stats() # self.send_debug() def send_debug(self): reactor.callLater(0.01, self.send_debug) if self.entity_id is None: return entity = self.entities[self.entity_id] from cuwo.vector import Vector3 shoot = ShootPacket() shoot.entity_id = 2 shoot.chunk_x, shoot.chunk_y = get_chunk( Vector3(entity.x, entity.y, entity.z)) import random shoot.something5 = random.randrange(0, 10) shoot.something13 = 0 shoot.something14 = 0 shoot.something15 = 0 shoot.something19 = 10.49137020111084 shoot.something20 = 0.5 shoot.something21 = 1.0 shoot.something22 = 0.0 shoot.something23 = 0 shoot.something24 = 0 shoot.something25 = 0 shoot.something26 = 0 shoot.something27 = 0 shoot.something28 = 0 shoot.pos = Vector3(entity.x, entity.y, entity.z + 150000) shoot.velocity = Vector3(93.929801940, -34.1773529054, -3.0167741775) self.relay_client.transport.write(write_packet(shoot)) def print_stats(self): reactor.callLater(4, self.print_stats) if self.entity_id is None: return entity = self.entities[self.entity_id] print 'Info:' print 'Pos:', entity.x, entity.y, entity.z def send_chat(self, value): packet = ServerChatMessage() packet.entity_id = 0 packet.value = value self.transport.write(write_packet(packet)) def on_entity_update(self, packet): if packet.entity_id not in self.entities: entity = create_entity_data() self.entities[packet.entity_id] = entity else: entity = self.entities[packet.entity_id] packet.update_entity(entity) def on_client_packet(self, packet): if packet.packet_id == EntityUpdate.packet_id: self.on_entity_update(packet) if self.relay_client is None: self.relay_packets.append(write_packet(packet)) return self.relay_client.transport.write(write_packet(packet)) if packet.packet_id not in (0,): print 'Got client packet:', packet.packet_id def on_server_packet(self, packet): if packet.packet_id == EntityUpdate.packet_id: self.on_entity_update(packet) elif packet.packet_id == ServerData.packet_id: self.entity_id = packet.entity_id elif packet.packet_id == CurrentTime.packet_id: # I hate darkness packet.time = constants.MAX_TIME / 2 self.transport.write(write_packet(packet)) if packet.packet_id not in (0, 2, 4, 5): print 'Got server packet:', packet.packet_id def got_relay_client(self, p): self.relay_client = p for data in self.relay_packets: self.relay_client.transport.write(data) self.relay_packets = None def connectionMade(self): point = TCP4ClientEndpoint(reactor, "127.0.0.1", 12346) d = point.connect(RelayFactory(self)) d.addCallback(self.got_relay_client) print 'Connected' def connectionLost(self, reason): print 'Lost connection' if self.relay_client is not None: self.relay_client.transport.loseConnection() def serverDataReceived(self, data): self.server_handler.feed(data) def dataReceived(self, data): self.client_handler.feed(data)