초기커밋

This commit is contained in:
2025-05-01 07:20:41 +09:00
commit 98bb2e3c5c
2747 changed files with 646947 additions and 0 deletions

View File

@@ -0,0 +1,584 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using Amazon.S3.Model;
using Axion.Collections.Concurrent;
using NeoSmart.AsyncLock;
using Microsoft.Extensions.Logging;
using ServerCore; using ServerBase;
using ServerCommon;
using MetaAssets;
using META_ID = System.UInt32;
using LAND_AUCTION_KEY = System.String;
using REQUESTOR_ID = System.String;
namespace GameServer
{
public class LandAuctionManager : Singleton<LandAuctionManager>
{
private AsyncLock m_reserved_lock = new();
// 랜드 경매가 활성화중인 목록
private ConcurrentDictionary<META_ID, LandAuction> m_activitings = new();
// 랜드 경매가 종료된 목록
private ConcurrentDictionary<META_ID, LandAuction> m_records = new();
public LandAuctionManager()
{
}
public async Task<Result> tryActivitingLandAuctions( REQUESTOR_ID requestorId
, List<META_ID> toAddActivitings
, string callTid )
{
var result = new Result();
var err_msg = string.Empty;
Stopwatch? stopwatch = null;
var event_tid = string.Empty;
var server_logic = GameServerApp.getServerLogic();
var server_config = server_logic.getServerConfig();
using ( var releaser = await m_reserved_lock.LockAsync() )
{
if(0 < toAddActivitings.Count)
{
// 1. 현재 활성화중인 랜드 경매 키를 읽어 온다.
var activiting_keys = getActivitings().Keys.ToList();
// 2. 활성화 목록에 추가할 랜드 경매 키를 추출 한다.
var to_add_reserved_keys = KeyComparer.getKeysOnlyInSecond(activiting_keys, toAddActivitings);
// 3. 신규 랜드 경매를 활성화 목록에 추가 한다.
foreach (var land_meta_id in to_add_reserved_keys)
{
result = await addActivitingLandAuctionByReservationKey(land_meta_id);
if (result.isFail())
{
err_msg = $"Failed to addActivitingLandAuctionByReservationKey() !!!, in onTaskTick() : {result.toBasicString()} - landMetaId:{land_meta_id}, {toBasicString()}";
Log.getLogger().error(err_msg);
continue;
}
}
}
// 4. 활성화중인 모든 랜드 경매를 업데이트 한다.
var activitings = getActivitings().Values.ToList();
foreach (var land_auction in activitings)
{
if (true == server_config.PerformanceCheckEnable)
{
event_tid = System.Guid.NewGuid().ToString("N");
stopwatch = Stopwatch.StartNew();
}
var land_auction_action = land_auction.getEntityAction<LandAuctionAction>();
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!!");
var fn_land_auction_check = async delegate ()
{
var err_msg = $"LandAuctionCheck in LandAuctionCheckTicker.onTaskTick() !!! - TID:{callTid} - {land_auction.toBasicString()}";
Log.getLogger().debug(err_msg);
var result = new Result();
var land_meta_id = land_auction_action.getLandMetaId();
result = await land_auction_action.tryCheckLandAuction(land_meta_id, requestorId, true);
if (result.isFail())
{
err_msg = $"Failed to tryCheckLandAuction() !!! : {result.toBasicString()} - {land_auction.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
err_msg = $"Successed LandAuctionAction.tryCheckLandAuctionByTicker() !!! - TID:{callTid} - {land_auction.toBasicString()}";
Log.getLogger().debug(err_msg);
return result;
};
result = await land_auction.runTransactionRunnerSafelyWithTransGuid( requestorId
, TransactionIdType.PrivateContents, "LandAuctionCheck"
, fn_land_auction_check);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {land_auction.toBasicString()}";
Log.getLogger().error(err_msg);
}
if (null != stopwatch)
{
var elapsed_msec = stopwatch.ElapsedMilliseconds;
stopwatch.Stop();
if (1000 <= elapsed_msec)
{
Log.getLogger().debug( $"{this.getTypeName()} Performance alert !!! : Execution delayed !!!"
+ $" - ETID:{event_tid}, ElapsedMSec:{elapsed_msec}");
}
}
}
}
return result;
}
public async Task<Result> tryConfigureAndAddReservedLandAuctioKeyAll(REQUESTOR_ID requstorId)
{
var result = new Result();
var err_msg = string.Empty;
var reserved_land_meta_ids = new HashSet<META_ID>();
(var auctionable_land_meta_ids, var calculated_ttl_sec) = getAuctionableLandMetaIdsWithTtlSec();
if(0 >= auctionable_land_meta_ids.Count)
{
return result;
}
// 1. 랜드 경매 예약 설정 WriteLock 권한을 획득 한다.
var is_success = await LandAuctionCacheHelper.tryAcquireWriteLockWithLandAuctionReservation(requstorId, calculated_ttl_sec);
if (true == is_success)
{
foreach (var land_meta_id in auctionable_land_meta_ids)
{
var is_continue = false;
// 1.1. 랜드 경매의 예약 가능 여부를 체크하고 예약 설정 한다.
(result, var is_to_add_activiting) = await LandAuctionReservationHelper.configureNextLandAuctionToDb(land_meta_id);
if (result.isFail())
{
err_msg = $"Failed to configureNextAuctionToDb() !!! : {result.toBasicString()} - landMetaId:{land_meta_id}";
Log.getLogger().error(err_msg);
is_continue = true;
}
if (false == is_to_add_activiting)
{
is_continue = true;
}
if (true == is_continue)
{
continue;
}
// 랜드 메타 id를 예약 목록에 등록 한다.
if (false == reserved_land_meta_ids.Add(land_meta_id))
{
err_msg = $"Failed to Add() !!!, in tryConfigureAndAddReservedLandAuctionAll(), Already exist Reserved Key !!! : landMetaId:{land_meta_id}";
Log.getLogger().error(err_msg);
continue;
}
err_msg = $"LandAuction ReservedKeys to add Key !!! : landMetaId:{land_meta_id}";
Log.getLogger().debug(err_msg);
}
await LandAuctionCacheHelper.tryReleaseWriteLockWithLandAuctionReservation(requstorId);
if (0 < reserved_land_meta_ids.Count)
{
LandAuctionNotifyHelper.broadcast_GS2GS_NTF_LAND_AUCTION_RESERVATION(reserved_land_meta_ids.ToList());
}
}
return result;
}
private (List<META_ID>, short) getAuctionableLandMetaIdsWithTtlSec()
{
var auctionable_land_meta_ids = new HashSet<META_ID>();
var err_msg = string.Empty;
foreach (var each in MetaData.Instance._LandTable)
{
var land_meta = each.Value;
var land_meta_id = (META_ID)land_meta.LandId;
if (EditorType.USER != land_meta.Editor)
{
continue;
}
var result = OwnedLandHelper.checkLandWithoutOwner((META_ID)land_meta_id);
if (result.isFail())
{
err_msg = $"Failed to checkLandWithoutOwner() !!! : {result.toBasicString()}, landMetaId:{land_meta_id}";
Log.getLogger().debug(err_msg);
continue;
}
if(false == auctionable_land_meta_ids.Add(land_meta_id))
{
err_msg = $"Failed to Add() !!!, in getAuctionableLandMetaIdsWithTtlSec() - landMetaId:{land_meta_id}, {toBasicString()}";
Log.getLogger().error(err_msg);
continue;
}
}
short ttl_sec = 0;
if(0 < auctionable_land_meta_ids.Count)
{
ttl_sec = (short)(auctionable_land_meta_ids.Count * 2);
}
return (auctionable_land_meta_ids.ToList(), ttl_sec);
}
public async Task<Result> addActivitingLandAuctionByReservationKey(META_ID landMetaId)
{
var result = new Result();
var err_msg = string.Empty;
if (false == m_activitings.TryGetValue(landMetaId, out var found_land_auction))
{
var new_land_auction = new LandAuction();
result = await new_land_auction.onInit();
if (result.isFail())
{
err_msg = $"Failed to LandAuction.onInit() !!!, in add_land_auction() - landMetaId:{landMetaId}, {toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
m_activitings[landMetaId] = new_land_auction;
found_land_auction = new_land_auction;
var registry_attribute = new_land_auction.getEntityAttribute<LandAuctionRegistryAttribute>();
NullReferenceCheckHelper.throwIfNull(registry_attribute, () => $"registry_attribute is null !!! - landMetaId:{landMetaId}, {toBasicString()}");
registry_attribute.LandMetaId = landMetaId;
}
var land_auction_action = found_land_auction.getEntityAction<LandAuctionAction>();
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {found_land_auction.toBasicString()}");
err_msg = $"LandAuction Activitings <= ReservedKeys !!! : landMetaId:{landMetaId}, auctionNumber:{land_auction_action.getAuctionNumber()}";
Log.getLogger().debug(err_msg);
return result;
}
public async Task<Result> tryLoadLandAuctionAll()
{
var result = new Result();
var err_msg = string.Empty;
(result, var activity_docs) = await LandAuctionDbHelper.readLandAuctionActivityDocsFromDb();
if (result.isFail())
{
err_msg = $"Failed to readLandAuctionActivityDocsFromDb() !!! : {result.toBasicString()} - {toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
NullReferenceCheckHelper.throwIfNull(activity_docs, () => $"activity_docs is null !!! - {toBasicString()}");
foreach(var activity_doc in activity_docs)
{
var activity_attrib = activity_doc.getAttrib<LandAuctionActivityAttrib>();
NullReferenceCheckHelper.throwIfNull(activity_attrib, () => $"activity_attrib is null !!! - {toBasicString()}");
var land_meta_id = activity_attrib.LandMetaId;
var auction_number = activity_attrib.AuctionNumber;
(var registry_result, _) = await tryLoadLandAuctionByMetaId(land_meta_id);
if(registry_result.isFail())
{
err_msg = $"Failed to tryLoadLandAuctionByMetaId() !!! : {registry_result.toBasicString()} - {toBasicString()}";
Log.getLogger().error(err_msg);
continue;
}
}
(result, var record_docs) = await LandAuctionDbHelper.readLandAuctionRecordDocsFromDb();
if (result.isFail())
{
err_msg = $"Failed to readLandAuctionRecordDocsFromDb() !!! : {result.toBasicString()} - {toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
NullReferenceCheckHelper.throwIfNull(record_docs, () => $"record_docs is null !!!");
foreach (var record_doc in record_docs)
{
var record_attrib = record_doc.getAttrib<LandAuctionRecordAttrib>();
NullReferenceCheckHelper.throwIfNull(record_attrib, () => $"record_attrib is null !!! - {toBasicString()}");
var land_meta_id = record_attrib.LandMetaId;
var auction_number = record_attrib.AuctionNumber;
var found_land_auction = findRecordLandAuction(land_meta_id);
if(null == found_land_auction)
{
err_msg = $"Not found record LandAuction !!!, in Record LandAuction : landMetaId:{land_meta_id}, auctionNumber:{auction_number} - {toBasicString()}";
Log.getLogger().error(err_msg);
continue;
}
var land_auction_action = found_land_auction.getEntityAction<LandAuctionAction>();
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {toBasicString()}");
var record_result = await land_auction_action.tryLoadLandAuctionForRecord(auction_number);
if (record_result.isFail())
{
err_msg = $"Failed to tryLoadLandAuctionForRecord() !!! : {record_result.toBasicString()} - {toBasicString()}";
Log.getLogger().error(err_msg);
continue;
}
}
return result;
}
public void sendLandAuctionAllToUserGuid(Player player)
{
var err_msg = string.Empty;
if( 0 >= m_activitings.Count
&& 0 >= m_records.Count )
{
err_msg = $"No loaded LandAuction !!! - {toBasicString()}, {player.toBasicString()}";
Log.getLogger().warn(err_msg);
return;
}
var land_auction_summaries = getLandAuctionAll();
if (false == LandAuctionNotifyHelper.send_GS2C_NTF_LAND_AUCTION_ALL_LOAD(player, land_auction_summaries))
{
err_msg = $"Failed to send_GS2C_NTF_LAND_AUCTION_ALL_LOAD() !!! - {toBasicString()} - {player.toBasicString()}";
Log.getLogger().warn(err_msg);
return;
}
Log.getLogger().info($"Sent LandAuction All : Count:{land_auction_summaries.Count} - {toBasicString()}");
}
public async Task<(Result, LandAuction?)> tryLoadLandAuctionByMetaId(META_ID landMetaId)
{
var result = new Result();
var err_msg = string.Empty;
var land_auction = new LandAuction();
result = land_auction.onInit().GetAwaiter().GetResult();
if (result.isFail())
{
err_msg = $"Failed to LandAuction.onInit() !!!, in add_land_auction() - landMetaId:{landMetaId}, {toBasicString()}";
Log.getLogger().error(err_msg);
return (result, null);
}
var land_auction_action = land_auction.getEntityAction<LandAuctionAction>();
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - landMetaId:{landMetaId}, {toBasicString()}");
result = await land_auction_action.tryLoadLandAuctionMetaWithLock(landMetaId);
if (result.isFail())
{
err_msg = $"Failed to tryLoadLandAuctionMeta() !!! : {result.toBasicString()} - {toBasicString()}";
Log.getLogger().error(err_msg);
return (result, null);
}
if (true == land_auction_action.isLandAuctionState(LandAuctionState.Ended))
{
m_records.TryAdd(landMetaId, land_auction);
}
else
{
var add_land_auction = delegate (META_ID landMetaId)
{
return land_auction;
};
var found_land_auction = m_activitings.AddOrUpdate(landMetaId, add_land_auction, (key, value) => value);
NullReferenceCheckHelper.throwIfNull(found_land_auction, () => $"found_land_auction is null !!! - landMetaId:{landMetaId}, {toBasicString()}");
}
return (result, land_auction);
}
public async Task<(Result, LandAuctionCheckResult?)> tryCheckActivitingLandAuctionByMetaId(META_ID landMetaId, REQUESTOR_ID requestorId)
{
var result = new Result();
var err_msg = string.Empty;
var is_load_required_meta = true;
if (false == MetaData.Instance._LandTable.TryGetValue((Int32)landMetaId, out var land_meta_data))
{
err_msg = $"Failed to TryGetValue() !!! : landMetaId:{landMetaId} - requestorId:{requestorId}";
result.setFail(ServerErrorCode.LandMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null);
}
if (false == m_activitings.TryGetValue(landMetaId, out var found_land_auction))
{
err_msg = $"Failed to TryGetValue() !!! : landMetaId:{landMetaId} - requestorId:{requestorId}";
result.setFail(ServerErrorCode.LandAuctionNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null);
}
NullReferenceCheckHelper.throwIfNull(found_land_auction, () => $"found_land_auction is null !!! - landMetaId:{landMetaId}, requestorId:{requestorId}");
var land_auction_action = found_land_auction.getEntityAction<LandAuctionAction>();
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - landMetaId:{landMetaId}, requestorId:{requestorId}, {toBasicString()}");
(result, var auction_check_result) = await land_auction_action.tryCheckActivitingLandAuctionWithTransactionRunner(landMetaId, requestorId, is_load_required_meta);
if (result.isFail())
{
err_msg = $"Failed to tryCheckActivitingLandAuctionWithTransactionRunner() !!! : {result.toBasicString()} - landMetaId:{landMetaId}, requestorId{requestorId}, {toBasicString()}";
Log.getLogger().error(err_msg);
return (result, null);
}
return (result, auction_check_result);
}
public void activitingToRecord(META_ID landMetaId, LandAuction landAuction)
{
var err_msg = string.Empty;
if(false == m_activitings.TryRemove(landMetaId, out _))
{
err_msg = $"Failed to TryRemove() !!!, in Activitings : {landAuction.toBasicString()} - {toBasicString()}";
Log.getLogger().debug(err_msg);
}
m_records[landMetaId] = landAuction;
var land_auction_action = landAuction.getEntityAction<LandAuctionAction>();
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {landAuction.toBasicString()}");
err_msg = $"LandAuction Records <= Activitings !!! : landMetaId:{landMetaId}, auctionNumber:{land_auction_action.getAuctionNumber()}";
Log.getLogger().debug(err_msg);
}
public LandAuction? findRecordLandAuction(META_ID landMetaId)
{
m_records.TryGetValue(landMetaId, out var found_land_auction);
return found_land_auction;
}
public LandAuction? findActivitingLandAuction(META_ID landMetaId)
{
m_activitings.TryGetValue(landMetaId, out var found_land_auction);
return found_land_auction;
}
public bool hasActivitingLandAuction(META_ID landMetaId)
{
return m_activitings.ContainsKey(landMetaId);
}
public async Task<List<LandAuctionCompact>> getLandAuctionHistoryAll()
{
var land_auction_compacts = new List<LandAuctionCompact>();
foreach (var each in m_records)
{
var land_auction = each.Value;
var land_auction_action = land_auction.getEntityAction<LandAuctionAction>();
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {toBasicString()}");
if (true == land_auction_action.isHistory())
{
var land_auction_compact = await land_auction_action.toLandAuctionCompact();
if (null == land_auction_compact)
{
continue;
}
land_auction_compacts.Add(land_auction_compact);
}
}
return land_auction_compacts;
}
public List<LandAuctionSummary> getLandAuctionScheduleAll()
{
var land_auction_summaries = new List<LandAuctionSummary>();
foreach (var each in m_activitings)
{
var land_auction = each.Value;
var land_auction_action = land_auction.getEntityAction<LandAuctionAction>();
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {toBasicString()}");
if(true == land_auction_action.isScheduling())
{
land_auction_summaries.Add(land_auction_action.toLandAuctionSummary());
}
}
return land_auction_summaries;
}
public List<LandAuctionSummary> getLandAuctionAll()
{
var land_auction_summaries = new List<LandAuctionSummary>();
foreach (var each in m_activitings)
{
var land_auction = each.Value;
var land_auction_action = land_auction.getEntityAction<LandAuctionAction>();
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {toBasicString()}");
if ( true == land_auction_action.isLandAuctionState(LandAuctionState.Scheduled )
|| true == land_auction_action.isLandAuctionState(LandAuctionState.Started )
|| true == land_auction_action.isLandAuctionState(LandAuctionState.Ended )
)
{
land_auction_summaries.Add(land_auction_action.toLandAuctionSummary());
}
}
foreach (var each in m_records)
{
var land_auction = each.Value;
var land_auction_action = land_auction.getEntityAction<LandAuctionAction>();
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {toBasicString()}");
if(land_auction_action.isLandAuctionResult(LandAuctionResult.Successed))
{
land_auction_summaries.Add(land_auction_action.toLandAuctionSummary());
}
}
return land_auction_summaries;
}
public ConcurrentDictionary<META_ID, LandAuction> getRecords() => m_records;
public ConcurrentDictionary<META_ID, LandAuction> getActivitings() => m_activitings;
public string toBasicString()
{
return $"{GameServerApp.getServerLogic().toBasicString()}";
}
}
}