예제 #1
0
class Helbreath:
    def __init__(self, Cfg):
        self.Config = Cfg
        self.AutoMSG = 0

    def Login(self):
        self.AutoMSG = Packets.MSGID_REQUEST_LOGIN
        self.LSock = XSocket(
            {
                "host": self.Config["IP"],
                "port": self.Config["Port"],
                "onConnect": self.LSock_Connect,
                "onDisconnect": self.LSock_Disconnect,
                "onRead": self.LSock_Read,
            }
        )
        self.LoggedIn = False
        self.Status = 0
        self.char_list = []
        self.LSock.Active = True
        self.LSock.join()
        self.Timers = TimerManager()
        del self.LSock

        return self.Status

    def EnterGame(self):
        if not self.LoggedIn:
            return False
        self.LSock = XSocket(
            {
                "host": self.Config["IP"],
                "port": self.Config["Port"],
                "onConnect": self.LSock_Connect,
                "onDisconnect": self.LSock_Disconnect,
                "onRead": self.LSock_Read,
            }
        )
        self.AutoMSG = Packets.MSGID_REQUEST_ENTERGAME
        self.Status = False
        self.LSock.Active = True
        self.LSock.join()
        del self.LSock
        if self.Status == False:
            return False
        else:
            self.LSock = XSocket(
                {
                    "host": self.Status[0],
                    "port": self.Status[1],
                    "onConnect": self.LSock_Connect,
                    "onDisconnect": self.LSock_Disconnect,
                    "onRead": self.LSock_Read,
                }
            )
            self.AutoMSG = Packets.MSGID_REQUEST_INITPLAYER
            self.Status = False
            self.LSock.Active = True
            return True

    def run(self):
        ok = Acc.Login()
        if ok == Packets.DEF_MSGTYPE_CONFIRM:
            print "Logged in."
            if Acc.EnterGame() == False:
                print "Unable to log into game server."
            else:
                print "Logged into game server."
        else:
            print "Could not login."

    def LSock_Connect(self, sender):
        # global Config
        # print "Connected to login server at %s:%d" % (Config['IP'], Config['Port'])
        if self.AutoMSG == Packets.MSGID_REQUEST_LOGIN:
            self.LSock.Write(
                Packets.MSGID_REQUEST_LOGIN,
                0,
                struct.pack(
                    "<10s10s30s", self.Config["Account"], self.Config["Password"], self.Config["WorldServerName"]
                ),
            )
        elif self.AutoMSG == Packets.MSGID_REQUEST_ENTERGAME:
            chr = None
            for c in self.char_list:
                if c.CharName == self.Config["CharName"]:
                    chr = c
                    break
            self.Player = chr
            self.LSock.Write(
                Packets.MSGID_REQUEST_ENTERGAME,
                Packets.DEF_ENTERGAMEMSGTYPE_NEW,
                struct.pack(
                    "<10s10s10s10si30s120s",
                    self.Config["CharName"],
                    chr.MapLoc,
                    self.Config["Account"],
                    self.Config["Password"],
                    chr.Level,
                    self.Config["WorldServerName"],
                    "",
                ),
            )

        elif self.AutoMSG == Packets.MSGID_REQUEST_INITPLAYER:
            self.LSock.Write(
                Packets.MSGID_REQUEST_INITPLAYER,
                0,
                struct.pack(
                    "<10s10s10s?20s", self.Player.CharName, self.Config["Account"], self.Config["Password"], False, ""
                ),
            )

    def LSock_Disconnect(self, sender):
        pass

    def LSock_Read(self, sender, data):
        self.Status = "error"
        while len(data) > 0:
            format = "<Bh"
            header_size = struct.calcsize(format)
            if len(data) < header_size:
                raise Exception
            s = struct.unpack(format, data[:header_size])
            Header = namedtuple("Header", "cKey dwSize")._make(s)
            size = len(data)
            data = data[header_size:]
            buffer = data[: Header.dwSize - 3]
            data = data[Header.dwSize - 3 :]

            if Header.cKey > 0:
                Decode = lambda buffer, dwSize, cKey: "".join(
                    map(
                        lambda n: (lambda asdf: chr(asdf & 255))((ord(buffer[n]) ^ (cKey ^ (dwSize - n))) - (n ^ cKey)),
                        range(len(buffer)),
                    )
                )
                buffer = Decode(buffer, Header.dwSize - 3, Header.cKey)

            self.Status = 0

            MsgID = struct.unpack("<L", buffer[:4])[0]
            buffer = buffer[4:]
            if MsgID == Packets.MSGID_RESPONSE_LOG:
                self.OnAccountLogin(buffer)
                sender.disconnect()
            elif MsgID == Packets.MSGID_RESPONSE_ENTERGAME:
                self.OnResponseEnterGame(buffer)
                sender.disconnect()
                # elif MsgID in [Packets.MSGID_REQUEST_INITDATA, Packets.MSGID_RESPONSE_INITPLAYER]:
            elif MsgID == Packets.MSGID_RESPONSE_INITPLAYER:
                self.InitPlayerResponseHandler(buffer)
            elif MsgID == Packets.MSGID_RESPONSE_INITDATA:
                # self.RequestInitDataHandler(buffer)
                self.InitDataResponseHandler(buffer)
            elif MsgID == Packets.MSGID_RESPONSE_NOTICEMENT:
                self.ResponseNoticementHandler(buffer)
            else:
                # if MsgID in Packets:
                # 	print "MsgID: %s" % (Packets.reverse_lookup_without_mask(MsgID))
                # else:
                print "MsgID: 0x%08X %db" % (MsgID, len(data))

    def RequestNoticement(self):
        try:
            f = open("CONTENTS\\contents1000.txt", "r")
            try:
                fs = len(f.read())
            finally:
                f.close()
        except:
            fs = 0

        self.LSock.Write(Packets.MSGID_REQUEST_NOTICEMENT, 0, struct.pack("<L", fs))

    def ResponseNoticementHandler(self, buffer):

        MsgType = struct.unpack("<h", buffer[:2])[0]
        buffer = buffer[2:]
        if MsgType == Packets.DEF_MSGTYPE_CONFIRM:
            pass
        elif MsgType == Packets.DEF_MSGTYPE_REJECT:
            print buffer
            f = open("CONTENTS\\contents1000.txt", "w")
            try:
                f.write(buffer)
            finally:
                f.close()

    def InitDataResponseHandler(self, buffer):
        print "Data response: %d " % len(buffer)
        self.RequestNoticement()
        self.Timers.register_timer(self.__checkconnection, "check_conn", 8.0, True)

    def __checkconnection(self):
        t = int(time.time())
        self.LSock.Write(Packets.MSGID_COMMAND_CHECKCONNECTION, 0, struct.pack("<L", t))

    def InitPlayerResponseHandler(self, buffer):
        MsgType = struct.unpack("<h", buffer[:2])[0]
        if MsgType == Packets.DEF_MSGTYPE_CONFIRM:
            self.LSock.Write(
                Packets.MSGID_REQUEST_INITDATA,
                0,
                struct.pack(
                    "<10s10s10s?20s", self.Player.CharName, self.Config["Account"], self.Config["Password"], False, ""
                ),
            )
        elif MsgType == Packets.DEF_MSGTYPE_REJECT:
            print "Reject in init data handler"
            self.LSock.disconect()

    def OnResponseEnterGame(self, buffer):
        global packet_format
        MsgType = struct.unpack("<h", buffer[:2])[0]
        buffer = buffer[2:]
        if MsgType == Packets.DEF_ENTERGAMERESTYPE_REJECT:
            self.Status = False
            return
        elif MsgType == Packets.DEF_ENTERGAMERESTYPE_CONFIRM:
            self.Status = True
            fmt = "<16sh"
            fmt_s = struct.calcsize(fmt)
            self.Status = map(packet_format, struct.unpack(fmt, buffer[:fmt_s]))
            return
        else:
            print Packets.reverse_lookup_without_mask(MsgType)
            self.Status = False

    def OnAccountLogin(self, buffer):

        MsgType = struct.unpack("<h", buffer[:2])[0]
        buffer = buffer[2:]

        self.Status = MsgType

        if MsgType == Packets.DEF_MSGTYPE_CONFIRM:
            print "Account %s login ok... Retrieving character list." % self.Config["Account"]
            account_fmt = "<2H13xb"  # 12x -> dates -> can skip
            account_size = struct.calcsize(account_fmt)
            account = struct.unpack(account_fmt, buffer[:account_size])
            buffer = buffer[account_size:]
            account = namedtuple("Account", "LowerVersion UpperVersion CharCount")._make(account)
            char_format = "<10sx12xhi6h4x10x10s"
            char_size = struct.calcsize(char_format)
            character = namedtuple("Character", "CharName Level Exp Str Vit Dex Int Mag Chr MapLoc")
            char_list = []
            for c in range(account.CharCount):
                tmp = buffer[:char_size]
                buffer = buffer[char_size:]
                tmp = map(packet_format, struct.unpack(char_format, tmp))
                char_list += [character._make(tmp)]
            self.char_list = char_list
            self.LoggedIn = True
            return True
        elif MsgType == Packets.DEF_LOGRESMSGTYPE_REJECT:
            print "Account %s blocked!" % self.Config["Account"]
            return False
        elif MsgType == Packets.DEF_LOGRESMSGTYPE_PASSWORDMISMATCH:
            print "Account %s password mismatch!" % self.Config["Password"]
            return False
        elif MsgType == Packets.DEF_LOGRESMSGTYPE_NOTEXISTINGACCOUNT:
            print "Account %s does not exists!" % self.Config["Account"]
            return False
        elif MsgType == Packets.DEF_LOGRESMSGTYPE_NOTEXISTINGWORLDSERVER:
            print "Account %s: World server is not activated" % (self.Config["Account"])
            return False
        else:
            print Packets.reverse_lookup_without_mask(MsgType)
            return False
예제 #2
0
class Server(object):
    '''
		New game server
		2011 Drajwer
	'''
    def __init__(self):
        self.server_name = ''
        self.maps = []
        self.clients = []
        self.logsockets = []
        self.serversocket = None
        self.noticement = ''
        self.event_thread_alive = False
        self.event_thread = False

        # Guards...

        self.clients_guard = Semaphore()

    def stop_and_cleanup(self):
        # Called when someone interrupts main thread
        self.event_thread_alive = False
        self.event_thread.join()

    def read_config(self):
        # JSON configuration reader
        import json, os
        from HBMap import HBMap
        config = json.load(open('settings.cfg'))
        self.server_name = str(config['CONFIG']['game-server-name'])
        self.address = str(config['CONFIG']['game-server-address'])
        self.port = int(config['CONFIG']['game-server-port'])

        self.log_server_address = str(config['CONFIG']['log-server-address'])
        self.gate_server_port = int(config['CONFIG']['gate-server-port'])

        self.maps = {}

        for map_name, options in config['MAPS'].items():
            map_name = str(map_name)
            print 'Initializing map %s...' % (map_name, )
            file_name = os.path.join(os.path.dirname(__file__), 'MAPDATA',
                                     options['amd'])

            if not os.path.exists(file_name):
                print 'Failure. Map %s does not exists.' % (map_name, )
                continue
            try:
                amd = HBMap(file_name)
            except Exception as e:
                print 'Failure. %s.' % (e, )
                continue
            print 'OK! SIZE(%d, %d)' % (amd.MAPSIZEX, amd.MAPSIZEY)
            self.maps[map_name] = config['MAPS'][map_name]
            self.maps[map_name]['amd'] = amd
        return True

    def initialize(self):
        if not self.read_config():
            return False

        for i in range(5):
            socket = GateSocket(address=self.log_server_address,
                                port=self.gate_server_port)

            self.setup_callbacks_gate(socket)

            self.logsockets += [socket]

        self.logsockets[0].connect()

        self.serversocket = ServerSocket((self.address, self.port),
                                         socketcls=ClientSocket)

        self.serversocket.on_listen = self.on_gameserver_listen
        self.serversocket.open_socket()

        return True

    def loop(self):
        # TODO: wrap around all clients_guard dependent code
        rinput = filter(lambda sock: sock.connected, self.logsockets)
        self.clients_guard.acquire()
        rinput += self.clients
        self.clients_guard.release()

        rinput += [self.serversocket]

        winput = filter(lambda sock: sock.connecting or sock.write_buffer,
                        self.logsockets)
        winput += filter(lambda sock: sock.write_buffer, self.clients)

        (rlist, wlist, elist) = select.select(rinput, winput, [], 0.5)

        for socket in rlist:
            if socket in self.logsockets:
                n = socket.recv()
                if not n:
                    socket.on_disconnect(socket)
                    socket.close()
                    continue

                while socket.pop_packet():
                    # Why would we even disconnect gate socket?
                    # Just do nothing
                    pass

            if socket in self.clients:
                n = socket.recv()
                if not n:
                    self.delete_client(socket, cleanup_only=True)
                    continue

                while True:
                    try:
                        if not socket.pop_packet():
                            break
                    except:
                        traceback.print_exc()
                        print
                        self.delete_client(socket, cleanup_only=True)

            if socket == self.serversocket:
                c = self.serversocket.accept(socketcls=ClientSocket)
                c.setblocking(False)
                self.clients_guard.acquire()
                try:
                    c.id = max(map(lambda client: client.id, self.clients)) + 1
                except ValueError as e:
                    c.id = 0
                self.clients.append(c)
                self.clients_guard.release()
                self.setup_callbacks_client(c)
                c.on_connect(c)

        for socket in wlist:
            if socket.connecting:
                socket.connecting = False
                socket.connected = True
                socket.on_connect(socket)

            n = socket.flush()

    def event_loop(self):
        # Event thread main entry function
        self.timers.process_all()

    def timer_connected_players(self):
        self.clients_guard.acquire()
        print '(O) Players connected:', len(self.clients)
        self.clients_guard.release()

    def on_server_registered(self):
        self.timers = TimerManager()
        self.timers.register_timer(None, self.timer_connected_players, 1.0)

        def thread_ep(server_instance):
            # Thread entry point
            server_instance.event_thread_alive = True
            while server_instance.event_thread_alive:
                server_instance.event_loop()
                time.sleep(0.1)

        self.event_thread = Thread(target=thread_ep, args=(self, ))
        self.event_thread.start()

    '''
		Socket events
	'''

    def on_logsocket_connected(self, logsocket):
        '''
			Request game server registration
		'''

        #How many connected sockets we have?
        connected = len(filter(lambda _: _.connected, self.logsockets))

        if connected > 1:
            print 'Trying to register game server socket'
            logsocket.do_register_gameserversocket(gsid=self.gsid)
        else:
            print 'Trying to register game server %s...' % self.server_name
            logsocket.do_register_gameserver(server_name=self.server_name,
                                             address=self.address,
                                             port=self.port,
                                             maps=self.maps.keys())

    def on_logsocket_connection_lost(self, logsocket):
        '''
			Fired when gate server socket lost connection
		'''

        print 'Lost connection to gate server on socket-%d' % self.logsockets.index(
            logsocket)
        if not filter(lambda _: _.connected, self.logsockets):
            print 'Lost connection to gate server!'

    def on_gameserver_listen(self):
        print 'Game server socket is working!'

    def on_client_connect(self, client):
        print 'Client connected!'

    def on_client_disconnect(self, client):
        print 'Client disconnected!'

    '''
		Communication
	'''

    def getlogsocket(self):
        # TODO : Filter only connected logsockets?
        return random.choice(self.logsockets)

    '''
		Functions
	'''

    def setup_callbacks_gate(self, logsocket):
        '''
			Setup callbacks on gate socket
		'''
        logsocket.on_response_registergameserver = self.on_response_registergameserver
        logsocket.on_connect = self.on_logsocket_connected
        logsocket.on_disconnect = self.on_logsocket_connection_lost
        logsocket.on_response_playerdata = self.on_response_playerdata

        # Configs

        logsocket.on_receive_config_noticement = self.on_receive_config_noticement

    def setup_callbacks_client(self, client):
        '''
			Setup callbacks on client socket
		'''
        client.on_connect = self.on_client_connect
        client.on_disconnect = self.on_client_disconnect

        client.on_request_noticement = self.client_on_request_noticement
        client.on_request_initplayer = self.client_on_request_initplayer
        client.on_request_initdata = self.client_on_request_initdata
        client.on_request_fullobjectdata = self.client_on_request_fullobjectdata

    def delete_client(self, client, cleanup_only=False):
        # TODO: options etc
        if cleanup_only:
            client.on_disconnect(client)
            client.close()
            self.clients_guard.acquire()
            self.clients.remove(client)
            self.clients_guard.release()
            return

        client.close()
        if client in self.clients:
            self.clients.remove(client)

    '''
		Gate server handlers
	'''

    def on_receive_config_noticement(self, noticement):
        self.noticement = noticement.rstrip()

    def on_response_registergameserver(self, success, gsid=None):
        if not success:
            print 'Game server %s registration rejected!' % self.server_name
            return

        self.gsid = gsid

        print 'Game server %s registration success! (GSID:%r)' % (
            self.server_name, gsid)

        for i, socket in enumerate(self.logsockets):
            if not socket.connected:
                print 'Connecting gate server socket-%d!' % (i, )
                socket.connect()

        self.on_server_registered()

    def on_response_playerdata(self, char_name, player_data):
        try:
            client, = filter(lambda _: _.char_name, self.clients)
        except ValueError as e:
            print '(O) Got unknown player data %r' % char_name
            return

        if not player_data:
            print '(HACK?) Not existing character(%s) data request! Rejected!' % (
                char_name, )
            self.delete_client(client)
            return

        if player_data.map_name not in self.maps:
            print 'Player stuck on not existing map "%s" !' % (
                player_data.map_name, )
            self.delete_client(client)
            return

        maploc = self.maps[player_data.map_name]

        if (player_data.x, player_data.y) not in maploc:
            player_data.x, player_data.y = random.choice(
                maploc['initial-points'])
            print '%s new initial point is', player_data.x, player_data.y

        client.player_data = player_data
        client.map = maploc

        client.do_response_initplayer(success=True)

        # TODO : when you call it with success = False client will get
        # 'World server full try other server'. Player limit could be
        # implemented.

        self.getlogsocket().do_entergame_confirm(
            account_name=client.account_name,
            account_password=client.account_password,
            server_name=self.server_name,
            address=client.address,
            level=player_data.level)

        print '(TestLog) Enter Game Confirm Level: %d' % player_data.level

    '''
		Client socket handlers
	'''

    def client_on_request_initplayer(self, char_name, account_name,
                                     account_password, is_observer_mode,
                                     client):
        print 'Request init player'
        print char_name, account_name, account_password, is_observer_mode

        client.char_name = char_name
        client.account_name = account_name
        client.account_password = account_password

        self.getlogsocket().do_request_playerdata(
            char_name=char_name,
            account_name=account_name,
            account_password=account_password,
            address=client.address)

    def client_on_request_initdata(self, char_name, account_name,
                                   account_password, client):
        if client.char_name != char_name:
            print '(!) Error!', self.char_name, '!=', char_name
            self.delete_client(client)
            return
        client.do_playercharactercontents()
        client.do_response_initdata()

    def client_on_request_noticement(self, client, file_size):
        # Ignore client size of noticement data stored on disk and always
        # send new noticement.
        client.send_noticement(self.noticement)

    def client_on_request_fullobjectdata(self, client, object_id):
        print 'request fullobjectdata req:%d client:%d' % (object_id,
                                                           client.id)
        try:
            obj, = filter(lambda _: _.id == object_id, self.clients)
        except ValueError as e:
            print '(!) Client requests full data from unknown object.'
            self.delete_client(client)
            return

        self.do_event_motion('stop', obj)
예제 #3
0
class Helbreath():
    def __init__(self, Cfg):
        self.Config = Cfg
        self.AutoMSG = 0

    def Login(self):
        self.AutoMSG = Packets.MSGID_REQUEST_LOGIN
        self.LSock = XSocket({
            'host': self.Config['IP'],
            'port': self.Config['Port'],
            'onConnect': self.LSock_Connect,
            'onDisconnect': self.LSock_Disconnect,
            'onRead': self.LSock_Read
        })
        self.LoggedIn = False
        self.Status = 0
        self.char_list = []
        self.LSock.Active = True
        self.LSock.join()
        self.Timers = TimerManager()
        del self.LSock

        return self.Status

    def EnterGame(self):
        if not self.LoggedIn:
            return False
        self.LSock = XSocket({
            'host': self.Config['IP'],
            'port': self.Config['Port'],
            'onConnect': self.LSock_Connect,
            'onDisconnect': self.LSock_Disconnect,
            'onRead': self.LSock_Read
        })
        self.AutoMSG = Packets.MSGID_REQUEST_ENTERGAME
        self.Status = False
        self.LSock.Active = True
        self.LSock.join()
        del self.LSock
        if self.Status == False:
            return False
        else:
            self.LSock = XSocket({
                'host': self.Status[0],
                'port': self.Status[1],
                'onConnect': self.LSock_Connect,
                'onDisconnect': self.LSock_Disconnect,
                'onRead': self.LSock_Read
            })
            self.AutoMSG = Packets.MSGID_REQUEST_INITPLAYER
            self.Status = False
            self.LSock.Active = True
            return True

    def run(self):
        ok = Acc.Login()
        if ok == Packets.DEF_MSGTYPE_CONFIRM:
            print "Logged in."
            if Acc.EnterGame() == False:
                print "Unable to log into game server."
            else:
                print "Logged into game server."
        else:
            print "Could not login."

    def LSock_Connect(self, sender):
        #global Config
        #print "Connected to login server at %s:%d" % (Config['IP'], Config['Port'])
        if self.AutoMSG == Packets.MSGID_REQUEST_LOGIN:
            self.LSock.Write(
                Packets.MSGID_REQUEST_LOGIN, 0,
                struct.pack('<10s10s30s', self.Config['Account'],
                            self.Config['Password'],
                            self.Config['WorldServerName']))
        elif self.AutoMSG == Packets.MSGID_REQUEST_ENTERGAME:
            chr = None
            for c in self.char_list:
                if c.CharName == self.Config['CharName']:
                    chr = c
                    break
            self.Player = chr
            self.LSock.Write(
                Packets.MSGID_REQUEST_ENTERGAME,
                Packets.DEF_ENTERGAMEMSGTYPE_NEW,
                struct.pack('<10s10s10s10si30s120s', self.Config['CharName'],
                            chr.MapLoc, self.Config['Account'],
                            self.Config['Password'], chr.Level,
                            self.Config['WorldServerName'], ""))

        elif self.AutoMSG == Packets.MSGID_REQUEST_INITPLAYER:
            self.LSock.Write(
                Packets.MSGID_REQUEST_INITPLAYER, 0,
                struct.pack('<10s10s10s?20s', self.Player.CharName,
                            self.Config['Account'], self.Config['Password'],
                            False, ""))

    def LSock_Disconnect(self, sender):
        pass

    def LSock_Read(self, sender, data):
        self.Status = "error"
        while len(data) > 0:
            format = '<Bh'
            header_size = struct.calcsize(format)
            if len(data) < header_size:
                raise Exception
            s = struct.unpack(format, data[:header_size])
            Header = namedtuple('Header', 'cKey dwSize')._make(s)
            size = len(data)
            data = data[header_size:]
            buffer = data[:Header.dwSize - 3]
            data = data[Header.dwSize - 3:]

            if Header.cKey > 0:
                Decode = lambda buffer, dwSize, cKey: "".join(
                    map(
                        lambda n: (lambda asdf: chr(asdf & 255))
                        ((ord(buffer[n]) ^ (cKey ^ (dwSize - n))) -
                         (n ^ cKey)), range(len(buffer))))
                buffer = Decode(buffer, Header.dwSize - 3, Header.cKey)

            self.Status = 0

            MsgID = struct.unpack('<L', buffer[:4])[0]
            buffer = buffer[4:]
            if MsgID == Packets.MSGID_RESPONSE_LOG:
                self.OnAccountLogin(buffer)
                sender.disconnect()
            elif MsgID == Packets.MSGID_RESPONSE_ENTERGAME:
                self.OnResponseEnterGame(buffer)
                sender.disconnect()
            #elif MsgID in [Packets.MSGID_REQUEST_INITDATA, Packets.MSGID_RESPONSE_INITPLAYER]:
            elif MsgID == Packets.MSGID_RESPONSE_INITPLAYER:
                self.InitPlayerResponseHandler(buffer)
            elif MsgID == Packets.MSGID_RESPONSE_INITDATA:
                #self.RequestInitDataHandler(buffer)
                self.InitDataResponseHandler(buffer)
            elif MsgID == Packets.MSGID_RESPONSE_NOTICEMENT:
                self.ResponseNoticementHandler(buffer)
            else:
                #if MsgID in Packets:
                #	print "MsgID: %s" % (Packets.reverse_lookup_without_mask(MsgID))
                #else:
                print "MsgID: 0x%08X %db" % (MsgID, len(data))

    def RequestNoticement(self):
        try:
            f = open("CONTENTS\\contents1000.txt", "r")
            try:
                fs = len(f.read())
            finally:
                f.close()
        except:
            fs = 0

        self.LSock.Write(Packets.MSGID_REQUEST_NOTICEMENT, 0,
                         struct.pack('<L', fs))

    def ResponseNoticementHandler(self, buffer):

        MsgType = struct.unpack('<h', buffer[:2])[0]
        buffer = buffer[2:]
        if MsgType == Packets.DEF_MSGTYPE_CONFIRM:
            pass
        elif MsgType == Packets.DEF_MSGTYPE_REJECT:
            print buffer
            f = open("CONTENTS\\contents1000.txt", "w")
            try:
                f.write(buffer)
            finally:
                f.close()

    def InitDataResponseHandler(self, buffer):
        print "Data response: %d " % len(buffer)
        self.RequestNoticement()
        self.Timers.register_timer(self.__checkconnection, 'check_conn', 8.0,
                                   True)

    def __checkconnection(self):
        t = int(time.time())
        self.LSock.Write(Packets.MSGID_COMMAND_CHECKCONNECTION, 0,
                         struct.pack('<L', t))

    def InitPlayerResponseHandler(self, buffer):
        MsgType = struct.unpack('<h', buffer[:2])[0]
        if MsgType == Packets.DEF_MSGTYPE_CONFIRM:
            self.LSock.Write(
                Packets.MSGID_REQUEST_INITDATA, 0,
                struct.pack('<10s10s10s?20s', self.Player.CharName,
                            self.Config['Account'], self.Config['Password'],
                            False, ""))
        elif MsgType == Packets.DEF_MSGTYPE_REJECT:
            print "Reject in init data handler"
            self.LSock.disconect()

    def OnResponseEnterGame(self, buffer):
        global packet_format
        MsgType = struct.unpack('<h', buffer[:2])[0]
        buffer = buffer[2:]
        if MsgType == Packets.DEF_ENTERGAMERESTYPE_REJECT:
            self.Status = False
            return
        elif MsgType == Packets.DEF_ENTERGAMERESTYPE_CONFIRM:
            self.Status = True
            fmt = "<16sh"
            fmt_s = struct.calcsize(fmt)
            self.Status = map(packet_format,
                              struct.unpack(fmt, buffer[:fmt_s]))
            return
        else:
            print Packets.reverse_lookup_without_mask(MsgType)
            self.Status = False

    def OnAccountLogin(self, buffer):

        MsgType = struct.unpack('<h', buffer[:2])[0]
        buffer = buffer[2:]

        self.Status = MsgType

        if MsgType == Packets.DEF_MSGTYPE_CONFIRM:
            print "Account %s login ok... Retrieving character list." % self.Config[
                'Account']
            account_fmt = "<2H13xb"  #12x -> dates -> can skip
            account_size = struct.calcsize(account_fmt)
            account = struct.unpack(account_fmt, buffer[:account_size])
            buffer = buffer[account_size:]
            account = namedtuple(
                'Account',
                'LowerVersion UpperVersion CharCount')._make(account)
            char_format = "<10sx12xhi6h4x10x10s"
            char_size = struct.calcsize(char_format)
            character = namedtuple(
                'Character',
                'CharName Level Exp Str Vit Dex Int Mag Chr MapLoc')
            char_list = []
            for c in range(account.CharCount):
                tmp = buffer[:char_size]
                buffer = buffer[char_size:]
                tmp = map(packet_format, struct.unpack(char_format, tmp))
                char_list += [character._make(tmp)]
            self.char_list = char_list
            self.LoggedIn = True
            return True
        elif MsgType == Packets.DEF_LOGRESMSGTYPE_REJECT:
            print "Account %s blocked!" % self.Config['Account']
            return False
        elif MsgType == Packets.DEF_LOGRESMSGTYPE_PASSWORDMISMATCH:
            print "Account %s password mismatch!" % self.Config['Password']
            return False
        elif MsgType == Packets.DEF_LOGRESMSGTYPE_NOTEXISTINGACCOUNT:
            print "Account %s does not exists!" % self.Config['Account']
            return False
        elif MsgType == Packets.DEF_LOGRESMSGTYPE_NOTEXISTINGWORLDSERVER:
            print "Account %s: World server is not activated" % (
                self.Config['Account'])
            return False
        else:
            print Packets.reverse_lookup_without_mask(MsgType)
            return False
예제 #4
0
class Server(object):
	'''
		New game server
		2011 Drajwer
	'''
	
	def __init__(self):
		self.server_name = ''
		self.maps = []
		self.clients = []
		self.logsockets = []
		self.serversocket = None
		self.noticement = ''
		self.event_thread_alive = False
		self.event_thread = False
		
		# Guards...
		
		self.clients_guard = Semaphore()
		
	def stop_and_cleanup(self):
		# Called when someone interrupts main thread
		self.event_thread_alive = False
		self.event_thread.join()
		
	def read_config(self):
		# JSON configuration reader
		import json, os
		from HBMap import HBMap
		config = json.load(open('settings.cfg'))
		self.server_name = str(config['CONFIG']['game-server-name'])
		self.address = str(config['CONFIG']['game-server-address'])
		self.port = int(config['CONFIG']['game-server-port'])
		
		self.log_server_address = str(config['CONFIG']['log-server-address'])
		self.gate_server_port = int(config['CONFIG']['gate-server-port'])
		
		self.maps = {}
		
		for map_name, options in config['MAPS'].items():
			map_name = str(map_name)
			print 'Initializing map %s...' % (map_name, )
			file_name = os.path.join(os.path.dirname(__file__), 'MAPDATA', options['amd'])
			
			if not os.path.exists(file_name):
				print 'Failure. Map %s does not exists.' % (map_name, )
				continue
			try:
				amd = HBMap(file_name)
			except Exception as e:
				print 'Failure. %s.' % (e, )
				continue
			print 'OK! SIZE(%d, %d)' % (amd.MAPSIZEX, amd.MAPSIZEY)
			self.maps[map_name] = config['MAPS'][map_name]
			self.maps[map_name]['amd'] = amd
		return True
	
	def initialize(self):
		if not self.read_config():
			return False
		
		for i in range(5):
			socket = GateSocket(
				address = self.log_server_address,
				port = self.gate_server_port
			)
			
			self.setup_callbacks_gate(socket)
	
			self.logsockets += [socket]
			
		self.logsockets[0].connect()
		
		self.serversocket = ServerSocket(
			(self.address, self.port),
			socketcls = ClientSocket
		)
		
		self.serversocket.on_listen = self.on_gameserver_listen
		self.serversocket.open_socket()
		
		return True
		
	def loop(self):
		# TODO: wrap around all clients_guard dependent code 
		rinput = filter(lambda sock: sock.connected, self.logsockets)
		self.clients_guard.acquire()
		rinput += self.clients
		self.clients_guard.release()
		
		rinput += [self.serversocket]

		winput = filter(lambda sock: sock.connecting or sock.write_buffer, self.logsockets)
		winput += filter(lambda sock: sock.write_buffer, self.clients)
		
		(rlist, wlist, elist) = select.select(rinput, winput, [], 0.5)
		
		for socket in rlist:
			if socket in self.logsockets:
				n = socket.recv()
				if not n:
					socket.on_disconnect(socket)
					socket.close()
					continue
													
				while socket.pop_packet():
					# Why would we even disconnect gate socket?
					# Just do nothing
					pass 
			
			if socket in self.clients:
				n = socket.recv()
				if not n:
					self.delete_client(socket, cleanup_only = True)
					continue
				
				while True:
					try:
						if not socket.pop_packet():
							break
					except:
						traceback.print_exc()
						print
						self.delete_client(socket, cleanup_only = True)
						
			if socket == self.serversocket:
				c = self.serversocket.accept(socketcls = ClientSocket)
				c.setblocking(False)
				self.clients_guard.acquire()
				try:
					c.id = max(map(lambda client: client.id, self.clients)) + 1
				except ValueError as e:
					c.id = 0
				self.clients.append(c)
				self.clients_guard.release()
				self.setup_callbacks_client(c)
				c.on_connect(c)
				
				
		for socket in wlist:
			if socket.connecting:
				socket.connecting = False
				socket.connected = True
				socket.on_connect(socket)
				
			n = socket.flush()
	
	def event_loop(self):
		# Event thread main entry function
		self.timers.process_all()

	def timer_connected_players(self):
		self.clients_guard.acquire() 
		print '(O) Players connected:', len(self.clients)
		self.clients_guard.release()
		
	def on_server_registered(self):
		self.timers = TimerManager()
		self.timers.register_timer(None, self.timer_connected_players, 1.0)
		
		def thread_ep(server_instance):
			# Thread entry point
			server_instance.event_thread_alive = True
			while server_instance.event_thread_alive:
				server_instance.event_loop()
				time.sleep(0.1)
				
		self.event_thread = Thread(target = thread_ep, args = (self, ))
		self.event_thread.start()
		
	'''
		Socket events
	'''
	
	def on_logsocket_connected(self, logsocket):
		'''
			Request game server registration
		'''
		
		#How many connected sockets we have?
		connected = len(filter(lambda _: _.connected, self.logsockets)) 
		
		if connected > 1:
			print 'Trying to register game server socket'
			logsocket.do_register_gameserversocket(
				gsid = self.gsid
			)
		else:
			print 'Trying to register game server %s...' % self.server_name
			logsocket.do_register_gameserver(
				server_name = self.server_name,
				address = self.address,
				port = self.port,
				maps = self.maps.keys()
			)
			
	def on_logsocket_connection_lost(self, logsocket):
		'''
			Fired when gate server socket lost connection
		'''
		
		print 'Lost connection to gate server on socket-%d' % self.logsockets.index(logsocket)
		if not filter(lambda _: _.connected, self.logsockets):
			print 'Lost connection to gate server!'
	
	def on_gameserver_listen(self):
		print 'Game server socket is working!'
		
	def on_client_connect(self, client):
		print 'Client connected!'
	
	def on_client_disconnect(self, client):
		print 'Client disconnected!'

	'''
		Communication
	'''
	
	
	def getlogsocket(self):
		# TODO : Filter only connected logsockets?
		return random.choice(self.logsockets)
		
	'''
		Functions
	'''
	
	def setup_callbacks_gate(self, logsocket):
		'''
			Setup callbacks on gate socket
		'''
		logsocket.on_response_registergameserver = self.on_response_registergameserver
		logsocket.on_connect = self.on_logsocket_connected
		logsocket.on_disconnect = self.on_logsocket_connection_lost
		logsocket.on_response_playerdata = self.on_response_playerdata
		
		# Configs
		
		logsocket.on_receive_config_noticement = self.on_receive_config_noticement		

	def setup_callbacks_client(self, client):
		'''
			Setup callbacks on client socket
		'''
		client.on_connect = self.on_client_connect
		client.on_disconnect = self.on_client_disconnect
		
		client.on_request_noticement = self.client_on_request_noticement
		client.on_request_initplayer = self.client_on_request_initplayer
		client.on_request_initdata = self.client_on_request_initdata
		client.on_request_fullobjectdata = self.client_on_request_fullobjectdata
		
	def delete_client(self, client, cleanup_only = False):
		# TODO: options etc
		if cleanup_only:
			client.on_disconnect(client)
			client.close()
			self.clients_guard.acquire()
			self.clients.remove(client)
			self.clients_guard.release()
			return
		
		client.close()
		if client in self.clients:
			self.clients.remove(client)
		
	'''
		Gate server handlers
	'''
	
	def on_receive_config_noticement(self, noticement):
		self.noticement = noticement.rstrip()
	
	def on_response_registergameserver(self, success, gsid = None):
		if not success:
			print 'Game server %s registration rejected!' % self.server_name
			return
		
		self.gsid = gsid
		
		print 'Game server %s registration success! (GSID:%r)' % (self.server_name, gsid)
		
		for i, socket in enumerate(self.logsockets):
			if not socket.connected:
				print 'Connecting gate server socket-%d!' % (i, )
				socket.connect()
				
		self.on_server_registered()
			
	def on_response_playerdata(self, char_name, player_data):
		try:
			client, = filter(lambda _: _.char_name, self.clients)
		except ValueError as e:
			print '(O) Got unknown player data %r' % char_name
			return
		
		if not player_data:
			print '(HACK?) Not existing character(%s) data request! Rejected!' % (char_name, )
			self.delete_client(client)
			return
		
		if player_data.map_name not in self.maps:
			print 'Player stuck on not existing map "%s" !' % (player_data.map_name, )
			self.delete_client(client)
			return
		
		maploc = self.maps[player_data.map_name]
		
		if (player_data.x, player_data.y) not in maploc:
			player_data.x, player_data.y = random.choice(maploc['initial-points'])
			print '%s new initial point is', player_data.x, player_data.y
			
		client.player_data = player_data
		client.map = maploc
				
		client.do_response_initplayer(success = True)
		
		# TODO : when you call it with success = False client will get 
		# 'World server full try other server'. Player limit could be 
		# implemented.
		
		self.getlogsocket().do_entergame_confirm(
			account_name = client.account_name,
			account_password = client.account_password,
			server_name = self.server_name,
			address = client.address,
			level = player_data.level
		)
		
		print '(TestLog) Enter Game Confirm Level: %d' % player_data.level
		
	'''
		Client socket handlers
	'''
	
	def client_on_request_initplayer(self, char_name, account_name, account_password, is_observer_mode, client):
		print 'Request init player'
		print char_name, account_name, account_password, is_observer_mode
		
		client.char_name = char_name
		client.account_name = account_name
		client.account_password = account_password
		
		self.getlogsocket().do_request_playerdata(
			char_name = char_name,
			account_name = account_name,
			account_password = account_password,
			address = client.address
		)
		
	def client_on_request_initdata(self, char_name, account_name, account_password, client):
		if client.char_name != char_name:
			print '(!) Error!', self.char_name, '!=', char_name
			self.delete_client(client)
			return
		client.do_playercharactercontents()
		client.do_response_initdata()
		
	def client_on_request_noticement(self, client, file_size):
		# Ignore client size of noticement data stored on disk and always
		# send new noticement.
		client.send_noticement(self.noticement)
				
	def client_on_request_fullobjectdata(self, client, object_id):
		print 'request fullobjectdata req:%d client:%d' % (object_id, client.id)
		try:
			obj, = filter(lambda _: _.id == object_id, self.clients)
		except ValueError as e:
			print '(!) Client requests full data from unknown object.'
			self.delete_client(client)
			return
		
		self.do_event_motion('stop', obj)