mirror of
https://github.com/zoffline/zwift-offline.git
synced 2025-12-05 20:40:03 -08:00
Add option to announce joining and leaving players
This commit is contained in:
@@ -370,6 +370,7 @@ To enable support for multiple users perform the steps below:
|
||||
channel =
|
||||
welcome_message =
|
||||
help_message =
|
||||
announce_players =
|
||||
```
|
||||
</details>
|
||||
|
||||
|
||||
@@ -11,11 +11,12 @@ import zwift_offline
|
||||
|
||||
|
||||
class DiscordBot(discord.Client):
|
||||
def __init__(self, intents, channel, welcome_msg, help_msg):
|
||||
def __init__(self, intents, channel, welcome_msg, help_msg, announce):
|
||||
discord.Client.__init__(self, intents=intents)
|
||||
self.channel_id = channel
|
||||
self.welcome_msg = welcome_msg
|
||||
self.help_msg = help_msg
|
||||
self.announce = announce
|
||||
|
||||
async def on_ready(self):
|
||||
self.channel = self.get_channel(self.channel_id)
|
||||
@@ -49,8 +50,9 @@ class DiscordThread(threading.Thread):
|
||||
self.token = self.CONFIG.get(SECTION, 'token')
|
||||
self.webhook = self.CONFIG.get(SECTION, 'webhook')
|
||||
self.channel = self.CONFIG.getint(SECTION, 'channel')
|
||||
self.welcome_msg = self.CONFIG.get(SECTION, 'welcome_message')
|
||||
self.help_msg = self.CONFIG.get(SECTION, 'help_message')
|
||||
self.welcome_msg = self.CONFIG.get(SECTION, 'welcome_message', fallback='')
|
||||
self.help_msg = self.CONFIG.get(SECTION, 'help_message', fallback='')
|
||||
self.announce = self.CONFIG.getboolean(SECTION, 'announce_players', fallback=False)
|
||||
|
||||
self.intents = discord.Intents.default()
|
||||
self.intents.members = True
|
||||
@@ -59,7 +61,7 @@ class DiscordThread(threading.Thread):
|
||||
self.start()
|
||||
|
||||
async def starter(self):
|
||||
self.discord_bot = DiscordBot(self.intents, self.channel, self.welcome_msg, self.help_msg)
|
||||
self.discord_bot = DiscordBot(self.intents, self.channel, self.welcome_msg, self.help_msg, self.announce)
|
||||
await self.discord_bot.start(self.token)
|
||||
|
||||
def run(self):
|
||||
|
||||
@@ -72,6 +72,7 @@ else:
|
||||
pass
|
||||
def change_presence(self, n):
|
||||
pass
|
||||
announce = False
|
||||
discord = DummyDiscord()
|
||||
|
||||
bot_update_freq = 3
|
||||
@@ -399,6 +400,16 @@ class GhostsVariables:
|
||||
start_road = 0
|
||||
start_rt = 0
|
||||
|
||||
def get_routes():
|
||||
with open('%s/data/start_lines.txt' % SCRIPT_DIR) as fd:
|
||||
return json.load(fd, object_hook=lambda d: {int(k) if k.lstrip('-').isdigit() else k: v for k, v in d.items()})
|
||||
|
||||
def get_route_name(state):
|
||||
routes = get_routes()
|
||||
if state.route in routes:
|
||||
return routes[state.route]['name']
|
||||
return zo.courses_lookup[zo.get_course(state)]
|
||||
|
||||
def load_ghosts_folder(folder, ghosts):
|
||||
if os.path.isdir(folder):
|
||||
for f in os.listdir(folder):
|
||||
@@ -419,11 +430,10 @@ def load_ghosts(player_id, state, ghosts):
|
||||
load_ghosts_folder('%s/%s' % (folder, state.route), ghosts)
|
||||
ghosts.start_road = zo.road_id(state)
|
||||
ghosts.start_rt = state.roadTime
|
||||
with open('%s/data/start_lines.txt' % SCRIPT_DIR) as fd:
|
||||
sl = json.load(fd, object_hook=lambda d: {int(k) if k.lstrip('-').isdigit() else k: v for k, v in d.items()})
|
||||
if state.route in sl:
|
||||
ghosts.start_road = sl[state.route]['road']
|
||||
ghosts.start_rt = sl[state.route]['time']
|
||||
sl = get_routes()
|
||||
if state.route in sl:
|
||||
ghosts.start_road = sl[state.route]['road']
|
||||
ghosts.start_rt = sl[state.route]['time']
|
||||
|
||||
def regroup_ghosts(player_id):
|
||||
p = online[player_id]
|
||||
@@ -555,9 +565,14 @@ def play_bots():
|
||||
def remove_inactive():
|
||||
while True:
|
||||
for p_id in list(online.keys()):
|
||||
if zo.world_time() > online[p_id].worldTime + 10000:
|
||||
if zo.world_time() > online[p_id].worldTime + 30000:
|
||||
zo.save_bookmark(online[p_id], 'Last ' + ('run' if online[p_id].sport == profile_pb2.Sport.RUNNING else 'ride'))
|
||||
online.pop(p_id)
|
||||
discord.change_presence(len(online))
|
||||
if discord.announce:
|
||||
discord.send_message("Leaving", p_id)
|
||||
zo.logout_player(p_id)
|
||||
time.sleep(1)
|
||||
time.sleep(5)
|
||||
|
||||
def is_state_new_for(peer_player_state, player_id):
|
||||
if not player_id in global_news.keys():
|
||||
@@ -639,9 +654,12 @@ class UDPHandler(socketserver.BaseRequestHandler):
|
||||
if player_id in online.keys():
|
||||
if online[player_id].worldTime > state.worldTime:
|
||||
return #udp is unordered -> drop old state
|
||||
else:
|
||||
discord.change_presence(len(online) + 1)
|
||||
online[player_id] = state
|
||||
online[player_id] = state
|
||||
elif zo.world_time() < state.worldTime + 10000:
|
||||
online[player_id] = state
|
||||
discord.change_presence(len(online))
|
||||
if discord.announce:
|
||||
discord.send_message("%s in %s" % (('Running' if state.sport == profile_pb2.Sport.RUNNING else 'Riding'), get_route_name(state)), player_id)
|
||||
|
||||
#Add handling of ghosts for player if it's missing
|
||||
if not player_id in global_ghosts.keys():
|
||||
@@ -690,7 +708,7 @@ class UDPHandler(socketserver.BaseRequestHandler):
|
||||
nearby = {}
|
||||
for p_id in online.keys():
|
||||
player = online[p_id]
|
||||
if player.id != player_id:
|
||||
if player.id != player_id and zo.world_time() < player.worldTime + 10000:
|
||||
is_nearby, distance = nearby_distance(watching_state, player)
|
||||
if is_nearby and is_state_new_for(player, player_id):
|
||||
nearby[p_id] = distance
|
||||
|
||||
@@ -391,6 +391,7 @@ class PartialProfile:
|
||||
male = True
|
||||
weight_in_grams = 0
|
||||
imageSrc = ''
|
||||
time = 0
|
||||
def to_json(self):
|
||||
return {"countryCode": self.country_code,
|
||||
"enrolledZwiftAcademy": False, #don't need
|
||||
@@ -481,6 +482,10 @@ def get_partial_profile(player_id):
|
||||
partial_profile.player_id = player_id
|
||||
if player_id in global_pace_partners.keys():
|
||||
profile = global_pace_partners[player_id].profile
|
||||
for f in profile.public_attributes:
|
||||
if f.id == 1766985504: #crc32 of "PACE PARTNER - ROUTE"
|
||||
partial_profile.route = toSigned(f.number_value, 4) if f.number_value >= 0 else -toSigned(-f.number_value, 4)
|
||||
break
|
||||
elif player_id in global_bots.keys():
|
||||
profile = global_bots[player_id].profile
|
||||
elif player_id > 10000000:
|
||||
@@ -509,15 +514,8 @@ def get_partial_profile(player_id):
|
||||
partial_profile.player_type = profile_pb2.PlayerType.Name(jsf(profile, 'player_type', 1))
|
||||
partial_profile.male = profile.is_male
|
||||
partial_profile.weight_in_grams = profile.weight_in_grams
|
||||
for f in profile.public_attributes:
|
||||
#0x69520F20=1766985504 - crc32 of "PACE PARTNER - ROUTE"
|
||||
if f.id == 1766985504:
|
||||
if f.number_value >= 0:
|
||||
partial_profile.route = toSigned(f.number_value, 4)
|
||||
else:
|
||||
partial_profile.route = -toSigned(-f.number_value, 4)
|
||||
break
|
||||
player_partial_profiles[player_id] = partial_profile
|
||||
player_partial_profiles[player_id].time = time.monotonic()
|
||||
return player_partial_profiles[player_id]
|
||||
|
||||
|
||||
@@ -1420,31 +1418,20 @@ def relay_session_refresh():
|
||||
return refresh.SerializeToString(), 200
|
||||
|
||||
|
||||
def save_bookmark(state, name):
|
||||
bookmarks_dir = os.path.join(STORAGE_DIR, str(state.id), 'bookmarks', str(get_course(state)), str(state.sport))
|
||||
if not make_dir(bookmarks_dir):
|
||||
return
|
||||
with open(os.path.join(bookmarks_dir, name + '.bin'), 'wb') as f:
|
||||
f.write(state.SerializeToString())
|
||||
|
||||
def logout_player(player_id):
|
||||
#Remove player from online when leaving game/world
|
||||
if player_id in online:
|
||||
activity = 'run' if online[player_id].sport == profile_pb2.Sport.RUNNING else 'ride'
|
||||
save_bookmark(online[player_id], 'Last ' + activity)
|
||||
online.pop(player_id)
|
||||
discord.change_presence(len(online))
|
||||
if player_id in global_ghosts:
|
||||
del global_ghosts[player_id].rec.states[:]
|
||||
global_ghosts[player_id].play.clear()
|
||||
global_ghosts.pop(player_id)
|
||||
if player_id in player_partial_profiles:
|
||||
player_partial_profiles.pop(player_id)
|
||||
if player_id in global_bookmarks:
|
||||
global_bookmarks[player_id].clear()
|
||||
global_bookmarks.pop(player_id)
|
||||
|
||||
@app.route('/api/users/logout', methods=['POST'])
|
||||
@jwt_to_session_cookie
|
||||
@login_required
|
||||
def api_users_logout():
|
||||
logout_player(current_user.player_id)
|
||||
return '', 204
|
||||
|
||||
|
||||
@@ -3286,6 +3273,13 @@ def relay_worlds_hash_seeds():
|
||||
return seeds.SerializeToString(), 200
|
||||
|
||||
|
||||
def save_bookmark(state, name):
|
||||
bookmarks_dir = os.path.join(STORAGE_DIR, str(state.id), 'bookmarks', str(get_course(state)), str(state.sport))
|
||||
if not make_dir(bookmarks_dir):
|
||||
return
|
||||
with open(os.path.join(bookmarks_dir, name + '.bin'), 'wb') as f:
|
||||
f.write(state.SerializeToString())
|
||||
|
||||
@app.route('/relay/worlds/attributes', methods=['POST'])
|
||||
@jwt_to_session_cookie
|
||||
@login_required
|
||||
@@ -3893,6 +3887,13 @@ def send_server_back_online_message():
|
||||
send_message(message)
|
||||
discord.send_message(message)
|
||||
|
||||
def remove_inactive():
|
||||
while True:
|
||||
for p_id in list(player_partial_profiles.keys()):
|
||||
if time.monotonic() > player_partial_profiles[p_id].time + 3600:
|
||||
player_partial_profiles.pop(p_id)
|
||||
time.sleep(600)
|
||||
|
||||
|
||||
with app.app_context():
|
||||
db.create_all()
|
||||
@@ -4088,6 +4089,8 @@ def run_standalone(passed_online, passed_global_relay, passed_global_pace_partne
|
||||
|
||||
send_message_thread = threading.Thread(target=send_server_back_online_message)
|
||||
send_message_thread.start()
|
||||
remove_inactive_thread = threading.Thread(target=remove_inactive)
|
||||
remove_inactive_thread.start()
|
||||
logger.info("Server version %s is running." % ZWIFT_VER_CUR)
|
||||
server = WSGIServer(('0.0.0.0', 443), app, certfile='%s/cert-zwift-com.pem' % SSL_DIR, keyfile='%s/key-zwift-com.pem' % SSL_DIR, log=logger)
|
||||
server.serve_forever()
|
||||
|
||||
Reference in New Issue
Block a user