초기커밋

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,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServerCore; using ServerBase;
using SESSION_ID = System.Int32;
using META_ID = System.UInt32;
using ENTITY_GUID = System.String;
using ACCOUNT_ID = System.String;
using OWNER_GUID = System.String;
using USER_GUID = System.String;
using CHARACTER_GUID = System.String;
using ITEM_GUID = System.String;
namespace ServerBase;
public abstract partial class EntityActionBase : IInitializer
{
private EntityBase m_owner;
public EntityActionBase(EntityBase owner)
{
m_owner = owner;
}
public abstract Task<Result> onInit();
public abstract void onClear();
public virtual async Task onTick()
{
await Task.CompletedTask;
}
public virtual string toBasicString()
{
return $"{this.getTypeName()}";
}
}

View File

@@ -0,0 +1,72 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using ServerCore; using ServerBase;
namespace ServerBase;
public class EntityAggregator<TKey, TCounterType>
where TKey : ITuple
where TCounterType : struct
{
private readonly ConcurrentDictionary<TKey, TCounterType> m_counters = new();
public EntityAggregator()
{
}
public void reset()
{
m_counters.Clear();
}
public void incCounter(TKey key, TCounterType toIncValue, Func<TCounterType, TCounterType, TCounterType> fnUpdate)
{
var add_counter = delegate (TKey key)
{
return toIncValue;
};
var update_recorder = delegate (TKey key, TCounterType currValue)
{
return fnUpdate(currValue, toIncValue);
};
m_counters.AddOrUpdate(key, add_counter, update_recorder);
}
public void decCounter(TKey key, TCounterType toDecValue, Func<TCounterType, TCounterType, TCounterType> fnUpdate)
{
var add_counter = delegate (TKey key)
{
return toDecValue;
};
var update_recorder = delegate (TKey key, TCounterType currValue)
{
return fnUpdate(currValue, toDecValue);
};
m_counters.AddOrUpdate(key, add_counter, update_recorder);
}
public TCounterType getCounter(TKey key, TCounterType defaultValue)
{
if(false == m_counters.TryGetValue(key, out var found_counter))
{
return defaultValue;
}
return found_counter;
}
public ConcurrentDictionary<TKey, TCounterType> getCounters() => m_counters;
}

View File

@@ -0,0 +1,397 @@
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Threading;
using Newtonsoft.Json;
using NeoSmart;
using NeoSmart.AsyncLock;
using ServerCore; using ServerBase;
using SESSION_ID = System.Int32;
using WORLD_ID = System.UInt32;
using META_ID = System.UInt32;
using ENTITY_GUID = System.String;
using ACCOUNT_ID = System.String;
using OWNER_GUID = System.String;
using USER_GUID = System.String;
using CHARACTER_GUID = System.String;
using ITEM_GUID = System.String;
namespace ServerBase;
public abstract partial class EntityAttributeBase : IInitializer
{
public enum StateType
{
None = 0,
Created, // 신규 정보로 추가 한다. delta count == Stack count !!!
Modified, // +, - : 증가, 감소
Removed, // 제거
}
public class AttributeState : Flags<StateType>
{
public AttributeState()
{
reset();
}
public void tryApplyModifyFlag(bool isTrue)
{
setFlag(StateType.Modified, isTrue);
}
}
#region
private EntityBase m_owner;
#endregion
private bool m_is_origin = true;
private DynamoDbDocBase? m_origin_doc_base_nullable;
private DynamoDbDocBase? m_try_pending_doc_base_nullable;
// CommonResult에 적용 되는가?
private readonly bool m_is_applicable_to_common_result;
private AttributeState m_attribute_state = new();
private bool m_is_upsert = false;
private bool m_is_delete = false;
private EntityRecorder? m_recorder_nullable;
#region Owner Contents [OwnerEntityType, EntityBase]
private OwnerEntityType m_owner_entity_type = OwnerEntityType.None;
private EntityBase? m_entity_of_owner_entity_type = null;
#endregion
private ReaderWriterLockSlim m_rw_lock = new();
private AsyncLock m_async_lock = new();
//=========================================================================================
// Owner 객체와 OwnerEntityType 객체가 동일한 경우
//=========================================================================================
public EntityAttributeBase(EntityBase owner, bool isApplicableCommonResult = false)
{
m_owner = owner;
setEntityOfOwnerEntityType(owner.onGetOwnerEntityType(), owner);
m_is_applicable_to_common_result = isApplicableCommonResult;
}
//=========================================================================================
// Owner 객체와 OwnerEntityType 객체가 다른 경우
//=========================================================================================
public EntityAttributeBase(EntityBase owner, EntityBase entityOfOwnerEntityType, bool isApplicableCommonResult = false)
{
if(false == entityOfOwnerEntityType.isValidOwnerEntityType())
{
throw new ArgumentException($"argument exception isValidOwnerEntityType() !!! : {entityOfOwnerEntityType.toBasicString()} - {toBasicString()}");
}
m_owner = owner;
setEntityOfOwnerEntityType(entityOfOwnerEntityType.onGetOwnerEntityType(), entityOfOwnerEntityType);
m_is_applicable_to_common_result = isApplicableCommonResult;
}
public virtual async Task<Result> onInit()
{
var result = new Result();
return await Task.FromResult(result);
}
public abstract void onClear();
public virtual void newEntityAttribute()
{
getAttributeState().setFlag(StateType.Created, true);
}
public virtual void deleteEntityAttribute()
{
getAttributeState().reset();
m_is_upsert = false;
getAttributeState().setFlag(StateType.Removed, true);
}
public virtual void modifiedEntityAttribute(bool isUpsert = false)
{
if (true == getAttributeState().hasFlag(StateType.Created))
{
return;
}
getAttributeState().setFlag(StateType.Modified, true);
if(true == isUpsert)
{
m_is_upsert = isUpsert;
}
}
public abstract IEntityAttributeTransactor onNewEntityAttributeTransactor();
public abstract EntityAttributeBase onCloned();
protected void deepCopyFromBase(EntityAttributeBase other)
{
m_attribute_state.deepCopy(other.getAttributeState());
}
public virtual DynamoDbDocBase? onCreateDocBase()
{
var err_msg = $"Not implementation EntityAttribute.onCreateDocBase() !!! : {this.getTypeName()} - {getOwner().toBasicString()}";
Log.getLogger().error(err_msg);
throw new NotImplementedException(err_msg);
}
public virtual async Task<(Result, DynamoDbDocBase?)> toDocBase(bool isForQuery = true)
{
var result = new Result();
var err_msg = $"Not implementation EntityAttribute.toDocBase() !!! : {this.getTypeName()} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.NotImplemented, err_msg);
Log.getLogger().warn(result.toBasicString());
return await Task.FromResult<(Result, DynamoDbDocBase?)>((result, null));
}
public virtual async Task<Result> fillupDocBase<TDoc>(TDoc copyToDocBase)
where TDoc : DynamoDbDocBase
{
var result = new Result();
var err_msg = string.Empty;
var owner = getOwner();
var parent = owner.getRootParent();
var copy_to_doc = copyToDocBase as ICopyDocFromEntityAttribute;
if(null == copy_to_doc)
{
err_msg = $"Failed to cast ICopyDocFromEntityAttribute !!! : {copyToDocBase.getTypeName()} - {owner.toBasicString()}";
result.setFail(ServerErrorCode.ClassDoesNotImplementInterfaceInheritance, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
if(false == copy_to_doc.copyDocFromEntityAttribute(this))
{
err_msg = $"Failed to copyDocFromEntityAttribute() !!!, to:{copyToDocBase.getTypeName()}, from:{this.getTypeName()} - {toSummaryString()}, {owner.toBasicString()}";
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
return await Task.FromResult(result);
}
public async Task<Result> fillupDoc4QueryWithAttribute<TDoc>(TDoc docBase)
where TDoc : DynamoDbDocBase
{
var result = new Result();
var err_msg = string.Empty;
var owner = getOwner();
var parent = owner.getRootParent();
result = await fillupDocBase<TDoc>(docBase);
if (result.isFail())
{
err_msg = $"Failed to fillupDocBase() !!! : {result.toBasicString()} - {owner.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
(result, _) = await applyDoc4Query(docBase);
if(result.isFail())
{
return result;
}
return result;
}
protected async Task<(Result, DynamoDbDocBase?)> applyDoc4Query(DynamoDbDocBase docBase)
{
var result = new Result();
var err_msg = string.Empty;
var owner = getOwner();
var parent = owner.getRootParent();
bool is_apply = false;
if (true == getAttributeState().hasFlag(StateType.Created))
{
result = await docBase.newDoc4Query();
if (result.isFail())
{
return (result, null);
}
is_apply = true;
}
else
{
if (true == getAttributeState().hasFlag(StateType.Modified))
{
if (true == m_is_upsert)
{
result = await docBase.upsertDoc4Query();
if (result.isFail())
{
return (result, null);
}
}
else
{
result = await docBase.updateDoc4Query();
if (result.isFail())
{
return (result, null);
}
}
m_is_upsert = false;
is_apply = true;
}
if (true == getAttributeState().hasFlag(StateType.Removed))
{
result = await docBase.deleteDoc4Query();
if (result.isFail())
{
return (result, null);
}
is_apply = true;
setDelete();
}
}
if (false == is_apply)
{
err_msg = $"Invalid AttributeState !!!, all false state - {owner.toBasicString()}";
result.setFail(ServerErrorCode.DynamoDbDocAttributeStateNotSet, err_msg);
return (result, null);
}
getAttributeState().reset();
return (result, docBase);
}
public void enterReadLock()
{
m_rw_lock.EnterReadLock();
}
public void exitReadLock()
{
m_rw_lock.ExitReadLock();
}
public void enterWriteLock()
{
m_rw_lock.EnterWriteLock();
}
public void exitWriteLock()
{
m_rw_lock.ExitWriteLock();
}
public bool hasQueryFlag()
{
return 0 < getAttributeState().getData().Count;
}
#region DB
//=================================================================================================
// EntityAttribute로 Db에 저장할 OwnerEntity를 반환해 준다.
//=================================================================================================
public virtual (Result, OwnerEntityType, OWNER_GUID) onToOwnerEntity4Db(EntityBase ownerEntity)
{
var result = new Result();
result.setFail(ServerErrorCode.NotImplemented, $"Not implemented onToOwnerEntity4Db() !!! - {getOwner().toBasicString()}");
return (result, OwnerEntityType.None, string.Empty);
}
//=========================================================================================
// DB 에 저장되어 있는 정보가 있는 경우 호출되어야 한다.
//=========================================================================================
public void syncOriginDocBaseWithNewDoc<EntityAttributeType>(DynamoDbDocBase newDoc)
where EntityAttributeType : EntityAttributeBase
{
if(true == isOrigin())
{
m_origin_doc_base_nullable = newDoc;
return;
}
var owner = getOwner();
var origin_entity_attribute = owner.getOriginEntityAttribute<EntityAttributeType>();
NullReferenceCheckHelper.throwIfNull(origin_entity_attribute, () => $"origin_entity_attribute is null !!! - {owner.toBasicString()}");
origin_entity_attribute.syncOriginDocBaseWithNewDoc<EntityAttributeType>(newDoc);
}
public DynamoDbDocBase? getOriginDocBase<EntityAttributeType>()
where EntityAttributeType : EntityAttributeBase
{
if (true == isOrigin())
{
return m_origin_doc_base_nullable;
}
var owner = getOwner();
var origin_entity_attribute = owner.getOriginEntityAttribute<EntityAttributeType>();
NullReferenceCheckHelper.throwIfNull(origin_entity_attribute, () => $"origin_entity_attribute is null !!! - {owner.toBasicString()}");
return origin_entity_attribute.getOriginDocBase<EntityAttributeType>();
}
#endregion DB
#region
public virtual string toSummaryString()
{
return $"{this.getTypeName()}, {JsonConvert.SerializeObject(this)}";
}
public virtual string toBasicString()
{
return $"{this.getTypeName()}, isOrigin:{isOrigin()}, hasQueryFlag:{hasQueryFlag()}";
}
#endregion
}

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServerCore; using ServerBase;
using SESSION_ID = System.Int32;
using WORLD_ID = System.UInt32;
using META_ID = System.UInt32;
using ENTITY_GUID = System.String;
using ACCOUNT_ID = System.String;
using OWNER_GUID = System.String;
using USER_GUID = System.String;
using CHARACTER_GUID = System.String;
using ITEM_GUID = System.String;
namespace ServerBase;
public abstract partial class EntityAttributeTransactorBase<TEntityAttribute> : IEntityAttributeTransactor
where TEntityAttribute : EntityAttributeBase
{
public enum TransactionState
{
None = 0,
New, // 생성
Modify, // 변경
Remove, // 제거
Completed // 처리 완료
}
private EntityBase m_owner;
private TEntityAttribute? m_cloned_entity_attribute_nullable;
private TransactionState m_transaction_state = TransactionState.None;
private readonly EntityRecorder m_entity_recorder;
private TEntityAttribute? m_origin_entity_attribute_nullable;
public EntityAttributeTransactorBase(EntityBase owner)
{
m_owner = owner;
m_entity_recorder = new EntityRecorder(owner);
}
public bool cloneFromOriginEntityAttribute(EntityAttributeBase fromOriginEntityAttribute)
{
m_cloned_entity_attribute_nullable = fromOriginEntityAttribute.onCloned() as TEntityAttribute;
if(null == m_cloned_entity_attribute_nullable)
{
var err_msg = $"m_cloned_entity_attribute_nullable is null !!! : toCloneTarget:{typeof(TEntityAttribute).Name} != OriginEntityAttribute:{fromOriginEntityAttribute.getTypeName()} - {getOwner().toBasicString()}";
Log.getLogger().error(err_msg);
return false;
}
m_cloned_entity_attribute_nullable.setCloned();
m_cloned_entity_attribute_nullable.bindEntityRecorder(m_entity_recorder);
m_origin_entity_attribute_nullable = fromOriginEntityAttribute as TEntityAttribute;
return true;
}
public bool isReadOnly()
{
NullReferenceCheckHelper.throwIfNull(m_cloned_entity_attribute_nullable, () => $"m_cloned_entity_attribute_nullable is null !!! - {getOwner().toBasicString()}");
if(true == m_cloned_entity_attribute_nullable.getAttributeState().isEmptyFlags())
{
return true;
}
return false;
}
public async Task<(Result, DynamoDbDocBase?)> makeDocBase()
{
NullReferenceCheckHelper.throwIfNull(m_cloned_entity_attribute_nullable, () => $"m_cloned_entity_attribute_nullable is null !!! - {getOwner().toBasicString()}");
(var result, var doc) = await m_cloned_entity_attribute_nullable.toDocBase();
if(result.isFail())
{
return (result, null);
}
return (result, doc);
}
public virtual void onClear()
{
m_cloned_entity_attribute_nullable?.onClear();
m_entity_recorder.reset();
}
public ENTITY_GUID getEntityGuid() => getOwner().getEntityGuid();
public virtual string toBasicString()
{
return $"{this.getTypeName()}, {m_cloned_entity_attribute_nullable?.toBasicString()}, {getOwner().toBasicString()}";
}
}

View File

@@ -0,0 +1,82 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Newtonsoft.Json.Linq;
namespace ServerBase;
public class EntityRecorder
{
private readonly EntityBase m_owner;
private readonly ConcurrentDictionary<object, NormalDeltaRecorder> m_normal_delta_recorders = new();
public EntityRecorder(EntityBase owner)
{
m_owner = owner;
}
public void applyDeltaCounter(object entityDeltaType, double deltaCount, double totalCount)
{
var add_recorder = delegate (object deltaType)
{
return new NormalDeltaRecorder(entityDeltaType, deltaCount, totalCount);
};
var update_recorder = delegate (object key, NormalDeltaRecorder value)
{
value.incDeltaCount(deltaCount);
value.setTotalCount(totalCount);
return value;
};
m_normal_delta_recorders.AddOrUpdate(entityDeltaType, add_recorder, update_recorder);
}
public NormalDeltaRecorder? findDeltaCounter(object deltaType)
{
m_normal_delta_recorders.TryGetValue(deltaType, out var found_delta_counter);
return found_delta_counter;
}
public void reset()
{
m_normal_delta_recorders.Clear();
}
}
public class NormalDeltaRecorder
{
private object m_entity_delta_type;
private double m_delta_count;
private double m_total_count;
public NormalDeltaRecorder(object deltaType, double deltaCount, double totalCount)
{
m_entity_delta_type = deltaType;
m_delta_count = deltaCount;
m_total_count = totalCount;
}
public void setDeltaCount(double deltaCount) => m_delta_count = deltaCount;
public double getDeltaCount() => m_delta_count;
public void incDeltaCount(double deltaCount) => m_delta_count += deltaCount;
public void decDeltaCount(double deltaCount) => m_delta_count -= deltaCount;
public void setTotalCount(double totalCount) => m_total_count = totalCount;
public double getTotalCount() => m_total_count;
public object getEntityDeltaType() => m_entity_delta_type;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AsyncStateMachine;
using ServerCore; using ServerBase;
using SESSION_ID = System.Int32;
using META_ID = System.UInt32;
using ENTITY_GUID = System.String;
using ACCOUNT_ID = System.String;
using OWNER_GUID = System.String;
using USER_GUID = System.String;
using CHARACTER_GUID = System.String;
using ITEM_GUID = System.String;
namespace ServerBase;
public abstract partial class EntityHFSMBase : HFSMBase<EntityStateTriggerType, EntityStateType>, IWithEntityOwner
{
private readonly EntityBase m_owner;
public EntityHFSMBase(EntityBase owner)
: base()
{
m_owner = owner;
}
public async Task<Result> loadHfsm()
{
var result = new Result();
var err_msg = string.Empty;
if (false == await initHfsm(EntityStateType.Created, setupHfsm))
{
err_msg = $"\"Failed to create Entity HFSM !!!";
result.setFail(ServerErrorCode.EntityBaseHfsmInitFailed, err_msg);
return result;
}
return result;
}
protected abstract bool setupHfsm(HFSMBase<EntityStateTriggerType, EntityStateType> initHFSM);
public override void onSubscribeStateChangeNotify()
{
var sm = getStateMachine();
NullReferenceCheckHelper.throwIfNull(sm, () => $"sm is null !!!");
sm.Observable.Subscribe(onTransitionedState);
}
protected virtual void onTransitionedState(AsyncStateMachine.Transition<EntityStateTriggerType, EntityStateType> transition)
{
if (false == transition.isChangedState())
{
return;
}
var owner = getOwner();
var debug_msg = $"EntityHFSM transited State !!! : {transition.toBasicString()} - {owner.toBasicString()}";
Log.getLogger().debug(debug_msg);
}
}

View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServerCore; using ServerBase;
using SESSION_ID = System.Int32;
using WORLD_ID = System.UInt32;
using META_ID = System.UInt32;
using ENTITY_GUID = System.String;
using ACCOUNT_ID = System.String;
using OWNER_GUID = System.String;
using USER_GUID = System.String;
using CHARACTER_GUID = System.String;
using ITEM_GUID = System.String;
namespace ServerBase;
public abstract partial class EntityStateBase
{
private readonly EntityBase m_owner;
private DateTime m_start_time = DateTime.MinValue;
private DateTime m_end_time = DateTime.MinValue;
public EntityStateBase(EntityBase owner)
{
m_owner = owner;
}
public virtual async Task onEnter()
{
await Task.CompletedTask;
m_start_time = DateTimeHelper.Current;
}
public virtual async Task onTick()
{
await Task.CompletedTask;
}
public virtual async Task onExit()
{
await Task.CompletedTask;
m_end_time = DateTimeHelper.Current;
}
public DateTime getStartTime() { return m_start_time; }
public DateTime getEndTime() { return m_end_time; }
public UInt64 getElapsedMilliSeconds()
{
return (UInt64)(m_end_time - m_start_time).TotalMilliseconds;
}
}

View File

@@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServerCore; using ServerBase;
namespace ServerBase;
public abstract class EntityTicker : EntityBase, ITaskTicker
{
private double m_tick_interval_milliseconds;
private PeriodicTaskTimer? m_timer_nullable;
private readonly CancellationTokenSource m_cancel_token;
private readonly bool m_is_cancel_by_self;
public EntityTicker( EntityType entityType
, double onTickIntervalMilliseconds, CancellationTokenSource? toCancelToken )
: base(entityType)
{
m_tick_interval_milliseconds = onTickIntervalMilliseconds;
if(null == toCancelToken)
{
m_cancel_token = new();
m_is_cancel_by_self = true;
}
else
{
m_cancel_token = toCancelToken;
m_is_cancel_by_self = false;
}
}
public EntityTicker(EntityType entityType, EntityBase parent, Int32 onTickIntervalMilliseconds, CancellationTokenSource toCancelToken)
: base(entityType, parent)
{
m_tick_interval_milliseconds = onTickIntervalMilliseconds;
if(null == toCancelToken)
{
m_cancel_token = new();
m_is_cancel_by_self = true;
}
else
{
m_cancel_token = toCancelToken;
m_is_cancel_by_self = false;
}
}
public override async Task<Result> onInit()
{
return await onCreateTask();
}
public virtual async Task<Result> onCreateTask()
{
await Task.CompletedTask;
var result = new Result();
try
{
m_timer_nullable = new PeriodicTaskTimer( GetType().Name
, getOnTickIntervalMilliseconds()
, getCancelToken(), onTaskTick );
}
catch(Exception e)
{
var err_msg = $"Exception !!!, new PeriodicTaskTimer() : exception:{e} - {toBasicString()}";
result.setFail(ServerErrorCode.TryCatchException, err_msg);
return result;
}
return result;
}
public abstract Task onTaskTick();
public async Task onTaskWait()
{
if (m_timer_nullable != null)
await m_timer_nullable.getTask();
}
public void cancel()
{
if(true == m_is_cancel_by_self)
{
m_timer_nullable?.cancelTimer();
}
}
public double getOnTickIntervalMilliseconds() => m_tick_interval_milliseconds;
public CancellationTokenSource getCancelToken() => m_cancel_token;
public PeriodicTaskTimer? getPeriodicTaskTimer() => m_timer_nullable;
}

View File

@@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NeoSmart.AsyncLock;
using ServerCore; using ServerBase;
using MASTER_GUID = System.String;
namespace ServerBase;
public class EntityTransactionRunnerWithScopLock : IDisposable
{
private readonly EntityBase m_owner;
private readonly MASTER_GUID m_transact_master_guid;
public EntityTransactionRunnerWithScopLock(EntityBase owner, string transactMasterGuid = "")
{
m_owner = owner;
m_transact_master_guid = transactMasterGuid;
}
public void Dispose()
{
if (m_transact_master_guid.isNullOrWhiteSpace())
{
return;
}
var master_guid = m_owner.getMasterGuid();
if (m_transact_master_guid != master_guid)
{
Log.getLogger().error($"Not matched MasterGuid !!! - attachedMasterGuid:{master_guid} == settedMasterGuid:{m_transact_master_guid}");
return;
}
m_owner.detachMasterGuid();
}
public async Task<T> tryInvokeWithAsyncLock<T>(Func<Task<T>> func)
{
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
var result = default(T);
var err_msg = string.Empty;
using (var releaser = await m_owner.getAsyncLock())
{
err_msg = $"AsyncLock() Start !!! - {m_owner.toBasicString()}";
Log.getLogger().debug(err_msg);
if(false == m_transact_master_guid.isNullOrWhiteSpace())
{
ConditionValidCheckHelper.throwIfFalseWithCondition( () => true == m_owner.attachMasterGuid(m_transact_master_guid)
, () => $"Failed to attach Master !!! : transactMasterGuid:{m_transact_master_guid} - {owner.toBasicString()}");
}
result = await func();
err_msg = $"AsyncLock() End !!! - {m_owner.toBasicString()}";
Log.getLogger().debug(err_msg);
}
return result;
}
public EntityBase getOwner() => m_owner;
}

View File

@@ -0,0 +1,847 @@
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.ConstrainedExecution;
using NLog;
using Amazon.DynamoDBv2.Model;
using Newtonsoft.Json;
using Pipelines.Sockets.Unofficial.Buffers;
using StackExchange.Redis;
using Google.Protobuf.Collections;
using ServerControlCenter;
using Amazon.S3.Model;
using ServerCore; using ServerBase;
using SESSION_ID = System.Int32;
using WORLD_ID = System.UInt32;
using META_ID = System.UInt32;
using TRANSACTION_NAME = System.String;
using TRANSACTION_GUID = System.String;
using ENTITY_GUID = System.String;
using ACCOUNT_ID = System.String;
using OWNER_GUID = System.String;
using USER_GUID = System.String;
using CHARACTER_GUID = System.String;
using ITEM_GUID = System.String;
namespace ServerBase;
public class ReservedSlotOnInven
{
public class ReservedSlot
{
private Int16 m_reserved_count = 0;
private EntityBase? m_equip_entity_nullable;
private EntityBase? m_unequip_entity_nullable;
public ReservedSlot()
{ }
public void incReservedCount(Int16 reservedItemCount)
{
m_reserved_count += reservedItemCount;
}
public void decReservedCount(Int16 reservedItemCount)
{
m_reserved_count -= reservedItemCount;
}
public Int16 getReservedCount() => m_reserved_count;
public void setEquipEntity(EntityBase? entityBase) => m_equip_entity_nullable = entityBase;
public EntityBase? getEquipEntity() => m_equip_entity_nullable;
public void setUnequipEntity(EntityBase? entityBase) => m_unequip_entity_nullable = entityBase;
public EntityBase? getUnequipEntity() => m_unequip_entity_nullable;
}
private EntityType m_entity_inven_type = EntityType.None;
private readonly Dictionary<string, ReservedSlot> m_reserved_slots = new();
public ReservedSlotOnInven(EntityType entityInvenType)
{
m_entity_inven_type = entityInvenType;
}
public void addOrInc(string slotKey, Int16 incReservedCount)
{
if(false == m_reserved_slots.TryGetValue(slotKey, out var found_reserved_slot))
{
found_reserved_slot = new ReservedSlot();
m_reserved_slots.Add(slotKey, found_reserved_slot);
}
found_reserved_slot.incReservedCount(incReservedCount);
}
public void addOrDec(string slotKey, Int16 decReservedCount)
{
if (false == m_reserved_slots.TryGetValue(slotKey, out var found_reserved_slot))
{
found_reserved_slot = new ReservedSlot();
m_reserved_slots.Add(slotKey, found_reserved_slot);
}
found_reserved_slot.decReservedCount(decReservedCount);
}
public Dictionary<string, ReservedSlot> getReservedSlots() => m_reserved_slots;
public EntityType getEntityType() => m_entity_inven_type;
}
public partial class TransactionRunner : IDisposable
{
private readonly EntityBase m_owner;
private readonly string m_trans_id = string.Empty;
private readonly TransactionIdType m_transaction_id_type = TransactionIdType.None;
private readonly ConcurrentDictionary<Type, ConcurrentDictionary<ENTITY_GUID, IEntityAttributeTransactor>> m_entity_attribute_transactors = new();
private readonly ConcurrentQueue<IEntityAttributeTransactor> m_to_db_query_transactors = new(); // Db Query용 (순서 보장 중요)
private readonly ConcurrentDictionary<EntityBase, ConcurrentDictionary<EntityType, ReservedSlotOnInven>> m_reserved_inven_slots_of_owners = new();
private readonly ConcurrentDictionary<string, EntityCommonResult> m_entity_common_results = new();
//IRemoteTransaction
private readonly List<Func<Task>> m_remote_transaction_funcs = new();
private string m_transaction_name;
private bool m_is_binding = false;
public TransactionRunner(EntityBase owner, TransactionIdType idType, string transactionName)
{
m_owner = owner;
m_trans_id = System.Guid.NewGuid().ToString("N");
m_transaction_id_type = idType;
m_transaction_name = transactionName;
}
public TransactionRunner(EntityBase owner, string transId, TransactionIdType idType, string transactionName)
{
m_owner = owner;
m_trans_id = transId;
m_transaction_id_type = idType;
m_transaction_name = transactionName;
}
public Result beginTransaction()
{
var result = new Result();
var err_msg = string.Empty;
result = m_owner.bindTransactionRunner(this);
if(result.isFail())
{
return result;
}
setBinding();
return result;
}
public void clearTransaction()
{
m_entity_attribute_transactors.Clear();
m_reserved_inven_slots_of_owners.Clear();
m_to_db_query_transactors.Clear();
}
// override IDisposable.Dispose
public void Dispose()
{
var err_msg = string.Empty;
if (false == isBinding())
{
return;
}
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
if (false == m_owner.unbindTransactionRunner(this))
{
err_msg = $"Failed to unbindTransactionRunner() !!! : {toBasicString()} - {owner.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
}
public void resetTransaction(string transactionName)
{
clearTransaction();
m_transaction_name = transactionName;
}
public async Task<Result> onCommitResults(QueryBatchBase? queryBatch = null)
{
await Task.CompletedTask;
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
var result = new Result();
var err_msg = string.Empty;
var transactors = getEntityAttributeTransactorAll();
// 메모리를 동기화 한다.
foreach (var to_sync_merge in transactors)
{
var origin_entity_attribute = to_sync_merge.getOriginEntityAttribute();
NullReferenceCheckHelper.throwIfNull(origin_entity_attribute, () => $"origin_entity_attribute is null !!! - {owner.toBasicString()}");
var to_merge_attribute = origin_entity_attribute as IMergeWithEntityAttribute;
if (null == to_merge_attribute)
{
err_msg = $"Failed to cast IMergeWithEntityAttribute !!! : OriginEntityAttribute:{origin_entity_attribute.toBasicString()} - {owner.toBasicString()}";
Log.getLogger().error(err_msg);
continue;
}
var cloned_entity_attribute = to_sync_merge.getClonedEntityAttribute();
if (null == cloned_entity_attribute)
{
err_msg = $"getClonedEntityAttribute() is null !!! : OriginEntityAttribute:{origin_entity_attribute.toBasicString()} - {owner.toBasicString()}";
Log.getLogger().error(err_msg);
continue;
}
var comon_result_filler = cloned_entity_attribute as IWithCommonResultFiller;
if (null != comon_result_filler)
{
(result, var entity_common_result) = getOrNewEntityCommonResult(cloned_entity_attribute);
if (result.isFail())
{
Log.getLogger().fatal(result.toBasicString());
}
else
{
NullReferenceCheckHelper.throwIfNull(entity_common_result, () => $"entity_common_result is null !!! - {owner.toBasicString()}");
comon_result_filler.onFillCommonResult(entity_common_result, origin_entity_attribute, queryBatch);
}
}
result = to_merge_attribute.onMerge(cloned_entity_attribute);
if (result.isFail())
{
err_msg = $"Failed to onMerge() !!! : {result.toBasicString()} - {owner.toBasicString()}";
Log.getLogger().debug(err_msg);
continue;
}
}
var reserved_iven_slots_of_owners = getReservedInvenSlotAllOfOwners();
foreach(var each in reserved_iven_slots_of_owners)
{
var inven_owner = each.Key;
var reserved_inven_slots = each.Value;
var to_merge_inventory = inven_owner as IMergeWithInventory;
if (null != to_merge_inventory)
{
result = await to_merge_inventory.onMerge(reserved_inven_slots.Values.ToList<ReservedSlotOnInven>(), this);
if (result.isFail())
{
err_msg = $"Failed to IMergeWithInventory.onMerge() !!! : {result.toBasicString()} - {inven_owner.toBasicString()}, {owner.toBasicString()}";
Log.getLogger().fatal(err_msg);
continue;
}
}
}
reserved_iven_slots_of_owners.Clear();
await tryStartRemoteTransaction();
return result;
}
public async Task<Result> onCommitResults4DbQuery(List<IEntityAttributeTransactor> dbQueriedTransactors, QueryBatchBase? queryBatch = null)
{
await Task.CompletedTask;
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
NullReferenceCheckHelper.throwIfNull(dbQueriedTransactors, () => $"dbQueriedTransactors is null !!! - {owner.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
foreach (var to_sync_merge in dbQueriedTransactors)
{
var origin_entity_attribute = to_sync_merge.getOriginEntityAttribute();
NullReferenceCheckHelper.throwIfNull(origin_entity_attribute, () => $"origin_entity_attribute is null !!! - {owner.toBasicString()}");
var to_merge_attribute = origin_entity_attribute as IMergeWithEntityAttribute;
if (null == to_merge_attribute)
{
err_msg = $"Failed to cast IMergeWithEntityAttribute !!! : OriginEntityAttribute:{origin_entity_attribute.toBasicString()} - {owner.toBasicString()}";
Log.getLogger().error(err_msg);
continue;
}
var cloned_entity_attribute = to_sync_merge.getClonedEntityAttribute();
if (null == cloned_entity_attribute)
{
err_msg = $"getClonedEntityAttribute() is null !!! : OriginEntityAttribute:{origin_entity_attribute.toBasicString()} - {owner.toBasicString()}";
Log.getLogger().error(err_msg);
continue;
}
if(true == m_entity_attribute_transactors.TryGetValue(origin_entity_attribute.GetType(), out var found_transactors))
{
// DB 처리후 여기서 origin_entity_attribute Merge를 하므로
// onCommitResults() 함수로 중복된 Merge를 시도할 수 있으므로 m_entity_attribute_transactors 에서 제거 한다. - kangms
found_transactors.Remove(origin_entity_attribute.getOwner().getEntityGuid(), out _);
}
var comon_result_filler = cloned_entity_attribute as IWithCommonResultFiller;
if (null != comon_result_filler)
{
(result, var entity_common_result) = getOrNewEntityCommonResult(cloned_entity_attribute);
if (result.isFail())
{
Log.getLogger().fatal(result.toBasicString());
}
else
{
NullReferenceCheckHelper.throwIfNull(entity_common_result, () => $"entity_common_result is null !!! - {owner.toBasicString()}");
comon_result_filler.onFillCommonResult(entity_common_result, origin_entity_attribute, queryBatch);
}
}
result = to_merge_attribute.onMerge(cloned_entity_attribute);
if (result.isFail())
{
err_msg = $"Failed to onMerge() !!! : {result.toBasicString()} - {owner.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
}
var reserved_iven_slots_of_owners = getReservedInvenSlotAllOfOwners();
foreach (var each in reserved_iven_slots_of_owners)
{
var inven_owner = each.Key;
var reserved_inven_slots = each.Value;
var to_merge_inventory = inven_owner as IMergeWithInventory;
if (null != to_merge_inventory)
{
result = await to_merge_inventory.onMerge(reserved_inven_slots.Values.ToList<ReservedSlotOnInven>(), this);
if (result.isFail())
{
err_msg = $"Failed to IMergeWithInventory.onMerge() !!! : {result.toBasicString()} - {inven_owner.toBasicString()}, {owner.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
}
}
reserved_iven_slots_of_owners.Clear();
await tryStartRemoteTransaction();
return result;
}
public ConcurrentDictionary<ENTITY_GUID, IEntityAttributeTransactor> getEntityAttributeTransactorAll(Type targetEntityAttribute)
{
var err_msg = string.Empty;
var entity_attribute_transactors = new List<IEntityAttributeTransactor>();
if(false == m_entity_attribute_transactors.TryGetValue(targetEntityAttribute, out var found_transactors))
{
return new ConcurrentDictionary<ENTITY_GUID, IEntityAttributeTransactor>();
}
return found_transactors;
}
public ConcurrentDictionary<ENTITY_GUID, IEntityAttributeTransactor> getEntityAttributeTransactorAll<TEntityAttributeType>()
where TEntityAttributeType : EntityAttributeBase
{
var err_msg = string.Empty;
var entity_attribute_transactors = new List<IEntityAttributeTransactor>();
var target_type = typeof(TEntityAttributeType);
if(false == m_entity_attribute_transactors.TryGetValue(target_type, out var found_transactors))
{
return new ConcurrentDictionary<ENTITY_GUID, IEntityAttributeTransactor>();
}
return found_transactors;
}
public List<IEntityAttributeTransactor> getEntityAttributeTransactorAll()
{
var err_msg = string.Empty;
var entity_attribute_transactors = new List<IEntityAttributeTransactor>();
foreach (var each_attribute_type in m_entity_attribute_transactors)
{
foreach (var each_attribute_transactor in each_attribute_type.Value)
{
var transactor_entity_guid = each_attribute_transactor.Key;
var transactor = each_attribute_transactor.Value;
if (null == transactor)
{
continue;
}
entity_attribute_transactors.Add(transactor);
}
}
return entity_attribute_transactors;
}
public List<IEntityAttributeTransactor> getEntityAttributeTransactorAll4DbQuery()
{
var err_msg = string.Empty;
var transactors = new List<IEntityAttributeTransactor>();
while (false == m_to_db_query_transactors.IsEmpty)
{
if (true == m_to_db_query_transactors.TryDequeue(out var transactor))
{
transactors.Add(transactor);
}
}
return transactors;
}
public TEntityAttribute? getEntityAttribute<TEntityAttribute>(TEntityAttribute fromOriginEntityAttributeBase)
where TEntityAttribute : EntityAttributeBase
{
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
ArgumentNullReferenceCheckHelper.throwIfNull(fromOriginEntityAttributeBase, () => $"fromOriginEntityAttributeBase is null !!! - {owner.toBasicString()}");
var to_add_type = fromOriginEntityAttributeBase.GetType();
var entity_guid = fromOriginEntityAttributeBase.getOwner().getEntityGuid();
ConcurrentDictionary<ENTITY_GUID, IEntityAttributeTransactor>? found_transactors;
lock (m_entity_attribute_transactors)
{
if (false == m_entity_attribute_transactors.TryGetValue(to_add_type, out found_transactors))
{
found_transactors = new();
m_entity_attribute_transactors[to_add_type] = found_transactors;
}
}
IEntityAttributeTransactor found_transactor;
var add_transactor = delegate (ENTITY_GUID entityGuid)
{
found_transactor = fromOriginEntityAttributeBase.onNewEntityAttributeTransactor();
if (false == found_transactor.cloneFromOriginEntityAttribute(fromOriginEntityAttributeBase))
{
var err_msg = $"Failed to cloneFromOriginEntityAttribute() !!! - {toBasicString()}, {owner.toBasicString()}";
Log.getLogger().error(err_msg);
return null;
}
m_to_db_query_transactors.Enqueue(found_transactor);
return found_transactor;
};
found_transactor = found_transactors.GetOrAdd(entity_guid, add_transactor!);
if (null == found_transactor)
{
var err_msg = $"Failed to GetOrAdd() !!! : {fromOriginEntityAttributeBase.toBasicString()} - {toBasicString()}, {owner.toBasicString()}";
Log.getLogger().error(err_msg);
}
else
{
return found_transactor.getClonedEntityAttribute() as TEntityAttribute;
}
return fromOriginEntityAttributeBase as TEntityAttribute;
}
public TEntityAttribute? getEntityAttributeWithReadOnly<TEntityAttribute>(TEntityAttribute fromOriginEntityAttributeBase)
where TEntityAttribute : EntityAttributeBase
{
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
ArgumentNullReferenceCheckHelper.throwIfNull(fromOriginEntityAttributeBase, () => $"fromOriginEntityAttributeBase is null !!! - {owner.toBasicString()}");
var to_add_type = fromOriginEntityAttributeBase.GetType();
var entity_guid = fromOriginEntityAttributeBase.getOwner().getEntityGuid();
ConcurrentDictionary<ENTITY_GUID, IEntityAttributeTransactor>? found_transactors;
lock (m_entity_attribute_transactors)
{
m_entity_attribute_transactors.TryGetValue(to_add_type, out found_transactors);
IEntityAttributeTransactor? found_transactor = null;
if (null != found_transactors)
{
found_transactors.TryGetValue(entity_guid, out found_transactor);
}
if (null != found_transactor)
{
return found_transactor.getClonedEntityAttribute() as TEntityAttribute;
}
return fromOriginEntityAttributeBase as TEntityAttribute;
}
}
public Result tryIncReserveSlotCount(EntityBase invenOwner, EntityType entityInvenType, string slotType)
{
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
ArgumentNullReferenceCheckHelper.throwIfNull(invenOwner, () => $"invenOwner is null !!! - {owner.toBasicString()}");
var result = new Result();
ConcurrentDictionary<EntityType, ReservedSlotOnInven>? found_reserved_inven_slots;
lock (m_reserved_inven_slots_of_owners)
{
if (false == m_reserved_inven_slots_of_owners.TryGetValue(invenOwner, out found_reserved_inven_slots))
{
found_reserved_inven_slots = new ConcurrentDictionary<EntityType, ReservedSlotOnInven>();
m_reserved_inven_slots_of_owners[invenOwner] = found_reserved_inven_slots;
}
}
var add_recorder = delegate (EntityType invenType)
{
var reserved_slot = new ReservedSlotOnInven(entityInvenType);
reserved_slot.addOrInc(slotType, 1);
return reserved_slot;
};
var update_recorder = delegate (EntityType invenType, ReservedSlotOnInven currValue)
{
if (false == currValue.getReservedSlots().TryGetValue(slotType, out var found_reserved_slot))
{
found_reserved_slot = new ReservedSlotOnInven.ReservedSlot();
currValue.getReservedSlots().Add(slotType, found_reserved_slot);
}
found_reserved_slot.incReservedCount(1);
return currValue;
};
found_reserved_inven_slots.AddOrUpdate(entityInvenType, add_recorder, update_recorder);
return result;
}
public Result tryDecToReserveSlotCount(EntityBase invenOwner, EntityType entityInvenType, string slotType)
{
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
ArgumentNullReferenceCheckHelper.throwIfNull(invenOwner, () => $"invenOwner is null !!! - {owner.toBasicString()}");
var result = new Result();
ConcurrentDictionary<EntityType, ReservedSlotOnInven>? found_reserved_inven_slots;
lock (m_reserved_inven_slots_of_owners)
{
if (false == m_reserved_inven_slots_of_owners.TryGetValue(invenOwner, out found_reserved_inven_slots))
{
found_reserved_inven_slots = new ConcurrentDictionary<EntityType, ReservedSlotOnInven>();
m_reserved_inven_slots_of_owners[invenOwner] = found_reserved_inven_slots;
}
}
var add_recorder = delegate (EntityType invenType)
{
var reserved_slot = new ReservedSlotOnInven(entityInvenType);
reserved_slot.addOrDec(slotType, 1);
return reserved_slot;
};
var update_recorder = delegate (EntityType invenType, ReservedSlotOnInven currValue)
{
if (false == currValue.getReservedSlots().TryGetValue(slotType, out var found_reserved_slot))
{
found_reserved_slot = new ReservedSlotOnInven.ReservedSlot();
currValue.getReservedSlots().Add(slotType, found_reserved_slot);
}
found_reserved_slot.decReservedCount(1);
return currValue;
};
found_reserved_inven_slots.AddOrUpdate(entityInvenType, add_recorder, update_recorder);
return result;
}
public Result tryEquipToReserveSlotWithEntityBase(EntityBase invenOwner, EntityType entityInvenType, string slotType, EntityBase? entityBase)
{
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
ArgumentNullReferenceCheckHelper.throwIfNull(invenOwner, () => $"invenOwner is null !!! - {owner.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
ConcurrentDictionary<EntityType, ReservedSlotOnInven>? found_reserved_inven_slots;
lock (m_reserved_inven_slots_of_owners)
{
if (false == m_reserved_inven_slots_of_owners.TryGetValue(invenOwner, out found_reserved_inven_slots))
{
found_reserved_inven_slots = new ConcurrentDictionary<EntityType, ReservedSlotOnInven>();
m_reserved_inven_slots_of_owners[invenOwner] = found_reserved_inven_slots;
}
}
var slot_key = slotType;
var add_recorder = delegate (EntityType invenType)
{
var reserved_slot_on_inven = new ReservedSlotOnInven(entityInvenType);
reserved_slot_on_inven.addOrInc(slot_key, 1);
reserved_slot_on_inven.getReservedSlots()[slot_key].setEquipEntity(entityBase);
return reserved_slot_on_inven;
};
var update_recorder = delegate (EntityType invenType, ReservedSlotOnInven currValue)
{
if (false == currValue.getReservedSlots().TryGetValue(slot_key, out var found_reserved_slot))
{
found_reserved_slot = new ReservedSlotOnInven.ReservedSlot();
currValue.getReservedSlots()[slot_key] = found_reserved_slot;
}
var equip_entity = found_reserved_slot.getEquipEntity();
if (null != equip_entity)
{
err_msg = $"Already reserved equip item !!! : reservedEquipItem:{equip_entity.toBasicString()} - {entityBase?.toBasicString()}, {toBasicString()}, {owner.toBasicString()}";
result.setFail(ServerErrorCode.SlotsAlreadyReservedEquip, err_msg);
Log.getLogger().warn(result.toBasicString());
return currValue;
}
found_reserved_slot.incReservedCount(1);
found_reserved_slot.setEquipEntity(entityBase);
return currValue;
};
found_reserved_inven_slots.AddOrUpdate(entityInvenType, add_recorder, update_recorder);
return result;
}
public Result tryUnequipToReserveSlotWithEntityBase(EntityBase invenOwner, EntityType entityInvenType, string slotType, EntityBase? entityBase)
{
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
ArgumentNullReferenceCheckHelper.throwIfNull(invenOwner, () => $"invenOwner is null !!! - {owner.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
var slot_key = slotType;
ConcurrentDictionary<EntityType, ReservedSlotOnInven>? found_reserved_inven_slots = null;
lock (m_reserved_inven_slots_of_owners)
{
if (false == m_reserved_inven_slots_of_owners.TryGetValue(invenOwner, out found_reserved_inven_slots))
{
found_reserved_inven_slots = new ConcurrentDictionary<EntityType, ReservedSlotOnInven>();
m_reserved_inven_slots_of_owners[invenOwner] = found_reserved_inven_slots;
}
}
var add_recorder = delegate (EntityType invenType)
{
var reserved_slot_on_inven = new ReservedSlotOnInven(entityInvenType);
reserved_slot_on_inven.addOrDec(slot_key, 1);
reserved_slot_on_inven.getReservedSlots()[slot_key].setUnequipEntity(entityBase);
return reserved_slot_on_inven;
};
var update_recorder = delegate (EntityType invenType, ReservedSlotOnInven currValue)
{
if (false == currValue.getReservedSlots().TryGetValue(slot_key, out var found_reserved_slot))
{
found_reserved_slot = new ReservedSlotOnInven.ReservedSlot();
currValue.getReservedSlots()[slot_key] = found_reserved_slot;
}
var unequip_entity = found_reserved_slot.getUnequipEntity();
if (null != unequip_entity)
{
err_msg = $"Already reserved unequip item !!! : reservedUnequipItem:{unequip_entity.toBasicString()} - {entityBase?.toBasicString()}, {toBasicString()}, {owner.toBasicString()}";
result.setFail(ServerErrorCode.SlotsAlreadyReservedUnequip, err_msg);
Log.getLogger().warn(result.toBasicString());
return currValue;
}
found_reserved_slot.decReservedCount(1);
found_reserved_slot.setUnequipEntity(entityBase);
return currValue;
};
found_reserved_inven_slots.AddOrUpdate(entityInvenType, add_recorder, update_recorder);
return result;
}
public Result tryEquipToReserveSlot(EntityBase invenOwner, EntityType entityInvenType, string slotType)
{
return tryEquipToReserveSlotWithEntityBase(invenOwner, entityInvenType, slotType, null);
}
public Result tryUnequipToReserveSlot(EntityBase invenOwner, EntityType entityInvenType, string slotType)
{
return tryUnequipToReserveSlotWithEntityBase(invenOwner, entityInvenType, slotType, null);
}
public ReservedSlotOnInven.ReservedSlot? findReservedSlot(EntityBase invenOwner, EntityType entityInvenType, string slotType)
{
if(false == m_reserved_inven_slots_of_owners.TryGetValue(invenOwner, out var found_reserved_inven_slots))
{
return null;
}
if (true == found_reserved_inven_slots.TryGetValue(entityInvenType, out var found_reserved_slot_on_inven))
{
if(found_reserved_slot_on_inven.getReservedSlots().TryGetValue(slotType, out var found_reserved_slot))
{
return found_reserved_slot;
}
}
return null;
}
public (Result, EntityCommonResult?) getOrNewEntityCommonResult(EntityAttributeBase entityAttribute)
{
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
ArgumentNullReferenceCheckHelper.throwIfNull(entityAttribute, () => $"entityAttribute is null !!! - {owner.toBasicString()}");
var entity_of_owner_entity_type = entityAttribute.getEntityOfOwnerEntityType();
NullReferenceCheckHelper.throwIfNull(entity_of_owner_entity_type, () => $"entity_of_owner_entity_type is null !!! - {owner.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
var owner_guid = entity_of_owner_entity_type.onGetDbGuid();
if(owner_guid.isNullOrWhiteSpace())
{
err_msg = $"Invlid OwnerGuid of onGetDbGuid() !!! : entityAttribute:{entityAttribute.toBasicString()} - {owner.toBasicString()}";
result.setFail(ServerErrorCode.OwnerGuidInvalid, err_msg);
Log.getLogger().fatal(result.toBasicString());
return (result, null);
}
if (false == m_entity_common_results.TryGetValue(owner_guid, out var found_entity_common_result))
{
found_entity_common_result = new EntityCommonResult();
found_entity_common_result.EntityType = entity_of_owner_entity_type.getEntityType();
found_entity_common_result.EntityGuid = owner_guid;
found_entity_common_result.Money = new MoneyResult();
found_entity_common_result.Exp = new ExpResult();
found_entity_common_result.Item = new ItemResult();
m_entity_common_results[owner_guid] = found_entity_common_result;
}
return (result, found_entity_common_result);
}
public CommonResult getCommonResult()
{
var common_result = new CommonResult();
foreach(var each in m_entity_common_results)
{
common_result.EntityCommonResults.Add(each.Value);
}
return common_result;
}
public void addRemoteChargeAIPoint(IRemoteTransaction remoteTransaction, double beamDelta)
{
var fn_buy_cart = new Func<Task>(() =>
{
return remoteTransaction.callRemoteChargeAIPoint(beamDelta);
});
m_remote_transaction_funcs.Add(fn_buy_cart);
}
public void addNotifyCaliumEvent(IRemoteTransaction remoteTransaction, string eventName, CurrencyType currencyType, double delta)
{
var fn = new Func<Task>(() => remoteTransaction.callNotifyCaliumEvent(eventName, currencyType, delta));
m_remote_transaction_funcs.Add(fn);
}
public async Task tryStartRemoteTransaction()
{
foreach(var remote_transaction_funcs in m_remote_transaction_funcs)
{
await remote_transaction_funcs();
}
}
public string toBasicString()
{
return $"TransactionRunnger - transId:{m_trans_id}, transactionIdType:{m_transaction_id_type}, transactionName:{m_transaction_name}";
}
}