Space Traveller
Last updated
Was this helpful?
Last updated
Was this helpful?
Catégorie: Divers - Difficulté: Facile
Description:
Solution:
Voici le script afin de terminer le jeu (infernal) :
import json
import time
import random
sio = socketio.Client(logger=False, engineio_logger=False)
score = 0
flag = None
game_started_successfully = False
target_score = 90
waves_pending_completion = []
PLAYER_X_POS = 50
PLAYER_WIDTH = 49
PLAYER_HEIGHT = 40
ASTEROID_WIDTH = 55
ASTEROID_HEIGHT = 48
ASTEROID_START_X = 400
TARGET_ASTEROID_X_FOR_COMPLETION = -2.0
GAME_TICK_INTERVAL_SECONDS = 0.030
MAX_PLAYER_Y = 600 # Hauteur du canvas du jeu
EFFECTIVE_MAX_PLAYER_Y = MAX_PLAYER_Y - PLAYER_HEIGHT # Max Y pour le coin supérieur gauche du joueur
@sio.event
def connect():
print("Connecté au serveur !")
print("Envoi de game_start...")
sio.emit("message", "game_start")
global game_started_successfully
game_started_successfully = True
@sio.event
def connect_error(data):
print(f"Erreur de connexion : {data}")
def is_player_safe(player_y, spawns_for_wave):
player_top = player_y
player_bottom = player_y + PLAYER_HEIGHT
for asteroid in spawns_for_wave:
asteroid_top = asteroid['y']
asteroid_bottom = asteroid['y'] + ASTEROID_HEIGHT
# Condition de collision (chevauchement vertical)
# Le joueur est touché si le bas du joueur est sous le haut de l'astéroïde ET
# le haut du joueur est au-dessus du bas de l'astéroïde.
# C'est-à-dire : player_bottom > asteroid_top AND player_top < asteroid_bottom
if player_bottom > asteroid_top and player_top < asteroid_bottom:
return False # Collision
return True # Pas de collision
@sio.on("message")
def on_server_message(type_interne, data_interne=None):
global score, flag, waves_pending_completion
if type_interne == "message":
if data_interne is None:
print("Erreur: type_interne est 'message' mais data_interne est None.")
return
try:
event_data = json.loads(data_interne)
actual_event_type = event_data.get("event")
if actual_event_type == "score_up":
score += 1
print(f"Score augmenté ! Score actuel : {score}")
if score >= target_score and not flag:
print(f"Score de {target_score} atteint ou dépassé ! En attente du flag.")
elif actual_event_type == "reward":
flag = event_data.get("flag")
print(f"Récompense reçue ! Flag : {flag}")
if flag:
sio.disconnect()
elif actual_event_type == "new_wave":
wave_index = event_data.get("i")
spawns = event_data.get("spawns", [])
chosen_player_y_for_wave = EFFECTIVE_MAX_PLAYER_Y // 2 # Default
if spawns:
speed = spawns[0].get("speed", 5)
distance_to_travel = ASTEROID_START_X - TARGET_ASTEROID_X_FOR_COMPLETION
ticks_needed = distance_to_travel / speed
base_delay_seconds = ticks_needed * GAME_TICK_INTERVAL_SECONDS
found_safe_y = False
# Essayer de trouver une position Y sûre par incréments
for y_candidate in range(0, EFFECTIVE_MAX_PLAYER_Y + 1, 5):
if is_player_safe(y_candidate, spawns):
chosen_player_y_for_wave = y_candidate
found_safe_y = True
break
if not found_safe_y:
# Si aucune position sûre n'est trouvée par incréments, essayer des positions aléatoires
for _ in range(10): # 10 tentatives aléatoires
y_candidate = random.randint(0, EFFECTIVE_MAX_PLAYER_Y)
if is_player_safe(y_candidate, spawns):
chosen_player_y_for_wave = y_candidate
found_safe_y = True
break
if not found_safe_y:
print(f"AVERTISSEMENT: Aucune position Y sûre trouvée pour la vague {wave_index}. Utilisation de {chosen_player_y_for_wave}.")
actual_completion_delay = base_delay_seconds + random.uniform(0.05, 0.15) # Petit délai aléatoire
completion_time = time.time() + actual_completion_delay
waves_pending_completion.append({
"index": wave_index,
"completion_time": completion_time,
"playerY_at_completion": chosen_player_y_for_wave
})
print(f"Nouvelle vague {wave_index} (speed {speed:.2f}). Player_Y choisi: {chosen_player_y_for_wave}. Complétion en ~{actual_completion_delay:.2f}s.")
else: # Pas de spawns, vague vide ?
print(f"Nouvelle vague {wave_index} sans données de spawn. Utilisation d'un délai par défaut et Y par défaut.")
completion_time = time.time() + random.uniform(1.0, 1.5)
waves_pending_completion.append({"index": wave_index, "completion_time": completion_time, "playerY_at_completion": chosen_player_y_for_wave})
elif actual_event_type == "game_over":
print("Game Over reçu du serveur.")
if not flag:
sio.disconnect()
except json.JSONDecodeError:
print(f"Erreur de décodage JSON pour les données : {data_interne}")
except Exception as e:
print(f"Erreur lors du traitement du message (type interne 'message') du serveur : {e}, données: {data_interne}")
elif type_interne == "ping":
sio.emit("message", "pong")
@sio.event
def disconnect():
print("Déconnecté du serveur.")
def process_pending_waves():
global waves_pending_completion
if not sio.connected or not game_started_successfully or flag:
return
current_time = time.time()
waves_pending_completion.sort(key=lambda w: w["completion_time"])
processed_indices_this_tick = set()
temp_pending_waves = []
for wave_info in waves_pending_completion:
if current_time >= wave_info["completion_time"] and wave_info["index"] not in processed_indices_this_tick:
payload = {"playerY": wave_info["playerY_at_completion"], "waveIndex": wave_info["index"]}
print(f"Envoi de wave_completed pour l'index: {wave_info['index']} avec playerY: {wave_info['playerY_at_completion']}")
sio.emit("message", ("wave_completed", json.dumps(payload)))
processed_indices_this_tick.add(wave_info["index"])
else:
temp_pending_waves.append(wave_info)
waves_pending_completion = temp_pending_waves
# Programme principal
if __name__ == '__main__':
try:
print("Tentative de connexion à wss://space-traveler.404ctf.fr/")
sio.connect('wss://space-traveler.404ctf.fr/', transports=['websocket'], socketio_path='socket.io')
start_time = time.time()
timeout_seconds = 300 # 5 minutes
while not game_started_successfully and (time.time() - start_time) < 5:
time.sleep(0.1)
if not game_started_successfully:
print("Échec du démarrage du jeu.")
else:
print("Jeu démarré. Boucle principale.")
while sio.connected and not flag and (time.time() - start_time) < timeout_seconds:
process_pending_waves()
time.sleep(GAME_TICK_INTERVAL_SECONDS / 2)
if score >= target_score and not flag:
print(f"Score de {score} atteint. Attente du flag...")
if not flag and (time.time() - start_time) >= timeout_seconds:
print(f"Timeout: Flag non obtenu après {timeout_seconds} secondes.")
elif not sio.connected and not flag and not ((time.time() - start_time) >= timeout_seconds) :
print(f"Déconnecté avant d'obtenir le flag (et avant timeout). Score: {score}")
elif not flag:
print(f"Flag non obtenu après la boucle principale (score: {score}).")
except socketio.exceptions.ConnectionError as e:
print(f"Erreur de connexion Socket.IO : {e}")
except Exception as e:
print(f"Une erreur inattendue est survenue : {e}")
finally:
if sio.connected:
sio.disconnect()
print(f"Script terminé. Score final: {score}, Flag: {flag if flag else 'Non obtenu'}")
Ce script a été créé en étudiant toutes les fonctions JS qui tournent en arrière plan de l'application web. Lorsque nous lançons ce script, voici ce que nous obtenons (étape par étape) :
[...]