server-master/srcs/_plugins/Plugin.ResourceLoader/Loaders/MapResourceFileLoader.cs

172 lines
No EOL
6.9 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Npgsql;
using PhoenixLib.Logging;
using WingsAPI.Data.GameData;
using WingsEmu.DTOs.Maps;
namespace Plugin.ResourceLoader.Loaders
{
public class MapResourceFileLoader : IResourceLoader<MapDataDTO>
{
private readonly ResourceLoadingConfiguration _config;
public MapResourceFileLoader(ResourceLoadingConfiguration config) => _config = config;
public async Task<IReadOnlyList<MapDataDTO>> LoadAsync()
{
string filePath = Path.Combine(_config.GameDataPath, "MapIDData.dat");
if (!File.Exists(filePath))
{
bool dbFirst = string.Equals(Environment.GetEnvironmentVariable("DB_FIRST"), "true", StringComparison.OrdinalIgnoreCase)
|| string.Equals(Environment.GetEnvironmentVariable("RESOURCE_DB_FIRST"), "true", StringComparison.OrdinalIgnoreCase);
if (dbFirst)
{
TryHydrateDatFileFromDatabase("MapIDData.dat", filePath);
TryHydrateMapFilesFromDatabase();
}
}
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"{filePath} should be present");
}
var maps = new List<MapDataDTO>();
var dictionaryId = new Dictionary<int, string>();
int i = 0;
using (var mapIdStream = new StreamReader(filePath, Encoding.GetEncoding(1252)))
{
string line;
while ((line = await mapIdStream.ReadLineAsync()) != null)
{
string[] values = line.Split(' ');
if (values.Length <= 1)
{
continue;
}
if (!int.TryParse(values[0], out int mapId))
{
continue;
}
if (!dictionaryId.ContainsKey(mapId))
{
dictionaryId.Add(mapId, values[4]);
}
}
}
if (!Directory.Exists(_config.GameMapsPath) || !new DirectoryInfo(_config.GameMapsPath).GetFiles().Any())
{
bool dbFirst = string.Equals(Environment.GetEnvironmentVariable("DB_FIRST"), "true", StringComparison.OrdinalIgnoreCase)
|| string.Equals(Environment.GetEnvironmentVariable("RESOURCE_DB_FIRST"), "true", StringComparison.OrdinalIgnoreCase);
if (dbFirst)
{
TryHydrateMapFilesFromDatabase();
}
}
foreach (FileInfo file in new DirectoryInfo(_config.GameMapsPath).GetFiles())
{
string name = string.Empty;
if (dictionaryId.TryGetValue(int.Parse(file.Name), out string value))
{
name = value;
}
byte[] data = await File.ReadAllBytesAsync(file.FullName);
short width = BitConverter.ToInt16(data, 0);
short height = BitConverter.ToInt16(data, 2);
maps.Add(new MapDataDTO
{
Id = short.Parse(file.Name),
Name = name,
Width = width,
Height = height,
Grid = data.Skip(4).ToArray()
});
i++;
}
Log.Info($"[RESOURCE_LOADER] {maps.Count} Maps loaded");
return maps;
}
private void TryHydrateDatFileFromDatabase(string datFileName, string targetPath)
{
try
{
using var conn = OpenConnection();
using var cmd = new NpgsqlCommand("SELECT content FROM resource_files WHERE category='dat' AND relative_path=@path LIMIT 1;", conn);
cmd.Parameters.AddWithValue("path", $"dat/{datFileName}");
object result = cmd.ExecuteScalar();
if (result is byte[] bytes && bytes.Length > 0)
{
Directory.CreateDirectory(Path.GetDirectoryName(targetPath) ?? _config.GameDataPath);
File.WriteAllBytes(targetPath, bytes);
Log.Info($"[DB_FIRST] Hydrated {datFileName} from resource_files");
}
}
catch (Exception ex)
{
Log.Error($"[DB_FIRST] Could not hydrate {datFileName} from database", ex);
}
}
private void TryHydrateMapFilesFromDatabase()
{
try
{
Directory.CreateDirectory(_config.GameMapsPath);
using var conn = OpenConnection();
using var cmd = new NpgsqlCommand("SELECT relative_path, content FROM resource_files WHERE category='maps';", conn);
using var reader = cmd.ExecuteReader();
int count = 0;
while (reader.Read())
{
string relative = reader.GetString(0).Replace('/', Path.DirectorySeparatorChar);
byte[] content = (byte[])reader[1];
string path = Path.Combine(_config.ResourcePaths, relative);
Directory.CreateDirectory(Path.GetDirectoryName(path) ?? _config.GameMapsPath);
File.WriteAllBytes(path, content);
count++;
}
if (count > 0)
{
Log.Info($"[DB_FIRST] Hydrated {count} map files from resource_files");
}
}
catch (Exception ex)
{
Log.Error("[DB_FIRST] Could not hydrate map files from database", ex);
}
}
private static NpgsqlConnection OpenConnection()
{
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";
var conn = new NpgsqlConnection($"Host={host};Port={port};Database={db};Username={user};Password={pass}");
conn.Open();
return conn;
}
}
}