def loadGhosts(player_id, state): global play global spawn if not player_id: return folder = '%s/%s/ghosts/load' % (STORAGE_DIR, player_id) if not os.path.isdir(folder): return s = list() for (root, dirs, files) in os.walk(folder): for f in files: if f.endswith('.bin'): with open(os.path.join(root, f), 'rb') as fd: g = udp_node_msgs_pb2.Ghost() g.ParseFromString(fd.read()) if course(g.states[0]) == course(state) and roadID( g.states[0]) == roadID(state) and isForward( g.states[0]) == isForward(state): h = play.ghosts.add() h.CopyFrom(g) s.append(g.states[0].roadTime) s.append(state.roadTime) if isForward(state): spawn = max(s) else: spawn = min(s) for g in play.ghosts: if isForward(g.states[0]): while g.states[0].roadTime < spawn: del g.states[0] else: while g.states[0].roadTime > spawn: del g.states[0]
def load_bots(): if not os.path.isdir(BOTS_DIR): return for (root, dirs, files) in os.walk(BOTS_DIR): for bot_id in dirs: p_id = int(bot_id) route = '%s/%s/route.bin' % (BOTS_DIR, bot_id) if os.path.isfile(route): with open(route, 'rb') as fd: global_bots[p_id] = BotVariables() bot = global_bots[p_id] bot.route = udp_node_msgs_pb2.Ghost() bot.route.ParseFromString(fd.read()) bot.position = 0
def load_pace_partners(): if not os.path.isdir(PACE_PARTNERS_DIR): return for (root, dirs, files) in os.walk(PACE_PARTNERS_DIR): for pp_id in dirs: p_id = int(pp_id) route = '%s/%s/route.bin' % (PACE_PARTNERS_DIR, pp_id) if os.path.isfile(route): with open(route, 'rb') as fd: global_pace_partners[p_id] = PacePartnerVariables() pp = global_pace_partners[p_id] pp.route = udp_node_msgs_pb2.Ghost() pp.route.ParseFromString(fd.read()) pp.position = 0
def loadGhosts(player_id, state): global play global start_road global start_rt if not player_id: return folder = '%s/%s/ghosts/load' % (STORAGE_DIR, player_id) if not os.path.isdir(folder): return s = list() for (root, dirs, files) in os.walk(folder): for f in files: if f.endswith('.bin'): with open(os.path.join(root, f), 'rb') as fd: g = udp_node_msgs_pb2.Ghost() g.ParseFromString(fd.read()) if course(g.states[0]) == course(state) and roadID(g.states[0]) == roadID(state) and isForward( g.states[0]) == isForward(state): h = play.ghosts.add() h.CopyFrom(g) s.append(g.states[0].roadTime) start_road = roadID(state) start_rt = 0 sl_file = '%s/start_lines.csv' % STORAGE_DIR if os.path.isfile(sl_file): with open(sl_file, 'r') as fd: sl = [tuple(line) for line in csv.reader(fd)] rt = [t for t in sl if t[0] == str(course(state)) and t[1] == str(roadID(state)) and ( t[2] == str(isForward(state)) or not t[2])] if rt: start_road = int(rt[0][3]) start_rt = int(rt[0][4]) if not start_rt: s.append(state.roadTime) if isForward(state): start_rt = max(s) else: start_rt = min(s) for g in play.ghosts: while roadID(g.states[0]) != start_road: del g.states[0] if isForward(g.states[0]): while not (g.states[0].roadTime <= start_rt <= g.states[1].roadTime): del g.states[0] else: while not (g.states[0].roadTime >= start_rt >= g.states[1].roadTime): del g.states[0]
def organizeGhosts(player_id): # organize ghosts in course/roadID 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, course(g.states[0]), roadID(g.states[0])) if not isForward(g.states[0]): dest += '/reverse' try: if not os.path.isdir(dest): os.makedirs(dest) except: return os.rename(file, os.path.join(dest, f))
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: 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_updates.keys(): last_updates[player_id] = 0 if not player_id in last_online_updates.keys(): last_online_updates[player_id] = 0 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(zwift_offline.get_utc_time()) #Update player online state if state.roadTime and t >= last_updates[player_id] + online_update_freq: last_updates[player_id] = t if not player_id in online.keys(): discord.send_message('%s riders online' % (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 get_course(state) and ghosts.course != get_course(state): ghosts.rec = None ghosts.course = 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 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 road_id( state) == ghosts.start_road: if 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', get_course(state), 'road', road_id(state), 'isForward', 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() if t >= last_online_updates[player_id] + online_update_freq: last_online_updates[player_id] = t for p_id in online.keys(): player = online[p_id] if player.id != player_id and zwift_offline.is_nearby( watching_state, player): 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 zwift_offline.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 zwift_offline.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 zwift_offline.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 = ghosts.play.ghosts[math.floor(p_id / 10000000) - 1].states[ghosts.play_count - 1] player.id = p_id player.worldTime = zwift_offline.world_time() if player != None: if len(message.states) > 9: message.world_time = zwift_offline.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 = zwift_offline.world_time() socket.sendto(message.SerializeToString(), client_address)
STORAGE_DIR = "%s/storage" % os.path.dirname(sys.executable) START_LINES_FILE = '%s/start_lines.csv' % STORAGE_DIR if not os.path.isfile(START_LINES_FILE): copyfile('%s/start_lines.csv' % sys._MEIPASS, START_LINES_FILE) else: SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) CDN_DIR = "%s/cdn" % SCRIPT_DIR STORAGE_DIR = "%s/storage" % SCRIPT_DIR START_LINES_FILE = '%s/start_lines.csv' % SCRIPT_DIR PROXYPASS_FILE = "%s/cdn-proxy.txt" % STORAGE_DIR SERVER_IP_FILE = "%s/server-ip.txt" % STORAGE_DIR MAP_OVERRIDE = None ENABLEGHOSTS_FILE = "%s/enable_ghosts.txt" % STORAGE_DIR rec = udp_node_msgs_pb2.Ghost() play = udp_node_msgs_pb2.Ghosts() seqno = 1 last_rec = 0 last_play = 0 play_count = 0 last_rt = 0 ghosts_enabled = False ghosts_loaded = False ghosts_started = False start_road = 0 start_rt = 0 update_freq = 3 def roadID(state): return (state.f20 & 0xff00) >> 8
def handle(self): data = self.request[0] socket = self.request[1] recv = udp_node_msgs_pb2.ClientToServer() try: recv.ParseFromString(data[:-4]) except: try: recv.ParseFromString(data[3:-4]) except: return client_address = self.client_address player_id = recv.player_id state = recv.state nearby_state = state if state.watchingRiderId in online.keys(): nearby_state = online[state.watchingRiderId] elif state.watchingRiderId in global_pace_partners.keys(): pp = global_pace_partners[state.watchingRiderId] nearby_state = pp.route.states[pp.position] #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] #Add pace partner last update for player if it's missing if not player_id in last_pp_updates.keys(): last_pp_updates[player_id] = 0 last_pp_update = last_pp_updates[player_id] #Add bot last update for player if it's missing if not player_id in last_bot_updates.keys(): last_bot_updates[player_id] = 0 last_bot_update = last_bot_updates[player_id] if recv.seqno == 1 or 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 organize_ghosts(player_id) t = int(zwift_offline.get_utc_time()) ghosts.last_package_time = t if player_id in ghosts_enabled and ghosts_enabled[player_id]: if not ghosts.loaded and get_course(state): ghosts.loaded = True load_ghosts(player_id, state, ghosts) 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 if not ghosts.started and ghosts.play.ghosts and road_id( state) == ghosts.start_road: if is_forward(state): if state.roadTime >= ghosts.start_rt >= ghosts.last_rt: ghosts.started = True else: if state.roadTime <= ghosts.start_rt <= ghosts.last_rt: ghosts.started = True # else: print('course', get_course(state), 'road', road_id(state), 'isForward', is_forward(state), 'roadTime', state.roadTime) ghosts.last_rt = state.roadTime keys = online.keys() remove_players = list() for p_id in keys: if zwift_offline.world_time() > online[p_id].worldTime + 10000: remove_players.insert(0, p_id) for p_id in remove_players: online.pop(p_id) if state.roadTime: online[player_id] = state #Remove ghosts entries for inactive players (disconnected?) keys = global_ghosts.keys() remove_players = list() for p_id in keys: if global_ghosts[p_id].last_package_time < t - 10: remove_players.insert(0, p_id) for p_id in remove_players: global_ghosts.pop(p_id) if ghosts.started and t >= ghosts.last_play + ghost_update_freq: message = get_empty_message(player_id) active_ghosts = 0 for g in ghosts.play.ghosts: if len(g.states) > ghosts.play_count: active_ghosts += 1 if active_ghosts: message.num_msgs = active_ghosts // 10 if active_ghosts % 10: message.num_msgs += 1 ghost_id = 1 for g in ghosts.play.ghosts: if len(g.states) > ghosts.play_count: if len(message.states) < 10: state = message.states.add() state.CopyFrom(g.states[ghosts.play_count]) state.id = player_id + ghost_id * 10000000 state.worldTime = zwift_offline.world_time() else: message.world_time = zwift_offline.world_time() socket.sendto(message.SerializeToString(), client_address) message.msgnum += 1 del message.states[:] state = message.states.add() state.CopyFrom(g.states[ghosts.play_count]) state.id = player_id + ghost_id * 10000000 state.worldTime = zwift_offline.world_time() ghost_id += 1 else: message.num_msgs = 1 message.world_time = zwift_offline.world_time() socket.sendto(message.SerializeToString(), client_address) ghosts.play_count += 1 ghosts.last_play = t message = get_empty_message(player_id) nearby = list() for p_id in online.keys(): player = online[p_id] if player.id != player_id: #Check if players are close in world if zwift_offline.is_nearby(nearby_state, player): nearby.append(p_id) if t >= last_pp_update + 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] #Check if pacepartner is close to player in world if zwift_offline.is_nearby(nearby_state, pace_partner): nearby.append(p_id) if t >= last_bot_update + 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] #Check if bot is close to player in world if zwift_offline.is_nearby(nearby_state, bot): nearby.append(p_id) players = len(nearby) message.num_msgs = players // 10 if players % 10: message.num_msgs += 1 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] if player != None: if len(message.states) < 10: state = message.states.add() state.CopyFrom(player) else: message.world_time = zwift_offline.world_time() socket.sendto(message.SerializeToString(), client_address) message.msgnum += 1 del message.states[:] state = message.states.add() state.CopyFrom(player) message.world_time = zwift_offline.world_time() socket.sendto(message.SerializeToString(), client_address)