254 lines
No EOL
12 KiB
C#
254 lines
No EOL
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Npgsql;
|
|
using PhoenixLib.Logging;
|
|
using WingsAPI.Data.GameData;
|
|
using WingsEmu.DTOs.BCards;
|
|
using WingsEmu.DTOs.Buffs;
|
|
using WingsEmu.Game._enum;
|
|
using WingsEmu.Packets.Enums;
|
|
|
|
namespace Plugin.ResourceLoader.Loaders
|
|
{
|
|
public class CardResourceFileLoader : IResourceLoader<CardDTO>
|
|
{
|
|
private readonly ResourceLoadingConfiguration _config;
|
|
|
|
public CardResourceFileLoader(ResourceLoadingConfiguration config) => _config = config;
|
|
|
|
public async Task<IReadOnlyList<CardDTO>> LoadAsync()
|
|
{
|
|
string filePath = Path.Combine(_config.GameDataPath, "Card.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("Card.dat", filePath);
|
|
}
|
|
}
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
throw new FileNotFoundException($"{filePath} should be present");
|
|
}
|
|
|
|
|
|
var card = new CardDTO();
|
|
var cards = new List<CardDTO>();
|
|
|
|
int counter = 0;
|
|
bool itemAreaBegin = false;
|
|
|
|
using var npcIdStream = new StreamReader(filePath, Encoding.GetEncoding(1252));
|
|
string line;
|
|
while ((line = await npcIdStream.ReadLineAsync()) != null)
|
|
{
|
|
string[] currentLine = line.Split('\t');
|
|
|
|
switch (currentLine.Length)
|
|
{
|
|
case > 2 when currentLine[1] == "VNUM":
|
|
card = new CardDTO
|
|
{
|
|
Id = Convert.ToInt16(currentLine[2])
|
|
};
|
|
itemAreaBegin = true;
|
|
break;
|
|
case > 2 when currentLine[1] == "NAME":
|
|
card.Name = currentLine[2];
|
|
break;
|
|
case > 3 when currentLine[1] == "GROUP":
|
|
{
|
|
if (!itemAreaBegin)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
card.GroupId = Convert.ToInt32(currentLine[2]);
|
|
card.Level = Convert.ToByte(currentLine[3]);
|
|
break;
|
|
}
|
|
case > 3 when currentLine[1] == "STYLE":
|
|
card.BuffCategory = (BuffCategory)byte.Parse(currentLine[2]);
|
|
card.BuffType = Convert.ToByte(currentLine[3]);
|
|
card.ElementType = Convert.ToByte(currentLine[4]);
|
|
card.IsConstEffect = currentLine[5] == "1";
|
|
card.BuffPartnerLevel = Convert.ToByte(currentLine[6]);
|
|
break;
|
|
case > 3 when currentLine[1] == "EFFECT":
|
|
card.EffectId = Convert.ToInt32(currentLine[2]);
|
|
break;
|
|
case > 3 when currentLine[1] == "TIME":
|
|
card.Duration = Convert.ToInt32(currentLine[2]);
|
|
card.SecondBCardsDelay = Convert.ToInt32(currentLine[3]);
|
|
break;
|
|
default:
|
|
{
|
|
BCardDTO bCard;
|
|
switch (currentLine.Length)
|
|
{
|
|
case > 3 when currentLine[1] == "1ST":
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
if (currentLine[2 + i * 6] == "-1" || currentLine[2 + i * 6] == "0")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int first = int.Parse(currentLine[6 + i * 6]);
|
|
int second = int.Parse(currentLine[7 + i * 6]);
|
|
|
|
int firstModulo = first % 4;
|
|
firstModulo = firstModulo switch
|
|
{
|
|
-1 => 1,
|
|
-2 => 2,
|
|
-3 => 1,
|
|
_ => firstModulo
|
|
};
|
|
|
|
int secondModulo = second % 4;
|
|
secondModulo = secondModulo switch
|
|
{
|
|
-1 => 1,
|
|
-2 => 2,
|
|
-3 => 1,
|
|
_ => secondModulo
|
|
};
|
|
|
|
byte tickPeriod = byte.Parse(currentLine[5 + i * 6]);
|
|
bCard = new BCardDTO
|
|
{
|
|
CardId = card.Id,
|
|
Type = byte.Parse(currentLine[2 + i * 6]),
|
|
SubType = (byte)((Convert.ToByte(currentLine[3 + i * 6]) + 1) * 10 + 1 + (first < 0 ? 1 : 0)),
|
|
FirstData = (int)Math.Abs(Math.Floor(first / 4.0)),
|
|
SecondData = (int)Math.Abs(Math.Floor(second / 4.0)),
|
|
ProcChance = int.Parse(currentLine[4 + i * 6]),
|
|
TickPeriod = tickPeriod == 0 ? null : (byte?)(tickPeriod * 2),
|
|
FirstDataScalingType = (BCardScalingType)firstModulo,
|
|
SecondDataScalingType = (BCardScalingType)secondModulo,
|
|
IsSecondBCardExecution = false
|
|
};
|
|
|
|
card.Bcards.Add(bCard);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case > 3 when currentLine[1] == "2ST":
|
|
{
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
if (currentLine[2 + i * 6] == "-1" || currentLine[2 + i * 6] == "0")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int first = int.Parse(currentLine[6 + i * 6]);
|
|
int second = int.Parse(currentLine[7 + i * 6]);
|
|
|
|
int firstModulo = first % 4;
|
|
firstModulo = firstModulo switch
|
|
{
|
|
-1 => 1,
|
|
-2 => 2,
|
|
-3 => 1,
|
|
_ => firstModulo
|
|
};
|
|
|
|
int secondModulo = second % 4;
|
|
secondModulo = secondModulo switch
|
|
{
|
|
-1 => 1,
|
|
-2 => 2,
|
|
-3 => 1,
|
|
_ => secondModulo
|
|
};
|
|
|
|
byte tickPeriod = byte.Parse(currentLine[5 + i * 6]);
|
|
bCard = new BCardDTO
|
|
{
|
|
CardId = card.Id,
|
|
Type = byte.Parse(currentLine[2 + i * 6]),
|
|
SubType = (byte)((Convert.ToByte(currentLine[3 + i * 6]) + 1) * 10 + 1 + (first < 0 ? 1 : 0)),
|
|
FirstData = (int)Math.Abs(Math.Floor(first / 4.0)),
|
|
SecondData = (int)Math.Abs(Math.Floor(second / 4.0)),
|
|
ProcChance = int.Parse(currentLine[4 + i * 6]),
|
|
TickPeriod = tickPeriod == 0 ? null : (byte?)(tickPeriod * 2),
|
|
FirstDataScalingType = (BCardScalingType)firstModulo,
|
|
SecondDataScalingType = (BCardScalingType)secondModulo,
|
|
IsSecondBCardExecution = true
|
|
};
|
|
|
|
card.Bcards.Add(bCard);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case > 3 when currentLine[1] == "LAST":
|
|
card.TimeoutBuff = short.Parse(currentLine[2]);
|
|
card.TimeoutBuffChance = byte.Parse(currentLine[3]);
|
|
itemAreaBegin = false;
|
|
cards.Add(card);
|
|
counter++;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Log.Info($"[RESOURCE_LOADER] {cards.Count.ToString()} act desc loaded");
|
|
return cards;
|
|
}
|
|
|
|
private void TryHydrateDatFileFromDatabase(string datFileName, string targetPath)
|
|
{
|
|
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 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);
|
|
}
|
|
}
|
|
}
|
|
} |