using System; using System.Collections.Generic; using System.IO; using MoonSharp.Interpreter; using Npgsql; using PhoenixLib.Logging; using WingsAPI.Scripting; using WingsAPI.Scripting.Attribute; using WingsAPI.Scripting.LUA; using WingsAPI.Scripting.Object.Timespace; using WingsAPI.Scripting.ScriptManager; namespace Plugin.TimeSpaces; [ScriptObject] public class DebuggableScriptGenerator { public int TimeSpaceId { get; set; } public Closure GenerateMission { get; set; } } public class LuaTimeSpaceScriptManager : ITimeSpaceScriptManager { private readonly Dictionary _cache = new(); private readonly IScriptFactory _scriptFactory; private readonly ScriptFactoryConfiguration _scriptFactoryConfiguration; private readonly STimeSpaceValidator _validator; public LuaTimeSpaceScriptManager(IScriptFactory scriptFactory, ScriptFactoryConfiguration scriptFactoryConfiguration, STimeSpaceValidator validator) { _scriptFactory = scriptFactory; _scriptFactoryConfiguration = scriptFactoryConfiguration; _validator = validator; } public void Load() { EnsureTimespaceScriptsDirectoryHydrated(); Directory.CreateDirectory(_scriptFactoryConfiguration.TimeSpacesDirectory); IEnumerable files = Directory.GetFiles(_scriptFactoryConfiguration.TimeSpacesDirectory, "*.lua"); foreach (string file in files) { try { ScriptTimeSpace raid = _scriptFactory.LoadScript(file); if (raid == null) { Log.Warn($"Failed to load timespace script {file}"); continue; } Log.Warn($"[TIMESPACE_SCRIPT_MANAGER] Loaded {Path.GetFileName(file)} for timespace: {raid.TimeSpaceId}"); _cache[raid.TimeSpaceId] = raid; } catch (InvalidScriptException e) { Log.Error($"[TIMESPACE_SCRIPT_MANAGER] InvalidScript: {file}", e); } catch (ScriptRuntimeException e) { Log.Error($"[TIMESPACE_SCRIPT_MANAGER][SCRIPT ERROR] {file}, {e.DecoratedMessage}", e); } catch (Exception e) { Log.Error($"[TIMESPACE_SCRIPT_MANAGER][ERROR] {file}", e); } } Log.Info($"Loaded {_cache.Count} timespace from scripts"); } public ScriptTimeSpace GetScriptedTimeSpace(long id) { if (!_cache.TryGetValue(id, out ScriptTimeSpace timeSpace)) { return null; } return timeSpace; } private void EnsureTimespaceScriptsDirectoryHydrated() { bool dbFirst = string.Equals(Environment.GetEnvironmentVariable("DB_FIRST"), "true", StringComparison.OrdinalIgnoreCase) || string.Equals(Environment.GetEnvironmentVariable("RESOURCE_DB_FIRST"), "true", StringComparison.OrdinalIgnoreCase); if (!dbFirst) { return; } if (Directory.Exists(_scriptFactoryConfiguration.TimeSpacesDirectory)) { return; } try { string host = Environment.GetEnvironmentVariable("DATABASE_IP") ?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_IP") ?? "127.0.0.1"; string port = Environment.GetEnvironmentVariable("DATABASE_PORT") ?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_PORT") ?? "5432"; string db = Environment.GetEnvironmentVariable("DATABASE_NAME") ?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_NAME") ?? "game"; string user = Environment.GetEnvironmentVariable("DATABASE_USER") ?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_USER") ?? "postgres"; string pass = Environment.GetEnvironmentVariable("DATABASE_PASSWORD") ?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_PASSWORD") ?? "postgres"; using var conn = new NpgsqlConnection($"Host={host};Port={port};Database={db};Username={user};Password={pass}"); conn.Open(); using var cmd = new NpgsqlCommand("SELECT relative_path, content FROM resource_files WHERE category='config_scripts' AND relative_path LIKE 'config/scripts/timespaces/%';", conn); using var reader = cmd.ExecuteReader(); int count = 0; while (reader.Read()) { string relative = reader.GetString(0).Replace('/', Path.DirectorySeparatorChar); byte[] bytes = (byte[])reader[1]; string fullPath = Path.Combine(Directory.GetCurrentDirectory(), relative); Directory.CreateDirectory(Path.GetDirectoryName(fullPath) ?? _scriptFactoryConfiguration.TimeSpacesDirectory); File.WriteAllBytes(fullPath, bytes); count++; } if (count > 0) { Log.Info($"[DB_FIRST] Hydrated {count} timespace scripts from resource_files"); } } catch (Exception ex) { Log.Error("[DB_FIRST] Could not hydrate timespace scripts from database", ex); } } }