You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
339 lines
13 KiB
339 lines
13 KiB
#!/usr/bin/env python3 |
|
""" |
|
User Profile Integration Module |
|
Provides integration between games and the user profile system |
|
""" |
|
|
|
import json |
|
import uuid |
|
import platform |
|
import hashlib |
|
from datetime import datetime |
|
from score_api_client import ScoreAPIClient |
|
|
|
|
|
class UserProfileIntegration: |
|
"""Integration layer between the game and profile system""" |
|
|
|
def __init__(self, profiles_file="user_profiles.json", api_url="http://172.27.23.245:8000"): |
|
self.profiles_file = profiles_file |
|
self.current_profile = None |
|
self.device_id = self.generate_device_id() |
|
self.api_client = ScoreAPIClient(api_url) |
|
self.api_enabled = self.api_client.is_server_available() |
|
self.load_active_profile() |
|
|
|
if self.api_enabled: |
|
print(f"✓ Connected to score server at {api_url}") |
|
else: |
|
print(f"✗ Score server not available at {api_url} - running offline") |
|
|
|
def generate_device_id(self): |
|
"""Generate a unique device ID based on system information""" |
|
# Get system information |
|
system_info = f"{platform.system()}-{platform.machine()}-{platform.processor()}" |
|
|
|
# Try to get MAC address for more uniqueness |
|
try: |
|
mac = ':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff) |
|
for ele in range(0,8*6,8)][::-1]) |
|
system_info += f"-{mac}" |
|
except: |
|
pass |
|
|
|
# Create hash and take first 8 characters |
|
device_hash = hashlib.md5(system_info.encode()).hexdigest()[:8].upper() |
|
return f"DEV-{device_hash}" |
|
|
|
def load_active_profile(self): |
|
"""Load the currently active profile""" |
|
try: |
|
with open(self.profiles_file, 'r') as f: |
|
data = json.load(f) |
|
active_name = data.get('active_profile') |
|
if active_name and active_name in data['profiles']: |
|
self.current_profile = data['profiles'][active_name] |
|
print(f"Loaded profile: {self.current_profile['name']}") |
|
|
|
# Sync with API if available |
|
if self.api_enabled: |
|
self.sync_profile_with_api() |
|
|
|
return True |
|
except (FileNotFoundError, json.JSONDecodeError) as e: |
|
print(f"Could not load profile: {e}") |
|
|
|
self.current_profile = None |
|
return False |
|
|
|
def get_profile_name(self): |
|
"""Get current profile name or default""" |
|
return self.current_profile['name'] if self.current_profile else "Guest Player" |
|
|
|
def get_device_id(self): |
|
"""Get the unique device identifier""" |
|
return self.device_id |
|
|
|
def get_setting(self, setting_name, default_value=None): |
|
"""Get a setting from the current profile, or return default""" |
|
if self.current_profile and 'settings' in self.current_profile: |
|
return self.current_profile['settings'].get(setting_name, default_value) |
|
return default_value |
|
|
|
def sync_profile_with_api(self): |
|
"""Ensure current profile is registered with the API server""" |
|
if not self.current_profile or not self.api_enabled: |
|
return False |
|
|
|
profile_name = self.current_profile['name'] |
|
|
|
# Check if user exists on server |
|
if not self.api_client.user_exists(self.device_id, profile_name): |
|
print(f"Registering {profile_name} with score server...") |
|
result = self.api_client.signup_user(self.device_id, profile_name) |
|
if result.get('success'): |
|
print(f"✓ {profile_name} registered successfully") |
|
return True |
|
else: |
|
print(f"✗ Failed to register {profile_name}: {result.get('message')}") |
|
return False |
|
else: |
|
print(f"✓ {profile_name} already registered on server") |
|
return True |
|
|
|
def register_new_user(self, user_id): |
|
"""Register a new user both locally and on the API server""" |
|
if not self.api_enabled: |
|
print("API server not available - user will only be registered locally") |
|
return True |
|
|
|
result = self.api_client.signup_user(self.device_id, user_id) |
|
if result.get('success'): |
|
print(f"✓ {user_id} registered with server successfully") |
|
return True |
|
else: |
|
print(f"✗ Failed to register {user_id} with server: {result.get('message')}") |
|
return False |
|
|
|
def update_game_stats(self, score, completed=True): |
|
"""Update the current profile's game statistics""" |
|
if not self.current_profile: |
|
print("No profile loaded - stats not saved") |
|
return False |
|
|
|
# Submit score to API first if available |
|
if self.api_enabled: |
|
profile_name = self.current_profile['name'] |
|
result = self.api_client.submit_score( |
|
self.device_id, |
|
profile_name, |
|
score, |
|
completed |
|
) |
|
if result.get('success'): |
|
print(f"✓ Score {score} submitted to server successfully") |
|
# Print server stats if available |
|
if 'user_stats' in result: |
|
stats = result['user_stats'] |
|
print(f" Server stats - Games: {stats['total_games']}, Best: {stats['best_score']}") |
|
else: |
|
print(f"✗ Failed to submit score to server: {result.get('message')}") |
|
|
|
try: |
|
# Update local profile |
|
with open(self.profiles_file, 'r') as f: |
|
data = json.load(f) |
|
|
|
profile_name = self.current_profile['name'] |
|
if profile_name in data['profiles']: |
|
profile = data['profiles'][profile_name] |
|
|
|
# Update statistics |
|
if completed: |
|
profile['games_played'] += 1 |
|
print(f"Game completed for {profile_name}! Total games: {profile['games_played']}") |
|
|
|
profile['total_score'] += score |
|
if score > profile['best_score']: |
|
profile['best_score'] = score |
|
print(f"New best score for {profile_name}: {score}!") |
|
|
|
profile['last_played'] = datetime.now().isoformat() |
|
|
|
# Update our local copy |
|
self.current_profile = profile |
|
|
|
# Save back to file |
|
with open(self.profiles_file, 'w') as f: |
|
json.dump(data, f, indent=2) |
|
|
|
print(f"Local profile stats updated: Score +{score}, Total: {profile['total_score']}") |
|
return True |
|
|
|
except Exception as e: |
|
print(f"Error updating profile stats: {e}") |
|
|
|
return False |
|
|
|
def add_achievement(self, achievement_id): |
|
"""Add an achievement to the current profile""" |
|
if not self.current_profile: |
|
return False |
|
|
|
try: |
|
with open(self.profiles_file, 'r') as f: |
|
data = json.load(f) |
|
|
|
profile_name = self.current_profile['name'] |
|
if profile_name in data['profiles']: |
|
profile = data['profiles'][profile_name] |
|
|
|
if achievement_id not in profile['achievements']: |
|
profile['achievements'].append(achievement_id) |
|
self.current_profile = profile |
|
|
|
with open(self.profiles_file, 'w') as f: |
|
json.dump(data, f, indent=2) |
|
|
|
print(f"Achievement unlocked for {profile_name}: {achievement_id}") |
|
return True |
|
|
|
except Exception as e: |
|
print(f"Error adding achievement: {e}") |
|
|
|
return False |
|
|
|
def get_profile_info(self): |
|
"""Get current profile information for display""" |
|
if self.current_profile: |
|
info = { |
|
'name': self.current_profile['name'], |
|
'games_played': self.current_profile['games_played'], |
|
'best_score': self.current_profile['best_score'], |
|
'total_score': self.current_profile['total_score'], |
|
'achievements': len(self.current_profile['achievements']), |
|
'difficulty': self.current_profile['settings'].get('difficulty', 'normal'), |
|
'device_id': self.device_id, |
|
'api_connected': self.api_enabled |
|
} |
|
return info |
|
return None |
|
|
|
def get_device_leaderboard(self, limit=10): |
|
"""Get leaderboard for the current device from API server""" |
|
if not self.api_enabled: |
|
print("API server not available - cannot get leaderboard") |
|
return [] |
|
|
|
leaderboard = self.api_client.get_leaderboard(self.device_id, limit) |
|
return leaderboard |
|
|
|
def get_global_leaderboard(self, limit=10): |
|
"""Get global leaderboard across all devices from API server""" |
|
if not self.api_enabled: |
|
print("API server not available - cannot get global leaderboard") |
|
return [] |
|
|
|
leaderboard = self.api_client.get_global_leaderboard(limit) |
|
return leaderboard |
|
|
|
def get_all_device_users(self): |
|
"""Get all users registered for this device from API server""" |
|
if not self.api_enabled: |
|
print("API server not available - cannot get user list") |
|
return [] |
|
|
|
users = self.api_client.get_device_users(self.device_id) |
|
return users |
|
|
|
def get_user_server_scores(self, user_id=None, limit=10): |
|
"""Get recent scores from server for a user (defaults to current profile)""" |
|
if not self.api_enabled: |
|
return [] |
|
|
|
if user_id is None: |
|
if not self.current_profile: |
|
return [] |
|
user_id = self.current_profile['name'] |
|
|
|
scores = self.api_client.get_user_scores(self.device_id, user_id, limit) |
|
return scores |
|
|
|
def reload_profile(self): |
|
"""Reload the current profile from disk (useful for external profile changes)""" |
|
return self.load_active_profile() |
|
|
|
|
|
# Convenience functions for quick integration |
|
def get_active_profile(): |
|
"""Quick function to get active profile info""" |
|
integration = UserProfileIntegration() |
|
return integration.get_profile_info() |
|
|
|
def update_profile_score(score, completed=True): |
|
"""Quick function to update profile score""" |
|
integration = UserProfileIntegration() |
|
return integration.update_game_stats(score, completed) |
|
|
|
def get_profile_setting(setting_name, default_value=None): |
|
"""Quick function to get a profile setting""" |
|
integration = UserProfileIntegration() |
|
return integration.get_setting(setting_name, default_value) |
|
|
|
def get_device_leaderboard(limit=10): |
|
"""Quick function to get device leaderboard""" |
|
integration = UserProfileIntegration() |
|
return integration.get_device_leaderboard(limit) |
|
|
|
def get_global_leaderboard(limit=10): |
|
"""Quick function to get global leaderboard""" |
|
integration = UserProfileIntegration() |
|
return integration.get_global_leaderboard(limit) |
|
|
|
|
|
if __name__ == "__main__": |
|
# Test the integration |
|
print("Testing User Profile Integration with API...") |
|
|
|
integration = UserProfileIntegration() |
|
print(f"Device ID: {integration.get_device_id()}") |
|
print(f"Profile Name: {integration.get_profile_name()}") |
|
print(f"API Connected: {integration.api_enabled}") |
|
|
|
info = integration.get_profile_info() |
|
if info: |
|
print(f"Profile Info: {info}") |
|
else: |
|
print("No profile loaded") |
|
|
|
# Test settings |
|
difficulty = integration.get_setting('difficulty', 'normal') |
|
sound_volume = integration.get_setting('sound_volume', 50) |
|
print(f"Settings - Difficulty: {difficulty}, Sound: {sound_volume}%") |
|
|
|
# Test API features if connected |
|
if integration.api_enabled: |
|
print("\nTesting API features...") |
|
|
|
# Get leaderboard |
|
leaderboard = integration.get_device_leaderboard(5) |
|
if leaderboard: |
|
print("Device Leaderboard:") |
|
for entry in leaderboard: |
|
print(f" {entry['rank']}. {entry['user_id']}: {entry['best_score']} pts ({entry['total_games']} games)") |
|
else: |
|
print("No leaderboard data available") |
|
|
|
# Get all users |
|
users = integration.get_all_device_users() |
|
print(f"\nTotal users on device: {len(users)}") |
|
for user in users: |
|
print(f" {user['user_id']}: Best {user['best_score']}, {user['total_scores']} games") |
|
|
|
# Test score submission |
|
if integration.current_profile: |
|
print(f"\nTesting score submission for {integration.current_profile['name']}...") |
|
result = integration.update_game_stats(1234, True) |
|
print(f"Score update result: {result}") |
|
else: |
|
print("API features not available - server offline")
|
|
|