nice
This commit is contained in:
@@ -0,0 +1,339 @@
|
||||
#!/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 engine.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://localhost: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")
|
||||
Reference in New Issue
Block a user