초기커밋
This commit is contained in:
46
ServerBase/Entity/Action/EntityActionBase.cs
Normal file
46
ServerBase/Entity/Action/EntityActionBase.cs
Normal 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()}";
|
||||
}
|
||||
}
|
||||
72
ServerBase/Entity/Aggregation/EntityAggregator.cs
Normal file
72
ServerBase/Entity/Aggregation/EntityAggregator.cs
Normal 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;
|
||||
}
|
||||
397
ServerBase/Entity/Attribute/EntityAttributeBase.cs
Normal file
397
ServerBase/Entity/Attribute/EntityAttributeBase.cs
Normal 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 로그와 관련된 함수들
|
||||
}
|
||||
113
ServerBase/Entity/Attribute/EntityAttributeTransactorBase.cs
Normal file
113
ServerBase/Entity/Attribute/EntityAttributeTransactorBase.cs
Normal 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()}";
|
||||
}
|
||||
}
|
||||
82
ServerBase/Entity/Delta/EntityDeltaRecorder.cs
Normal file
82
ServerBase/Entity/Delta/EntityDeltaRecorder.cs
Normal 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;
|
||||
}
|
||||
1026
ServerBase/Entity/EntityBase.cs
Normal file
1026
ServerBase/Entity/EntityBase.cs
Normal file
File diff suppressed because it is too large
Load Diff
75
ServerBase/Entity/State/EntityHFSMBase.cs
Normal file
75
ServerBase/Entity/State/EntityHFSMBase.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
61
ServerBase/Entity/State/EntityStateBase.cs
Normal file
61
ServerBase/Entity/State/EntityStateBase.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
107
ServerBase/Entity/Task/EntityTicker.cs
Normal file
107
ServerBase/Entity/Task/EntityTicker.cs
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
847
ServerBase/Entity/Transaction/TransactionRunner.cs
Normal file
847
ServerBase/Entity/Transaction/TransactionRunner.cs
Normal 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}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user