Пример #1
0
    def __init__(self, *args, **kwargs):
        socketserver.ThreadingTCPServer.__init__(self, *args, **kwargs)
        self._stop = threading.Event()

        self.world = WorldServer(self)
        self.players = {}  # Dict of all players connected. {ipaddress: requesthandler,}
        self.player_ids = []  # List of all players this session, indexes are their ID's [0: first requesthandler,]

        self.command_parser = CommandParser()
Пример #2
0
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
    inventory = "\0"*(4*40)  # Currently, is serialized to be 4 bytes * (27 inv + 9 quickbar + 4 armor) = 160 bytes
    command_parser = CommandParser()

    operator = False

    def sendpacket(self, size, packet):
        self.request.sendall(struct.pack("i", 5+size)+packet)
    def sendchat(self, txt, color=(255,255,255,255)):
        txt = txt.encode('utf-8')
        self.sendpacket(len(txt) + 4, "\5" + txt + struct.pack("BBBB", *color))
    def sendinfo(self, info, color=(255,255,255,255)):
        info = info.encode('utf-8')
        self.sendpacket(len(info) + 4, "\5" + info + struct.pack("BBBB", *color))
    def broadcast(self, txt):
        for player in self.server.players.itervalues():
            player.sendchat(txt)
    def sendpos(self, pos_bytes, mom_bytes):
        self.sendpacket(38, "\x08" + struct.pack("H", self.id) + mom_bytes + pos_bytes)

    def lookup_player(self, playername):
        # find player by name
        for player in self.server.players.values():
            if player.username == playername:
                return player
        return None

    def handle(self):
        self.username = str(self.client_address)
        print "Client connecting...", self.client_address
        self.server.players[self.client_address] = self
        self.server.player_ids.append(self)
        self.id = len(self.server.player_ids) - 1
        try:
            self.loop()
        except socket.error as e:
            if self.server._stop.isSet():
                return  # Socket error while shutting down doesn't matter
            if e[0] in (10053, 10054):
                print "Client %s %s crashed." % (self.username, self.client_address)
            else:
                raise e

    def loop(self):
        world, players = self.server.world, self.server.players
        while 1:
            byte = self.request.recv(1)
            if not byte: return  # The client has disconnected intentionally

            packettype = struct.unpack("B", byte)[0]  # Client Packet Type
            if packettype == 1:  # Sector request
                sector = struct.unpack("iii", self.request.recv(4*3))

                if sector not in world.sectors:
                    with world.server_lock:
                        world.open_sector(sector)

                if not world.sectors[sector]:
                    #Empty sector, send packet 2
                    self.sendpacket(12, "\2" + struct.pack("iii",*sector))
                else:
                    msg = struct.pack("iii",*sector) + save_sector_to_string(world, sector) + world.get_exposed_sector(sector)
                    self.sendpacket(len(msg), "\1" + msg)
            elif packettype == 3:  # Add block
                positionbytes = self.request.recv(4*3)
                blockbytes = self.request.recv(2)

                position = struct.unpack("iii", positionbytes)
                blockid = G.BLOCKS_DIR[struct.unpack("BB", blockbytes)]
                with world.server_lock:
                    world.add_block(position, blockid, sync=False)

                for address in players:
                    if address is self.client_address: continue  # He told us, we don't need to tell him
                    players[address].sendpacket(14, "\3" + positionbytes + blockbytes)
            elif packettype == 4:  # Remove block
                positionbytes = self.request.recv(4*3)

                with world.server_lock:
                    world.remove_block(struct.unpack("iii", positionbytes), sync=False)

                for address in players:
                    if address is self.client_address: continue  # He told us, we don't need to tell him
                    players[address].sendpacket(12, "\4" + positionbytes)
            elif packettype == 5:  # Receive chat text
                txtlen = struct.unpack("i", self.request.recv(4))[0]
                raw_txt = self.request.recv(txtlen).decode('utf-8')
                txt = "%s: %s" % (self.username, raw_txt)
                try:
                    if raw_txt[0] == '/':
                        ex = self.command_parser.execute(raw_txt, user=self, world=world)
                        if ex != COMMAND_HANDLED:
                            self.sendchat('$$rUnknown command.')
                    else:
                        # Not a command, send the chat to all players
                        for address in players:
                            players[address].sendchat(txt)
                        print txt  # May as well let console see it too
                except CommandException, e:
                    self.sendchat(str(e), COMMAND_ERROR_COLOR)
            elif packettype == 6:  # Player Inventory Update
                self.inventory = self.request.recv(4*40)
                #TODO: All player's inventories should be autosaved at a regular interval.
            elif packettype == 8:  # Player Movement
                mom_bytes, pos_bytes = self.request.recv(4*3), self.request.recv(8*3)
                self.momentum = struct.unpack("fff", mom_bytes)
                self.position = struct.unpack("ddd", pos_bytes)
                for address in players:
                    if address is self.client_address: continue  # He told us, we don't need to tell him
                    #TODO: Only send to nearby players
                    players[address].sendpacket(38, "\x08" + struct.pack("H", self.id) + mom_bytes + pos_bytes)
Пример #3
0
class ServerPlayer(socketserver.BaseRequestHandler):
    inventory = b"\0" * (
        4 * 40
    )  # Currently, is serialized to be 4 bytes * (27 inv + 9 quickbar + 4 armor) = 160 bytes
    command_parser = CommandParser()

    operator = False

    def sendpacket(self, size: int, packet: bytes):
        self.request.sendall(struct.pack("i", 5 + size) + packet)

    def sendchat(self, txt: str, color=(255, 255, 255, 255)):
        txt_bytes = txt.encode('utf-8')
        self.sendpacket(
            len(txt_bytes) + 4,
            b"\5" + txt_bytes + struct.pack("BBBB", *color))

    def sendinfo(self, info: str, color=(255, 255, 255, 255)):
        info_bytes = info.encode('utf-8')
        self.sendpacket(
            len(info_bytes) + 4,
            b"\5" + info_bytes + struct.pack("BBBB", *color))

    def broadcast(self, txt: str):
        for player in self.server.players.values():
            player.sendchat(txt)

    def sendpos(self, pos_bytes, mom_bytes):
        self.sendpacket(
            38, b"\x08" + struct.pack("H", self.id) + mom_bytes + pos_bytes)

    def lookup_player(self, playername):
        # find player by name
        for player in list(self.server.players.values()):
            if player.username == playername:
                return player
        return None

    def handle(self):
        self.username = str(self.client_address)
        print("Client connecting...", self.client_address)
        self.server.players[self.client_address] = self
        self.server.player_ids.append(self)
        self.id = len(self.server.player_ids) - 1
        try:
            self.loop()
        except socket.error as e:
            if self.server._stop.isSet():
                return  # Socket error while shutting down doesn't matter
            if e.errno in (10053, 10054):
                print("Client %s %s crashed." %
                      (self.username, self.client_address))
            else:
                raise e

    def loop(self):
        world, players = self.server.world, self.server.players
        while 1:
            byte = self.request.recv(1)
            if not byte: return  # The client has disconnected intentionally

            packettype = struct.unpack("B", byte)[0]  # Client Packet Type
            if packettype == 1:  # Sector request
                sector = struct.unpack("iii", self.request.recv(4 * 3))

                if sector not in world.sectors:
                    with world.server_lock:
                        world.open_sector(sector)

                if not world.sectors[sector]:
                    # Empty sector, send packet 2
                    self.sendpacket(12, b"\2" + struct.pack("iii", *sector))
                else:
                    msg = struct.pack("iii", *sector) + save_sector_to_bytes(
                        world, sector) + world.get_exposed_sector(sector)
                    self.sendpacket(len(msg), b"\1" + msg)
            elif packettype == 3:  # Add block
                positionbytes = self.request.recv(4 * 3)
                blockbytes = self.request.recv(2)

                position = struct.unpack("iii", positionbytes)
                blockid = G.BLOCKS_DIR[struct.unpack("BB", blockbytes)]
                with world.server_lock:
                    world.add_block(position, blockid, sync=False)

                for address in players:
                    if address is self.client_address:
                        continue  # He told us, we don't need to tell him
                    players[address].sendpacket(
                        14, b"\3" + positionbytes + blockbytes)
            elif packettype == 4:  # Remove block
                positionbytes = self.request.recv(4 * 3)

                with world.server_lock:
                    world.remove_block(struct.unpack("iii", positionbytes),
                                       sync=False)

                for address in players:
                    if address is self.client_address:
                        continue  # He told us, we don't need to tell him
                    players[address].sendpacket(12, b"\4" + positionbytes)
            elif packettype == 5:  # Receive chat text
                txtlen = struct.unpack("i", self.request.recv(4))[0]
                raw_txt = self.request.recv(txtlen).decode('utf-8')
                txt = "%s: %s" % (self.username, raw_txt)
                try:
                    if raw_txt[0] == '/':
                        ex = self.command_parser.execute(raw_txt,
                                                         user=self,
                                                         world=world)
                        if ex != COMMAND_HANDLED:
                            self.sendchat('$$rUnknown command.')
                    else:
                        # Not a command, send the chat to all players
                        for address in players:
                            players[address].sendchat(txt)
                        print(txt)  # May as well let console see it too
                except CommandException as e:
                    self.sendchat(str(e), COMMAND_ERROR_COLOR)
            elif packettype == 6:  # Player Inventory Update
                self.inventory = self.request.recv(4 * 40)
                #TODO: All player's inventories should be autosaved at a regular interval.
            elif packettype == 8:  # Player Movement
                mom_bytes, pos_bytes = self.request.recv(
                    4 * 3), self.request.recv(8 * 3)
                self.momentum = struct.unpack("fff", mom_bytes)
                self.position = struct.unpack("ddd", pos_bytes)
                for address in players:
                    if address is self.client_address:
                        continue  # He told us, we don't need to tell him
                    #TODO: Only send to nearby players
                    players[address].sendpacket(
                        38, b"\x08" + struct.pack("H", self.id) + mom_bytes +
                        pos_bytes)
            elif packettype == 9:  # Player Jump
                for address in players:
                    if address is self.client_address:
                        continue  # He told us, we don't need to tell him
                    #TODO: Only send to nearby players
                    players[address].sendpacket(
                        2, b"\x09" + struct.pack("H", self.id))
            elif packettype == 10:  # Update Tile Entity
                block_pos = struct.unpack("iii", self.request.recv(4 * 3))
                ent_size = struct.unpack("i", self.request.recv(4))[0]
                world[block_pos].update_tile_entity(
                    self.request.recv(ent_size))
            elif packettype == 255:  # Initial Login
                txtlen = struct.unpack("i", self.request.recv(4))[0]
                self.username = self.request.recv(txtlen).decode('utf-8')
                self.position = None
                load_player(self, "world")

                for player in self.server.players.values():
                    player.sendchat("$$y%s has connected." % self.username)
                print("%s's username is %s" %
                      (self.client_address, self.username))

                position = (0,
                            self.server.world.terraingen.get_height(0, 0) + 2,
                            0)
                if self.position is None:
                    self.position = position  # New player, set initial position

                # Send list of current players to the newcomer
                for player in self.server.players.values():
                    if player is self: continue
                    name = player.username.encode('utf-8')
                    self.sendpacket(2 + len(name),
                                    b'\7' + struct.pack("H", player.id) + name)
                # Send the newcomer's name to all current players
                name = self.username.encode('utf-8')
                for player in self.server.players.values():
                    if player is self: continue
                    player.sendpacket(2 + len(name),
                                      b'\7' + struct.pack("H", self.id) + name)

                #Send them the sector under their feet first so they don't fall
                sector = sectorize(position)
                if sector not in world.sectors:
                    with world.server_lock:
                        world.open_sector(sector)
                msg = struct.pack("iii", *sector) + save_sector_to_bytes(
                    world, sector) + world.get_exposed_sector(sector)
                self.sendpacket(len(msg), b"\1" + msg)

                # Send them their spawn position and world seed(for client side biome generator)
                seed_packet = make_string_packet(str(G.SEED))
                self.sendpacket(
                    12 + len(seed_packet),
                    struct.pack("B", 255) + struct.pack("iii", *position) +
                    seed_packet)
                self.sendpacket(4 * 40, b"\6" + self.inventory)
            else:
                print("Received unknown packettype", packettype)

    def finish(self):
        print("Client disconnected,", self.client_address, self.username)
        try:
            del self.server.players[self.client_address]
        except KeyError:
            pass
        for player in self.server.players.values():
            player.sendchat("%s has disconnected." % self.username)
        # Send user list
        for player in self.server.players.values():
            player.sendpacket(2 + 1, b'\7' + struct.pack("H", self.id) + b'\0')
        save_player(self, "world")