예제 #1
0
def load_ghosts(player_id, state, ghosts):
    folder = '%s/%s/ghosts/%s/%s' % (STORAGE_DIR, player_id,
                                     zo.get_course(state), zo.road_id(state))
    if not zo.is_forward(state): folder += '/reverse'
    if not os.path.isdir(folder): return
    s = list()
    for f in os.listdir(folder):
        if f.endswith('.bin'):
            with open(os.path.join(folder, f), 'rb') as fd:
                g = ghosts.play.ghosts.add()
                g.ParseFromString(fd.read())
                s.append(g.states[0].roadTime)
    ghosts.start_road = zo.road_id(state)
    ghosts.start_rt = 0
    if os.path.isfile(START_LINES_FILE):
        with open(START_LINES_FILE, 'r') as fd:
            sl = [tuple(line) for line in csv.reader(fd)]
            rt = [
                t for t in sl if t[0] == str(zo.get_course(state))
                and t[1] == str(zo.road_id(state)) and (
                    boolean(t[2]) == zo.is_forward(state) or not t[2])
            ]
            if rt:
                ghosts.start_road = int(rt[0][3])
                ghosts.start_rt = int(rt[0][4])
    if not ghosts.start_rt:
        s.append(state.roadTime)
        if zo.is_forward(state): ghosts.start_rt = max(s)
        else: ghosts.start_rt = min(s)
    for g in ghosts.play.ghosts:
        try:
            while zo.road_id(g.states[0]) != ghosts.start_road:
                del g.states[0]
            if zo.is_forward(g.states[0]):
                while g.states[0].roadTime < ghosts.start_rt or abs(
                        g.states[0].roadTime - ghosts.start_rt) > 500000:
                    del g.states[0]
            else:
                while g.states[0].roadTime > ghosts.start_rt or abs(
                        g.states[0].roadTime - ghosts.start_rt) > 500000:
                    del g.states[0]
        except IndexError:
            pass
예제 #2
0
def save_ghost(name, player_id):
    global global_ghosts
    if not player_id in global_ghosts.keys(): return
    ghosts = global_ghosts[player_id]
    if len(ghosts.rec.states) > 0:
        folder = '%s/%s/ghosts/%s/%s' % (STORAGE_DIR, player_id,
                                         zo.get_course(ghosts.rec.states[0]),
                                         zo.road_id(ghosts.rec.states[0]))
        if not zo.is_forward(ghosts.rec.states[0]): folder += '/reverse'
        try:
            if not os.path.isdir(folder):
                os.makedirs(folder)
        except Exception as exc:
            print('save_ghost: %s' % repr(exc))
        f = '%s/%s-%s.bin' % (
            folder, zo.get_utc_date_time().strftime("%Y-%m-%d-%H-%M-%S"), name)
        with open(f, 'wb') as fd:
            fd.write(ghosts.rec.SerializeToString())
    ghosts.rec = None
예제 #3
0
def organize_ghosts(player_id):
    # organize ghosts in course/road_id directory structure
    # previously they were saved directly in player_id/ghosts
    folder = '%s/%s/ghosts' % (STORAGE_DIR, player_id)
    if not os.path.isdir(folder): return
    for f in os.listdir(folder):
        if f.endswith('.bin'):
            file = os.path.join(folder, f)
            with open(file, 'rb') as fd:
                g = udp_node_msgs_pb2.Ghost()
                g.ParseFromString(fd.read())
                dest = '%s/%s/%s' % (folder, zo.get_course(
                    g.states[0]), zo.road_id(g.states[0]))
                if not zo.is_forward(g.states[0]): dest += '/reverse'
                try:
                    if not os.path.isdir(dest):
                        os.makedirs(dest)
                except Exception as exc:
                    print('organize_ghosts: %s' % repr(exc))
            os.rename(file, os.path.join(dest, f))
예제 #4
0
    def handle(self):
        data = self.request[0]
        socket = self.request[1]
        recv = udp_node_msgs_pb2.ClientToServer()

        try:
            recv.ParseFromString(data[:-4])
        except:
            try:
                #If no sensors connected, first byte must be skipped
                recv.ParseFromString(data[1:-4])
            except Exception as exc:
                print('UDPHandler ParseFromString exception: %s' % repr(exc))
                return

        client_address = self.client_address
        player_id = recv.player_id
        state = recv.state

        #Add last updates for player if missing
        if not player_id in last_pp_updates.keys():
            last_pp_updates[player_id] = 0
        if not player_id in last_bot_updates.keys():
            last_bot_updates[player_id] = 0

        t = int(zo.get_utc_time())

        #Update player online state
        if state.roadTime:
            if player_id in online.keys():
                if online[player_id].worldTime > state.worldTime:
                    return  #udp is unordered -> drop old state
            elif time.time() > start_time + 10:
                discord.change_presence(len(online) + 1)
            online[player_id] = state

        #Add handling of ghosts for player if it's missing
        if not player_id in global_ghosts.keys():
            global_ghosts[player_id] = GhostsVariables()

        ghosts = global_ghosts[player_id]
        ghosts.last_package_time = t

        if recv.seqno == 1:
            ghosts.rec = None
            organize_ghosts(player_id)

        #Changed course
        if zo.get_course(state) and ghosts.course != zo.get_course(state):
            ghosts.rec = None
            ghosts.course = zo.get_course(state)

        if ghosts.rec == None:
            ghosts.rec = udp_node_msgs_pb2.Ghost()
            ghosts.play = udp_node_msgs_pb2.Ghosts()
            ghosts.last_rt = 0
            ghosts.play_count = 0
            ghosts.loaded = False
            ghosts.started = False
            ghosts.rec.player_id = player_id

        if player_id in ghosts_enabled and ghosts_enabled[player_id]:
            #Load ghosts for current course
            if not ghosts.loaded and zo.get_course(state):
                ghosts.loaded = True
                load_ghosts(player_id, state, ghosts)
            #Save player state as ghost if moving
            if state.roadTime and ghosts.last_rt and state.roadTime != ghosts.last_rt:
                if t >= ghosts.last_rec + ghost_update_freq:
                    s = ghosts.rec.states.add()
                    s.CopyFrom(state)
                    ghosts.last_rec = t
                #Start loaded ghosts
                if not ghosts.started and ghosts.play.ghosts and zo.road_id(
                        state) == ghosts.start_road:
                    if zo.is_forward(state):
                        if state.roadTime > ghosts.start_rt and abs(
                                state.roadTime - ghosts.start_rt) < 500000:
                            ghosts.started = True
                    else:
                        if state.roadTime < ghosts.start_rt and abs(
                                state.roadTime - ghosts.start_rt) < 500000:
                            ghosts.started = True
            #Uncomment to print player state when stopped (to find new start lines)
            #else: print('course', zo.get_course(state), 'road', zo.road_id(state), 'isForward', zo.is_forward(state), 'roadTime', state.roadTime)
            ghosts.last_rt = state.roadTime

        #Set state of player being watched
        watching_state = None
        if state.watchingRiderId == player_id:
            watching_state = state
        elif state.watchingRiderId in online.keys():
            watching_state = online[state.watchingRiderId]
        elif state.watchingRiderId in global_pace_partners.keys():
            pp = global_pace_partners[state.watchingRiderId]
            watching_state = pp.route.states[pp.position]
        elif state.watchingRiderId in global_bots.keys():
            bot = global_bots[state.watchingRiderId]
            watching_state = bot.route.states[bot.position]
        elif state.watchingRiderId > 10000000:
            ghost = ghosts.play.ghosts[math.floor(state.watchingRiderId /
                                                  10000000) - 1]
            if len(ghost.states) > ghosts.play_count:
                watching_state = ghost.states[ghosts.play_count]

        #Check if online players, pace partners, bots and ghosts are nearby
        nearby = list()
        for p_id in online.keys():
            player = online[p_id]
            if player.id != player_id and zo.is_nearby(
                    watching_state, player) and is_state_new_for(
                        player, player_id):
                nearby.append(p_id)
        if t >= last_pp_updates[player_id] + pacer_update_freq:
            last_pp_updates[player_id] = t
            for p_id in global_pace_partners.keys():
                pace_partner_variables = global_pace_partners[p_id]
                pace_partner = pace_partner_variables.route.states[
                    pace_partner_variables.position]
                if zo.is_nearby(watching_state, pace_partner):
                    nearby.append(p_id)
        if t >= last_bot_updates[player_id] + bot_update_freq:
            last_bot_updates[player_id] = t
            for p_id in global_bots.keys():
                bot_variables = global_bots[p_id]
                bot = bot_variables.route.states[bot_variables.position]
                if zo.is_nearby(watching_state, bot):
                    nearby.append(p_id)
        if ghosts.started and t >= ghosts.last_play + ghost_update_freq:
            ghosts.last_play = t
            ghost_id = 1
            for g in ghosts.play.ghosts:
                if len(g.states) > ghosts.play_count and zo.is_nearby(
                        watching_state, g.states[ghosts.play_count]):
                    nearby.append(player_id + ghost_id * 10000000)
                ghost_id += 1
            ghosts.play_count += 1

        #Send nearby riders states or empty message
        message = get_empty_message(player_id)
        if nearby:
            message.num_msgs = math.ceil(len(nearby) / 10)
            for p_id in nearby:
                player = None
                if p_id in online.keys():
                    player = online[p_id]
                elif p_id in global_pace_partners.keys():
                    pace_partner_variables = global_pace_partners[p_id]
                    player = pace_partner_variables.route.states[
                        pace_partner_variables.position]
                elif p_id in global_bots.keys():
                    bot_variables = global_bots[p_id]
                    player = bot_variables.route.states[bot_variables.position]
                elif p_id > 10000000:
                    player = udp_node_msgs_pb2.PlayerState()
                    player.CopyFrom(
                        ghosts.play.ghosts[math.floor(p_id / 10000000) -
                                           1].states[ghosts.play_count - 1])
                    player.id = p_id
                    player.worldTime = zo.world_time()
                if player != None:
                    if len(message.states) > 9:
                        message.world_time = zo.world_time()
                        message.cts_latency = message.world_time - recv.world_time
                        socket.sendto(message.SerializeToString(),
                                      client_address)
                        message.msgnum += 1
                        del message.states[:]
                    s = message.states.add()
                    s.CopyFrom(player)
        else:
            message.num_msgs = 1
        message.world_time = zo.world_time()
        message.cts_latency = message.world_time - recv.world_time
        socket.sendto(message.SerializeToString(), client_address)