|
| 1 | +extends Node |
| 2 | +## Steam Integration Manager |
| 3 | +## |
| 4 | +## Handles initialization, authentication, and Steam API interactions. |
| 5 | +## Works as graceful fallback when Steam is not available. |
| 6 | + |
| 7 | +## Emitted when Steam initialization completes |
| 8 | +signal steam_initialized(success: bool) |
| 9 | +## Emitted when player info is loaded |
| 10 | +signal player_info_loaded(steam_id: int, name: String) |
| 11 | + |
| 12 | +## Whether Steam is available and initialized |
| 13 | +var is_steam_enabled: bool = false |
| 14 | +## The player's Steam ID |
| 15 | +var steam_id: int = 0 |
| 16 | +## The player's Steam display name |
| 17 | +var player_name: String = "" |
| 18 | +## Steam app ID (will be loaded from steam_appid.txt) |
| 19 | +var app_id: int = 480 # Default to Spacewar for testing |
| 20 | + |
| 21 | +func _ready(): |
| 22 | + # Load app ID from steam_appid.txt |
| 23 | + _load_app_id() |
| 24 | + |
| 25 | + # Only initialize if running through Steam |
| 26 | + if OS.has_feature("steam"): |
| 27 | + print("[Steam] Detected Steam runtime") |
| 28 | + _initialize_steam() |
| 29 | + else: |
| 30 | + print("[Steam] Not running through Steam - using fallback mode") |
| 31 | + is_steam_enabled = false |
| 32 | + steam_initialized.emit(false) |
| 33 | + |
| 34 | +func _load_app_id(): |
| 35 | + """Load Steam App ID from steam_appid.txt""" |
| 36 | + var app_id_path = "res://steam_appid.txt" |
| 37 | + if FileAccess.file_exists(app_id_path): |
| 38 | + var file = FileAccess.open(app_id_path, FileAccess.READ) |
| 39 | + if file: |
| 40 | + var content = file.get_as_text().strip_edges() |
| 41 | + app_id = int(content) |
| 42 | + print("[Steam] Loaded App ID: %d" % app_id) |
| 43 | + else: |
| 44 | + push_warning("[Steam] Could not open steam_appid.txt") |
| 45 | + else: |
| 46 | + push_warning("[Steam] steam_appid.txt not found - using default App ID 480 (Spacewar)") |
| 47 | + |
| 48 | +func _initialize_steam(): |
| 49 | + """Initialize the Steamworks API""" |
| 50 | + # Check if GodotSteam is available |
| 51 | + if not Engine.has_singleton("Steam"): |
| 52 | + push_error("[Steam] GodotSteam singleton not found - plugin may not be installed correctly") |
| 53 | + is_steam_enabled = false |
| 54 | + steam_initialized.emit(false) |
| 55 | + return |
| 56 | + |
| 57 | + # Initialize Steam |
| 58 | + var init_response = Steam.steamInit() |
| 59 | + |
| 60 | + # Handle both dictionary and bool returns |
| 61 | + var status_ok = false |
| 62 | + if typeof(init_response) == TYPE_DICTIONARY: |
| 63 | + status_ok = (init_response.get('status', 0) == 1) |
| 64 | + if not status_ok: |
| 65 | + push_error("[Steam] Failed to initialize: %s" % init_response.get('verbal', 'Unknown error')) |
| 66 | + elif typeof(init_response) == TYPE_BOOL: |
| 67 | + status_ok = init_response |
| 68 | + |
| 69 | + if not status_ok: |
| 70 | + is_steam_enabled = false |
| 71 | + steam_initialized.emit(false) |
| 72 | + return |
| 73 | + |
| 74 | + # Steam initialized successfully |
| 75 | + is_steam_enabled = true |
| 76 | + |
| 77 | + # Get player info |
| 78 | + steam_id = Steam.getSteamID() |
| 79 | + player_name = Steam.getPersonaName() |
| 80 | + |
| 81 | + print("[Steam] Initialized successfully") |
| 82 | + print("[Steam] Player: %s (ID: %d)" % [player_name, steam_id]) |
| 83 | + |
| 84 | + steam_initialized.emit(true) |
| 85 | + player_info_loaded.emit(steam_id, player_name) |
| 86 | + |
| 87 | +func _process(_delta): |
| 88 | + """Run Steam callbacks every frame""" |
| 89 | + if is_steam_enabled: |
| 90 | + Steam.run_callbacks() |
| 91 | + |
| 92 | +func unlock_achievement(achievement_id: String): |
| 93 | + """Unlock a Steam achievement""" |
| 94 | + if not is_steam_enabled: |
| 95 | + return |
| 96 | + |
| 97 | + # Check if already unlocked |
| 98 | + var achievement_data = Steam.getAchievement(achievement_id) |
| 99 | + if achievement_data and achievement_data['achieved']: |
| 100 | + return # Already unlocked |
| 101 | + |
| 102 | + # Unlock the achievement |
| 103 | + var success = Steam.setAchievement(achievement_id) |
| 104 | + if success: |
| 105 | + print("[Steam] Unlocked achievement: %s" % achievement_id) |
| 106 | + Steam.storeStats() # Save achievement progress |
| 107 | + else: |
| 108 | + push_warning("[Steam] Failed to unlock achievement: %s" % achievement_id) |
| 109 | + |
| 110 | +func get_achievement_status(achievement_id: String) -> Dictionary: |
| 111 | + """Get achievement unlock status""" |
| 112 | + if not is_steam_enabled: |
| 113 | + return {'achieved': false, 'unlock_time': 0} |
| 114 | + |
| 115 | + return Steam.getAchievement(achievement_id) |
| 116 | + |
| 117 | +func clear_achievement(achievement_id: String): |
| 118 | + """Clear an achievement (for testing only)""" |
| 119 | + if not is_steam_enabled: |
| 120 | + return |
| 121 | + |
| 122 | + Steam.clearAchievement(achievement_id) |
| 123 | + Steam.storeStats() |
| 124 | + print("[Steam] Cleared achievement: %s" % achievement_id) |
| 125 | + |
| 126 | +func reset_all_stats(achievements_too: bool = true): |
| 127 | + """Reset all stats and optionally achievements (for testing only)""" |
| 128 | + if not is_steam_enabled: |
| 129 | + return |
| 130 | + |
| 131 | + Steam.resetAllStats(achievements_too) |
| 132 | + print("[Steam] Reset all stats (achievements: %s)" % achievements_too) |
| 133 | + |
| 134 | +func get_stat_int(stat_name: String) -> int: |
| 135 | + """Get an integer stat value""" |
| 136 | + if not is_steam_enabled: |
| 137 | + return 0 |
| 138 | + |
| 139 | + return Steam.getStatInt(stat_name) |
| 140 | + |
| 141 | +func set_stat_int(stat_name: String, value: int): |
| 142 | + """Set an integer stat value""" |
| 143 | + if not is_steam_enabled: |
| 144 | + return |
| 145 | + |
| 146 | + Steam.setStatInt(stat_name, value) |
| 147 | + Steam.storeStats() |
| 148 | + |
| 149 | +func get_stat_float(stat_name: String) -> float: |
| 150 | + """Get a float stat value""" |
| 151 | + if not is_steam_enabled: |
| 152 | + return 0.0 |
| 153 | + |
| 154 | + return Steam.getStatFloat(stat_name) |
| 155 | + |
| 156 | +func set_stat_float(stat_name: String, value: float): |
| 157 | + """Set a float stat value""" |
| 158 | + if not is_steam_enabled: |
| 159 | + return |
| 160 | + |
| 161 | + Steam.setStatFloat(stat_name, value) |
| 162 | + Steam.storeStats() |
0 commit comments