Пример #1
0
class DummyController:
    def __init__(self, proto_id, addr, s_addr, delay=0.09):

        self.gg_c = GGClient(proto_id, addr, s_addr)
        self.id = None
        self.delay = delay

        self.connect_start = None
        self.connect_end = None
        self.connect_event = Event()

        self.update_start = None
        self.update_end = None
        self.update_event = Event()

        self.kill_start = None
        self.kill_end = None
        self.kill_event = Event()
        self.kill_report_id = None

        self.reconnect_start = []
        self.reconnect_end = []
        self.reconnect_lock = Lock()
        self.reconnect_count = 0

        self.server = None

    def get_conn_interval(self):
        self.connect_event.wait()
        self.connect_event.clear()

        return (self.connect_start, self.connect_end)

    def get_update_interval(self):
        self.update_event.wait()
        self.update_event.clear()

        return (self.update_start, self.update_end)

    def get_kill_interval(self):
        self.kill_event.wait()
        self.kill_event.clear()

        return (self.kill_start, self.kill_end)

    def get_reconnect_intervals(self):
        with self.reconnect_lock:
            return (self.reconnect_start, self.reconnect_end)

    def start(self):
        self.gg_c.add_hook(MessageType.UserDisconnected,
                           self.__on_user_kill_disc)
        self.gg_c.add_hook(MessageType.UserKilled, self.__on_user_kill_disc)
        self.gg_c.add_hook(MessageType.UsersUpdate, self.__on_user_update)

        self.gg_c.add_hook(MessageType.ConnectTo, self.__connect_to)

        self.connect_start = time()
        self.__connect()

    def __on_user_kill_disc(self, data):

        uid, t = unpack('=Id', data)

        print("got kill")

        if uid != self.kill_report_id:
            return

        self.kill_end = time()
        self.kill_event.set()
        self.kill_report_id = None

    def __connect_to(self, data):

        s1, s2, s3, s4, s_port = unpack("=BBBBI", data)
        s_addr = str(s1) + "." + str(s2) + "." + str(s3) + "." + str(s4)

        with self.reconnect_lock:
            self.reconnect_start.append(time())
            self.reconnect_count += 1

        #print("[Controller]: -reconnecting to {}".format((s_addr, s_port)))
        self.server = (s_addr, s_port)

        self.__disconnect()
        self.gg_c.connect_to_server(s_addr, s_port)

        with self.reconnect_lock:
            self.reconnect_end.append(time())

    def report_kill(self, k_id):

        self.kill_start = time()
        self.kill_report_id = k_id

        print("[Controller]: -Reporting kill on {}".format(k_id))
        m_t = pack("=BId", int(MessageType.UserKilled), k_id, time())
        self.gg_c.send(m_t)

    def report_update(self, x, y):
        print("[Controller]: -updating with {}".format((x, y)))
        self.update_start = time()

        m_t = pack("=BIIBd", int(MessageType.UsersUpdate), x, y, Directions(0),
                   time())
        self.gg_c.send(m_t)

    def __on_user_update(self, data):
        x, y, o, uid, t = unpack('=IIBId', data)

        if uid != self.id:
            return

        print("[Controller]: -User update")

        if not self.update_event.is_set():
            self.update_event.set()
            self.update_end = time()

    def __connect(self):
        print("[Controller]: -Connecting to main server")
        self.gg_c.connect()
        print("[Controller]: -Connected")
        self.x, self.y, o, self.id = self.gg_c.wait_id()
        self.server = self.gg_c.server
        self.connect_end = time()
        self.connect_event.set()

    def __disconnect(self):
        #print("[Controller]: -Reporting")
        m_t = pack("=I", int(MessageType.UserDisconnected))
        self.gg_c.send(m_t)
Пример #2
0
class Controller:
    def __init__(self,
                 screen,
                 p_tank_i,
                 e_tank_i,
                 bg,
                 proto_id,
                 addr,
                 s_addr,
                 pygame_q,
                 bulled_dims=(3, 3),
                 delay=0.09):

        self.gg_c = GGClient(proto_id, addr, s_addr)
        self.tanks = {}
        self.screen = screen
        self.died = Event()
        self.p_tank_img = p_tank_i
        self.e_tank_img = e_tank_i
        self.bullet_dimentions = bulled_dims
        self.id = None

        self.pygame_q = pygame_q

        self.bg = bg

        self.last_user_updates = {}
        self.last_user_fire = {}
        self.delay = delay

        self.p_e_queuer = Thread(target=self.__pygame_e_queuer_w)
        self.p_queuer_stop_e = Event()

    def __del__(self):
        self.__disconnect()
        self.p_queuer_stop_e.set()

    def start(self):
        self.gg_c.add_hook(MessageType.UserConnected, self.__on_new_user)
        self.gg_c.add_hook(MessageType.UserFired, self.__on_user_fire)
        self.gg_c.add_hook(MessageType.UsersUpdate, self.__on_user_update)
        self.gg_c.add_hook(MessageType.UserDisconnected,
                           self.__on_user_kill_disc)
        self.gg_c.add_hook(MessageType.UserKilled, self.__on_user_kill_disc)
        self.gg_c.add_hook(MessageType.UsersPositions,
                           self.__on_users_positions)

        self.gg_c.add_hook(MessageType.ConnectTo, self.__connect_to)

        self.__connect()
        self.p_e_queuer.start()

    def __connect_to(self, data):

        s1, s2, s3, s4, s_port = unpack("=BBBBI", data)
        s_addr = str(s1) + "." + str(s2) + "." + str(s3) + "." + str(s4)

        print("[Controller]: -reconnecting to {}".format((s_addr, s_port)))

        self.__disconnect()
        self.gg_c.connect_to_server(s_addr, s_port)

    def __pygame_e_queuer_w(self):
        while not self.p_queuer_stop_e.is_set():
            for e in pygame.event.get():
                if e is None:
                    continue

                try:
                    self.pygame_q.put_nowait(e)
                except:
                    print(
                        "[Controller]: -pygameq is full with {}. Maybe try a different size"
                        .format(self.pygame_q.qsize()))
                    sys.exit(1)

    def get_event(self):
        return self.pygame_q.get()

    def report_update(self, x, y):
        if self.died.is_set():
            return

        now = time()
        tank = self.tanks[self.id]

        if tank.last_local_update and now - tank.last_local_update < 0.04:
            return

        t_x, t_y, t_o = tank.s_move([x, y])
        print("[Controller]: -tank is at {}, updating with {}".format(
            tank.rect.topleft, (t_x, t_y)))

        m_t = pack("=BIIBd", int(MessageType.UsersUpdate), t_x, t_y, t_o,
                   time())
        self.gg_c.send(m_t)

    def create_tank(self, data, ours=False):
        if ours:
            img = self.p_tank_img
        else:
            img = self.e_tank_img

        return Tank(data["uid"], img, self.screen, self.bullet_dimentions,
                    [data["x"], data["y"]], Directions(data["o"]))

    def report_fire(self):
        if self.died.is_set():
            return

        tank = self.tanks[self.id]
        t_x, t_y, t_o = tank.get_local_pos()

        m_t = pack("=BIIBd", int(MessageType.UserFired), t_x, t_y, t_o, time())

        self.gg_c.send(m_t)

    def __report_kill(self, k_id):
        print("[Controller]: -Reporting kill on {}".format(k_id))
        m_t = pack("=BId", int(MessageType.UserKilled), k_id, time())
        self.gg_c.send(m_t)

    def __disconnect(self):
        print("[Controller]: -Reporting")
        m_t = pack("=I", int(MessageType.UserDisconnected))
        self.gg_c.send(m_t)

    def __connect(self):
        print("[Controller]: -Connecting to main server")
        self.gg_c.connect()
        print("[Controller]: -Connected")
        x, y, o, self.id = self.gg_c.wait_id()
        self.last_user_updates[self.id] = 0
        self.tanks[self.id] = Tank(self.id, self.p_tank_img,
                                   self.screen, self.bullet_dimentions, [x, y],
                                   Directions(o))

    def on_new_user(self, data):
        self.tanks[data["uid"]] = self.create_tank(data)

    def __on_new_user(self, data):
        print("[Controller]: -Got new user")
        x, y, o, uid = unpack('=IIBI', data)

        self.last_user_updates[uid] = time()

        e_d = {"x": x, "y": y, "o": o, "uid": uid}

        e = pygame.event.Event(server_update_event, {
            "g_type": "new",
            "data": e_d
        })

        try:
            self.pygame_q.put_nowait(e)
        except:
            print(
                "[Controller]: -pygameq is full with {}. Maybe try a different size"
                .format(self.pygame_q.qsize()))
            sys.exit(1)

    def on_user_update(self, data):

        t_id = data["uid"]

        if t_id not in self.tanks.keys():
            return

        tank = self.tanks[t_id]

        old_x, old_y, _ = tank.get_pos()

        print(
            "[Controller]: ------------tankk is at {}, updating to {}".format(
                (old_x, old_y), (data["x"], data["y"])))
        if (old_x, old_y) == (data["x"], data["y"]):
            print("[Controller]: -egale")
            return

        tank.move([data["x"] - old_x, data["y"] - old_y], data["t"])
        tank.update_o(data["o"])

    def __on_user_update(self, data):
        x, y, o, uid, t = unpack('=IIBId', data)

        print("[Controller]: -User update")
        if uid not in self.last_user_updates.keys():
            print("[Controller]: -r 1")
            return

        last_update = self.last_user_updates[uid]

        if last_update > t:
            print("[Controller]: -r 2")
            return

        if t - last_update < self.delay:
            print("[Controller]: -r 3")
            return

        e_d = {"x": x, "y": y, "o": o, "uid": uid, "t": t}

        e = pygame.event.Event(server_update_event, {
            "g_type": "upd",
            "data": e_d
        })

        self.last_user_updates[uid] = t

        try:
            self.pygame_q.put_nowait(e)
        except:
            print(
                "[Controller]: -pygameq is full with {}. Maybe try a different size"
                .format(self.pygame_q.qsize()))
            sys.exit(1)

    def on_user_fire(self, data):
        tank = self.tanks[data["uid"]]

        tank.update_o(Directions(data["o"]))

        tank.fire(data["t"])

    def __on_user_fire(self, data):
        x, y, o, uid, t = unpack('=IIBId', data)

        if uid not in self.last_user_fire.keys():
            self.last_user_fire[uid] = 0

        last_fired = self.last_user_fire[uid]

        if last_fired > t:
            return

        if t - last_fired < self.delay:
            return

        self.last_user_fire[uid] = t

        e_d = {"o": o, "uid": uid, "t": t}

        e = pygame.event.Event(server_update_event, {
            "g_type": "fire",
            "data": e_d
        })

        try:
            self.pygame_q.put_nowait(e)
        except:
            print(
                "[Controller]: -pygameq is full with {}. Maybe try a different size"
                .format(self.pygame_q.qsize()))
            sys.exit(1)

    def on_users_positions(self, data):
        print("[Controller]: -Got one user x: {}, y:{}".format(
            data["x"], data["y"]))
        self.tanks[data["uid"]] = self.create_tank(data)

    def __on_users_positions(self, data):
        print("[Controller]: -Got users positions with {}".format(len(data)))

        (n_clients, ) = unpack("=I", data[:4])
        data = data[4:]

        for _ in range(0, n_clients):

            x, y, o, uid = unpack("=IIBI", data[:13])

            self.last_user_updates[uid] = time()

            e_d = {"x": x, "y": y, "o": o, "uid": uid}

            e = pygame.event.Event(server_update_event, {
                "g_type": "pos",
                "data": e_d
            })

            try:
                self.pygame_q.put_nowait(e)
            except:
                print(
                    "[Controller]: -pygameq is full with {}. Maybe try a different size"
                    .format(self.pygame_q.qsize()))
                sys.exit(1)

            data = data[13:]

    def on_user_kill_disc(self, data):
        if data["uid"] == self.gg_c.id:
            self.died.set()

        self.tanks.pop(data["uid"], None)

    def __on_user_kill_disc(self, data):

        uid, t = unpack('=Id', data)

        self.last_user_fire.pop(uid, None)
        self.last_user_updates.pop(uid, None)

        e_d = {"uid": uid, "t": t}

        e = pygame.event.Event(server_update_event, {
            "g_type": "kill",
            "data": e_d
        })

        try:
            self.pygame_q.put_nowait(e)
        except:
            print(
                "[Controller]: -pygameq is full with {}. Maybe try a different size"
                .format(self.pygame_q.qsize()))
            sys.exit(1)

    def worker_draw_and_report(self):

        self.screen.blit(self.bg, (0, 0))

        if self.id is None or self.id not in self.tanks.keys():
            return

        our_t = self.tanks[self.id]
        their_ts = [
            tank.rect for tank in self.tanks.values() if tank.id != self.id
        ]
        their_ids = [uid for uid in self.tanks.keys() if uid != self.id]
        our_b = [bullet.get_rect() for bullet in our_t.bullets]

        if not self.died.is_set():
            tanks_i = our_t.rect.collidelist(their_ts)
            if tanks_i != -1:
                print("[Controller]: -Reporting kill on {} from collision. My poz: ({}), their: ({})"\
                .format(their_ids[tanks_i], our_t.rect.topleft, \
                self.tanks[their_ids[tanks_i]].rect.topleft))
                self.__report_kill(their_ids[tanks_i])
                self.__report_kill(self.gg_c.id)
                self.tanks.pop(their_ids[tanks_i], None)

                del their_ids[tanks_i]
                del their_ts[tanks_i]

                self.died.set()
                #TODO: Say that we died and stop sending update reports

        bullet_inds = []
        for ind, bullet in enumerate(our_b):
            bullet_i = bullet.collidelist(their_ts)

            if bullet_i != -1:
                print(
                    "[Controller]: -Reporting kill from bullets on {}. Got him with bullet {} of {}"
                    .format(their_ids[bullet_i], ind, len(our_b)))
                self.__report_kill(their_ids[bullet_i])
                self.tanks.pop(their_ids[bullet_i], None)

                del their_ids[bullet_i]
                del their_ts[bullet_i]

                bullet_inds.append(ind)

        bullet_inds.reverse()
        for b_i in bullet_inds:
            del our_t.bullets[b_i]

        for tank in self.tanks.values():
            inds = []
            for ind, bullet in enumerate(tank.bullets):
                if not bullet.update():
                    inds.append(ind)

            inds.reverse()
            for ind in inds:
                del tank.bullets[ind]

            tank.draw()
            for bullet in tank.bullets:
                bullet.draw()

        if not self.died.is_set():
            our_t.draw()

        for bullet in our_t.bullets:
            bullet.draw()

        pygame.display.flip()