server-master/srcs/_plugins/Plugin.Act4/DungeonScriptManager.cs

135 lines
No EOL
5.4 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FluentValidation.Results;
using MoonSharp.Interpreter;
using Npgsql;
using PhoenixLib.Logging;
using Plugin.Act4.Scripting.Validator;
using WingsAPI.Scripting;
using WingsAPI.Scripting.Enum.Dungeon;
using WingsAPI.Scripting.LUA;
using WingsAPI.Scripting.Object.Dungeon;
using WingsAPI.Scripting.ScriptManager;
namespace Plugin.Act4;
public class DungeonScriptManager : IDungeonScriptManager
{
private readonly Dictionary<SDungeonType, SDungeon> _cache = new();
private readonly IScriptFactory _scriptFactory;
private readonly ScriptFactoryConfiguration _scriptFactoryConfiguration;
private readonly SDungeonValidator _validator;
public DungeonScriptManager(IScriptFactory scriptFactory, ScriptFactoryConfiguration scriptFactoryConfiguration, SDungeonValidator validator)
{
_scriptFactory = scriptFactory;
_scriptFactoryConfiguration = scriptFactoryConfiguration;
_validator = validator;
}
public SDungeon GetScriptedDungeon(SDungeonType raidType) => _cache.GetValueOrDefault(raidType);
public void Load()
{
EnsureDungeonScriptsDirectoryHydrated();
Directory.CreateDirectory(_scriptFactoryConfiguration.DungeonsDirectory);
IEnumerable<string> files = Directory.GetFiles(_scriptFactoryConfiguration.DungeonsDirectory, "*.lua");
foreach (string file in files)
{
try
{
SDungeon dungeon = _scriptFactory.LoadScript<SDungeon>(file);
if (dungeon == null)
{
Log.Warn($"Failed to load raid script {file}");
continue;
}
ValidationResult result = _validator.Validate(dungeon);
if (!result.IsValid)
{
throw new InvalidScriptException(result.Errors.First().ErrorMessage);
}
Log.Warn($"[DUNGEON_SCRIPT_MANAGER] Loaded {Path.GetFileName(file)} for raid: {dungeon.DungeonType}");
_cache[dungeon.DungeonType] = dungeon;
}
catch (InvalidScriptException e)
{
Log.Error($"[DUNGEON_SCRIPT_MANAGER][SCRIPT_ERROR] InvalidScript: {file}", e);
}
catch (ScriptRuntimeException e)
{
Log.Error($"[DUNGEON_SCRIPT_MANAGER][SCRIPT ERROR] {file}, {e.DecoratedMessage}", e);
}
catch (Exception e)
{
Log.Error($"[DUNGEON_SCRIPT_MANAGER][SCRIPT_ERROR] {file}", e);
}
}
Log.Info($"Loaded {_cache.Count} dungeons from scripts");
}
private void EnsureDungeonScriptsDirectoryHydrated()
{
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.DungeonsDirectory))
{
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/dungeons/%';", 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.DungeonsDirectory);
File.WriteAllBytes(fullPath, bytes);
count++;
}
if (count > 0)
{
Log.Info($"[DB_FIRST] Hydrated {count} dungeon scripts from resource_files");
}
}
catch (Exception ex)
{
Log.Error("[DB_FIRST] Could not hydrate dungeon scripts from database", ex);
}
}
}