Files
caliverse_server/BrokerApiCore/Meta/BrokerMetaDataManager.cs
2025-05-01 07:23:28 +09:00

259 lines
7.3 KiB
C#

using System.Collections.Concurrent;
using MetaAssets;
using ServerBase;
using ServerCommon;
namespace BrokerApiCore;
public class BrokerMetaTable
{
public string Version { get; private set; }
private readonly MetaTable m_meta_table = new MetaTable();
public ProductMetaTable ProductMetaTable => m_meta_table.ProductMetaTable;
// TODO: PlanetItemExchangePolicyMetaTable를 PlanetItemExchangePolicyTable로 이름 변경
public PlanetItemExchangePolicyMetaTable PlanetItemExchangePolicyMetaTable => m_meta_table.PlanetItemExchangePolicyMetaTable;
public SystemMailMetaTable SystemMailMetaTable => m_meta_table.SystemMailMetaTable;
public ItemMetaTable ItemMetaTable => m_meta_table.ItemMetaTable;
public TextStringMetaTable TextStringMetaTable => m_meta_table.TextStringMetaTable;
public BrokerMetaTable(MetaTable? source = null, string? versionName = null)
{
if (source != null)
{
m_meta_table = source;
Version = versionName ?? Guid.NewGuid().ToString();
}
}
}
public class BrokerApiMetaLoader : IDisposable
{
readonly string m_input_path = "resource/meta";
// 스레드 세이프한 딕셔너리로 변경
private readonly ConcurrentDictionary<string, BrokerMetaTable> m_meta_tables =
new ConcurrentDictionary<string, BrokerMetaTable>();
// 더 세밀한 제어가 필요한 경우를 위한 ReaderWriterLockSlim 추가
private readonly ReaderWriterLockSlim m_lock = new ReaderWriterLockSlim();
// 기본 메타테이블 캐싱
private BrokerMetaTable m_default_meta_table;
public Result load(string? dataPath = null)
{
try
{
m_lock.EnterWriteLock();
// 기본 메타 테이블 로드
var (result, meta_table) = loadMetaData(dataPath);
if (result.isFail() || meta_table == null)
{
return result;
}
if (m_meta_tables.TryAdd(meta_table.Version, meta_table))
{
m_default_meta_table = meta_table;
}
return result;
}
finally
{
m_lock.ExitWriteLock();
}
}
private (Result, BrokerMetaTable?) loadMetaData(string? dataPath = null, string? versionName = null)
{
var result = new Result();
var input_path = dataPath ?? m_input_path;
try
{
var full_path = Path.GetFullPath(input_path, Environment.CurrentDirectory);
if (!Directory.Exists(full_path))
{
full_path = Path.GetFullPath(input_path, AppContext.BaseDirectory);
if (!Directory.Exists(full_path))
{
result.setFail(ServerErrorCode.MetaDataLoadFailed, $"Meta data path not found: {input_path}");
return (result, null);
}
}
var meta_table = new MetaTable();
meta_table.loadForBrokerApi(full_path);
var errors = new ValidatorErrorCollection();
foreach (var data in meta_table.PlanetItemExchangePolicyMetaTable.PlanetItemExchangePolicyDataList)
{
validate(data, meta_table, errors);
}
if (errors.HasError)
{
errors.log();
}
//TODO: ProductMetaTable, SystemMailMetaTable, ItemMetaTable 에 대한 검사도 필요하다.
var broker_meta_table = new BrokerMetaTable(meta_table, versionName);
return (result, broker_meta_table);
}
catch (Exception ex)
{
result.setFail(ServerErrorCode.MetaDataLoadFailed, $"Meta data load failed => {ex.Message}");
}
return (result, null);
}
public BrokerMetaTable getMetaTable(string? versionName = null!)
{
try
{
m_lock.EnterReadLock();
if (string.IsNullOrEmpty(versionName) || versionName == "default")
{
return m_default_meta_table;
}
return m_meta_tables.GetValueOrDefault(versionName, m_default_meta_table);
// 요청된 버전이 없으면 기본 메타테이블 반환
}
finally
{
m_lock.ExitReadLock();
}
}
private ValidatorErrorCollection validate(PlanetItemExchangePolicyMetaData planetItemExchange, MetaTable metaTable, ValidatorErrorCollection errors)
{
checkValidCaliverseItem(planetItemExchange);
checkValidPlanetItem(planetItemExchange);
return errors;
void checkValidPlanetItem(PlanetItemExchangePolicyMetaData data)
{
var planet_item_type = toEnum(data.PlanetItemType, PlanetItemType.None);
switch (planet_item_type)
{
case PlanetItemType.Igm26Currency:
{
var currency_type = toEnum(data.PlanetItemId, PlanetCurrencyType.None);
if (currency_type == PlanetCurrencyType.None)
{
addError(nameof(data.PlanetItemId),
$"Planet 화폐 타입이 잘못되었습니다 => PlanetItemId:{data.PlanetItemId}");
}
// if (data.PlanetItemAmount >= 0)
// {
// // 재화는 차감만 가능
// addError(nameof(data.PlanetItemAmount),
// $"Planet 화폐 수량은 양수 합니다 => PlanetItemAmount:{data.PlanetItemAmount}");
// }
break;
}
case PlanetItemType.Igm26Quest:
break;
case PlanetItemType.None:
default:
addError(nameof(data.PlanetItemId),
$"Planet 화폐 타입이 잘못되었습니다 => PlanetItemId:{data.PlanetItemId}");
break;
}
}
void checkValidCaliverseItem(PlanetItemExchangePolicyMetaData data)
{
var caliverse_item_type = toEnum(data.CaliverseItemType, CaliverseItemType.None);
switch (caliverse_item_type)
{
case CaliverseItemType.Currency:
{
var currency_type = toEnum(data.CaliverseItemId, CurrencyType.None);
if (currency_type == CurrencyType.None)
{
addError(nameof(data.CaliverseItemId),
$"Caliverse 화폐 타입이 잘못되었습니다 => CaliverseItemId:{data.CaliverseItemId}");
}
// if (data.CaliverseItemAmount >= 0)
// {
// // 재화는 차감만 가능
// addError(nameof(data.CaliverseItemAmount),
// $"Caliverse 화폐 수량은 음수여야 합니다 => CaliverseItemAmount:{data.CaliverseItemAmount}");
// }
break;
}
case CaliverseItemType.CaliverseProduct:
{
var product_id = Convert.ToInt32(data.CaliverseItemId);
if (metaTable.ProductMetaTable.ProductMetaDataListbyId.ContainsKey(product_id) == false)
{
addError(nameof(data.CaliverseItemId),
$"CaliverseItemId이 존재하지 않습니다 => CaliverseItemId: {data.CaliverseItemId}");
}
if (data.CaliverseItemAmount < 0)
{
addError(nameof(data.CaliverseItemAmount),
$"Product 수량은 0보다 커야합니다 => CaliverseItemAmount:{data.CaliverseItemAmount}");
}
break;
}
case CaliverseItemType.None:
default:
{
addError(nameof(data.CaliverseItemType),
$"Caliverse 아이템 타입이 잘못되었습니다 => CaliverseItemType:{data.CaliverseItemType}");
break;
}
}
}
void addError(string variableName, string msg)
{
errors.add($"Invalid PlanetItemExchangePolicyMetaData Value: {variableName} - {msg}");
}
TEnum toEnum<TEnum>(string enumTypeString, TEnum defaultValue) where TEnum : struct, Enum
{
var enum_type_string_result = enumTypeString.Replace("_", "");
return Enum.TryParse<TEnum>(enum_type_string_result, ignoreCase: true, out var enum_type)
? enum_type
: defaultValue;
}
}
// 리소스 해제를 위한 Dispose 패턴 구현
private bool m_disposed = false;
public void Dispose()
{
if (!m_disposed)
{
m_lock.Dispose();
m_disposed = true;
}
}
}
// 최신 메타테이블을 참조하는 클래스
public class BrokerMetaTableRef
{
public BrokerMetaTable MetaTable => m_meta_table;
private readonly BrokerMetaTable m_meta_table;
public BrokerMetaTableRef(BrokerMetaTable metaTable)
{
m_meta_table = metaTable;
}
}