초기커밋
This commit is contained in:
241
GameServer/Entity/Building/Action/BuildingAction.cs
Normal file
241
GameServer/Entity/Building/Action/BuildingAction.cs
Normal file
@@ -0,0 +1,241 @@
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
internal class BuildingAction : EntityActionBase
|
||||
{
|
||||
public BuildingAction(Building owner)
|
||||
: base(owner)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> tryLoadBuildingFromDb(int buildingMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var doc = new BuildingDoc();
|
||||
doc.setCombinationKeyForPK(buildingMetaId.ToString());
|
||||
|
||||
var error_code = doc.onApplyPKSK();
|
||||
if (error_code.isFail())
|
||||
{
|
||||
err_msg = $"Failed to onApplyPKSK() !!! : {error_code.toBasicString()}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var query_config = db_client.makeQueryConfigForReadByPKSK(doc.getPK());
|
||||
(result, var read_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig<BuildingDoc>(query_config);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypesWithQueryOperationConfig() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!!");
|
||||
|
||||
foreach (var read_doc in read_docs)
|
||||
{
|
||||
if (!building_attribute.copyEntityAttributeFromDoc(read_doc))
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDoc() !!! to:{building_attribute.getTypeName()}, from:{read_doc.getTypeName()} : {this.getTypeName()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (building_attribute.BuildingMetaId == 0)
|
||||
{
|
||||
(result, var land_meta_data, var rental_fee_meta_data) = BuildingHelper.validCheckBuilding((uint)buildingMetaId);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to validCheckOwnerLand() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(land_meta_data, () => $"land_meta_data is null !!!");
|
||||
NullReferenceCheckHelper.throwIfNull(rental_fee_meta_data, () => $"rental_fee_meta_data is null !!!");
|
||||
|
||||
building_attribute.BuildingMetaId = (uint)buildingMetaId;
|
||||
building_attribute.RentalCurrencyType = (CurrencyType)rental_fee_meta_data.CurrencyType;
|
||||
building_attribute.RentalCurrencyAmount = rental_fee_meta_data.CurrencyValue;
|
||||
building_attribute.IsRentalOpen = land_meta_data.RentalAvailable;
|
||||
|
||||
if (read_docs.Count != 0)
|
||||
{
|
||||
Log.getLogger().info($"BuildingDoc.BuildingAtrib.BuildingMetaId is 0 !!! - buildingMetaId:{buildingMetaId}");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(Result, DynamoDbDocBase?)> modifyBuildingInfo(string buildingName, string buildingDescription, CurrencyType rentalCurrencyType, double rentalCurrencyAmount, bool isRantalOpen)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var currency_amount = rentalCurrencyAmount;
|
||||
if (rentalCurrencyType != CurrencyType.Calium)
|
||||
{
|
||||
currency_amount = (int)rentalCurrencyAmount;
|
||||
}
|
||||
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!!");
|
||||
|
||||
building_attribute.BuildingName = buildingName;
|
||||
building_attribute.Description = buildingDescription;
|
||||
building_attribute.RentalCurrencyType = rentalCurrencyType;
|
||||
building_attribute.RentalCurrencyAmount = currency_amount;
|
||||
building_attribute.IsRentalOpen = isRantalOpen;
|
||||
building_attribute.modifiedEntityAttribute();
|
||||
|
||||
(result, var building_doc) = await building_attribute.toDocBase();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to toDocBase() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, building_doc);
|
||||
}
|
||||
|
||||
public void modifyBuildingInfo(BuildingInfo buildingInfo)
|
||||
{
|
||||
var currency_amount = buildingInfo.RentalCurrencyAmount;
|
||||
if (buildingInfo.RentalCurrencyType != CurrencyType.Calium)
|
||||
{
|
||||
currency_amount = (int)buildingInfo.RentalCurrencyAmount;
|
||||
}
|
||||
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!!");
|
||||
|
||||
building_attribute.BuildingName = buildingInfo.BuildingName;
|
||||
building_attribute.Description = buildingInfo.BuildingDescription;
|
||||
building_attribute.RentalCurrencyType = buildingInfo.RentalCurrencyType;
|
||||
building_attribute.RentalCurrencyAmount = currency_amount;
|
||||
building_attribute.IsRentalOpen = buildingInfo.IsRentalOpen == BoolType.True;
|
||||
building_attribute.IsLoadFromDb = true;
|
||||
building_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
|
||||
public (CurrencyType, double) getRentalCurrency()
|
||||
{
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!!");
|
||||
|
||||
return (building_attribute.RentalCurrencyType, building_attribute.RentalCurrencyAmount);
|
||||
}
|
||||
|
||||
public void setBuildingOwner(int buildingMetaId, string userGuid, CurrencyType rentalCurrencyType, double rentalCurrencyAmount, bool initialRentalOpen)
|
||||
{
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!!");
|
||||
|
||||
if (!building_attribute.IsLoadFromDb)
|
||||
{
|
||||
building_attribute.BuildingMetaId = (uint)buildingMetaId;
|
||||
building_attribute.OwnerUserGuid = userGuid;
|
||||
building_attribute.RentalCurrencyType = rentalCurrencyType;
|
||||
building_attribute.RentalCurrencyAmount = rentalCurrencyAmount;
|
||||
building_attribute.IsRentalOpen = initialRentalOpen;
|
||||
building_attribute.IsLoadFromDb = true;
|
||||
building_attribute.newEntityAttribute();
|
||||
}
|
||||
else
|
||||
{
|
||||
building_attribute.OwnerUserGuid = userGuid;
|
||||
building_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
}
|
||||
|
||||
public bool isRentalOpen()
|
||||
{
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!!");
|
||||
|
||||
return building_attribute.IsRentalOpen;
|
||||
}
|
||||
|
||||
public void initOwner()
|
||||
{
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!!");
|
||||
|
||||
building_attribute.OwnerUserGuid = string.Empty;
|
||||
building_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
|
||||
public bool isBuildingOwner(string userGuid)
|
||||
{
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!!");
|
||||
|
||||
return building_attribute.OwnerUserGuid == userGuid;
|
||||
}
|
||||
|
||||
public bool isLoadFromDb()
|
||||
{
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!!");
|
||||
|
||||
return building_attribute.IsLoadFromDb;
|
||||
}
|
||||
}
|
||||
44
GameServer/Entity/Building/Building.cs
Normal file
44
GameServer/Entity/Building/Building.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using ServerCommon;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class Building : EntityBase
|
||||
{
|
||||
public Building()
|
||||
: base(EntityType.Building)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
addEntityAttribute(new BuildingAttribute(this));
|
||||
|
||||
addEntityAction(new BuildingAction(this));
|
||||
addEntityAction(new BuildingFloorAgentAction(this));
|
||||
addEntityAction(new BuildingProfitAgentAction(this));
|
||||
addEntityAction(new BuildingProfitHistoryAgentAction(this));
|
||||
addEntityAction(new BuildingRentalHistoryAgentAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}, BuildingMetaId:{getOriginEntityAttribute<BuildingAttribute>()?.BuildingMetaId}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}, {getEntityAttribute<BuildingAttribute>()?.toBasicString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class BuildingBusinessLogHelper
|
||||
{
|
||||
public static BuildingLogInfo toBuildingLogInfo(this Building building)
|
||||
{
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!!");
|
||||
|
||||
var building_log_info = new BuildingLogInfo();
|
||||
building_log_info.setBuildingInfo(building_attribute);
|
||||
|
||||
return building_log_info;
|
||||
}
|
||||
|
||||
public static void setBuildingInfo(this BuildingLogInfo log, BuildingAttribute buildingAttribute)
|
||||
{
|
||||
log.setLogProperty(
|
||||
(int)buildingAttribute.BuildingMetaId,
|
||||
buildingAttribute.OwnerUserGuid,
|
||||
buildingAttribute.RentalCurrencyType,
|
||||
buildingAttribute.RentalCurrencyAmount,
|
||||
buildingAttribute.IsRentalOpen
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
250
GameServer/Entity/Building/Helper/BuildingHelper.cs
Normal file
250
GameServer/Entity/Building/Helper/BuildingHelper.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using META_ID = System.UInt32;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class BuildingHelper
|
||||
{
|
||||
public static async Task<BuildingInfo> toBuildingInfo(this Building building)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!!");
|
||||
|
||||
var building_info = new BuildingInfo();
|
||||
|
||||
building_info.BuildingMetaId = (int)building_attribute.BuildingMetaId;
|
||||
building_info.BuildingName = building_attribute.BuildingName;
|
||||
building_info.BuildingDescription = building_attribute.Description;
|
||||
building_info.OwnerUserGuid = building_attribute.OwnerUserGuid;
|
||||
building_info.RentalCurrencyType = building_attribute.RentalCurrencyType;
|
||||
building_info.RentalCurrencyAmount = building_attribute.RentalCurrencyAmount;
|
||||
building_info.IsRentalOpen = building_attribute.IsRentalOpen == true ? BoolType.True : BoolType.False;
|
||||
|
||||
if (building_attribute.OwnerUserGuid != string.Empty)
|
||||
{
|
||||
(result, var nickname_attrib) = await NicknameDoc.findNicknameFromGuid(building_attribute.OwnerUserGuid);
|
||||
if (result.isSuccess() && nickname_attrib != null)
|
||||
{
|
||||
building_info.OwnerUserNickname = nickname_attrib.Nickname;
|
||||
}
|
||||
}
|
||||
|
||||
result = MapManager.Instance.tryGetUsingFloorCountByBuildingMetaId((int)building_attribute.BuildingMetaId, out var usingFloorCount);
|
||||
if (result.isSuccess())
|
||||
{
|
||||
building_info.RentalFloorCount = usingFloorCount;
|
||||
}
|
||||
|
||||
return building_info;
|
||||
}
|
||||
|
||||
public static async Task<(Result, Building?, OwnedBuilding?, DynamoDbDocBase?)> tryGainBuilding(Player player, int buildingMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
(result, var land_meta_data, var rental_fee_meta_data) = validCheckBuilding((META_ID)buildingMetaId);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to validCheckOwnerLand() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, null, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(land_meta_data, () => $"land_meta_data is null !!!");
|
||||
NullReferenceCheckHelper.throwIfNull(rental_fee_meta_data, () => $"rental_fee_meta_data is null !!!");
|
||||
|
||||
|
||||
var building_manager = server_logic.getBuildingManager();
|
||||
if (!building_manager.tryGetBuilding(buildingMetaId, out var building))
|
||||
{
|
||||
err_msg = $"Failed to tryGetBuilding() !!! : BuildingMetaId:{buildingMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.BuildingNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
var building_action = building.getEntityAction<BuildingAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_action, () => $"building_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var user_guid = player.getUserGuid();
|
||||
building_action.setBuildingOwner( buildingMetaId, user_guid
|
||||
, (CurrencyType)rental_fee_meta_data.CurrencyType
|
||||
, rental_fee_meta_data.CurrencyValue, land_meta_data.RentalAvailable );
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"land_building_attributettribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
(result, var building_doc_base) = await building_attribute.toDocBase();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to toDocBase() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(building_doc_base, () => $"building_doc_base is null !!! - {player.toBasicString()}");
|
||||
|
||||
(result, var owned_building) = await OwnedBuildingHelper.createOwnedBuilding(player, buildingMetaId, OwnedType.Own);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to createOwnedBuilding() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
return (result, building, owned_building, building_doc_base);
|
||||
}
|
||||
|
||||
public static (Result, LandMetaData?, RentalfeeData?) validCheckBuilding(META_ID buildingMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (!MapManager.Instance.GetBuildingMapTree((Int32)buildingMetaId, out var building_map_tree))
|
||||
{
|
||||
err_msg = $"Failed to GetBuildingMapTree() !!! : BuildingMetaId:{buildingMetaId}";
|
||||
result.setFail(ServerErrorCode.BuildingMapTreeDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var land_map_tree = building_map_tree.ParentLandMapTree;
|
||||
if (land_map_tree == null)
|
||||
{
|
||||
err_msg = $"Not Exist BuildingMapTree ParentLand !!! : BuildingMap:{building_map_tree.BuildingMapFileName}";
|
||||
result.setFail(ServerErrorCode.BuildingMapTreeParentLandNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
if (!MetaData.Instance._LandTable.TryGetValue(land_map_tree.LandId, out var land_meta_data))
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TryGetValue() !!! : LandMetaId:{land_map_tree.LandId}";
|
||||
result.setFail(ServerErrorCode.LandMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
if (!MetaData.Instance._RentalfeeTable.TryGetValue((land_meta_data.Editor, land_meta_data.LandSize), out var rentalfee_meta_data))
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TryGetValue() !!! : Editor:{land_meta_data.Editor}, Size:{land_meta_data.LandSize}";
|
||||
result.setFail(ServerErrorCode.RentalfeeMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
return (result, land_meta_data, rentalfee_meta_data);
|
||||
}
|
||||
|
||||
public static async Task<(Result, Building?, OwnedBuilding?, DynamoDbDocBase?)> tryInitMyBuildingOwnership(Player player, int buildingMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
if (!MapManager.Instance.GetBuildingMapTree(buildingMetaId, out var building_map_tree))
|
||||
{
|
||||
err_msg = $"Failed to GetBuildingMapTree() !!! : BuildingMetaId:{buildingMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.BuildingMapTreeDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
var land_map_tree = building_map_tree.ParentLandMapTree;
|
||||
if (land_map_tree == null)
|
||||
{
|
||||
err_msg = $"Not Exist BuildingMapTree ParentLand !!! : BuildingMap:{building_map_tree.BuildingMapFileName} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.BuildingMapTreeParentLandNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
if (!MetaData.Instance._LandTable.TryGetValue(land_map_tree.LandId, out var land_meta_data))
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TryGetValue() !!! : LandMetaId:{land_map_tree.LandId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
var building_manager = server_logic.getBuildingManager();
|
||||
if (!building_manager.tryGetBuilding(buildingMetaId, out var building))
|
||||
{
|
||||
err_msg = $"Failed to tryGetBuilding() !!! : BuildingMetaId:{buildingMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.BuildingNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
var building_action = building.getEntityAction<BuildingAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_action, () => $"building_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var user_guid = player.getUserGuid();
|
||||
if (!building_action.isBuildingOwner(user_guid))
|
||||
{
|
||||
err_msg = $"Building Owner is Not Match !!! : buildingMetaId:{buildingMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.BuildingOwnerIsNotMatch, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
building_action.initOwner();
|
||||
|
||||
var building_attribute = building.getEntityAttribute<BuildingAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_attribute, () => $"building_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
(result, var building_doc_base) = await building_attribute.toDocBase();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to toDocBase() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(building_doc_base, () => $"building_doc_base is null !!! - {player.toBasicString()}");
|
||||
|
||||
var owned_building_agent_action = player.getEntityAction<OwnedBuildingAgentAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(owned_building_agent_action, () => $"owned_building_agent_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
if (!owned_building_agent_action.tryGetOwnedBuilding(buildingMetaId, out var owned_building))
|
||||
{
|
||||
err_msg = $"Failed to tryGetOwnedBuilding() !!! : buildingMetaId:{buildingMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.OwnedBuildingNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
var owned_building_action = owned_building.getEntityAction<OwnedBuildingAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(owned_building_action, () => $"owned_building_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
owned_building_action.DeleteOwnedBuilding();
|
||||
|
||||
return (result, building, owned_building, building_doc_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
132
GameServer/Entity/Building/Helper/BuildingNotifyHelper.cs
Normal file
132
GameServer/Entity/Building/Helper/BuildingNotifyHelper.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Org.BouncyCastle.Asn1.Ocsp;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static ClientToGameMessage.Types;
|
||||
using static ServerMessage.Types;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class BuildingNotifyHelper
|
||||
{
|
||||
public static async Task<bool> send_S2C_NTF_BUILDING_INFOS(this Player player)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var building_manager = server_logic.getBuildingManager();
|
||||
|
||||
var ntf_packet = new ClientToGame();
|
||||
ntf_packet.Message = new ClientToGameMessage();
|
||||
ntf_packet.Message.NtfBuildingInfos = new GS2C_NTF_BUILDING_INFOS();
|
||||
|
||||
var building_infos = await building_manager.tryGetBuildingInfos();
|
||||
foreach (var building_info in building_infos)
|
||||
{
|
||||
ntf_packet.Message.NtfBuildingInfos.BuildingInfos.Add(building_info.BuildingMetaId, building_info);
|
||||
}
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(player, ntf_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool broadcast_S2C_NTF_BUILDING_INFOS(BuildingInfo buildingInfo)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var users = server_logic.getPlayerManager().getUsers();
|
||||
var players = users.Values.ToArray();
|
||||
|
||||
if (players.Length == 0)
|
||||
return true;
|
||||
|
||||
var ntf_packet = new ClientToGame();
|
||||
ntf_packet.Message = new ClientToGameMessage();
|
||||
ntf_packet.Message.NtfBuildingInfos = new GS2C_NTF_BUILDING_INFOS();
|
||||
|
||||
ntf_packet.Message.NtfBuildingInfos.BuildingInfos.Add(buildingInfo.BuildingMetaId, buildingInfo);
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(players, ntf_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool broadcast_S2C_NTF_BUILDING_INFOS(List<BuildingInfo> buildingInfos)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var users = server_logic.getPlayerManager().getUsers();
|
||||
var players = users.Values.ToArray();
|
||||
|
||||
if (players.Length == 0)
|
||||
return true;
|
||||
|
||||
var ntf_packet = new ClientToGame();
|
||||
ntf_packet.Message = new ClientToGameMessage();
|
||||
ntf_packet.Message.NtfBuildingInfos = new GS2C_NTF_BUILDING_INFOS();
|
||||
|
||||
foreach (var buildingInfo in buildingInfos)
|
||||
{
|
||||
ntf_packet.Message.NtfBuildingInfos.BuildingInfos.Add(buildingInfo.BuildingMetaId, buildingInfo);
|
||||
}
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(players, ntf_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool send_GS2GS_NTF_MODIFY_BUILDING_INFO(List<BuildingInfo> buildingInfos)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var message = new ServerMessage();
|
||||
|
||||
message.NtfModifyBuildingInfo = new GS2GS_NTF_MODIFY_BUILDING_INFO();
|
||||
message.NtfModifyBuildingInfo.ExceptServerName = server_logic.getServerName();
|
||||
message.NtfModifyBuildingInfo.BuildingInfos.AddRange(buildingInfos);
|
||||
|
||||
var rabbit_mq = server_logic.getRabbitMqConnector() as RabbitMQ4Game;
|
||||
NullReferenceCheckHelper.throwIfNull(rabbit_mq, () => $"rabbit_mq is null !!!");
|
||||
|
||||
rabbit_mq.sendMessageToExchangeAllGame(message);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<bool> sendNtfModifyBuildingInfo(Building building)
|
||||
{
|
||||
var building_info = await building.toBuildingInfo();
|
||||
var building_infos = new List<BuildingInfo>();
|
||||
building_infos.Add(building_info);
|
||||
|
||||
// 현재 서버 유저
|
||||
broadcast_S2C_NTF_BUILDING_INFOS(building_info);
|
||||
|
||||
// 다른 서버
|
||||
send_GS2GS_NTF_MODIFY_BUILDING_INFO(building_infos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool sendNtfModifyBuildingInfo(List<BuildingInfo> buildingInfos)
|
||||
{
|
||||
broadcast_S2C_NTF_BUILDING_INFOS(buildingInfos);
|
||||
|
||||
send_GS2GS_NTF_MODIFY_BUILDING_INFO(buildingInfos);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingFloorAction : EntityActionBase
|
||||
{
|
||||
public BuildingFloorAction(BuildingFloor owner)
|
||||
: base(owner)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public Result tryLoadBuildingFloorFromDoc(BuildingFloorDoc buildingFloorDoc)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var building_floor = getOwner() as BuildingFloor;
|
||||
NullReferenceCheckHelper.throwIfNull(building_floor, () => $"building_floor is null !!!");
|
||||
|
||||
var building_floor_attribute = building_floor.getEntityAttribute<BuildingFloorAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_floor_attribute, () => $"building_floor_attribute is null !!!");
|
||||
|
||||
if (!building_floor_attribute.copyEntityAttributeFromDoc(buildingFloorDoc))
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDoc() !!! to:{building_floor_attribute.getTypeName()}, from:{buildingFloorDoc.getTypeName()} : {this.getTypeName()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool isRentalFinish()
|
||||
{
|
||||
var building_floor = getOwner() as BuildingFloor;
|
||||
NullReferenceCheckHelper.throwIfNull(building_floor, () => $"building_floor is null !!!");
|
||||
|
||||
var building_floor_attribute = building_floor.getEntityAttribute<BuildingFloorAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_floor_attribute, () => $"building_floor_attribute is null !!!");
|
||||
|
||||
if (DateTime.UtcNow > building_floor_attribute.RentalFinishTime)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public (int, int, int) getAddress()
|
||||
{
|
||||
var building_floor = getOwner() as BuildingFloor;
|
||||
NullReferenceCheckHelper.throwIfNull(building_floor, () => $"building_floor is null !!!");
|
||||
|
||||
var building_floor_attribute = building_floor.getEntityAttribute<BuildingFloorAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_floor_attribute, () => $"building_floor_attribute is null !!!");
|
||||
|
||||
var land_meta_id = building_floor_attribute.LandMetaId;
|
||||
var building_meta_id = building_floor_attribute.BuildingMetaId;
|
||||
var floor = building_floor_attribute.Floor;
|
||||
|
||||
return (land_meta_id, building_meta_id, floor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static ClientToGameReq.Types;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingFloorAgentAction : EntityActionBase
|
||||
{
|
||||
ConcurrentDictionary<int, BuildingFloor> m_building_floors = new();
|
||||
|
||||
public BuildingFloorAgentAction(Building owner)
|
||||
: base(owner)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> tryLoadBuildingFloorFromDb(int buildingMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var doc = new BuildingFloorDoc();
|
||||
doc.setCombinationKeyForPK(buildingMetaId.ToString());
|
||||
|
||||
var error_code = doc.onApplyPKSK();
|
||||
if (error_code.isFail())
|
||||
{
|
||||
err_msg = $"Failed to onApplyPKSK() !!! : {error_code.toBasicString()}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var query_config = db_client.makeQueryConfigWithPKSKBySKBeginWith(doc.getPK(), BuildingFloorDoc.getPrefixOfSK());
|
||||
|
||||
(result, var read_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig<BuildingFloorDoc>(query_config);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypesWithQueryOperationConfig() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
foreach (var read_doc in read_docs)
|
||||
{
|
||||
var building_floor_attrib = read_doc.getAttrib<BuildingFloorAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_floor_attrib, () => $"building_floor_attrib is null !!!");
|
||||
|
||||
if (building_floor_attrib.RentalFinishTime < DateTime.UtcNow)
|
||||
continue;
|
||||
|
||||
var building_floor = new BuildingFloor(building);
|
||||
await building_floor.onInit();
|
||||
|
||||
var building_floor_action = building_floor.getEntityAction<BuildingFloorAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_floor_action, () => $"building_floor_action is null !!!");
|
||||
|
||||
result = building_floor_action.tryLoadBuildingFloorFromDoc(read_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryLoadBuildingFloorFromDoc() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var building_floor_attribute = building_floor.getEntityAttribute<BuildingFloorAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_floor_attribute, () => $"building_floor_attribute is null !!!");
|
||||
|
||||
if (!m_building_floors.TryAdd(building_floor_attribute.Floor, building_floor))
|
||||
{
|
||||
err_msg = $"Failed to TryAdd() !!! : {building_floor.toBasicString()} : {this.getTypeName()}";
|
||||
result.setFail(ServerErrorCode.RentalDocLoadDuplicatedRental, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
await MapManager.Instance.tryAddRoomMapTreeFromDb(read_doc);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool isEmptyFloor(int floor)
|
||||
{
|
||||
return !m_building_floors.ContainsKey(floor);
|
||||
}
|
||||
|
||||
public void addBuildingFloor(int floor, BuildingFloor buildingFloor)
|
||||
{
|
||||
m_building_floors[floor] = buildingFloor;
|
||||
}
|
||||
|
||||
public void removeBuildingFloor(int floor)
|
||||
{
|
||||
m_building_floors.TryRemove(floor, out _);
|
||||
}
|
||||
|
||||
public ConcurrentDictionary<int, BuildingFloor> getBuildingFloors() => m_building_floors;
|
||||
}
|
||||
}
|
||||
41
GameServer/Entity/BuildingFloor/BuildingFloor.cs
Normal file
41
GameServer/Entity/BuildingFloor/BuildingFloor.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using ServerCommon;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingFloor : EntityBase
|
||||
|
||||
{
|
||||
public BuildingFloor(Building building)
|
||||
: base(EntityType.BuildingFloor, building)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
addEntityAttribute(new BuildingFloorAttribute(this));
|
||||
addEntityAction(new BuildingFloorAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}, BuildingMetaId:{getOriginEntityAttribute<BuildingFloorAttribute>()?.BuildingMetaId}, Floor:{getOriginEntityAttribute<BuildingFloorAttribute>()?.Floor}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}, {getEntityAttribute<BuildingFloorAttribute>()?.toBasicString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class BuildingFloorHelper
|
||||
{
|
||||
public static async Task<(Result, BuildingFloorInfo)> tryGetBuildingFloorInfo(this BuildingFloor buildingFloor)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var building_floor_info = new BuildingFloorInfo();
|
||||
|
||||
var building_floor_attribute = buildingFloor.getEntityAttribute<BuildingFloorAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_floor_attribute, () => $"building_floor_attribute is null !!!");
|
||||
|
||||
(result, var nickname_attrib) = await NicknameDoc.findNicknameFromGuid(building_floor_attribute.OwnerGuid);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to findNicknameFromGuid() !!! : userGuid:{building_floor_attribute.OwnerGuid}, {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, building_floor_info);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(nickname_attrib, () => $"nickname_attrib is null !!!");
|
||||
|
||||
building_floor_info.Floor = (int)building_floor_attribute.Floor;
|
||||
building_floor_info.InstanceName = building_floor_attribute.InstanceName;
|
||||
building_floor_info.RenteeUserGuid = building_floor_attribute.OwnerGuid;
|
||||
building_floor_info.RenteeUserNickname = nickname_attrib.Nickname;
|
||||
building_floor_info.RentalFinishTime = building_floor_attribute.RentalFinishTime.ToTimestamp();
|
||||
|
||||
return (result, building_floor_info);
|
||||
}
|
||||
|
||||
public static async Task<(Result, BuildingFloor?, DynamoDbDocBase?)> tryMakeBuildingFloor(Building building, RentFloorRequestInfo rentFloorRequestInfo)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var building_floor = new BuildingFloor(building);
|
||||
await building_floor.onInit();
|
||||
|
||||
var building_floor_attribute = building_floor.getEntityAttribute<BuildingFloorAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_floor_attribute, () => $"building_floor_attribute is null !!!");
|
||||
|
||||
var rental_period = TimeSpan.FromDays(rentFloorRequestInfo.RentalPeriod);
|
||||
|
||||
building_floor_attribute.LandMetaId = rentFloorRequestInfo.LandId;
|
||||
building_floor_attribute.BuildingMetaId = rentFloorRequestInfo.BuildingId;
|
||||
building_floor_attribute.Floor = rentFloorRequestInfo.Floor;
|
||||
building_floor_attribute.OwnerGuid = rentFloorRequestInfo.OwnerGuid;
|
||||
building_floor_attribute.MyhomeGuid = rentFloorRequestInfo.MyhomeGuid;
|
||||
building_floor_attribute.InstanceName = rentFloorRequestInfo.InstanceName;
|
||||
building_floor_attribute.ThumbnailImageId = rentFloorRequestInfo.ThumbnailImageId;
|
||||
building_floor_attribute.ListImageId = rentFloorRequestInfo.ListImageId;
|
||||
building_floor_attribute.EnterPlayerCount = rentFloorRequestInfo.EnterPlayerCount;
|
||||
building_floor_attribute.RentalPeriod = rental_period;
|
||||
building_floor_attribute.RentalStartTime = rentFloorRequestInfo.RentalStartTime.ToDateTime();
|
||||
building_floor_attribute.RentalFinishTime = rentFloorRequestInfo.RentalFinishTime.ToDateTime();
|
||||
building_floor_attribute.modifiedEntityAttribute(true);
|
||||
|
||||
(result, var building_floor_doc) = await building_floor_attribute.toDocBase();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to toDocBase() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
return (result, building_floor, building_floor_doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
102
GameServer/Entity/BuildingProfit/Action/BuildingProfitAction.cs
Normal file
102
GameServer/Entity/BuildingProfit/Action/BuildingProfitAction.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingProfitAction : EntityActionBase
|
||||
{
|
||||
public BuildingProfitAction(BuildingProfit owner)
|
||||
: base(owner)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public Result tryLoadBuildingProfitFromDoc(BuildingProfitDoc buildingProfitDoc)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var building_profit = getOwner() as BuildingProfit;
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit, () => $"building_profit is null !!!");
|
||||
|
||||
var building_profit_attribute = building_profit.getEntityAttribute<BuildingProfitAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_attribute, () => $"building_profit_attribute is null !!!");
|
||||
|
||||
if (!building_profit_attribute.copyEntityAttributeFromDoc(buildingProfitDoc))
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDoc() !!! to:{building_profit_attribute.getTypeName()}, from:{buildingProfitDoc.getTypeName()} : {this.getTypeName()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getFloor()
|
||||
{
|
||||
var building_profit = getOwner() as BuildingProfit;
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit, () => $"building_profit is null !!!");
|
||||
|
||||
var building_profit_attribute = building_profit.getEntityAttribute<BuildingProfitAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_attribute, () => $"building_profit_attribute is null !!!");
|
||||
|
||||
return building_profit_attribute.Floor;
|
||||
}
|
||||
|
||||
public Dictionary<CurrencyType, double> getProfits()
|
||||
{
|
||||
var building_profit = getOwner() as BuildingProfit;
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit, () => $"building_profit is null !!!");
|
||||
|
||||
var building_profit_attribute = building_profit.getEntityAttribute<BuildingProfitAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_attribute, () => $"building_profit_attribute is null !!!");
|
||||
|
||||
var profits = new Dictionary<CurrencyType, double>(building_profit_attribute.Profits);
|
||||
|
||||
return profits;
|
||||
}
|
||||
|
||||
public double getProfit(CurrencyType currencyType)
|
||||
{
|
||||
var building_profit = getOwner() as BuildingProfit;
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit, () => $"building_profit is null !!!");
|
||||
|
||||
var building_profit_attribute = building_profit.getEntityAttribute<BuildingProfitAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_attribute, () => $"building_profit_attribute is null !!!");
|
||||
|
||||
building_profit_attribute.Profits.TryGetValue(currencyType, out var currency_amount);
|
||||
|
||||
return currency_amount;
|
||||
}
|
||||
|
||||
public void modifyProfit(CurrencyType currencyType, double deltaAmount)
|
||||
{
|
||||
var building_profit = getOwner() as BuildingProfit;
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit, () => $"building_profit is null !!!");
|
||||
|
||||
var building_profit_attribute = building_profit.getEntityAttribute<BuildingProfitAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_attribute, () => $"building_profit_attribute is null !!!");
|
||||
|
||||
building_profit_attribute.Profits.TryGetValue(currencyType, out var currency_amount);
|
||||
|
||||
currency_amount += deltaAmount;
|
||||
building_profit_attribute.Profits[currencyType] = currency_amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using NeoSmart.AsyncLock;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingProfitAgentAction : EntityActionBase
|
||||
{
|
||||
ConcurrentDictionary<int, BuildingProfit> m_building_profits = new();
|
||||
|
||||
AsyncLock m_lock = new();
|
||||
|
||||
public BuildingProfitAgentAction(Building owner)
|
||||
: base(owner)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public AsyncLock getAsyncLock() => m_lock;
|
||||
|
||||
public async Task<Result> tryLoadBuildingProfitFromDb(int buildingMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var doc = new BuildingProfitDoc();
|
||||
doc.setCombinationKeyForPK(buildingMetaId.ToString());
|
||||
|
||||
var error_code = doc.onApplyPKSK();
|
||||
if (error_code.isFail())
|
||||
{
|
||||
err_msg = $"Failed to onApplyPKSK() !!! : {error_code.toBasicString()}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var query_config = db_client.makeQueryConfigWithPKSKBySKBeginWith(doc.getPK(), BuildingProfitDoc.getPrefixOfSK());
|
||||
|
||||
(result, var read_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig<BuildingProfitDoc>(query_config);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypesWithQueryOperationConfig() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
foreach (var read_doc in read_docs)
|
||||
{
|
||||
var building_profit = new BuildingProfit(building);
|
||||
await building_profit.onInit();
|
||||
|
||||
var building_profit_action = building_profit.getEntityAction<BuildingProfitAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_action, () => $"building_profit_action is null !!!");
|
||||
|
||||
result = building_profit_action.tryLoadBuildingProfitFromDoc(read_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryLoadBuildingProfitFromDoc() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var building_profit_attribute = building_profit.getEntityAttribute<BuildingProfitAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_attribute, () => $"building_profit_attribute is null !!!");
|
||||
|
||||
if (!m_building_profits.TryAdd(building_profit_attribute.Floor, building_profit))
|
||||
{
|
||||
err_msg = $"Failed to TryAdd() !!! : {building_profit.toBasicString()} : {this.getTypeName()}";
|
||||
result.setFail(ServerErrorCode.RentalDocLoadDuplicatedRental, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Dictionary<int, FloorProfitInfo> getBuildingProfitInfos()
|
||||
{
|
||||
var floor_profit_infos = new Dictionary<int, FloorProfitInfo>();
|
||||
|
||||
foreach (var building_profit in m_building_profits.Values)
|
||||
{
|
||||
var building_profit_attribute = building_profit.getEntityAttribute<BuildingProfitAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_attribute, () => $"building_profit_history_attribute is null !!!");
|
||||
|
||||
var floor_profit = building_profit.toFloorProfitInfo();
|
||||
floor_profit_infos.Add(building_profit_attribute.Floor, floor_profit);
|
||||
}
|
||||
|
||||
return floor_profit_infos;
|
||||
}
|
||||
|
||||
public bool tryGetBuildingProfit(int floor, [MaybeNullWhen(false)] out BuildingProfit buildingProfit)
|
||||
{
|
||||
return m_building_profits.TryGetValue(floor, out buildingProfit);
|
||||
}
|
||||
|
||||
public List<BuildingProfit> getAllBuildingProfit()
|
||||
{
|
||||
return m_building_profits.Values.ToList();
|
||||
}
|
||||
|
||||
public void addBuildingProfit(int floor, BuildingProfit buildingProfit)
|
||||
{
|
||||
m_building_profits[floor] = buildingProfit;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
GameServer/Entity/BuildingProfit/BuildingProfit.cs
Normal file
36
GameServer/Entity/BuildingProfit/BuildingProfit.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingProfit : EntityBase
|
||||
{
|
||||
public BuildingProfit(Building building)
|
||||
: base(EntityType.BuildingProfit, building)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
addEntityAttribute(new BuildingProfitAttribute(this));
|
||||
addEntityAction(new BuildingProfitAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}, BuildingMetaId:{getOriginEntityAttribute<BuildingFloorAttribute>()?.BuildingMetaId}, Floor:{getOriginEntityAttribute<BuildingFloorAttribute>()?.Floor}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}, {getEntityAttribute<BuildingFloorAttribute>()?.toBasicString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class BuildingProfitBusinessLogHelper
|
||||
{
|
||||
public static BuildingProfitLogInfo toBuildingProfitLogInfo(int buildingMetaId, int floor, CurrencyType currencyType, AmountDeltaType amountDeltaType, double deltaAmount, double currencyAmount)
|
||||
{
|
||||
var building_profit_log_info = new BuildingProfitLogInfo();
|
||||
building_profit_log_info.setLogProperty(buildingMetaId, floor, currencyType, amountDeltaType, deltaAmount, currencyAmount);
|
||||
|
||||
return building_profit_log_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
123
GameServer/Entity/BuildingProfit/Helper/BuildingProfitHelper.cs
Normal file
123
GameServer/Entity/BuildingProfit/Helper/BuildingProfitHelper.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using Amazon.DynamoDBv2.Model;
|
||||
using Amazon.DynamoDBv2;
|
||||
using Amazon.Runtime.Internal.Transform;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Org.BouncyCastle.Asn1.Ocsp;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class BuildingProfitHelper
|
||||
{
|
||||
public static FloorProfitInfo toFloorProfitInfo(this BuildingProfit buildingProfit)
|
||||
{
|
||||
var building_profit_attribute = buildingProfit.getEntityAttribute<BuildingProfitAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_attribute, () => $"building_profit_history_attribute is null !!!");
|
||||
|
||||
var floor_profit_info = new FloorProfitInfo();
|
||||
|
||||
foreach (var (currency_type, currency_amount) in building_profit_attribute.Profits)
|
||||
{
|
||||
var money = new Money();
|
||||
money.Amount = currency_amount;
|
||||
|
||||
floor_profit_info.Profits.Add((int)currency_type, money);
|
||||
}
|
||||
|
||||
return floor_profit_info;
|
||||
}
|
||||
|
||||
public static (Result, DynamoDbItemRequestQueryContext?) tryMakeUpdateItemRequestFromBuildingProfit(int buildingMetaId, int floor, CurrencyType currencyType, double deltaAmount)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var doc = new BuildingProfitDoc(buildingMetaId, floor);
|
||||
var primary_key = doc.getPrimaryKey();
|
||||
|
||||
var query_builder = new DynamoDbItemRequestHelper.UpdateItemRequestBuilder(db_client.getTableFullName(doc.TableName));
|
||||
query_builder.withKeys(primary_key.toKeyWithAttributeValue());
|
||||
|
||||
var attrib_path_json_string = doc.toJsonStringOfAttribs();
|
||||
var target_key = JsonHelper.getJsonPropertyName<BuildingProfitAttrib>(nameof(BuildingProfitAttrib.Profits));
|
||||
|
||||
(var is_success, var attribute_expression) = DynamoDbClientHelper.toAttributeExpressionFromJson(attrib_path_json_string, target_key);
|
||||
if (false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to DynamoDbClientHelper.toAttributeExpressionFromJson() !!! : attribPath:{attrib_path_json_string}, targetKey:{target_key}";
|
||||
result.setFail(ServerErrorCode.AttribPathMakeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
var attributeNames = DynamoDbClientHelper.toExpressionAttributeNamesFromJson(attrib_path_json_string, target_key);
|
||||
attributeNames.Add($"#{currencyType}", currencyType.ToString());
|
||||
query_builder.withExpressionAttributeNames(attributeNames);
|
||||
|
||||
attribute_expression += $".#{currencyType}";
|
||||
var update_expression = (deltaAmount >= 0)
|
||||
? $"SET {attribute_expression} = if_not_exists({attribute_expression}, :start) + :changeValue"
|
||||
: $"SET {attribute_expression} = if_not_exists({attribute_expression}, :start) - :changeValue";
|
||||
query_builder.withUpdateExpression(update_expression);
|
||||
|
||||
var expression_attribute_values = new Dictionary<string, AttributeValue>
|
||||
{
|
||||
{ ":changeValue", new AttributeValue { N = Math.Abs(deltaAmount).ToString() } },
|
||||
{ ":start", new AttributeValue { N = "0" } }
|
||||
};
|
||||
query_builder.withExpressionAttributeValues(expression_attribute_values);
|
||||
|
||||
query_builder.withReturnValues(ReturnValue.ALL_NEW);
|
||||
|
||||
(result, var update_item_request) = query_builder.build();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to DynamoDbItemRequestHelper.build() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(update_item_request, () => $"update_item_request is null !!! - {primary_key.toBasicString()}");
|
||||
|
||||
return (result, update_item_request.createItemRequestQueryContext(QueryType.Update));
|
||||
}
|
||||
|
||||
public static async Task<(Result, BuildingProfit?, DynamoDbDocBase?)> tryMakeBuildingProfit(Building building, int buildingMetaId, int floor, CurrencyType currencyType, double currencyAmount)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var building_profit = new BuildingProfit(building);
|
||||
await building_profit.onInit();
|
||||
|
||||
var new_building_profit_attribute = building_profit.getEntityAttribute<BuildingProfitAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(new_building_profit_attribute, () => $"new_building_profit_attribute is null !!!");
|
||||
|
||||
new_building_profit_attribute.BuildingMetaId = buildingMetaId;
|
||||
new_building_profit_attribute.Floor = floor;
|
||||
new_building_profit_attribute.Profits[currencyType] = currencyAmount;
|
||||
new_building_profit_attribute.newEntityAttribute();
|
||||
|
||||
(result, var building_profit_doc) = await new_building_profit_attribute.toDocBase();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to toDocBase() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_doc, () => $"building_profit_doc is null !!!");
|
||||
|
||||
return (result, building_profit, building_profit_doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static ClientToGameMessage.Types;
|
||||
using static ServerMessage.Types;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class BuildingProfitNotifyHelper
|
||||
{
|
||||
public static bool send_GS2GS_NTF_MODIFY_BUILDING_PROFIT(int buildingMetaId, List<(int, CurrencyType, double)> profits)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var message = new ServerMessage();
|
||||
message.NtfModifyBuildingProfit = new GS2GS_NTF_MODIFY_BUILDING_PROFIT();
|
||||
|
||||
message.NtfModifyBuildingProfit.ExceptServerName = server_logic.getServerName();
|
||||
message.NtfModifyBuildingProfit.BuildingMetaId = buildingMetaId;
|
||||
|
||||
foreach (var (floor, currency_type, delta_amount) in profits)
|
||||
{
|
||||
if (!message.NtfModifyBuildingProfit.FloorProfits.TryGetValue(floor, out var floor_profits))
|
||||
{
|
||||
floor_profits = new FloorProfitInfo();
|
||||
message.NtfModifyBuildingProfit.FloorProfits[floor] = floor_profits;
|
||||
}
|
||||
|
||||
var money = new Money();
|
||||
money.Amount = delta_amount;
|
||||
|
||||
floor_profits.Profits[(int)currency_type] = money;
|
||||
}
|
||||
|
||||
var rabbit_mq = server_logic.getRabbitMqConnector() as RabbitMQ4Game;
|
||||
NullReferenceCheckHelper.throwIfNull(rabbit_mq, () => $"rabbit_mq is null !!!");
|
||||
|
||||
rabbit_mq.sendMessageToExchangeAllGame(message);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool send_GS2GS_NTF_MODIFY_BUILDING_PROFIT(int buildingMetaId, int floor, CurrencyType currencyType, double currencyAmount)
|
||||
{
|
||||
var modify_profits = new List<(int, CurrencyType, double)>();
|
||||
modify_profits.Add((floor, currencyType, currencyAmount));
|
||||
|
||||
return send_GS2GS_NTF_MODIFY_BUILDING_PROFIT(buildingMetaId, modify_profits);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingProfitHistoryAction : EntityActionBase
|
||||
{
|
||||
public BuildingProfitHistoryAction(BuildingProfitHistory owner)
|
||||
: base(owner)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public Result tryLoadBuildingProfitHistoryFromDoc(BuildingProfitHistoryDoc buildingProfitHistoryDoc)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var building_profit_history = getOwner() as BuildingProfitHistory;
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_history, () => $"building_profit_history is null !!!");
|
||||
|
||||
var building_profit_history_attribute = building_profit_history.getEntityAttribute<BuildingProfitHistoryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_history_attribute, () => $"building_profit_history_attribute is null !!!");
|
||||
|
||||
if (!building_profit_history_attribute.copyEntityAttributeFromDoc(buildingProfitHistoryDoc))
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDoc() !!! to:{building_profit_history_attribute.getTypeName()}, from:{buildingProfitHistoryDoc.getTypeName()} : {this.getTypeName()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingProfitHistoryAgentAction : EntityActionBase
|
||||
{
|
||||
ConcurrentBag<BuildingProfitHistory> m_building_profit_historys = new();
|
||||
|
||||
public BuildingProfitHistoryAgentAction(Building owner)
|
||||
: base(owner)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> tryLoadBuildingProfitHistoryFromDb(int buildingMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var doc = new BuildingProfitHistoryDoc();
|
||||
doc.setCombinationKeyForPK(buildingMetaId.ToString());
|
||||
|
||||
var error_code = doc.onApplyPKSK();
|
||||
if (error_code.isFail())
|
||||
{
|
||||
err_msg = $"Failed to onApplyPKSK() !!! : {error_code.toBasicString()}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var query_config = db_client.makeQueryConfigWithPKSKBySKBeginWith(doc.getPK(), BuildingProfitHistoryDoc.getPrefixOfSK());
|
||||
|
||||
(result, var read_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig<BuildingProfitHistoryDoc>(query_config);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypesWithQueryOperationConfig() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
foreach (var read_doc in read_docs)
|
||||
{
|
||||
var building_profit_history = new BuildingProfitHistory(building);
|
||||
await building_profit_history.onInit();
|
||||
|
||||
var building_profit_history_action = building_profit_history.getEntityAction<BuildingProfitHistoryAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_history_action, () => $"building_profit_history_attribute is null !!!");
|
||||
|
||||
result = building_profit_history_action.tryLoadBuildingProfitHistoryFromDoc(read_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryLoadBuildingProfitHistoryFromDoc() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var building_profit_history_attribute = building_profit_history.getEntityAttribute<BuildingProfitHistoryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_history_attribute, () => $"building_profit_history_attribute is null !!!");
|
||||
|
||||
m_building_profit_historys.Add(building_profit_history);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<BuildingProfitHistoryInfo> getBuildingProfitHistoryInfos()
|
||||
{
|
||||
var building_profit_story_infos = new List<BuildingProfitHistoryInfo>();
|
||||
|
||||
foreach (var building_profit_history in m_building_profit_historys)
|
||||
{
|
||||
var building_profit_history_info = building_profit_history.toBuildingProfitHistoryInfo();
|
||||
building_profit_story_infos.Add(building_profit_history_info);
|
||||
}
|
||||
|
||||
return building_profit_story_infos;
|
||||
}
|
||||
|
||||
public void addBuildingProfitHistory(BuildingProfitHistory buildingProfitHistory)
|
||||
{
|
||||
m_building_profit_historys.Add(buildingProfitHistory);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingProfitHistory : EntityBase
|
||||
{
|
||||
public BuildingProfitHistory(Building building)
|
||||
: base(EntityType.BuildingProfitHistory, building)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
addEntityAttribute(new BuildingProfitHistoryAttribute(this));
|
||||
addEntityAction(new BuildingProfitHistoryAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}, BuildingMetaId:{getOriginEntityAttribute<BuildingFloorAttribute>()?.BuildingMetaId}, Floor:{getOriginEntityAttribute<BuildingFloorAttribute>()?.Floor}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}, {getEntityAttribute<BuildingFloorAttribute>()?.toBasicString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class BuildingProfitHistoryHelper
|
||||
{
|
||||
public static BuildingProfitHistoryInfo toBuildingProfitHistoryInfo(this BuildingProfitHistory buildingProfitHistory)
|
||||
{
|
||||
var building_profit_history_attribute = buildingProfitHistory.getEntityAttribute<BuildingProfitHistoryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_history_attribute, () => $"building_profit_history_attribute is null !!!");
|
||||
|
||||
var building_profit_history_info = new BuildingProfitHistoryInfo
|
||||
{
|
||||
HistoryDate = building_profit_history_attribute.ProfitTime.ToTimestamp(),
|
||||
Floor = (int)building_profit_history_attribute.Floor,
|
||||
ProfitHistoryType = building_profit_history_attribute.ProfitHistoryType,
|
||||
FloorProfit = new FloorProfitInfo()
|
||||
};
|
||||
|
||||
foreach (var (currency_type, currency_amount) in building_profit_history_attribute.Profits)
|
||||
{
|
||||
var money = new Money();
|
||||
money.Amount = currency_amount;
|
||||
|
||||
building_profit_history_info.FloorProfit.Profits.Add((int)currency_type, money);
|
||||
}
|
||||
|
||||
return building_profit_history_info;
|
||||
}
|
||||
|
||||
public static async Task<(Result, BuildingProfitHistory?, DynamoDbDocBase?)> tryMakeBuildingProfitHistory(Building building, int buildingMetaId, int floor, DateTime profitTime, ProfitHistoryType profitHistoryType, Dictionary<CurrencyType, double> profits)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var building_profit_history = new BuildingProfitHistory(building);
|
||||
await building_profit_history.onInit();
|
||||
|
||||
var building_profit_history_attribute = building_profit_history.getEntityAttribute<BuildingProfitHistoryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_history_attribute, () => $"building_profit_history_attribute is null !!!");
|
||||
|
||||
building_profit_history_attribute.BuildingMetaId = buildingMetaId;
|
||||
building_profit_history_attribute.Floor = floor;
|
||||
building_profit_history_attribute.ProfitTime = profitTime;
|
||||
building_profit_history_attribute.ProfitHistoryType = profitHistoryType;
|
||||
building_profit_history_attribute.Profits = profits;
|
||||
building_profit_history_attribute.newEntityAttribute();
|
||||
|
||||
(result, var building_profit_history_doc) = await building_profit_history_attribute.toDocBase();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to toDocBase() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
return (result, building_profit_history, building_profit_history_doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static ServerMessage.Types;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class BuildingProfitHistoryNotifyHelper
|
||||
{
|
||||
public static bool send_GS2GS_NTF_ADD_BUILDING_PROFIT_HISTORY(BuildingProfitHistory buildingProfitHistory)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var building_profit_history_attribute = buildingProfitHistory.getEntityAttribute<BuildingProfitHistoryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_profit_history_attribute, () => $"building_profit_history_attribute is null !!!");
|
||||
|
||||
var message = new ServerMessage();
|
||||
message.NtfAddBuildingProfitHistory = new GS2GS_NTF_ADD_BUILDING_PROFIT_HISTORY();
|
||||
|
||||
message.NtfAddBuildingProfitHistory.ExceptServerName = server_logic.getServerName();
|
||||
message.NtfAddBuildingProfitHistory.BuildingMetaId = building_profit_history_attribute.BuildingMetaId;
|
||||
message.NtfAddBuildingProfitHistory.Floor = building_profit_history_attribute.Floor;
|
||||
message.NtfAddBuildingProfitHistory.ProfitTime = building_profit_history_attribute.ProfitTime.ToTimestamp();
|
||||
message.NtfAddBuildingProfitHistory.ProfitHistoryType = building_profit_history_attribute.ProfitHistoryType;
|
||||
message.NtfAddBuildingProfitHistory.FloorProfit = new FloorProfitInfo();
|
||||
|
||||
foreach (var (currency_type, currency_amount) in building_profit_history_attribute.Profits)
|
||||
{
|
||||
var money = new Money();
|
||||
money.Amount = currency_amount;
|
||||
|
||||
message.NtfAddBuildingProfitHistory.FloorProfit.Profits.Add((int)currency_type, money);
|
||||
}
|
||||
|
||||
var rabbit_mq = server_logic.getRabbitMqConnector() as RabbitMQ4Game;
|
||||
NullReferenceCheckHelper.throwIfNull(rabbit_mq, () => $"rabbit_mq is null !!!");
|
||||
|
||||
rabbit_mq.sendMessageToExchangeAllGame(message);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingRentalHistoryAction : EntityActionBase
|
||||
{
|
||||
public BuildingRentalHistoryAction(BuildingRentalHistory owner)
|
||||
: base(owner)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public Result tryLoadBuildingRentalHistoryFromDoc(BuildingRentalHistoryDoc buildingRentalHistoryDoc)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var building_rental_history = getOwner() as BuildingRentalHistory;
|
||||
NullReferenceCheckHelper.throwIfNull(building_rental_history, () => $"building_rental_history is null !!!");
|
||||
|
||||
var building_rental_history_attribute = building_rental_history.getEntityAttribute<BuildingRentalHistoryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_rental_history_attribute, () => $"building_rental_history_attribute is null !!!");
|
||||
|
||||
if (!building_rental_history_attribute.copyEntityAttributeFromDoc(buildingRentalHistoryDoc))
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDoc() !!! to:{building_rental_history_attribute.getTypeName()}, from:{buildingRentalHistoryDoc.getTypeName()} : {this.getTypeName()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingRentalHistoryAgentAction : EntityActionBase
|
||||
{
|
||||
ConcurrentBag<BuildingRentalHistory> m_building_rental_historys = new();
|
||||
|
||||
public BuildingRentalHistoryAgentAction(Building owner)
|
||||
: base(owner)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> tryLoadBuildingRentalHistoryFromDb(int buildingMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var doc = new BuildingRentalHistoryDoc();
|
||||
doc.setCombinationKeyForPK(buildingMetaId.ToString());
|
||||
|
||||
var error_code = doc.onApplyPKSK();
|
||||
if (error_code.isFail())
|
||||
{
|
||||
err_msg = $"Failed to onApplyPKSK() !!! : {error_code.toBasicString()}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var query_config = db_client.makeQueryConfigWithPKSKBySKBeginWith(doc.getPK(), BuildingRentalHistoryDoc.getPrefixOfSK());
|
||||
|
||||
(result, var read_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig<BuildingRentalHistoryDoc>(query_config);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypesWithQueryOperationConfig() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var building = getOwner() as Building;
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!!");
|
||||
|
||||
foreach (var read_doc in read_docs)
|
||||
{
|
||||
var building_rental_history = new BuildingRentalHistory(building);
|
||||
await building_rental_history.onInit();
|
||||
|
||||
var building_rental_history_action = building_rental_history.getEntityAction<BuildingRentalHistoryAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_rental_history_action, () => $"building_rental_history_action is null !!!");
|
||||
|
||||
result = building_rental_history_action.tryLoadBuildingRentalHistoryFromDoc(read_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryLoadBuildingRentalHistoryFromDoc() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var building_rental_history_attribute = building_rental_history.getEntityAttribute<BuildingRentalHistoryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_rental_history_attribute, () => $"building_rental_history_attribute is null !!!");
|
||||
|
||||
m_building_rental_historys.Add(building_rental_history);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<List<BuildingRentalHistoryInfo>> getBuildingRentalHistoryInfos()
|
||||
{
|
||||
var building_rental_story_infos = new List<BuildingRentalHistoryInfo>();
|
||||
|
||||
foreach (var building_rental_history in m_building_rental_historys)
|
||||
{
|
||||
var building_rental_history_info = await building_rental_history.toBuildingRentalHistoryInfo();
|
||||
building_rental_story_infos.Add(building_rental_history_info);
|
||||
}
|
||||
|
||||
return building_rental_story_infos;
|
||||
}
|
||||
|
||||
public void addBuildingRentalHistory(BuildingRentalHistory buildingRentalHistory)
|
||||
{
|
||||
m_building_rental_historys.Add(buildingRentalHistory);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class BuildingRentalHistory : EntityBase
|
||||
{
|
||||
public BuildingRentalHistory(Building building)
|
||||
: base(EntityType.BuildingRentalHistory, building)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
addEntityAttribute(new BuildingRentalHistoryAttribute(this));
|
||||
addEntityAction(new BuildingRentalHistoryAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}, BuildingMetaId:{getOriginEntityAttribute<BuildingFloorAttribute>()?.BuildingMetaId}, Floor:{getOriginEntityAttribute<BuildingFloorAttribute>()?.Floor}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}, {getEntityAttribute<BuildingFloorAttribute>()?.toBasicString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class BuildingRentalHistoryHelper
|
||||
{
|
||||
public static async Task<BuildingRentalHistoryInfo> toBuildingRentalHistoryInfo(this BuildingRentalHistory buildingRentalHistory)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var building_rental_history_attribute = buildingRentalHistory.getEntityAttribute<BuildingRentalHistoryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_rental_history_attribute, () => $"building_rental_history_attribute is null !!!");
|
||||
|
||||
var building_rental_history_info = new BuildingRentalHistoryInfo
|
||||
{
|
||||
HistoryDate = building_rental_history_attribute.RentalTime.ToTimestamp(),
|
||||
UserGuid = building_rental_history_attribute.RenteeUserGuid,
|
||||
RentalPeriod = building_rental_history_attribute.RentalPeriod,
|
||||
Floor = (int)building_rental_history_attribute.Floor,
|
||||
};
|
||||
|
||||
(result, var nickname_attrib) = await NicknameDoc.findNicknameFromGuid(building_rental_history_attribute.RenteeUserGuid);
|
||||
if (result.isSuccess() && nickname_attrib != null)
|
||||
{
|
||||
building_rental_history_info.UserName = nickname_attrib.Nickname;
|
||||
}
|
||||
|
||||
return building_rental_history_info;
|
||||
}
|
||||
|
||||
public static async Task<(Result, BuildingRentalHistory?, DynamoDbDocBase?)> tryMakeBuildingRentalHistory(Building building, int buildingMetaId, int floor, string userGuid, DateTime rentalTime, int rentalPeriod)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var building_rental_history = new BuildingRentalHistory(building);
|
||||
await building_rental_history.onInit();
|
||||
|
||||
var building_rental_history_attribute = building_rental_history.getEntityAttribute<BuildingRentalHistoryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_rental_history_attribute, () => $"building_profit_history_attribute is null !!!");
|
||||
|
||||
building_rental_history_attribute.BuildingMetaId = buildingMetaId;
|
||||
building_rental_history_attribute.Floor = floor;
|
||||
building_rental_history_attribute.RenteeUserGuid = userGuid;
|
||||
building_rental_history_attribute.RentalTime = rentalTime;
|
||||
building_rental_history_attribute.RentalPeriod = rentalPeriod;
|
||||
building_rental_history_attribute.newEntityAttribute();
|
||||
|
||||
(result, var building_rental_history_doc) = await building_rental_history_attribute.toDocBase();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to toDocBase() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
return (result, building_rental_history, building_rental_history_doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static ServerMessage.Types;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class BuildingRentalHistoryNotifyHelper
|
||||
{
|
||||
public static bool send_GS2GS_NTF_ADD_BUILDING_RENTAL_HISTORY(BuildingRentalHistory buildingProfitHistory)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var building_rental_history_attribute = buildingProfitHistory.getEntityAttribute<BuildingRentalHistoryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(building_rental_history_attribute, () => $"building_profit_history_attribute is null !!!");
|
||||
|
||||
var message = new ServerMessage();
|
||||
message.NtfAddBuildingRentalHistory = new GS2GS_NTF_ADD_BUILDING_RENTAL_HISTORY();
|
||||
|
||||
message.NtfAddBuildingRentalHistory.ExceptServerName = server_logic.getServerName();
|
||||
message.NtfAddBuildingRentalHistory.BuildingMetaId = building_rental_history_attribute.BuildingMetaId;
|
||||
message.NtfAddBuildingRentalHistory.Floor = building_rental_history_attribute.Floor;
|
||||
message.NtfAddBuildingRentalHistory.RenteeUserGuid = building_rental_history_attribute.RenteeUserGuid;
|
||||
message.NtfAddBuildingRentalHistory.RentalTime = building_rental_history_attribute.RentalTime.ToTimestamp();
|
||||
message.NtfAddBuildingRentalHistory.RentalPeriod = building_rental_history_attribute.RentalPeriod;
|
||||
|
||||
var rabbit_mq = server_logic.getRabbitMqConnector() as RabbitMQ4Game;
|
||||
NullReferenceCheckHelper.throwIfNull(rabbit_mq, () => $"rabbit_mq is null !!!");
|
||||
|
||||
rabbit_mq.sendMessageToExchangeAllGame(message);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class CaliumContentAction : EntityActionBase
|
||||
{
|
||||
public CaliumContentAction(CaliumStorageEntity owner) : base(owner) { }
|
||||
|
||||
public override async Task<Result> onInit() => await Task.FromResult(new Result());
|
||||
|
||||
public override void onClear() {}
|
||||
|
||||
}
|
||||
298
GameServer/Entity/CaliumStorage/Action/CaliumEventAction.cs
Normal file
298
GameServer/Entity/CaliumStorage/Action/CaliumEventAction.cs
Normal file
@@ -0,0 +1,298 @@
|
||||
using Amazon.DynamoDBv2;
|
||||
using Amazon.DynamoDBv2.Model;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class CaliumEventAction : EntityActionBase
|
||||
{
|
||||
private enum ReTryStatus
|
||||
{
|
||||
None = 0,
|
||||
Success = 1,
|
||||
Fail = 2
|
||||
}
|
||||
|
||||
public CaliumEventAction(CaliumStorageEntity owner) : base(owner) { }
|
||||
|
||||
public override async Task<Result> onInit() => await Task.FromResult(new Result());
|
||||
|
||||
public override void onClear() {}
|
||||
|
||||
public async Task<Result> sendCaliumEventFromDB(CaliumEventDoc sendDoc)
|
||||
{
|
||||
var owner = getOwner() as CaliumStorageEntity;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
|
||||
|
||||
var web3_action = owner.getEntityAction<CaliumWeb3Action>();
|
||||
NullReferenceCheckHelper.throwIfNull(web3_action, () => $"calium_web3_action is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
// 0. 이벤트 전송
|
||||
var request = CaliumStorageHelper.makeCaliumEventRequest(sendDoc);
|
||||
var (result, response) = await web3_action.postCaliumEvent(request);
|
||||
|
||||
// 1. 성공시 리턴 ( 상태 수정 : Success )
|
||||
if (result.isSuccess())
|
||||
{
|
||||
await updateCaliumEventStatus(sendDoc, CaliumEventStatus.Sending, CaliumEventStatus.Success);
|
||||
return result;
|
||||
}
|
||||
|
||||
var res = checkRetryFail(result.ErrorCode, response?.m_code);
|
||||
|
||||
// 2. 이미 처리된 데이터 ( 상태 수정 : Success )
|
||||
if (res == ReTryStatus.Success)
|
||||
{
|
||||
await updateCaliumEventStatus(sendDoc, CaliumEventStatus.Sending, CaliumEventStatus.Success);
|
||||
return new Result();
|
||||
}
|
||||
|
||||
// 3. 실패시 재시도 (상태 수정 : Regist)
|
||||
if (res == ReTryStatus.None)
|
||||
{
|
||||
await updateCaliumEventStatus(sendDoc, CaliumEventStatus.Sending, CaliumEventStatus.Regist);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 3. 재시도 불가 기록 (상태 수정 : Failed)
|
||||
await updateCaliumEventStatus(sendDoc, CaliumEventStatus.Sending, CaliumEventStatus.Failed);
|
||||
|
||||
// 4. 로그 기록
|
||||
var log = new CaliumEchoSystemFailLogData { EventData = request };
|
||||
log.FailCode = response?.m_code ?? string.Empty;
|
||||
log.FailMessages = response?.m_messages ?? new();
|
||||
log.EventData = request;
|
||||
CaliumStorageHelper.writeFailEchoSystemLog(owner, log);
|
||||
Log.getLogger().error($"Failed to send Calium Event !! : {owner.toBasicString()}");
|
||||
|
||||
return new Result();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 칼리움 소각시 Web3 통보 함수
|
||||
/// </summary>
|
||||
/// <param name="actor"> 소각 행위자 </param>
|
||||
/// <param name="eventGuid"> Transaction ID </param>
|
||||
/// <param name="userNickname"> 유저 닉네임 </param>
|
||||
/// <param name="subType"> 소각 행위 구분 </param>
|
||||
/// <param name="caliumDelta"> 칼리움 변화량 ( 음수값 ) </param>
|
||||
/// <returns></returns>
|
||||
public async Task<Result> sendCaliumBurnEvent(IWithLogActor actor, string eventGuid, string userNickname, string subType, double caliumDelta)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
if (ServerCore.TypeHelper.NumericSignType.Positive == ServerCore.TypeHelper.checkNumericSignType<double>(caliumDelta))
|
||||
{
|
||||
caliumDelta *= -1;
|
||||
}
|
||||
|
||||
var send = await sendCaliumEvent(actor, CaliumEventType.calium_burn, eventGuid, userNickname, subType, 0, caliumDelta, true);
|
||||
|
||||
if (false == send.is_success)
|
||||
{
|
||||
var err_msg =
|
||||
$"fail to send calium event !! : eventGuid[{eventGuid}] subtype[{subType}] userNickanme[{userNickname}] caliumDelta[{caliumDelta}] / {nameof(sendCaliumEventFromPlayer)}";
|
||||
result.setFail(ServerErrorCode.FailToSendEchoSystem, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(bool is_success, CaliumEventData event_data)> sendCaliumEventFromPlayer(Player player, CaliumEventType type, string subType, double sapphireDelta, double caliumdelta, bool isReTry = true)
|
||||
{
|
||||
return await sendCaliumEvent(player, type, player.getUserGuid(), player.getUserNickname(), subType, sapphireDelta, caliumdelta, isReTry);
|
||||
}
|
||||
|
||||
public async Task<(Result result, CaliumEventDoc? change_doc)> updateCaliumEventStatus(CaliumEventDoc targetDoc, CaliumEventStatus beforeStatus, CaliumEventStatus afterStatus)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var dynamoDb_client = server_logic.getDynamoDbClient();
|
||||
NullReferenceCheckHelper.throwIfNull(dynamoDb_client, () => $"dynamodb client is null !!! ");
|
||||
|
||||
var make_primary_key = targetDoc.getPrimaryKey();
|
||||
|
||||
var updateRequest = makeUpdateItemRequest(targetDoc, make_primary_key.toKeyWithAttributeValue(), nameof(CaliumEventAttrib.Status), beforeStatus, afterStatus);
|
||||
if (updateRequest.result.isFail() || null == updateRequest.request)
|
||||
{
|
||||
if (updateRequest.result.isSuccess())
|
||||
{
|
||||
result.setFail(ServerErrorCode.FailToGetEchoSystemException, $"failed to make item request!!! - {getOwner().toBasicString()}");
|
||||
}
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
(result, var change_doc) = await dynamoDb_client.simpleQueryDocTypesWithUpdateItemRequest<CaliumEventDoc>(updateRequest.request);
|
||||
return (result, change_doc);
|
||||
}
|
||||
|
||||
private async Task<(bool is_success, CaliumEventData event_data)> sendCaliumEvent(IWithLogActor actor, CaliumEventType type, string eventGuid, string userNickname, string subType, double sapphireDelta, double caliumDelta, bool isRetry)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var owner = getOwner() as CaliumStorageEntity;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
|
||||
|
||||
var web3_action = owner.getEntityAction<CaliumWeb3Action>();
|
||||
NullReferenceCheckHelper.throwIfNull(web3_action, () => $"calium_web3_action is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
// 0. echoSystem 전송
|
||||
var request = await CaliumStorageHelper.makeCaliumEventRequest(owner, type, subType, userNickname, sapphireDelta, caliumDelta);
|
||||
(result, var response) = await web3_action.postCaliumEvent(request);
|
||||
|
||||
// 1. 성공시 리턴
|
||||
if (result.isSuccess()) return (true, request);
|
||||
|
||||
// 2. 실패시 DB 기록 및 Retry
|
||||
if (isRetry)
|
||||
{
|
||||
var event_guid = await retryPostCaliumEvent(eventGuid, result.ErrorCode, request, response);
|
||||
result.setSuccess();
|
||||
return (true, request);
|
||||
}
|
||||
|
||||
// 3. 실패시 실패 로그 기록
|
||||
var fail_log = new CaliumEchoSystemFailLogData();
|
||||
fail_log.FailCode = response?.m_code ?? string.Empty;
|
||||
fail_log.FailMessages = response?.m_messages ?? new();
|
||||
fail_log.ReTry = false;
|
||||
fail_log.EventData = request;
|
||||
|
||||
CaliumStorageHelper.writeFailEchoSystemLog(actor, fail_log);
|
||||
|
||||
return (false, request);
|
||||
}
|
||||
|
||||
private async Task<string> retryPostCaliumEvent(string userGuid, ServerErrorCode errCode, CaliumEventRequest request, EchoSystemBaseResponse? response)
|
||||
{
|
||||
var calium_entity = getOwner() as CaliumStorageEntity;
|
||||
NullReferenceCheckHelper.throwIfNull(calium_entity, () => "calium_entity is null !!!");
|
||||
|
||||
string event_guid;
|
||||
|
||||
var res = checkRetryFail(errCode, response?.m_code);
|
||||
|
||||
// 0. 이미 처리된 메시지
|
||||
if (res == ReTryStatus.Success)
|
||||
{
|
||||
event_guid = await saveCaliumEventToDB(userGuid, request, CaliumEventStatus.Success);
|
||||
return event_guid;
|
||||
}
|
||||
|
||||
// 1. 실패시 재시도 저장
|
||||
if (res != ReTryStatus.Fail)
|
||||
{
|
||||
event_guid = await saveCaliumEventToDB(userGuid, request, CaliumEventStatus.Regist);
|
||||
return event_guid;
|
||||
}
|
||||
|
||||
// 2. 재시도 불가 기록
|
||||
event_guid = await saveCaliumEventToDB(userGuid, request, CaliumEventStatus.Failed);
|
||||
|
||||
// 3. 로그 기록 ( 비즈니스? DB? )
|
||||
var fail_log = new CaliumEchoSystemFailLogData();
|
||||
fail_log.FailCode = response?.m_code ?? string.Empty;
|
||||
fail_log.FailMessages = response?.m_messages ?? new();
|
||||
fail_log.ReTry = true;
|
||||
fail_log.EventData = request;
|
||||
|
||||
CaliumStorageHelper.writeFailEchoSystemLog(calium_entity, fail_log);
|
||||
|
||||
return event_guid;
|
||||
}
|
||||
|
||||
private ReTryStatus checkRetryFail(ServerErrorCode errCode, string? code)
|
||||
{
|
||||
// 1. http 에러인 경우
|
||||
if (ServerErrorCode.FailToGetEchoSystemHttpError == errCode) return ReTryStatus.Fail;
|
||||
|
||||
// 2. DB insert fail 인 경우
|
||||
if (ServerErrorCode.GetFailEchoSystemResponse == errCode && code == "RET.WCE.101") return ReTryStatus.None;
|
||||
|
||||
// 3. 이미 처리된 Message 인 경우 ( 성공 처리 )
|
||||
if (ServerErrorCode.GetFailEchoSystemResponse == errCode && code == "FIN_WCE_200") return ReTryStatus.Success;
|
||||
|
||||
return ReTryStatus.Fail;
|
||||
}
|
||||
|
||||
private async Task<string> saveCaliumEventToDB(string userGuid, CaliumEventRequest request, CaliumEventStatus isRetry)
|
||||
{
|
||||
var doc = new CaliumEventDoc(request.m_event_id);
|
||||
var attrib = doc.getAttrib<CaliumEventAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(attrib, () => $"calium event attrib is null !!! - userGuid[{userGuid}] / {getOwner().toBasicString()}");
|
||||
|
||||
attrib.UserGuid = userGuid;
|
||||
attrib.EventData.m_server_type = request.m_server_type;
|
||||
attrib.EventData.m_event_type = request.m_event_type;
|
||||
attrib.EventData.m_sub_type = request.m_sub_type;
|
||||
attrib.EventData.m_div_type = request.m_div_type;
|
||||
attrib.EventData.m_div_id = request.m_div_id;
|
||||
attrib.EventData.m_calium_delta = request.m_calium_delta;
|
||||
attrib.EventData.m_sapphire_delta = request.m_sapphire_delta;
|
||||
attrib.EventData.m_current_epoch = request.m_current_epoch;
|
||||
attrib.EventData.m_current_inflation_rate = request.m_current_inflation_rate;
|
||||
attrib.Status = isRetry;
|
||||
|
||||
var dynamoDb_client = GameServerApp.getServerLogic().getDynamoDbClient();
|
||||
await dynamoDb_client.simpleUpsertDocumentWithDocType(doc);
|
||||
|
||||
return request.m_event_id;
|
||||
}
|
||||
|
||||
private (Result result, UpdateItemRequest? request) makeUpdateItemRequest( CaliumEventDoc target_doc, Dictionary<string, AttributeValue> attributeValueWithPrimaryKey
|
||||
, string targetAttribName
|
||||
, CaliumEventStatus beforeStatus
|
||||
, CaliumEventStatus afterStatus )
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var dynamoDb_client = server_logic.getDynamoDbClient();
|
||||
NullReferenceCheckHelper.throwIfNull(dynamoDb_client, () => $"dynamodb client is null !!! ");
|
||||
|
||||
var result = new Result();
|
||||
|
||||
var query_builder = new DynamoDbItemRequestHelper.UpdateItemRequestBuilder(dynamoDb_client.getTableFullName(target_doc.TableName));
|
||||
query_builder.withKeys(attributeValueWithPrimaryKey);
|
||||
|
||||
var attrib_path_json_string = target_doc.toJsonStringOfAttribs();
|
||||
var target_key = JsonHelper.getJsonPropertyName<CaliumEventAttrib>(targetAttribName);
|
||||
var (is_success, attribute_expression) = DynamoDbClientHelper.toAttributeExpressionFromJson(attrib_path_json_string, target_key);
|
||||
if (false == is_success)
|
||||
{
|
||||
var err_msg = $"Failed to DynamoDbClientHelper.toAttributeExpressionFromJson() !!! : attribPath:{attrib_path_json_string}, targetKey:{target_key}";
|
||||
result.setFail(ServerErrorCode.AttribPathMakeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
query_builder.withExpressionAttributeNames(DynamoDbClientHelper.toExpressionAttributeNamesFromJson(attrib_path_json_string, target_key));
|
||||
|
||||
// 변경값 설정
|
||||
var update_expression = $"SET {attribute_expression} = :changeValue";
|
||||
query_builder.withUpdateExpression(update_expression);
|
||||
|
||||
// 조건 추가
|
||||
query_builder.withConditionExpression($"{attribute_expression} = :beforeValue");
|
||||
|
||||
// 설정값 등록
|
||||
var expression_attribute_values = new Dictionary<string, AttributeValue>
|
||||
{
|
||||
{ ":changeValue", new AttributeValue { S = afterStatus.ToString() } },
|
||||
{ ":beforeValue", new AttributeValue { S = beforeStatus.ToString() } }
|
||||
};
|
||||
query_builder.withExpressionAttributeValues(expression_attribute_values);
|
||||
|
||||
query_builder.withReturnValues(ReturnValue.ALL_NEW);
|
||||
|
||||
return query_builder.build();
|
||||
}
|
||||
}
|
||||
602
GameServer/Entity/CaliumStorage/Action/CaliumStorageAction.cs
Normal file
602
GameServer/Entity/CaliumStorage/Action/CaliumStorageAction.cs
Normal file
@@ -0,0 +1,602 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class CaliumStorageAction : EntityActionBase
|
||||
{
|
||||
private readonly CaliumStorageCacheRequest m_cache_request;
|
||||
private int m_repeat_count { get; set; }
|
||||
|
||||
public CaliumStorageAction(CaliumStorageEntity owner) : base(owner)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis = server_logic.getRedisConnector();
|
||||
|
||||
m_cache_request = new CaliumStorageCacheRequest(redis);
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
// 1. fill up 시간 체크
|
||||
var pivot_date = CaliumStorageHelper.CurrentPivotTimeDate();
|
||||
var task_date = pivot_date;
|
||||
|
||||
// 2. repeat count
|
||||
m_repeat_count = 24 / MetaHelper.GameConfigMeta.CaliumConverterCycleTime;
|
||||
|
||||
// 3. DailyTimeEventManager 등록
|
||||
string task_name;
|
||||
|
||||
for (var repeat = 0; repeat < m_repeat_count; repeat++)
|
||||
{
|
||||
var is_first_run = repeat != 0;
|
||||
|
||||
task_name = "CaliumConverterManage";
|
||||
task_name = $"{task_name}_{repeat}";
|
||||
DailyTimeEventManager.Instance.tryAddTask(task_name, task_date, onFillUpDailyCalium, is_first_run);
|
||||
|
||||
task_date = task_date.AddHours(MetaHelper.GameConfigMeta.CaliumConverterCycleTime);
|
||||
}
|
||||
|
||||
// 4. 컨버터 동기화 체크 Manager 등록
|
||||
task_name = "CaliumConverterSyncManage";
|
||||
DailyTimeEventManager.Instance.tryAddTask(task_name, task_date.AddHours(1), onSyncConverterCalium);
|
||||
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
public override void onClear() {}
|
||||
|
||||
public async Task<Result> initStorageAttribute()
|
||||
{
|
||||
var owner = getOwner() as CaliumStorageEntity;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
|
||||
|
||||
// 0. Web3 Connection 체크
|
||||
var web3_action = getOwner().getEntityAction<CaliumWeb3Action>();
|
||||
NullReferenceCheckHelper.throwIfNull(web3_action, () => $"web3_action is null !!! - {owner.toBasicString()}");
|
||||
var result = await web3_action.checkWeb3Connection();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 1. 데이터 로딩
|
||||
result = await loadStorageAttribute();
|
||||
if (result.isSuccess()) return result;
|
||||
|
||||
// 2. Storage Doc 을 찾지 못하는 에러가 아닌 경우 에러 처리
|
||||
if (result.ErrorCode != ServerErrorCode.DynamoDbQueryNoMatchAttribute) return result;
|
||||
|
||||
// 3. 신규 데이터 저장
|
||||
var dynamodb_client = GameServerApp.getServerLogic().getDynamoDbClient();
|
||||
|
||||
var doc = new CaliumStorageDoc();
|
||||
result = await dynamodb_client.simpleInsertDocumentWithDocType<CaliumStorageDoc>(doc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public double getTotalCalium(CaliumStorageType storageType)
|
||||
{
|
||||
var attribute = getOwner().getEntityAttribute<CaliumStorageAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"calium_storage_attribute is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
return storageType switch
|
||||
{
|
||||
CaliumStorageType.Converter => attribute.ConverterTotalCalium,
|
||||
CaliumStorageType.Operator => attribute.OperatorTotalCalium,
|
||||
_ => -1
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<CaliumStorageAttribute> getCaliumStorageInfo()
|
||||
{
|
||||
await checkNewCaliumStoragePivotTime();
|
||||
|
||||
var attribute = getOwner().getEntityAttribute<CaliumStorageAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"calium_storage_attribute is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
return attribute;
|
||||
}
|
||||
|
||||
public async Task<double> getCaliumConverterEfficiency()
|
||||
{
|
||||
await checkNewCaliumStoragePivotTime();
|
||||
|
||||
var attribute = getOwner().getEntityAttribute<CaliumStorageAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"calium_storage_attribute is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
return attribute.DailyConvertRate;
|
||||
}
|
||||
|
||||
public async Task<Result> loadStorageAttribute()
|
||||
{
|
||||
var dynamodb_client = GameServerApp.getServerLogic().getDynamoDbClient();
|
||||
|
||||
var owner = getOwner() as CaliumStorageEntity;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(owner, LogActionType.ConvertCalium, dynamodb_client);
|
||||
batch.addQuery(new DBQCaliumStorageLoad());
|
||||
|
||||
var result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void sendChangeStorageInfo()
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var rabbit_mq = server_logic.getRabbitMqConnector() as RabbitMQ4Game;;
|
||||
NullReferenceCheckHelper.throwIfNull(rabbit_mq, () => $"rabbit_mq is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var server_message = new ServerMessage();
|
||||
server_message.NtfChangeCaliumStorageInfo = new();
|
||||
|
||||
rabbit_mq.sendMessageToExchangeAllGame(server_message);
|
||||
}
|
||||
|
||||
public async Task<Result> enableCaliumStorage()
|
||||
{
|
||||
await checkNewCaliumStoragePivotTime();
|
||||
var result = new Result();
|
||||
|
||||
var storage_attribute = getOwner().getEntityAttribute<CaliumStorageAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(storage_attribute, () => $"storage_attribute is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
if (storage_attribute.DailyPivotDate < CaliumStorageHelper.CurrentPivotTimeDate())
|
||||
{
|
||||
var err_msg = $"rollup date is old data !!! : current[{storage_attribute.DailyPivotDate}] / to[{CaliumStorageHelper.CurrentPivotTimeDate()}]";
|
||||
result.setFail(ServerErrorCode.FailToGetEchoSystemRollUp, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<bool> checkRetryCaliumEchoSystem()
|
||||
{
|
||||
return await m_cache_request.checkRetryKey();
|
||||
}
|
||||
|
||||
private Result initializeStorage(CaliumStorageAttrib attrib, RollUpData? rollUp)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
if (null == rollUp)
|
||||
{
|
||||
var err_msg = "fail to initialize calium storage : roll up data is null!!";
|
||||
result.setFail(ServerErrorCode.GetFailEchoSystemResponse, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
attrib.DailyEpoch = rollUp.m_epoch - 1;
|
||||
attrib.DailyPivotDate = CaliumStorageHelper.CurrentPivotTimeDate().AddDays(-1);
|
||||
|
||||
var calium = CaliumStorageHelper.SubTractDoubleByLong(rollUp.m_stack_converter_volume, rollUp.m_convertor_volume);
|
||||
attrib.ConverterStorage.ConverterCumulativeCalium = calium;
|
||||
attrib.ConverterStorage.DailyConvertRate = rollUp.m_daily_converter_rate;
|
||||
attrib.ConverterStorage.TotalCalium = calium;
|
||||
attrib.ConverterStorage.LastFillUpDate = CaliumStorageHelper.CurrentPivotTimeDate().AddHours(-1 * MetaHelper.GameConfigMeta.CaliumConverterCycleTime);
|
||||
attrib.ConverterStorage.DailyFillUpStandardCalium = rollUp.m_convertor_volume;
|
||||
|
||||
attrib.ExchangerStorage.DailyInflationRate = rollUp.m_daily_inflation_rate;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> changeCaliumConverterTotal(double delta)
|
||||
{
|
||||
var result = new Result();
|
||||
if (delta == 0) return result;
|
||||
|
||||
var owner = getOwner() as CaliumStorageEntity;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
|
||||
|
||||
// 1. delta 값 변경
|
||||
var item_request_batch = new QueryBatchEx<QueryRunnerWithItemRequest>(owner, LogActionType.ConvertCalium, GameServerApp.getServerLogic().getDynamoDbClient(), true);
|
||||
item_request_batch.addQuery(new DBQStorageCaliumUpdate(CaliumStorageType.Converter, delta, true));
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(item_request_batch);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. calium storage attribute 갱신
|
||||
_ = loadStorageAttribute();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<CaliumStorageDoc?> getCaliumStorageDoc()
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var dynamodb_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var query_config = dynamodb_client.makeQueryConfigForReadByPKOnly(CaliumStorageDoc.pk);
|
||||
var (result, found_doc) = await dynamodb_client.simpleQueryDocTypeWithQueryOperationConfig<CaliumStorageDoc>(query_config);
|
||||
if (result.isFail() || null == found_doc) return null;
|
||||
|
||||
return found_doc;
|
||||
}
|
||||
|
||||
private async Task checkNewCaliumStoragePivotTime()
|
||||
{
|
||||
var owner = getOwner() as CaliumStorageEntity;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
|
||||
|
||||
var attribute = getOwner().getEntityAttribute<CaliumStorageAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"calium_storage_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
// 1. calium storage daily data 갱신 날짜 체크
|
||||
if (attribute.DailyPivotDate >= CaliumStorageHelper.CurrentPivotTimeDate()) return;
|
||||
|
||||
// 2. calium storage 데이터 수정
|
||||
_ = await loadStorageAttribute();
|
||||
}
|
||||
|
||||
public async Task onFillUpDailyCalium()
|
||||
{
|
||||
NullReferenceCheckHelper.throwIfNull(m_cache_request, () => $"m_cache_request is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
// 1. 시작 조건 체크
|
||||
var is_start = await m_cache_request.startCaliumConverterManage();
|
||||
if (!is_start) return;
|
||||
|
||||
// 2. doc 데이터 로딩
|
||||
var found_doc = await getCaliumStorageDoc();
|
||||
NullReferenceCheckHelper.throwIfNull(found_doc, () => $"calium_storage_doc is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var calium_storage_attrib = found_doc.getAttrib<CaliumStorageAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(calium_storage_attrib, () => $"calium_storage_attrib is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
// 3. Daily Calium Converter 정보 갱신 처리
|
||||
var update = await updateDailyCaliumConverter(found_doc);
|
||||
if (false == update.is_success) return;
|
||||
|
||||
// 4. 미 충전 횟수 체크
|
||||
var check_fill_up = checkMissFillUpDailyCalium(calium_storage_attrib);
|
||||
|
||||
// 5. daily calium 충전
|
||||
var fill_up_calium = await fillUpDailyCalium(calium_storage_attrib, check_fill_up.missFillUpCount, check_fill_up.lastFillUpDate);
|
||||
if (fill_up_calium <= 0) return;
|
||||
|
||||
// 6. business log 기록
|
||||
var calium_log_data = new CaliumConverterLogData();
|
||||
calium_log_data.CurrentDailyCalium = 0;
|
||||
calium_log_data.CurrentTotalCalium = getTotalCalium(CaliumStorageType.Converter);
|
||||
calium_log_data.DeltaDailyCalium = 0;
|
||||
calium_log_data.DeltaTotalCalium = CaliumStorageHelper.AddDoubleByLong(fill_up_calium, update.mis_pivot_calium);
|
||||
calium_log_data.AmountDeltaType = AmountDeltaType.Acquire;
|
||||
|
||||
var calium_business_log = new CaliumBusinessLog(new LogActionEx(LogActionType.FillupCalium), calium_log_data);
|
||||
|
||||
var calium_converter = GameServerApp.getServerLogic().findGlobalEntity<CaliumStorageEntity>();
|
||||
NullReferenceCheckHelper.throwIfNull(calium_converter, () => $"calium_converter is null !!!");
|
||||
BusinessLogger.collectLog(calium_converter, calium_business_log);
|
||||
}
|
||||
|
||||
private async Task onSyncConverterCalium()
|
||||
{
|
||||
// 실행 기본 딜레이 처리
|
||||
await Task.Delay(10_000);
|
||||
|
||||
var owner = getOwner() as CaliumStorageEntity;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
|
||||
|
||||
// 1. 시작 조건 체크
|
||||
var is_start = await m_cache_request.startCaliumConverterManage(true);
|
||||
if (!is_start) return;
|
||||
|
||||
// 2. doc 데이터 로딩
|
||||
var found_doc = await getCaliumStorageDoc();
|
||||
NullReferenceCheckHelper.throwIfNull(found_doc, () => $"calium_storage_doc is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var calium_storage_attrib = found_doc.getAttrib<CaliumStorageAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(calium_storage_attrib, () => $"calium_storage_attrib is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
// 3. sync 시작 체크
|
||||
var is_check = checkSyncEchoSystem(calium_storage_attrib);
|
||||
if (is_check) return;
|
||||
|
||||
// 4. echoSystem 조회
|
||||
var web3_action = getOwner().getEntityAction<CaliumWeb3Action>();
|
||||
NullReferenceCheckHelper.throwIfNull(web3_action, () => $"web3_action is null !!! - {getOwner().toBasicString()}");
|
||||
var (result, msg) = await web3_action.getConverterSyncDataAsync();
|
||||
if (result.isFail())
|
||||
{
|
||||
var log = new CaliumEchoSystemFailLogData();
|
||||
log.FailCode = msg?.m_code ?? string.Empty;
|
||||
log.FailMessages = msg?.m_messages ?? new();
|
||||
CaliumStorageHelper.writeFailEchoSystemLog(owner, log);
|
||||
|
||||
Log.getLogger().error($"fail to sync converter from echo system !!! : code[{log.FailCode}] message[{log.FailMessages}]");
|
||||
return;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(msg, () => $"web3 response is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
// 5. 동기화 체크 : 적용 회차
|
||||
if (calium_storage_attrib.DailyEpoch != msg.m_sync?.m_epoch)
|
||||
{
|
||||
var log = new CaliumEchoSystemFailLogData();
|
||||
log.FailCode = "caliverse_error";
|
||||
log.FailMessages = new List<string> { $"failed to match epoch!! - current[{calium_storage_attrib.DailyEpoch}] / echoSystem[{msg.m_sync?.m_epoch}]" };
|
||||
CaliumStorageHelper.writeFailEchoSystemLog(owner, log);
|
||||
|
||||
Log.getLogger().error($"fail to sync converter from echo system !!! : code[{log.FailCode}] message[{log.FailMessages}]");
|
||||
return;
|
||||
}
|
||||
|
||||
// 6. 동기화 체크 : 총 누적 량
|
||||
if (false == CaliumStorageHelper.compareDoubleByLong(calium_storage_attrib.ConverterStorage.ConverterCumulativeCalium, msg.m_sync.m_stack_calium))
|
||||
{
|
||||
var log = new CaliumEchoSystemFailLogData();
|
||||
log.FailCode = "caliverse_error";
|
||||
log.FailMessages = new List<string> { $"failed to match converter calium!! - current[{calium_storage_attrib.ConverterStorage.ConverterCumulativeCalium}] / echoSystem[{msg.m_sync.m_stack_calium}]" };
|
||||
CaliumStorageHelper.writeFailEchoSystemLog(owner, log);
|
||||
|
||||
Log.getLogger().error($"fail to sync converter from echo system !!! : code[{log.FailCode}] message[{log.FailMessages}]");
|
||||
return;
|
||||
}
|
||||
|
||||
// 7. Sync Date 수정
|
||||
var item_request_batch = new QueryBatchEx<QueryRunnerWithItemRequest>(owner, LogActionType.CaliumSyncEchoSystem, GameServerApp.getServerLogic().getDynamoDbClient(), true);
|
||||
item_request_batch.addQuery(new DBQStorageCaliumSyncDateUpdate(DateTimeHelper.Current));
|
||||
|
||||
_ = await QueryHelper.sendQueryAndBusinessLog(item_request_batch);
|
||||
|
||||
var success_log = $"success to sync converter from echo system !!! : epoch[{calium_storage_attrib.DailyEpoch}] converter_cumulative_calium[{calium_storage_attrib.ConverterStorage.ConverterCumulativeCalium}]";
|
||||
Log.getLogger().info(success_log);
|
||||
}
|
||||
|
||||
private bool checkSyncEchoSystem(CaliumStorageAttrib caliumStorageAttrib)
|
||||
{
|
||||
var current_pivot_date = CaliumStorageHelper.CurrentPivotTimeDate();
|
||||
if (caliumStorageAttrib.DailyRollUpCheckDate < current_pivot_date.AddHours(1)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<(bool is_success, double mis_pivot_calium)> updateDailyCaliumConverter(CaliumStorageDoc originDoc)
|
||||
{
|
||||
var pivot_time = CaliumStorageHelper.CurrentPivotTimeDate();
|
||||
|
||||
var calium_storage_attrib = originDoc.getAttrib<CaliumStorageAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(calium_storage_attrib, () => $"calium_storage_attrib is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
// 1. Daily Calium Converter 갱신 조건 체크
|
||||
if (calium_storage_attrib.DailyPivotDate >= pivot_time) return (true, 0);
|
||||
|
||||
// 2. Daily Calium Roll Up 체크
|
||||
var (result, mis_pivot_calium) = await checkEchoSystemDailyCaliumAsync(calium_storage_attrib, pivot_time);
|
||||
if (result.isFail())
|
||||
{
|
||||
// retry 처리
|
||||
if (result.ErrorCode != ServerErrorCode.GetFailEchoSystemResponse)
|
||||
{
|
||||
await m_cache_request.setRetryKey();
|
||||
}
|
||||
|
||||
return (false, mis_pivot_calium);
|
||||
}
|
||||
|
||||
// 2. doc 갱신
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var dynamodb_client = server_logic.getDynamoDbClient();
|
||||
|
||||
result = await dynamodb_client.simpleUpdateDocumentWithDocType<CaliumStorageDoc>(originDoc);
|
||||
if (result.isFail())
|
||||
{
|
||||
var err_msg = $"failed to update daily calium converter info !!! - doc:{originDoc.toBasicString()} / {getOwner().toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
await m_cache_request.setRetryKey();
|
||||
return (false, -1);
|
||||
}
|
||||
|
||||
await m_cache_request.deleteRetryKey();
|
||||
|
||||
Log.getLogger().debug($"updateDailyCaliumConverter : finished!!! - mis_pivot_calium[{mis_pivot_calium}]");
|
||||
return (true, mis_pivot_calium);
|
||||
}
|
||||
|
||||
private async Task<(Result, double mis_pivot_calium)> checkEchoSystemDailyCaliumAsync(CaliumStorageAttrib caliumStorageAttrib, DateTime pivotTime)
|
||||
{
|
||||
var mis_pivot_calium = 0.0;
|
||||
|
||||
// 1. echoSystem 조회
|
||||
var web3_action = getOwner().getEntityAction<CaliumWeb3Action>();
|
||||
NullReferenceCheckHelper.throwIfNull(web3_action, () => $"web3_action is null !!! - {getOwner().toBasicString()}");
|
||||
var (result, msg) = await web3_action.getDailyRollUpDataAsync(caliumStorageAttrib.DailyEpoch + caliumStorageAttrib.MisEpoch);
|
||||
if (result.isFail() && msg?.m_code != "FIN.WRY.000") return (result, -1);
|
||||
|
||||
// 1-1. 최초 호출인 경우 데이터 정리
|
||||
if (caliumStorageAttrib.DailyEpoch <= 0)
|
||||
{
|
||||
result = initializeStorage(caliumStorageAttrib, msg?.m_list?.FirstOrDefault());
|
||||
if(result.isFail()) return (result, 0);
|
||||
}
|
||||
|
||||
// 2. Data 를 찾지 못하면, 당일 Rollup 이 되지 않은 상태, 예전 데이터로 채워서 넣어야함.
|
||||
if (msg?.m_code == "FIN.WRY.000")
|
||||
{
|
||||
msg = makePreviousRollUpData(caliumStorageAttrib);
|
||||
caliumStorageAttrib.MisEpoch += 1;
|
||||
result.setSuccess();
|
||||
}
|
||||
else
|
||||
{
|
||||
caliumStorageAttrib.MisEpoch = 0;
|
||||
}
|
||||
|
||||
NullReferenceCheckHelper.throwIfNull(msg, () => $"web3 response is null !!! - epoch:{caliumStorageAttrib.DailyEpoch} / {getOwner().toBasicString()}");
|
||||
NullReferenceCheckHelper.throwIfNull(msg.m_list, () => $"web3 response is null !!! - epoch:{caliumStorageAttrib.DailyEpoch} / {getOwner().toBasicString()}");
|
||||
|
||||
Log.getLogger().debug($"checkEchoSystemDailyCaliumAsync : RollUpData Count[{msg.m_list.Count}]");
|
||||
|
||||
// 3. Daily 데이터 적용
|
||||
foreach (var rollup in msg.m_list)
|
||||
{
|
||||
var pivot_calium = supplyRollUpData(caliumStorageAttrib, rollup, mis_pivot_calium, pivotTime);
|
||||
mis_pivot_calium = CaliumStorageHelper.AddDoubleByLong(mis_pivot_calium, pivot_calium);
|
||||
}
|
||||
|
||||
caliumStorageAttrib.DailyPivotDate = pivotTime;
|
||||
|
||||
Log.getLogger().debug($"checkEchoSystemDailyCaliumAsync : DailyPivotDate[{pivotTime}] / mis_pivot_calium[{mis_pivot_calium}]");
|
||||
return (result, mis_pivot_calium);
|
||||
}
|
||||
|
||||
private CaliumRollUpResponse makePreviousRollUpData(CaliumStorageAttrib attrib)
|
||||
{
|
||||
var response = new CaliumRollUpResponse();
|
||||
response.m_list = new List<RollUpData>();
|
||||
|
||||
var rollup = new RollUpData();
|
||||
rollup.m_create_time = attrib.DailyPivotDate.AddDays(1).AddHours(-1);
|
||||
rollup.m_daily_converter_rate = attrib.ConverterStorage.DailyConvertRate;
|
||||
rollup.m_epoch = attrib.DailyEpoch;
|
||||
rollup.m_daily_inflation_rate = attrib.ExchangerStorage.DailyInflationRate;
|
||||
rollup.m_convertor_volume = attrib.ConverterStorage.DailyFillUpStandardCalium;
|
||||
|
||||
response.m_list.Add(rollup);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private double supplyRollUpData(CaliumStorageAttrib caliumStorageAttrib, RollUpData rollup, double mis_pivot_calium, DateTime pivotTime)
|
||||
{
|
||||
Log.getLogger().debug($"supplyRollUpData : Attrib [epoch-{caliumStorageAttrib.DailyEpoch}] RollUp [epoch-{rollup.m_epoch}]");
|
||||
|
||||
if (rollup.m_epoch != 0 && rollup.m_epoch == caliumStorageAttrib.DailyEpoch)
|
||||
{
|
||||
// 그날의 미지급 Calium 추가
|
||||
var check_pivot_time = CaliumStorageHelper.CurrentPivotTimeDate(caliumStorageAttrib.ConverterStorage.LastFillUpDate);
|
||||
var data = checkMissFillUpDailyCalium(caliumStorageAttrib, check_pivot_time.AddDays(1).AddSeconds(-1));
|
||||
var fill_up_calium = calculateFillupCalium(caliumStorageAttrib, data.missFillUpCount, data.lastFillUpDate);
|
||||
|
||||
mis_pivot_calium = CaliumStorageHelper.AddDoubleByLong(mis_pivot_calium, fill_up_calium);
|
||||
caliumStorageAttrib.ConverterStorage.TotalCalium = CaliumStorageHelper.AddDoubleByLong(caliumStorageAttrib.ConverterStorage.TotalCalium, fill_up_calium);
|
||||
caliumStorageAttrib.ConverterStorage.LastFillUpDate = check_pivot_time.AddHours(MetaHelper.GameConfigMeta.CaliumConverterCycleTime * 2);
|
||||
|
||||
Log.getLogger().debug($"supplyRollUpData : 1. mis_pivot_calium[{mis_pivot_calium}]");
|
||||
return mis_pivot_calium;
|
||||
}
|
||||
|
||||
caliumStorageAttrib.ConverterStorage.ConverterCumulativeCalium = CaliumStorageHelper.AddDoubleByLong(caliumStorageAttrib.ConverterStorage.ConverterCumulativeCalium, rollup.m_convertor_volume);
|
||||
|
||||
// 1일을 추가한 이유 : create_time 이 전일 23:00:00 ~ 23:59:59 에 생성되기 때문
|
||||
var check_date = new DateTime(rollup.m_create_time.Year, rollup.m_create_time.Month, rollup.m_create_time.Day, 0, 0, 0);
|
||||
check_date = check_date.AddDays(1);
|
||||
|
||||
// PivotTime 이 00시 기준이 아닌 경우 체크해야 하기 때문에 시간 추가
|
||||
check_date = check_date.AddHours(MetaHelper.GameConfigMeta.CaliumConverterPivotTime);
|
||||
|
||||
if (check_date < pivotTime)
|
||||
{
|
||||
mis_pivot_calium = CaliumStorageHelper.AddDoubleByLong(mis_pivot_calium, rollup.m_convertor_volume);
|
||||
caliumStorageAttrib.ConverterStorage.TotalCalium = CaliumStorageHelper.AddDoubleByLong(caliumStorageAttrib.ConverterStorage.TotalCalium, rollup.m_convertor_volume);
|
||||
caliumStorageAttrib.ConverterStorage.LastFillUpDate = check_date.AddHours(MetaHelper.GameConfigMeta.CaliumConverterCycleTime * 2);
|
||||
}
|
||||
|
||||
if (caliumStorageAttrib.DailyEpoch >= rollup.m_epoch)
|
||||
{
|
||||
Log.getLogger().debug($"supplyRollUpData : 2. mis_pivot_calium[{mis_pivot_calium}]");
|
||||
return mis_pivot_calium;
|
||||
}
|
||||
caliumStorageAttrib.DailyEpoch = rollup.m_epoch;
|
||||
caliumStorageAttrib.ConverterStorage.DailyFillUpStandardCalium = rollup.m_convertor_volume;
|
||||
caliumStorageAttrib.ConverterStorage.DailyConvertRate = rollup.m_daily_converter_rate;
|
||||
caliumStorageAttrib.ExchangerStorage.DailyInflationRate = rollup.m_daily_inflation_rate;
|
||||
|
||||
Log.getLogger().debug($"supplyRollUpData : 3. mis_pivot_calium[{mis_pivot_calium}]");
|
||||
return mis_pivot_calium;
|
||||
}
|
||||
|
||||
private (int missFillUpCount, DateTime lastFillUpDate) checkMissFillUpDailyCalium(CaliumStorageAttrib caliumStorageAttrib, DateTime? nextPivotTime = null)
|
||||
{
|
||||
var current = nextPivotTime ?? DateTimeHelper.Current;
|
||||
var miss_fill_up_count = 0;
|
||||
|
||||
// 1. 마지막 충전 시간 확인
|
||||
var last_fill_up_date = caliumStorageAttrib.ConverterStorage.LastFillUpDate;
|
||||
var fill_up_date = (last_fill_up_date == DateTimeHelper.MinTime) ? current : last_fill_up_date;
|
||||
var next_fill_up_date = getNextFillDate(caliumStorageAttrib, fill_up_date);
|
||||
|
||||
// 2. 다음 충전 시간 체크
|
||||
while (next_fill_up_date <= current)
|
||||
{
|
||||
miss_fill_up_count++;
|
||||
|
||||
fill_up_date = next_fill_up_date;
|
||||
next_fill_up_date = getNextFillDate(caliumStorageAttrib, fill_up_date);
|
||||
}
|
||||
|
||||
Log.getLogger().debug($"checkMissFillUpDailyCalium - miss_fill_up_count[{miss_fill_up_count}] / last_fill_up_date[{last_fill_up_date}] / fill_up_date[{fill_up_date}] / next_pivot_time[{nextPivotTime ?? DateTimeHelper.MinTime}]");
|
||||
|
||||
return (miss_fill_up_count, fill_up_date);
|
||||
}
|
||||
|
||||
private DateTime getNextFillDate(CaliumStorageAttrib storageAttrib, DateTime current)
|
||||
{
|
||||
var check = storageAttrib.DailyPivotDate;
|
||||
|
||||
while (check <= current)
|
||||
{
|
||||
check = check.AddHours(MetaHelper.GameConfigMeta.CaliumConverterCycleTime);
|
||||
}
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
private async Task<double> fillUpDailyCalium(CaliumStorageAttrib caliumStorageAttrib, int fillUpCount, DateTime lastFillUpDate)
|
||||
{
|
||||
// 1. daily calium 충전량 계산
|
||||
var fill_up_calium = calculateFillupCalium(caliumStorageAttrib, fillUpCount, lastFillUpDate);
|
||||
|
||||
// 2. 최초 시작은 기본값으로 채움
|
||||
if (caliumStorageAttrib.ConverterStorage.LastFillUpDate == DateTimeHelper.MinTime)
|
||||
{
|
||||
fill_up_calium = (double)MetaHelper.GameConfigMeta.CaliumConverterInitialValue;
|
||||
}
|
||||
|
||||
Log.getLogger().debug($"fillUpDailyCalium - fill_up_calium[{fill_up_calium}] / fillUpCount[{fillUpCount}]");
|
||||
|
||||
if (fill_up_calium <= 0) return fill_up_calium;
|
||||
|
||||
// 3. calium 변경
|
||||
var result = await changeCaliumConverterTotal(fill_up_calium);
|
||||
if (result.isFail()) return -1;
|
||||
|
||||
// 4. data 갱신
|
||||
_ = loadStorageAttribute();
|
||||
|
||||
return fill_up_calium;
|
||||
}
|
||||
|
||||
private double calculateFillupCalium(CaliumStorageAttrib caliumStorageAttrib, int fillUpCount, DateTime lastFillupDate)
|
||||
{
|
||||
// 0. 충전 횟수가 0 이면, 처리 안함
|
||||
if (fillUpCount <= 0) return 0;
|
||||
|
||||
var daily_total_calium_long = (long)(caliumStorageAttrib.ConverterStorage.DailyFillUpStandardCalium * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
|
||||
var fill_up_calium_long = daily_total_calium_long / m_repeat_count;
|
||||
var fill_up_leave_long = daily_total_calium_long % m_repeat_count;
|
||||
|
||||
fill_up_calium_long *= fillUpCount;
|
||||
|
||||
// 마지막 회차의 경우, 나머지 부분을 추가해줘야 한다.
|
||||
if (lastFillupDate.AddHours(MetaHelper.GameConfigMeta.CaliumConverterCycleTime) >= caliumStorageAttrib.DailyPivotDate.AddDays(1))
|
||||
{
|
||||
fill_up_calium_long += fill_up_leave_long;
|
||||
}
|
||||
|
||||
return fill_up_calium_long / (double)EchoSystemHelper.DoubleCalculateDigitsLong;
|
||||
}
|
||||
}
|
||||
62
GameServer/Entity/CaliumStorage/Action/CaliumWeb3Action.cs
Normal file
62
GameServer/Entity/CaliumStorage/Action/CaliumWeb3Action.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class CaliumWeb3Action : EntityActionBase
|
||||
{
|
||||
private readonly EchoSystemRequester m_echo_requester;
|
||||
public const string SERVER_TYPE = "caliverse";
|
||||
|
||||
public CaliumWeb3Action(CaliumStorageEntity owner) : base(owner)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var server_config = server_logic.getServerConfig();
|
||||
|
||||
var ip = AwsHelper.getAwsPublicIPv4OrEthernetIPv4();
|
||||
var port = server_config.getAppParamPort();
|
||||
|
||||
m_echo_requester = new EchoSystemRequester(server_config.EchoSystemConfig.BaseAddress, server_logic.getServerName(), $"{ip}.{port}", server_config.EchoSystemConfig.SlackAddress);
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit() => await Task.FromResult(new Result());
|
||||
|
||||
public override void onClear() {}
|
||||
|
||||
public async Task<(Result result, CaliumRollUpResponse? response)> getDailyRollUpDataAsync(int epoch)
|
||||
{
|
||||
if (epoch > 0)
|
||||
{
|
||||
return await m_echo_requester.getDailyRollUpData(epoch);
|
||||
}
|
||||
|
||||
var current_pivot_date = CaliumStorageHelper.CurrentPivotTimeDate();
|
||||
|
||||
// 1일을 감소한 이유 : create_time 이 전일 23:00:00 ~ 23:59:59 에 생성되기 때문
|
||||
current_pivot_date = current_pivot_date.AddDays(-1);
|
||||
return await m_echo_requester.getDailyRollUpData(current_pivot_date);
|
||||
}
|
||||
|
||||
public async Task<(Result result, ConverterSyncResponse? response)> getConverterSyncDataAsync()
|
||||
{
|
||||
return await m_echo_requester.getConverterSyncData();
|
||||
}
|
||||
|
||||
public async Task<(Result result, CaliumEventResponse? response)> postCaliumEvent(CaliumEventRequest data)
|
||||
{
|
||||
return await m_echo_requester.postCaliumEvent(data);
|
||||
}
|
||||
|
||||
public async Task<Result> checkWeb3Connection()
|
||||
{
|
||||
return await m_echo_requester.checkWeb3Connection();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class CaliumConverterFailBusinessLog : ILogInvokerEx
|
||||
{
|
||||
private CaliumConverterFailLogData m_data_to_log;
|
||||
|
||||
public CaliumConverterFailBusinessLog(CaliumConverterFailLogData log) : base(LogDomainType.CaliumStorageFail)
|
||||
{
|
||||
m_data_to_log = log;
|
||||
}
|
||||
|
||||
public override bool hasLog() => true;
|
||||
|
||||
protected override void fillup(ref BusinessLog.LogBody body)
|
||||
{
|
||||
body.append(new CaliumConverterFailLogData(this, m_data_to_log));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class CaliumEchoSystemFailBusinessLog : ILogInvokerEx
|
||||
{
|
||||
private CaliumEchoSystemFailLogData m_data_to_log;
|
||||
|
||||
public CaliumEchoSystemFailBusinessLog(CaliumEchoSystemFailLogData log) : base(LogDomainType.CaliumEchoSystem)
|
||||
{
|
||||
m_data_to_log = log;
|
||||
}
|
||||
|
||||
public override bool hasLog() => true;
|
||||
|
||||
protected override void fillup(ref BusinessLog.LogBody body)
|
||||
{
|
||||
body.append(new CaliumEchoSystemFailLogData(this, m_data_to_log));
|
||||
}
|
||||
}
|
||||
83
GameServer/Entity/CaliumStorage/CaliumConverterCheat.cs
Normal file
83
GameServer/Entity/CaliumStorage/CaliumConverterCheat.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
[ChatCommandAttribute("caliumconverter", typeof(ChatCommandCaliumConverter), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
|
||||
internal class ChatCommandCaliumConverter : ChatCommandBase
|
||||
{
|
||||
public override async Task invoke(Player player, string token, string[] args)
|
||||
{
|
||||
Log.getLogger().info($"ChatCommandCaliumConverter");
|
||||
|
||||
var message = new ClientToGame();
|
||||
message.Request = new ClientToGameReq();
|
||||
message.Request.ReqCaliumConverter = new();
|
||||
|
||||
var result = await GameServerApp.getServerLogic().onCallProtocolHandler(player, message);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error($"fail to run ConvertCaliumCommand!! : {result.toBasicString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ChatCommandAttribute("initcaliumforuser", typeof(ChatCommandInitCaliumForUser), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
|
||||
internal class ChatCommandInitCaliumForUser : ChatCommandBase
|
||||
{
|
||||
public override async Task invoke(Player player, string token, string[] args)
|
||||
{
|
||||
Log.getLogger().info($"InitCaliumForUserCommand");
|
||||
|
||||
var result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "CheatInitCaliumForUserDaily", initCaliumDelegate);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error($"fail to run InitCaliumForUserCommand!! : {result.toBasicString()} / {player.toBasicString()}");
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
async Task<Result> initCaliumDelegate() => await initCalium(player);
|
||||
}
|
||||
|
||||
private async Task<Result> initCalium(Player player)
|
||||
{
|
||||
var user_calium_attribute = player.getEntityAttribute<CaliumAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_calium_attribute, () => $"user_calium_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
user_calium_attribute.DailyCalium = (double)MetaHelper.GameConfigMeta.CaliumConverterLimitPerPerson;
|
||||
user_calium_attribute.modifiedEntityAttribute();
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.ConvertCalium, GameServerApp.getServerLogic().getDynamoDbClient(), true);
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
|
||||
return await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
}
|
||||
}
|
||||
|
||||
[ChatCommandAttribute("caliumcontentcreate", typeof(ChatCommandCaliumContentCreate), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
|
||||
internal class ChatCommandCaliumContentCreate : ChatCommandBase
|
||||
{
|
||||
public override async Task invoke(Player player, string token, string[] args)
|
||||
{
|
||||
Log.getLogger().info($"ChatCommandCaliumContentCreate");
|
||||
|
||||
if (args.Length < 2) return;
|
||||
|
||||
var content_id = args[0];
|
||||
if (false == double.TryParse(args[1], out var calium)) return;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var message = new ServerMessage();
|
||||
message.ReqCreateContentStorage = new();
|
||||
message.ReqCreateContentStorage.ContentId = content_id;
|
||||
message.ReqCreateContentStorage.Calium = calium;
|
||||
message.ReqCreateContentStorage.RequestServerName = server_logic.getServerName();
|
||||
|
||||
var handler = new ReqCreateCaliumContentStorageHandler();
|
||||
var result = await handler.createCaliumContentStorage(message.ReqCreateContentStorage.ContentId, message.ReqCreateContentStorage.Calium);
|
||||
}
|
||||
}
|
||||
57
GameServer/Entity/CaliumStorage/CaliumStorageEntity.cs
Normal file
57
GameServer/Entity/CaliumStorage/CaliumStorageEntity.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class CaliumStorageEntity : EntityBase, IWithLogActor
|
||||
{
|
||||
public CaliumStorageEntity() : base(EntityType.CaliumConverter)
|
||||
{}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
// attribute
|
||||
addEntityAttribute(new CaliumStorageAttribute(this));
|
||||
|
||||
// action
|
||||
addEntityAction(new CaliumStorageAction(this));
|
||||
addEntityAction(new CaliumContentAction(this));
|
||||
addEntityAction(new CaliumEventAction(this));
|
||||
addEntityAction(new CaliumWeb3Action(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}";
|
||||
}
|
||||
|
||||
public virtual ILogActor toLogActor()
|
||||
{
|
||||
var server_logic = ServerLogicApp.getServerLogicApp();
|
||||
var log_info = new CaliumActorLog();
|
||||
|
||||
log_info.initLogInfo(
|
||||
// 서버 정보
|
||||
server_logic.getServerConfig().getRegionId()
|
||||
, server_logic.getServerConfig().getWorldId()
|
||||
, server_logic.getServerType().toServerType()
|
||||
);
|
||||
|
||||
return log_info;
|
||||
}
|
||||
}
|
||||
162
GameServer/Entity/CaliumStorage/CaliumStorageHelper.cs
Normal file
162
GameServer/Entity/CaliumStorage/CaliumStorageHelper.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public static class CaliumStorageHelper
|
||||
{
|
||||
public const double FixedExchangeRate = 0.01;
|
||||
|
||||
public static DateTime CurrentPivotTimeDate(DateTime? customDate = null)
|
||||
{
|
||||
var current = customDate ?? DateTimeHelper.Current;
|
||||
|
||||
if (current.Hour < ServerCommon.MetaHelper.GameConfigMeta.CaliumConverterPivotTime)
|
||||
{
|
||||
current = current.AddDays(-1);
|
||||
}
|
||||
|
||||
return new DateTime(current.Year, current.Month, current.Day, ServerCommon.MetaHelper.GameConfigMeta.CaliumConverterPivotTime, 0, 0);
|
||||
}
|
||||
|
||||
public static async Task<double> calculateCaliumFromSapphire(double sapphire, bool isCeiling = false)
|
||||
{
|
||||
// 1. 기본 정보 조회
|
||||
var calium_storage_entity = GameServerApp.getServerLogic().findGlobalEntity<CaliumStorageEntity>();
|
||||
NullReferenceCheckHelper.throwIfNull(calium_storage_entity, () => "calium_storage_entity is null !!!");
|
||||
|
||||
var calium_storage_action = calium_storage_entity.getEntityAction<CaliumStorageAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(calium_storage_action, () => $"calium_storage_action is null !!! - {calium_storage_entity.toBasicString()}");
|
||||
|
||||
var info = await calium_storage_action.getCaliumStorageInfo();
|
||||
|
||||
// 2. calium 교환비 계산 : (사파이어 * 고정 교환비) / 인플레이션 가중치(당일, % 처리)
|
||||
var calium = MultiplyDoubleByLong(sapphire, FixedExchangeRate);
|
||||
calium /= info.DailyInflationRate / 100;
|
||||
|
||||
// 3. 소수점 2자리수에서 판매는 올림 / 교환은 버림
|
||||
calium = isCeiling ? roundUpDefaultDigitsFromDouble(calium) : roundDownDefaultDigitsFromDouble(calium);
|
||||
|
||||
Log.getLogger().debug($"calculateCaliumFromSapphire !! : sapphire[{sapphire}] / calium[{calium}] / isCeiling[{isCeiling}] / swap_rate[{info.DailyInflationRate}]");
|
||||
|
||||
return calium;
|
||||
}
|
||||
|
||||
public static bool compareDoubleByLong(double first, double second)
|
||||
{
|
||||
var first_long = (long)(roundHalfUpDefaultDigitsFromDouble(first) * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
var second_long = (long)(roundHalfUpDefaultDigitsFromDouble(second) * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
|
||||
return first_long == second_long;
|
||||
}
|
||||
|
||||
public static double roundHalfUpDefaultDigitsFromDouble(double value)
|
||||
{
|
||||
var default_value = Math.Round(value * EchoSystemHelper.DoubleCalculateDigitsLong, 0);
|
||||
|
||||
var value_long = (long)default_value;
|
||||
return value_long / (double)EchoSystemHelper.DoubleCalculateDigitsLong;
|
||||
}
|
||||
|
||||
public static double roundDownDefaultDigitsFromDouble(double value)
|
||||
{
|
||||
var value_long = (long)(value * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
return value_long / (double)EchoSystemHelper.DoubleCalculateDigitsLong;
|
||||
}
|
||||
|
||||
public static double roundUpDefaultDigitsFromDouble(double value)
|
||||
{
|
||||
var default_value = Math.Ceiling(value * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
|
||||
var value_long = (long)default_value;
|
||||
return value_long / (double)EchoSystemHelper.DoubleCalculateDigitsLong;
|
||||
}
|
||||
|
||||
public static double AddDoubleByLong(double first, double second)
|
||||
{
|
||||
var first_long = (long)(first * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
var second_long = (long)(second * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
|
||||
var add = first_long + second_long;
|
||||
|
||||
return add / (double)EchoSystemHelper.DoubleCalculateDigitsLong;
|
||||
}
|
||||
|
||||
public static double SubTractDoubleByLong(double first, double second)
|
||||
{
|
||||
var first_long = (long)(first * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
var second_long = (long)(second * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
|
||||
var add = first_long - second_long;
|
||||
|
||||
return add / (double)EchoSystemHelper.DoubleCalculateDigitsLong;
|
||||
}
|
||||
|
||||
public static double MultiplyDoubleByLong(double first, double second)
|
||||
{
|
||||
var first_long = (long)(first * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
var second_long = (long)(second * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
|
||||
var mul = first_long * second_long;
|
||||
|
||||
return mul / (double)(EchoSystemHelper.DoubleCalculateDigitsLong * EchoSystemHelper.DoubleCalculateDigitsLong);
|
||||
}
|
||||
|
||||
public static void writeFailEchoSystemLog(IWithLogActor logActor, CaliumEchoSystemFailLogData log)
|
||||
{
|
||||
var log_action = new LogActionEx(LogActionType.FailCaliumEchoSystem);
|
||||
var invokers = new List<ILogInvoker>();
|
||||
invokers.Add(new CaliumEchoSystemFailBusinessLog(log));
|
||||
|
||||
BusinessLogger.collectLogs(log_action, logActor, invokers);
|
||||
}
|
||||
|
||||
public static async Task<CaliumEventRequest> makeCaliumEventRequest(CaliumStorageEntity owner, CaliumEventType type, string subType, string userNickname, double sapphireDelta, double caliumDelta)
|
||||
{
|
||||
var storage_action = owner.getEntityAction<CaliumStorageAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(storage_action, () => $"calium_storage_action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var storage = await storage_action.getCaliumStorageInfo();
|
||||
|
||||
var request = new CaliumEventRequest();
|
||||
request.m_server_type = CaliumWeb3Action.SERVER_TYPE;
|
||||
request.m_event_type = type.ToString();
|
||||
request.m_sub_type = subType;
|
||||
request.m_div_id = userNickname;
|
||||
request.m_calium_delta = caliumDelta;
|
||||
request.m_sapphire_delta = sapphireDelta;
|
||||
request.m_current_epoch = storage.DailyApplyEpoch;
|
||||
request.m_current_inflation_rate = storage.DailyInflationRate;
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
public static CaliumEventRequest makeCaliumEventRequest(CaliumEventDoc sendDoc)
|
||||
{
|
||||
var attrib = sendDoc.getAttrib<CaliumEventAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(attrib, () => $"calium_event_attrib is null !!! - {sendDoc.toBasicString()}");
|
||||
|
||||
// 2. echoSystem 전송
|
||||
var request = new CaliumEventRequest();
|
||||
request.m_event_id = sendDoc.getCombinationKeyForSK();
|
||||
request.m_server_type = attrib.EventData.m_server_type;
|
||||
request.m_event_type = attrib.EventData.m_event_type;
|
||||
request.m_sub_type = attrib.EventData.m_sub_type;
|
||||
request.m_div_type = attrib.EventData.m_div_type;
|
||||
request.m_div_id = attrib.EventData.m_div_id;
|
||||
request.m_calium_delta = attrib.EventData.m_calium_delta;
|
||||
request.m_sapphire_delta = attrib.EventData.m_sapphire_delta;
|
||||
request.m_current_epoch = attrib.EventData.m_current_epoch;
|
||||
request.m_current_inflation_rate = attrib.EventData.m_current_inflation_rate;
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
||||
100
GameServer/Entity/CaliumStorage/DbQuery/DBQCaliumStorageLoad.cs
Normal file
100
GameServer/Entity/CaliumStorage/DbQuery/DBQCaliumStorageLoad.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class DBQCaliumStorageLoad : QueryExecutorBase
|
||||
{
|
||||
private string m_pk = string.Empty;
|
||||
|
||||
public DBQCaliumStorageLoad() : base(nameof(DBQCaliumStorageLoad)) {}
|
||||
|
||||
//===================================================================================================
|
||||
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
|
||||
//===================================================================================================
|
||||
public override Task<Result> onPrepareQuery()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var doc = new CaliumStorageDoc();
|
||||
doc.setCombinationKeyForPK(string.Empty);
|
||||
|
||||
var error_code = doc.onApplyPKSK();
|
||||
if (error_code.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to onApplyPKSK() !!! : {error_code.toBasicString()} - {toBasicString()}, {owner.toBasicString()}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
m_pk = doc.getPK();
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
//===================================================================================================
|
||||
// onPrepareQuery()를 성공할 경우 호출된다.
|
||||
//===================================================================================================
|
||||
public override async Task<Result> onQuery()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
|
||||
|
||||
var query_batch = getQueryBatch();
|
||||
NullReferenceCheckHelper.throwIfNull(query_batch, () => $"query_batch is null !!!");
|
||||
|
||||
var db_connector = query_batch.getDynamoDbConnector();
|
||||
var query_config = db_connector.makeQueryConfigForReadByPKOnly(m_pk);
|
||||
|
||||
(result, var read_docs) = await db_connector.simpleQueryDocTypesWithQueryOperationConfig<CaliumStorageDoc>(query_config, eventTid: query_batch.getTransId());
|
||||
if (result.isFail()) return result;
|
||||
|
||||
if (read_docs.Count <= 0)
|
||||
{
|
||||
result.setFail(ServerErrorCode.DynamoDbQueryNoMatchAttribute, $"fail to find calium storage doc");
|
||||
return result;
|
||||
}
|
||||
|
||||
var calium_storage_doc = read_docs.FirstOrDefault();
|
||||
NullReferenceCheckHelper.throwIfNull(calium_storage_doc, () => $"calium_storage_doc is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var calium_storage_attribute = owner.getEntityAttribute<CaliumStorageAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(calium_storage_attribute, () => $"calium_storage_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
if (false == calium_storage_attribute.copyEntityAttributeFromDoc(calium_storage_doc))
|
||||
{
|
||||
var err_msg = $"failed to load Calium Storage !!! - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.FailToLoadCalium, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//===================================================================================================
|
||||
// DB 쿼리를 성공하고, doFnCommit()가 QueryResultType.NotCalledQueryFunc를 반환할 경우 호출된다.
|
||||
//===================================================================================================
|
||||
public override Task onQueryResponseCommit()
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
//===================================================================================================
|
||||
// DB 쿼리를 실패하고, doFnRollback()가 QueryResultType.NotCalledQueryFunc를 반환할 경우 호출된다.
|
||||
//===================================================================================================
|
||||
public override Task onQueryResponseRollback(Result errorResult)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private new CaliumStorageEntity? getOwner() => getQueryBatch()?.getLogActor() as CaliumStorageEntity;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using Amazon.DynamoDBv2.DocumentModel;
|
||||
using Amazon.DynamoDBv2.Model;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class DBQContentCaliumCreate : QueryExecutorBase
|
||||
{
|
||||
private readonly string m_contentId;
|
||||
private readonly double m_calium;
|
||||
|
||||
public DBQContentCaliumCreate(string contentId, double calium) : base(nameof(DBQContentCaliumCreate))
|
||||
{
|
||||
m_contentId = contentId;
|
||||
m_calium = calium;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
|
||||
//=====================================================================================
|
||||
public override async Task<Result> onPrepareQuery() => await Task.FromResult(new Result());
|
||||
|
||||
//=====================================================================================
|
||||
// onPrepareQuery()를 성공할 경우 호출된다.
|
||||
//=====================================================================================
|
||||
public override async Task<Result> onQuery()
|
||||
{
|
||||
var owner = getOwner();
|
||||
|
||||
var query_batch = getQueryBatch() as QueryBatch<QueryRunnerWithItemRequest>;
|
||||
NullReferenceCheckHelper.throwIfNull(query_batch, () => $"query_batch is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var query_runner_with_item_request = query_batch.getQueryRunner();
|
||||
NullReferenceCheckHelper.throwIfNull(query_runner_with_item_request, () => $"query_runner_with_item_request is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var db_connector = query_batch.getDynamoDbConnector();
|
||||
var create = await makeCreateItemRequestCaliumContentStorage(db_connector);
|
||||
if (create.result.isFail()) return create.result;
|
||||
NullReferenceCheckHelper.throwIfNull(create.putItemRequest, () => $"create_request is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var query_context = create.putItemRequest.createItemRequestQueryContext(QueryType.Insert);
|
||||
var result = await query_runner_with_item_request.tryRegisterQueryContext(query_context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// DB 쿼리를 성공하고, doFnCommit()가 QueryResultType.NotCalledQueryFunc를 반환할 경우 호출된다.
|
||||
//=====================================================================================
|
||||
public override async Task onQueryResponseCommit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// DB 쿼리를 실패하고, doFnRollback()가 QueryResultType.NotCalledQueryFunc를 반환할 경우 호출된다.
|
||||
//=====================================================================================
|
||||
public override async Task onQueryResponseRollback(Result errorResult)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
private async Task<(Result result, PutItemRequest? putItemRequest)> makeCreateItemRequestCaliumContentStorage(DynamoDbClient dbClient)
|
||||
{
|
||||
var target_doc = new CaliumContentDoc(m_contentId);
|
||||
var attrib = target_doc.getAttrib<CaliumContentAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(attrib, () => $"calium_content_attrib is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
attrib.ContentId = m_contentId;
|
||||
attrib.TotalCalium = m_calium;
|
||||
|
||||
var (result, document) = await target_doc.onCopyToDocument();
|
||||
if (result.isFail()) return (result, null);
|
||||
|
||||
var put_item_request = new PutItemRequest();
|
||||
put_item_request.TableName = dbClient.getTableFullName(ServerBase.DynamoDbDefine.TableNames.Main);
|
||||
put_item_request.Item = document.ToAttributeMap();
|
||||
|
||||
return (result, put_item_request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using Amazon.DynamoDBv2;
|
||||
using Amazon.DynamoDBv2.Model;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class DBQStorageCaliumSyncDateUpdate : QueryExecutorBase
|
||||
{
|
||||
private PrimaryKey m_primary_key = new();
|
||||
private DateTime m_sync_date { get; set; }
|
||||
|
||||
public DBQStorageCaliumSyncDateUpdate(DateTime syncDate) : base(nameof(DBQStorageCaliumSyncDateUpdate))
|
||||
{
|
||||
m_sync_date = syncDate;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
|
||||
//=====================================================================================
|
||||
public override async Task<Result> onPrepareQuery()
|
||||
{
|
||||
var owner = getOwner();
|
||||
|
||||
var (result, make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<CaliumStorageDoc>(string.Empty);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - {owner.toBasicString()}");
|
||||
|
||||
m_primary_key = make_primary_key;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// onPrepareQuery()를 성공할 경우 호출된다.
|
||||
//=====================================================================================
|
||||
public override async Task<Result> onQuery()
|
||||
{
|
||||
var owner = getOwner();
|
||||
|
||||
var query_batch = getQueryBatch() as QueryBatch<QueryRunnerWithItemRequest>;
|
||||
NullReferenceCheckHelper.throwIfNull(query_batch, () => $"query_batch is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var query_runner_with_item_request = query_batch.getQueryRunner();
|
||||
NullReferenceCheckHelper.throwIfNull(query_runner_with_item_request, () => $"query_runner_with_item_request is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var db_connector = query_batch.getDynamoDbConnector();
|
||||
var target = JsonHelper.getJsonPropertyName<CaliumStorageAttrib>(nameof(CaliumStorageAttrib.DailyRollUpCheckDate));
|
||||
var update = makeUpdateItemRequest(db_connector, m_primary_key.toKeyWithAttributeValue(), target);
|
||||
if (update.result.isFail()) return update.result;
|
||||
NullReferenceCheckHelper.throwIfNull(update.updateRequest, () => $"update_request is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var exception_handler = new DynamoDbQueryExceptionNotifier.ExceptionHandler(DynamoDbQueryExceptionNotifier.ConditionalCheckFailed, ServerErrorCode.LackOfTotalCalium);
|
||||
|
||||
var query_context = update.updateRequest.createItemRequestQueryContext(QueryType.Update, exception_handler);
|
||||
var result = await query_runner_with_item_request.tryRegisterQueryContext(query_context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// DB 쿼리를 성공하고, doFnCommit()가 QueryResultType.NotCalledQueryFunc를 반환할 경우 호출된다.
|
||||
//=====================================================================================
|
||||
public override async Task onQueryResponseCommit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// DB 쿼리를 실패하고, doFnRollback()가 QueryResultType.NotCalledQueryFunc를 반환할 경우 호출된다.
|
||||
//=====================================================================================
|
||||
public override async Task onQueryResponseRollback(Result errorResult)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
private (Result result, UpdateItemRequest? updateRequest) makeUpdateItemRequest(DynamoDbClient dbClient, Dictionary<string, AttributeValue> attributeValueWithPrimaryKey, string targetAttribName)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
if (string.IsNullOrEmpty(targetAttribName))
|
||||
{
|
||||
err_msg = $"Failed to DynamoDbClientHelper.toAttributeExpressionFromJson() !!! : targetAttribName - {targetAttribName}";
|
||||
result.setFail(ServerErrorCode.AttribPathMakeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
var target_doc = new CaliumStorageDoc();
|
||||
|
||||
var query_builder = new DynamoDbItemRequestHelper.UpdateItemRequestBuilder(dbClient.getTableFullName(target_doc.TableName));
|
||||
query_builder.withKeys(attributeValueWithPrimaryKey);
|
||||
|
||||
var attrib_path_json_string = target_doc.toJsonStringOfAttribs();
|
||||
(var is_success, var attribute_expression) = DynamoDbClientHelper.toAttributeExpressionFromJson(attrib_path_json_string, targetAttribName);
|
||||
if (false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to DynamoDbClientHelper.toAttributeExpressionFromJson() !!! : attribPath:{attrib_path_json_string}, targetKey:{targetAttribName}";
|
||||
result.setFail(ServerErrorCode.AttribPathMakeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
var attribute_names = DynamoDbClientHelper.toExpressionAttributeNamesFromJson(attrib_path_json_string, targetAttribName);
|
||||
query_builder.withExpressionAttributeNames(attribute_names);
|
||||
|
||||
var update_expression = $"SET {attribute_expression} = :changeValue";
|
||||
query_builder.withUpdateExpression(update_expression);
|
||||
|
||||
var expression_attribute_values = new Dictionary<string, AttributeValue>
|
||||
{
|
||||
{ ":changeValue", new AttributeValue { S = m_sync_date.toString("yyyy-MM-ddTHH:mm:ss") } }
|
||||
};
|
||||
query_builder.withExpressionAttributeValues(expression_attribute_values);
|
||||
|
||||
query_builder.withReturnValues(ReturnValue.ALL_NEW);
|
||||
|
||||
return query_builder.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
using System.Globalization;
|
||||
|
||||
|
||||
using Amazon.DynamoDBv2;
|
||||
using Amazon.DynamoDBv2.Model;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public enum CaliumStorageType
|
||||
{
|
||||
None = 0,
|
||||
Converter = 1,
|
||||
Operator = 2
|
||||
}
|
||||
|
||||
public class DBQStorageCaliumUpdate : QueryExecutorBase
|
||||
{
|
||||
private CaliumStorageType m_storage_type { get; set; } = CaliumStorageType.None;
|
||||
private double m_delta { get; set; }
|
||||
private bool m_is_update_last_date { get; set; }
|
||||
private bool m_is_pivot { get; set; }
|
||||
|
||||
private PrimaryKey m_primary_key = new();
|
||||
|
||||
//=====================================================================================
|
||||
// 0 < deltaCount => 증가
|
||||
// 0 > deltaCount => 감소
|
||||
//=====================================================================================
|
||||
|
||||
public DBQStorageCaliumUpdate(CaliumStorageType storageType, double deltaCalium, bool isUpdateLastDate = false, bool isPivot = false) : base(nameof(DBQStorageCaliumUpdate))
|
||||
{
|
||||
m_storage_type = storageType;
|
||||
m_delta = deltaCalium;
|
||||
m_is_update_last_date = isUpdateLastDate;
|
||||
m_is_pivot = isPivot;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
|
||||
//=====================================================================================
|
||||
public override async Task<Result> onPrepareQuery()
|
||||
{
|
||||
var owner = getOwner();
|
||||
|
||||
var (result, make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<CaliumStorageDoc>(string.Empty);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - {owner.toBasicString()}");
|
||||
|
||||
m_primary_key = make_primary_key;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// onPrepareQuery()를 성공할 경우 호출된다.
|
||||
//=====================================================================================
|
||||
public override async Task<Result> onQuery()
|
||||
{
|
||||
var owner = getOwner();
|
||||
|
||||
var query_batch = getQueryBatch() as QueryBatch<QueryRunnerWithItemRequest>;
|
||||
NullReferenceCheckHelper.throwIfNull(query_batch, () => $"query_batch is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var query_runner_with_item_request = query_batch.getQueryRunner();
|
||||
NullReferenceCheckHelper.throwIfNull(query_runner_with_item_request, () => $"query_runner_with_item_request is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var db_connector = query_batch.getDynamoDbConnector();
|
||||
var update = makeUpdateItemRequestChangeConverterTotalCalium(db_connector, m_primary_key.toKeyWithAttributeValue(), convertCaliumStorageTypeToValueName());
|
||||
if (update.result.isFail()) return update.result;
|
||||
NullReferenceCheckHelper.throwIfNull(update.updateRequest, () => $"update_request is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var exception_handler = new DynamoDbQueryExceptionNotifier.ExceptionHandler(DynamoDbQueryExceptionNotifier.ConditionalCheckFailed, ServerErrorCode.LackOfTotalCalium);
|
||||
|
||||
var query_context = update.updateRequest.createItemRequestQueryContext(QueryType.Update, exception_handler);
|
||||
var result = await query_runner_with_item_request.tryRegisterQueryContext(query_context);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// DB 쿼리를 성공하고, doFnCommit()가 QueryResultType.NotCalledQueryFunc를 반환할 경우 호출된다.
|
||||
//=====================================================================================
|
||||
public override async Task onQueryResponseCommit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// DB 쿼리를 실패하고, doFnRollback()가 QueryResultType.NotCalledQueryFunc를 반환할 경우 호출된다.
|
||||
//=====================================================================================
|
||||
public override async Task onQueryResponseRollback(Result errorResult)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
return;
|
||||
}
|
||||
|
||||
private string convertCaliumStorageTypeToValueName()
|
||||
{
|
||||
return m_storage_type switch
|
||||
{
|
||||
CaliumStorageType.Converter => JsonHelper.getJsonPropertyName<CaliumConverterInfo>(nameof(CaliumConverterInfo.TotalCalium)),
|
||||
CaliumStorageType.Operator => JsonHelper.getJsonPropertyName<CaliumOperatorInfo>(nameof(CaliumOperatorInfo.TotalCalium)),
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
private (Result result, UpdateItemRequest? updateRequest) makeUpdateItemRequestChangeConverterTotalCalium( DynamoDbClient dbClient
|
||||
, Dictionary<string, AttributeValue> attributeValueWithPrimaryKey
|
||||
, string targetAttribName )
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
if (string.IsNullOrEmpty(targetAttribName))
|
||||
{
|
||||
err_msg = $"Failed to DynamoDbClientHelper.toAttributeExpressionFromJson() !!! : targetAttribName - {targetAttribName}";
|
||||
result.setFail(ServerErrorCode.AttribPathMakeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
var target_doc = new CaliumStorageDoc();
|
||||
|
||||
var query_builder = new DynamoDbItemRequestHelper.UpdateItemRequestBuilder(dbClient.getTableFullName(target_doc.TableName));
|
||||
query_builder.withKeys(attributeValueWithPrimaryKey);
|
||||
|
||||
var attrib_path_json_string = target_doc.toJsonStringOfAttribs();
|
||||
(var is_success, var attribute_expression) = DynamoDbClientHelper.toAttributeExpressionFromJson(attrib_path_json_string, targetAttribName);
|
||||
if (false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to DynamoDbClientHelper.toAttributeExpressionFromJson() !!! : attribPath:{attrib_path_json_string}, targetKey:{targetAttribName}";
|
||||
result.setFail(ServerErrorCode.AttribPathMakeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
var attribute_names = DynamoDbClientHelper.toExpressionAttributeNamesFromJson(attrib_path_json_string, targetAttribName);
|
||||
query_builder.withExpressionAttributeNames(attribute_names);
|
||||
|
||||
var update_expression = (m_delta >= 0)
|
||||
? $"SET {attribute_expression} = if_not_exists({attribute_expression}, :start) + :changeValue"
|
||||
: $"SET {attribute_expression} = if_not_exists({attribute_expression}, :start) - :changeValue";
|
||||
|
||||
query_builder.withUpdateExpression(update_expression);
|
||||
|
||||
// 차감시 조건 추가
|
||||
if (m_delta < 0)
|
||||
{
|
||||
query_builder.withConditionExpression($"{attribute_expression} >= :changeValue");
|
||||
}
|
||||
|
||||
var expression_attribute_values = new Dictionary<string, AttributeValue>
|
||||
{
|
||||
{ ":changeValue", new AttributeValue { N = Math.Abs(m_delta).ToString(CultureInfo.InvariantCulture) } },
|
||||
{ ":start", new AttributeValue { N = "0" } }
|
||||
};
|
||||
query_builder.withExpressionAttributeValues(expression_attribute_values);
|
||||
|
||||
// 마지막 업데이트 날짜 수정
|
||||
if (m_is_update_last_date)
|
||||
{
|
||||
result = updateLastDate(query_builder, attrib_path_json_string);
|
||||
if (result.isFail()) return (result, null);
|
||||
}
|
||||
|
||||
query_builder.withReturnValues(ReturnValue.ALL_NEW);
|
||||
|
||||
return query_builder.build();
|
||||
}
|
||||
|
||||
private Result updateLastDate(DynamoDbItemRequestHelper.UpdateItemRequestBuilder query_builder, string attrib_path_json_string)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var request = query_builder.getItemRequest();
|
||||
var attribute_last_date = JsonHelper.getJsonPropertyName<CaliumConverterInfo>(nameof(CaliumConverterInfo.LastFillUpDate));
|
||||
|
||||
// 1. add attribute names
|
||||
var attribute_last_date_names = DynamoDbClientHelper.toExpressionAttributeNamesFromJson(attrib_path_json_string, attribute_last_date);
|
||||
foreach (var name in attribute_last_date_names.Where(name => !request.ExpressionAttributeNames.ContainsKey(name.Key)))
|
||||
{
|
||||
request.ExpressionAttributeNames.Add(name.Key, name.Value);
|
||||
}
|
||||
|
||||
// 2. add attribute expression
|
||||
var (is_success, last_date_expression) = DynamoDbClientHelper.toAttributeExpressionFromJson(attrib_path_json_string, attribute_last_date);
|
||||
if (false == is_success)
|
||||
{
|
||||
var err_msg = $"Failed to DynamoDbClientHelper.toAttributeExpressionFromJson() !!! : attribPath:{attrib_path_json_string}, targetKey:{attribute_last_date}";
|
||||
result.setFail(ServerErrorCode.AttribPathMakeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
request.UpdateExpression += ", ";
|
||||
request.UpdateExpression += $"{last_date_expression} = :lastDateValue";
|
||||
|
||||
// 3. add values
|
||||
request.ExpressionAttributeValues.Add(":lastDateValue", new AttributeValue { S = DateTimeHelper.Current.toString("yyyy-MM-ddTHH:mm:ss")});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class ReqCreateCaliumContentStorageHandler
|
||||
{
|
||||
public async Task<Result> createCaliumContentStorage(string contentId, double calium)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var calium_storage_entity = server_logic.findGlobalEntity<CaliumStorageEntity>();
|
||||
NullReferenceCheckHelper.throwIfNull(calium_storage_entity, () => "calium_storage_entity is null !!!");
|
||||
|
||||
// 1. contentId 검사
|
||||
// Todo(sangyeob.kim) : calium content Id 를 위한 xlxs 등록되면 추가한다.
|
||||
|
||||
// 2. calium content storage 생성
|
||||
var result = await calium_storage_entity.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "CreateCaliumContentStorage", createCaliumContentStorageDelegate);
|
||||
if (result.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {calium_storage_entity.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
async Task<Result> createCaliumContentStorageDelegate() => await createCaliumContentStorage(calium_storage_entity, contentId, calium);
|
||||
}
|
||||
|
||||
private async Task<Result> createCaliumContentStorage(CaliumStorageEntity caliumStorageEntity, string contentId, double calium)
|
||||
{
|
||||
var dynamoDb_client = GameServerApp.getServerLogic().getDynamoDbClient();
|
||||
NullReferenceCheckHelper.throwIfNull(dynamoDb_client, () => $"dynamoDb_client is null !!! - {caliumStorageEntity.toBasicString()}");
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithItemRequest>(caliumStorageEntity, LogActionType.CreateCaliumContent, dynamoDb_client, true);
|
||||
batch.addQuery(new DBQStorageCaliumUpdate(CaliumStorageType.Operator, -1 * calium));
|
||||
batch.addQuery(new DBQContentCaliumCreate(contentId, calium));
|
||||
|
||||
var result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
297
GameServer/Entity/Character/Action/CharacterAction.cs
Normal file
297
GameServer/Entity/Character/Action/CharacterAction.cs
Normal file
@@ -0,0 +1,297 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using static ClientToGameMessage.Types;
|
||||
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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;
|
||||
using ANCHOR_META_GUID = System.String;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class CharacterAction : EntityActionBase
|
||||
{
|
||||
public CharacterAction(Character owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public void setStateInfo(EntityStateType stateType, ANCHOR_META_GUID anchorMetaGuid, META_ID metaId)
|
||||
{
|
||||
var owner = getOwner();
|
||||
|
||||
var character_attribute = owner.getEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute, () => $"character_attribute is null !!!");
|
||||
|
||||
character_attribute.StateInfo.StateType = stateType;
|
||||
character_attribute.StateInfo.MetaIdOfStateType = (Int32)metaId;
|
||||
character_attribute.StateInfo.AnchorMetaGuid = anchorMetaGuid;
|
||||
}
|
||||
|
||||
public async Task<Result> tryUpdateApperanceProfile(AvatarInfo? avatarInfo, ClothInfo? clothInfo)
|
||||
{
|
||||
var character = getOwner() as Character;
|
||||
NullReferenceCheckHelper.throwIfNull(character, () => $"character is null !!!");
|
||||
|
||||
var player = character.getRootParent() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var user_create_or_load_action = player.getEntityAction<UserCreateOrLoadAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_create_or_load_action, () => $"user_create_or_load_action is null !!!");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (null == avatarInfo)
|
||||
{
|
||||
err_msg = $"AvatarInfo is null !!! - {character.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.FunctionParamNull, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if(true == isCompletedApprearance())
|
||||
{
|
||||
var character_attribute = character.getEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute, () => $"character_attribute is null !!!");
|
||||
var appearance_profile = character_attribute.AppearanceProfileValue;
|
||||
NullReferenceCheckHelper.throwIfNull(appearance_profile, () => $"appearance_profile is null !!!");
|
||||
|
||||
err_msg = $"Already Customizing Completed !!! : currCustomizing:{appearance_profile.CustomValues} - {character.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.CharacterCustomizingAlreadyCompleted, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 1. 캐릭터 외형 정보를 갱신 한다.
|
||||
updateAppearanceProfile(avatarInfo);
|
||||
|
||||
var item_cloth_action = player.getEntityAction<ItemClothAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(item_cloth_action, () => $"server_logic is null !!!");
|
||||
|
||||
// 2. 테스트 유저가 아닌 경우 캐릭터 의상 정보를 갱신 한다.
|
||||
if (user_create_or_load_action.isTestUser() == false)
|
||||
{
|
||||
result = await item_cloth_action.tryApplyClothsByMetaId(clothInfo);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryApplyClothsByMetaId() !!! : {result.toBasicString()} - {character.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {player.toBasicString()}");
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>( player, LogActionType.CharacterAppearanceUpdate
|
||||
, server_logic.getDynamoDbClient()
|
||||
, true);
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
batch.addQuery(new QueryFinal(), async (_query) =>
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var query_batch = _query.getQueryBatch();
|
||||
NullReferenceCheckHelper.throwIfNull(query_batch, () => $"query_batch is null !!! - {player.toBasicString()}");
|
||||
var log_action = query_batch.getLogAction();
|
||||
NullReferenceCheckHelper.throwIfNull(log_action, () => $"log_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var character_attribute = character.getEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute, () => $"character_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
var character_log_info = new CharacterLogInfo();
|
||||
|
||||
(var result, var update_character_log_info) = await character_attribute.toCharacterLogInfo();
|
||||
NullReferenceCheckHelper.throwIfNull(update_character_log_info, () => $"update_character_log_info is null !!!");
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to toCharacterLogInfo() !!! : {result.toBasicString()} - {toBasicString()}, {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
character_log_info.setInfo(update_character_log_info);
|
||||
|
||||
// 비즈니스 로그 추가
|
||||
query_batch.appendBusinessLog(new CharacterBusinessLog(log_action, character_log_info));
|
||||
}
|
||||
|
||||
return QueryBatchBase.QueryResultType.Success;
|
||||
});
|
||||
}
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void updateAppearanceProfile(AvatarInfo avatarInfo)
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"server_logic is null !!!");
|
||||
|
||||
if (null == avatarInfo)
|
||||
{
|
||||
var err_msg = $"AvatarInfo is null !!! - {owner.toBasicString()}";
|
||||
Log.getLogger().info(err_msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var character = owner as Character;
|
||||
NullReferenceCheckHelper.throwIfNull(character, () => $"character is null !!!");
|
||||
var character_attribute = character.getEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute, () => $"character_attribute is null !!!");
|
||||
var appearance_profile = character_attribute.AppearanceProfileValue;
|
||||
NullReferenceCheckHelper.throwIfNull(appearance_profile, () => $"appearance_profile is null !!!");
|
||||
|
||||
if (null == avatarInfo.AppearCustomize)
|
||||
{
|
||||
var err_msg = $"avatarInfo.AppearCustomize is null !!! - {owner.toBasicString()}";
|
||||
Log.getLogger().info(err_msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var appearance_customize = avatarInfo.AppearCustomize;
|
||||
|
||||
appearance_profile.BasicStyle = (UInt32)appearance_customize.BasicStyle;
|
||||
appearance_profile.BodyShape = (UInt32)appearance_customize.BodyShape;
|
||||
appearance_profile.HairStyle = (UInt32)appearance_customize.HairStyle;
|
||||
appearance_profile.CustomValues = appearance_customize.CustomValues.Select(x => x).ToList();
|
||||
appearance_profile.IsCustomCompleted = true;
|
||||
|
||||
character_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
|
||||
public bool isCompletedApprearance()
|
||||
{
|
||||
var character = getOwner() as Character;
|
||||
NullReferenceCheckHelper.throwIfNull(character, () => $"character is null !!!");
|
||||
|
||||
var character_attribute = character.getEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute, () => $"character_attribute is null !!!");
|
||||
|
||||
var appearance_profile = character_attribute.AppearanceProfileValue;
|
||||
NullReferenceCheckHelper.throwIfNull(appearance_profile, () => $"appearance_profile is null !!!");
|
||||
|
||||
return appearance_profile.IsCustomCompleted;
|
||||
}
|
||||
|
||||
public void broadcastCharacterInfo()
|
||||
{
|
||||
var character = getOwner() as Character;
|
||||
NullReferenceCheckHelper.throwIfNull(character, () => $"appearanccharactere_profile is null !!!");
|
||||
|
||||
var player = character.getRootParent() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var game_zone_action = player.getEntityAction<GameZoneAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!!");
|
||||
|
||||
|
||||
var curr_join_map = game_zone_action.getLinkedToMap();
|
||||
if (null == curr_join_map)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ClientToGame to_client_msg = new();
|
||||
to_client_msg.Message = new();
|
||||
|
||||
// GS2C_NTF_PLAYER_MODIFY, 본 코드가 C/S 연동 테스트 확인 되면 ClientToGameMessage.Types.ActorModify 패킷 및 코드는 제거 해야 한다. - kangms
|
||||
to_client_msg.Message.NtfPlayerModify = new GS2C_NTF_PLAYER_MODIFY();
|
||||
|
||||
var character_attribute = character.getEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute, () => $"character_attribute is null !!!");
|
||||
|
||||
var inventory_action = player.getEntityAction<InventoryActionBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!!");
|
||||
|
||||
to_client_msg.Message.NtfPlayerModify.ToModifyPlayerGuid = player.getUserGuid(); // 클라이언트는 USER_GUID를 사용 한다.
|
||||
to_client_msg.Message.NtfPlayerModify.AvatarInfo = character_attribute.AppearanceProfileValue.toCharacterAppearanceProfile4Client();
|
||||
var cloth_info = inventory_action.toClothInven4Client();
|
||||
NullReferenceCheckHelper.throwIfNull(cloth_info, () => $"cloth_info is null !!!");
|
||||
|
||||
to_client_msg.Message.NtfPlayerModify.ClothInfo = cloth_info.toClothInfoOfAnotherUser();
|
||||
to_client_msg.Message.NtfPlayerModify.EntityStateInfo = character_attribute.StateInfo;
|
||||
|
||||
curr_join_map.Broadcast(player, to_client_msg);
|
||||
}
|
||||
|
||||
public void CheatResetCompletedApprearance()
|
||||
{
|
||||
var character = getOwner() as Character;
|
||||
NullReferenceCheckHelper.throwIfNull(character, () => $"character is null !!!");
|
||||
|
||||
var character_attribute = character.getEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute, () => $"character_attribute is null !!!");
|
||||
|
||||
var appearance_profile = character_attribute.AppearanceProfileValue;
|
||||
NullReferenceCheckHelper.throwIfNull(appearance_profile, () => $"appearance_profile is null !!!");
|
||||
|
||||
appearance_profile.IsCustomCompleted = false;
|
||||
character_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
|
||||
public bool isFarming()
|
||||
{
|
||||
var character = getOwner() as Character;
|
||||
NullReferenceCheckHelper.throwIfNull(character, () => $"character is null !!!");
|
||||
|
||||
var character_attribute = character.getEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute, () => $"character_attribute is null !!!");
|
||||
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if(EntityStateType.UsingByFarming == character_attribute.StateInfo.StateType)
|
||||
{
|
||||
err_msg = $"Character state is Farming !!! : currState:{character_attribute.StateInfo.StateType} - {character.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
84
GameServer/Entity/Character/Character.cs
Normal file
84
GameServer/Entity/Character/Character.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 GameServer
|
||||
{
|
||||
public class Character : EntityBase
|
||||
{
|
||||
public Character(Player parent)
|
||||
: base(EntityType.Character, parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var direct_parent = getDirectParent();
|
||||
NullReferenceCheckHelper.throwIfNull(direct_parent, () => $"direct_parent is null !!!");
|
||||
|
||||
addEntityAttribute(new CharacterAttribute(this, direct_parent));
|
||||
|
||||
addEntityAction(new CharacterAction(this));
|
||||
|
||||
addEntityAction(new CharacterAppearanceCustomizeAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public async Task<Result> createByCharacterBaseDoc(CharacterBaseDoc characterBaseDoc)
|
||||
{
|
||||
var err_msg = string.Empty;
|
||||
var result = new Result();
|
||||
|
||||
var character_attribute = getEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute, () => $"character_attribute is null !!!");
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromDocs(character_attribute, new List<DynamoDbDocBase>() { characterBaseDoc });
|
||||
if( result.isFail() )
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDocs() !!!, to:{character_attribute.getTypeName()}, from:{this.getTypeName()} - {toBasicString()}, {getRootParent().toBasicString()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public CharacterAttribute.AppearanceProfile getOriginAppearanceProfile()
|
||||
{
|
||||
var character_attribute = getOriginEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute, () => $"character_attribute is null !!!");
|
||||
|
||||
return character_attribute.AppearanceProfileValue;
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using Google.Protobuf.Collections;
|
||||
using Nettention.Proud;
|
||||
using Amazon.Runtime.Internal;
|
||||
using Amazon.Runtime.Internal.Endpoints.StandardLibrary;
|
||||
|
||||
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
|
||||
using GameServer.PacketHandler;
|
||||
using Microsoft.AspNetCore.DataProtection.KeyManagement;
|
||||
using static Pipelines.Sockets.Unofficial.SocketConnection;
|
||||
|
||||
|
||||
using UI_KEY = System.String;
|
||||
using MongoDB.Bson;
|
||||
using Amazon.S3.Model;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class CustomDefinedUiAction : EntityActionBase
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, CustomDefinedUi> m_custom_defined_uis = new();
|
||||
|
||||
public CustomDefinedUiAction(EntityBase owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> tryLoadCustomDefinedUiFromDoc(CustomDefinedUiDoc toLoadCustomDefinedUiDoc)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var owner = getOwner();
|
||||
var root_parent = owner.getRootParent();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var to_load_custom_defined_ui_attrib = toLoadCustomDefinedUiDoc.getAttrib<CustomDefinedUiAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_load_custom_defined_ui_attrib, () => $"to_load_custom_defined_ui_attrib is null !!! - {owner.toBasicString()}, {root_parent.toBasicString()}");
|
||||
|
||||
var ui_key = to_load_custom_defined_ui_attrib.UiKey;
|
||||
var ui_value = to_load_custom_defined_ui_attrib.CustomDefinedUi;
|
||||
|
||||
result = await tryUpdateCustomDefinedUi(ui_key, ui_value, false);
|
||||
if(result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> tryUpdateCustomDefinedUi(UI_KEY uiKey, string customDefinedUi, bool isApplyToDb = true)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var owner = getOwner();
|
||||
var root_parent = owner.getRootParent();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var item_string = uiKey + customDefinedUi;
|
||||
result = await checkCustomDefinedUiSize(item_string);
|
||||
if(result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var add_custom_defined_ui = delegate (string uiKey)
|
||||
{
|
||||
var custom_defined_ui = new CustomDefinedUi(owner);
|
||||
result = custom_defined_ui.onInit().GetAwaiter().GetResult();
|
||||
if(result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to CustomDefinedUi.onInit() !!!, CustomDefinedUIAction.updateCustomDefinedUi() - {owner.toBasicString()}, {root_parent.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return null;
|
||||
}
|
||||
|
||||
var custom_defined_attribute = custom_defined_ui.getEntityAttribute<CustomDefinedUiAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(custom_defined_attribute, () => $"custom_defined_attribute is null !!! - {owner.toBasicString()}, {root_parent.toBasicString()}");
|
||||
|
||||
custom_defined_attribute.UiKey = uiKey;
|
||||
custom_defined_attribute.CustomDefinedUi = customDefinedUi;
|
||||
|
||||
if(true == isApplyToDb)
|
||||
{
|
||||
custom_defined_attribute.newEntityAttribute();
|
||||
}
|
||||
|
||||
return custom_defined_ui;
|
||||
};
|
||||
|
||||
var update_custom_defined_ui = delegate (string uiKey, CustomDefinedUi currCustomDefinedUi)
|
||||
{
|
||||
var custom_defined_ui_attribute = currCustomDefinedUi.getEntityAttribute<CustomDefinedUiAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(custom_defined_ui_attribute, () => $"custom_defined_ui_attribute is null !!! - {owner.toBasicString()}, {root_parent.toBasicString()}");
|
||||
|
||||
custom_defined_ui_attribute.UiKey = uiKey;
|
||||
custom_defined_ui_attribute.CustomDefinedUi = customDefinedUi;
|
||||
|
||||
if (true == isApplyToDb)
|
||||
{
|
||||
custom_defined_ui_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
|
||||
return currCustomDefinedUi;
|
||||
};
|
||||
|
||||
m_custom_defined_uis.AddOrUpdate(uiKey, add_custom_defined_ui, update_custom_defined_ui);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void removeCustomDefinedUi(UI_KEY uiKey)
|
||||
{
|
||||
var owner = getOwner();
|
||||
var root_parent = owner.getRootParent();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (false == m_custom_defined_uis.TryRemove(uiKey, out _))
|
||||
{
|
||||
err_msg = $"Failed to Remove() !!!, not found UIKey : UIKey:{uiKey} - {owner.toBasicString()}, {root_parent.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
public bool findCustomDefinedUi(UI_KEY uiKey, [MaybeNullWhen(false)] out CustomDefinedUi customDefinedUi)
|
||||
{
|
||||
return m_custom_defined_uis.TryGetValue(uiKey, out customDefinedUi);
|
||||
}
|
||||
|
||||
public bool getTattooVisible(TattooSlotType slotType, out bool foundVisible)
|
||||
{
|
||||
var owner = getOwner();
|
||||
var root_parent = owner.getRootParent();
|
||||
|
||||
var err_msg = string.Empty;
|
||||
|
||||
foundVisible = false;
|
||||
|
||||
var ui_key = slotType.convertEnumToEnumTypeAndValueString();
|
||||
|
||||
if (false == m_custom_defined_uis.TryGetValue(ui_key, out var found_custom_defined_ui))
|
||||
{
|
||||
err_msg = $"Failed to TryGetValue() !!!, CustomDefinedUIAction.getTattooVisible() : uiKey:{ui_key} - {owner.toBasicString()}, {root_parent.toBasicString()}";
|
||||
Log.getLogger().info(err_msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var custom_defined_ui_attribute = found_custom_defined_ui.getEntityAttribute<CustomDefinedUiAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(custom_defined_ui_attribute, () => $"custom_defined_ui_attribute is null !!! - uiKey:{ui_key}, {owner.toBasicString()}, {root_parent.toBasicString()}");
|
||||
|
||||
if(false == custom_defined_ui_attribute.CustomDefinedUi.toBool(out var is_visible))
|
||||
{
|
||||
err_msg = $"Failed to toBool() !!!, CustomDefinedUIAction.getTattooVisible() - uiKey:{ui_key}, {owner.toBasicString()}, {root_parent.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
foundVisible = is_visible;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<Result> setTattooVisible(TattooSlotType slotType, bool foundVisible)
|
||||
{
|
||||
var owner = getOwner();
|
||||
var root_parent = owner.getRootParent();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var ui_key = slotType.convertEnumToEnumTypeAndValueString();
|
||||
var item_string = ui_key + foundVisible.ToString();
|
||||
result = await checkCustomDefinedUiSize(item_string);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var add_custom_defined_ui = delegate (string uiKey)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var custom_defined_ui = new CustomDefinedUi(owner);
|
||||
result = custom_defined_ui.onInit().GetAwaiter().GetResult();
|
||||
if(result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to CustomDefinedUi.onInit() !!!, CustomDefinedUIAction.setTattooVisible() - {owner.toBasicString()}, {root_parent.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return null;
|
||||
}
|
||||
var custom_defined_ui_attribute = custom_defined_ui.getEntityAttribute<CustomDefinedUiAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(custom_defined_ui_attribute, () => $"custom_defined_ui_attribute is null !!! - {owner.toBasicString()}, {root_parent.toBasicString()}");
|
||||
|
||||
custom_defined_ui_attribute.UiKey = uiKey;
|
||||
custom_defined_ui_attribute.CustomDefinedUi = foundVisible.ToString();
|
||||
|
||||
custom_defined_ui_attribute.newEntityAttribute();
|
||||
|
||||
return custom_defined_ui;
|
||||
};
|
||||
|
||||
var update_custom_defined_ui = delegate (string uiKey, CustomDefinedUi currValue)
|
||||
{
|
||||
var custom_defined_ui_attribute = currValue.getEntityAttribute<CustomDefinedUiAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(custom_defined_ui_attribute, () => $"custom_defined_ui_attribute is null !!! - {owner.toBasicString()}, {root_parent.toBasicString()}");
|
||||
|
||||
custom_defined_ui_attribute.UiKey = uiKey;
|
||||
custom_defined_ui_attribute.CustomDefinedUi = foundVisible.ToString();
|
||||
|
||||
custom_defined_ui_attribute.modifiedEntityAttribute();
|
||||
|
||||
return currValue;
|
||||
};
|
||||
|
||||
m_custom_defined_uis.AddOrUpdate(ui_key, add_custom_defined_ui, update_custom_defined_ui);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> checkCustomDefinedUiSize(string itemString)
|
||||
{
|
||||
var owner = getOwner();
|
||||
var root_parent = owner.getRootParent();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var to_save_data = itemString + CustomDefinedUiDoc.getPrefixOfPK() + CustomDefinedUiDoc.getPrefixOfSK();
|
||||
|
||||
if (false == DynamoDbConnectorBase.checkItemSizeLimit(to_save_data))
|
||||
{
|
||||
err_msg = $"Failed to DynamoDbConnectorBase.checkItemSizeLimit() !!! - {owner.toBasicString()}, {root_parent.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbItemSizeExceeded, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public MapField<UI_KEY, string> toCustomDefinedUiAll()
|
||||
{
|
||||
var map_field = new MapField<UI_KEY, string>();
|
||||
|
||||
foreach (var each in m_custom_defined_uis)
|
||||
{
|
||||
var custom_defined_ui_attribute = each.Value.getEntityAttribute<CustomDefinedUiAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(custom_defined_ui_attribute, () => $"custom_defined_ui_attribute is null !!!");
|
||||
|
||||
var ui_key = each.Key;
|
||||
var ui_value = custom_defined_ui_attribute.CustomDefinedUi;
|
||||
|
||||
map_field.Add(each.Key, ui_value);
|
||||
}
|
||||
|
||||
return map_field;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
GameServer/Entity/CustomDefinedUi/CustomDefinedUi.cs
Normal file
48
GameServer/Entity/CustomDefinedUi/CustomDefinedUi.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class CustomDefinedUi : EntityBase
|
||||
{
|
||||
public CustomDefinedUi(EntityBase parent)
|
||||
: base(EntityType.CustomDefinedUi, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var parent = getDirectParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
|
||||
|
||||
addEntityAttribute(new CustomDefinedUiAttribute(this, parent));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
var custom_defined_ui_attribute = getOriginEntityAttribute<CustomDefinedUiAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(custom_defined_ui_attribute, () => $"custom_defined_ui_attribute is null !!!");
|
||||
|
||||
return $"{this.getTypeName()}, UIKey:{custom_defined_ui_attribute.UiKey}, UILength:{custom_defined_ui_attribute.CustomDefinedUi.Length}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
var custom_defined_ui_attribute = getOriginEntityAttribute<CustomDefinedUiAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(custom_defined_ui_attribute, () => $"custom_defined_ui_attribute is null !!!");
|
||||
|
||||
return $"{this.getTypeName()}, {custom_defined_ui_attribute.toBasicString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
1069
GameServer/Entity/Effect/Farming/Action/FarmingEffectAction.cs
Normal file
1069
GameServer/Entity/Effect/Farming/Action/FarmingEffectAction.cs
Normal file
File diff suppressed because it is too large
Load Diff
150
GameServer/Entity/Effect/Farming/FarmingEffect.cs
Normal file
150
GameServer/Entity/Effect/Farming/FarmingEffect.cs
Normal file
@@ -0,0 +1,150 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using static ClientToGameReq.Types;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 MASTER_GUID = System.String;
|
||||
using CHARACTER_GUID = System.String;
|
||||
using ITEM_GUID = System.String;
|
||||
using ENTITY_UNIQUE_ID = System.String;
|
||||
using ANCHOR_META_GUID = System.String;
|
||||
using NPC_UNIQUE_ID = System.String;
|
||||
using FARMING_ENTITY_GUID = System.String;
|
||||
using LOCATION_UNIQUE_ID = System.String;
|
||||
using GUARD_KEY = System.String;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class FarmingEffect : EntityBase
|
||||
{
|
||||
private Map m_curr_map;
|
||||
|
||||
private AtomicString m_guard_key_nullable = new();
|
||||
private AtomicBool m_guard_bool = new(false);
|
||||
|
||||
public FarmingEffect( EntityBase parent, Map currMap)
|
||||
: base(EntityType.Farming, parent)
|
||||
{
|
||||
m_curr_map = currMap;
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var direct_parent = getDirectParent();
|
||||
NullReferenceCheckHelper.throwIfNull(direct_parent, () => $"direct_parent is null !!!");
|
||||
|
||||
addEntityAttribute(new FarmingEffectAttribute(this, direct_parent));
|
||||
addEntityAttribute(new FarmingEffectLocationInTargetAttribute(this));
|
||||
addEntityAttribute(new FarmingEffectOwnerAttribute(this));
|
||||
|
||||
addEntityAction(new FarmingEffectAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override EntityBase? onGetMasterEntity()
|
||||
{
|
||||
if (false == hasMasterGuid())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var master_guid = getMasterGuid();
|
||||
|
||||
var server_logc = GameServerApp.getServerLogic();
|
||||
var player_manager = server_logc.getPlayerManager();
|
||||
|
||||
if (false == player_manager.tryGetUserByPrimaryKey(master_guid, out var found_player))
|
||||
{
|
||||
// 별도 Task로 처리해주는 처리자가 있다면 해당 처리자를 반환 한다. !!! - kangms
|
||||
|
||||
err_msg = $"Failed to player_manager.tryGetUserByPrimaryKey() !!!, Not found MasterEntity : MasterGuid:{master_guid} - {toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return found_player;
|
||||
}
|
||||
|
||||
public override OWNER_GUID onGetGuidOfOwnerEntityType()
|
||||
{
|
||||
var farming_effect_attribute = getEntityAttributeWithReadOnly<FarmingEffectAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(farming_effect_attribute, () => $"farming_effect_attribute is null !!! - {toBasicStringWithMaster()}");
|
||||
|
||||
return farming_effect_attribute.FarmingEntityGuid;
|
||||
}
|
||||
|
||||
public override OwnerEntityType onGetOwnerEntityType()
|
||||
{
|
||||
var farming_effect_attribute = getEntityAttributeWithReadOnly<FarmingEffectAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(farming_effect_attribute, () => $"farming_effect_attribute is null !!! - {toBasicStringWithMaster()}");
|
||||
|
||||
if(FarmingSummonedEntityType.User == farming_effect_attribute.FarmingSummonedEntityType)
|
||||
{
|
||||
return OwnerEntityType.User;
|
||||
}
|
||||
else if (FarmingSummonedEntityType.Beacon == farming_effect_attribute.FarmingSummonedEntityType)
|
||||
{
|
||||
return OwnerEntityType.UgcNpc;
|
||||
}
|
||||
|
||||
return OwnerEntityType.None;
|
||||
}
|
||||
|
||||
public ANCHOR_META_GUID getAnchorMetaGuid()
|
||||
{
|
||||
var farming_effect_attribute = getEntityAttributeWithReadOnly<FarmingEffectAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(farming_effect_attribute, () => $"farming_effect_attribute is null !!! - {toBasicStringWithMaster()}");
|
||||
|
||||
return farming_effect_attribute.AnchorMetaGuid;
|
||||
}
|
||||
|
||||
public Map getCurrMap() => m_curr_map;
|
||||
|
||||
public FarmingSummary toFarmingSummary()
|
||||
{
|
||||
var farming_effect_attribute = getEntityAttributeWithReadOnly<FarmingEffectAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(farming_effect_attribute, () => $"farming_effect_attribute is null !!! - {toBasicString()}");
|
||||
|
||||
var farming_effect_action = getEntityAction<FarmingEffectAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(farming_effect_action, () => $"farming_effect_action is null !!! - {toBasicString()}");
|
||||
|
||||
var farming_anchor_info = farming_effect_action.getAnchorInfo();
|
||||
var farming_anchor_prop = farming_anchor_info.AnchorProp;
|
||||
|
||||
var farming_summary = new FarmingSummary();
|
||||
farming_summary.FarmingAnchorMetaId = farming_effect_attribute.AnchorMetaGuid;
|
||||
farming_summary.FarmingPropMetaId = farming_anchor_prop.TableId;
|
||||
farming_summary.FarmingUserGuid = farming_effect_attribute.OwnerGuid;
|
||||
|
||||
farming_summary.FarmingSummonType = farming_effect_attribute.FarmingSummonedEntityType;
|
||||
farming_summary.FarmingEntityGuid = farming_effect_attribute.FarmingEntityGuid;
|
||||
|
||||
farming_summary.FarmingState = farming_effect_attribute.FarmingState;
|
||||
farming_summary.StartTime = farming_effect_attribute.FarmingStartTime.ToTimestamp();
|
||||
farming_summary.EndTime = farming_effect_attribute.FarmingEndTime.ToTimestamp();
|
||||
|
||||
return farming_summary;
|
||||
}
|
||||
}
|
||||
42
GameServer/Entity/EntityGetSet.cs
Normal file
42
GameServer/Entity/EntityGetSet.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 GameServer;
|
||||
|
||||
public partial class Player : UserBase, IEntityWithSession, IMergeWithInventory, IInitNotifyPacket
|
||||
{
|
||||
public string getOtpForServerConnect()
|
||||
{
|
||||
var account_attribute = getOriginEntityAttribute<AccountAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(account_attribute, () => $"account_attribute is null !!!");
|
||||
|
||||
return account_attribute.OtpForServerConnect;
|
||||
}
|
||||
|
||||
public LanguageType getLanguageType()
|
||||
{
|
||||
var account_attribute = getOriginEntityAttribute<AccountAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(account_attribute, () => $"account_attribute is null !!!");
|
||||
|
||||
return account_attribute.LanguageType;
|
||||
}
|
||||
}
|
||||
251
GameServer/Entity/Helper/NpcHelper.cs
Normal file
251
GameServer/Entity/Helper/NpcHelper.cs
Normal file
@@ -0,0 +1,251 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
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 NPC_UNIQUE_ID = System.String;
|
||||
using UGC_NPC_META_GUID = System.String;
|
||||
using ITEM_GUID = System.String;
|
||||
using ENTITY_INSTANCE_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public static class NpcHelper
|
||||
{
|
||||
public static async Task<(Result, EntityBase?, EntityBase?)> findNpc(EntityType targetNpcType, NPC_UNIQUE_ID npcUniqueId, USER_GUID ownerGuid)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
switch(targetNpcType)
|
||||
{
|
||||
case EntityType.UgcNpc:
|
||||
case EntityType.Beacon:
|
||||
(result, var found_ugc_npc, var found_master) = await findUgcNpc(npcUniqueId, ownerGuid);
|
||||
if(result.isSuccess())
|
||||
{
|
||||
return (result, found_ugc_npc, found_master);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
err_msg = $"Invalid EntityType of Npc !!! : targetNpcType:{targetNpcType}, npcUniqueId:{npcUniqueId}, ownerGuid:{ownerGuid}";
|
||||
result.setFail(ServerErrorCode.EntityTypeInvalid, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
break;
|
||||
}
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
public static async Task<(Result, UgcNpc?, Player?)> findUgcNpc(NPC_UNIQUE_ID npcUniqueId, USER_GUID ownerGuid)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! : npcUniqueId:{npcUniqueId}, ownerGuid:{ownerGuid}");
|
||||
var player_manager = server_logic.getPlayerManager();
|
||||
NullReferenceCheckHelper.throwIfNull(player_manager, () => $"player_manager is null !!! : npcUniqueId:{npcUniqueId}, ownerGuid:{ownerGuid}");
|
||||
|
||||
UgcNpc? found_ugc_npc = null;
|
||||
|
||||
// 플레이어가 접속 상태인지 조회 한다. !!!
|
||||
if(true == player_manager.tryGetUserByPrimaryKey(ownerGuid, out var found_player))
|
||||
{
|
||||
var player_action = found_player.getEntityAction<PlayerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! : npcUniqueId:{npcUniqueId}, ownerGuid:{ownerGuid}");
|
||||
|
||||
found_ugc_npc = player_action.findUgcNpc(npcUniqueId);
|
||||
|
||||
return (result, found_ugc_npc, found_player);
|
||||
}
|
||||
|
||||
if(null == found_ugc_npc)
|
||||
{
|
||||
// 채널 및 던전에 있는지 조회 한다. !!!
|
||||
found_ugc_npc = server_logic.findUgcNpcInGameZone(npcUniqueId);
|
||||
if(null != found_ugc_npc)
|
||||
{
|
||||
return (result, found_ugc_npc, found_player);
|
||||
}
|
||||
}
|
||||
|
||||
err_msg = $"Not found UgcNpc !!! : npcUniqueId:{npcUniqueId}, ownerGuid:{ownerGuid}";
|
||||
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return await Task.FromResult<(Result, UgcNpc?, Player?)>((result, null, null));
|
||||
}
|
||||
|
||||
public static UgcNpc? findUgcNpcInGameZone(this GameServerLogic gameServerLogic, UGC_NPC_META_GUID ugcNpcMetaGuid)
|
||||
{
|
||||
if(gameServerLogic.getServerType().toServerType() == ServerType.Channel)
|
||||
{
|
||||
return gameServerLogic.getMap().findUgcNpc(ugcNpcMetaGuid);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(var each in InstanceRoomManager.Instance.getInstanceRooms())
|
||||
{
|
||||
var room_key = each.Key;
|
||||
var instance_room = each.Value;
|
||||
|
||||
var found_ugc_npc = instance_room.getMap().findUgcNpc(ugcNpcMetaGuid);
|
||||
if(null != found_ugc_npc)
|
||||
{
|
||||
return found_ugc_npc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<(Result, EntityBase?)> findInstanceNpc(EntityType targetNpcType, ENTITY_INSTANCE_GUID entityInstanceGuid)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
switch (targetNpcType)
|
||||
{
|
||||
case EntityType.UgcNpc:
|
||||
case EntityType.Beacon:
|
||||
(result, var found_ugc_npc) = await findInstanceUgcNpc(entityInstanceGuid);
|
||||
if (result.isSuccess())
|
||||
{
|
||||
return (result, found_ugc_npc);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
err_msg = $"Invalid EntityType of Npc !!! : targetNpcType:{targetNpcType}, entityInstanceGuid:{entityInstanceGuid}";
|
||||
result.setFail(ServerErrorCode.EntityTypeInvalid, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
break;
|
||||
}
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
public static async Task<(Result, UgcNpc?)> findInstanceUgcNpc(ENTITY_INSTANCE_GUID entityInstanceGuid)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! : entityInstanceGuid:{entityInstanceGuid}");
|
||||
var player_manager = server_logic.getPlayerManager();
|
||||
NullReferenceCheckHelper.throwIfNull(player_manager, () => $"player_manager is null !!! : entityInstanceGuid:{entityInstanceGuid}");
|
||||
|
||||
UgcNpc? found_ugc_npc = null;
|
||||
|
||||
// 채널 및 던전에 있는지 조회 한다. !!!
|
||||
found_ugc_npc = server_logic.findUgcNpcInGameZone(entityInstanceGuid);
|
||||
if (null != found_ugc_npc)
|
||||
{
|
||||
return (result, found_ugc_npc);
|
||||
}
|
||||
|
||||
err_msg = $"Not found UgcNpc !!! : entityInstanceGuid:{entityInstanceGuid}";
|
||||
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return await Task.FromResult<(Result, UgcNpc?)>((result, null));
|
||||
}
|
||||
public static async Task notifyNpcInfo(Player player, EntityType targetNpcType, EntityBase entityNpc)
|
||||
{
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! : targetNpcType:{targetNpcType}");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(entityNpc, () => $"entityNpc is null !!! : targetNpcType:{targetNpcType} - {player.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
switch (targetNpcType)
|
||||
{
|
||||
case EntityType.UgcNpc:
|
||||
case EntityType.Beacon:
|
||||
var ugc_npc = entityNpc as UgcNpc;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!! : targetNpcType:{targetNpcType} - {player.toBasicString()}");
|
||||
|
||||
var ugc_npc_meta_guid = ugc_npc.getUgcNpcMetaGuid();
|
||||
(result, var like_count) = await UgcNpcHelper.getLikeCountOfUgcNpc(ugc_npc_meta_guid, player);
|
||||
if(result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to UgcNpcHelper.getLikeCountOfUgcNpc() !!! : {result.toBasicString()}, targetNpcType:{targetNpcType}, ugcNpc:{ugc_npc.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
(result, var dialog_count) = await UgcNpcHelper.getDialogCountOfUgcNpc(ugc_npc_meta_guid, player);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to UgcNpcHelper.getDialogCountOfUgcNpc() !!! : {result.toBasicString()}, targetNpcType:{targetNpcType}, ugcNpc:{ugc_npc.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
var ugc_npc_action = ugc_npc.getEntityAction<UgcNpcAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! : targetNpcType:{targetNpcType} - {player.toBasicString()}");
|
||||
|
||||
UgcNpcNotifyHelper.send_GS2C_NTF_BEACON_DETAIL_INFO(player, ugc_npc_action.toUgcNpcSummary(), like_count, dialog_count);
|
||||
break;
|
||||
|
||||
default:
|
||||
err_msg = $"Invalid EntityType of Npc !!! : targetNpcType:{targetNpcType}, entityNpc:{entityNpc.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.EntityTypeInvalid, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task notifyNpcInteractionInfo(Player player, EntityType targetNpcType, EntityBase entityNpc)
|
||||
{
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! : targetNpcType:{targetNpcType}");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(entityNpc, () => $"entityNpc is null !!! : targetNpcType:{targetNpcType} - {player.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
switch (targetNpcType)
|
||||
{
|
||||
case EntityType.UgcNpc:
|
||||
case EntityType.Beacon:
|
||||
var ugc_npc = entityNpc as UgcNpc;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!! : targetNpcType:{targetNpcType} - {player.toBasicString()}");
|
||||
|
||||
var ugc_npc_meta_guid = ugc_npc.getUgcNpcMetaGuid();
|
||||
(result, var is_check_like) = await UgcNpcHelper.getLikeCheckFlagOfUgcNpc(ugc_npc_meta_guid, player);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to UgcNpcHelper.getLikeCheckFlagOfUgcNpc() !!! : {result.toBasicString()}, targetNpcType:{targetNpcType}, ugcNpc:{ugc_npc.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
var ugc_npc_action = ugc_npc.getEntityAction<UgcNpcAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! : targetNpcType:{targetNpcType} - {player.toBasicString()}");
|
||||
|
||||
UgcNpcNotifyHelper.send_GS2C_NTF_BEACON_INTERACTION_INFO(player, ugc_npc, ugc_npc_action.toUgcNpcInteraction(is_check_like));
|
||||
break;
|
||||
|
||||
default:
|
||||
err_msg = $"Invalid EntityType of Npc !!! : targetNpcType:{targetNpcType}, entityNpc:{entityNpc.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.EntityTypeInvalid, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1848
GameServer/Entity/Inventory/Base/Action/InventoryActionBase.cs
Normal file
1848
GameServer/Entity/Inventory/Base/Action/InventoryActionBase.cs
Normal file
File diff suppressed because it is too large
Load Diff
1173
GameServer/Entity/Inventory/Base/BagInven.cs
Normal file
1173
GameServer/Entity/Inventory/Base/BagInven.cs
Normal file
File diff suppressed because it is too large
Load Diff
40
GameServer/Entity/Inventory/Base/ClothEquipInven.cs
Normal file
40
GameServer/Entity/Inventory/Base/ClothEquipInven.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 GameServer
|
||||
{
|
||||
|
||||
|
||||
public class ClothEquipInven : InventoryBase<ClothSlotType>
|
||||
{
|
||||
public ClothEquipInven(EntityBase parent)
|
||||
: base(EntityType.ClothEquipInven, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
40
GameServer/Entity/Inventory/Base/TattooEquipInven.cs
Normal file
40
GameServer/Entity/Inventory/Base/TattooEquipInven.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 GameServer
|
||||
{
|
||||
public class TattooEquipInven : InventoryBase<TattooSlotType>
|
||||
{
|
||||
private readonly ConcurrentDictionary<string/*TattooSlotType*/, bool> m_slot_visibles = new();
|
||||
|
||||
public TattooEquipInven(EntityBase parent)
|
||||
: base(EntityType.TattooEquipInven, parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
40
GameServer/Entity/Inventory/Base/ToolEquipInven.cs
Normal file
40
GameServer/Entity/Inventory/Base/ToolEquipInven.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class ToolEquipInven : InventoryBase<ToolSlotType>
|
||||
{
|
||||
public ToolEquipInven(EntityBase parent)
|
||||
: base(EntityType.ToolEquipInven, parent)
|
||||
{
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
internal class MyhomeInventoryAction : InventoryActionBase
|
||||
{
|
||||
public MyhomeInventoryAction(Myhome owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var owner = getOwner() as Myhome;
|
||||
ArgumentNullException.ThrowIfNull(owner, $"owner is null !!!");
|
||||
|
||||
result = await getBagInven().onInit();
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
var owner = getOwner();
|
||||
ArgumentNullException.ThrowIfNull(owner, $"owner is null !!!");
|
||||
|
||||
var bag_inven = getBagInven();
|
||||
ArgumentNullException.ThrowIfNull(bag_inven, $"bag_inven is null !!! - {owner.toBasicString()}");
|
||||
var has_items = bag_inven.getHasItemBases();
|
||||
ArgumentNullException.ThrowIfNull(has_items, $"has_items is null !!! - {owner.toBasicString()}");
|
||||
|
||||
has_items.Clear();
|
||||
}
|
||||
|
||||
public override Item onAllocItem()
|
||||
{
|
||||
var owner = getOwner() as Myhome;
|
||||
ArgumentNullException.ThrowIfNull(owner, $"owner is null !!!");
|
||||
|
||||
return new MyhomeItem(owner);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 GameServer
|
||||
{
|
||||
public class UgcNpcInventoryAction : InventoryActionBase
|
||||
{
|
||||
public UgcNpcInventoryAction(UgcNpc owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var ugc_npc = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!!");
|
||||
|
||||
var result = new Result();
|
||||
|
||||
result = await getBagInven().onInit();
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
getEquipInvens().TryAdd(InvenEquipType.Cloth, new ClothEquipInven(ugc_npc));
|
||||
getEquipInvens().TryAdd(InvenEquipType.Tattoo, new TattooEquipInven(ugc_npc));
|
||||
|
||||
var equip_inven_initializers = new Initializers();
|
||||
foreach (var each in getEquipInvens())
|
||||
{
|
||||
equip_inven_initializers.appendInitializer(each.Value as IInitializer);
|
||||
}
|
||||
result = await equip_inven_initializers.init("UgcNpc EquipInvens");
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
// 삭제할 가방 인벤토리내의 아이템 목록을 초기화 한다.
|
||||
var bag_inven = getBagInven();
|
||||
NullReferenceCheckHelper.throwIfNull(bag_inven, () => $"bag_inven is null !!! - {owner.toBasicString()}");
|
||||
|
||||
bag_inven.clearItemAll();
|
||||
// 가방 인벤토리내의 Tab별 개수 정보 초기화 한다.
|
||||
bag_inven.resetItemCountInTabs();
|
||||
|
||||
// 삭제할 장착 인벤토리내의 아이템 목록을 초기화 한다.
|
||||
var to_clear_equip_invens = new List<InvenEquipType>() {
|
||||
InvenEquipType.Cloth
|
||||
, InvenEquipType.Tattoo
|
||||
};
|
||||
foreach (var inven_equip_type in to_clear_equip_invens)
|
||||
{
|
||||
if (true == getEquipInvens().TryGetValue(inven_equip_type, out var found_equip_inven))
|
||||
{
|
||||
var tool_equip_inven = found_equip_inven as IWithInventoryAccessor;
|
||||
NullReferenceCheckHelper.throwIfNull(tool_equip_inven, () => $"tool_equip_inven is null !!! - {owner.toBasicString()}");
|
||||
|
||||
tool_equip_inven.clearItemAll();
|
||||
}
|
||||
}
|
||||
|
||||
// 능력치 속성 정보들도 초기화 한다.
|
||||
var ability_action = owner.getEntityAction<AbilityAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ability_action, () => $"ability_action is null !!! - {owner.toBasicString()}" );
|
||||
|
||||
ability_action.clearAbility();
|
||||
}
|
||||
|
||||
public override Item onAllocItem()
|
||||
{
|
||||
var ugc_npc = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!!");
|
||||
|
||||
return new UgcNpcItem(ugc_npc);
|
||||
}
|
||||
|
||||
public Dictionary<ITEM_GUID, global::Item> toItemAll4Client()
|
||||
{
|
||||
var ugc_npc = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var inventory_rule = server_logic.findRule<InventoryRule>();
|
||||
NullReferenceCheckHelper.throwIfNull(inventory_rule, () => $"inventory_rule is null !!! - {ugc_npc.toBasicString()}");
|
||||
|
||||
var bag_inven = getBagInven();
|
||||
NullReferenceCheckHelper.throwIfNull(bag_inven, () => $"bag_inven is null !!! - {ugc_npc.toBasicString()}");
|
||||
|
||||
var items = new Dictionary<ITEM_GUID, global::Item>();
|
||||
|
||||
var has_items = bag_inven.getHasItemBases();
|
||||
|
||||
foreach (var item in has_items)
|
||||
{
|
||||
var item_ui = item.toItemData4Client();
|
||||
NullReferenceCheckHelper.throwIfNull(item_ui, () => $"item_ui is null !!! - {ugc_npc.toBasicString()}");
|
||||
var item_meta = item.getItemMeta();
|
||||
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {ugc_npc.toBasicString()}");
|
||||
|
||||
if(false == items.TryAdd(item_ui.ItemGuid, item_ui))
|
||||
{
|
||||
var err_msg = $"Already added Item !!! : itemGuid:{item_ui.ItemGuid}, itemMetaId:{item_meta.ItemId} - {ugc_npc.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public Dictionary<Int32, global::TattooSlotInfo> toTattooAll4Client()
|
||||
{
|
||||
var ugc_npc = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!!");
|
||||
|
||||
var item_tattoo_action = ugc_npc.getEntityAction<ItemTattooAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(item_tattoo_action, () => $"item_tattoo_action is null !!! - {ugc_npc.toBasicString()}");
|
||||
|
||||
var tattoo_slots = new Dictionary<Int32, global::TattooSlotInfo>();
|
||||
|
||||
var inven_tattoo = getEquipInvens()[InvenEquipType.Tattoo] as TattooEquipInven;
|
||||
NullReferenceCheckHelper.throwIfNull(inven_tattoo, () => $"inven_tattoo is null !!! - {ugc_npc.toBasicString()}");
|
||||
|
||||
var custom_defined_ui_action = ugc_npc.getEntityAction<CustomDefinedUiAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(custom_defined_ui_action, () => $"custom_defined_ui_action is null !!! - {ugc_npc.toBasicString()}");
|
||||
|
||||
var tattoo_slot_types = InvenEquipType.Tattoo.toEquipableTattooSlotTypes(ugc_npc.getEntityType());
|
||||
foreach (var tattoo_slot_type in tattoo_slot_types)
|
||||
{
|
||||
var tattoo_slot = new TattooSlotInfo();
|
||||
tattoo_slot.ItemInfo = new();
|
||||
if (false == custom_defined_ui_action.getTattooVisible(tattoo_slot_type, out var found_visible))
|
||||
{
|
||||
found_visible = true;
|
||||
}
|
||||
tattoo_slot.IsVisible = found_visible == true ? 1 : 0;
|
||||
|
||||
if(false == tattoo_slots.TryAdd((Int32)tattoo_slot_type, tattoo_slot))
|
||||
{
|
||||
var err_msg = $"Already added Tattoo Item !!! : tattooSlotType:{tattoo_slot_type} - {ugc_npc.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
var found_tattoo = inven_tattoo.getData().findEntityBaseInSlotType(tattoo_slot_type) as Item;
|
||||
if (null == found_tattoo)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
item_tattoo_action.fillupTattooSlotInfo(tattoo_slot_type, found_tattoo, ref tattoo_slot);
|
||||
}
|
||||
|
||||
return tattoo_slots;
|
||||
}
|
||||
}
|
||||
}
|
||||
103
GameServer/Entity/Inventory/Owner/User/UserInventoryAction.cs
Normal file
103
GameServer/Entity/Inventory/Owner/User/UserInventoryAction.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using Amazon.S3.Model;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class UserInventoryAction : InventoryActionBase
|
||||
{
|
||||
public UserInventoryAction(Player owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
result = await getBagInven().onInit();
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
getEquipInvens().TryAdd(InvenEquipType.Tool, new ToolEquipInven(owner));
|
||||
getEquipInvens().TryAdd(InvenEquipType.Cloth, new ClothEquipInven(owner));
|
||||
getEquipInvens().TryAdd(InvenEquipType.Tattoo, new TattooEquipInven(owner));
|
||||
|
||||
var equip_inven_initializers = new Initializers();
|
||||
foreach (var each in getEquipInvens())
|
||||
{
|
||||
equip_inven_initializers.appendInitializer(each.Value as IInitializer);
|
||||
}
|
||||
result = await equip_inven_initializers.init("User EquipInvens");
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
// 삭제할 가방 인벤토리내의 아이템 목록을 초기화 한다.
|
||||
var bag_inven = getBagInven();
|
||||
NullReferenceCheckHelper.throwIfNull(bag_inven, () => $"bag_inven is null !!! - {player.toBasicString()}");
|
||||
|
||||
bag_inven.clearItemAll();
|
||||
// 가방 인벤토리내의 Tab별 개수 정보 초기화 한다.
|
||||
bag_inven.resetItemCountInTabs();
|
||||
|
||||
// 삭제할 장착 인벤토리내의 아이템 목록을 초기화 한다.
|
||||
var to_clear_equip_invens = new List<InvenEquipType>() {
|
||||
InvenEquipType.Tool
|
||||
, InvenEquipType.Cloth
|
||||
, InvenEquipType.Tattoo
|
||||
};
|
||||
foreach(var inven_equip_type in to_clear_equip_invens)
|
||||
{
|
||||
if (true == getEquipInvens().TryGetValue(inven_equip_type, out var found_equip_inven))
|
||||
{
|
||||
var tool_equip_inven = found_equip_inven as IWithInventoryAccessor;
|
||||
NullReferenceCheckHelper.throwIfNull(tool_equip_inven, () => $"tool_equip_inven is null !!! - {player.toBasicString()}");
|
||||
|
||||
tool_equip_inven.clearItemAll();
|
||||
}
|
||||
}
|
||||
|
||||
// 능력치 속성 정보들도 초기화 한다.
|
||||
var ability_action = player.getEntityAction<AbilityAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ability_action, () => $"ability_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
ability_action.clearAbility();
|
||||
}
|
||||
|
||||
public override Item onAllocItem()
|
||||
{
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
return new UserItem(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
578
GameServer/Entity/Item/Base/Action/ItemAction.cs
Normal file
578
GameServer/Entity/Item/Base/Action/ItemAction.cs
Normal file
@@ -0,0 +1,578 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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;
|
||||
using ServerCore; using ServerBase;
|
||||
using MetaAssets;
|
||||
using Amazon.S3.Model;
|
||||
using static ServerCommon.MetaHelper;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class ItemAction : EntityActionBase
|
||||
{
|
||||
public ItemAction(ItemBase owner)
|
||||
: base(owner)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
var parent = owner.getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
|
||||
var alert_action = owner.getEntityAction<EntityAlertAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(alert_action, () => $"alert_action is null !!! - {owner.toBasicString()}, {parent.toBasicString()}");
|
||||
|
||||
alert_action.attachAlertFunction(EntityAlertTriggerType.ItemExpireWarningBefore, onAlertItemExpireWaringBefore);
|
||||
alert_action.attachAlertFunction(EntityAlertTriggerType.ItemExpire, onAlertItemExpire);
|
||||
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<(Result, List<DynamoDbDocBase>, EntityAlertMethodType)> onAlertItemExpireWaringBefore(EntityAlertTriggerType triggerType)
|
||||
{
|
||||
var owner = getOwner() as Item;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
var parent = owner.getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var err_msg = string.Empty;
|
||||
var result = new Result();
|
||||
var doc_bases = new List<DynamoDbDocBase>();
|
||||
|
||||
Player? player = null;
|
||||
if (parent is Player root_player)
|
||||
{
|
||||
player = root_player;
|
||||
}
|
||||
else if (parent is UgcNpc ugc_npc)
|
||||
{
|
||||
player = ugc_npc.onGetMasterEntity() as Player;
|
||||
}
|
||||
|
||||
if (null == player)
|
||||
{
|
||||
err_msg = $"Failed to cast Player !!!, in ItemAction.onTick() - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return (result, doc_bases, EntityAlertMethodType.None);
|
||||
}
|
||||
|
||||
var system_mail_key = "Item_Expiring_Soon";
|
||||
if (MetaData.Instance.SystemMailMetaData.TryGetValue(system_mail_key, out var systemMailMetaData) == false)
|
||||
{
|
||||
err_msg = $"Not found SystemMailMeta !!! : mailKey:{system_mail_key} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.SystemMailMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, doc_bases, EntityAlertMethodType.None);
|
||||
}
|
||||
|
||||
var item_meta = owner.getItemMeta();
|
||||
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}");
|
||||
|
||||
var meta_id = (META_ID)item_meta.ItemId;
|
||||
var user_nickname = player.getUserNickname();
|
||||
|
||||
var contents_arguments = new List<string>();
|
||||
contents_arguments.Add(item_meta.getStringKeyOfItemName());
|
||||
|
||||
(result, var new_mail_doc) = await Mail.createSystemMailWithMeta( player.getUserGuid(), user_nickname, systemMailMetaData, contents_arguments
|
||||
, new List<ServerCommon.MailItem>(), GameConfigMeta.SystemMailStoragePeriod );
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to createSystemMailWithMeta() !!! : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, doc_bases, EntityAlertMethodType.None);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(new_mail_doc, () => $"new_mail_doc is null !!! - {player.toBasicString()}");
|
||||
|
||||
doc_bases.Add(new_mail_doc);
|
||||
|
||||
var item_attribute_base = owner.getEntityAttribute<ItemAttributeBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(item_attribute_base, () => $"item_attribute_base is null !!! - {player.toBasicString()}");
|
||||
|
||||
var alert_record_attribute = owner.getEntityAttribute<EntityAlertRecordAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(alert_record_attribute, () => $"alert_record_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
alert_record_attribute.AlertKey = EntityAlertRecordDoc.makeALERT_KEY(triggerType, meta_id);
|
||||
alert_record_attribute.AlertedTime = DateTimeHelper.Current;
|
||||
alert_record_attribute.OwnerEntityType = owner.onGetOwnerEntityType();
|
||||
alert_record_attribute.OwnerGuid = item_attribute_base.ItemGuid;
|
||||
alert_record_attribute.EntityAlertTriggerType = triggerType;
|
||||
alert_record_attribute.MetaId = meta_id;
|
||||
alert_record_attribute.modifiedEntityAttribute(true);
|
||||
|
||||
return (result, doc_bases, EntityAlertMethodType.Mail);
|
||||
}
|
||||
|
||||
public async Task<(Result, List<DynamoDbDocBase>, EntityAlertMethodType)> onAlertItemExpire(EntityAlertTriggerType triggerType)
|
||||
{
|
||||
var owner = getOwner() as Item;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
var parent = owner.getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var err_msg = string.Empty;
|
||||
var result = new Result();
|
||||
var doc_bases = new List<DynamoDbDocBase>();
|
||||
|
||||
Player? player = null;
|
||||
if (parent is Player root_player)
|
||||
{
|
||||
player = root_player;
|
||||
}
|
||||
else if (parent is UgcNpc ugc_npc)
|
||||
{
|
||||
player = ugc_npc.onGetMasterEntity() as Player;
|
||||
}
|
||||
|
||||
if (null == player)
|
||||
{
|
||||
err_msg = $"Failed to cast Player !!!, in ItemAction.onTick() - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return (result, doc_bases, EntityAlertMethodType.None);
|
||||
}
|
||||
|
||||
var system_mail_key = "Item_Expired_Deleted";
|
||||
if (MetaData.Instance.SystemMailMetaData.TryGetValue(system_mail_key, out var systemMailMetaData) == false)
|
||||
{
|
||||
err_msg = $"Not found SystemMailMeta !!! : mailKey:{system_mail_key} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.SystemMailMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, doc_bases, EntityAlertMethodType.None);
|
||||
}
|
||||
|
||||
var item_meta = owner.getItemMeta();
|
||||
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}");
|
||||
|
||||
var meta_id = (META_ID)item_meta.ItemId;
|
||||
var user_nickname = player.getUserNickname();
|
||||
|
||||
var contents_arguments = new List<string>();
|
||||
contents_arguments.Add(item_meta.getStringKeyOfItemName());
|
||||
|
||||
(result, var new_mail_doc) = await Mail.createSystemMailWithMeta(player.getUserGuid(), user_nickname, systemMailMetaData, contents_arguments
|
||||
, new List<ServerCommon.MailItem>(), GameConfigMeta.SystemMailStoragePeriod);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to createSystemMailWithMeta() !!! : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, doc_bases, EntityAlertMethodType.None);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(new_mail_doc, () => $"new_mail_doc is null !!! - {player.toBasicString()}");
|
||||
|
||||
doc_bases.Add(new_mail_doc);
|
||||
|
||||
var item_attribute_base = owner.getEntityAttribute<ItemAttributeBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(item_attribute_base, () => $"item_attribute_base is null !!! - {player.toBasicString()}");
|
||||
|
||||
var alert_record_attribute = owner.getEntityAttribute<EntityAlertRecordAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(alert_record_attribute, () => $"alert_record_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
alert_record_attribute.AlertKey = EntityAlertRecordDoc.makeALERT_KEY(triggerType, meta_id);
|
||||
alert_record_attribute.AlertedTime = DateTimeHelper.Current;
|
||||
alert_record_attribute.OwnerEntityType = owner.onGetOwnerEntityType();
|
||||
alert_record_attribute.OwnerGuid = item_attribute_base.ItemGuid;
|
||||
alert_record_attribute.EntityAlertTriggerType = triggerType;
|
||||
alert_record_attribute.MetaId = meta_id;
|
||||
alert_record_attribute.modifiedEntityAttribute(true);
|
||||
|
||||
return (result, doc_bases, EntityAlertMethodType.Mail);
|
||||
}
|
||||
|
||||
public async Task<(Result, bool, List<Item>?)> tryLevelUpByTattoo()
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var owner = getOwner() as Item;
|
||||
ArgumentNullException.ThrowIfNull(owner);
|
||||
|
||||
var parent = owner.getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent);
|
||||
|
||||
var inventory_action = parent.getEntityAction<InventoryActionBase>();
|
||||
ArgumentNullException.ThrowIfNull(inventory_action);
|
||||
|
||||
inventory_action.getEquipInvens().TryGetValue(InvenEquipType.Tattoo, out var found_equip_inven);
|
||||
var tattoo_inven = found_equip_inven as TattooEquipInven;
|
||||
ArgumentNullException.ThrowIfNull(tattoo_inven);
|
||||
|
||||
var tattoo_inven_data = tattoo_inven.getData();
|
||||
ArgumentNullException.ThrowIfNull(tattoo_inven_data);
|
||||
|
||||
var item_attribute = owner.getEntityAttribute<ItemAttributeBase>();
|
||||
ArgumentNullException.ThrowIfNull(item_attribute);
|
||||
|
||||
bool is_equiped_tatoo_slot = false;
|
||||
var tattoo_slot_type = (TattooSlotType)item_attribute.EquipedPos;
|
||||
var found_using_tattoo_slot = tattoo_inven_data.findEntityBaseInSlotType(tattoo_slot_type) as Item;
|
||||
if (null != found_using_tattoo_slot)
|
||||
{
|
||||
is_equiped_tatoo_slot = true;
|
||||
}
|
||||
|
||||
var item_meta = owner.getItemMeta();
|
||||
ArgumentNullException.ThrowIfNull(item_meta);
|
||||
|
||||
var curr_level = item_attribute.Level;
|
||||
var next_level = item_attribute.Level + 1;
|
||||
|
||||
// 다음 레벨에 해당하는 메타 데이터를 참조 한다.
|
||||
if (false == MetaData.Instance._ItemLevelEnchantMetaTable.TryGetValue(next_level, out var found_new_item_level_enchant_meta))
|
||||
{
|
||||
err_msg = $"Not found new ItemLevelEchantMeta !!!, current level is Max : newLevel:{next_level}, currLevel:{curr_level} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ItemLevelCurrentMax, err_msg);
|
||||
|
||||
return (result, false, null);
|
||||
}
|
||||
|
||||
var found_new_enchant = found_new_item_level_enchant_meta?.GetConsumeItem(item_meta.Rarity);
|
||||
if (found_new_enchant == null)
|
||||
{
|
||||
err_msg = $"Not found next Enchant Data !!! : itemRarity:{item_meta.Rarity} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ItemEnchantNotFoundInMeta, err_msg);
|
||||
|
||||
return (result, false, null);
|
||||
}
|
||||
|
||||
(result, var deleted_items) = await inventory_action.tryDeleteItemByMetaId((META_ID)found_new_enchant.ConsumeItemID, (UInt16)found_new_enchant.ConsumeItemCount);
|
||||
if(result.isFail())
|
||||
{
|
||||
return (result, false, null);
|
||||
}
|
||||
|
||||
var is_success_enchant = false;
|
||||
|
||||
if (found_new_enchant.Probability >= RandomHelper.next(0, 10000) == true)
|
||||
{
|
||||
if(true == is_equiped_tatoo_slot)
|
||||
{
|
||||
var ability_action = parent.getEntityAction<AbilityAction>();
|
||||
ArgumentNullException.ThrowIfNull(ability_action);
|
||||
|
||||
result = await ability_action.setAbilities(owner, (Int16)next_level, false);
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, false, null);
|
||||
}
|
||||
|
||||
await ability_action.setAbilities(owner, (Int16)(item_attribute.Level), true);
|
||||
}
|
||||
|
||||
is_success_enchant = true;
|
||||
item_attribute.Level = (UInt16)next_level;
|
||||
item_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
|
||||
var updated_items = new List<Item>();
|
||||
updated_items.AddRange(deleted_items);
|
||||
updated_items.Add(owner);
|
||||
|
||||
return (result, is_success_enchant, updated_items);
|
||||
}
|
||||
|
||||
public async Task<(Result, List<Item>?)> tryChangeAttributeByTattoo(Int16 targetSlotIndex)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var owner = getOwner() as Item;
|
||||
ArgumentNullException.ThrowIfNull(owner);
|
||||
|
||||
var parent = owner.getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent);
|
||||
|
||||
var inventory_action = parent.getEntityAction<InventoryActionBase>();
|
||||
ArgumentNullException.ThrowIfNull(inventory_action);
|
||||
|
||||
inventory_action.getEquipInvens().TryGetValue(InvenEquipType.Tattoo, out var found_equip_inven);
|
||||
var tattoo_inven = found_equip_inven as TattooEquipInven;
|
||||
ArgumentNullException.ThrowIfNull(tattoo_inven);
|
||||
|
||||
var tattoo_inven_data = tattoo_inven.getData();
|
||||
ArgumentNullException.ThrowIfNull(tattoo_inven_data);
|
||||
|
||||
var item_attribute = owner.getEntityAttribute<ItemAttributeBase>();
|
||||
ArgumentNullException.ThrowIfNull(item_attribute);
|
||||
|
||||
bool is_equiped_tatoo_slot = false;
|
||||
var tattoo_slot_type = (TattooSlotType)item_attribute.EquipedPos;
|
||||
var found_using_tattoo_slot = tattoo_inven_data.findEntityBaseInSlotType(tattoo_slot_type) as Item;
|
||||
if (null != found_using_tattoo_slot)
|
||||
{
|
||||
is_equiped_tatoo_slot = true;
|
||||
}
|
||||
|
||||
var item_meta = owner.getItemMeta();
|
||||
ArgumentNullException.ThrowIfNull(item_meta, $"item_meta is null !!! - {parent.toBasicString()}");
|
||||
|
||||
if (false == MetaData.Instance.Meta.AttributeEnchantMetaTable.AttributeEnchantMetaDataListbyRarity.TryGetValue(item_meta.Rarity, out var found_attribute_enchant_meta))
|
||||
{
|
||||
err_msg = $"Not found AttributeEnchantMeta !!! : itemRarity:{item_meta.Rarity} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ItemAttributeEnchantMetaNotFound, err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
if (false == MetaData.Instance._ItemLevelEnchantMetaTable.TryGetValue(item_attribute.Level, out var found_item_level_enchant_meta))
|
||||
{
|
||||
err_msg = $"Not found new ItemLevelEchantMeta !!! : newLevel:{item_attribute.Level} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ItemLevelEnchantNotFoundInMeta, err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
var found_enchant = found_item_level_enchant_meta.GetConsumeItem(item_meta.Rarity);
|
||||
if (found_enchant == null)
|
||||
{
|
||||
err_msg = $"Not found new Enchant Data !!! : itemRarity:{item_meta.Rarity} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ItemEnchantNotFoundInMeta, err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
(result, var deleted_items) = await inventory_action.tryDeleteItemByMetaId((META_ID)found_attribute_enchant_meta.ItemID, (UInt16)found_attribute_enchant_meta.ItemCount);
|
||||
if(result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
if(0 == targetSlotIndex)
|
||||
{
|
||||
result = owner.fillupMakeAttributeIds(item_meta, out var selected_attribute_ids);
|
||||
if(result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
if(true == is_equiped_tatoo_slot)
|
||||
{
|
||||
var ability_action = parent.getEntityAction<AbilityAction>();
|
||||
ArgumentNullException.ThrowIfNull(ability_action);
|
||||
|
||||
result = await ability_action.setAbilities(owner, (Int16)item_attribute.Level, true);
|
||||
if(result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
item_attribute.Attributes = selected_attribute_ids;
|
||||
result = await ability_action.setAbilities(owner, (Int16)item_attribute.Level, false);
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item_attribute.Attributes = selected_attribute_ids;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(result, var change_attribute_id) = await owner.fillupChangeAttributeIds();
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
if (true == is_equiped_tatoo_slot)
|
||||
{
|
||||
var ability_action = parent.getEntityAction<AbilityAction>();
|
||||
ArgumentNullException.ThrowIfNull(ability_action);
|
||||
|
||||
var attriubte_id = item_attribute.Attributes[targetSlotIndex];
|
||||
result = await ability_action.changeAbilities( owner
|
||||
, new Dictionary<int, int>() { { targetSlotIndex, attriubte_id } }
|
||||
, true );
|
||||
if(result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
item_attribute.Attributes[targetSlotIndex] = (UInt16)change_attribute_id;
|
||||
result = await ability_action.changeAbilities( owner
|
||||
, new Dictionary<int, int>() { { targetSlotIndex, change_attribute_id } }
|
||||
, false );
|
||||
if(result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item_attribute.Attributes[targetSlotIndex] = (UInt16)change_attribute_id;
|
||||
}
|
||||
}
|
||||
|
||||
item_attribute.modifiedEntityAttribute();
|
||||
|
||||
var updated_items = new List<Item>();
|
||||
updated_items.AddRange(deleted_items);
|
||||
updated_items.Add(owner);
|
||||
|
||||
return (result, updated_items);
|
||||
}
|
||||
|
||||
public async Task<bool> isExpiredItem()
|
||||
{
|
||||
var owner = getOwner() as Item;
|
||||
ArgumentNullException.ThrowIfNull(owner);
|
||||
|
||||
var parent = owner.getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent);
|
||||
|
||||
var item_meta = owner.getItemMeta();
|
||||
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}");
|
||||
|
||||
if( EExpireType.DELAY != item_meta.ExpireType
|
||||
|| 0 >= item_meta.ExpireTimeSec )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var item_attribute_base = owner.getEntityAttribute<ItemAttributeBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(item_attribute_base, () => $"item_attribute_base is null !!! - {parent.toBasicString()}");
|
||||
|
||||
(var result, DynamoDbDocBase? doc_base) = await item_attribute_base.toDocBase(false);
|
||||
if(result.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to toDocBase() !!!, in isExpiredItem() : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return false;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(doc_base, () => $"doc_base is null !!! - {owner.toBasicString()}, {parent.toBasicString()}");
|
||||
|
||||
var created_time = doc_base.getCreatedDateTime().ProcessedTime;
|
||||
if (false == created_time.isValidTime())
|
||||
{
|
||||
var err_msg = $"Failed to isValidTime() !!!, in isExpiredItem() : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
var to_expire_date_time = created_time.AddSeconds(item_meta.ExpireTimeSec);
|
||||
|
||||
if(false == DateTimeHelper.hasTimeReached(to_expire_date_time))
|
||||
{
|
||||
await onAlertItemExpireBeforeHourTime(created_time, to_expire_date_time);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task onAlertItemExpireBeforeHourTime(DateTime createdTime, DateTime toExpireTime)
|
||||
{
|
||||
var owner = getOwner() as Item;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!! - {toBasicString()}");
|
||||
var parent = owner.getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var past_time = MetaHelper.GameConfigMeta.ItemExpireAlertBeforeHourTime * -1;
|
||||
var alert_time = toExpireTime.AddHours(past_time);
|
||||
|
||||
if (false == DateTimeHelper.hasTimeReached(alert_time))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var entity_alert_auction = owner.getEntityAction<EntityAlertAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(entity_alert_auction, () => $"entity_alert_auction is null !!! - {owner.toBasicString()}, {parent.toBasicString()}");
|
||||
|
||||
await entity_alert_auction.onAlert(EntityAlertTriggerType.ItemExpireWarningBefore);
|
||||
}
|
||||
|
||||
public override async Task onTick()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var owner = getOwner() as Item;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!! - {toBasicString()}");
|
||||
|
||||
var parent = owner.getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var err_msg = string.Empty;
|
||||
var result = new Result();
|
||||
|
||||
var item_attribute_base = owner.getEntityAttribute<ItemAttributeBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(item_attribute_base, () => $"item_attribute_base is null !!! - {owner.toBasicString()}");
|
||||
|
||||
Player? player = null;
|
||||
if (parent is Player root_player)
|
||||
{
|
||||
player = root_player;
|
||||
}
|
||||
else if (parent is UgcNpc ugc_npc)
|
||||
{
|
||||
player = ugc_npc.onGetMasterEntity() as Player;
|
||||
}
|
||||
|
||||
if (null == player)
|
||||
{
|
||||
err_msg = $"Failed to cast Player !!!, in ItemAction.onTick() - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return;
|
||||
}
|
||||
|
||||
var target_item_guid = item_attribute_base.ItemGuid;
|
||||
var item_stack_count = item_attribute_base.ItemStackCount;
|
||||
|
||||
if (true == await isExpiredItem())
|
||||
{
|
||||
var entity_alert_auction = owner.getEntityAction<EntityAlertAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(entity_alert_auction, () => $"entity_alert_auction is null !!! - {owner.toBasicString()}, {parent.toBasicString()}");
|
||||
|
||||
await entity_alert_auction.onAlert(EntityAlertTriggerType.ItemExpire);
|
||||
|
||||
(result, _) = await PacketHandler.ItemDeletePacketHandler.tryDeleteItemWithTransactionRunner( player
|
||||
, target_item_guid
|
||||
, item_stack_count
|
||||
, LogActionType.ItemDestoryByExpiration );
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryDeleteItemWithTransactionRunner() !!!, in onTick() : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
var user_create_or_load_action = player.getEntityAction<UserCreateOrLoadAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_create_or_load_action, () => $"user_create_or_load_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
ItemNotifyHelper.send_S2C_NTF_ITEM_DELETE(player, target_item_guid, item_stack_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
GameServer/Entity/Item/Base/Item.cs
Normal file
44
GameServer/Entity/Item/Base/Item.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 GameServer
|
||||
{
|
||||
public class Item : ItemBase
|
||||
{
|
||||
public Item(EntityBase parent)
|
||||
: base(parent)
|
||||
{
|
||||
}
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var direct_parent = getDirectParent();
|
||||
NullReferenceCheckHelper.throwIfNull(direct_parent, () => $"direct_parent is null !!!");
|
||||
|
||||
addEntityAttribute(new EntityAlertRecordAttribute(this, direct_parent));
|
||||
|
||||
addEntityAction(new EntityAlertAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
}
|
||||
}
|
||||
133
GameServer/Entity/Item/Owner/Myhome/MyhomeItem.cs
Normal file
133
GameServer/Entity/Item/Owner/Myhome/MyhomeItem.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class MyhomeItem : Item
|
||||
{
|
||||
public MyhomeItem(Myhome owner)
|
||||
: base(owner)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var parent = getDirectParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
|
||||
addEntityAttribute(new MyhomeItemAttribute(this, parent));
|
||||
|
||||
addEntityAction(new MyhomeItemAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override TAction getEntityAction<TAction>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent, $"parent is null !!!");
|
||||
|
||||
if (typeof(TAction) == typeof(ItemAction))
|
||||
{
|
||||
var item_action = base.getEntityAction<MyhomeItemAction>() as TAction;
|
||||
NullReferenceCheckHelper.throwIfNull(item_action, () => $"item_action is null !!!");
|
||||
return item_action;
|
||||
}
|
||||
|
||||
var action = base.getEntityAction<TAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(action, () => $"action is null !!!");
|
||||
return action;
|
||||
}
|
||||
|
||||
public override TAttribute getOriginEntityAttribute<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent, $"parent is null !!!");
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
var item_attrib = base.getOriginEntityAttribute<MyhomeItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(item_attrib, () => $"item_attrib is null !!!");
|
||||
return item_attrib;
|
||||
}
|
||||
|
||||
var attrib = base.getOriginEntityAttribute<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attrib, () => $"attrib is null !!!");
|
||||
return attrib;
|
||||
}
|
||||
|
||||
public override TAttribute getEntityAttributeWithReadOnly<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent, $"parent is null !!!");
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
var item_attrib = base.getEntityAttributeWithReadOnly<MyhomeItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(item_attrib, () => $"item_attrib is null !!!");
|
||||
return item_attrib;
|
||||
}
|
||||
|
||||
var attrib = base.getEntityAttributeWithReadOnly<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attrib, () => $"attrib is null !!!");
|
||||
return attrib;
|
||||
}
|
||||
|
||||
public override TAttribute getEntityAttributeWithCloneOnly<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent, $"parent is null !!!");
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
var item_attrib = base.getEntityAttributeWithCloneOnly<MyhomeItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(item_attrib, () => $"item_attrib is null !!!");
|
||||
return item_attrib;
|
||||
}
|
||||
|
||||
var attrib = base.getEntityAttributeWithCloneOnly<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attrib, () => $"attrib is null !!!");
|
||||
return attrib;
|
||||
}
|
||||
|
||||
public override TAttribute getClonedEntityAttribute<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent, $"parent is null !!!");
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
var item_attrib = base.getClonedEntityAttribute<MyhomeItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(item_attrib, () => $"item_attrib is null !!!");
|
||||
return item_attrib;
|
||||
}
|
||||
|
||||
var attrib = base.getClonedEntityAttribute<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attrib, () => $"attrib is null !!!");
|
||||
return attrib;
|
||||
}
|
||||
|
||||
public override TAttribute getEntityAttribute<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent, $"parent is null !!!");
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
var item_attrib = base.getEntityAttribute<MyhomeItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(item_attrib, () => $"item_attrib is null !!!");
|
||||
return item_attrib;
|
||||
}
|
||||
|
||||
var attrib = base.getEntityAttribute<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attrib, () => $"attrib is null !!!");
|
||||
return attrib;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
GameServer/Entity/Item/Owner/Myhome/MyhomeItemAction.cs
Normal file
19
GameServer/Entity/Item/Owner/Myhome/MyhomeItemAction.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class MyhomeItemAction : ItemAction
|
||||
{
|
||||
public MyhomeItemAction(MyhomeItem owner)
|
||||
: base(owner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
160
GameServer/Entity/Item/Owner/UgcNpc/UgcNpcItem.cs
Normal file
160
GameServer/Entity/Item/Owner/UgcNpc/UgcNpcItem.cs
Normal file
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class UgcNpcItem : Item
|
||||
{
|
||||
public UgcNpcItem(UgcNpc owner)
|
||||
: base(owner)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var direct_parent = getDirectParent();
|
||||
NullReferenceCheckHelper.throwIfNull(direct_parent, () => $"direct_parent is null !!!");
|
||||
|
||||
addEntityAttribute(new UgcNpcItemAttribute(this, direct_parent));
|
||||
|
||||
addEntityAction(new UgcNpcItemAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override TAction getEntityAction<TAction>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
|
||||
|
||||
TAction? to_cast_entity_atcion;
|
||||
|
||||
if (typeof(TAction) == typeof(ItemAction))
|
||||
{
|
||||
to_cast_entity_atcion = base.getEntityAction<UgcNpcItemAction>() as TAction;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_atcion, () => $"to_cast_entity_atcion is null !!!");
|
||||
|
||||
return to_cast_entity_atcion;
|
||||
}
|
||||
|
||||
to_cast_entity_atcion = base.getEntityAction<TAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_atcion, () => $"to_cast_entity_atcion is null !!!");
|
||||
|
||||
return to_cast_entity_atcion;
|
||||
}
|
||||
|
||||
public override TAttribute getOriginEntityAttribute<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent, $"parent is null !!!");
|
||||
|
||||
TAttribute? to_cast_entity_attribute;
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
to_cast_entity_attribute = base.getOriginEntityAttribute<UgcNpcItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
to_cast_entity_attribute = base.getOriginEntityAttribute<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
public override TAttribute getEntityAttributeWithReadOnly<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent, $"parent is null !!!");
|
||||
|
||||
TAttribute? to_cast_entity_attribute;
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
to_cast_entity_attribute = base.getEntityAttributeWithReadOnly<UgcNpcItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
to_cast_entity_attribute = base.getEntityAttributeWithReadOnly<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
public override TAttribute getEntityAttributeWithCloneOnly<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent, $"parent is null !!!");
|
||||
|
||||
TAttribute? to_cast_entity_attribute;
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
to_cast_entity_attribute = base.getEntityAttributeWithCloneOnly<UgcNpcItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
to_cast_entity_attribute = base.getEntityAttributeWithCloneOnly<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
public override TAttribute getClonedEntityAttribute<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent, $"parent is null !!!");
|
||||
|
||||
TAttribute? to_cast_entity_attribute;
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
to_cast_entity_attribute = base.getClonedEntityAttribute<UgcNpcItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
to_cast_entity_attribute = base.getClonedEntityAttribute<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
public override TAttribute getEntityAttribute<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
ArgumentNullException.ThrowIfNull(parent, $"parent is null !!!");
|
||||
|
||||
TAttribute? to_cast_entity_attribute;
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
to_cast_entity_attribute = base.getEntityAttribute<UgcNpcItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
to_cast_entity_attribute = base.getEntityAttribute<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
GameServer/Entity/Item/Owner/UgcNpc/UgcNpcItemAction.cs
Normal file
21
GameServer/Entity/Item/Owner/UgcNpc/UgcNpcItemAction.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class UgcNpcItemAction : ItemAction
|
||||
{
|
||||
public UgcNpcItemAction(UgcNpcItem owner)
|
||||
: base(owner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
165
GameServer/Entity/Item/Owner/User/UserItem.cs
Normal file
165
GameServer/Entity/Item/Owner/User/UserItem.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class UserItem : Item
|
||||
{
|
||||
public UserItem(Player player)
|
||||
: base(player)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var direct_parent = getDirectParent();
|
||||
NullReferenceCheckHelper.throwIfNull(direct_parent, () => $"direct_parent is null !!!");
|
||||
|
||||
addEntityAttribute(new UserItemAttribute(this, direct_parent));
|
||||
|
||||
addEntityAction(new UserItemAction(this));
|
||||
addEntityAction(new ItemUseAction(this));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override TAction getEntityAction<TAction>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
|
||||
|
||||
TAction? to_cast_entity_atcion;
|
||||
|
||||
if (typeof(TAction) == typeof(ItemAction))
|
||||
{
|
||||
to_cast_entity_atcion = base.getEntityAction<UserItemAction>() as TAction;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_atcion, () => $"to_cast_entity_atcion is null !!!");
|
||||
|
||||
return to_cast_entity_atcion;
|
||||
}
|
||||
|
||||
to_cast_entity_atcion = base.getEntityAction<TAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_atcion, () => $"to_cast_entity_atcion is null !!!");
|
||||
|
||||
return to_cast_entity_atcion;
|
||||
}
|
||||
|
||||
public override TAttribute getOriginEntityAttribute<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
|
||||
|
||||
TAttribute? to_cast_entity_attribute;
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
to_cast_entity_attribute = base.getOriginEntityAttribute<UserItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
to_cast_entity_attribute = base.getOriginEntityAttribute<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
public override TAttribute getEntityAttributeWithReadOnly<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
|
||||
|
||||
TAttribute? to_cast_entity_attribute;
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
to_cast_entity_attribute = base.getEntityAttributeWithReadOnly<UserItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
to_cast_entity_attribute = base.getEntityAttributeWithReadOnly<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
public override TAttribute getEntityAttributeWithCloneOnly<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
|
||||
|
||||
TAttribute? to_cast_entity_attribute;
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
to_cast_entity_attribute = base.getEntityAttributeWithCloneOnly<UserItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
to_cast_entity_attribute = base.getEntityAttributeWithCloneOnly<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
public override TAttribute getClonedEntityAttribute<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
|
||||
|
||||
TAttribute? to_cast_entity_attribute;
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
to_cast_entity_attribute = base.getClonedEntityAttribute<UserItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
to_cast_entity_attribute = base.getClonedEntityAttribute<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
public override TAttribute getEntityAttribute<TAttribute>()
|
||||
{
|
||||
var parent = getRootParent();
|
||||
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
|
||||
|
||||
TAttribute? to_cast_entity_attribute;
|
||||
|
||||
if (typeof(TAttribute) == typeof(ItemAttributeBase))
|
||||
{
|
||||
to_cast_entity_attribute = base.getEntityAttribute<UserItemAttribute>() as TAttribute;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
|
||||
to_cast_entity_attribute = base.getEntityAttribute<TAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_attribute, () => $"to_cast_entity_attribute is null !!!");
|
||||
|
||||
return to_cast_entity_attribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
GameServer/Entity/Item/Owner/User/UserItemAction.cs
Normal file
20
GameServer/Entity/Item/Owner/User/UserItemAction.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class UserItemAction : ItemAction
|
||||
{
|
||||
public UserItemAction(UserItem owner)
|
||||
: base(owner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
201
GameServer/Entity/Land/Action/LandAction.cs
Normal file
201
GameServer/Entity/Land/Action/LandAction.cs
Normal file
@@ -0,0 +1,201 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using META_ID = System.UInt32;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal class LandAction : EntityActionBase
|
||||
{
|
||||
public LandAction(Land owner)
|
||||
: base(owner)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> tryLoadLandFromDb(int landMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var doc = new LandDoc();
|
||||
doc.setCombinationKeyForPK(landMetaId.ToString());
|
||||
|
||||
var error_code = doc.onApplyPKSK();
|
||||
if (error_code.isFail())
|
||||
{
|
||||
err_msg = $"Failed to onApplyPKSK() !!! : {error_code.toBasicString()}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var query_config = db_client.makeQueryConfigForReadByPKSK(doc.getPK());
|
||||
(result, var read_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig<LandDoc>(query_config);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypesWithQueryOperationConfig() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var land = getOwner() as Land;
|
||||
NullReferenceCheckHelper.throwIfNull(land, () => $"land is null !!!");
|
||||
|
||||
var land_attribute = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribute, () => $"land_attribute is null !!!");
|
||||
|
||||
foreach (var read_doc in read_docs)
|
||||
{
|
||||
if (!land_attribute.copyEntityAttributeFromDoc(read_doc))
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDoc() !!! to:{land_attribute.getTypeName()}, from:{read_doc.getTypeName()} : {this.getTypeName()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (land_attribute.LandMetaId == 0)
|
||||
{
|
||||
land_attribute.LandMetaId = (uint)landMetaId;
|
||||
|
||||
if (read_docs.Count != 0)
|
||||
{
|
||||
Log.getLogger().info($"LandDoc.LandAtrib.LandMetaId is 0 !!! - landMetaId:{landMetaId}");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(Result, DynamoDbDocBase?)> modifyLandInfo(string landName, string landDescription)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var land = getOwner() as Land;
|
||||
NullReferenceCheckHelper.throwIfNull(land, () => $"land is null !!!");
|
||||
|
||||
var land_attribute = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribute, () => $"land_attribute is null !!!");
|
||||
|
||||
land_attribute.LandName = landName;
|
||||
land_attribute.Description = landDescription;
|
||||
land_attribute.IsLoadFromDb = true;
|
||||
land_attribute.modifiedEntityAttribute();
|
||||
|
||||
(result, var land_doc) = await land_attribute.toDocBase();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to toDocBase() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, land_doc);
|
||||
}
|
||||
|
||||
public void modifyLandInfo(LandInfo landInfo)
|
||||
{
|
||||
var land = getOwner() as Land;
|
||||
NullReferenceCheckHelper.throwIfNull(land, () => $"land is null !!!");
|
||||
|
||||
var land_attribute = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribute, () => $"land_attribute is null !!!");
|
||||
|
||||
land_attribute.OwnerUserGuid = landInfo.OwnerUserGuid;
|
||||
land_attribute.LandName = landInfo.LandName;
|
||||
land_attribute.Description = landInfo.LandDescription;
|
||||
land_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
|
||||
public bool isExistOwner()
|
||||
{
|
||||
var land = getOwner() as Land;
|
||||
NullReferenceCheckHelper.throwIfNull(land, () => $"land is null !!!");
|
||||
|
||||
var land_attribute = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribute, () => $"land_attribute is null !!!");
|
||||
|
||||
return land_attribute.OwnerUserGuid != string.Empty;
|
||||
}
|
||||
|
||||
public void setLandOwner(int landMetaId, string userGuid)
|
||||
{
|
||||
var land = getOwner() as Land;
|
||||
NullReferenceCheckHelper.throwIfNull(land, () => $"land is null !!!");
|
||||
|
||||
var land_attribute = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribute, () => $"land_attribute is null !!!");
|
||||
|
||||
if (!land_attribute.IsLoadFromDb)
|
||||
{
|
||||
land_attribute.LandMetaId = (uint)landMetaId;
|
||||
land_attribute.OwnerUserGuid = userGuid;
|
||||
land_attribute.newEntityAttribute();
|
||||
}
|
||||
else
|
||||
{
|
||||
land_attribute.OwnerUserGuid = userGuid;
|
||||
land_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void changeOwner(string userGuid)
|
||||
{
|
||||
var land = getOwner() as Land;
|
||||
NullReferenceCheckHelper.throwIfNull(land, () => $"land is null !!!");
|
||||
|
||||
var land_attribute = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribute, () => $"land_attribute is null !!!");
|
||||
|
||||
land_attribute.OwnerUserGuid = userGuid;
|
||||
land_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
|
||||
public void initOwner()
|
||||
{
|
||||
var land = getOwner() as Land;
|
||||
NullReferenceCheckHelper.throwIfNull(land, () => $"land is null !!!");
|
||||
|
||||
var land_attribute = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribute, () => $"land_attribute is null !!!");
|
||||
|
||||
land_attribute.OwnerUserGuid = string.Empty;
|
||||
land_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
|
||||
public bool isLandOwner(string userGuid)
|
||||
{
|
||||
var land = getOwner() as Land;
|
||||
NullReferenceCheckHelper.throwIfNull(land, () => $"land is null !!!");
|
||||
|
||||
var land_attribute = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribute, () => $"land_attribute is null !!!");
|
||||
|
||||
return land_attribute.OwnerUserGuid == userGuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
GameServer/Entity/Land/Helper/LandBusinessLogHelper.cs
Normal file
30
GameServer/Entity/Land/Helper/LandBusinessLogHelper.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class LandBusinessLogHelper
|
||||
{
|
||||
public static LandLogInfo toLandLogInfo(this Land land)
|
||||
{
|
||||
var land_attribue = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribue, () => $"land_attribue is null !!!");
|
||||
|
||||
var land_log_info = new LandLogInfo();
|
||||
land_log_info.setLandInfo(land_attribue);
|
||||
|
||||
return land_log_info;
|
||||
}
|
||||
|
||||
public static void setLandInfo(this LandLogInfo log, LandAttribute landAttribute)
|
||||
{
|
||||
log.setLogProperty((int)landAttribute.LandMetaId, landAttribute.OwnerUserGuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
216
GameServer/Entity/Land/Helper/LandHelper.cs
Normal file
216
GameServer/Entity/Land/Helper/LandHelper.cs
Normal file
@@ -0,0 +1,216 @@
|
||||
using Amazon.Runtime.Internal;
|
||||
using Org.BouncyCastle.Asn1.Ocsp;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class LandHelper
|
||||
{
|
||||
public static async Task<LandInfo> toLandInfo(this Land land)
|
||||
{
|
||||
var land_attribute = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribute, () => $"land_attribute is null !!!");
|
||||
|
||||
var land_info = new LandInfo();
|
||||
|
||||
land_info.LandMetaId = (int)land_attribute.LandMetaId;
|
||||
land_info.LandName = land_attribute.LandName;
|
||||
land_info.LandDescription = land_attribute.Description;
|
||||
land_info.OwnerUserGuid = land_attribute.OwnerUserGuid;
|
||||
|
||||
if (land_attribute.OwnerUserGuid != string.Empty)
|
||||
{
|
||||
var (result, nickname_attrib) = await NicknameDoc.findNicknameFromGuid(land_attribute.OwnerUserGuid);
|
||||
if (result.isSuccess() && nickname_attrib != null)
|
||||
{
|
||||
land_info.OwnerUserNickname = nickname_attrib.Nickname;
|
||||
}
|
||||
}
|
||||
|
||||
return land_info;
|
||||
}
|
||||
|
||||
public static async Task<(Result, Land?, OwnedLand?, DynamoDbDocBase?)> tryGainLand(Player player, int landMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
if (!MetaData.Instance._LandTable.TryGetValue(landMetaId, out var land_meta_data))
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TryGetValue() !!! : LandMetaId:{landMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
if (land_meta_data.Editor != MetaAssets.EditorType.USER)
|
||||
{
|
||||
err_msg = $"Land EditorType is NOT USER !!! : LandMetaId:{landMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandEditorIsNotUser, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
if (!MapManager.Instance.GetLandMapTree(landMetaId, out var land_map_tree))
|
||||
{
|
||||
err_msg = $"Failed to GetLandMapTree() !!! : LandMetaId:{landMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandMapTreeDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
var land_manager = server_logic.getLandManager();
|
||||
if (!land_manager.tryGetLand(landMetaId, out var land))
|
||||
{
|
||||
err_msg = $"Failed to tryGetLand() !!! : landMetaId:{landMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
var land_action = land.getEntityAction<LandAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_action, () => $"land_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
if (land_action.isExistOwner())
|
||||
{
|
||||
err_msg = $"Land Exist Owner !!! : landMetaId:{landMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandExistOwner, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
var user_guid = player.getUserGuid();
|
||||
land_action.setLandOwner(landMetaId, user_guid);
|
||||
|
||||
var land_attribute = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribute, () => $"land_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
(result, var land_doc_base) = await land_attribute.toDocBase();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to toDocBase() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(land_doc_base, () => $"land_doc_base is null !!! - {player.toBasicString()}");
|
||||
|
||||
(result, var owned_land) = await OwnedLandHelper.createOwnedLand(player, landMetaId, OwnedType.Own);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to createOwnedLand() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(owned_land, () => $"owned_land is null !!! - {player.toBasicString()}");
|
||||
|
||||
return (result, land, owned_land, land_doc_base);
|
||||
}
|
||||
|
||||
public static async Task<(Result, Land?, OwnedLand?, DynamoDbDocBase?)> tryInitMyLandOwnership(Player player, int landMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
if (!MetaData.Instance._LandTable.TryGetValue(landMetaId, out var land_meta_data))
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TryGetValue() !!! : LandMetaId:{landMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
if (land_meta_data.Editor != MetaAssets.EditorType.USER)
|
||||
{
|
||||
err_msg = $"Land EditorType is NOT USER !!! : LandMetaId:{landMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandEditorIsNotUser, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
if (!MapManager.Instance.GetLandMapTree(landMetaId, out var land_map_tree))
|
||||
{
|
||||
err_msg = $"Failed to GetLandMapTree() !!! : LandMetaId:{landMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandMapTreeDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
var land_manager = server_logic.getLandManager();
|
||||
if (!land_manager.tryGetLand(landMetaId, out var land))
|
||||
{
|
||||
err_msg = $"Failed to tryGetLand() !!! : landMetaId:{landMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
var land_action = land.getEntityAction<LandAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_action, () => $"land_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var user_guid = player.getUserGuid();
|
||||
if (!land_action.isLandOwner(user_guid))
|
||||
{
|
||||
err_msg = $"Land Owner is Not Match !!! : landMetaId:{landMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandOwnerIsNotMatch, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
land_action.initOwner();
|
||||
|
||||
var land_attribute = land.getEntityAttribute<LandAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_attribute, () => $"land_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
(result, var land_doc_base) = await land_attribute.toDocBase();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to toDocBase() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(land_doc_base, () => $"land_doc_base is null !!! - {player.toBasicString()}");
|
||||
|
||||
var owned_land_agent_action = player.getEntityAction<OwnedLandAgentAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(owned_land_agent_action, () => $"owned_land_agent_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
if (!owned_land_agent_action.tryGetOwnedLand(landMetaId, out var owned_land))
|
||||
{
|
||||
err_msg = $"Failed to tryGetOwnedLand() !!! : landMetaId:{landMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.OwnedLandNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, null, null);
|
||||
}
|
||||
|
||||
var owned_land_action = owned_land.getEntityAction<OwnedLandAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(owned_land_action, () => $"owned_land_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
owned_land_action.DeleteOwnedLand();
|
||||
|
||||
return (result, land, owned_land, land_doc_base);
|
||||
}
|
||||
}
|
||||
}
|
||||
130
GameServer/Entity/Land/Helper/LandNotifyHelper.cs
Normal file
130
GameServer/Entity/Land/Helper/LandNotifyHelper.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static ClientToGameMessage.Types;
|
||||
using static ServerMessage.Types;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class LandNotifyHelper
|
||||
{
|
||||
public static async Task<bool> send_S2C_NTF_LAND_INFOS(this Player player)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var land_manager = server_logic.getLandManager();
|
||||
|
||||
var ntf_packet = new ClientToGame();
|
||||
ntf_packet.Message = new ClientToGameMessage();
|
||||
ntf_packet.Message.NtfLandInfos = new GS2C_NTF_LAND_INFOS();
|
||||
|
||||
var land_infos = await land_manager.getLandInfos();
|
||||
foreach (var land_info in land_infos)
|
||||
{
|
||||
ntf_packet.Message.NtfLandInfos.LandInfos.Add(land_info.LandMetaId, land_info);
|
||||
}
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(player, ntf_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool broadcast_S2C_NTF_LAND_INFOS(LandInfo landInfo)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var users = server_logic.getPlayerManager().getUsers();
|
||||
var players = users.Values.ToArray();
|
||||
|
||||
if (players.Length == 0)
|
||||
return true;
|
||||
|
||||
var ntf_packet = new ClientToGame();
|
||||
ntf_packet.Message = new ClientToGameMessage();
|
||||
ntf_packet.Message.NtfLandInfos = new GS2C_NTF_LAND_INFOS();
|
||||
|
||||
ntf_packet.Message.NtfLandInfos.LandInfos.Add(landInfo.LandMetaId, landInfo);
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(players, ntf_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool broadcast_S2C_NTF_LAND_INFOS(List<LandInfo> landInfos)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var users = server_logic.getPlayerManager().getUsers();
|
||||
var players = users.Values.ToArray();
|
||||
|
||||
if (players.Length == 0)
|
||||
return true;
|
||||
|
||||
var ntf_packet = new ClientToGame();
|
||||
ntf_packet.Message = new ClientToGameMessage();
|
||||
ntf_packet.Message.NtfLandInfos = new GS2C_NTF_LAND_INFOS();
|
||||
|
||||
foreach (var landInfo in landInfos)
|
||||
{
|
||||
ntf_packet.Message.NtfLandInfos.LandInfos.Add(landInfo.LandMetaId, landInfo);
|
||||
}
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(players, ntf_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool send_GS2GS_NTF_MODIFY_LAND_INFO(List<LandInfo> landInfos)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var message = new ServerMessage();
|
||||
|
||||
message.NtfModifyLandInfo = new GS2GS_NTF_MODIFY_LAND_INFO();
|
||||
message.NtfModifyLandInfo.ExceptServerName = server_logic.getServerName();
|
||||
message.NtfModifyLandInfo.LandInfos.AddRange(landInfos);
|
||||
|
||||
var rabbit_mq = server_logic.getRabbitMqConnector() as RabbitMQ4Game;
|
||||
NullReferenceCheckHelper.throwIfNull(rabbit_mq, () => $"rabbit_mq is null !!!");
|
||||
|
||||
rabbit_mq.sendMessageToExchangeAllGame(message);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<bool> sendNtfModifyLandInfo(Land land)
|
||||
{
|
||||
var land_info = await land.toLandInfo();
|
||||
var land_infos = new List<LandInfo>();
|
||||
land_infos.Add(land_info);
|
||||
|
||||
// 현재 서버 유저
|
||||
broadcast_S2C_NTF_LAND_INFOS(land_info);
|
||||
|
||||
// 다른 서버
|
||||
send_GS2GS_NTF_MODIFY_LAND_INFO(land_infos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool sendNtfModifyLandInfos(List<LandInfo> landInfos)
|
||||
{
|
||||
broadcast_S2C_NTF_LAND_INFOS(landInfos);
|
||||
|
||||
send_GS2GS_NTF_MODIFY_LAND_INFO(landInfos);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
GameServer/Entity/Land/Land.cs
Normal file
40
GameServer/Entity/Land/Land.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class Land : EntityBase
|
||||
{
|
||||
public Land()
|
||||
: base(EntityType.Land)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
addEntityAttribute(new LandAttribute(this));
|
||||
|
||||
addEntityAction(new LandAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}, LandMetaId:{getOriginEntityAttribute<LandAttribute>()?.LandMetaId}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}, {getEntityAttribute<LandAttribute>()?.toBasicString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
290
GameServer/Entity/Land/LandCheat.cs
Normal file
290
GameServer/Entity/Land/LandCheat.cs
Normal file
@@ -0,0 +1,290 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
[ChatCommandAttribute("gainland", typeof(LandCheatGainLand), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
|
||||
internal class LandCheatGainLand : ChatCommandBase
|
||||
{
|
||||
public override async Task invoke(Player player, string token, string[] args)
|
||||
{
|
||||
Log.getLogger().info($"Call gainland !!! - {player.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
if (args.Length < 1)
|
||||
{
|
||||
err_msg = $"Not enough argument !!! : argCount:{args.Length} == 1 - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(args[0], out var land_meta_id))
|
||||
{
|
||||
err_msg = $"GainLand param parsing Error args : {args[0]}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var owned_land_agent_action = player.getEntityAction<OwnedLandAgentAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(owned_land_agent_action, () => $"owned_land_agent_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var owned_building_agent_action = player.getEntityAction<OwnedBuildingAgentAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(owned_building_agent_action, () => $"owned_building_agent_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var fn_gain_land = async delegate ()
|
||||
{
|
||||
// Land 획득
|
||||
(result, var land, var owned_land, var land_doc_base) = await LandHelper.tryGainLand(player, land_meta_id);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryGainLand() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(land, () => $"land is null !!! - {player.toBasicString()}");
|
||||
NullReferenceCheckHelper.throwIfNull(owned_land, () => $"owned_land is null !!! - {player.toBasicString()}");
|
||||
NullReferenceCheckHelper.throwIfNull(land_doc_base, () => $"land_doc_base is null !!! - {player.toBasicString()}");
|
||||
|
||||
var land_log_info = land.toLandLogInfo();
|
||||
var land_business_log = new LandBusinessLog(land_log_info);
|
||||
|
||||
// Land 종속 BuildingMetaId 얻기
|
||||
if (!MapManager.Instance.tryGetLandChildBuildingMetaId(land_meta_id, out var building_meta_id))
|
||||
{
|
||||
err_msg = $"Failed to tryGetLandChildBuildingMetaId() !!! - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Building 획득
|
||||
(result, var building, var owned_building, var building_doc_base) = await BuildingHelper.tryGainBuilding(player, building_meta_id);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryGainBuilding() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!! - {player.toBasicString()}");
|
||||
NullReferenceCheckHelper.throwIfNull(owned_building, () => $"owned_building is null !!! - {player.toBasicString()}");
|
||||
NullReferenceCheckHelper.throwIfNull(building_doc_base, () => $"building_doc_base is null !!! - {player.toBasicString()}");
|
||||
|
||||
var building_log_info = building.toBuildingLogInfo();
|
||||
var building_business_log = new BuildingBusinessLog(building_log_info);
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CheatCommandGainLand, server_logic.getDynamoDbClient());
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
batch.addQuery(new DBQEntityWrite(land_doc_base));
|
||||
batch.addQuery(new DBQEntityWrite(building_doc_base));
|
||||
}
|
||||
|
||||
batch.appendBusinessLog(land_business_log);
|
||||
batch.appendBusinessLog(building_business_log);
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// OwnedLand, OwnedBuilding Agent에 추가
|
||||
owned_land_agent_action.addOwnedLand(land_meta_id, owned_land);
|
||||
owned_building_agent_action.addOwnedBuilding(building_meta_id, owned_building);
|
||||
|
||||
// OwnedLand, OwnedBuilding Noti
|
||||
player.send_S2C_NTF_OWNED_LAND_INFOS();
|
||||
player.send_S2C_NTF_OWNED_BUILDING_INFOS();
|
||||
|
||||
// Land, Building 전서버 Noti
|
||||
await LandNotifyHelper.sendNtfModifyLandInfo(land);
|
||||
await BuildingNotifyHelper.sendNtfModifyBuildingInfo(building);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var transaction_name = "Cheat.GainLand";
|
||||
result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid(), TransactionIdType.PrivateContents, transaction_name, fn_gain_land);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()} - transactionName:{transaction_name}, {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ChatCommandAttribute("initmylandownership", typeof(LandCheatInitMyLandOwnership), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
|
||||
internal class LandCheatInitMyLandOwnership : ChatCommandBase
|
||||
{
|
||||
public override async Task invoke(Player player, string token, string[] args)
|
||||
{
|
||||
Log.getLogger().info($"Call initmylandownership !!! - {player.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
if (args.Length < 1)
|
||||
{
|
||||
err_msg = $"Not enough argument !!! : argCount:{args.Length} == 1 - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(args[0], out var argument_land_meta_id))
|
||||
{
|
||||
err_msg = $"InitMyLandOwnership param parsing Error args : {args[0]}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var owned_land_agent_action = player.getEntityAction<OwnedLandAgentAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(owned_land_agent_action, () => $"owned_land_agent_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var owned_building_agent_action = player.getEntityAction<OwnedBuildingAgentAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(owned_building_agent_action, () => $"owned_building_agent_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var fn_init_my_land_ownership = async delegate ()
|
||||
{
|
||||
var land_meta_ids = new List<int>();
|
||||
if (argument_land_meta_id == 0)
|
||||
{
|
||||
land_meta_ids = owned_land_agent_action.getOwnedLandMetaIds();
|
||||
}
|
||||
else
|
||||
{
|
||||
land_meta_ids.Add(argument_land_meta_id);
|
||||
}
|
||||
|
||||
var land_infos = new List<LandInfo>();
|
||||
var land_business_logs = new List<ILogInvoker>();
|
||||
var land_doc_bases = new List<DynamoDbDocBase>();
|
||||
var building_meta_ids = new List<int>();
|
||||
foreach (var land_meta_id in land_meta_ids)
|
||||
{
|
||||
(result, var land, var owned_land, var land_doc_base) = await LandHelper.tryInitMyLandOwnership(player, land_meta_id);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryInitMyLandOwnership() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(land, () => $"land is null !!! - {player.toBasicString()}");
|
||||
NullReferenceCheckHelper.throwIfNull(owned_land, () => $"owned_land is null !!! - {player.toBasicString()}");
|
||||
NullReferenceCheckHelper.throwIfNull(land_doc_base, () => $"land_doc_base is null !!! - {player.toBasicString()}");
|
||||
|
||||
var land_info = await land.toLandInfo();
|
||||
land_infos.Add(land_info);
|
||||
|
||||
var land_log_info = land.toLandLogInfo();
|
||||
var land_business_log = new LandBusinessLog(land_log_info);
|
||||
land_business_logs.Add(land_business_log);
|
||||
|
||||
land_doc_bases.Add(land_doc_base);
|
||||
|
||||
if (!MapManager.Instance.tryGetLandChildBuildingMetaId(land_meta_id, out var building_meta_id))
|
||||
{
|
||||
err_msg = $"Failed to tryGetLandChildBuildingMetaId() !!! - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
building_meta_ids.Add(building_meta_id);
|
||||
}
|
||||
|
||||
var building_infos = new List<BuildingInfo>();
|
||||
var building_business_logs = new List<ILogInvoker>();
|
||||
var building_doc_bases = new List<DynamoDbDocBase>();
|
||||
foreach (var building_meta_id in building_meta_ids)
|
||||
{
|
||||
(result, var building, var owned_building, var building_doc_base) = await BuildingHelper.tryInitMyBuildingOwnership(player, building_meta_id);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryInitMyLandOwnership() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(building, () => $"building is null !!! - {player.toBasicString()}");
|
||||
NullReferenceCheckHelper.throwIfNull(owned_building, () => $"owned_building is null !!! - {player.toBasicString()}");
|
||||
NullReferenceCheckHelper.throwIfNull(building_doc_base, () => $"building_doc_base is null !!! - {player.toBasicString()}");
|
||||
|
||||
var building_info = await building.toBuildingInfo();
|
||||
building_infos.Add(building_info);
|
||||
|
||||
var building_log_info = building.toBuildingLogInfo();
|
||||
var building_business_log = new BuildingBusinessLog(building_log_info);
|
||||
building_business_logs.Add(building_business_log);
|
||||
|
||||
building_doc_bases.Add(building_doc_base);
|
||||
}
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CheatCommandGainLand, server_logic.getDynamoDbClient());
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
batch.addQuery(new DBQEntityWrite(land_doc_bases));
|
||||
batch.addQuery(new DBQEntityWrite(building_doc_bases));
|
||||
}
|
||||
|
||||
batch.appendBusinessLogs(land_business_logs);
|
||||
batch.appendBusinessLogs(building_business_logs);
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// OwnedLand, OwnedBuilding Agent에서 제거
|
||||
foreach (var init_land_meta_id in land_meta_ids)
|
||||
{
|
||||
owned_land_agent_action.removeOwnedLand(init_land_meta_id);
|
||||
}
|
||||
|
||||
foreach (var init_building_meta_id in building_meta_ids)
|
||||
{
|
||||
owned_building_agent_action.removeOwnedBuilding(init_building_meta_id);
|
||||
}
|
||||
|
||||
// OwnedLand, OwnedBuilding Noti
|
||||
player.send_S2C_NTF_OWNED_LAND_INFOS();
|
||||
player.send_S2C_NTF_OWNED_BUILDING_INFOS();
|
||||
|
||||
// Land, Building 전서버 Noti
|
||||
LandNotifyHelper.sendNtfModifyLandInfos(land_infos);
|
||||
BuildingNotifyHelper.sendNtfModifyBuildingInfo(building_infos);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var transaction_name = "Cheat.InitMyLandOwnership";
|
||||
result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid(), TransactionIdType.PrivateContents, transaction_name, fn_init_my_land_ownership);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()} - transactionName:{transaction_name}, {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
2442
GameServer/Entity/LandAuction/Action/LandAuctionAction.cs
Normal file
2442
GameServer/Entity/LandAuction/Action/LandAuctionAction.cs
Normal file
File diff suppressed because it is too large
Load Diff
353
GameServer/Entity/LandAuction/Action/UserLandAuctionAction.cs
Normal file
353
GameServer/Entity/LandAuction/Action/UserLandAuctionAction.cs
Normal file
@@ -0,0 +1,353 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
||||
|
||||
using Amazon.S3.Model;
|
||||
using Amazon.DynamoDBv2.Model;
|
||||
using Amazon.DynamoDBv2;
|
||||
using Renci.SshNet.Security;
|
||||
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
|
||||
using META_ID = System.UInt32;
|
||||
using USER_GUID = System.String;
|
||||
using LAND_AUCTION_NUMBER = System.Int32;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
|
||||
|
||||
public class UserLandAuctionAction : EntityActionBase
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, LandAuctionRefundBidPrice> m_refund_bid_prices = new();
|
||||
|
||||
public UserLandAuctionAction(Player owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> tryLoadLandAuctionBidPriceAllFromDb()
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
(result, var read_docs) = await LandAuctionDbHelper.readLandAuctionRefundBidPriceDocsFromDb(owner);
|
||||
if(result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to readLandAuctionRefundBidPriceDocsFromDb() !!! : {result.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(read_docs, () => $"read_docs is null !!! - {owner.toBasicString()}");
|
||||
|
||||
foreach (var read_doc in read_docs)
|
||||
{
|
||||
var refund_bid_price = new LandAuctionRefundBidPrice(owner);
|
||||
var init_result = await refund_bid_price.onInit();
|
||||
if (init_result.isFail())
|
||||
{
|
||||
Log.getLogger().error(init_result.toBasicString());
|
||||
continue;
|
||||
}
|
||||
|
||||
var primary_key = read_doc.getPrimaryKey();
|
||||
if (false == m_refund_bid_prices.TryAdd(primary_key.SK, refund_bid_price))
|
||||
{
|
||||
err_msg = $"Failed to TryAdd() !!!, duplicated SK !!! : {primary_key.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
var refund_bid_price_action = refund_bid_price.getEntityAction<LandAuctionRefundBidPriceAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_action, () => $"refund_bid_price_action is null !!!");
|
||||
|
||||
var load_result = refund_bid_price_action.tryLoadRefundBidPriceFromDoc(read_doc);
|
||||
if (load_result.isFail())
|
||||
{
|
||||
Log.getLogger().error(load_result.toBasicString());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task updateRefundBidPriceAll()
|
||||
{
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
var redis_connector = server_logic.getRedisDb();
|
||||
|
||||
var fn_land_auction_bid_price_refund = async delegate ()
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var to_delete_refund_bid_prices = new List<LandAuctionRefundBidPrice>();
|
||||
var to_send_new_mail_docs = new List<DynamoDbDocBase>();
|
||||
|
||||
var refund_bid_prices = m_refund_bid_prices.Values.ToList();
|
||||
|
||||
foreach (var refund_bid_price in refund_bid_prices)
|
||||
{
|
||||
var refund_bid_price_action = refund_bid_price.getEntityAction<LandAuctionRefundBidPriceAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_action, () => $"refund_bid_price_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var update_result = await refund_bid_price_action.tryUpdateRefundBidPrice();
|
||||
if (update_result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryUpdateRefundBidPrice() !!! : {update_result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(true == refund_bid_price_action.isDeletable())
|
||||
{
|
||||
var key = LandAuctionRefundBidPriceDoc.makeCombinationKeyForSK(refund_bid_price_action.getLandMetaId(), refund_bid_price_action.getAuctionNumber());
|
||||
m_refund_bid_prices.Remove(key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "RefundBidPrice", fn_land_auction_bid_price_refund);
|
||||
if (result.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(Result, LandAuctionBidResult?)> tryBidLandAuction( LandAuctionBidType reqBidType
|
||||
, CurrencyType currencyType, double bidPrice
|
||||
, LandAuctionCheckResult checkResult )
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
var redis_connector = server_logic.getRedisDb();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var land_meta_id = (META_ID)checkResult.LandAuctionInfo.LandMetaId;
|
||||
var auction_number = checkResult.LandAuctionInfo.AuctionNumber;
|
||||
|
||||
var found_land_auction = LandAuctionManager.It.findActivitingLandAuction(land_meta_id);
|
||||
if( null == found_land_auction )
|
||||
{
|
||||
err_msg = $"Not found activiting LandAuction !!! : landMetaId:{land_meta_id} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandAuctionNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, null);
|
||||
}
|
||||
var land_auction_action = found_land_auction.getEntityAction<LandAuctionAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
// 1. 입찰 가능 여부를 체크 한다.
|
||||
result = land_auction_action.isBidableLandAuction(checkResult, currencyType, bidPrice);
|
||||
if (result.isFail()) { return (result, null); }
|
||||
|
||||
// 2. 금전 소모 가능 여부를 체크 한다.
|
||||
var money_action = owner.getEntityAction<MoneyAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(money_action, () => $"money_action is null !!! - {owner.toBasicString()}");
|
||||
result = await money_action.spendMoney(currencyType, bidPrice, useCaliumEvent:false);
|
||||
if(result.isFail()) { return (result, null); }
|
||||
|
||||
// 3. LandAuctionBidPriceDoc를 존재하는 지 체크하고, 없으면 생성 한다 !!!
|
||||
var bid_price_doc = new LandAuctionRefundBidPriceDoc(owner.getUserGuid(), land_meta_id, auction_number);
|
||||
result = await bid_price_doc.newDoc4Query();
|
||||
if (result.isFail()) { return (result, null); }
|
||||
result = await db_connector.createIfNotExist<LandAuctionRefundBidPriceDoc>(bid_price_doc
|
||||
, (bid_price_doc) =>
|
||||
{
|
||||
var bid_price_attrib = bid_price_doc.getAttrib<LandAuctionRefundBidPriceAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(bid_price_attrib, () => $"bid_price_attrib is null !!! - {owner.toBasicString()}");
|
||||
bid_price_attrib.LandMetaId = land_meta_id;
|
||||
bid_price_attrib.AuctionNumber = auction_number;
|
||||
bid_price_attrib.BidUserGuid = owner.getUserGuid();
|
||||
bid_price_attrib.BidCurrencyType = currencyType;
|
||||
}
|
||||
);
|
||||
if (result.isFail()) { return (result, null); }
|
||||
|
||||
// 4. 입찰을 시도 한다.
|
||||
( result, var bid_result ) = await land_auction_action.tryBidLandAuction( checkResult
|
||||
, owner
|
||||
, reqBidType
|
||||
, currencyType, bidPrice );
|
||||
if(result.isFail()) { return (result, null); }
|
||||
NullReferenceCheckHelper.throwIfNull(bid_result, () => $"bid_result is null !!! - {owner.toBasicString()}");
|
||||
|
||||
return (result, bid_result);
|
||||
}
|
||||
|
||||
public async Task completedRefundBidPrice(LandAuctionBidResult bidResult, QueryExecutorBase queryExecutorBase)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null");
|
||||
|
||||
var land_auction = bidResult.TargetLandAuction;
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction, () => $"land_auction is null - {owner.toBasicString()}");
|
||||
var curr_top_bidder = bidResult.CurrTopBidder;
|
||||
NullReferenceCheckHelper.throwIfNull(curr_top_bidder, () => $"curr_top_bidder is null - {owner.toBasicString()}");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var registry_attribute = land_auction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(registry_attribute, () => $"registry_attribute is null - {owner.toBasicString()}");
|
||||
|
||||
var land_meta_id = registry_attribute.LandMetaId;
|
||||
var auction_number = registry_attribute.AuctionNumber;
|
||||
|
||||
// 입찰자의 입찰 환급 처리 LandAuctionRefundBidPrice 객체를 생성 및 등록 한다.
|
||||
{
|
||||
(result, var refund_bid_price_doc) = await LandAuctionDbHelper.readLandAuctionRefundBidPriceDocFromDb(owner, land_meta_id, auction_number);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to readLandAuctionRefundBidPriceDocFromDb() !!! : {result.toBasicString()}, {land_auction.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_doc, () => $"refund_bid_price_doc is null - {owner.toBasicString()}");
|
||||
var refund_bid_price_attrib = refund_bid_price_doc.getAttrib<LandAuctionRefundBidPriceAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_attrib, () => $"refund_bid_price_attrib is null - {owner.toBasicString()}");
|
||||
|
||||
var key = LandAuctionRefundBidPriceDoc.makeCombinationKeyForSK(land_meta_id, auction_number);
|
||||
if (false == m_refund_bid_prices.TryGetValue(key, out var found_bid_price))
|
||||
{
|
||||
found_bid_price = new LandAuctionRefundBidPrice(owner);
|
||||
result = await found_bid_price.onInit();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to onInit() !!! : {result.toBasicString()}, {land_auction.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().fatal(err_msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_refund_bid_prices[key] = found_bid_price;
|
||||
}
|
||||
}
|
||||
|
||||
var refund_bid_price_attribute = found_bid_price.getEntityAttribute<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_attribute, () => $"refund_bid_price_attribute is null - {owner.toBasicString()}");
|
||||
|
||||
result = found_bid_price.copyDocToEntityAttributeForRefundBidPrice(refund_bid_price_attribute, refund_bid_price_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to copyDocToEntityAttributeForRefundBidPrice() !!! : {result.toBasicString()}, docType:{refund_bid_price_doc.getTypeName()}, {result.toBasicString()}, {land_auction.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().fatal(err_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 최고 입찰자와 차순위 입찰자의 비즈니스 로그를 작성 한다. !!!
|
||||
var bidder_caches = new List<LandAuctionTopBidderCache>();
|
||||
bidder_caches.Add(curr_top_bidder);
|
||||
if (null != bidResult.OldTopBidder) { bidder_caches.Add(bidResult.OldTopBidder); }
|
||||
|
||||
foreach (var bidder_cache in bidder_caches)
|
||||
{
|
||||
var target_user_guid = bidder_cache.HighestBidUserGuid;
|
||||
|
||||
(result, var refund_bid_price_doc) = await LandAuctionDbHelper.readLandAuctionRefundBidPriceDocFromDb(target_user_guid, land_meta_id, auction_number);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to readLandAuctionRefundBidPriceDocFromDb() !!! : {result.toBasicString()}, landMetaId:{land_meta_id}, auctionNumber:{auction_number}, bidUserGuid:{target_user_guid} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
continue;
|
||||
}
|
||||
if (null == refund_bid_price_doc)
|
||||
{
|
||||
err_msg = $"Not found LandAuctionRefundBidPriceDoc !!! : landMetaId:{land_meta_id}, auctionNumber:{auction_number} - {owner.toBasicString()}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
LandAuctionBusinessLogHelper.writeBusinessLogByLandAuctionBidPriceRefund(refund_bid_price_doc, registry_attribute.LandAuctionResult, queryExecutorBase);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<(Result, LandAuctionRefundBidPriceDoc?)> findRefundBidPriceDoc(META_ID landMetaId, LAND_AUCTION_NUMBER auctionNumber)
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
(result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<LandAuctionRefundBidPriceDoc>( owner.getUserGuid()
|
||||
, LandAuctionRefundBidPriceDoc.makeCombinationKeyForSK(landMetaId, auctionNumber) );
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to makePrimaryKey<LandAuctionRefundBidPriceDoc>() !!! : {result.toBasicString()} - landMetaId:{landMetaId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!!");
|
||||
|
||||
var query_config = db_client.makeQueryConfigForReadByPKSK(make_primary_key.PK, make_primary_key.SK);
|
||||
(result, var found_refund_bid_price_doc) = await db_client.simpleQueryDocTypeWithQueryOperationConfig<LandAuctionRefundBidPriceDoc>(query_config, false);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to parse simpleQueryDocTypeWithQueryOperationConfig<LandAuctionRefundBidPriceDoc>() !!! : {result.toBasicString()}, {make_primary_key.toBasicString()} - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, found_refund_bid_price_doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
|
||||
|
||||
using META_ID = System.UInt32;
|
||||
using META_TYPE = System.String;
|
||||
using USER_GUID = System.String;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public static class LandAuctionBusinessLogHelper
|
||||
{
|
||||
public static void writeBusinessLogByLandAuctionResult( LandAuction landAuction, LandAuctionWinningResult? winningResult
|
||||
, QueryExecutorBase queryExecutorBase )
|
||||
{
|
||||
var query_batch = queryExecutorBase.getQueryBatch();
|
||||
NullReferenceCheckHelper.throwIfNull(query_batch, () => $"query_batch is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
query_batch.appendBusinessLog(new LandAuctionBusinessLog(query_batch.getLogAction(), landAuction.toLandAuctionLogInfo(winningResult)));
|
||||
}
|
||||
|
||||
public static void writeBusinessLogByLandAuctionBid( LandAuction landAuction, LandAuctionBidResult bidResult
|
||||
, QueryExecutorBase queryExecutorBase)
|
||||
{
|
||||
var query_batch = queryExecutorBase.getQueryBatch();
|
||||
NullReferenceCheckHelper.throwIfNull(query_batch, () => $"query_batch is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
query_batch.appendBusinessLog(new LandAuctionBusinessLog(query_batch.getLogAction(), landAuction.toLandAuctionLogInfo(null)));
|
||||
query_batch.appendBusinessLog(new LandAuctionBidBusinessLog(query_batch.getLogAction(), landAuction.toLandAuctionBidLogInfo(bidResult)));
|
||||
}
|
||||
|
||||
public static void writeBusinessLogByLandAuctionBidPriceRefund( LandAuctionRefundBidPriceDoc refundBidPriceDoc, LandAuctionResult auctionResult
|
||||
, QueryExecutorBase queryExecutorBase )
|
||||
{
|
||||
var query_batch = queryExecutorBase.getQueryBatch();
|
||||
NullReferenceCheckHelper.throwIfNull(query_batch, () => $"query_batch is null !!! - {refundBidPriceDoc.toBasicString()}");
|
||||
|
||||
query_batch.appendBusinessLog(new LandAuctionBidPriceRefundBusinessLog(query_batch.getLogAction(), refundBidPriceDoc.toLandAuctionBidPriceRefundLogInfo(auctionResult)));
|
||||
}
|
||||
|
||||
public static void writeBusinessLogByLandAuctionBidPriceRefund( LandAuctionRefundBidPrice refundBidPrice, LandAuctionResult auctionResult
|
||||
, QueryExecutorBase queryExecutorBase )
|
||||
{
|
||||
var query_batch = queryExecutorBase.getQueryBatch();
|
||||
NullReferenceCheckHelper.throwIfNull(query_batch, () => $"query_batch is null !!! - {refundBidPrice.toBasicString()}");
|
||||
|
||||
query_batch.appendBusinessLog(new LandAuctionBidPriceRefundBusinessLog(query_batch.getLogAction(), refundBidPrice.toLandAuctionBidPriceRefundLogInfo(auctionResult)));
|
||||
}
|
||||
|
||||
public static void writeBusinessLogByLandAuctionActivity(LandAuctionActivityDoc activityDoc)
|
||||
{
|
||||
var activity_attrib = activityDoc.getAttrib<LandAuctionActivityAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(activity_attrib, () => $"activity_attrib is null !!!");
|
||||
|
||||
var log_action = new LogActionEx(LogActionType.LandAuctionActivity);
|
||||
var log_info = new LandAuctionActivityLogInfo();
|
||||
log_info.setLogProperty( activity_attrib.LandMetaId, activity_attrib.AuctionNumber
|
||||
, activityDoc.getPK(), activityDoc.getSK()
|
||||
, DateTimeHelper.Current);
|
||||
|
||||
var error_code = BusinessLogger.collectLog( GameServerApp.getServerLogic()
|
||||
, new LandAuctionActivityBusinessLog(log_action, log_info) );
|
||||
if(error_code.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to collectLog() !!! : {error_code.toBasicString()} - {log_info.getTypeName()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static LandAuctionBidPriceRefundLogInfo toLandAuctionBidPriceRefundLogInfo(this LandAuctionRefundBidPriceDoc refundBidPriceDoc, LandAuctionResult auctionResult)
|
||||
{
|
||||
var refund_bid_price_attrib = refundBidPriceDoc.getAttrib<LandAuctionRefundBidPriceAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_attrib, () => $"refund_bid_price_attrib is null !!! - {refundBidPriceDoc.toBasicString()}");
|
||||
|
||||
var log_info = new LandAuctionBidPriceRefundLogInfo();
|
||||
log_info.setLogProperty( refund_bid_price_attrib.LandMetaId, refund_bid_price_attrib.AuctionNumber
|
||||
, refundBidPriceDoc.getPK(), refundBidPriceDoc.getSK()
|
||||
, refund_bid_price_attrib.BidUserGuid
|
||||
, refund_bid_price_attrib.LastBidType, refund_bid_price_attrib.BidCurrencyType, refund_bid_price_attrib.LastBidPrice
|
||||
, auctionResult
|
||||
, refund_bid_price_attrib.RefundableNormalBidPrice, refund_bid_price_attrib.RefundableBlindBidPrice);
|
||||
|
||||
return log_info;
|
||||
}
|
||||
|
||||
public static LandAuctionBidPriceRefundLogInfo toLandAuctionBidPriceRefundLogInfo(this LandAuctionRefundBidPrice refundBidPrice, LandAuctionResult auctionResult)
|
||||
{
|
||||
var refund_bid_price_attribute = refundBidPrice.getEntityAttribute<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_attribute, () => $"refund_bid_price_attribute is null !!! - {refundBidPrice.toBasicString()}");
|
||||
|
||||
var origin_refund_bid_price_doc = refund_bid_price_attribute.getOriginDocBase<LandAuctionRefundBidPriceAttribute>() as LandAuctionRefundBidPriceDoc;
|
||||
NullReferenceCheckHelper.throwIfNull(origin_refund_bid_price_doc, () => $"origin_refund_bid_price_doc is null !!! - {refundBidPrice.toBasicString()}");
|
||||
|
||||
var log_info = new LandAuctionBidPriceRefundLogInfo();
|
||||
log_info.setLogProperty( refund_bid_price_attribute.LandMetaId, refund_bid_price_attribute.AuctionNumber
|
||||
, origin_refund_bid_price_doc.getPK(), origin_refund_bid_price_doc.getSK()
|
||||
, refund_bid_price_attribute.BidUserGuid
|
||||
, refund_bid_price_attribute.LastBidType, refund_bid_price_attribute.BidCurrencyType, refund_bid_price_attribute.LastBidPrice
|
||||
, auctionResult
|
||||
, refund_bid_price_attribute.RefundableNormalBidPrice, refund_bid_price_attribute.RefundableBlindBidPrice );
|
||||
|
||||
return log_info;
|
||||
}
|
||||
|
||||
public static LandAuctionBidLogInfo toLandAuctionBidLogInfo(this LandAuction landAuction, LandAuctionBidResult bidResult)
|
||||
{
|
||||
var highest_bid_user_attribute = landAuction.getEntityAttribute<LandAuctionHighestBidUserAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(highest_bid_user_attribute, () => $"highest_bid_user_attribute is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var origin_highest_bid_user_doc = highest_bid_user_attribute.getOriginDocBase<LandAuctionHighestBidUserAttribute>() as LandAuctionHighestBidUserDoc;
|
||||
NullReferenceCheckHelper.throwIfNull(origin_highest_bid_user_doc, () => $"origin_highest_bid_user_doc is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var log_info = new LandAuctionBidLogInfo();
|
||||
log_info.setLogProperty( highest_bid_user_attribute.LandMetaId, highest_bid_user_attribute.AuctionNumber
|
||||
, origin_highest_bid_user_doc.getPK(), origin_highest_bid_user_doc.getSK()
|
||||
, bidResult.CurrentBidType
|
||||
, highest_bid_user_attribute.BidCurrencyType
|
||||
, highest_bid_user_attribute.HighestBidPrice, highest_bid_user_attribute.HighestBidUserGuid, highest_bid_user_attribute.HighestBidUserNickname
|
||||
, highest_bid_user_attribute.NormalHighestBidPrice, highest_bid_user_attribute.NormalHighestBidUserGuid, highest_bid_user_attribute.NormalHighestBidUserNickname
|
||||
, bidResult.BidTime );
|
||||
|
||||
return log_info;
|
||||
}
|
||||
|
||||
public static LandAuctionLogInfo toLandAuctionLogInfo(this LandAuction landAuction, LandAuctionWinningResult? winningResult)
|
||||
{
|
||||
var registry_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(registry_attribute, () => $"registry_attribute is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var winning_user_guid = string.Empty;
|
||||
var winning_user_nickname = string.Empty;
|
||||
|
||||
if(null != winningResult)
|
||||
{
|
||||
winning_user_guid = winningResult.WinningUserGuid;
|
||||
winning_user_guid = winningResult.WinningUserNickname;
|
||||
}
|
||||
|
||||
var origin_registry_doc = registry_attribute.getOriginDocBase<LandAuctionRegistryAttribute>() as LandAuctionRegistryDoc;
|
||||
NullReferenceCheckHelper.throwIfNull(origin_registry_doc, () => $"origin_registry_doc is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var log_info = new LandAuctionLogInfo();
|
||||
log_info.setLogProperty( registry_attribute.LandMetaId, registry_attribute.AuctionNumber
|
||||
, origin_registry_doc.getPK(), origin_registry_doc.getSK()
|
||||
, registry_attribute.BidCurrencyType
|
||||
, registry_attribute.BidStartPrice
|
||||
, registry_attribute.AuctionReservationNoticeStartTime
|
||||
, registry_attribute.AuctionStartTime
|
||||
, registry_attribute.AuctionEndTime
|
||||
, registry_attribute.IsCancelAuction
|
||||
, registry_attribute.RegisteredVersionTime
|
||||
, registry_attribute.LandAuctionState
|
||||
, registry_attribute.LandAuctionResult
|
||||
, winning_user_guid, winning_user_nickname
|
||||
, registry_attribute.ProcessVersionTime );
|
||||
|
||||
return log_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
479
GameServer/Entity/LandAuction/Helper/LandAuctionCacheHelper.cs
Normal file
479
GameServer/Entity/LandAuction/Helper/LandAuctionCacheHelper.cs
Normal file
@@ -0,0 +1,479 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using StackExchange.Redis;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.Cache;
|
||||
|
||||
|
||||
using META_ID = System.UInt32;
|
||||
using REQUESTOR_ID = System.String;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public static class LandAuctionCacheHelper
|
||||
{
|
||||
public static async Task<Result> trySaveToCache(this LandAuction landAuction, REQUESTOR_ID requestorId)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
|
||||
var result = new Result();
|
||||
|
||||
var land_auction_action = landAuction.getEntityAction<LandAuctionAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var registry_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(registry_attribute, () => $"registry_attribute is null !!! - {landAuction.toBasicString()}");
|
||||
var highest_bid_user_attribute = landAuction.getEntityAttribute<LandAuctionHighestBidUserAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(highest_bid_user_attribute, () => $"highest_bid_user_attribute is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var land_auction_cache = new LandAuctionCache();
|
||||
land_auction_cache.LandMetaId = registry_attribute.LandMetaId;
|
||||
land_auction_cache.AuctionNumber = registry_attribute.AuctionNumber;
|
||||
|
||||
land_auction_cache.LandAuctionState = registry_attribute.LandAuctionState;
|
||||
land_auction_cache.LandAuctionResult = registry_attribute.LandAuctionResult;
|
||||
land_auction_cache.ProcessVersionTime = registry_attribute.ProcessVersionTime;
|
||||
|
||||
var land_auction_cache_request = new LandAuctionCacheRequest(land_auction_cache, redis_connector);
|
||||
result = await land_auction_cache_request.upsertLandAuction(DateTimeHelper.toRemainingTimeMin(registry_attribute.AuctionEndTime));
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (LandAuctionState.Started == land_auction_cache.LandAuctionState)
|
||||
{
|
||||
await landAuction.tryRemoveLandAuctionTopBidderBlockFromCache();
|
||||
}
|
||||
|
||||
land_auction_action.resetCacheSaveStep();
|
||||
|
||||
var is_success = await landAuction.tryReleaseWriteLockWithLandAuction(requestorId);
|
||||
if (false == is_success)
|
||||
{
|
||||
var err_msg = $"Failed to tryReleaseWriteLockWithLandAuction() !!! - {landAuction.toBasicString()}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
}
|
||||
|
||||
Log.getLogger().debug($"Called trySaveToCache() - {landAuction.toBasicString()}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<bool> tryAcquireWriteLockWithLandAuctionBidders(this LandAuction landAuction, REQUESTOR_ID requestorId, Int16 ttlSec)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor();
|
||||
|
||||
var land_auction_registry_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_registry_attribute, () => $"land_auction_registry_attribute is null !!! - requestorId:{requestorId}");
|
||||
|
||||
var land_meta_id = land_auction_registry_attribute.LandMetaId;
|
||||
|
||||
var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector);
|
||||
|
||||
var lock_key = $"lock:{bid_price_order_cache_request.toKey()}";
|
||||
var locker_id = $"locker_id:{requestorId}";
|
||||
|
||||
var is_success = await redis_lua_executor.tryAcquireLock(lock_key, locker_id, ttlSec);
|
||||
if (false == is_success)
|
||||
{
|
||||
var err_msg = $"Failed to tryAcquireLock() !!! : LockKey:{lock_key}, LockerId:{locker_id}, TTLSec:{ttlSec} - {landAuction.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<bool> tryReleaseWriteLockWithLandAuctionBidders(this LandAuction landAuction, REQUESTOR_ID requestorId)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor();
|
||||
|
||||
var land_auction_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - requestorId:{requestorId}");
|
||||
|
||||
var land_meta_id = land_auction_attribute.LandMetaId;
|
||||
|
||||
var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector);
|
||||
|
||||
var lock_key = $"lock:{bid_price_order_cache_request.toKey()}";
|
||||
var locker_id = $"locker_id:{requestorId}";
|
||||
|
||||
var is_success = await redis_lua_executor.tyrReleaseLock(lock_key, locker_id);
|
||||
if (false == is_success)
|
||||
{
|
||||
var err_msg = $"Failed to tyrReleaseLock() !!! : LockKey:{lock_key}, LockerId:{locker_id} - {landAuction.toBasicString()}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<(bool, LandAuctionTopBidderCache?, LandAuctionTopBidderCache?, bool)> tryRankLandAuctionTopBidderCache(this LandAuction landAuction, REQUESTOR_ID requestorId, double bidPrice)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor();
|
||||
|
||||
var land_auction_action = landAuction.getEntityAction<LandAuctionAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - requestorId:{requestorId}");
|
||||
|
||||
var land_meta_id = land_auction_action.getLandMetaId();
|
||||
|
||||
var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector);
|
||||
|
||||
( var is_success
|
||||
, var curr_ranker_id, var curr_ranker_score
|
||||
, var old_ranker_id, var old_ranker_score
|
||||
, var is_top_change ) = await redis_lua_executor.tryPlaceTopRankOnly( bid_price_order_cache_request.toKey()
|
||||
, requestorId
|
||||
, bidPrice, bid_price_order_cache_request.toBlockKey());
|
||||
if (false == is_success)
|
||||
{
|
||||
var err_msg = $"Failed to tryPlaceTopRankOnly() !!! : {bid_price_order_cache_request.toKeyAll()} - {landAuction.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (false, null, null, false);
|
||||
}
|
||||
|
||||
var curr_top_bidder = new LandAuctionTopBidderCache();
|
||||
curr_top_bidder.LandMetaId = land_meta_id;
|
||||
curr_top_bidder.HighestBidUserGuid = curr_ranker_id;
|
||||
curr_top_bidder.HighestBidPrice = curr_ranker_score;
|
||||
|
||||
if (true == is_top_change)
|
||||
{
|
||||
if(false == old_ranker_id.isNullOrWhiteSpace())
|
||||
{
|
||||
var old_top_bidder = new LandAuctionTopBidderCache();
|
||||
old_top_bidder.LandMetaId = land_meta_id;
|
||||
old_top_bidder.HighestBidUserGuid = old_ranker_id;
|
||||
old_top_bidder.HighestBidPrice = old_ranker_score;
|
||||
|
||||
return (true, curr_top_bidder, old_top_bidder, is_top_change);
|
||||
}
|
||||
}
|
||||
|
||||
return (true, curr_top_bidder, null, is_top_change);
|
||||
}
|
||||
|
||||
public static async Task<(bool, LandAuctionTopBidderCache?)> tryGetLandAuctionTopBidderCacheWithBlock(this LandAuction landAuction)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor();
|
||||
|
||||
var land_auction_action = landAuction.getEntityAction<LandAuctionAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var land_meta_id = land_auction_action.getLandMetaId();
|
||||
|
||||
var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector);
|
||||
|
||||
( var is_success
|
||||
, var is_top_found
|
||||
, var top_ranker_id, var top_ranker_score ) = await redis_lua_executor.tryGetTopRankAndSetBlock( bid_price_order_cache_request.toKey()
|
||||
, bid_price_order_cache_request.toBlockKey() );
|
||||
if (false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to tryGetTopRankAndSetBlock() !!! : {bid_price_order_cache_request.toKeyAll()} - {landAuction.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
if (true == is_top_found)
|
||||
{
|
||||
var curr_top_bidder = new LandAuctionTopBidderCache();
|
||||
curr_top_bidder.LandMetaId = land_meta_id;
|
||||
curr_top_bidder.HighestBidUserGuid = top_ranker_id;
|
||||
curr_top_bidder.HighestBidPrice = top_ranker_score;
|
||||
|
||||
return (true, curr_top_bidder);
|
||||
}
|
||||
|
||||
return (true, null);
|
||||
}
|
||||
|
||||
public static async Task<(Result, LandAuctionTopBidderCache?)> tryGetLandAuctionTopBidderCache(this LandAuction landAuction)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
var redis_db = redis_connector.getDatabase();
|
||||
NullReferenceCheckHelper.throwIfNull(redis_db, () => $"redis_db is null !!!");
|
||||
|
||||
var land_auction_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!!");
|
||||
|
||||
var top_bidder = new LandAuctionTopBidderCache();
|
||||
var land_meta_id = land_auction_attribute.LandMetaId;
|
||||
|
||||
var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector);
|
||||
|
||||
try
|
||||
{
|
||||
var top_ranker = await redis_db.SortedSetRangeByRankWithScoresAsync(bid_price_order_cache_request.toKey(), 0, 0, Order.Descending);
|
||||
if (top_ranker.Length == 0)
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
top_bidder.LandMetaId = land_meta_id;
|
||||
top_bidder.HighestBidUserGuid = top_ranker[0].Element.ToString();
|
||||
top_bidder.HighestBidPrice = top_ranker[0].Score;
|
||||
|
||||
return (result, top_bidder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
err_msg = $"Exception !!!, Failed to perfom in tryGetLandAuctionTopBidderCache() !!! : exception:{e}, errorCode:{error_code}, key:{bid_price_order_cache_request.toKey()} - {landAuction.toBasicString()}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
public static async Task<bool> tryRemoveLandAuctionTopBidderBlockFromCache(this LandAuction landAuction)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor();
|
||||
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var land_auction_action = landAuction.getEntityAction<LandAuctionAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var land_meta_id = land_auction_action.getLandMetaId();
|
||||
|
||||
var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector);
|
||||
|
||||
var is_success = await redis_lua_executor.tryRemoveTopRankAndBlock( bid_price_order_cache_request.toKey()
|
||||
, bid_price_order_cache_request.toBlockKey() );
|
||||
if (false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to tryRemoveTopRankAndBlock() !!! : {bid_price_order_cache_request.toKeyAll()} - {landAuction.toBasicString()}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<bool> isExistTopBidderFromCache(this LandAuction landAuction)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
|
||||
var land_auction_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var land_meta_id = land_auction_attribute.LandMetaId;
|
||||
|
||||
var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector);
|
||||
|
||||
var is_exist_key = await bid_price_order_cache_request.isExistKey();
|
||||
if (false == is_exist_key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<bool> IsExistLandAuctionFromCache(this LandAuction landAuction, REQUESTOR_ID requestorId)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor();
|
||||
|
||||
var land_auction_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - requstorId:{requestorId}");
|
||||
|
||||
var land_meta_id = land_auction_attribute.LandMetaId;
|
||||
|
||||
var land_auction_cache_request = new LandAuctionCacheRequest(land_meta_id, redis_connector);
|
||||
|
||||
var is_exist_key = await land_auction_cache_request.isExistKey();
|
||||
if (false == is_exist_key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<(bool, string)> tryGetLandAuctionWithWriteLock(this LandAuction landAuction, REQUESTOR_ID requestorId, Int16 ttlSec)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor();
|
||||
|
||||
var land_auction_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - requstorId:{requestorId}");
|
||||
|
||||
var land_meta_id = land_auction_attribute.LandMetaId;
|
||||
|
||||
var land_auction_cache_request = new LandAuctionCacheRequest(land_meta_id, redis_connector);
|
||||
|
||||
var lock_key = $"lock:{land_auction_cache_request.toKey()}";
|
||||
var locker_id = $"locker_id:{requestorId}";
|
||||
|
||||
(var is_success, var read_data) = await redis_lua_executor.tryReadWithLock( lock_key, locker_id
|
||||
, land_auction_cache_request.toKey(), ttlSec );
|
||||
if (false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to tryReadWithLock() !!! : LockKey:{land_auction_cache_request.toKey()}, LockerId:{locker_id}, TTLSec:{ttlSec} - {landAuction.toBasicString()}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
|
||||
return (false, string.Empty);
|
||||
}
|
||||
if(null == read_data)
|
||||
{
|
||||
return (true, string.Empty);
|
||||
}
|
||||
|
||||
return (true, read_data);
|
||||
}
|
||||
|
||||
public static async Task<bool> tryAcquireWriteLockWithLandAuction(this LandAuction landAuction, REQUESTOR_ID requestorId, Int16 ttlSec)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor();
|
||||
|
||||
var land_auction_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - requestorId:{requestorId}");
|
||||
|
||||
var land_meta_id = land_auction_attribute.LandMetaId;
|
||||
|
||||
var land_auction_cache_request = new LandAuctionCacheRequest(land_meta_id, redis_connector);
|
||||
|
||||
var lock_key = $"lock:{land_auction_cache_request.toKey()}";
|
||||
var locker_id = $"locker_id:{requestorId}";
|
||||
|
||||
var is_success = await redis_lua_executor.tryAcquireLock(lock_key, locker_id, ttlSec);
|
||||
if (false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to tryAcquireLock() !!! : LockKey:{land_auction_cache_request.toKey()}, LockerId:{locker_id}, TTLSec:{ttlSec} - {landAuction.toBasicString()}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<bool> tryReleaseWriteLockWithLandAuction(this LandAuction landAuction, REQUESTOR_ID requestorid)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor();
|
||||
|
||||
var land_auction_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - requstorId:{requestorid}");
|
||||
|
||||
var land_meta_id = land_auction_attribute.LandMetaId;
|
||||
|
||||
var land_auction_cache_request = new LandAuctionCacheRequest(land_meta_id, redis_connector);
|
||||
|
||||
var lock_key = $"lock:{land_auction_cache_request.toKey()}";
|
||||
var locker_id = $"locker_id:{requestorid}";
|
||||
|
||||
var is_success = await redis_lua_executor.tyrReleaseLock(lock_key, locker_id);
|
||||
if (false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to tyrReleaseLock() !!! : LockKey:{land_auction_cache_request.toKey()}, LockerId:{locker_id} - {landAuction.toBasicString()}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<bool> tryAcquireWriteLockWithLandAuctionReservation(REQUESTOR_ID requestorId, Int16 ttlSec)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor();
|
||||
|
||||
var lock_key = $"land_auction_reservation:write_lock";
|
||||
var locker_id = $"land_auction_reservation:locker_id:{requestorId}";
|
||||
|
||||
var is_success = await redis_lua_executor.tryAcquireLock(lock_key, locker_id, ttlSec);
|
||||
if (false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to tryAcquireLock() !!! : LockKey:{lock_key}, LockerId:{locker_id}, TTLSec:{ttlSec} - requstorId:{requestorId}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static async Task<bool> tryReleaseWriteLockWithLandAuctionReservation(REQUESTOR_ID requestorId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisDb();
|
||||
var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor();
|
||||
|
||||
var lock_key = $"land_auction_reservation:write_lock";
|
||||
var locker_id = $"land_auction_reservation:locker_id:{requestorId}";
|
||||
|
||||
var is_success = await redis_lua_executor.tyrReleaseLock(lock_key, locker_id);
|
||||
if (false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to tyrReleaseLock() !!! : LockKey:{lock_key}, LockerId:{locker_id} - requstorId:{requestorId}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
499
GameServer/Entity/LandAuction/Helper/LandAuctionDbHelper.cs
Normal file
499
GameServer/Entity/LandAuction/Helper/LandAuctionDbHelper.cs
Normal file
@@ -0,0 +1,499 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using Amazon.DynamoDBv2.Model;
|
||||
using Amazon.DynamoDBv2;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using static ServerCommon.MetaHelper;
|
||||
|
||||
|
||||
using META_ID = System.UInt32;
|
||||
using USER_GUID = System.String;
|
||||
using LAND_AUCTION_NUMBER = System.Int32;
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public static class LandAuctionDbHelper
|
||||
{
|
||||
public static async Task<(Result, bool)> isExistHighestBidderFromDb(this LandAuction landAuction, USER_GUID toCheckHighestBidUserGuid, double toCheckHighestBidPrice)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var registry_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(registry_attribute, () => $"registry_attribute is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var highest_bid_user_doc = new LandAuctionHighestBidUserDoc(registry_attribute.LandMetaId, registry_attribute.AuctionNumber);
|
||||
|
||||
var get_request = new TransactGetItem
|
||||
{
|
||||
Get = new Get
|
||||
{
|
||||
TableName = db_connector.getTableFullName(highest_bid_user_doc.TableName),
|
||||
Key = highest_bid_user_doc.getPrimaryKey().toKeyWithAttributeValue()
|
||||
}
|
||||
};
|
||||
(var result, var found_highest_bid_user_item_doc) = await db_connector.simpleQueryTransactReadDocWithItemRequest<LandAuctionHighestBidUserDoc>(get_request, isFailOnEmptyData: false);
|
||||
if (result.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to simpleQueryTransactReadDocWithItemRequest<LandAuctionHighestBidUserDoc>() !!! : {get_request.Get.toBasicString()} - {landAuction.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, false);
|
||||
}
|
||||
if( null == found_highest_bid_user_item_doc)
|
||||
{
|
||||
var err_msg = $"Not found LandAuctionHighestBidUserDoc at simpleQueryTransactReadDocWithItemRequest<LandAuctionHighestBidUserDoc>() !!! : {get_request.Get.toBasicString()} - {landAuction.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, false);
|
||||
}
|
||||
|
||||
var heighest_bid_user_attrib = found_highest_bid_user_item_doc.getAttrib<LandAuctionHighestBidUserAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(heighest_bid_user_attrib, () => $"heighest_bid_user_attrib is null !!! - {landAuction.toBasicString()}");
|
||||
if ( heighest_bid_user_attrib.HighestBidUserGuid == toCheckHighestBidUserGuid
|
||||
&& heighest_bid_user_attrib.HighestBidPrice == toCheckHighestBidPrice )
|
||||
{
|
||||
return (result, true);
|
||||
}
|
||||
|
||||
return (result, false);
|
||||
}
|
||||
|
||||
public static async Task<(Result, LandAuctionHighestBidUserDoc?)> tryGetLandAuctionHighestBidUserDoc(this LandAuction landAuction, META_ID landMetaId, LAND_AUCTION_NUMBER auctionNumber)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
(result, var found_highest_bid_user_doc) = await readLandAuctionHighestBidUserDocFromDb(landMetaId, auctionNumber);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to readLandAuctionHighestBidUserDocFromDb() !!! : {result.toBasicString()} - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, found_highest_bid_user_doc);
|
||||
}
|
||||
|
||||
public static async Task<Result> tryLoadLandAuctionActivityDoc(this LandAuction landAuction, META_ID landMetaId)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var activity_attribute = landAuction.getEntityAttribute<LandAuctionActivityAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(activity_attribute, () => $"activity_attribute is null !!! - landMetaId:{landMetaId}");
|
||||
|
||||
(result, var found_activity_doc) = await readLandAuctionActivityDocFromDb(landMetaId);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to readLandAuctionActivityDocFromDb() !!! : {result.toBasicString()} - landMetaId:{landMetaId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(found_activity_doc, () => $"found_activity_doc is null !!! - landMetaId:{landMetaId}");
|
||||
|
||||
result = await landAuction.copyDocToEntityAttributeForLandAuction(activity_attribute, found_activity_doc, false);
|
||||
if(result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to copyDocToEntityAttributeForLandAuction() !!! : {result.toBasicString()} - landMetaId:{landMetaId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<Result> tryLoadLandAuctionRegistryDoc(this LandAuction landAuction, META_ID landMetaId, LAND_AUCTION_NUMBER auctionNumber)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var registry_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(registry_attribute, () => $"registry_attribute is null !!! - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}");
|
||||
|
||||
var auction_aution = landAuction.getEntityAction<LandAuctionAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(auction_aution, () => $"auction_aution is null !!! - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}");
|
||||
|
||||
(result, var found_registry_doc) = await readLandAuctionRegistryDocFromDb(landMetaId, auctionNumber);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to parse readLandAuctionRegistryDocFromDb() !!! : {result.toBasicString()} - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(found_registry_doc, () => $"found_registry_doc is null !!!");
|
||||
|
||||
result = await landAuction.copyDocToEntityAttributeForLandAuction(registry_attribute, found_registry_doc, false);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to copyDocToEntityAttributeForLandAuction() !!! : {result.toBasicString()} - landMetaId:{landMetaId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<(Result, bool)> tryLoadLandAuctionHighestBidUserDoc(this LandAuction landAuction, META_ID landMetaId, LAND_AUCTION_NUMBER auctionNumber)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var highest_bid_user_attribute = landAuction.getEntityAttribute<LandAuctionHighestBidUserAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(highest_bid_user_attribute, () => $"highest_bid_user_attribute is null !!! - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}");
|
||||
|
||||
(result, var found_highest_bid_user_doc) = await readLandAuctionHighestBidUserDocFromDb(landMetaId, auctionNumber);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to parse readLandAuctionHighestBidUserDocFromDb() !!! : {result.toBasicString()} - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, false);
|
||||
}
|
||||
|
||||
if (null != found_highest_bid_user_doc)
|
||||
{
|
||||
result = await landAuction.copyDocToEntityAttributeForLandAuction(highest_bid_user_attribute, found_highest_bid_user_doc, false);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to copyDocToEntityAttributeForLandAuction() !!! : {result.toBasicString()} - landMetaId:{landMetaId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, false);
|
||||
}
|
||||
}
|
||||
|
||||
return (result, false);
|
||||
}
|
||||
|
||||
public static async Task<Result> tryFillupLandAuctionActivityFromDb(this LandAuction landAuction, META_ID landMetaId)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var activity_attribute = landAuction.getEntityAttribute<LandAuctionActivityAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(activity_attribute, () => $"activity_attribute is null !!! - landMetaId:{landMetaId}");
|
||||
|
||||
(result, var found_activity_doc) = await readLandAuctionActivityDocFromDb(landMetaId);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to readLandAuctionActivityDocFromDb() !!! : {result.toBasicString()} - landMetaId:{landMetaId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(found_activity_doc, () => $"found_activity_doc is null !!!");
|
||||
|
||||
result = await landAuction.copyDocToEntityAttributeForLandAuction(activity_attribute, found_activity_doc, true);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to copyDocToEntityAttributeForLandAuction() !!! : {result.toBasicString()} - landMetaId:{landMetaId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<Result> tryFillupLandAuctionRegistryFromDb(this LandAuction landAuction, META_ID landMetaId, LAND_AUCTION_NUMBER auctionNumber)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var registry_attribute = landAuction.getEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(registry_attribute, () => $"land_auction_registry_attribute is null !!! - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}");
|
||||
|
||||
(result, var found_registry_doc) = await readLandAuctionRegistryDocFromDb(landMetaId, auctionNumber);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to parse readLandAuctionRegistryDocFromDb() !!! : {result.toBasicString()} - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(found_registry_doc, () => $"found_registry_doc is null !!!");
|
||||
|
||||
result = await landAuction.copyDocToEntityAttributeForLandAuction(registry_attribute, found_registry_doc, true);
|
||||
if(result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<(Result, List<LandAuctionActivityDoc>?)> readLandAuctionActivityDocsFromDb()
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
(result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<LandAuctionActivityDoc>(DynamoDbClient.PK_GLOBAL);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to makePrimaryKey<LandAuctionActivityDoc>() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!!");
|
||||
|
||||
var query_config = db_connector.makeQueryConfigForReadByPKOnly(make_primary_key.PK);
|
||||
(result, var found_land_auction_activity_docs) = await db_connector.simpleQueryDocTypesWithQueryOperationConfig<LandAuctionActivityDoc>(query_config, false);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypesWithQueryOperationConfig<LandAuctionActivityDoc>() !!! : {result.toBasicString()}, {make_primary_key.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(found_land_auction_activity_docs, () => $"found_land_auction_activity_docs is null !!!");
|
||||
|
||||
return (result, found_land_auction_activity_docs);
|
||||
}
|
||||
|
||||
public static async Task<(Result, LandAuctionActivityDoc?)> readLandAuctionActivityDocFromDb(META_ID landMetaId, bool isFailOnEmptyDoc = true)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
(result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<LandAuctionActivityDoc>(DynamoDbClient.PK_GLOBAL, landMetaId.ToString());
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to makePrimaryKey<LandAuctionActivityDoc>() !!! : {result.toBasicString()} - landMetaId:{landMetaId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!!");
|
||||
|
||||
var query_config = db_connector.makeQueryConfigForReadByPKSK(make_primary_key.PK, make_primary_key.SK);
|
||||
(result, var found_land_auction_activity_doc) = await db_connector.simpleQueryDocTypeWithQueryOperationConfig<LandAuctionActivityDoc>(query_config, isFailOnEmptyDoc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypeWithQueryOperationConfig<LandAuctionActivityDoc>() !!! : {result.toBasicString()}, {make_primary_key.toBasicString()} - landMetaId:{landMetaId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, found_land_auction_activity_doc);
|
||||
}
|
||||
|
||||
public static async Task<(Result, LandAuctionRegistryDoc?)> readLandAuctionRegistryDocFromDb(META_ID landMetaId, LAND_AUCTION_NUMBER auctionNumber, bool isFailOnEmptyDoc = true)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
(result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<LandAuctionRegistryDoc>( DynamoDbClient.PK_GLOBAL
|
||||
, LandAuctionRegistryDoc.makeCombinationKeyForSK(landMetaId, auctionNumber));
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to makePrimaryKey<LandAuctionRegistryDoc>() !!! : {result.toBasicString()} - landMetaId:{landMetaId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!!");
|
||||
|
||||
var query_config = db_connector.makeQueryConfigForReadByPKSK(make_primary_key.PK, make_primary_key.SK);
|
||||
(result, var found_land_auction_registry_doc) = await db_connector.simpleQueryDocTypeWithQueryOperationConfig<LandAuctionRegistryDoc>(query_config, isFailOnEmptyDoc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypeWithQueryOperationConfig<LandAuctionRegistryDoc>() !!! : {result.toBasicString()}, {make_primary_key.toBasicString()} - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, found_land_auction_registry_doc);
|
||||
}
|
||||
|
||||
public static async Task<(Result, LandAuctionHighestBidUserDoc?)> readLandAuctionHighestBidUserDocFromDb(META_ID landMetaId, LAND_AUCTION_NUMBER auctionNumber)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
(result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<LandAuctionHighestBidUserDoc>( DynamoDbClient.PK_GLOBAL
|
||||
, LandAuctionHighestBidUserDoc.makeCombinationKeyForSK(landMetaId, auctionNumber) );
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to makePrimaryKey<LandAuctionHighestBidUserDoc>() !!! : {result.toBasicString()} - landMetaId:{landMetaId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!!");
|
||||
|
||||
var query_config = db_connector.makeQueryConfigForReadByPKSK(make_primary_key.PK, make_primary_key.SK);
|
||||
(result, var found_land_auction_highest_bid_user_doc) = await db_connector.simpleQueryDocTypeWithQueryOperationConfig<LandAuctionHighestBidUserDoc>(query_config, false);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypeWithQueryOperationConfig<LandAuctionHighestBidUserDoc>() !!! : {result.toBasicString()}, {make_primary_key.toBasicString()} - landMetaId:{landMetaId}, auctionNumber:{auctionNumber}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, found_land_auction_highest_bid_user_doc);
|
||||
}
|
||||
|
||||
public static async Task<(Result, LandAuctionRefundBidPriceDoc?)> readLandAuctionRefundBidPriceDocFromDb( Player player
|
||||
, META_ID landMetaId, LAND_AUCTION_NUMBER auctionNumber )
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
(result, var found_refund_bid_price_doc) = await readLandAuctionRefundBidPriceDocFromDb( player.getUserGuid()
|
||||
, landMetaId, auctionNumber );
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to readLandAuctionRefundBidPriceDocFromDb() !!! : {result.toBasicString()}, landMetaId:{landMetaId}, auctionNumber:{auctionNumber} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, found_refund_bid_price_doc);
|
||||
}
|
||||
|
||||
public static async Task<(Result, LandAuctionRefundBidPriceDoc?)> readLandAuctionRefundBidPriceDocFromDb( USER_GUID userGuid
|
||||
, META_ID landMetaId, LAND_AUCTION_NUMBER auctionNumber )
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
(result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<LandAuctionRefundBidPriceDoc>(userGuid, LandAuctionRefundBidPriceDoc.makeCombinationKeyForSK(landMetaId, auctionNumber));
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to makePrimaryKey<LandAuctionRefundBidPriceDoc>() !!! : {result.toBasicString()} - userGuid:{userGuid}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!!");
|
||||
|
||||
var query_config = db_connector.makeQueryConfigForReadByPKSK(make_primary_key.PK, make_primary_key.SK);
|
||||
(result, var found_refund_bid_price_doc) = await db_connector.simpleQueryDocTypeWithQueryOperationConfig<LandAuctionRefundBidPriceDoc>(query_config);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypesWithQueryOperationConfig<LandAuctionRefundBidPriceDoc>() !!! : {result.toBasicString()}, {make_primary_key.toBasicString()} - userGuid:{userGuid}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, found_refund_bid_price_doc);
|
||||
}
|
||||
|
||||
public static async Task<(Result, List<LandAuctionRefundBidPriceDoc>?)> readLandAuctionRefundBidPriceDocsFromDb(Player player)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
(result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<LandAuctionRefundBidPriceDoc>(player.getUserGuid());
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to makePrimaryKey<LandAuctionRefundBidPriceDoc>() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!!");
|
||||
|
||||
var query_config = db_connector.makeQueryConfigForReadByPKOnly(make_primary_key.PK);
|
||||
(result, var found_land_auction_bid_price_docs) = await db_connector.simpleQueryDocTypesWithQueryOperationConfig<LandAuctionRefundBidPriceDoc>(query_config);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypesWithQueryOperationConfig<LandAuctionRefundBidPriceDoc>() !!! : {result.toBasicString()}, {make_primary_key.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(found_land_auction_bid_price_docs, () => $"found_land_auction_bid_price_docs is null !!! - {player.toBasicString()}");
|
||||
|
||||
return (result, found_land_auction_bid_price_docs);
|
||||
}
|
||||
|
||||
public static async Task<(Result, List<LandAuctionRecordDoc>?)> readLandAuctionRecordDocsFromDb()
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
(result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<LandAuctionRecordDoc>(DynamoDbClient.PK_GLOBAL);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to makePrimaryKey<LandAuctionRecordDoc>() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!!");
|
||||
|
||||
var query_config = db_connector.makeQueryConfigForReadByPKOnly(make_primary_key.PK);
|
||||
(result, var found_land_auction_record_docs) = await db_connector.simpleQueryDocTypesWithQueryOperationConfig<LandAuctionRecordDoc>(query_config);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleQueryDocTypesWithQueryOperationConfig<LandAuctionRecordDoc>() !!! : {result.toBasicString()}, {make_primary_key.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(found_land_auction_record_docs, () => $"found_docs is null !!!");
|
||||
|
||||
return (result, found_land_auction_record_docs);
|
||||
}
|
||||
}
|
||||
}
|
||||
375
GameServer/Entity/LandAuction/Helper/LandAuctionHelper.cs
Normal file
375
GameServer/Entity/LandAuction/Helper/LandAuctionHelper.cs
Normal file
@@ -0,0 +1,375 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using ServerCommon.Cache;
|
||||
using Amazon.DynamoDBv2.Model;
|
||||
|
||||
|
||||
using META_ID = System.UInt32;
|
||||
using USER_GUID = System.String;
|
||||
using LAND_OWNER_GUID = System.String;
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public static class LandAuctionHelper
|
||||
{
|
||||
public static string getWinningBidValue(this LandAuction landAuction)
|
||||
{
|
||||
var land_auction_action = landAuction.getEntityAction<LandAuctionAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
return land_auction_action.getHighestBidPrice().ToString("N0"); // 천 단위 구분 기호 포함, 소숫점은 없다 !!! - kangms
|
||||
}
|
||||
|
||||
public static Result copyDocToEntityAttributeForRefundBidPrice( this LandAuctionRefundBidPrice refundBidPrice
|
||||
, EntityAttributeBase toClonedAttributeBase, DynamoDbDocBase fromDoc )
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var refund_bid_price_attribute = toClonedAttributeBase as LandAuctionRefundBidPriceAttribute;
|
||||
if (null != refund_bid_price_attribute)
|
||||
{
|
||||
var is_success = refund_bid_price_attribute.copyEntityAttributeFromDoc(fromDoc);
|
||||
if (false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDoc() !!! : docType:{fromDoc.getTypeName()} - {refundBidPrice.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
var origin_attribute = refundBidPrice.getOriginEntityAttribute<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_attribute, () => $"origin_attribute is null !!! - {refundBidPrice.toBasicString()}");
|
||||
origin_attribute.copyEntityAttributeFromDoc(fromDoc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ConditionValidCheckHelper.throwIfFalseWithCondition(() => false
|
||||
, () => $"Failed to copy EntityAttribute from Doc !!! : attributeType:{toClonedAttributeBase.getTypeName()} <= docType:{fromDoc.getTypeName()}"
|
||||
+ $" - {refundBidPrice.toBasicString()}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Result copyCacheToEntityAttributeForLandAuction( this LandAuction landAuction
|
||||
, EntityAttributeBase toClonedAttributeBase, CacheBase fromCache )
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var auction_action = landAuction.getEntityAction<LandAuctionAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(auction_action, () => $"auction_action is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var registry_attribute = toClonedAttributeBase as LandAuctionRegistryAttribute;
|
||||
if (null != registry_attribute)
|
||||
{
|
||||
var origin_attribute = landAuction.getOriginEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_attribute);
|
||||
|
||||
var land_auction_cache = fromCache as LandAuctionCache;
|
||||
if (null != land_auction_cache)
|
||||
{
|
||||
registry_attribute.copyProcessInfoFromCache(land_auction_cache);
|
||||
origin_attribute.copyProcessInfoFromCache(land_auction_cache);
|
||||
|
||||
auction_action.updateProcessVersion(land_auction_cache.ProcessVersionTime);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var highest_bid_user_attribute = toClonedAttributeBase as LandAuctionHighestBidUserAttribute;
|
||||
if (null != highest_bid_user_attribute)
|
||||
{
|
||||
var origin_attribute = landAuction.getOriginEntityAttribute<LandAuctionHighestBidUserAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_attribute);
|
||||
|
||||
var normal_bid_highest_user_cache = fromCache as NormalBidHighestUserCache;
|
||||
if (null != normal_bid_highest_user_cache)
|
||||
{
|
||||
highest_bid_user_attribute.copyEntityAttributeFromCache(normal_bid_highest_user_cache);
|
||||
origin_attribute.copyEntityAttributeFromCache(normal_bid_highest_user_cache);
|
||||
|
||||
auction_action.updateHighestRankVersion(normal_bid_highest_user_cache.HighestRankVersionTime);
|
||||
}
|
||||
|
||||
var top_bidder_cache = fromCache as LandAuctionTopBidderCache;
|
||||
if (null != top_bidder_cache)
|
||||
{
|
||||
highest_bid_user_attribute.copyEntityAttributeFromCache(top_bidder_cache);
|
||||
origin_attribute.copyEntityAttributeFromCache(top_bidder_cache);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ConditionValidCheckHelper.throwIfFalseWithCondition( () => false
|
||||
, () => $"Failed to copy EntityAttribute from Cache !!! : attributeType:{toClonedAttributeBase.getTypeName()} <= cacheType:{fromCache.getTypeName()}"
|
||||
+ $" - {landAuction.toBasicString()}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<Result> copyDocToEntityAttributeForLandAuction( this LandAuction landAuction
|
||||
, EntityAttributeBase toClonedAttributeBase, DynamoDbDocBase fromDoc
|
||||
, bool isWithLock )
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var auction_action = landAuction.getEntityAction<LandAuctionAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(auction_action, () => $"auction_action is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
var activity_attribute = toClonedAttributeBase as LandAuctionActivityAttribute;
|
||||
if(null != activity_attribute)
|
||||
{
|
||||
var is_success = activity_attribute.copyEntityAttributeFromDoc(fromDoc);
|
||||
if(false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDoc() !!! : docType:{fromDoc.getTypeName()} - {landAuction.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
var origin_attribute = landAuction.getOriginEntityAttribute<LandAuctionActivityAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_attribute, () => $"origin_attribute is null !!! - {landAuction.toBasicString()}");
|
||||
origin_attribute.copyEntityAttributeFromDoc(fromDoc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var registry_attribute = toClonedAttributeBase as LandAuctionRegistryAttribute;
|
||||
if (null != registry_attribute)
|
||||
{
|
||||
var origin_attribute = landAuction.getOriginEntityAttribute<LandAuctionRegistryAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_attribute);
|
||||
|
||||
var registry_doc = fromDoc as LandAuctionRegistryDoc;
|
||||
NullReferenceCheckHelper.throwIfNull(registry_doc, () => $"registry_doc is null !!! : docType:{fromDoc.getTypeName()} - {landAuction.toBasicString()}");
|
||||
var registry_attrib = registry_doc.getAttrib<LandAuctionRegistryAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(registry_attrib, () => $"registry_attrib is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
result = registry_attrib.checkValidLandAuctionRegistry();
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var fn_copy_to_attribute = delegate ()
|
||||
{
|
||||
if (origin_attribute.RegisteredVersionTime < registry_attrib.RegisteredVersionTime)
|
||||
{
|
||||
registry_attribute.copyRegisteredInfoFromDoc(registry_doc);
|
||||
origin_attribute.copyRegisteredInfoFromDoc(registry_doc);
|
||||
}
|
||||
|
||||
if (origin_attribute.ProcessVersionTime < registry_attrib.ProcessVersionTime)
|
||||
{
|
||||
registry_attribute.copyProcessInfoFromDoc(registry_doc);
|
||||
origin_attribute.copyProcessInfoFromDoc(registry_doc);
|
||||
}
|
||||
|
||||
auction_action.updateRegistryVersion( registry_attrib.RegisteredVersionTime, registry_attrib.ProcessVersionTime );
|
||||
};
|
||||
|
||||
if (true == isWithLock)
|
||||
{
|
||||
using (var releaser = await landAuction.getAsyncLock())
|
||||
{
|
||||
fn_copy_to_attribute();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fn_copy_to_attribute();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var highest_bid_user_attribute = toClonedAttributeBase as LandAuctionHighestBidUserAttribute;
|
||||
if (null != highest_bid_user_attribute)
|
||||
{
|
||||
var origin_attribute = landAuction.getOriginEntityAttribute<LandAuctionHighestBidUserAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_attribute);
|
||||
|
||||
var highest_bid_user_doc = fromDoc as LandAuctionHighestBidUserDoc;
|
||||
NullReferenceCheckHelper.throwIfNull(highest_bid_user_doc, () => $"highest_bid_user_doc is null !!! : docType:{fromDoc.getTypeName()} - {landAuction.toBasicString()}");
|
||||
var highest_bid_user_attrib = highest_bid_user_doc.getAttrib<LandAuctionHighestBidUserAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(highest_bid_user_attrib, () => $"highest_bid_user_attrib is null !!! - {landAuction.toBasicString()}");
|
||||
|
||||
if (origin_attribute.HighestRankVersionTime < highest_bid_user_attrib.HighestRankVersionTime)
|
||||
{
|
||||
highest_bid_user_attribute.copyEntityAttributeFromDoc(highest_bid_user_doc);
|
||||
origin_attribute.copyEntityAttributeFromDoc(highest_bid_user_doc);
|
||||
}
|
||||
|
||||
auction_action.updateHighestRankVersion(highest_bid_user_attrib.HighestRankVersionTime);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ConditionValidCheckHelper.throwIfFalseWithCondition( () => false
|
||||
, () => $"Failed to copy EntityAttribute from Doc !!! : attributeType:{toClonedAttributeBase.getTypeName()} <= docType:{fromDoc.getTypeName()}"
|
||||
+ $" - {landAuction.toBasicString()}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static (bool, LandAuctionVersion?) checkChangedVersion( this LandAuctionVersion preVersion
|
||||
, DateTime registeredVersionTime, DateTime processVersionTime, DateTime highestRankVersionTime )
|
||||
{
|
||||
var version = new LandAuctionVersion(registeredVersionTime, processVersionTime, highestRankVersionTime);
|
||||
if (true == preVersion.checkChangedVersion(version))
|
||||
{
|
||||
return (true, version);
|
||||
}
|
||||
|
||||
return (false, null);
|
||||
}
|
||||
|
||||
public static bool checkChangedVersion(this LandAuctionVersion preVersion, LandAuctionVersion currVersion)
|
||||
{
|
||||
if( preVersion.RegisteredVersionTime < currVersion.RegisteredVersionTime
|
||||
|| preVersion.ProcessVersionTime < currVersion.ProcessVersionTime
|
||||
|| preVersion.HighestRankVersionTime < currVersion.HighestRankVersionTime )
|
||||
{
|
||||
Log.getLogger().info( $"changed Version !!! "
|
||||
+ $" : prevVersion.RegisteredVersion:{preVersion.RegisteredVersionTime} < currVersion.RegisteredVersion:{currVersion.RegisteredVersionTime}"
|
||||
+ $", prevVersion.ProcessVersion:{preVersion.ProcessVersionTime} < currVersion.ProcessVersion:{currVersion.ProcessVersionTime}"
|
||||
+ $", prevVersion.HighestRankVersion:{preVersion.HighestRankVersionTime} < currVersion.HighestRankVersion:{currVersion.HighestRankVersionTime}" );
|
||||
|
||||
if(preVersion.RegisteredVersionTime > currVersion.RegisteredVersionTime) { currVersion.RegisteredVersionTime = preVersion.RegisteredVersionTime; }
|
||||
if(preVersion.ProcessVersionTime > currVersion.ProcessVersionTime) { currVersion.ProcessVersionTime = preVersion.ProcessVersionTime; }
|
||||
if(preVersion.HighestRankVersionTime > currVersion.HighestRankVersionTime) { currVersion.HighestRankVersionTime = preVersion.HighestRankVersionTime; }
|
||||
|
||||
currVersion.IsSyncRequried = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool isLandAuctionStateByTime(this LandAuctionCheckResult checkResult, LandAuctionState state)
|
||||
{
|
||||
var land_auction_info = checkResult.LandAuctionInfo;
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_info, () => $"land_auction_info is null !!!");
|
||||
|
||||
if (LandAuctionState.Waiting == state)
|
||||
{
|
||||
if (false == DateTimeHelper.hasTimeReached(land_auction_info.AuctionReservationNoticeStartTime.ToDateTime()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (LandAuctionState.Scheduled == state)
|
||||
{
|
||||
if ( true == DateTimeHelper.hasTimeReached(land_auction_info.AuctionReservationNoticeStartTime.ToDateTime())
|
||||
&& false == DateTimeHelper.hasTimeReached(land_auction_info.AuctionStartTime.ToDateTime()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (LandAuctionState.Started == state)
|
||||
{
|
||||
if (true == DateTimeHelper.isBetween(land_auction_info.AuctionStartTime.ToDateTime(), land_auction_info.AuctionEndTime.ToDateTime()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (LandAuctionState.Ended == state)
|
||||
{
|
||||
if (true == DateTimeHelper.hasTimeReached(land_auction_info.AuctionEndTime.ToDateTime()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var err_msg = $"Invalid LandAuctionState !!! : {state}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool isLandAuctionState(this LandAuctionCheckResult checkResult, LandAuctionState state)
|
||||
{
|
||||
var land_auction_info = checkResult.LandAuctionInfo;
|
||||
NullReferenceCheckHelper.throwIfNull(land_auction_info, () => $"land_auction_info is null !!!");
|
||||
|
||||
if ( state == land_auction_info.LandAuctionState )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string toBasicString(this LandAuctionCheckResult checkResult)
|
||||
{
|
||||
return $"{checkResult.getTypeName()}: LandAuctionInfo:{checkResult.LandAuctionInfo.toBasicString()}, BidType:{checkResult.LandAuctionBidType}"
|
||||
+ $", CurrencyType:{checkResult.MyBidCurrencyType}, MyBidPrice:{checkResult.MyBidPrice}, {checkResult.Version.toBasicString()}";
|
||||
|
||||
}
|
||||
|
||||
public static string toBasicString(this LandAuctionBidResult bidResult)
|
||||
{
|
||||
return $"{bidResult.getTypeName()}: TargetLandAuction:{bidResult.TargetLandAuction?.toBasicString()}, BidType:{bidResult.CurrentBidType}"
|
||||
+ $", BidTime:{bidResult.BidTime}";
|
||||
}
|
||||
|
||||
public static bool isLandAuctionStateByTime(this LandAuctionRegistryAttribute registryAttribute, LandAuctionState state)
|
||||
{
|
||||
if (LandAuctionState.Waiting == state)
|
||||
{
|
||||
if (false == DateTimeHelper.hasTimeReached(registryAttribute.AuctionReservationNoticeStartTime))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (LandAuctionState.Scheduled == state)
|
||||
{
|
||||
if ( true == DateTimeHelper.hasTimeReached(registryAttribute.AuctionReservationNoticeStartTime)
|
||||
&& false == DateTimeHelper.hasTimeReached(registryAttribute.AuctionStartTime) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (LandAuctionState.Started == state)
|
||||
{
|
||||
if (true == DateTimeHelper.isBetween( registryAttribute.AuctionStartTime, registryAttribute.AuctionEndTime) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (LandAuctionState.Ended == state)
|
||||
{
|
||||
if (true == DateTimeHelper.hasTimeReached(registryAttribute.AuctionEndTime))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var err_msg = $"Invalid LandAuctionState !!! : {state}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
146
GameServer/Entity/LandAuction/Helper/LandAuctionMetaHelper.cs
Normal file
146
GameServer/Entity/LandAuction/Helper/LandAuctionMetaHelper.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
using MetaAssets;
|
||||
|
||||
using static ServerCommon.MetaHelper;
|
||||
|
||||
|
||||
using META_ID = System.UInt32;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public static class LandAuctionMetaHelper
|
||||
{
|
||||
public static string getStringKeyOfLandName(this LandMetaData landMetaData)
|
||||
{
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (false == MetaData.Instance._textTable.TryGetValue(landMetaData.LandName, out var found_text_string_meta))
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TextTable.TryGetValue() !!! : LandName:{landMetaData.LandName} - LandMetaId:{landMetaData.LandId}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return err_msg;
|
||||
}
|
||||
|
||||
return found_text_string_meta.Key;
|
||||
}
|
||||
|
||||
public static Result checkValidLandAuctionRegistry(this LandAuctionRegistryAttrib attrib)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var is_invalid = false;
|
||||
|
||||
var land_meta_id = attrib.LandMetaId;
|
||||
|
||||
if (false == MetaData.Instance._LandTable.TryGetValue((Int32)land_meta_id, out var land_meta_data))
|
||||
{
|
||||
err_msg = $"Not found LandMeta !!! : landMetaId:{land_meta_id} - {attrib.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
if (EditorType.USER != land_meta_data.Editor)
|
||||
{
|
||||
err_msg = $"Invalid EditorType !!! : EditorType.USER == {land_meta_data.Editor} landMetaId:{land_meta_id} - {attrib.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandAuctionEditorTypeInvalid, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
if (0 >= land_meta_data.LinkedItem)
|
||||
{
|
||||
err_msg = $"Not set LinkedItem of LandItem : landMetaId:{land_meta_id} - {attrib.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandAuctionLandItemNotSet, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
var bid_currency_type = attrib.BidCurrencyType;
|
||||
if (CurrencyType.None == bid_currency_type)
|
||||
{
|
||||
err_msg = $"invalid CurrencyType !!! : bidCurrencyType:{bid_currency_type} != CurrencyType.None - {attrib.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
is_invalid = true;
|
||||
}
|
||||
|
||||
var notice_start_time = attrib.AuctionReservationNoticeStartTime;
|
||||
if (false == notice_start_time.isValidTime())
|
||||
{
|
||||
err_msg = $"invalid AuctionReservationNoticeStartTime !!! : setTime:{notice_start_time} - {attrib.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
is_invalid = true;
|
||||
}
|
||||
|
||||
var start_time = attrib.AuctionStartTime;
|
||||
if (false == start_time.isValidTime())
|
||||
{
|
||||
err_msg = $"invalid AuctionStartTime !!! : setTime:{start_time} - {attrib.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
is_invalid = true;
|
||||
}
|
||||
|
||||
var end_time = attrib.AuctionEndTime;
|
||||
if (false == end_time.isValidTime())
|
||||
{
|
||||
err_msg = $"invalid AuctionEndTime !!! : setTime:{end_time} - {attrib.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
is_invalid = true;
|
||||
}
|
||||
|
||||
if (start_time >= end_time)
|
||||
{
|
||||
err_msg = $"invalid AuctionEndTime !!!, AuctionEndTime must be greater than AuctionStartTime !!! : setEndTime:{end_time} > setStartTime:{start_time} - {attrib.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
is_invalid = true;
|
||||
}
|
||||
|
||||
var bid_start_price = attrib.BidStartPrice;
|
||||
if (0 >= bid_start_price)
|
||||
{
|
||||
err_msg = $"invalid BidStartPrice !!! : BidStartPrice:{bid_start_price} > 0 - {attrib.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
is_invalid = true;
|
||||
}
|
||||
|
||||
if (true == is_invalid)
|
||||
{
|
||||
result.setFail(ServerErrorCode.LandAuctionRegistryInfoInvalid, err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static LandAuctionBidType toCurrentBidType(DateTime auctionEndTime)
|
||||
{
|
||||
// 블라인드 입찰 시점인지 체크 한다.
|
||||
var time_span_before_auction_end_time = TimeSpan.FromMinutes(ServerCommon.MetaHelper.GameConfigMeta.BlindBidStartBeforeLandAuctionEndMinutes);
|
||||
var blind_bid_start_time = auctionEndTime.Subtract(time_span_before_auction_end_time);
|
||||
|
||||
|
||||
// 시간을 기준으로 입찰 종료 예외 체크
|
||||
if(DateTimeHelper.Current >= auctionEndTime)
|
||||
{
|
||||
return LandAuctionBidType.None;
|
||||
}
|
||||
|
||||
// 일반 입찰
|
||||
if (DateTimeHelper.Current < blind_bid_start_time)
|
||||
{
|
||||
return LandAuctionBidType.Normal;
|
||||
}
|
||||
|
||||
// 블라인드 입찰
|
||||
return LandAuctionBidType.Blind;
|
||||
}
|
||||
}
|
||||
}
|
||||
95
GameServer/Entity/LandAuction/LandAuction.cs
Normal file
95
GameServer/Entity/LandAuction/LandAuction.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using META_ID = System.String;
|
||||
using MASTER_GUID = System.String;
|
||||
using REQUESTOR_ID = System.String;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class LandAuction : EntityBase, IWithLogActor
|
||||
{
|
||||
public LandAuction()
|
||||
: base(EntityType.LandAuction)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
addEntityAttribute(new LandAuctionRegistryAttribute(this));
|
||||
addEntityAttribute(new LandAuctionHighestBidUserAttribute(this));
|
||||
addEntityAttribute(new LandAuctionRecordAttribute(this));
|
||||
|
||||
addEntityAttribute(new LandAuctionActivityAttribute(this));
|
||||
|
||||
addEntityAction(new LandAuctionAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override EntityBase? onGetMasterEntity()
|
||||
{
|
||||
if (false == hasMasterGuid())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var master_guid = getMasterGuid();
|
||||
|
||||
var server_logc = GameServerApp.getServerLogic();
|
||||
var player_manager = server_logc.getPlayerManager();
|
||||
|
||||
if (false == player_manager.tryGetUserByPrimaryKey(master_guid, out var found_player))
|
||||
{
|
||||
// 별도 Task로 처리해주는 처리자가 있다면 해당 처리자를 반환 한다. !!! - kangms
|
||||
|
||||
err_msg = $"Failed to player_manager.tryGetUserByPrimaryKey() !!!, Not found MasterEntity : MasterGuid:{master_guid} - {toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return found_player;
|
||||
}
|
||||
|
||||
public ILogActor toLogActor()
|
||||
{
|
||||
var server_logic = ServerLogicApp.getServerLogicApp();
|
||||
|
||||
var log_info = new LandAuctionActorLog();
|
||||
if (server_logic == null)
|
||||
return log_info;
|
||||
|
||||
log_info.initLogInfo(
|
||||
// 서버 정보
|
||||
server_logic.getServerConfig().getRegionId()
|
||||
, server_logic.getServerConfig().getWorldId()
|
||||
, server_logic.getServerType().toServerType()
|
||||
);
|
||||
|
||||
return log_info;
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}"
|
||||
+ $", {getOriginEntityAttribute<LandAuctionActivityAttribute>()?.toBasicString()}, {getOriginEntityAttribute<LandAuctionRegistryAttribute>()?.toBasicString()}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}, {getEntityAttribute<LandAuctionRegistryAttribute>()?.toSummaryString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,797 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using Amazon.S3.Model;
|
||||
using Amazon.DynamoDBv2.Model;
|
||||
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.Cache;
|
||||
using MetaAssets;
|
||||
using ServerControlCenter;
|
||||
|
||||
|
||||
using static ServerCommon.MetaHelper;
|
||||
using static GameServer.LandAuctionDbHelper;
|
||||
|
||||
|
||||
using META_ID = System.UInt32;
|
||||
using LAND_AUCTION_NUMBER = System.Int32;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class LandAuctionRefundBidPriceAction : EntityActionBase
|
||||
{
|
||||
private bool m_is_deletable = false;
|
||||
|
||||
public LandAuctionRefundBidPriceAction(LandAuctionRefundBidPrice owner)
|
||||
: base(owner)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
}
|
||||
|
||||
public Result tryLoadRefundBidPriceFromDoc(LandAuctionRefundBidPriceDoc doc)
|
||||
{
|
||||
var owner = getOwner() as LandAuctionRefundBidPrice;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
var player = owner.getRootParent() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var refund_bid_price_attribute = owner.getEntityAttribute<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_attribute, () => $"refund_bid_price_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
if(false == refund_bid_price_attribute.copyEntityAttributeFromDoc(doc))
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDoc !!! : docType:{doc.getTypeName()} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> tryUpdateRefundBidPrice()
|
||||
{
|
||||
var owner = getOwner() as LandAuctionRefundBidPrice;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
var player = owner.getRootParent() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisDb();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
( result
|
||||
, var is_sucess
|
||||
, var auction_result
|
||||
, var refundable_normal_bid_price, var refundable_blind_bid_price) = await checkRefundableNow();
|
||||
if(result.isFail()) { return result; }
|
||||
|
||||
if (true == is_sucess)
|
||||
{
|
||||
err_msg = $"Success to checkRefundableNow() !!!, AuctionResult:{auction_result}"
|
||||
+ $", refundableNormalBidAmount:{refundable_normal_bid_price}, refundableBlindBidAmount:{refundable_blind_bid_price}"
|
||||
+ $" : {owner.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().debug(err_msg);
|
||||
|
||||
result = await refundLandAuctionBidPrice(auction_result, refundable_normal_bid_price, refundable_blind_bid_price);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to refundLandAuctionBidPrice() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
result = await deleteRefundBidPrice(auction_result);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to deleteRefundBidPrice() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<(Result, bool, LandAuctionResult, double, double)> checkRefundableNow()
|
||||
{
|
||||
var refund_bid_price = getOwner() as LandAuctionRefundBidPrice;
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price, () => $"refund_bid_price is null !!!");
|
||||
var player = refund_bid_price.getRootParent() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisConnector();
|
||||
|
||||
var refund_bid_price_attribute = refund_bid_price.getEntityAttribute<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_attribute, () => $"refund_bid_price_attribute is null !!! - {refund_bid_price.toBasicString()}");
|
||||
|
||||
var user_guid = player.getUserGuid();
|
||||
var land_meta_id = refund_bid_price_attribute.LandMetaId;
|
||||
var auction_number = refund_bid_price_attribute.AuctionNumber;
|
||||
|
||||
//=====================================================================================
|
||||
// 1. 입찰금 정보를 읽는다. (항상 Db 에서 읽어오고 판단 !!!)
|
||||
//=====================================================================================
|
||||
(result, var refund_bid_price_doc) = await LandAuctionDbHelper.readLandAuctionRefundBidPriceDocFromDb(player, land_meta_id, auction_number);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to readLandAuctionRefundBidPriceDocFromDb() !!! : {result.toBasicString()}, {refund_bid_price.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, false, LandAuctionResult.None, 0, 0);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_doc, () => $"refund_bid_price_doc is null !!! - {refund_bid_price.toBasicString()}");
|
||||
var refund_bid_price_attrib = refund_bid_price_doc.getAttrib<LandAuctionRefundBidPriceAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_attrib, () => $"refund_bid_price_attrib is null !!! - {refund_bid_price.toBasicString()}");
|
||||
|
||||
result = refund_bid_price.copyDocToEntityAttributeForRefundBidPrice(refund_bid_price_attribute, refund_bid_price_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to copyDocToEntityAttributeForRefundBidPrice() !!! : {result.toBasicString()}, docType:{refund_bid_price_doc.getTypeName()}, {refund_bid_price.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, false, LandAuctionResult.None, 0, 0);
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// 2. 랜드 경매 결과를 확인 한다. (Cache => Db)
|
||||
//=====================================================================================
|
||||
var auction_result = LandAuctionResult.None;
|
||||
|
||||
var land_auction_cache_request = new LandAuctionCacheRequest(land_meta_id, redis_connector);
|
||||
var redis_result = await land_auction_cache_request.fetchLandAuction();
|
||||
if (redis_result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to fetchLandAuction() !!!, duplicated SK !!! : {redis_result.toBasicString()} - {refund_bid_price.toBasicString()}, {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
var land_auction_cache = land_auction_cache_request.getLandAuctionCache();
|
||||
if (null == land_auction_cache)
|
||||
{
|
||||
(result, var found_registry_doc) = await LandAuctionDbHelper.readLandAuctionRegistryDocFromDb(land_meta_id, auction_number);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to readLandAuctionRegistryDocFromDb() !!! : {result.toBasicString()} - {refund_bid_price.toBasicString()}, {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, false, LandAuctionResult.None, 0, 0);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(found_registry_doc, () => $"found_registry_doc is null !!! - {refund_bid_price.toBasicString()}");
|
||||
var registry_attrib = found_registry_doc.getAttrib<LandAuctionRegistryAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(registry_attrib, () => $"registry_attrib is null !!! - {refund_bid_price.toBasicString()}");
|
||||
|
||||
if (LandAuctionResult.None != registry_attrib.LandAuctionResult)
|
||||
{
|
||||
auction_result = registry_attrib.LandAuctionResult;
|
||||
|
||||
err_msg = $"LandAuctionResult:{auction_result} <= LandAuctionRegistryDoc from DB, in checkRefundableNow() : {refund_bid_price.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().debug(err_msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LandAuctionResult.None != land_auction_cache.LandAuctionResult)
|
||||
{
|
||||
auction_result = land_auction_cache.LandAuctionResult;
|
||||
|
||||
err_msg = $"LandAuctionResult:{auction_result} <= LandAuctionCache from Cache, in checkRefundableNow() : {refund_bid_price.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().debug(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// 3. 최고 입찰자 정보를 얻는다.
|
||||
//=====================================================================================
|
||||
(result, var found_highest_bid_user_doc) = await LandAuctionDbHelper.readLandAuctionHighestBidUserDocFromDb(land_meta_id, auction_number);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to readLandAuctionHighestBidUserDocFromDb() !!! : {result.toBasicString()} - {refund_bid_price.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, false, LandAuctionResult.None, 0, 0);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(found_highest_bid_user_doc, () => $"found_highest_bid_user_doc is null !!! - landMetaId:{land_meta_id}, auctionNumber:{auction_number}");
|
||||
var highest_bid_user_attrib = found_highest_bid_user_doc.getAttrib<LandAuctionHighestBidUserAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(highest_bid_user_attrib, () => $"highest_bid_user_attrib is null !!! - landMetaId:{land_meta_id}, auctionNumber:{auction_number}");
|
||||
|
||||
var bid_type = refund_bid_price_attrib.LastBidType;
|
||||
double deductible_bid_amount = 0;
|
||||
|
||||
// 현재 내가 최고 입찰자인 경우
|
||||
if (highest_bid_user_attrib.HighestBidUserGuid == user_guid)
|
||||
{
|
||||
// 환급 입찰금에서 차감해야 하는 금전량
|
||||
deductible_bid_amount = refund_bid_price_attrib.LastBidPrice;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// 4. 랜드 경매 결과 상태를 확인 및 환급 입찰금에서 차감액을 차감 한다.
|
||||
//=====================================================================================
|
||||
double refundable_normal_bid_price = 0;
|
||||
double refundable_blind_bid_price = 0;
|
||||
|
||||
if (LandAuctionResult.None != auction_result)
|
||||
{
|
||||
refundable_normal_bid_price = refund_bid_price_attribute.RefundableNormalBidPrice;
|
||||
refundable_blind_bid_price = refund_bid_price_attribute.RefundableBlindBidPrice;
|
||||
|
||||
if (LandAuctionBidType.Normal == bid_type)
|
||||
{
|
||||
refundable_normal_bid_price = refundable_normal_bid_price - deductible_bid_amount;
|
||||
refundable_normal_bid_price = MathHelper.min(double.MaxValue, refundable_normal_bid_price);
|
||||
refundable_normal_bid_price = MathHelper.max(double.MinValue, refundable_normal_bid_price);
|
||||
}
|
||||
else if (LandAuctionBidType.Blind == bid_type)
|
||||
{
|
||||
refundable_blind_bid_price = refundable_blind_bid_price - deductible_bid_amount;
|
||||
refundable_blind_bid_price = MathHelper.min(double.MaxValue, refundable_blind_bid_price);
|
||||
refundable_blind_bid_price = MathHelper.max(double.MinValue, refundable_blind_bid_price);
|
||||
}
|
||||
|
||||
if(0 < refundable_normal_bid_price || 0 < refundable_blind_bid_price)
|
||||
{
|
||||
return (result, true, auction_result, refundable_normal_bid_price, refundable_blind_bid_price);
|
||||
}
|
||||
}
|
||||
// 랜드 경매가 진행중 !!!
|
||||
else
|
||||
{
|
||||
// LandAuctionBidType.Normal 환급 입찰금은 언제든지 환급 가능하다 !!!
|
||||
if (0 < refund_bid_price_attribute.RefundableNormalBidPrice)
|
||||
{
|
||||
err_msg = $"Refundable normal Bid Price !!!, in checkRefundableNow() : auctionResult:{auction_result}, {refund_bid_price.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().debug(err_msg);
|
||||
|
||||
if (LandAuctionBidType.Normal == bid_type)
|
||||
{
|
||||
refundable_normal_bid_price = refund_bid_price_attribute.RefundableNormalBidPrice - deductible_bid_amount;
|
||||
refundable_normal_bid_price = MathHelper.min(double.MaxValue, refundable_normal_bid_price);
|
||||
refundable_normal_bid_price = MathHelper.max(double.MinValue, refundable_normal_bid_price);
|
||||
}
|
||||
|
||||
if(0 < refundable_normal_bid_price)
|
||||
{
|
||||
return (result, true, auction_result, refundable_normal_bid_price, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 환급이 불가능 하다 !!!
|
||||
return (result, false, auction_result, 0, 0);
|
||||
}
|
||||
|
||||
private async Task<Result> deleteRefundBidPrice(LandAuctionResult auctionResult)
|
||||
{
|
||||
var refund_bid_price = getOwner() as LandAuctionRefundBidPrice;
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price, () => $"refund_bid_price is null !!!");
|
||||
var player = refund_bid_price.getRootParent() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var refund_bid_price_attribute = refund_bid_price.getEntityAttribute<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_attribute, () => $"refund_bid_price_attribute is null !!! - {refund_bid_price.toBasicString()}");
|
||||
|
||||
var land_meta_id = refund_bid_price_attribute.LandMetaId;
|
||||
var auction_number = refund_bid_price_attribute.AuctionNumber;
|
||||
|
||||
(result, var refund_bid_price_doc) = await LandAuctionDbHelper.readLandAuctionRefundBidPriceDocFromDb(player, land_meta_id, auction_number);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to readLandAuctionRefundBidPriceDocFromDb() !!! : {result.toBasicString()}, {refund_bid_price.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_doc, () => $"refund_bid_price_doc is null !!! - {refund_bid_price.toBasicString()}");
|
||||
var refund_bid_price_attrib = refund_bid_price_doc.getAttrib<LandAuctionRefundBidPriceAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price_attrib, () => $"refund_bid_price_attrib is null !!! - {refund_bid_price.toBasicString()}");
|
||||
|
||||
result = refund_bid_price.copyDocToEntityAttributeForRefundBidPrice(refund_bid_price_attribute, refund_bid_price_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to copyDocToEntityAttributeForRefundBidPrice() !!! : {result.toBasicString()}, docType:{refund_bid_price_doc.getTypeName()} - {refund_bid_price.toBasicString()}, {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
var is_delete = false;
|
||||
if(LandAuctionResult.None != auctionResult)
|
||||
{
|
||||
if ( 0 >= ( LandAuctionBidType.Normal == refund_bid_price_attrib.LastBidType
|
||||
? refund_bid_price_attrib.RefundableNormalBidPrice - refund_bid_price_attrib.LastBidPrice
|
||||
: refund_bid_price_attrib.RefundableNormalBidPrice )
|
||||
&& 0 >= ( LandAuctionBidType.Blind == refund_bid_price_attrib.LastBidType
|
||||
? refund_bid_price_attrib.RefundableBlindBidPrice - refund_bid_price_attrib.LastBidPrice
|
||||
: refund_bid_price_attrib.RefundableBlindBidPrice )
|
||||
)
|
||||
{
|
||||
is_delete = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(true == is_delete)
|
||||
{
|
||||
result = await db_connector.simpleDeleteDocumentWithDocType<LandAuctionRefundBidPriceDoc>(refund_bid_price_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleDeleteDocumentWithDocType() !!! : {result.toBasicString()} - {refund_bid_price.toBasicString()}, {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
setDeletable();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> refundLandAuctionBidPrice( LandAuctionResult auctionResult
|
||||
, double refundableNormalBidPrice, double refundableBlindBidPrice)
|
||||
{
|
||||
var owner = getOwner() as LandAuctionRefundBidPrice;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
var player = owner.getRootParent() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var redis_connector = server_logic.getRedisDb();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var new_mail_docs = new List<DynamoDbDocBase>();
|
||||
DynamoDbItemRequestQueryContext? item_request_query_context = null;
|
||||
|
||||
err_msg = $"Try LandAuction refund Bid Price : LandAuctionResult:{auctionResult}, {owner.toSummaryString()} - {player.toBasicString()}";
|
||||
Log.getLogger().debug(err_msg);
|
||||
|
||||
if (LandAuctionResult.Canceled == auctionResult)
|
||||
{
|
||||
(result, var to_add_mail_docs, var query_context) = await createMailWithBidPriceByAuctionCancel( refundableNormalBidPrice, refundableBlindBidPrice );
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to createMailWithBidPriceByAuctionCancel() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
new_mail_docs = to_add_mail_docs;
|
||||
item_request_query_context = query_context;
|
||||
}
|
||||
else
|
||||
{
|
||||
(result, var to_add_mail_docs, var query_context) = await createMailWithRefundedBidPrice( auctionResult
|
||||
, refundableNormalBidPrice, refundableBlindBidPrice );
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to createMailWithRefundedBidPrice() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
new_mail_docs = to_add_mail_docs;
|
||||
item_request_query_context = query_context;
|
||||
}
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithItemRequest>( player, LogActionType.LandAuctionBidPriceRefund
|
||||
, server_logic.getDynamoDbClient()
|
||||
, true );
|
||||
{
|
||||
if (null != new_mail_docs)
|
||||
{
|
||||
batch.addQuery(new DBQEntityWrite(new_mail_docs));
|
||||
}
|
||||
if (null != item_request_query_context)
|
||||
{
|
||||
batch.addQuery(new DBQWithItemRequestQueryContext(item_request_query_context));
|
||||
}
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
batch.addQuery(new QueryFinal(), async (_query) =>
|
||||
{
|
||||
await completedRefundBidPrice(auctionResult, _query);
|
||||
if (null != new_mail_docs && 0 < new_mail_docs.Count)
|
||||
{
|
||||
var found_user_mail_action = player.getEntityAction<MailAction>();
|
||||
found_user_mail_action.NewReceivedMail();
|
||||
|
||||
foreach(var new_mail_doc in new_mail_docs)
|
||||
{
|
||||
err_msg = $"New Received Mail : {new_mail_doc.toAttribAllString()}, {owner.toSummaryString()} - {player.toBasicString()}";
|
||||
Log.getLogger().debug(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
err_msg = $"Completed refund Bid Price of LandAuction : LandAuctionResult:{auctionResult}, {owner.toSummaryString()} - {player.toBasicString()}";
|
||||
Log.getLogger().debug(err_msg);
|
||||
|
||||
return QueryBatchBase.QueryResultType.Success;
|
||||
});
|
||||
}
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task completedRefundBidPrice(LandAuctionResult auctionResult, QueryExecutorBase queryExecutorBase)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var refund_bid_price = getOwner() as LandAuctionRefundBidPrice;
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price, () => $"refund_bid_price is null !!!");
|
||||
var player = refund_bid_price.getRootParent() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var bid_price_attribute = refund_bid_price.getEntityAttribute<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(bid_price_attribute, () => $"bid_price_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
var origin_bid_price_attribute = refund_bid_price.getOriginEntityAttribute<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_bid_price_attribute, () => $"origin_bid_price_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
result = origin_bid_price_attribute.copyFromOtherEntityAttribute(bid_price_attribute);
|
||||
if(result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to copyFromOtherEntityAttribute() : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
LandAuctionBusinessLogHelper.writeBusinessLogByLandAuctionBidPriceRefund(refund_bid_price, auctionResult, queryExecutorBase);
|
||||
}
|
||||
|
||||
public async Task<(Result, List<DynamoDbDocBase>?, DynamoDbItemRequestQueryContext?)> createMailWithRefundedBidPrice( LandAuctionResult auctionResult
|
||||
, double refundableNormalBidPrice, double refundableBlindBidPrice)
|
||||
{
|
||||
var refund_bid_price = getOwner() as LandAuctionRefundBidPrice;
|
||||
NullReferenceCheckHelper.throwIfNull(refund_bid_price, () => $"refund_bid_price is null !!!");
|
||||
var player = refund_bid_price.getRootParent() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
ConditionValidCheckHelper.throwIfFalseWithCondition( () => LandAuctionResult.Canceled != auctionResult
|
||||
, () => $"Invalid LandAuctionResult !!! : LandAuctionResult.Canceled != {auctionResult} - {player.toBasicString()}");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
var redis_connector = server_logic.getRedisDb();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var user_land_auction_action = player.getEntityAction<UserLandAuctionAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_land_auction_action, () => $"user_land_auction_action is null !!! - {refund_bid_price.toBasicString()}");
|
||||
|
||||
var bid_price_attribute = refund_bid_price.getEntityAttribute<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(bid_price_attribute, () => $"bid_price_attribute is null !!! - {refund_bid_price.toBasicString()}");
|
||||
|
||||
var currency_type = bid_price_attribute.BidCurrencyType;
|
||||
if (MetaData.Instance._CurrencyMetaTableByCurrencyType.TryGetValue(currency_type, out var currencyMetaData) == false)
|
||||
{
|
||||
result.setFail(ServerErrorCode.CurrencyNotFoundData, err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var user_guid = player.getUserGuid();
|
||||
var land_meta_id = bid_price_attribute.LandMetaId;
|
||||
var auction_number = bid_price_attribute.AuctionNumber;
|
||||
|
||||
if (false == server_logic.getLandManager().tryGetLand((Int32)land_meta_id, out var found_land))
|
||||
{
|
||||
err_msg = $"Not found Land !!! : landMetaId:{land_meta_id} - {refund_bid_price.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
if (false == MetaData.Instance._LandTable.TryGetValue((Int32)land_meta_id, out var found_land_meta))
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TryGetValue() !!! : LandMetaId:{land_meta_id}";
|
||||
result.setFail(ServerErrorCode.LandMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var to_new_mail_docs = new List<DynamoDbDocBase>();
|
||||
DynamoDbItemRequestQueryContext? item_request_query_context = null;
|
||||
|
||||
var to_change_attrib_actions = new Dictionary<string, DynamoDbItemRequestHelper.AttribAction>();
|
||||
|
||||
var user_nickname = player.getUserNickname();
|
||||
|
||||
if (0 < refundableNormalBidPrice)
|
||||
{
|
||||
var system_mail_key = "LandAuctionBidReturn";
|
||||
if (MetaData.Instance.SystemMailMetaData.TryGetValue(system_mail_key, out var systemMailMetaData) == false)
|
||||
{
|
||||
err_msg = $"Not found SystemMailMeta !!! : mailKey:{system_mail_key} - {refund_bid_price.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.SystemMailMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var contents_arguments = new List<string>();
|
||||
contents_arguments.Add(found_land_meta.getStringKeyOfLandName());
|
||||
contents_arguments.Add(user_nickname);
|
||||
|
||||
var mail_items = new List<ServerCommon.MailItem>() { new ServerCommon.MailItem() { ItemId = (META_ID)currencyMetaData.ItemId, Count = refundableNormalBidPrice } };
|
||||
(result, var new_mail_doc) = await Mail.createSystemMailWithMeta( player.getUserGuid(), user_nickname, systemMailMetaData, contents_arguments
|
||||
, mail_items, GameConfigMeta.LandAuctionFailedMailPeriodMinutes );
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to createSystemMailWithMeta() !!! : {result.toBasicString()} - {refund_bid_price.toBasicString()}";
|
||||
Log.getLogger().info(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(new_mail_doc, () => $"new_mail_doc is null !!! : ne - {player.toBasicString()}");
|
||||
|
||||
to_new_mail_docs.Add(new_mail_doc);
|
||||
|
||||
to_change_attrib_actions.Add( nameof(LandAuctionRefundBidPriceAttrib.RefundableNormalBidPrice)
|
||||
, new DynamoDbItemRequestHelper.AttribAction { ValueAction = DynamoDbItemRequestHelper.AttribValueAction.Decrease
|
||||
, Value = new AttributeValue { N = refundableNormalBidPrice.ToString() } });
|
||||
|
||||
bid_price_attribute.RefundableNormalBidPrice -= refundableNormalBidPrice;
|
||||
}
|
||||
|
||||
if (LandAuctionResult.None != auctionResult)
|
||||
{
|
||||
if (0 < refundableBlindBidPrice)
|
||||
{
|
||||
var system_mail_key = "LandAuctionBidReturn";
|
||||
if (MetaData.Instance.SystemMailMetaData.TryGetValue(system_mail_key, out var systemMailMetaData) == false)
|
||||
{
|
||||
err_msg = $"Not found SystemMailMeta !!! : mailKey:{system_mail_key} - {refund_bid_price.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.SystemMailMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var contens_arguments = new List<string>();
|
||||
contens_arguments.Add(found_land_meta.getStringKeyOfLandName());
|
||||
contens_arguments.Add(user_nickname);
|
||||
|
||||
var mail_items = new List<ServerCommon.MailItem>() { new ServerCommon.MailItem() { ItemId = (META_ID)currencyMetaData.ItemId, Count = refundableBlindBidPrice } };
|
||||
(result, var new_mail_doc) = await Mail.createSystemMailWithMeta(player.getUserGuid(), user_nickname, systemMailMetaData, contens_arguments
|
||||
, mail_items, GameConfigMeta.LandAuctionFailedMailPeriodMinutes);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to createSystemMailWithMeta() !!! : {result.toBasicString()} - {refund_bid_price.toBasicString()}";
|
||||
Log.getLogger().info(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(new_mail_doc, () => $"new_mail_doc is null !!! : ne - {player.toBasicString()}");
|
||||
|
||||
to_new_mail_docs.Add(new_mail_doc);
|
||||
|
||||
to_change_attrib_actions.Add( nameof(LandAuctionRefundBidPriceAttrib.RefundableBlindBidPrice)
|
||||
, new DynamoDbItemRequestHelper.AttribAction{ ValueAction = DynamoDbItemRequestHelper.AttribValueAction.Decrease
|
||||
, Value = new AttributeValue { N = refundableBlindBidPrice.ToString() } });
|
||||
|
||||
bid_price_attribute.RefundableBlindBidPrice -= refundableBlindBidPrice;
|
||||
}
|
||||
}
|
||||
|
||||
if(0 < to_change_attrib_actions.Count)
|
||||
{
|
||||
var refund_bid_price_doc = new LandAuctionRefundBidPriceDoc(player.getUserGuid(), land_meta_id, auction_number);
|
||||
(result, var query_context) = DynamoDbItemRequestHelper.makeUpdateItemRequestWithDoc<LandAuctionRefundBidPriceAttrib>(refund_bid_price_doc, to_change_attrib_actions);
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(query_context, () => $"query_context is null !!!");
|
||||
|
||||
item_request_query_context = query_context;
|
||||
}
|
||||
|
||||
return (result, to_new_mail_docs, item_request_query_context);
|
||||
}
|
||||
|
||||
public async Task<(Result, List<DynamoDbDocBase>?, DynamoDbItemRequestQueryContext?)> createMailWithBidPriceByAuctionCancel(double refundableNormalBidPrice, double refundableBlindBidPrice)
|
||||
{
|
||||
var owner = getOwner() as LandAuctionRefundBidPrice;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
var player = owner.getRootParent() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var db_connector = server_logic.getDynamoDbClient();
|
||||
var redis_connector = server_logic.getRedisDb();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var user_land_auction_action = player.getEntityAction<UserLandAuctionAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_land_auction_action, () => $"user_land_auction_action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var bid_price_attribute = owner.getEntityAttributeWithReadOnly<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(bid_price_attribute, () => $"bid_price_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var currency_type = bid_price_attribute.BidCurrencyType;
|
||||
if (MetaData.Instance._CurrencyMetaTableByCurrencyType.TryGetValue(currency_type, out var currencyMetaData) == false)
|
||||
{
|
||||
result.setFail(ServerErrorCode.CurrencyNotFoundData, err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var land_meta_id = bid_price_attribute.LandMetaId;
|
||||
var auction_number = bid_price_attribute.AuctionNumber;
|
||||
|
||||
if (false == server_logic.getLandManager().tryGetLand((Int32)land_meta_id, out var found_land))
|
||||
{
|
||||
err_msg = $"Not found Land !!! : landMetaId:{land_meta_id} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
if (false == MetaData.Instance._LandTable.TryGetValue((Int32)land_meta_id, out var land_meta_data))
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TryGetValue() !!! : LandMetaId:{land_meta_id} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.LandMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var to_new_mail_docs = new List<DynamoDbDocBase>();
|
||||
DynamoDbItemRequestQueryContext? item_request_query_context = null;
|
||||
|
||||
var to_change_attrib_actions = new Dictionary<string, DynamoDbItemRequestHelper.AttribAction>();
|
||||
|
||||
var user_nickname = player.getUserNickname();
|
||||
var user_guid = player.getUserGuid();
|
||||
|
||||
if (0 < refundableNormalBidPrice)
|
||||
{
|
||||
var system_mail_key = "LandAuctionBidReturn";
|
||||
if (MetaData.Instance.SystemMailMetaData.TryGetValue(system_mail_key, out var systemMailMetaData) == false)
|
||||
{
|
||||
err_msg = $"Not found SystemMailMeta !!! : mailKey:{system_mail_key} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.SystemMailMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var contens_arguments = new List<string>();
|
||||
contens_arguments.Add(land_meta_data.getStringKeyOfLandName());
|
||||
contens_arguments.Add(user_nickname);
|
||||
|
||||
var mail_items = new List<ServerCommon.MailItem>() { new ServerCommon.MailItem() { ItemId = (META_ID)currencyMetaData.ItemId, Count = refundableNormalBidPrice } };
|
||||
(result, var new_mail_doc) = await Mail.createSystemMailWithMeta( player.getUserGuid(), user_nickname, systemMailMetaData, contens_arguments
|
||||
, mail_items, GameConfigMeta.LandAuctionFailedMailPeriodMinutes );
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to createSystemMailWithMeta() !!! : {result.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().info(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(new_mail_doc, () => $"new_mail_doc is null !!! : ne - {player.toBasicString()}");
|
||||
to_new_mail_docs.Add(new_mail_doc);
|
||||
|
||||
to_change_attrib_actions.Add( nameof(LandAuctionRefundBidPriceAttrib.RefundableNormalBidPrice)
|
||||
, new DynamoDbItemRequestHelper.AttribAction { ValueAction = DynamoDbItemRequestHelper.AttribValueAction.Decrease
|
||||
, Value = new AttributeValue { N = refundableNormalBidPrice.ToString() } } );
|
||||
|
||||
bid_price_attribute.RefundableNormalBidPrice = 0;
|
||||
}
|
||||
|
||||
if (0 < refundableBlindBidPrice)
|
||||
{
|
||||
var system_mail_key = "LandAuctionHoldReturn";
|
||||
if (MetaData.Instance.SystemMailMetaData.TryGetValue(system_mail_key, out var systemMailMetaData) == false)
|
||||
{
|
||||
err_msg = $"Not found SystemMailMeta !!! : mailKey:{system_mail_key} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.SystemMailMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var mail_items = new List<ServerCommon.MailItem>() { new ServerCommon.MailItem() { ItemId = (META_ID)currencyMetaData.ItemId, Count = refundableBlindBidPrice } };
|
||||
(result, var new_mail_doc) = await Mail.createSystemMailWithMeta( player.getUserGuid(), user_nickname, systemMailMetaData
|
||||
, mail_items, GameConfigMeta.LandAuctionFailedMailPeriodMinutes );
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to createSystemMailWithMeta() !!! : {result.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().info(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(new_mail_doc, () => $"new_mail_doc is null !!! : ne - {player.toBasicString()}");
|
||||
to_new_mail_docs.Add(new_mail_doc);
|
||||
|
||||
to_change_attrib_actions.Add( nameof(LandAuctionRefundBidPriceAttrib.RefundableBlindBidPrice)
|
||||
, new DynamoDbItemRequestHelper.AttribAction { ValueAction = DynamoDbItemRequestHelper.AttribValueAction.Decrease
|
||||
, Value = new AttributeValue { N = refundableBlindBidPrice.ToString() } });
|
||||
|
||||
bid_price_attribute.RefundableBlindBidPrice = 0;
|
||||
}
|
||||
|
||||
if(0 < to_change_attrib_actions.Count)
|
||||
{
|
||||
var refund_bid_price_doc = new LandAuctionRefundBidPriceDoc(player.getUserGuid(), land_meta_id, auction_number);
|
||||
(result, var query_context) = DynamoDbItemRequestHelper.makeUpdateItemRequestWithDoc<LandAuctionRefundBidPriceAttrib>(refund_bid_price_doc, to_change_attrib_actions);
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, null, null);
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(query_context, () => $"query_context is null !!!");
|
||||
|
||||
item_request_query_context = query_context;
|
||||
}
|
||||
|
||||
return (result, to_new_mail_docs, item_request_query_context);
|
||||
}
|
||||
|
||||
private void setDeletable() => m_is_deletable = true;
|
||||
public bool isDeletable() => m_is_deletable;
|
||||
|
||||
public LAND_AUCTION_NUMBER getAuctionNumber()
|
||||
{
|
||||
var owner = getOwner() as LandAuctionRefundBidPrice;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var bid_price_attribute = owner.getEntityAttributeWithReadOnly<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(bid_price_attribute, () => $"bid_price_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
return bid_price_attribute.AuctionNumber;
|
||||
}
|
||||
|
||||
public META_ID getLandMetaId()
|
||||
{
|
||||
var owner = getOwner() as LandAuctionRefundBidPrice;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var bid_price_attribute = owner.getEntityAttributeWithReadOnly<LandAuctionRefundBidPriceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(bid_price_attribute, () => $"bid_price_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
return bid_price_attribute.LandMetaId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class LandAuctionRefundBidPrice : EntityBase
|
||||
{
|
||||
public LandAuctionRefundBidPrice(Player owner)
|
||||
: base(EntityType.LandAuctionRefundBidPrice, owner)
|
||||
{
|
||||
}
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
addEntityAttribute(new LandAuctionRefundBidPriceAttribute(this));
|
||||
|
||||
addEntityAction(new LandAuctionRefundBidPriceAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}"
|
||||
+ $", {getOriginEntityAttribute<LandAuctionRefundBidPriceAttribute>()?.toBasicString()}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}"
|
||||
+ $", {getEntityAttribute<LandAuctionRefundBidPriceAttribute>()?.toSummaryString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
321
GameServer/Entity/Money/Action/MoneyAction.cs
Normal file
321
GameServer/Entity/Money/Action/MoneyAction.cs
Normal file
@@ -0,0 +1,321 @@
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class MoneyAction : EntityActionBase, IRemoteTransaction
|
||||
{
|
||||
public MoneyAction(Player owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//=============================================================================================
|
||||
// delta 만큼 금전을 쓴다.
|
||||
//=============================================================================================
|
||||
public async Task<Result> spendMoney(CurrencyType currencyType, double delta, bool isTrimExcess = false, bool useCaliumEvent = true)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
if (ServerCore.TypeHelper.NumericSignType.Positive == ServerCore.TypeHelper.checkNumericSignType<double>(delta))
|
||||
{
|
||||
delta *= -1;
|
||||
}
|
||||
|
||||
if (0 > delta)
|
||||
{
|
||||
result = await changeMoney(currencyType, delta, isTrimExcess, useCaliumEvent);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//=============================================================================================
|
||||
// delta 만큼 금전을 얻는다.
|
||||
//=============================================================================================
|
||||
public async Task<Result> earnMoney(CurrencyType currencyType, double delta, bool isTrimExcess = false)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
if (ServerCore.TypeHelper.NumericSignType.Negative == ServerCore.TypeHelper.checkNumericSignType<double>(delta))
|
||||
{
|
||||
delta *= -1;
|
||||
}
|
||||
|
||||
if (0 < delta)
|
||||
{
|
||||
result = await changeMoney(currencyType, delta, isTrimExcess);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================================
|
||||
// delta 만큼 금전을 변경(음수, 양수) 한다.
|
||||
//=============================================================================================
|
||||
public async Task<Result> changeMoney(CurrencyType currencyType, double delta, bool isTrimExcess = false, bool useCaliumEvent = true)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"player is null !!!");
|
||||
|
||||
delta = CurrencyControlHelper.roundMoneyByCurrencyType(currencyType, delta);
|
||||
|
||||
if (currencyType == CurrencyType.Beam)
|
||||
{
|
||||
var found_transaction_runner = owner.findTransactionRunner(TransactionIdType.PrivateContents);
|
||||
found_transaction_runner?.addRemoteChargeAIPoint(this, delta);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = changeMoneyFromCurrencyType(currencyType, delta, isTrimExcess);
|
||||
if (result.isSuccess() && useCaliumEvent)
|
||||
{
|
||||
var found_transaction_runner = owner.findTransactionRunner(TransactionIdType.PrivateContents);
|
||||
var event_name = found_transaction_runner?.getTransactionName() ?? "None";
|
||||
found_transaction_runner?.addNotifyCaliumEvent(this, event_name, currencyType, delta);
|
||||
}
|
||||
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
private Result changeMoneyFromCurrencyType(CurrencyType type, double delta, bool isTrimExcess = false)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"player is null !!!");
|
||||
|
||||
if (MetaData.Instance._CurrencyMetaTableByCurrencyType.TryGetValue(type, out var currencyMetaData) == false)
|
||||
{
|
||||
err_msg = $"Not found CurrencyMetaData !!! : currencyType:{type} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.CurrencyMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var money_attribute = owner.getEntityAttribute<MoneyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(money_attribute, () => $"money_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var currency = money_attribute.getCurrencyFromType(type);
|
||||
var change = currency + delta;
|
||||
if (change < 0)
|
||||
{
|
||||
err_msg = $"Failed to change getCurrencyFromType() !!!, not enough Money : deltaMoney:{delta}, changeCurrency:{change}, currencyType:{type} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MoneyNotEnough, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (change >= currencyMetaData.MaxCount)
|
||||
{
|
||||
MoneyNotifyHelper.send_GS2C_NTF_CURRENCY_MAX_ALERT(owner, type, currencyMetaData.MaxCount);
|
||||
|
||||
if (change > currencyMetaData.MaxCount
|
||||
&& false == isTrimExcess)
|
||||
{
|
||||
err_msg = $"Money exceeded Max Count !!! : toDelta:{delta}, toChange:{change} <= MaxCount:{currencyMetaData.MaxCount}, currencyType:{type} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MoneyMaxCountExceeded, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var trim_money = change - currencyMetaData.MaxCount;
|
||||
change = double.Min(change, currencyMetaData.MaxCount);
|
||||
|
||||
err_msg = $"Exceeded MaxCount of Money !!!, Trimming Money : currencyType:{type}, changeMoney:{change}, trimMoney:{trim_money}, deltaMoney:{delta}, maxMoney:{currencyMetaData.MaxCount} - {owner.toBasicString()}";
|
||||
Log.getLogger().info(err_msg);
|
||||
}
|
||||
|
||||
money_attribute.setCurrencyFromType(type, change);
|
||||
|
||||
money_attribute.modifiedEntityAttribute();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool hasMoney(CurrencyType currencyType, double toCheckAmount)
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"player is null !!!");
|
||||
|
||||
var money_attribute = owner.getEntityAttribute<MoneyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(money_attribute, () => $"money_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var has_money = money_attribute.getCurrencyFromType(currencyType);
|
||||
|
||||
if (has_money < toCheckAmount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public double getMoney(CurrencyType currencyType)
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"player is null !!!");
|
||||
|
||||
var money_attribute = owner.getEntityAttribute<MoneyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(money_attribute, () => $"money_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
return money_attribute.getCurrencyFromType(currencyType);
|
||||
}
|
||||
|
||||
public CharInfo toCurrency4Client()
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"player is null !!!");
|
||||
|
||||
var money_attribute = owner.getEntityAttribute<MoneyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(money_attribute, () => $"money_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var char_info = new CharInfo();
|
||||
char_info.Gold = money_attribute.Gold;
|
||||
char_info.Sapphire = money_attribute.Sapphire;
|
||||
char_info.Calium = money_attribute.Calium;
|
||||
char_info.Ruby = money_attribute.Ruby;
|
||||
|
||||
return char_info;
|
||||
}
|
||||
|
||||
public async Task<Result> callRemoteChargeAIPoint(double beamDelta)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!");
|
||||
|
||||
var ai_chat_action = player.getEntityAction<AIChatAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ai_chat_action, () => $"ai_chat_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
if (beamDelta <= 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var order_guid = Guid.NewGuid().ToString("N");
|
||||
result = await ai_chat_action.pointCharge(new AIChatPointCharge() { userGuid = player.getUserGuid(), points = beamDelta, orderGuid = order_guid, pointType = ServerCommon.Constant.AI_CHAT_FREE_POINT, description = "" });
|
||||
if (result.ErrorCode == ServerErrorCode.AiChatServerRetryChargePoint)
|
||||
{
|
||||
var task_reservation_action = player.getEntityAction<TaskReservationAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(task_reservation_action, () => $"task_reservation_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
(result, var task_reservation) = await TaskReservation.createTaskReservationForBeamCharge(player, beamDelta, ServerCommon.Constant.AI_CHAT_FREE_POINT, Guid.NewGuid().ToString("N"));
|
||||
if(result.isFail() || null == task_reservation)
|
||||
{
|
||||
err_msg = $"Failed to create task reservation for beam charge !!! : beamDelta - {beamDelta}, player:{player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
task_reservation_action.AddTask(task_reservation);
|
||||
}
|
||||
else if (result.isSuccess())
|
||||
{
|
||||
MoneyNotifyHelper.send_GS2C_NTF_BEAM_CHARGE(player);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> callNotifyCaliumEvent(string eventName, CurrencyType currencyType, double delta)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!");
|
||||
|
||||
// 1. 조건 체크
|
||||
var is_condition = checkConditionCaliumEvent(currencyType, delta);
|
||||
if (false == is_condition) return result;
|
||||
|
||||
var sapphire_delta = 0.0;
|
||||
var calium_delta = 0.0;
|
||||
|
||||
var event_type = CaliumEventType.none;
|
||||
|
||||
// 1. 기본 정보 설정
|
||||
if (currencyType == CurrencyType.Sapphire)
|
||||
{
|
||||
event_type = CaliumEventType.extra_get;
|
||||
sapphire_delta = delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
event_type = CaliumEventType.calium_burn;
|
||||
calium_delta = delta;
|
||||
}
|
||||
|
||||
// 2. 이벤트 전송 ( 실패시 재시도 처리 ) : Fire And Forget
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
var calium_storage_entity = GameServerApp.getServerLogic().findGlobalEntity<CaliumStorageEntity>();
|
||||
NullReferenceCheckHelper.throwIfNull(calium_storage_entity, () => $"calium_storage_entity");
|
||||
|
||||
var calium_event_action = calium_storage_entity.getEntityAction<CaliumEventAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(calium_event_action, () => $"calium_event_action is null !!! - {calium_storage_entity.toBasicString()} / {player.toBasicString()}");
|
||||
|
||||
var send = await calium_event_action.sendCaliumEventFromPlayer(player, event_type, eventName,
|
||||
sapphire_delta, calium_delta);
|
||||
if (false == send.is_success)
|
||||
{
|
||||
err_msg =
|
||||
$"failed to echo system from moneyAction !! event_type[{event_type}] / sapphireDelta[{sapphire_delta}] caliumDelta[{calium_delta}]";
|
||||
result.setFail(ServerErrorCode.FailToSendEchoSystem, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
});
|
||||
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
private bool checkConditionCaliumEvent(CurrencyType currencyType, double delta)
|
||||
{
|
||||
// 조건 1. 재화 타입이 Calium or Sapphire 가 아니면 리턴
|
||||
if (currencyType != CurrencyType.Sapphire && currencyType != CurrencyType.Calium) return false;
|
||||
|
||||
// 조건 2. 재화 타입이 Calium 이고 delta 가 양수 이면 리턴
|
||||
if (currencyType == CurrencyType.Calium && delta > 0) return false;
|
||||
|
||||
// 조건 3. 재화 타입이 sapphire 이고, 양수 이면 리턴
|
||||
if (currencyType == CurrencyType.Sapphire && delta > 0) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
117
GameServer/Entity/Money/MoneyCheat.cs
Normal file
117
GameServer/Entity/Money/MoneyCheat.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
[ChatCommandAttribute("currencymodify", typeof(ChatCommandModifyCurrency), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
|
||||
internal class ChatCommandModifyCurrency : ChatCommandBase
|
||||
{
|
||||
public override async Task invoke(Player player, string token, string[] args)
|
||||
{
|
||||
Log.getLogger().info($"Call currencymodify !!! - {player.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (args.Length < 2)
|
||||
{
|
||||
err_msg = $"Not enough argument !!! : argCount:{args.Length} == 2 - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (int.TryParse(args[0], out int currency_type) == false || double.TryParse(args[1], out double amount) == false)
|
||||
{
|
||||
err_msg = $"Invalid argument !!! - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((CurrencyType)currency_type == CurrencyType.Beam)
|
||||
{
|
||||
err_msg = $"Invalid CurrencyType !!! : {currency_type} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return;
|
||||
}
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"server_logic is null !! - {player.toBasicString()}");
|
||||
|
||||
var fn_currency_modify = async delegate ()
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
ClientToGame clientToGame = new();
|
||||
clientToGame.Response = new();
|
||||
clientToGame.Response.GetCurrencyInfoRes = new();
|
||||
|
||||
var money_action = player.getEntityAction<MoneyAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(money_action, () => $"money_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
result = await money_action.changeMoney((CurrencyType)currency_type, amount, true, false);
|
||||
if(result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to changeMoney() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>( player, LogActionType.MoneyChange
|
||||
, server_logic.getDynamoDbClient());
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
}
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
clientToGame.Response.GetCurrencyInfoRes.CurrencyInfo = money_action.toCurrency4Client();
|
||||
|
||||
player.sendPacket(clientToGame);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "Cheat.CurrencyModify", fn_currency_modify);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ChatCommandAttribute("beamcharge", typeof(ChatCommandBeamCharge), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
|
||||
internal class ChatCommandBeamCharge : ChatCommandBase
|
||||
{
|
||||
public override async Task invoke(Player player, string token, string[] args)
|
||||
{
|
||||
Log.getLogger().info($"Call beamcharge !!! - {player.toBasicString()}");
|
||||
|
||||
if (args.Length < 1)
|
||||
return;
|
||||
|
||||
if (int.TryParse(args[0], out int amount) == false)
|
||||
return;
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var ai_chat_action = player.getEntityAction<AIChatAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ai_chat_action, () => $"money_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var order_guid = Guid.NewGuid().ToString("N");
|
||||
result = await ai_chat_action.pointCharge(new AIChatPointCharge() { userGuid = player.getUserGuid(), points = amount, orderGuid = order_guid, pointType = ServerCommon.Constant.AI_CHAT_FREE_POINT, description = "Cheat Beam" });
|
||||
if (result.isSuccess())
|
||||
{
|
||||
MoneyNotifyHelper.send_GS2C_NTF_BEAM_CHARGE(player);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
948
GameServer/Entity/Npc/UgcNpc/Action/UgcNpcAction.cs
Normal file
948
GameServer/Entity/Npc/UgcNpc/Action/UgcNpcAction.cs
Normal file
@@ -0,0 +1,948 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
|
||||
using static ClientToGameRes.Types;
|
||||
using static ServerMessage.Types;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 UGC_NPC_META_GUID = System.String;
|
||||
using ITEM_GUID = System.String;
|
||||
using INSTANCE_GUID = System.String;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class UgcNpcAction : EntityActionBase
|
||||
{
|
||||
private Map? m_map_nullable;
|
||||
|
||||
private bool m_is_counting_as_add_connected_user = false;
|
||||
|
||||
public UgcNpcAction(UgcNpc owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<Result> createByUgcNpcDocWithMaster(UgcNpcDoc ugcNpcDoc, Player master)
|
||||
{
|
||||
var owner = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(master, () => $"master is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var err_msg = string.Empty;
|
||||
var result = new Result();
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromDocs(ugc_npc_attribute, new List<DynamoDbDocBase>() { ugcNpcDoc });
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDocs() !!!, to:{ugc_npc_attribute.getTypeName()}, from:{ugcNpcDoc.getTypeName()} : {result.toBasicString()} - {owner.toBasicString()}, {master.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
result = await ensureUgcNpcBasicDocs();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to ensureUgcNpcBasicDoc() !!! : {result.toBasicString()} - {owner.toBasicString()}, {master.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> ensureUgcNpcBasicDocs()
|
||||
{
|
||||
var owner = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
var dynamo_db_client = server_logic.getDynamoDbClient();
|
||||
{
|
||||
// UgcNpcNicknameRegistryDoc이 등록이 안되어 있는 경우 등록 한다. - kangms
|
||||
var ugc_npc_nickname_registry_doc = new UgcNpcNicknameRegistryDoc(OwnerEntityType.User, ugc_npc_attribute.OwnerGuid, ugc_npc_attribute.Nickname, ugc_npc_attribute.UgcNpcMetaGuid);
|
||||
var ugc_npc_nickname_registry_query_config = dynamo_db_client.makeQueryConfigForReadByPKSK(ugc_npc_nickname_registry_doc.getPK(), ugc_npc_nickname_registry_doc.getSK());
|
||||
(var query_result, var ugc_npc_nickname_registry_docs) = await dynamo_db_client.simpleQueryDocTypesWithQueryOperationConfig<UgcNpcNicknameRegistryDoc>(ugc_npc_nickname_registry_query_config);
|
||||
if (ugc_npc_nickname_registry_docs.Count == 0)
|
||||
{
|
||||
query_result = await ugc_npc_nickname_registry_doc.newDoc4Query();
|
||||
if(query_result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to newDoc4Query() !!!, {ugc_npc_nickname_registry_doc.toDocTypePKSK()}"
|
||||
+ $" : {query_result.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return query_result;
|
||||
}
|
||||
|
||||
query_result = await dynamo_db_client.simpleUpsertDocumentWithDocType(ugc_npc_nickname_registry_doc);
|
||||
if (query_result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleUpsertDocumentWithDocType() !!!, {ugc_npc_nickname_registry_doc.toDocTypePKSK()}"
|
||||
+ $" : {query_result.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return query_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// UgcNpcLikeSelecteeCountDoc 등록이 안되어 있는 경우 등록 한다. - kangms
|
||||
var selectee_count_doc = new UgcNpcLikeSelecteeCountDoc(OwnerEntityType.UgcNpc, ugc_npc_attribute.UgcNpcMetaGuid);
|
||||
var selectee_count_query_config = dynamo_db_client.makeQueryConfigForReadByPKSK(selectee_count_doc.getPK(), selectee_count_doc.getSK());
|
||||
(var query_result, var npc_like_selectee_count_docs) = await dynamo_db_client.simpleQueryDocTypesWithQueryOperationConfig<UgcNpcLikeSelecteeCountDoc>(selectee_count_query_config);
|
||||
if (npc_like_selectee_count_docs.Count == 0)
|
||||
{
|
||||
query_result = await selectee_count_doc.newDoc4Query();
|
||||
if (query_result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to newDoc4Query() !!!, {selectee_count_doc.toDocTypePKSK()}"
|
||||
+ $" : {query_result.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return query_result;
|
||||
}
|
||||
|
||||
query_result = await dynamo_db_client.simpleUpsertDocumentWithDocType(selectee_count_doc);
|
||||
if (query_result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleUpsertDocumentWithDocType() !!!, {selectee_count_doc.toDocTypePKSK()}"
|
||||
+ $" : {query_result.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return query_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> createByUgcNpcDoc(UgcNpcDoc ugcNpcDoc)
|
||||
{
|
||||
var owner = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var err_msg = string.Empty;
|
||||
var result = new Result();
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromDocs(ugc_npc_attribute, new List<DynamoDbDocBase>() { ugcNpcDoc });
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeFromDocs() !!!, to:{ugc_npc_attribute.getTypeName()}, from:{ugcNpcDoc.getTypeName()} - {owner.toBasicStringWithMaster()}";
|
||||
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(Result, ItemDoc?)> createItemDocByTransferOwnerFromUserItem(UserItemAttribute userItemAttribute)
|
||||
{
|
||||
var owner = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(userItemAttribute, () => $"userItemAttribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
var err_msg = string.Empty;
|
||||
var result = new Result();
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var item_doc = new ItemDoc(OwnerEntityType.UgcNpc, ugc_npc_attribute.UgcNpcMetaGuid, userItemAttribute.ItemGuid);
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyDocFromEntityAttributes(item_doc, new List<EntityAttributeBase>() { userItemAttribute });
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to copyDocFromEntityAttributes() !!!, to:{item_doc.getTypeName()}, from:{userItemAttribute.getTypeName()} - {owner.toBasicStringWithMaster()}";
|
||||
result.setFail(ServerErrorCode.EntityAttributeCopyToDynamoDbDocFailed, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, item_doc);
|
||||
}
|
||||
|
||||
public async Task<Result> tryTakableItemFromUser( List<ITEM_GUID> materialItemGuids, Dictionary<Int32, BoolType> tattooSlotVisibles
|
||||
, Dictionary<InvenEquipType, HashSet<Int16>> reservedSlotTypes
|
||||
, Player master )
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var ugc_npc = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!!");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(master, () => $"master is null !!!");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(materialItemGuids, () => $"materialItems is null !!! - {master.toBasicString()}");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(tattooSlotVisibles, () => $"tattooSlotVisibles is null !!! - {master.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var user_inventory_action = master.getEntityAction<UserInventoryAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_inventory_action, () => $"user_inventory_action is null !!! - {master.toBasicString()}");
|
||||
|
||||
var ugc_npc_inventory_action = ugc_npc.getEntityAction<UgcNpcInventoryAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_inventory_action, () => $"ugc_npc_inventory_action is null !!! - {master.toBasicString()}");
|
||||
|
||||
//=====================================================================================
|
||||
// 1. 재료 아이템 소유 관계 변경 : User => UgcNpc
|
||||
//=====================================================================================
|
||||
foreach (var material_item_guid in materialItemGuids)
|
||||
{
|
||||
var found_item = user_inventory_action.tryGetItemByItemGuid(material_item_guid);
|
||||
NullReferenceCheckHelper.throwIfNull(found_item, () => $"found_item is null !!! - {master.toBasicString()}");
|
||||
|
||||
var item_meta = found_item.getItemMeta();
|
||||
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {master.toBasicString()}");
|
||||
|
||||
var backup_item_attribute = found_item.getClonedEntityAttribute<UserItemAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(backup_item_attribute, () => $"backup_item_attribute is null !!! - {master.toBasicString()}");
|
||||
|
||||
(result, var deleted_item) = await user_inventory_action.tryDeleteItemByGuid(material_item_guid);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
(result, ItemDoc? to_create_item_doc_of_ugc_npc) = await backup_item_attribute.changeOwnerAndCreateItemDoc(OwnerEntityType.UgcNpc, ugc_npc.getUgcNpcMetaGuid());
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(to_create_item_doc_of_ugc_npc, () => $"to_create_item_doc_of_ugc_npc is null !!! - {master.toBasicString()}");
|
||||
|
||||
(result, var equipable_slot) = ugc_npc_inventory_action.getEquipableSlotOfEquipInven(item_meta, reservedSlotTypes);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
(result, _) = await ugc_npc_inventory_action.tryTakableToBagWithEquip(to_create_item_doc_of_ugc_npc, equipable_slot);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// 2. 타투 아이템 보이기/안보이기 설정
|
||||
//=====================================================================================
|
||||
var tattoo_inven = ugc_npc_inventory_action.getEquipInvens()[InvenEquipType.Tattoo] as TattooEquipInven;
|
||||
NullReferenceCheckHelper.throwIfNull(tattoo_inven, () => $"tattoo_inven is null !!! - {master.toBasicString()}");
|
||||
|
||||
foreach (var each in tattooSlotVisibles)
|
||||
{
|
||||
var slot_index = each.Key;
|
||||
var slot_visible = each.Value;
|
||||
|
||||
if (false == InvenEquipType.Tattoo.isEquipableTattooSlotType((TattooSlotType)slot_index, ugc_npc.getEntityType()))
|
||||
{
|
||||
err_msg = $"Not found TattooSlotType !!! : slotType:{slot_index} - {toBasicString()}, {master.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.TattooEquipRuleTattooSlotTypeNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var custom_defined_ui_action = ugc_npc.getEntityAction<CustomDefinedUiAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(custom_defined_ui_action, () => $"custom_defined_ui_action is null !!! - {toBasicString()}, {master.toBasicString()}");
|
||||
|
||||
var tattoo_slot = (TattooSlotType)slot_index;
|
||||
result = await custom_defined_ui_action.setTattooVisible(tattoo_slot, (slot_visible == BoolType.True ? true : false));
|
||||
if(result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> tryRegisterCharacterWithAiChatServer(Player master)
|
||||
{
|
||||
var owner = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(master, () => $"master is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var ai_chat_action = master.getEntityAction<AIChatAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ai_chat_action, () => $"ai_chat_action is null !!! - {master.toBasicString()}");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
if(true == ugc_npc_attribute.IsRegisteredAiChatServer)
|
||||
{
|
||||
err_msg = $"Already registered UgcNpc to AiChatServer !!! : ugcNpcMetaGuid:{ugc_npc_attribute.UgcNpcMetaGuid}, ugcNpcNickname:{ugc_npc_attribute.Nickname}, "
|
||||
+ $" - {owner?.toBasicStringWithMaster()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
result = await ai_chat_action.registerCharacter(toRegisterInfoWithAiChatServer());
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to AiChatAction.registerCharacter() !!!, {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ugc_npc_attribute.IsRegisteredAiChatServer = true;
|
||||
ugc_npc_attribute.modifiedEntityAttribute();
|
||||
|
||||
(result, var ugc_npc_doc) = await ugc_npc_attribute.toDocBase();
|
||||
if (result.isFail() || null == ugc_npc_doc)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var dynamo_db_client = server_logic.getDynamoDbClient();
|
||||
NullReferenceCheckHelper.throwIfNull(dynamo_db_client, () => $"dynamo_db_client is null !!! - {owner?.toBasicStringWithMaster()}");
|
||||
|
||||
result = await dynamo_db_client.simpleUpdateDocumentWithDocType(ugc_npc_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to DynamoDbClient.simpleUpdateDocumentWithDocType() !!! : {result.toBasicString()} - {owner.toBasicStringWithMaster()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> tryUpdateCharacterWithAiChatServer(Player master)
|
||||
{
|
||||
var owner = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(master, () => $"master is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var ugc_npc_action = owner.getEntityAction<UgcNpcAction>();
|
||||
ArgumentNullException.ThrowIfNull(ugc_npc_action, $"ugc_npc_action is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
var ai_chat_action = master.getEntityAction<AIChatAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ai_chat_action, () => $"ai_chat_action is null !!! - {master.toBasicString()}");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
if (false == ugc_npc_attribute.IsRegisteredAiChatServer)
|
||||
{
|
||||
err_msg = $"Not registered UgcNpc at AiChatServer !!! : ugcNpcMetaGuid:{ugc_npc_attribute.UgcNpcMetaGuid}, ugcNpcNickname:{ugc_npc_attribute.Nickname}, "
|
||||
+ $" - {owner.toBasicStringWithMaster()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
result = await ai_chat_action.registerCharacter(ugc_npc_action.toRegisterInfoWithAiChatServer());
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to AiChatAction.registerCharacter() !!!, {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
result = await ai_chat_action.updateCharacter(ugc_npc_action.toRegisterInfoWithAiChatServer());
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to AiChatAction.updateCharacter() !!!, {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ugc_npc_attribute.IsRegisteredAiChatServer = true;
|
||||
ugc_npc_attribute.modifiedEntityAttribute();
|
||||
|
||||
(result, var ugc_npc_doc) = await ugc_npc_attribute.toDocBase();
|
||||
if (result.isFail() || null == ugc_npc_doc)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var dynamo_db_client = server_logic.getDynamoDbClient();
|
||||
NullReferenceCheckHelper.throwIfNull(dynamo_db_client, () => $"dynamo_db_client is null !!! - {owner?.toBasicStringWithMaster()}");
|
||||
|
||||
result = await dynamo_db_client.simpleUpdateDocumentWithDocType(ugc_npc_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to DynamoDbClient.simpleUpdateDocumentWithDocType() !!! : {result.toBasicString()} - {owner.toBasicStringWithMaster()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(Result, UgcNpc?)> tryDelete()
|
||||
{
|
||||
var owner = getOwner();
|
||||
|
||||
var result = new Result();
|
||||
|
||||
// UgcNpcDoc 제거 하기
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
ugc_npc_attribute.deleteEntityAttribute();
|
||||
|
||||
// 보유중인 모든 ItemDoc 제거 하기
|
||||
var ugc_npc_inventory_action = owner.getEntityAction<UgcNpcInventoryAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_inventory_action, () => $"ugc_npc_inventory_action is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
var bag_inven = ugc_npc_inventory_action.getBagInven();
|
||||
NullReferenceCheckHelper.throwIfNull(bag_inven, () => $"bag_inven is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
(result, _) = await ugc_npc_inventory_action.tryDeleteItemAll();
|
||||
if(result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, owner as UgcNpc);
|
||||
}
|
||||
|
||||
public bool isEqualUgcNpc(string toCheckUgcNpcNickname)
|
||||
{
|
||||
var owner = getOwner();
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
if (ugc_npc_attribute.Nickname == toCheckUgcNpcNickname)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool isLocatedUgcNpc()
|
||||
{
|
||||
var owner = getOwner();
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
if(EntityStateType.None == ugc_npc_attribute.State)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<Result> tryLocateInGameZone(Map toLocateMap, INSTANCE_GUID instanceGuid = "")
|
||||
{
|
||||
var ugc_npc = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!!");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (true == isLinkedToMap())
|
||||
{
|
||||
var curr_map = getLinkedToMap();
|
||||
NullReferenceCheckHelper.throwIfNull(curr_map, () => $"curr_map is null !!! - {ugc_npc.toBasicStringWithMaster()}");
|
||||
|
||||
err_msg = $"Entity is linked to Map !!! : currMap:{curr_map.toBasicString()} - InstanceGuid:{instanceGuid}, {ugc_npc.toBasicStringWithMaster()}";
|
||||
result.setFail(ServerErrorCode.EntityLinkedToMap, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var linked_map = setLinkToMap(toLocateMap);
|
||||
|
||||
result = await linked_map.tryLocateUgcNpc(ugc_npc);
|
||||
if(result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var ugc_npc_attribute = ugc_npc.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {ugc_npc.toBasicStringWithMaster()}");
|
||||
|
||||
ugc_npc_attribute.LocatedInstanceGuid = instanceGuid;
|
||||
ugc_npc_attribute.LocatedInstanceMetaId = (UInt32)linked_map.MapMId;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> tryRemoveInGameZone()
|
||||
{
|
||||
var ugc_npc = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!!");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (false == isLinkedToMap())
|
||||
{
|
||||
err_msg = $"Enity not linked to Map !!! - {ugc_npc.toBasicStringWithMaster()}";
|
||||
result.setFail(ServerErrorCode.EntityNotLinkedToMap, err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var linked_to_map = getLinkedToMap();
|
||||
NullReferenceCheckHelper.throwIfNull(linked_to_map, () => $"linked_to_map is null !!! - {ugc_npc.toBasicStringWithMaster()}");
|
||||
|
||||
result = await linked_to_map.tryRemoveUgcNpc(ugc_npc);
|
||||
if(result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
unlinkToMap();
|
||||
|
||||
var ugc_npc_attribute = ugc_npc.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {ugc_npc.toBasicStringWithMaster()}");
|
||||
|
||||
ugc_npc_attribute.LocatedInstanceGuid = string.Empty;
|
||||
ugc_npc_attribute.LocatedInstanceMetaId = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool isLinkedToMap()
|
||||
{
|
||||
if (null != m_map_nullable)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void unlinkToMap()
|
||||
{
|
||||
m_map_nullable = null;
|
||||
}
|
||||
|
||||
private Map setLinkToMap(Map toLinkMap)
|
||||
{
|
||||
var owner = getOwner();
|
||||
|
||||
m_map_nullable = toLinkMap;
|
||||
|
||||
return m_map_nullable;
|
||||
}
|
||||
|
||||
public Map? getLinkedToMap()
|
||||
{
|
||||
return m_map_nullable;
|
||||
}
|
||||
|
||||
public void modifyStateInfo(EntityStateType entityStateType, EntityPos currPos, string anchorMetaGuid = "", META_ID metaId = 0, bool isApplyDb = true)
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
ugc_npc_attribute.State = entityStateType;
|
||||
ugc_npc_attribute.AnchorMetaGuid = anchorMetaGuid;
|
||||
ugc_npc_attribute.MetaIdOfEntityStateType = metaId;
|
||||
ugc_npc_attribute.setCurrentPos(currPos);
|
||||
|
||||
if (true == isApplyDb)
|
||||
{
|
||||
ugc_npc_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
}
|
||||
|
||||
public void resetPos(bool isApplyDb = true)
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
ugc_npc_attribute.State = EntityStateType.None;
|
||||
ugc_npc_attribute.AnchorMetaGuid = string.Empty;
|
||||
ugc_npc_attribute.MetaIdOfEntityStateType = 0;
|
||||
ugc_npc_attribute.setCurrentPos(new EntityPos());
|
||||
ugc_npc_attribute.LocatedInstanceGuid = string.Empty;
|
||||
ugc_npc_attribute.LocatedInstanceMetaId = 0;
|
||||
|
||||
if (true == isApplyDb)
|
||||
{
|
||||
ugc_npc_attribute.modifiedEntityAttribute();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateUgcNpcCompact(GS2MQS_NTF_BEACON_COMPACT_SYNC ugcNpcCompactSync)
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(ugcNpcCompactSync, () => $"ugcNpcCompactSync is null !!! - {owner.toBasicString()}");
|
||||
var ugc_npc_compact = ugcNpcCompactSync.UgcNpcCompact;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(ugc_npc_compact, () => $"ugc_npc_compact is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var ugc_npc_attribute_origin = owner.getOriginEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute_origin, () => $"ugc_npc_attribute_origin is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var entity_state_info = ugc_npc_compact.EntityStateInfo;
|
||||
NullReferenceCheckHelper.throwIfNull(entity_state_info, () => $"entity_state_info is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var state_type = ugc_npc_compact.EntityStateInfo.StateType;
|
||||
var anchor_meta_guid = ugc_npc_compact.EntityStateInfo.AnchorMetaGuid;
|
||||
var meta_id = (UInt32)ugc_npc_compact.EntityStateInfo.MetaIdOfStateType;
|
||||
var curr_pos = EntityStateType.None == state_type ? new EntityPos() : ugc_npc_attribute.getCurrentPos();
|
||||
modifyStateInfo(ugc_npc_compact.EntityStateInfo.StateType, curr_pos, anchor_meta_guid, meta_id, false);
|
||||
|
||||
var located_instance_context = ugc_npc_compact.LocatedInstanceContext;
|
||||
NullReferenceCheckHelper.throwIfNull(located_instance_context, () => $"located_instance_context is null !!! - {owner.toBasicString()}");
|
||||
|
||||
ugc_npc_attribute.LocatedInstanceGuid = ugcNpcCompactSync.LocatedInstanceGuid;
|
||||
ugc_npc_attribute.LocatedInstanceMetaId = (UInt32)located_instance_context.LocatedinstanceMetaId;
|
||||
|
||||
ugc_npc_attribute_origin.onMerge(ugc_npc_attribute);
|
||||
}
|
||||
|
||||
public EntityPos makeToLocatePosition( System.Numerics.Vector3 basePos, System.Numerics.Vector3 baseRotation
|
||||
, System.Numerics.Vector3 deltaPos, float deltaAngle )
|
||||
{
|
||||
// X축, Y축 Z축에 대한 회전을 순차적으로 적용
|
||||
var rotated_vector = MapHelper.applyRotation(deltaPos, baseRotation);
|
||||
var rotated_vector_with_unreal = new System.Numerics.Vector3(rotated_vector.Y, rotated_vector.X, rotated_vector.Z);
|
||||
|
||||
// 새로운 위치 계산
|
||||
var new_position = basePos + rotated_vector_with_unreal;
|
||||
|
||||
EntityPos current_pos = new EntityPos();
|
||||
current_pos.X = new_position.X;
|
||||
current_pos.Y = new_position.Y;
|
||||
current_pos.Z = new_position.Z;
|
||||
current_pos.FacingAngle = baseRotation.Y + deltaAngle;
|
||||
|
||||
return current_pos;
|
||||
}
|
||||
|
||||
public EntityPos makeToLocatePosition( System.Numerics.Vector3 basePos, double pitch, double yaw, double roll
|
||||
, System.Numerics.Vector3 deltaPos, double deltaAngle )
|
||||
{
|
||||
// X축, Y축 Z축 <=> Pitch, Yaw, Roll 적용
|
||||
//var euler_vector = MapHelper.applyRotationFromYawPitchRoll(deltaPos, (float)yaw, (float)pitch, (float)roll);
|
||||
//var rotated_vector_with_unreal = new System.Numerics.Vector3(euler_vector.Y, euler_vector.X, euler_vector.Z);
|
||||
|
||||
var euler_vector = MapHelper.applyRotationFromYawPitchRoll(deltaPos, (float)pitch, (float)roll, (float)yaw);
|
||||
var rotated_vector_with_unreal = euler_vector;
|
||||
|
||||
// 새로운 위치 계산
|
||||
var new_position = basePos + rotated_vector_with_unreal;
|
||||
|
||||
EntityPos current_pos = new EntityPos();
|
||||
current_pos.X = new_position.X;
|
||||
current_pos.Y = new_position.Y;
|
||||
current_pos.Z = new_position.Z;
|
||||
current_pos.FacingAngle = (float)(yaw + deltaAngle);
|
||||
|
||||
return current_pos;
|
||||
}
|
||||
|
||||
public EntityStateType getCurrentEntityStateType()
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
return ugc_npc_attribute.State;
|
||||
}
|
||||
|
||||
public AIChatRegisterCharacter toRegisterInfoWithAiChatServer()
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
EGenderType gender = EGenderType.MALE;
|
||||
if (MetaData.Instance._ItemTable.TryGetValue((int)ugc_npc_attribute.BodyItemMetaId, out var item_meta_data) == true)
|
||||
{
|
||||
gender = item_meta_data.Gender;
|
||||
|
||||
if(gender == EGenderType.ALL)
|
||||
gender = EGenderType.MALE;
|
||||
}
|
||||
|
||||
var to_register_ai_chat_server = new AIChatRegisterCharacter();
|
||||
to_register_ai_chat_server.guid = ugc_npc_attribute.UgcNpcMetaGuid;
|
||||
to_register_ai_chat_server.ownerUserGuid = ugc_npc_attribute.OwnerGuid;
|
||||
to_register_ai_chat_server.lang = ugc_npc_attribute.LanguageType.ToString().ToLower();
|
||||
to_register_ai_chat_server.name = ugc_npc_attribute.Nickname;
|
||||
to_register_ai_chat_server.persona = UgcNpcHelper.toPersonaWithJsonString(ugc_npc_attribute.WorldScenario, ugc_npc_attribute.Description);
|
||||
to_register_ai_chat_server.firstMes = ugc_npc_attribute.Greeting;
|
||||
to_register_ai_chat_server.shortDesc = ugc_npc_attribute.Introduction;
|
||||
to_register_ai_chat_server.tags = ugc_npc_attribute.HashTagMetaIds;
|
||||
to_register_ai_chat_server.isOfficial = false;
|
||||
to_register_ai_chat_server.socialActionConfig = UgcNpcHelper.toSocialActionConfigWithAIChatServer( ugc_npc_attribute.DefaultSocialActionMetaId, ugc_npc_attribute.HabitSocialActionMetaIds );
|
||||
to_register_ai_chat_server.attributes.gender = (int)gender;
|
||||
|
||||
return to_register_ai_chat_server;
|
||||
}
|
||||
|
||||
public bool isCountingAsAddConnectedUser() => m_is_counting_as_add_connected_user;
|
||||
|
||||
public void setCountingAsConnectedUser(bool isCounting) => m_is_counting_as_add_connected_user = isCounting;
|
||||
|
||||
public EntityPos getCurrentPos()
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
return ugc_npc_attribute.getCurrentPos();
|
||||
}
|
||||
|
||||
public UgcNpcEntity toUgcNpcEntity()
|
||||
{
|
||||
var owner = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
var ugc_npc_entity = new UgcNpcEntity();
|
||||
ugc_npc_entity.EntityInstantGuid = owner.getUgcNpcMetaGuid();
|
||||
ugc_npc_entity.CurrentPos = ugc_npc_attribute.getCurrentPos().toPos();
|
||||
ugc_npc_entity.UgcNpcAppearance = toUgcNpcAppearancec();
|
||||
|
||||
return ugc_npc_entity;
|
||||
}
|
||||
|
||||
public UgcNpcSummary toUgcNpcSummary()
|
||||
{
|
||||
var owner = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
var ability_action = owner.getEntityAction<AbilityAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ability_action, () => $"ability_action is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
var ugc_npc_beacon_shop_action = owner.getEntityAction<UgcNpcBeaconShopAction>();
|
||||
|
||||
var ugc_summary = new UgcNpcSummary();
|
||||
ugc_summary.UgcNpcMetaGuid = ugc_npc_attribute.UgcNpcMetaGuid;
|
||||
ugc_summary.OwnerUserGuid = ugc_npc_attribute.OwnerGuid;
|
||||
ugc_summary.Title = ugc_npc_attribute.Title;
|
||||
ugc_summary.Nickname = ugc_npc_attribute.Nickname;
|
||||
ugc_summary.Greeting = ugc_npc_attribute.Greeting;
|
||||
ugc_summary.Introduction = ugc_npc_attribute.Introduction;
|
||||
ugc_summary.Abilities = ability_action.toAbilityInfo();
|
||||
ugc_summary.BodyItemMetaId = (Int32)ugc_npc_attribute.BodyItemMetaId;
|
||||
ugc_summary.HashTagMetaIds.Add(ugc_npc_attribute.HashTagMetaIds.Select<META_ID, Int32>(x => (Int32)x).ToList());
|
||||
|
||||
ugc_summary.Description = ugc_npc_attribute.Description;
|
||||
ugc_summary.WorldScenario = ugc_npc_attribute.WorldScenario;
|
||||
ugc_summary.DefaultSocialActionId = (Int32)ugc_npc_attribute.DefaultSocialActionMetaId;
|
||||
ugc_summary.HabitSocialActionIds.AddRange(ugc_npc_attribute.HabitSocialActionMetaIds.ConvertAll<Int32>(Convert.ToInt32));
|
||||
ugc_summary.DialogueSocialActionIds.AddRange(ugc_npc_attribute.DialogueSocialActionMetaIds.ConvertAll<Int32>(Convert.ToInt32));
|
||||
|
||||
var entity_state_info = new EntityStateInfo();
|
||||
entity_state_info.StateType = ugc_npc_attribute.State;
|
||||
entity_state_info.AnchorMetaGuid = ugc_npc_attribute.AnchorMetaGuid;
|
||||
entity_state_info.MetaIdOfStateType = (Int32)ugc_npc_attribute.MetaIdOfEntityStateType;
|
||||
ugc_summary.EntityStateInfo = entity_state_info;
|
||||
|
||||
var located_instance_context = new LocatedInstanceContext();
|
||||
ugc_summary.LocatedInstanceContext = located_instance_context;
|
||||
located_instance_context.LocatedinstanceMetaId = (Int32)ugc_npc_attribute.LocatedInstanceMetaId;
|
||||
|
||||
var appearance_customize_action = owner.getEntityAction<BeaconAppearanceCustomizeAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(appearance_customize_action, () => $"appearance_customize_action is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
ugc_summary.AppearCustomize = appearance_customize_action.toAppearanceCustomization();
|
||||
|
||||
var ugc_npc_origin_doc = ugc_npc_attribute.getOriginDocBase<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_origin_doc, () => $"ugc_npc_origin_doc is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
ugc_summary.CreatedTime = ugc_npc_origin_doc.getCreatedDateTime().ProcessedTime.ToTimestamp();
|
||||
ugc_summary.HasBeaconShopItem = ugc_npc_beacon_shop_action.hasBeaconShopItem() == true ? BoolType.True : BoolType.False;
|
||||
ugc_summary.HasReceivePayment = BoolType.False;
|
||||
|
||||
|
||||
var masterEntity = owner.onGetMasterEntity();
|
||||
if (masterEntity != null)
|
||||
{
|
||||
var beacon_shop_action = masterEntity.getEntityAction<BeaconShopAction>();
|
||||
if (beacon_shop_action != null)
|
||||
ugc_summary.HasReceivePayment = beacon_shop_action.hasBeaconShopSoldRecord(ugc_summary.UgcNpcMetaGuid) == true ? BoolType.True : BoolType.False;
|
||||
}
|
||||
|
||||
return ugc_summary;
|
||||
}
|
||||
|
||||
public UgcNpcInteraction toUgcNpcInteraction(BoolType isCheckLikeFlag)
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
var ugc_npc_interaction = new UgcNpcInteraction();
|
||||
|
||||
ugc_npc_interaction.UgcNpcMetaGuid = ugc_npc_attribute.UgcNpcMetaGuid;
|
||||
ugc_npc_interaction.OwnerUserGuid = ugc_npc_attribute.OwnerGuid;
|
||||
ugc_npc_interaction.IsCheckLikeFlag = isCheckLikeFlag;
|
||||
|
||||
return ugc_npc_interaction;
|
||||
}
|
||||
|
||||
public UgcNpcAppearance toUgcNpcAppearancec()
|
||||
{
|
||||
var owner = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
var ability_action = owner.getEntityAction<AbilityAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ability_action, () => $"ability_action is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
var ugc_npc_beacon_shop_action = owner.getEntityAction<UgcNpcBeaconShopAction>();
|
||||
|
||||
var ugc_npc_appearance = new UgcNpcAppearance();
|
||||
ugc_npc_appearance.UgcNpcMetaGuid = ugc_npc_attribute.UgcNpcMetaGuid;
|
||||
ugc_npc_appearance.OwnerUserGuid = ugc_npc_attribute.OwnerGuid;
|
||||
ugc_npc_appearance.BodyItemMetaId = (Int32)ugc_npc_attribute.BodyItemMetaId;
|
||||
ugc_npc_appearance.Title = ugc_npc_attribute.Title;
|
||||
ugc_npc_appearance.Nickname = ugc_npc_attribute.Nickname;
|
||||
ugc_npc_appearance.Abilities = ability_action.toAbilityInfo();
|
||||
ugc_npc_appearance.HasItems = toUgcNpcItems();
|
||||
ugc_npc_appearance.DefaultSocialActionId = (Int32)ugc_npc_attribute.DefaultSocialActionMetaId;
|
||||
ugc_npc_appearance.HabitSocialActionIds.AddRange(ugc_npc_attribute.HabitSocialActionMetaIds.Select<META_ID, Int32>(x => (Int32)x).ToList());
|
||||
ugc_npc_appearance.DialogueSocialActionIds.AddRange(ugc_npc_attribute.DialogueSocialActionMetaIds.Select<META_ID, Int32>(x => (Int32)x).ToList());
|
||||
|
||||
var appearance_customize_action = owner.getEntityAction<BeaconAppearanceCustomizeAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(appearance_customize_action, () => $"appearance_customize_action is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
ugc_npc_appearance.AppearCustomize = appearance_customize_action.toAppearanceCustomization();
|
||||
|
||||
var entity_state_info = new EntityStateInfo();
|
||||
entity_state_info.StateType = ugc_npc_attribute.State;
|
||||
entity_state_info.AnchorMetaGuid = ugc_npc_attribute.AnchorMetaGuid;
|
||||
entity_state_info.MetaIdOfStateType = (Int32)ugc_npc_attribute.MetaIdOfEntityStateType;
|
||||
ugc_npc_appearance.EntityStateInfo = entity_state_info;
|
||||
|
||||
ugc_npc_appearance.HasBeaconShopItem = ugc_npc_beacon_shop_action.hasBeaconShopItem() == true ? BoolType.True : BoolType.False;
|
||||
|
||||
return ugc_npc_appearance;
|
||||
}
|
||||
|
||||
public UgcNpcCompact toUgcNpcCompact()
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_attribute = owner.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
var ability_action = owner.getEntityAction<AbilityAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ability_action, () => $"ability_action is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
var ugc_npc_compact = new UgcNpcCompact();
|
||||
ugc_npc_compact.UgcNpcMetaGuid = ugc_npc_attribute.UgcNpcMetaGuid;
|
||||
ugc_npc_compact.OwnerUserGuid = ugc_npc_attribute.OwnerGuid;
|
||||
ugc_npc_compact.Title = ugc_npc_attribute.Title;
|
||||
ugc_npc_compact.Nickname = ugc_npc_attribute.Nickname;
|
||||
ugc_npc_compact.BodyItemMetaId = (Int32)ugc_npc_attribute.BodyItemMetaId;
|
||||
|
||||
var entity_state_info = new EntityStateInfo();
|
||||
entity_state_info.StateType = ugc_npc_attribute.State;
|
||||
entity_state_info.AnchorMetaGuid = ugc_npc_attribute.AnchorMetaGuid;
|
||||
entity_state_info.MetaIdOfStateType = (Int32)ugc_npc_attribute.MetaIdOfEntityStateType;
|
||||
ugc_npc_compact.EntityStateInfo = entity_state_info;
|
||||
|
||||
var located_instance_context = new LocatedInstanceContext();
|
||||
ugc_npc_compact.LocatedInstanceContext = located_instance_context;
|
||||
located_instance_context.LocatedinstanceMetaId = (Int32)ugc_npc_attribute.LocatedInstanceMetaId;
|
||||
|
||||
var ugc_npc_origin_doc = ugc_npc_attribute.getOriginDocBase<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_origin_doc, () => $"ugc_npc_origin_doc is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
ugc_npc_compact.CreatedTime = ugc_npc_origin_doc.getCreatedDateTime().ProcessedTime.ToTimestamp();
|
||||
|
||||
return ugc_npc_compact;
|
||||
}
|
||||
|
||||
public UgcNpcItems toUgcNpcItems()
|
||||
{
|
||||
var owner = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_inventory_action = owner.getEntityAction<UgcNpcInventoryAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_inventory_action, () => $"ugc_npc_inventory_action is null !!! - {owner.toBasicStringWithMaster()}");
|
||||
|
||||
var ugc_npc_items = new UgcNpcItems();
|
||||
ugc_npc_items.HasItems.Add(ugc_npc_inventory_action.toItemAll4Client().toMapField());
|
||||
ugc_npc_items.HasTattooInfos.Add(ugc_npc_inventory_action.toTattooAll4Client().toMapField());
|
||||
|
||||
return ugc_npc_items;
|
||||
}
|
||||
}
|
||||
185
GameServer/Entity/Npc/UgcNpc/Action/UgcNpcBeaconShopAction.cs
Normal file
185
GameServer/Entity/Npc/UgcNpc/Action/UgcNpcBeaconShopAction.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
using System.Collections.Concurrent;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
using ITEM_GUID = System.String;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class UgcNpcBeaconShopAction : EntityActionBase
|
||||
{
|
||||
private bool m_isUpdateBeaconShopItem = false;
|
||||
private ConcurrentDictionary<ITEM_GUID, BeaconShopItem> m_beaconShopItems = new ConcurrentDictionary<ITEM_GUID, BeaconShopItem>();
|
||||
|
||||
public UgcNpcBeaconShopAction(UgcNpc owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<Result> ReloadBeaconShopInventoryFromDb()
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var ugc_npc = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!! - {toBasicString()}");
|
||||
|
||||
if (m_isUpdateBeaconShopItem == false)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {toBasicString()}");
|
||||
var dbClient = server_logic.getDynamoDbClient();
|
||||
|
||||
var ugcNpcMetaGuid = ugc_npc.getUgcNpcMetaGuid();
|
||||
if (ugcNpcMetaGuid == string.Empty)
|
||||
{
|
||||
result.setFail(ServerErrorCode.BeaconShopFailedReloadBeaconShopInven);
|
||||
return result;
|
||||
}
|
||||
|
||||
(result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<BeaconShopItemDoc>(ugcNpcMetaGuid);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - {toBasicString()}");
|
||||
|
||||
var beacon_shop_item_query_config = dbClient.makeQueryConfigForReadByPKOnly(make_primary_key.PK);
|
||||
(var beacon_shop_item_result, var beacon_shop_item_read_docs) = await dbClient.simpleQueryDocTypesWithQueryOperationConfig<BeaconShopItemDoc>(beacon_shop_item_query_config);
|
||||
if (beacon_shop_item_result.isFail() || beacon_shop_item_read_docs == null)
|
||||
{
|
||||
result.setFail(ServerErrorCode.BeaconShopFailedReloadBeaconShopInven);
|
||||
return result;
|
||||
}
|
||||
|
||||
m_beaconShopItems.Clear();
|
||||
|
||||
foreach (var read_doc in beacon_shop_item_read_docs)
|
||||
{
|
||||
var beacon_shop_item_attrib = read_doc.getAttrib<BeaconShopItemAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(beacon_shop_item_attrib, () => $"beacon_shop_item_attrib is null !!! - {toBasicString()}");
|
||||
|
||||
if(beacon_shop_item_attrib.ItemStackCount == 0)
|
||||
{
|
||||
await dbClient.simpleDeleteDocumentWithDocType(read_doc);
|
||||
continue;
|
||||
}
|
||||
|
||||
(result, var beaconShopItem) = await BeaconShopItem.createBeaconShopFromDoc(ugc_npc, read_doc);
|
||||
if (result.isFail() || beaconShopItem == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var beacon_shop_item_attribute = beaconShopItem.getEntityAttribute<BeaconShopItemAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(beacon_shop_item_attribute, () => $"beacon_shop_item_attribute is null !!! - {toBasicString()}");
|
||||
|
||||
m_beaconShopItems.TryAdd(beacon_shop_item_attribute.ItemGuid, beaconShopItem);
|
||||
}
|
||||
|
||||
m_isUpdateBeaconShopItem = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> addBeaconShopItem(BeaconShopItemDoc beaconShopItemDoc)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
var ugc_npc = getOwner() as UgcNpc;
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!! - {toBasicString()}");
|
||||
|
||||
var beacon_shop_item_attrib = beaconShopItemDoc.getAttrib<BeaconShopItemAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(beacon_shop_item_attrib, () => $"beacon_shop_item_attrib is null !!! - {toBasicString()}");
|
||||
|
||||
if (beacon_shop_item_attrib.ItemStackCount == 0)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {toBasicString()}");
|
||||
var dbClient = server_logic.getDynamoDbClient();
|
||||
|
||||
await dbClient.simpleDeleteDocumentWithDocType(beaconShopItemDoc);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (m_beaconShopItems.TryGetValue(beacon_shop_item_attrib.ItemGuid, out var beaconShopItem) == true)
|
||||
{
|
||||
err_msg = $"Found duplicated Item from BeaconShopItemDoc !!! : duplicatedItem:{beaconShopItem.toBasicString()} - {beaconShopItemDoc.toBasicString()}, {toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ItemDocLoadDuplicatedItem, err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
(result, var new_beacon_shop_item) = await BeaconShopItem.createBeaconShopFromDoc(ugc_npc, beaconShopItemDoc);
|
||||
if (result.isFail() || new_beacon_shop_item == null)
|
||||
{
|
||||
err_msg = $"Failed to create Item !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
m_beaconShopItems.TryAdd(beacon_shop_item_attrib.ItemGuid, new_beacon_shop_item);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addBeaconShopItem(ITEM_GUID itemGuid, BeaconShopItem beaconShopItem)
|
||||
{
|
||||
m_beaconShopItems.TryAdd(itemGuid, beaconShopItem);
|
||||
}
|
||||
|
||||
public void removeBeaconShopItem(ITEM_GUID itemGuid)
|
||||
{
|
||||
m_beaconShopItems.TryRemove(itemGuid, out var beaconShopItem);
|
||||
writeBeaconShopItemLog("removeBeaconShopItem");
|
||||
}
|
||||
|
||||
public List<BeaconShopItem> getHasBeaconShopItem()
|
||||
{
|
||||
return m_beaconShopItems.Select(x => x.Value).ToList();
|
||||
}
|
||||
|
||||
public BeaconShopItem? getBeaconShopItem(ITEM_GUID itemGuid)
|
||||
{
|
||||
if (m_beaconShopItems.TryGetValue(itemGuid, out var beaconShopItem) == false)
|
||||
{
|
||||
writeBeaconShopItemLog("Failed getBeaconShopItem");
|
||||
return null;
|
||||
}
|
||||
|
||||
return beaconShopItem;
|
||||
}
|
||||
|
||||
public void writeBeaconShopItemLog(string function)
|
||||
{
|
||||
var item_list = string.Empty;
|
||||
foreach (var item in m_beaconShopItems.Values)
|
||||
{
|
||||
var str = JsonConvert.SerializeObject(item.getEntityAttribute<BeaconShopItemAttribute>());
|
||||
item_list += $"{str},";
|
||||
}
|
||||
|
||||
Log.getLogger().Debug($"BeaconShop - {function}, Selling items : {item_list}");
|
||||
}
|
||||
|
||||
public bool hasBeaconShopItem()
|
||||
{
|
||||
return m_beaconShopItems.Count > 0 ? true : false;
|
||||
}
|
||||
public void setUpdateBeaconShopItem()
|
||||
{
|
||||
m_isUpdateBeaconShopItem = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
177
GameServer/Entity/Npc/UgcNpc/UgcNpc.cs
Normal file
177
GameServer/Entity/Npc/UgcNpc/UgcNpc.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 UGC_NPC_META_GUID = System.String;
|
||||
using ITEM_GUID = System.String;
|
||||
using MASTER_GUID = System.String;
|
||||
|
||||
|
||||
using static ClientToGameReq.Types;
|
||||
using Amazon.S3.Model;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class UgcNpc : EntityBase, IMergeWithInventory
|
||||
{
|
||||
public UgcNpc(MASTER_GUID masterGuid)
|
||||
: base(EntityType.UgcNpc, masterGuid)
|
||||
{ }
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
addEntityAttribute(new UgcNpcAttribute(this));
|
||||
addEntityAttribute(new AppearanceCustomizeAttribute(this));
|
||||
addEntityAttribute(new BeaconShopProfileAttribute(this));
|
||||
|
||||
addEntityAction(new UgcNpcAction(this));
|
||||
|
||||
addEntityAction(new UgcNpcEditAction(this));
|
||||
|
||||
addEntityAction(new AbilityAction(this));
|
||||
|
||||
addEntityAction(new UgcNpcInventoryAction(this));
|
||||
addEntityAction(new ItemClothAction(this));
|
||||
addEntityAction(new ItemTattooAction(this));
|
||||
|
||||
addEntityAction(new BeaconAppearanceCustomizeAction(this));
|
||||
|
||||
addEntityAction(new CustomDefinedUiAction(this));
|
||||
|
||||
// 현재 GameZoneAction은 Player를 위한 로직으로 작성되어 있다.
|
||||
// 추후 인던 관련 설계가 리펙토링되면 GameZoneAction 역시 계층화 되어야 한다. - kangms
|
||||
addEntityAction(new GameZoneAction(this));
|
||||
|
||||
addEntityAction(new FarmingAction(this));
|
||||
addEntityAction(new UgcNpcBeaconShopAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public async Task<Result> onMerge(List<ReservedSlotOnInven> reservedSlotOnInvens, TransactionRunner transactionRunner)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var ugc_inventory_action = getEntityAction<UgcNpcInventoryAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_inventory_action, () => $"ugc_inventory_action is null !!! - {toBasicStringWithMaster()}");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(transactionRunner, () => $"transactionRunner is null !!! - {toBasicStringWithMaster()}");
|
||||
|
||||
result = await ugc_inventory_action.onMergeInventory(reservedSlotOnInvens, transactionRunner);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override EntityBase? onGetMasterEntity()
|
||||
{
|
||||
if(false == hasMasterGuid())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var master_guid = getMasterGuid();
|
||||
|
||||
var server_logc = GameServerApp.getServerLogic();
|
||||
var player_manager = server_logc.getPlayerManager();
|
||||
|
||||
if(false == player_manager.tryGetUserByPrimaryKey(master_guid, out var found_player))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return found_player;
|
||||
}
|
||||
|
||||
public override TAction getEntityAction<TAction>()
|
||||
{
|
||||
TAction? to_cast_entity_atcion;
|
||||
|
||||
if (typeof(TAction) == typeof(InventoryActionBase))
|
||||
{
|
||||
to_cast_entity_atcion = base.getEntityAction<UgcNpcInventoryAction>() as TAction;
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_atcion, () => $"to_cast_action is null !!!");
|
||||
|
||||
return to_cast_entity_atcion;
|
||||
}
|
||||
|
||||
to_cast_entity_atcion = base.getEntityAction<TAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_cast_entity_atcion, () => $"to_cast_entity_atcion is null !!!");
|
||||
|
||||
return to_cast_entity_atcion;
|
||||
}
|
||||
|
||||
public override Type onGetAvailableItemAttributeType()
|
||||
{
|
||||
return typeof(UgcNpcItemAttribute);
|
||||
}
|
||||
|
||||
public override OWNER_GUID onGetGuidOfOwnerEntityType()
|
||||
{
|
||||
return getMasterGuid();
|
||||
}
|
||||
|
||||
public override OwnerEntityType onGetOwnerEntityType()
|
||||
{
|
||||
return OwnerEntityType.User;
|
||||
}
|
||||
|
||||
public override string onGetDbGuid()
|
||||
{
|
||||
return getUgcNpcMetaGuid();
|
||||
}
|
||||
|
||||
public UGC_NPC_META_GUID getUgcNpcMetaGuid()
|
||||
{
|
||||
return getEntityAttributeWithReadOnly<UgcNpcAttribute>()?.UgcNpcMetaGuid ?? string.Empty;
|
||||
}
|
||||
|
||||
public override string toStateString()
|
||||
{
|
||||
return $"beaconState:{getEntityAttributeWithReadOnly<UgcNpcAttribute>()?.State}"
|
||||
+ $", metaIdOfEntityStateType:{getOriginEntityAttribute<UgcNpcAttribute>()?.MetaIdOfEntityStateType}"
|
||||
+ $", locatedInstanceGuid:{getOriginEntityAttribute<UgcNpcAttribute>()?.LocatedInstanceGuid}"
|
||||
+ $", LocatedInstanceMetaId:{getOriginEntityAttribute<UgcNpcAttribute>()?.LocatedInstanceMetaId}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"beaconState:{getOriginEntityAttribute<UgcNpcAttribute>()?.State}"
|
||||
+ $", anchorMetaGuid:{getOriginEntityAttribute<UgcNpcAttribute>()?.AnchorMetaGuid}"
|
||||
+ $", metaIdOfEntityStateType:{getOriginEntityAttribute<UgcNpcAttribute>()?.MetaIdOfEntityStateType}"
|
||||
+ $", locatedInstanceGuid:{getOriginEntityAttribute<UgcNpcAttribute>()?.LocatedInstanceGuid}"
|
||||
+ $", LocatedInstanceMetaId:{getOriginEntityAttribute<UgcNpcAttribute>()?.LocatedInstanceMetaId}"
|
||||
+ $", MasterGuid:{getMasterGuid()}, SummonedCount:{getSummenedEntityGuids().Count}";
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"beaconNickname:{getOriginEntityAttribute<UgcNpcAttribute>()?.Nickname}"
|
||||
+ $", ugcNpcMetaGuid:{getOriginEntityAttribute<UgcNpcAttribute>()?.UgcNpcMetaGuid}"
|
||||
+ $", ownerGuid:{getOriginEntityAttribute<UgcNpcAttribute>()?.OwnerGuid}"
|
||||
+ $", ownerEntityType:{getOriginEntityAttribute<UgcNpcAttribute>()?.OwnerEntityType}"
|
||||
+ $", {base.toBasicString()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
402
GameServer/Entity/Party/Action/GlobalPartyAction.cs
Normal file
402
GameServer/Entity/Party/Action/GlobalPartyAction.cs
Normal file
@@ -0,0 +1,402 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using PARTY_GUID = System.String;
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyAction : EntityActionBase
|
||||
{
|
||||
private ConcurrentDictionary<string, GlobalPartyDetail> m_parties { get; set; } = new();
|
||||
|
||||
public GlobalPartyAction(GlobalParty owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public GlobalPartyDetail? getGlobalPartyDetail(PARTY_GUID party_guid)
|
||||
{
|
||||
if (string.IsNullOrEmpty(party_guid)) return null;
|
||||
|
||||
return m_parties.GetValueOrDefault(party_guid);
|
||||
}
|
||||
private void setGlobalPartyDetail(GlobalPartyDetail detail) => m_parties.TryAdd(detail.PartyGuid, detail);
|
||||
|
||||
public async Task<Result> createParty(PARTY_GUID party_guid, string leader_guid, string leader_nickname)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var owner = getOwner() as GlobalParty;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"GlobalParty is null !! - party_guid:{party_guid}");
|
||||
|
||||
var detail = new GlobalPartyDetail(owner, party_guid);
|
||||
await detail.onInit();
|
||||
|
||||
// redis 등록
|
||||
var detail_action = detail.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(detail_action, () => $"GlobalPartyDetailAction is null !! - party_guid:{party_guid}");
|
||||
|
||||
result = await detail_action.createPartyDetailInfo(leader_guid, leader_nickname);
|
||||
|
||||
// 메모리 등록
|
||||
setGlobalPartyDetail(detail);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> loadParty(PARTY_GUID party_guid)
|
||||
{
|
||||
var owner = getOwner() as GlobalParty;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"global party is null !!! - party guid: {party_guid}");
|
||||
|
||||
var detail = new GlobalPartyDetail(owner, party_guid);
|
||||
await detail.onInit();
|
||||
|
||||
var detail_action = detail.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(detail_action, () => $"global party detail action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = await detail_action.loadAllFromCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
setGlobalPartyDetail(detail);
|
||||
|
||||
// 1-1. party server 정보에 server 추가
|
||||
var global_party_server_action = detail.getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(global_party_server_action, () => $"global party detail server action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
result = await global_party_server_action.addPartyServer(GameServerApp.getServerLogic().getServerName());
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 1-2. 서버 변경 알림
|
||||
result = await global_party_server_action.notifyChangePartyServerToServers(BoolType.True, GameServerApp.getServerLogic().getServerName());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(string? leader_guid, string? leader_nickname, int? member_count)> getPartyLeaderGuidAndMemberCount(PARTY_GUID party_guid)
|
||||
{
|
||||
var owner = getOwner() as GlobalParty;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"global party is null !!! - party guid: {party_guid}");
|
||||
|
||||
var detail = getGlobalPartyDetail(party_guid);
|
||||
|
||||
// 메모리에 파티정보가 있으면, 활용
|
||||
if (null != detail)
|
||||
{
|
||||
var origin_detail_action = detail.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_detail_action, () => $"global party detail action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var origin_detail_member_action = detail.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(origin_detail_member_action, () => $"global party detail member action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
return (origin_detail_action.getLeaderGuid(), origin_detail_action.getLeaderNickname(), origin_detail_member_action.getMemberCount());
|
||||
}
|
||||
|
||||
// 메모리에 파티 정보가 없으면, load 하여 활용 ( 단, 메모리 저장은 하지 않음 - 서버내 없는 파티 정보 조회 )
|
||||
detail = new GlobalPartyDetail(owner, party_guid);
|
||||
await detail.onInit();
|
||||
|
||||
var detail_action = detail.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(detail_action, () => $"global party detail action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var detail_member_action = detail.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(detail_member_action, () => $"global party detail member action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = await detail_action.loadPartyCache();
|
||||
if (result.isFail()) return (null, null, null);
|
||||
|
||||
result = await detail_action.loadPartyMemberCache();
|
||||
if (result.isFail()) return (null, null, null);
|
||||
|
||||
return (detail_action.getLeaderGuid(), detail_action.getLeaderNickname(), detail_member_action.getMemberCount());
|
||||
}
|
||||
|
||||
public async Task<Result> joinParty(PARTY_GUID party_guid, PartyMemberInfo user)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var owner = getOwner() as GlobalParty;
|
||||
if (null == owner)
|
||||
{
|
||||
var err_msg = $"Fail to find global entity !!! : {nameof(GlobalParty)}";
|
||||
result.setFail(ServerErrorCode.EntityBaseNotFound, err_msg );
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var party = getGlobalPartyDetail(party_guid);
|
||||
|
||||
// 1. 없으면, Redis 에서 Load 하여 채워 넣음
|
||||
if (null == party)
|
||||
{
|
||||
result = await loadParty(party_guid);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
party = getGlobalPartyDetail(party_guid);
|
||||
}
|
||||
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"GlobalDetailParty is null !! - party_guid:{party_guid}");
|
||||
|
||||
// 2. member 추가
|
||||
var global_party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(global_party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - party_guid:{party_guid}");
|
||||
|
||||
var add_member = await global_party_member_action.addJoinMember(user);
|
||||
if (add_member.result.isFail()) return add_member.result;
|
||||
|
||||
// 3. Party p2p group host 전달 ( to client )
|
||||
var party_action = party.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_action, () => $"global party detail action is null !!! - {party.toBasicString()}");
|
||||
|
||||
_ = await party_action.joinPartyP2PGroup(user.UserGuid);
|
||||
_ = await party_action.checkPartyP2PState(user.UserGuid, true, true);
|
||||
|
||||
if (add_member.isAready == true) return add_member.result;
|
||||
|
||||
// 4. 파티 정보 전달
|
||||
var send_party_members = new List<USER_GUID>();
|
||||
var member_count = global_party_member_action.getMemberCount();
|
||||
if (member_count == 2)
|
||||
{
|
||||
send_party_members.Add(party_action.getLeaderGuid());
|
||||
}
|
||||
send_party_members.Add(user.UserGuid);
|
||||
await party_action.sendPartyInfo(send_party_members, party_action.getLeaderGuid(), false);
|
||||
|
||||
// 5. Party Instance 정보 전달
|
||||
var party_instance_attribute = party.getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_attribute, () => $"party instance attribute is null !!! - {party.toBasicString()}");
|
||||
|
||||
if (party_instance_attribute.InstanceId > 0)
|
||||
{
|
||||
party_action.sendPartyInstance(user.UserGuid);
|
||||
}
|
||||
|
||||
return add_member.result;
|
||||
}
|
||||
|
||||
public async Task<Result> leaveParty(PARTY_GUID party_guid, USER_GUID leave_user_guid, BoolType is_ban)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var global_party = getOwner() as GlobalParty;
|
||||
NullReferenceCheckHelper.throwIfNull(global_party, () => $"global party is null !!! - party guid: {party_guid}");
|
||||
|
||||
var party = global_party.getParty(party_guid);
|
||||
ArgumentNullException.ThrowIfNull(party);
|
||||
|
||||
// 1. 파티 멤버에서 삭제
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - party_guid:{party_guid}, {party.toBasicString()}");
|
||||
|
||||
var delete_party_member = await party_member_action.deleteJoinMember(leave_user_guid, true);
|
||||
if (delete_party_member.result.isFail()) return delete_party_member.result;
|
||||
|
||||
// 2. p2p 그룹에서 제외
|
||||
var party_action = party.getEntityAction<GlobalPartyDetailAction>();
|
||||
ArgumentNullException.ThrowIfNull(party_action);
|
||||
_ = party_action.leavePartyP2PGroup(leave_user_guid);
|
||||
_ = party_action.checkPartyP2PState(leave_user_guid, false, false);
|
||||
|
||||
// 3. 파티 탈퇴 알림
|
||||
notifyLeavePartyMember(party, leave_user_guid, is_ban);
|
||||
|
||||
// 4. 초대 메시지 발송 체크 : 초대 메시지에 응답하여 Party 가 결정될 수 있기 때문에 파티원이 1명이어도 Party 를 파괴시키지 않음
|
||||
var invite_send_action = party.getEntityAction<GlobalPartyInvitePartySendAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(invite_send_action, () => $"global party invite party send action is null !!! - {party.toBasicString()}");
|
||||
var sends = await invite_send_action.getInviteSendsCount();
|
||||
if (sends > 0 && delete_party_member.party_member_count >= 1)
|
||||
{
|
||||
Log.getLogger().debug($"Not Destory Party: Send Invite Count - {sends}");
|
||||
return result;
|
||||
}
|
||||
|
||||
// 5. 파티원이 1명으로 파티 파괴
|
||||
if (delete_party_member.party_member_count <= 1)
|
||||
{
|
||||
result = await destroyParty(party_guid, true);
|
||||
}
|
||||
// 6. party server 체크
|
||||
else
|
||||
{
|
||||
result = await checkPartyServer(party, leave_user_guid);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> destroyParty(PARTY_GUID party_guid, bool is_notify_to_servers)
|
||||
{
|
||||
var global_party = getOwner() as GlobalParty;
|
||||
ArgumentNullException.ThrowIfNull(global_party);
|
||||
|
||||
var party = global_party.getParty(party_guid);
|
||||
if (null == party) return new Result();
|
||||
|
||||
// 0. business log 준비
|
||||
var party_log_data = PartyBusinessLogHelper.toPartyLogData(party_guid, false);
|
||||
var party_business_log = new PartyBusinessLog(new LogActionEx(LogActionType.DestroyParty), party_log_data);
|
||||
|
||||
// 1. party info 제거
|
||||
var party_info_action = party.getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_info_action, () => $"global party detail info action is null !!! - {party.toBasicString()}");
|
||||
_ = await party_info_action.deleteParty();
|
||||
|
||||
// 2. party member 제거
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"global party detail member action is null !!! - {party.toBasicString()}");
|
||||
var members = party_member_action.getMembers();
|
||||
_ = await party_member_action.deletePartyMembers();
|
||||
|
||||
// 3. party server 제거
|
||||
var party_server_action = party.getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_action, () => $"global party detail server action is null !!! - {party.toBasicString()}");
|
||||
var servers = party_server_action.getServers();
|
||||
_ = await party_server_action.deleteAllPartyServers();
|
||||
|
||||
// 4. invite party send 제거
|
||||
var party_invite_party_send_action = party.getEntityAction<GlobalPartyInvitePartySendAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send_action, () => $"global party invite party send action is null !!! - {party.toBasicString()}");
|
||||
_ = await party_invite_party_send_action.deleteInvitePartySends();
|
||||
|
||||
// 5. instance 제거
|
||||
var party_instance_action = party.getEntityAction<GlobalPartyDetailInstanceAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_action, () => $"global party detail instance action is null !!! - {party.toBasicString()}");
|
||||
_ = await party_instance_action.deletePartyInstance();
|
||||
|
||||
// 5. p2pgroup 제거
|
||||
var party_action = party.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_action, () => $"global party detail action is null !!! - {party.toBasicString()}");
|
||||
_ = party_action.destroyPartyP2PGroup();
|
||||
|
||||
// 6. member 들의 Party 정보 제거
|
||||
await clearPersonalPartyWithMembers(members.ToList());
|
||||
|
||||
// 7. party 제거
|
||||
m_parties.Remove(party_guid, out _);
|
||||
|
||||
// 8. Server 에 알림
|
||||
if (is_notify_to_servers)
|
||||
{
|
||||
var server_message = new ServerMessage
|
||||
{
|
||||
NtfDestroyParty = new() { DestroyPartyGuid = party_guid }
|
||||
};
|
||||
|
||||
PartyHelper.BroadcastToServers(servers.ToList(), server_message, true);
|
||||
}
|
||||
|
||||
// 9. Client 에게 알림
|
||||
var client_message = new ClientToGame
|
||||
{
|
||||
Message = new()
|
||||
{
|
||||
DestroyPartyNoti = new()
|
||||
}
|
||||
};
|
||||
PartyHelper.BroadcastToClients(members.ToList(), client_message, new List<string>());
|
||||
|
||||
BusinessLogger.collectLog(party, party_business_log);
|
||||
|
||||
return new Result();
|
||||
}
|
||||
|
||||
private void notifyLeavePartyMember(GlobalPartyDetail party, USER_GUID leave_user_guid, BoolType is_ban)
|
||||
{
|
||||
// 1. 파티원 탈퇴에 따른 알림 ( to server )
|
||||
var server_message = new ServerMessage
|
||||
{
|
||||
LeavePartyMemberNoti = new()
|
||||
{
|
||||
IsBan = is_ban,
|
||||
PartyGuid = party.PartyGuid,
|
||||
LeavePartyUserGuid = leave_user_guid
|
||||
}
|
||||
};
|
||||
PartyHelper.BroadcastToServers(party, server_message, true);
|
||||
|
||||
// 2. 파티원 탈퇴에 따른 알림 ( to client )
|
||||
var client_message = new ClientToGame
|
||||
{
|
||||
Message = new()
|
||||
{
|
||||
LeavePartyMemberNoti = new()
|
||||
{
|
||||
IsBan = is_ban,
|
||||
LeavePartyUserGuid = leave_user_guid
|
||||
}
|
||||
}
|
||||
};
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<string>());
|
||||
}
|
||||
|
||||
public async Task<Result> checkPartyServer(GlobalPartyDetail party, USER_GUID leave_user_guid)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
// 1. 서버 내 파티원 체크
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !!! - {party.toBasicString()}");
|
||||
|
||||
var exist_members_without_me = party_member_action.checkExistPartyMembers(leave_user_guid);
|
||||
if (exist_members_without_me) return result;
|
||||
|
||||
// 2. 서버 정보 제거
|
||||
var party_server_action = party.getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_action, () => $"GlobalPartyDetailServerAction is null !!! - {party.toBasicString()}");
|
||||
|
||||
result = await party_server_action.deletePartyServer(GameServerApp.getServerLogic().getServerName());
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 3. 서버 정보 제거 알림
|
||||
result = await party_server_action.notifyChangePartyServerToServers(BoolType.False, GameServerApp.getServerLogic().getServerName());
|
||||
|
||||
// 4. 파티 정보 제거
|
||||
m_parties.Remove(party.PartyGuid, out _);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task clearPersonalPartyWithMembers(IReadOnlyList<USER_GUID> members)
|
||||
{
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
|
||||
foreach (var user in members)
|
||||
{
|
||||
if (!player_manager.tryGetUserByPrimaryKey(user, out var member)) continue;
|
||||
if (null == member) continue;
|
||||
|
||||
var personal_party_action = member.getEntityAction<PersonalPartyAction>();
|
||||
if (null == personal_party_action) continue;
|
||||
|
||||
await personal_party_action.clearPersonalParty();
|
||||
}
|
||||
}
|
||||
}
|
||||
552
GameServer/Entity/Party/Action/GlobalPartyDetailAction.cs
Normal file
552
GameServer/Entity/Party/Action/GlobalPartyDetailAction.cs
Normal file
@@ -0,0 +1,552 @@
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Nettention.Proud
|
||||
|
||||
;
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyDetailAction : EntityActionBase
|
||||
{
|
||||
public GlobalPartyDetailAction(GlobalPartyDetail owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> keepParty()
|
||||
{
|
||||
// 1. party keep
|
||||
var party_action = getOwner().getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_action, () => $"GlobalPartyDetailInfoAction is null !!! - {getOwner().toBasicString()}");
|
||||
await party_action.keep();
|
||||
|
||||
// 2. party member keep
|
||||
var party_member_action = getOwner().getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !!! - {getOwner().toBasicString()}");
|
||||
await party_member_action.keep();
|
||||
|
||||
// 3. party server keep
|
||||
var party_server_action = getOwner().getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_action, () => $"GlobalPartyDetailServerAction is null !!! - {getOwner().toBasicString()}");
|
||||
await party_server_action.keep();
|
||||
|
||||
// 4. party invite send keep
|
||||
var party_invite_send_action = getOwner().getEntityAction<GlobalPartyInvitePartySendAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_send_action, () => $"GlobalPartyInvitePartySendAction is null !!! - {getOwner().toBasicString()}");
|
||||
await party_invite_send_action.keep();
|
||||
|
||||
// 5. party instance keep
|
||||
var party_instance_action = getOwner().getEntityAction<GlobalPartyDetailInstanceAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_action, () => $"GlobalPartyDetailInstanceAction is null !!! - {getOwner().toBasicString()}");
|
||||
await party_instance_action.keep();
|
||||
|
||||
return new Result();
|
||||
}
|
||||
|
||||
public bool isLeader(USER_GUID user_guid)
|
||||
{
|
||||
var detail = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(detail, () => $"global party detail is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var party_attribute = detail.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !!! - user guid:{user_guid}, {detail.toBasicString()}");
|
||||
|
||||
return party_attribute.PartyLeaderCharGuid == user_guid;
|
||||
}
|
||||
|
||||
public USER_GUID getLeaderGuid()
|
||||
{
|
||||
var detail = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(detail, () => $"global party detail is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var party_attribute = detail.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !!! - {detail.toBasicString()}");
|
||||
|
||||
return party_attribute.PartyLeaderCharGuid;
|
||||
}
|
||||
|
||||
public string getLeaderNickname()
|
||||
{
|
||||
var detail = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(detail, () => $"global party detail is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var party_attribute = detail.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !!! - {detail.toBasicString()}");
|
||||
|
||||
return party_attribute.PartyLeaderNickname;
|
||||
}
|
||||
|
||||
public async Task<(Result result, string change_leader_guid)> changePartyLeader()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var party_member_attribute = party.getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - party_guid:{party.PartyGuid}");
|
||||
|
||||
// 1. 파티장 자동 변경 ( 조건 1. jointime 이 가장 오래된 유저 )
|
||||
var origin_leader_guid = getLeaderGuid();
|
||||
var next_leader_guid = origin_leader_guid;
|
||||
var join_time = DateTime.UtcNow.ToTimestamp();
|
||||
|
||||
foreach (var member in party_member_attribute.getPartyMembers())
|
||||
{
|
||||
if (origin_leader_guid == member.Value.UserGuid) continue;
|
||||
if (join_time < member.Value.JoinTime) continue;
|
||||
|
||||
next_leader_guid = member.Value.UserGuid;
|
||||
join_time = member.Value.JoinTime;
|
||||
}
|
||||
|
||||
// 2. 파티장 변경 처리
|
||||
var party_detail_info_action = party.getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_detail_info_action, () => $"GlobalPartyDetailInfoAction is null !! - party_guid:{party.PartyGuid}");
|
||||
result = await party_detail_info_action.changePartyLeader(next_leader_guid, true);
|
||||
|
||||
// 3. 파티장 변경 알림
|
||||
var message = new ServerMessage
|
||||
{
|
||||
ChangePartyLeaderNoti = new ServerMessage.Types.ChangePartyLeaderNoti()
|
||||
{
|
||||
PartyGuid = party.PartyGuid,
|
||||
NewPartyLeaderGuid = next_leader_guid
|
||||
}
|
||||
};
|
||||
PartyHelper.BroadcastToServers(party, message, false);
|
||||
|
||||
return (result, next_leader_guid);
|
||||
}
|
||||
|
||||
public HostID getP2PHostId()
|
||||
{
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
ArgumentNullException.ThrowIfNull(party_attribute);
|
||||
|
||||
return party_attribute.P2PGroup;
|
||||
}
|
||||
|
||||
public void sendPartyInstance(USER_GUID user_guid)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party_instance_attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
if (party_instance_attribute.InstanceId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyInstanceInfoNoti = new();
|
||||
client_message.Message.PartyInstanceInfoNoti.InstanceId = party_instance_attribute.InstanceId;
|
||||
client_message.Message.PartyInstanceInfoNoti.StartTime = party_instance_attribute.StartTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.EndTime = party_instance_attribute.EndTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.JoinMemberCount = party_instance_attribute.JoinMemberCount;
|
||||
client_message.Message.PartyInstanceInfoNoti.IsEnd = party_instance_attribute.InstanceId == 0 ? BoolType.True : BoolType.False;
|
||||
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
if (! player_manager.tryGetUserByPrimaryKey(user_guid, out var user_entity) || null == user_entity)
|
||||
{
|
||||
var err_msg = $"Failed to send party instance !!! : not logged in server - {user_guid}";
|
||||
result.setFail(ServerErrorCode.UserNotLogin,err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PartyHelper.sendToClient(client_message, user_entity.getHostId());
|
||||
}
|
||||
|
||||
public async Task<Result> sendPartyInfo(IReadOnlyList<USER_GUID> sendUsers, USER_GUID leaderGuid, bool exceptAnotherServer)
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"party is null !!");
|
||||
|
||||
var party_info_action = party.getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_info_action, () => $"GlobalPartyDetailInfoAction is null !! - {party.toBasicString()}");
|
||||
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - {party.toBasicString()}");
|
||||
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
foreach (var send in sendUsers)
|
||||
{
|
||||
if (player_manager.tryGetUserByPrimaryKey(send, out var player))
|
||||
{
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.JoinPartyInfoNoti = new();
|
||||
client_message.Message.JoinPartyInfoNoti.PartyName = party_info_action.getPartyName();
|
||||
client_message.Message.JoinPartyInfoNoti.PartyLeaderGuid = getLeaderGuid();
|
||||
client_message.Message.JoinPartyInfoNoti.PartyLeaderNickname = getLeaderNickname();
|
||||
client_message.Message.JoinPartyInfoNoti.PartyMemberList.AddRange(party_member_action.getMembers4PartyInfo().ToList());
|
||||
|
||||
if (leaderGuid != send)
|
||||
{
|
||||
client_message.Message.JoinPartyInfoNoti.ServerConnectInfo = await tryMoveToLeaderServer(leaderGuid, send);
|
||||
}
|
||||
|
||||
if (null == player) continue;
|
||||
|
||||
PartyHelper.sendToClient(client_message, player.getHostId());
|
||||
|
||||
await QuestManager.It.QuestCheck(player, new QuestParty(EQuestEventTargetType.PARTY, EQuestEventNameType.ENTERED));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (exceptAnotherServer) continue;
|
||||
|
||||
var server_message = new ServerMessage();
|
||||
server_message.NtfPartyInfo = new();
|
||||
server_message.NtfPartyInfo.PartyGuid = party.PartyGuid;
|
||||
server_message.NtfPartyInfo.PartyMemberGuids.Add(send);
|
||||
|
||||
await PartyHelper.sendToServerByTargetClient(send, server_message);
|
||||
}
|
||||
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
public async Task<Result> joinPartyP2PGroup(USER_GUID user_guid)
|
||||
{
|
||||
var result = new Result();
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
if (! player_manager.tryGetUserByPrimaryKey(user_guid, out var user_entity))
|
||||
{
|
||||
var err_msg = $"Failed to join party p2p group !!! : not logged in server - {user_guid}";
|
||||
result.setFail(ServerErrorCode.UserNotLogin,err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var p2p_group = getP2PHostId();
|
||||
GameServerApp.getServerLogic().getProudNetListener().getNetServer().JoinP2PGroup(user_entity.getHostId(), p2p_group);
|
||||
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyP2PGroupHostIdNoti = new();
|
||||
client_message.Message.PartyP2PGroupHostIdNoti.PartyP2PGroupHostId = (int)p2p_group;
|
||||
|
||||
PartyHelper.sendToClient(client_message, user_entity.getHostId());
|
||||
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
public async Task<Result> checkPartyP2PState(USER_GUID userGuid, bool isJoin, bool includeSendingMe)
|
||||
{
|
||||
// 1. 타 유저에게 내 정보 전송
|
||||
_ = await sendPartyP2PState(userGuid, isJoin);
|
||||
|
||||
if (!includeSendingMe) return await Task.FromResult(new Result());
|
||||
|
||||
// 2. 타 유저들의 정보를 내게 전송
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - {party.toBasicString()}");
|
||||
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyMemberP2PStateNoti = new();
|
||||
|
||||
var members = party_member_action.getMembers();
|
||||
foreach (var member in members)
|
||||
{
|
||||
if (member == userGuid) continue;
|
||||
client_message.Message.PartyMemberP2PStateNoti.MemberGuid = member;
|
||||
client_message.Message.PartyMemberP2PStateNoti.IsP2P = player_manager.tryGetUserByPrimaryKey(member, out _) ? BoolType.True : BoolType.False;
|
||||
PartyHelper.sendToClient(client_message, userGuid);
|
||||
}
|
||||
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
private async Task<Result> sendPartyP2PState(USER_GUID userGuid, bool isJoin)
|
||||
{
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyMemberP2PStateNoti = new();
|
||||
client_message.Message.PartyMemberP2PStateNoti.MemberGuid = userGuid;
|
||||
client_message.Message.PartyMemberP2PStateNoti.IsP2P = isJoin ? BoolType.True : BoolType.False;
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<USER_GUID> { userGuid });
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
public bool leavePartyP2PGroup(USER_GUID user_guid)
|
||||
{
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
if (player_manager.tryGetUserByPrimaryKey(user_guid, out var user))
|
||||
{
|
||||
return GameServerApp.getServerLogic().getProudNetListener().getNetServer().LeaveP2PGroup(user.getHostId(), getP2PHostId());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool destroyPartyP2PGroup()
|
||||
{
|
||||
var p2p_group = getP2PHostId();
|
||||
return GameServerApp.getServerLogic().getProudNetListener().getNetServer().DestroyP2PGroup(p2p_group);
|
||||
}
|
||||
|
||||
public async Task<Result> createPartyDetailInfo(string leader_guid, string leader_nickname)
|
||||
{
|
||||
var result = new Result();
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
if (null == party)
|
||||
{
|
||||
var err_msg = $"Fail to get entity base : {nameof(GlobalPartyDetail)}";
|
||||
result.setFail(ServerErrorCode.EntityBaseNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 1. party 정보 create
|
||||
var party_info_action = party.getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_info_action, () => $"GlobalPartyDetailInfoAction is null !! - {party.toBasicString()}");
|
||||
result = await party_info_action.createParty(leader_guid, leader_nickname);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. leader member 정보 설정
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - {party.toBasicString()}");
|
||||
var change = await party_member_action.changeMember(PartyHelper.makePartyMember(leader_guid, leader_nickname));
|
||||
if (change.result.isFail()) return result;
|
||||
|
||||
// 3. party server 정보 설정
|
||||
var party_server_action = party.getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_action, () => $"GlobalPartyDetailServerAction is null !! - {party.toBasicString()}");
|
||||
result = await party_server_action.addPartyServer(GameServerApp.getServerLogic().getServerName());
|
||||
if (result.isFail()) return result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> loadAllFromCache()
|
||||
{
|
||||
var result = new Result();
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
ArgumentNullException.ThrowIfNull(party);
|
||||
|
||||
// 1. party 정보 Load
|
||||
result = await loadPartyCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. party member 정보 Load
|
||||
result = await loadPartyMemberCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 3. party server 정보 Load
|
||||
result = await loadPartyServerCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 4. party invite send 정보 load
|
||||
result = await loadPartyInvitePartySendCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 5. party instance 정보 load ( 없을 수 있으므로 result 무시 )
|
||||
_ = await loadPartyInstanceCache();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> loadPartyCache()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_info_action = party.getEntityAction<GlobalPartyDetailInfoAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_info_action, () => $"GlobalPartyDetailInfoAction is null !! - {party.toBasicString()}");
|
||||
var result = await party_info_action.loadParty();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> loadPartyMemberCache()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - {party.toBasicString()}");
|
||||
var result = await party_member_action.loadPartyMember();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> loadPartyServerCache()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_server_action = party.getEntityAction<GlobalPartyDetailServerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_action, () => $"GlobalPartyDetailServerAction is null !! - {party.toBasicString()}");
|
||||
var result = await party_server_action.loadPartyServer();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> loadPartyInvitePartySendCache()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_invite_party_send_action = party.getEntityAction<GlobalPartyInvitePartySendAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send_action, () => $"GlobalPartyInvitePartySendAction is null !! - {party.toBasicString()}");
|
||||
var result = await party_invite_party_send_action.loadPartyInvitePartySend(party.PartyGuid);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> loadPartyInstanceCache()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "GlobalPartyDetail is null");
|
||||
|
||||
var party_instance_action = party.getEntityAction<GlobalPartyDetailInstanceAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_action, () => $"GlobalPartyDetailInstanceAction is null !! - {party.toBasicString()}");
|
||||
var result = await party_instance_action.loadPartyInstance();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<ServerConnectInfo?> tryMoveToLeaderServer(USER_GUID leaderGuid, USER_GUID userGuid)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
// 1. party leader 세션 체크
|
||||
var leader_login_cache = await PartyHelper.getOtherUserLoginCache(leaderGuid);
|
||||
if (null == leader_login_cache)
|
||||
{
|
||||
err_msg = $"Failed to get party leader session !!! - {leaderGuid}";
|
||||
result.setFail(ServerErrorCode.NotFoundParty, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2. 조건 체크
|
||||
if (false == await checkConditionLeaderServer(leader_login_cache.CurrentServer)) return null;
|
||||
|
||||
// 3. 서버 정보 조회
|
||||
(result, var server_info) = await server_logic.getServerInfoByServerName(leader_login_cache.CurrentServer);
|
||||
if (null == server_info) return null;
|
||||
if (server_info.Sessions + server_info.Reservation + server_info.ReturnCount >= server_info.Capacity)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 4. 예약 요청
|
||||
var message = new ServerMessage.Types.GS2GS_REQ_RESERVATION_ENTER_TO_SERVER();
|
||||
message.MoveType = ServerMoveType.Force;
|
||||
message.RequestServerName = server_logic.getServerName();
|
||||
message.RequestUserGuid = userGuid;
|
||||
|
||||
var reserved = await server_logic.getReservationManager().registerReservationEnterToServer(message, server_info.Name);
|
||||
|
||||
// 5. 예약 실패 체크
|
||||
if (null == reserved)
|
||||
{
|
||||
err_msg = $"Failed to reservation enter to game server!!! - {server_info.Name}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.FailedToReservationEnter, err_msg);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 6. 이동 처리
|
||||
var player_manager = server_logic.getPlayerManager();
|
||||
if (!player_manager.tryGetUserByPrimaryKey(userGuid, out var player)) return null;
|
||||
|
||||
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "JoinParty", moveDelegate);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 7. 이동 정보 체크
|
||||
var account_attribute = player.getEntityAttribute<AccountAttribute>();
|
||||
ArgumentNullException.ThrowIfNull(account_attribute);
|
||||
|
||||
var res = new ServerConnectInfo();
|
||||
res.ServerAddr = account_attribute.ToConnectGameServerAddress.IP;
|
||||
res.ServerPort = account_attribute.ToConnectGameServerAddress.Port;
|
||||
res.Otp = account_attribute.OtpForServerConnect;
|
||||
|
||||
return res;
|
||||
|
||||
async Task<Result> moveDelegate() => await moveAsync(player, server_info);
|
||||
}
|
||||
|
||||
private async Task<bool> checkConditionLeaderServer(string leaderServerName)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
(var result, var leader_server) = await server_logic.getServerInfoByServerName(leaderServerName);
|
||||
if (null == leader_server) return false;
|
||||
|
||||
// 1. join user 가 channel 에 있는지 확인
|
||||
if (server_logic.getServerType().toServerType() != ServerType.Channel) return false;
|
||||
|
||||
// 2. leader 와 동일한 channel 서버에 있는지 확인
|
||||
if (leaderServerName == server_logic.getServerName()) return false;
|
||||
|
||||
// 3. leader 가 channel 에 있는지 확인
|
||||
if (leaderServerName.toServerType() != ServerType.Channel) return false;
|
||||
|
||||
// 4. leader 와 동일한 world id 에 있는지 확인
|
||||
if (server_logic.getWorldId() != leader_server.WorldId) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task<Result> moveAsync(Player player, ServerInfo serverInfo)
|
||||
{
|
||||
// 1. 파티 리더 위치로 이동 ( to Channel )
|
||||
var result = await GameZoneMoveHelper.moveToAnotherChannel(player, serverInfo, null);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.None, GameServerApp.getServerLogic().getDynamoDbClient());
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
batch.addQuery(new QueryFinal());
|
||||
}
|
||||
|
||||
return await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
}
|
||||
}
|
||||
399
GameServer/Entity/Party/Action/GlobalPartyDetailInfoAction.cs
Normal file
399
GameServer/Entity/Party/Action/GlobalPartyDetailInfoAction.cs
Normal file
@@ -0,0 +1,399 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyDetailInfoAction : EntityActionBase
|
||||
{
|
||||
private readonly PartyCacheRequest m_party_cache_request;
|
||||
|
||||
private TaskCompletionSource m_vote_finish_task_source { get; set; } = new();
|
||||
|
||||
public GlobalPartyDetailInfoAction(GlobalPartyDetail owner) : base(owner)
|
||||
{
|
||||
m_party_cache_request =
|
||||
new PartyCacheRequest(owner.PartyGuid, GameServerApp.getServerLogic().getRedisConnector());
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit() => await Task.FromResult(new Result());
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task keep()
|
||||
{
|
||||
await m_party_cache_request.keepPartyCache();
|
||||
}
|
||||
|
||||
public async Task<Result> loadParty()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
result = await m_party_cache_request.fetchPartyCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_attribute, new List<CacheBase> { m_party_cache_request.getPartyCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> createParty(USER_GUID leader_guid, string leader_nickname)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
// 1. cache 생성
|
||||
result = await m_party_cache_request.createPartyCache(leader_guid, leader_nickname);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. attribute 복사
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_attribute, new List<CacheBase> { m_party_cache_request.getPartyCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deleteParty()
|
||||
{
|
||||
// 1. cache 제거
|
||||
var result = await m_party_cache_request.deletePartyCache();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
// 2. attribute 제거
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_attribute.onClear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> changePartyLeader(USER_GUID next_leader_guid, bool is_upsert_cache)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
// 1. attribute 수정
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_attribute.PartyLeaderCharGuid = next_leader_guid;
|
||||
|
||||
// 2. cache 수정
|
||||
var party_cache = m_party_cache_request.getPartyCache();
|
||||
NullReferenceCheckHelper.throwIfNull(party_cache, () => $"Party Cache is null !! - party name:{party_attribute.PartyName}");
|
||||
|
||||
party_cache.PartyLeaderCharGuid = next_leader_guid;
|
||||
|
||||
if(is_upsert_cache) result = await m_party_cache_request.upsertPartyCache();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> changePartyName(string new_party_name, bool is_upsert_cache)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
// 1. attribute 수정
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_attribute.PartyName = new_party_name;
|
||||
|
||||
// cache 수정
|
||||
var party_cache = m_party_cache_request.getPartyCache();
|
||||
NullReferenceCheckHelper.throwIfNull(party_cache, () => $"Party Cache is null !! - party name:{party_attribute.PartyName}");
|
||||
|
||||
party_cache.PartyName = new_party_name;
|
||||
|
||||
if(is_upsert_cache) result = await m_party_cache_request.upsertPartyCache();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string getPartyName()
|
||||
{
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_attribute.PartyName;
|
||||
}
|
||||
|
||||
public async Task<Result> VoteParty(VoteType vote, USER_GUID voter_guid)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!");
|
||||
|
||||
var party_attribute = party.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
// 1. 진행 중인 Vote 확인
|
||||
if (null == party_attribute.PartyVote)
|
||||
{
|
||||
err_msg = $"Failed to reply party vote !!! - not start party vote - {party.PartyGuid}";
|
||||
result.setFail(ServerErrorCode.NoStartPartyVote, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. 투표 허용 시간 확인
|
||||
var allow_vote_time = DateTime.UtcNow.AddSeconds(-1 * MetaHelper.GameConfigMeta.VoteTimeLimitSec + 5 );
|
||||
if (party_attribute.PartyVote.StartVoteTime < allow_vote_time.ToTimestamp())
|
||||
{
|
||||
err_msg = $"Failed to reply party vote !!! - already passed party vote time - {party.PartyGuid}";
|
||||
result.setFail(ServerErrorCode.AlreadyPassPartyVoteTime, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 3. 기 투표 여부 체크
|
||||
if (party_attribute.PartyVote.Votes.TryGetValue(voter_guid, out var saved_vote) && saved_vote != VoteType.None)
|
||||
{
|
||||
err_msg = $"Failed to reply party vote !!! - already reply party vote - {voter_guid}";
|
||||
result.setFail(ServerErrorCode.AlreadyReplyPartyVote, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
party_attribute.PartyVote.Votes[voter_guid] = vote;
|
||||
|
||||
// 4. 투표 종료 체크 ( party leader 가 있는 서버만 )
|
||||
var player_message = GameServerApp.getServerLogic().getPlayerManager();
|
||||
if (player_message.tryGetUserByPrimaryKey(party_attribute.PartyLeaderCharGuid, out _))
|
||||
{
|
||||
var is_finished = party_attribute.PartyVote.Votes.All(voted_type => voted_type.Value != VoteType.None);
|
||||
if (is_finished) m_vote_finish_task_source.TrySetResult();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var message = new ServerMessage();
|
||||
message.ReplyPartyVoteNoti = new();
|
||||
message.ReplyPartyVoteNoti.PartyGuid = party.PartyGuid;
|
||||
message.ReplyPartyVoteNoti.PartyVoterGuid = voter_guid;
|
||||
message.ReplyPartyVoteNoti.Vote = vote;
|
||||
|
||||
await PartyHelper.sendToServerByTargetClient(party_attribute.PartyLeaderCharGuid, message);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public PartyVoteInfo? getPartyVoteInfo()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!");
|
||||
|
||||
var party_attribute = party.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_attribute.PartyVote;
|
||||
}
|
||||
|
||||
public async Task<(Result result, PartyVoteInfo? vote)> registerPartyVote(string vote_title, Timestamp start_vote_time, bool is_start)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!");
|
||||
|
||||
var party_attribute = party.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"GlobalPartyDetailMemberAction is null !! - {party.toBasicString()}");
|
||||
|
||||
// 1. vote condition 체크
|
||||
result = await checkVoteCondition(party, vote_title);
|
||||
if (result.isFail()) return (result, null);
|
||||
|
||||
// 2. vote 정보 저장 : 시작시점의 유저 리스트 등록 - 추가(제외) / 감소(기권)
|
||||
var members = party_member_action.getMembers();
|
||||
var vote = new PartyVoteInfo
|
||||
{
|
||||
VoteTitle = vote_title,
|
||||
StartVoteTime = start_vote_time
|
||||
};
|
||||
foreach (var member in members)
|
||||
{
|
||||
vote.Votes.Add(member, VoteType.None);
|
||||
}
|
||||
party_attribute.PartyVote = vote;
|
||||
|
||||
// 3. cache 저장
|
||||
var cache = m_party_cache_request.getPartyCache();
|
||||
NullReferenceCheckHelper.throwIfNull(cache, () => $"Party Cache is null !! - party name:{party_attribute.PartyName} / {party.toBasicString()}");
|
||||
|
||||
cache.LastVoteTime = start_vote_time;
|
||||
party_attribute.LastVoteTime = start_vote_time;
|
||||
|
||||
if (is_start)
|
||||
{
|
||||
result = await m_party_cache_request.upsertPartyCache();
|
||||
if (result.isFail())
|
||||
{
|
||||
party_attribute.PartyVote = null;
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
// 4. Wait Vote Task 실행 ( fire and forget )
|
||||
_ = Task.Run(waitPartyVoteFinish);
|
||||
}
|
||||
|
||||
return (result, vote);
|
||||
}
|
||||
|
||||
private async Task<Result> checkVoteCondition(GlobalPartyDetail party, string vote_title)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
var party_attribute = party.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
// 1. vote title 길이 체크
|
||||
if (vote_title.Length > MetaHelper.GameConfigMeta.MaxVoteAgendaInput)
|
||||
{
|
||||
err_msg = $"fail to start party vote !!! : invalid vote title length - {vote_title.Length}";
|
||||
result.setFail(ServerErrorCode.InvalidPartyStringLength, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. 진행 중인 Vote 체크
|
||||
if (null != party_attribute.PartyVote)
|
||||
{
|
||||
err_msg = $"Failed to start party vote !!! : exist party vote - {party_attribute.PartyVote.VoteTitle}";
|
||||
result.setFail(ServerErrorCode.AlreadyStartPartyVote, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 3. Last Vote Time 체크
|
||||
var last_vote_time = party_attribute.LastVoteTime ?? DateTimeHelper.MinTime.ToTimestamp();
|
||||
if (last_vote_time > DateTime.UtcNow.AddSeconds(-1 * MetaHelper.GameConfigMeta.VoteCoolTimeSec).ToTimestamp())
|
||||
{
|
||||
err_msg = $"Failed to start party vote !!! : invalid party vote time - {vote_title}";
|
||||
result.setFail(ServerErrorCode.InvalidPartyVoteTime, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
private async Task waitPartyVoteFinish()
|
||||
{
|
||||
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(MetaHelper.GameConfigMeta.VoteTimeLimitSec + 1));
|
||||
m_vote_finish_task_source = new();
|
||||
|
||||
cts.Token.Register(() => { m_vote_finish_task_source.TrySetCanceled(); });
|
||||
try
|
||||
{
|
||||
await m_vote_finish_task_source.Task;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// Ignore...
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.getLogger().error($"Failed to wait party vote !!! : exception finish task - {e}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 파티 정보 획득
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!");
|
||||
|
||||
// 2. 투표 결과 수집
|
||||
var party_attribute = party.getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
// 3. 결과 수집
|
||||
var agreement = party_attribute.getVoteCount(VoteType.Agreement);
|
||||
var disAgreement = party_attribute.getVoteCount(VoteType.DisAgreement);
|
||||
var abstain = party_attribute.getVoteCount(VoteType.Abstain);
|
||||
abstain += party_attribute.getVoteCount(VoteType.None);
|
||||
|
||||
// 4. 결과 통보 ( to server )
|
||||
var server_message = new ServerMessage();
|
||||
server_message.PartyVoteResultNoti = new();
|
||||
server_message.PartyVoteResultNoti.PartyGuid = party.PartyGuid;
|
||||
server_message.PartyVoteResultNoti.VoteTitle = party_attribute.PartyVote?.VoteTitle ?? string.Empty;
|
||||
server_message.PartyVoteResultNoti.ResultTrue = agreement;
|
||||
server_message.PartyVoteResultNoti.ResultFalse = disAgreement;
|
||||
server_message.PartyVoteResultNoti.Abstain = abstain;
|
||||
|
||||
PartyHelper.BroadcastToServers(party, server_message, true);
|
||||
|
||||
// 4. 결과 통보 ( to client )
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyVoteResultNoti = new();
|
||||
client_message.Message.PartyVoteResultNoti.VoteTitle = party_attribute.PartyVote?.VoteTitle ?? string.Empty;
|
||||
client_message.Message.PartyVoteResultNoti.ResultTrue = agreement;
|
||||
client_message.Message.PartyVoteResultNoti.ResultFalse = disAgreement;
|
||||
client_message.Message.PartyVoteResultNoti.Abstain = abstain;
|
||||
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<string>());
|
||||
|
||||
// 5. Business Log 기록
|
||||
writeBusinessLog(party);
|
||||
|
||||
// 6. 투표 데이터 삭제
|
||||
party_attribute.PartyVote = null;
|
||||
}
|
||||
|
||||
private void writeBusinessLog(GlobalPartyDetail party)
|
||||
{
|
||||
var log_invokers = new List<ILogInvoker>(2);
|
||||
|
||||
// 1. 파티정보
|
||||
var party_log_data = PartyBusinessLogHelper.toPartyLogData(party.PartyGuid, false);
|
||||
var party_business_log = new PartyBusinessLog(party_log_data);
|
||||
log_invokers.Add(party_business_log);
|
||||
|
||||
// 2. 파티 투표 정보
|
||||
var party_vote_log = PartyBusinessLogHelper.toPartyVoteLogData(party.PartyGuid, false);
|
||||
var party_vote_business_log = new PartyVoteBusinessLog(party_vote_log);
|
||||
log_invokers.Add(party_vote_business_log);
|
||||
|
||||
BusinessLogger.collectLogs(new LogActionEx(LogActionType.EndPartyVote), party, log_invokers);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyDetailInstanceAction : EntityActionBase
|
||||
{
|
||||
private readonly PartyInstanceCacheRequest m_party_instance_cache_request;
|
||||
|
||||
public GlobalPartyDetailInstanceAction(GlobalPartyDetail owner) : base(owner)
|
||||
{
|
||||
m_party_instance_cache_request =
|
||||
new PartyInstanceCacheRequest(owner.PartyGuid, GameServerApp.getServerLogic().getRedisConnector());
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> keep()
|
||||
{
|
||||
return await m_party_instance_cache_request.keepPartyInstanceCache();
|
||||
}
|
||||
|
||||
public async Task<Result> loadPartyInstance()
|
||||
{
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var result = await m_party_instance_cache_request.fetchPartyInstanceCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(attribute,
|
||||
new List<CacheBase> { m_party_instance_cache_request.getPartyInstanceCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> registerPartyInstance(int instanceId, string roomId, Timestamp startTime, Timestamp endTime, int joinCount, bool isNotify)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "global party detail is null !!!");
|
||||
|
||||
var party_instance_attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_instance_attribute, () => $"PartyInstanceAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
// 1. cache 생성
|
||||
result = await m_party_instance_cache_request.createPartyInstanceCache(instanceId, roomId, startTime, endTime, joinCount);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. attribute 복사
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_instance_attribute,
|
||||
new List<CacheBase> { m_party_instance_cache_request.getPartyInstanceCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
if (false == isNotify) return result;
|
||||
|
||||
// 8. instance 정보 알림 ( to Servers )
|
||||
var server_message = new ServerMessage();
|
||||
server_message.PartyInstanceInfoNoti = new();
|
||||
server_message.PartyInstanceInfoNoti.PartyGuid = party.PartyGuid;
|
||||
|
||||
PartyHelper.BroadcastToServers(party, server_message, true);
|
||||
|
||||
// 9. instance 정보 알림 ( to Clients )
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyInstanceInfoNoti = new();
|
||||
client_message.Message.PartyInstanceInfoNoti.InstanceId = instanceId;
|
||||
client_message.Message.PartyInstanceInfoNoti.StartTime = startTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.EndTime = endTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.JoinMemberCount = joinCount;
|
||||
client_message.Message.PartyInstanceInfoNoti.IsEnd = BoolType.False;
|
||||
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<string>());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deletePartyInstance()
|
||||
{
|
||||
// 1. cache 제거
|
||||
var result = await m_party_instance_cache_request.deletePartyInstanceCache();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
// 2. attribute 제거
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
attribute.onClear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool isExist()
|
||||
{
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return attribute.InstanceId > 0;
|
||||
}
|
||||
|
||||
public Timestamp getStartTime()
|
||||
{
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return attribute.StartTime;
|
||||
}
|
||||
|
||||
public async Task<Result> finishPartyInstance(int joinCount = 0)
|
||||
{
|
||||
return await changePartyInstance(DateTimeHelper.MinTime.ToTimestamp(), DateTimeHelper.MinTime.ToTimestamp(), joinCount, true, true);
|
||||
}
|
||||
|
||||
public async Task<Result> changePartyInstance(Timestamp startTime, Timestamp endTime, int joinCount, bool isFinish, bool notifyStartInstance)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
// 1. cache 수정
|
||||
var cache = m_party_instance_cache_request.getPartyInstanceCache();
|
||||
NullReferenceCheckHelper.throwIfNull(cache, () => $"Party Instance Cache is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
cache.JoinMemberCount = joinCount;
|
||||
cache.StartTime = startTime;
|
||||
cache.EndTime = endTime;
|
||||
|
||||
if (isFinish)
|
||||
{
|
||||
cache.InstanceId = 0;
|
||||
cache.RoomId = string.Empty;
|
||||
}
|
||||
|
||||
result = await m_party_instance_cache_request.upsertPartyInstanceCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. attribute 수정
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
attribute.JoinMemberCount = cache.JoinMemberCount;
|
||||
attribute.StartTime = startTime;
|
||||
attribute.EndTime = endTime;
|
||||
|
||||
if (isFinish)
|
||||
{
|
||||
attribute.InstanceId = 0;
|
||||
attribute.RoomId = string.Empty;
|
||||
}
|
||||
|
||||
if (notifyStartInstance)
|
||||
{
|
||||
sendPartyInstanceInfoToMembers();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task changeJoinMemberCount(int joinCount, bool notify)
|
||||
{
|
||||
// 1. cache 수정
|
||||
var cache = m_party_instance_cache_request.getPartyInstanceCache();
|
||||
NullReferenceCheckHelper.throwIfNull(cache, () => $"Party Instance Cache is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
cache.JoinMemberCount = joinCount;
|
||||
|
||||
await m_party_instance_cache_request.upsertPartyInstanceCache();
|
||||
|
||||
// 2. attribute 수정
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
attribute.JoinMemberCount = cache.JoinMemberCount;
|
||||
|
||||
if (notify)
|
||||
{
|
||||
sendPartyInstanceInfoToMembers();
|
||||
}
|
||||
}
|
||||
|
||||
private void sendPartyInstanceInfoToMembers()
|
||||
|
||||
{
|
||||
// 1. server message
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => "Party Detail is null");
|
||||
|
||||
var attribute = getOwner().getEntityAttribute<PartyInstanceAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInstanceAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
var server_message = new ServerMessage();
|
||||
server_message.PartyInstanceInfoNoti = new();
|
||||
server_message.PartyInstanceInfoNoti.PartyGuid = party.PartyGuid;
|
||||
|
||||
PartyHelper.BroadcastToServers(party, server_message, true);
|
||||
|
||||
// 2. client message
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyInstanceInfoNoti = new();
|
||||
client_message.Message.PartyInstanceInfoNoti.InstanceId = attribute.InstanceId;
|
||||
client_message.Message.PartyInstanceInfoNoti.JoinMemberCount = attribute.JoinMemberCount;
|
||||
client_message.Message.PartyInstanceInfoNoti.StartTime = attribute.StartTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.EndTime = attribute.EndTime;
|
||||
client_message.Message.PartyInstanceInfoNoti.IsEnd = attribute.InstanceId == 0 ? BoolType.True : BoolType.False;
|
||||
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<string>());
|
||||
}
|
||||
}
|
||||
548
GameServer/Entity/Party/Action/GlobalPartyDetailMemberAction.cs
Normal file
548
GameServer/Entity/Party/Action/GlobalPartyDetailMemberAction.cs
Normal file
@@ -0,0 +1,548 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyDetailMemberAction : EntityActionBase
|
||||
{
|
||||
private readonly PartyMemberCacheRequest m_party_member_cache_request;
|
||||
|
||||
public GlobalPartyDetailMemberAction(GlobalPartyDetail owner) : base(owner)
|
||||
{
|
||||
m_party_member_cache_request =
|
||||
new PartyMemberCacheRequest(owner.PartyGuid, GameServerApp.getServerLogic().getRedisConnector());
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
}
|
||||
|
||||
public async Task<Result> keep()
|
||||
{
|
||||
return await m_party_member_cache_request.keepPartyMemberCache();
|
||||
}
|
||||
|
||||
public PartyMemberInfo? getMember(USER_GUID user_guid)
|
||||
{
|
||||
var party_member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_member_attribute.getPartyMembers().GetValueOrDefault(user_guid);
|
||||
}
|
||||
public IEnumerable<USER_GUID> getMembers()
|
||||
{
|
||||
var party_member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_member_attribute.getPartyMembers().Select(member => member.Key).ToList();
|
||||
}
|
||||
|
||||
public bool isPartyMember(USER_GUID user_guid)
|
||||
{
|
||||
var attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var member = attribute.getPartyMember(user_guid);
|
||||
return null != member;
|
||||
}
|
||||
|
||||
public int getMemberCount()
|
||||
{
|
||||
var party_member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_member_attribute.getPartyMembers().Count;
|
||||
}
|
||||
|
||||
public bool checkExistPartyMembers(USER_GUID except_member_user)
|
||||
{
|
||||
var attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
foreach (var member in attribute.getPartyMembers())
|
||||
{
|
||||
if (member.Key == except_member_user) continue;
|
||||
if (false == player_manager.tryGetUserByPrimaryKey(member.Key, out var player)) continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<Result> loadPartyMember()
|
||||
{
|
||||
var party_member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var result = await m_party_member_cache_request.fetchPartyMemberCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_member_attribute, new List<CacheBase> { m_party_member_cache_request.getPartyMemberCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public IEnumerable<PartyMemberState> getMembers4PartyInfo()
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!");
|
||||
|
||||
var party_member_attribute = party.getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
var states = new List<PartyMemberState>();
|
||||
foreach (var member in party_member_attribute.getPartyMembers())
|
||||
{
|
||||
var state = new PartyMemberState();
|
||||
state.MemberGuid = member.Value.UserGuid;
|
||||
state.MemberNickname = member.Value.Nickname;
|
||||
state.MarkId = member.Value.MarkId;
|
||||
state.LocationInfo = member.Value.LocationInfo;
|
||||
|
||||
states.Add(state);
|
||||
}
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
public async Task<(Result result, bool? isAready)> addJoinMember(PartyMemberInfo user)
|
||||
{
|
||||
var change = await changeMember(user);
|
||||
if (change.result.isFail()) return (change.result, null);
|
||||
|
||||
// 0. 데이터가 없으면, 기존 참가 인원으로 위치변경만 노티
|
||||
if (null == change.info)
|
||||
{
|
||||
sendPartyMemberLocation(user);
|
||||
return (change.result, true);
|
||||
}
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
ArgumentNullException.ThrowIfNull(party);
|
||||
|
||||
// 1. 파티 참가 멤버 알림 ( to server )
|
||||
var server_message = new ServerMessage
|
||||
{
|
||||
JoinPartyMemberNoti = new()
|
||||
{
|
||||
PartyGuid = party.PartyGuid,
|
||||
JoinPartyMemberInfo = JsonConvert.SerializeObject(change.info)
|
||||
}
|
||||
};
|
||||
PartyHelper.BroadcastToServers(party, server_message, true);
|
||||
|
||||
// 2. 파티 참가 멤버 알림 ( to client )
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.JoinPartyMemberNoti = new();
|
||||
client_message.Message.JoinPartyMemberNoti.JoinPartyMemberGuid = change.info.UserGuid;
|
||||
client_message.Message.JoinPartyMemberNoti.JoinMemberInfo = new PartyMemberState();
|
||||
client_message.Message.JoinPartyMemberNoti.JoinMemberInfo.MarkId = change.info.MarkId;
|
||||
client_message.Message.JoinPartyMemberNoti.JoinMemberInfo.MemberGuid = change.info.UserGuid;
|
||||
client_message.Message.JoinPartyMemberNoti.JoinMemberInfo.MemberNickname = change.info.Nickname;
|
||||
client_message.Message.JoinPartyMemberNoti.JoinMemberInfo.LocationInfo = change.info.LocationInfo;
|
||||
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<string> { user.UserGuid });
|
||||
|
||||
return (change.result, false);
|
||||
}
|
||||
|
||||
public async Task<Result> deletePartyMembers()
|
||||
{
|
||||
// 1. cache 제거
|
||||
var result = await m_party_member_cache_request.deletePartyMemberCache();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
// 2. attribute 수정
|
||||
var party_member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_member_attribute.onClear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(Result result, int party_member_count)> deleteJoinMember(USER_GUID delete_user_guid, bool is_upsert_cache)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!");
|
||||
|
||||
// 1. attribute 수정
|
||||
var party_member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
if (!party_member_attribute.deletePartyMember(delete_user_guid))
|
||||
{
|
||||
var err_msg = $"Failed to delete party memeber !!! : {delete_user_guid}";
|
||||
result.setFail(ServerErrorCode.NotPartyMember, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, party_member_attribute.getPartyMembers().Count);
|
||||
}
|
||||
|
||||
// 2. cache 수정
|
||||
var member_cache = m_party_member_cache_request.getPartyMemberCache();
|
||||
NullReferenceCheckHelper.throwIfNull(member_cache, () => $"member cache is null !!! - user_guid:{delete_user_guid}");
|
||||
|
||||
member_cache.deleteJoinMember(delete_user_guid);
|
||||
|
||||
if(is_upsert_cache) result = await m_party_member_cache_request.deleteJoinMember(delete_user_guid);
|
||||
return (result, party_member_attribute.getPartyMembers().Count);
|
||||
}
|
||||
|
||||
public async Task<Result> changeMemberMaker(USER_GUID user_guid, int new_marker_id, bool is_cash_upsert)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
var party_member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var exist_user = party_member_attribute.getPartyMember(user_guid);
|
||||
if (null == exist_user)
|
||||
{
|
||||
err_msg = $"Failed to get party member !!! : not party member - {user_guid}";
|
||||
result.setFail(ServerErrorCode.NotPartyMember, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 1. cache 수정
|
||||
var member_cache = m_party_member_cache_request.getPartyMemberCache();
|
||||
NullReferenceCheckHelper.throwIfNull(member_cache, () => $"member cache is null !!! - userGuid:{user_guid}");
|
||||
|
||||
if (!member_cache.PartyMembers.TryGetValue(user_guid, out var member))
|
||||
{
|
||||
err_msg = $"Failed to get party member !!! : not party member - {user_guid}";
|
||||
result.setFail(ServerErrorCode.NotPartyMember, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
member.MarkId = new_marker_id;
|
||||
|
||||
if (is_cash_upsert)
|
||||
{
|
||||
result = await m_party_member_cache_request.changeJoinMember(member);
|
||||
if (result.isFail()) return result;
|
||||
}
|
||||
|
||||
// 2. attribute 수정
|
||||
exist_user.MarkId = new_marker_id;
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(Result result, PartyMemberInfo? info)> changeMember(PartyMemberInfo user)
|
||||
{
|
||||
var party_member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var exist_user = party_member_attribute.getPartyMember(user.UserGuid);
|
||||
if (null != exist_user)
|
||||
{
|
||||
user.MarkId = exist_user.MarkId;
|
||||
user.JoinTime = exist_user.JoinTime;
|
||||
}
|
||||
|
||||
// 1. cache 수정
|
||||
var result = await m_party_member_cache_request.changeJoinMember(user);
|
||||
if (result.isFail()) return (result, null);
|
||||
|
||||
// 2. attribute 데이터 수정
|
||||
party_member_attribute.setPartyMember(user);
|
||||
|
||||
// 3. exist_user 가 있으면, 기존 참가 유저
|
||||
return null != exist_user ? (result, null) : (result, user);
|
||||
}
|
||||
|
||||
public IEnumerable<string> getSummonMembers()
|
||||
{
|
||||
var member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return (from member in member_attribute.getPartyMembers()
|
||||
where member.Value.Summon.IsAlreadySummon select member.Key).ToList();
|
||||
}
|
||||
|
||||
public async Task<(Result result, Item? delete_item)> summonMemberAsync(USER_GUID summon_user_guid, SummonInfo summon)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !! ");
|
||||
|
||||
var member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(member_attribute, () => $"PartyMemberAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
// 1. summon user login_cache 조회
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var summon_user_login_cache_request =
|
||||
new LoginCacheOtherUserRequest(server_logic, server_logic.getRedisConnector(), summon_user_guid);
|
||||
result = await summon_user_login_cache_request.fetchLogin();
|
||||
if (result.isFail()) return (result, null);
|
||||
|
||||
var summon_user_login_cache = summon_user_login_cache_request.getLoginCache();
|
||||
if (null == summon_user_login_cache)
|
||||
{
|
||||
err_msg = $"Failed to summon party member !!! : summon user not logged in - {summon_user_guid}";
|
||||
result.setFail(ServerErrorCode.UserNotLogin, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
var player_manager = server_logic.getPlayerManager();
|
||||
|
||||
// 2. 소환석 제거
|
||||
var summon_result = await spentSummonItemAsync(player_manager, party);
|
||||
if (summon_result.result.isFail()) return (summon_result.result, null);
|
||||
|
||||
// 3. summon 수정
|
||||
var member = member_attribute.getPartyMember(summon_user_guid);
|
||||
NullReferenceCheckHelper.throwIfNull(member, () => $"party member is null !!! - userGuid:{summon_user_guid}");
|
||||
member.Summon = summon;
|
||||
|
||||
result = await m_party_member_cache_request.changeJoinMember(member);
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
// 4. 대상 에게 summon 전송
|
||||
result = summon_user_login_cache.CurrentServer == server_logic.getServerName()
|
||||
? sendSummonMessageToClient(player_manager, summon_user_guid)
|
||||
: sendSummonMessageToServer(party, player_manager, summon_user_guid,
|
||||
summon_user_login_cache.CurrentServer);
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, summon_result.delete_summon_item);
|
||||
}
|
||||
|
||||
public async Task<Result> clearSummonMemberAsync(USER_GUID summon_user_guid, bool isNotify)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !!!");
|
||||
|
||||
var member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(member_attribute, () => $"PartyMemberAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
// 1. summon 수정
|
||||
var member = member_attribute.getPartyMember(summon_user_guid);
|
||||
NullReferenceCheckHelper.throwIfNull(member, () => $"party member is null !!! - userGuid:{summon_user_guid}");
|
||||
member.Summon = new();
|
||||
|
||||
result = await m_party_member_cache_request.changeJoinMember(member);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. 알림 처리
|
||||
if (isNotify)
|
||||
{
|
||||
var message = new ServerMessage();
|
||||
message.NtfClearPartySummon = new();
|
||||
message.NtfClearPartySummon.PartyGuid = party.PartyGuid;
|
||||
message.NtfClearPartySummon.MemberUserGuid = summon_user_guid;
|
||||
|
||||
PartyHelper.BroadcastToServers(party, message, true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(Result result, int cancelSummonCount)> cancelAllSummonAsync()
|
||||
{
|
||||
var result = new Result();
|
||||
var owner = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"global party detail is null !!");
|
||||
|
||||
var member_attribute = getOwner().getEntityAttribute<PartyMemberAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(member_attribute, () => $"PartyMemberAttribute is null !! - {owner.toBasicString()}");
|
||||
|
||||
var server_message = new ServerMessage
|
||||
{
|
||||
CancelSummonPartyMemberNoti = new ServerMessage.Types.CancelSummonPartyMemberNoti
|
||||
{
|
||||
PartyGuid = owner.PartyGuid
|
||||
}
|
||||
};
|
||||
|
||||
// 1. summon 수정
|
||||
foreach (var member in member_attribute.getPartyMembers())
|
||||
{
|
||||
if (!member.Value.Summon.IsAlreadySummon) continue;
|
||||
member.Value.Summon.clear();
|
||||
server_message.CancelSummonPartyMemberNoti.CancelSummonUserGuids.Add(member.Key);
|
||||
|
||||
result = await m_party_member_cache_request.changeJoinMember(member.Value);
|
||||
|
||||
server_message.CancelSummonPartyMemberNoti.CancelSummonUserGuids.Add(member.Value.UserGuid);
|
||||
}
|
||||
|
||||
// 2. notify 전송
|
||||
if (server_message.CancelSummonPartyMemberNoti.CancelSummonUserGuids.Count > 0)
|
||||
{
|
||||
PartyHelper.BroadcastToServers(owner, server_message, false);
|
||||
}
|
||||
|
||||
return (result, server_message.CancelSummonPartyMemberNoti.CancelSummonUserGuids.Count);
|
||||
}
|
||||
|
||||
private Result sendSummonMessageToClient(PlayerManager player_manager, USER_GUID summon_user_guid)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
// 1. summon user 조회
|
||||
if (!player_manager.tryGetUserByPrimaryKey(summon_user_guid, out var summon_user))
|
||||
{
|
||||
var err_msg = $"Failed to summon party member !!! : summon user not logged in - {summon_user_guid}";
|
||||
result.setFail(ServerErrorCode.UserNotLogin, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. client 전송
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new ClientToGameMessage();
|
||||
client_message.Message.SummonPartyMemberNoti = new ClientToGameMessage.Types.SummonPartyMemberNoti();
|
||||
|
||||
PartyHelper.sendToClient(client_message, summon_user.getHostId());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Result sendSummonMessageToServer(GlobalPartyDetail party, PlayerManager player_manager, USER_GUID summon_user_guid, string target_server)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
// 1. party leader 조회
|
||||
var party_action = party.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_action, () => $"GlobalPartyDetailAction is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
if (!player_manager.tryGetUserByPrimaryKey(party_action.getLeaderGuid(), out var leader))
|
||||
{
|
||||
var err_msg = $"Failed to summon party member !!! : leader not logged in - {leader?.getUserGuid()}";
|
||||
result.setFail(ServerErrorCode.UserNotLogin, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. leader 위치 조회
|
||||
var leader_location = leader.getEntityAction<LocationAction>()?.getCurrentPos();
|
||||
if (null == leader_location)
|
||||
{
|
||||
var err_msg = $"Failed to summon party member !!! : leader not logged in - {leader.getUserGuid()}";
|
||||
result.setFail(ServerErrorCode.UserNotLogin, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 3. server 전송
|
||||
var server_message = new ServerMessage();
|
||||
server_message.SummonPartyMemberNoti = new ServerMessage.Types.SummonPartyMemberNoti();
|
||||
server_message.SummonPartyMemberNoti.SummonPartyGuid = party.PartyGuid;
|
||||
server_message.SummonPartyMemberNoti.SummonUserGuid = summon_user_guid;
|
||||
server_message.SummonPartyMemberNoti.SummonServerName = GameServerApp.getServerLogic().getServerName();
|
||||
server_message.SummonPartyMemberNoti.SummonPos = leader_location;
|
||||
|
||||
PartyHelper.sendToServer(server_message, target_server);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<(Result result, Item? delete_summon_item)> spentSummonItemAsync(PlayerManager player_manager, GlobalPartyDetail party)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var party_action = party.getEntityAction<GlobalPartyDetailAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_action, () => $"GlobalPartyDetailAction is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
if (!player_manager.tryGetUserByPrimaryKey(party_action.getLeaderGuid(), out var leader))
|
||||
{
|
||||
var err_msg = $"Failed to summon party member !!! : leader not logged in - {party_action.getLeaderGuid()}";
|
||||
result.setFail(ServerErrorCode.PartyLeaderLoggedOut, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
var inventory_action = leader.getEntityAction<InventoryActionBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"InventoryActionBase is null !! - {leader.toBasicString()}");;
|
||||
|
||||
var delete_summon_item = await inventory_action.tryDeleteItemByMetaId((uint)MetaHelper.GameConfigMeta.SummonStoneItemMetaId, (ushort)MetaHelper.GameConfigMeta.ItemAmountPartySummon);
|
||||
if (delete_summon_item.Item1.isFail()) return (delete_summon_item.Item1, null);
|
||||
|
||||
var delete_item = delete_summon_item.Item2.FirstOrDefault();
|
||||
return (delete_summon_item.Item1, delete_item);
|
||||
|
||||
}
|
||||
|
||||
private void sendPartyMemberLocation(PartyMemberInfo user)
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !! ");;
|
||||
|
||||
// 1. 파티 참가 멤버 알림 ( to server )
|
||||
var server_message = new ServerMessage
|
||||
{
|
||||
PartyMemberLocationNoti = new()
|
||||
{
|
||||
PartyGuid = party.PartyGuid,
|
||||
PartyMemberGuid = user.UserGuid
|
||||
}
|
||||
};
|
||||
PartyHelper.BroadcastToServers(party, server_message, true);
|
||||
|
||||
// 2. 파티 참가 멤버 알림 ( to client )
|
||||
var client_message = new ClientToGame();
|
||||
client_message.Message = new();
|
||||
client_message.Message.PartyMemberLocationNoti = new();
|
||||
client_message.Message.PartyMemberLocationNoti.MemberGuid = user.UserGuid;
|
||||
client_message.Message.PartyMemberLocationNoti.LocationInfo = user.LocationInfo;
|
||||
|
||||
PartyHelper.BroadcastToClients(party, client_message, new List<string>());
|
||||
}
|
||||
}
|
||||
144
GameServer/Entity/Party/Action/GlobalPartyDetailServerAction.cs
Normal file
144
GameServer/Entity/Party/Action/GlobalPartyDetailServerAction.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyDetailServerAction : EntityActionBase
|
||||
{
|
||||
private readonly PartyServerCacheRequest m_party_server_cache_request;
|
||||
|
||||
public GlobalPartyDetailServerAction(GlobalPartyDetail owner) : base(owner)
|
||||
{
|
||||
m_party_server_cache_request =
|
||||
new PartyServerCacheRequest(owner.PartyGuid, GameServerApp.getServerLogic().getRedisConnector());
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> keep()
|
||||
{
|
||||
return await m_party_server_cache_request.keepPartyServerCache();
|
||||
}
|
||||
|
||||
public async Task<Result> loadPartyServer()
|
||||
{
|
||||
var party_server_attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_attribute, () => $"PartyServerAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var result = await m_party_server_cache_request.fetchPartyServerCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_server_attribute, new List<CacheBase> { m_party_server_cache_request.getPartyServerCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public IEnumerable<string> getServers()
|
||||
{
|
||||
var party_server_attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_attribute, () => $"PartyServerAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_server_attribute.getPartyServers().ToList();
|
||||
}
|
||||
|
||||
public async Task<Result> addPartyServer(string addServerName)
|
||||
{
|
||||
|
||||
var party_server_attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_attribute, () => $"PartyServerAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var result = await m_party_server_cache_request.addPartyServerCache(addServerName);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
party_server_attribute.addPartyServer(addServerName);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deletePartyServer(string delete_server_name)
|
||||
{
|
||||
// 1. cache 제거
|
||||
var result = await m_party_server_cache_request.deletePartyServerCache(delete_server_name);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
// 2. attribute 수정
|
||||
var attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyServerAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
attribute.deleteServer(delete_server_name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deleteAllPartyServers()
|
||||
{
|
||||
// 1. cache 제거
|
||||
var result = await m_party_server_cache_request.deleteAllPartyServerCache();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
// 2. attribute 수정
|
||||
var party_server_attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_attribute, () => $"PartyServerAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_server_attribute.onClear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> notifyChangePartyServerToServers(BoolType isAddition, string srcServerName)
|
||||
{
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"party deltail is null !!!");
|
||||
|
||||
var party_server_attribute = getOwner().getEntityAttribute<PartyServerAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_server_attribute, () => $"PartyServerAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
var rabbit_mq = GameServerApp.getServerLogic().getRabbitMqConnector() as RabbitMqConnector;
|
||||
NullReferenceCheckHelper.throwIfNull(rabbit_mq, () => $"rabbit mq is null !!! - {getOwner().toBasicString()}");
|
||||
|
||||
var message = new ServerMessage
|
||||
{
|
||||
ChangePartyServerNameNoti = new()
|
||||
{
|
||||
PartyGuid = party.PartyGuid,
|
||||
IsAddition = isAddition,
|
||||
ServerName = srcServerName
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var dest_server in party_server_attribute.getPartyServers())
|
||||
{
|
||||
if (srcServerName == dest_server) continue;
|
||||
rabbit_mq.SendMessage(dest_server, message);
|
||||
}
|
||||
|
||||
return await Task.FromResult(new Result());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using PARTY_GUID = System.String;
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyInvitePartySendAction : EntityActionBase
|
||||
{
|
||||
private readonly PartyInvitePartySendCacheRequest m_party_invite_party_send_cache_request;
|
||||
|
||||
public GlobalPartyInvitePartySendAction(GlobalPartyDetail owner) : base(owner)
|
||||
{
|
||||
m_party_invite_party_send_cache_request =
|
||||
new PartyInvitePartySendCacheRequest(owner.PartyGuid, GameServerApp.getServerLogic().getRedisConnector());
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public async Task<Result> keep()
|
||||
{
|
||||
return await m_party_invite_party_send_cache_request.keepInvitePartySendCache();
|
||||
}
|
||||
|
||||
public async Task<Result> loadPartyInvitePartySend(PARTY_GUID party_guid)
|
||||
{
|
||||
var result = new Result();
|
||||
if (PARTY_GUID.IsNullOrEmpty(party_guid))
|
||||
{
|
||||
var err_msg = $"Fail to load party invite party send !!! : argument is null - {nameof(loadPartyInvitePartySend)}";
|
||||
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var party_invite_party_send = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
result = await m_party_invite_party_send_cache_request.fetchInvitePartySendCache();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(party_invite_party_send, new List<CacheBase> { m_party_invite_party_send_cache_request.getPartyInvitePartySendCache()! });
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deleteInvitePartySends()
|
||||
{
|
||||
// 1. cache 제거
|
||||
var result = await m_party_invite_party_send_cache_request.deleteAllInvitePartySendCache();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
// 2. attribute 수정
|
||||
var party_invite_send_attribute = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_send_attribute, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_invite_send_attribute.onClear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deleteInvitePartySend(USER_GUID invitee_guid)
|
||||
{
|
||||
// 1. attribute 수정
|
||||
var party_invite_send_attribute = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_send_attribute, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_invite_send_attribute.deleteInvitePartySend(invitee_guid);
|
||||
|
||||
// 2. cache 에서 제거
|
||||
var result = await m_party_invite_party_send_cache_request.deleteInvitePartySendCache(new List<string> { invitee_guid });
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<bool> isExistCheck(string user_guid)
|
||||
{
|
||||
await organizeSendAttribute();
|
||||
|
||||
var party_invite_party_send = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var sends = party_invite_party_send.getPartyInvitePartySends();
|
||||
return sends.Any(send => send.Key == user_guid);
|
||||
}
|
||||
|
||||
public async Task<int> getInviteSendsCount()
|
||||
{
|
||||
var list = await getPartyInvitePartySends();
|
||||
return list.Count;
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, DateTime>> getPartyInvitePartySends()
|
||||
{
|
||||
await organizeSendAttribute();
|
||||
|
||||
var attribute = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
var sends = attribute.getPartyInvitePartySends();
|
||||
var list = sends.ToDictionary(send => send.Key, send => send.Value);
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<Result> sendInviteParty(IReadOnlyDictionary<string, string>? invite_users)
|
||||
{
|
||||
var result = new Result();
|
||||
var party = getOwner() as GlobalPartyDetail;
|
||||
NullReferenceCheckHelper.throwIfNull(party, () => $"global party detail is null !! ");
|
||||
|
||||
var send_users = invite_users?.Select(invitee => invitee.Key).ToList();
|
||||
if (null == send_users)
|
||||
{
|
||||
var err_msg = $"Failed to send invite party !!! : invite_users is null - {nameof(sendInviteParty)}";
|
||||
result.setFail(ServerErrorCode.FailToSendInviteMember, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. redis 저장
|
||||
result = await m_party_invite_party_send_cache_request.addInvitePartySendCache(send_users);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// 3. attribute 변경
|
||||
var party_invite_party_send = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send, () => $"PartyInvitePartySendsAttribute is null !! - {party.toBasicString()}");
|
||||
|
||||
party_invite_party_send.addInvitePartySends(send_users);
|
||||
|
||||
// 1. mq message 생성
|
||||
var message = new ServerMessage();
|
||||
message.InvitePartyNoti = new();
|
||||
message.InvitePartyNoti.InvitePartyLeaderGuid = getPartyLeaderGuid();
|
||||
message.InvitePartyNoti.InvitePartyGuid = party.PartyGuid;
|
||||
|
||||
var rabbit_mq = GameServerApp.getServerLogic().getRabbitMqConnector() as RabbitMqConnector;
|
||||
ArgumentNullException.ThrowIfNull(rabbit_mq);
|
||||
|
||||
// 4. invite 유저에게 메시지 전달
|
||||
NullReferenceCheckHelper.throwIfNull(invite_users, () => $"party invite users is null !!! - {party.toBasicString()}");
|
||||
foreach (var invitee in invite_users)
|
||||
{
|
||||
message.InvitePartyNoti.InviteUserGuid = invitee.Key;
|
||||
rabbit_mq.SendMessage(invitee.Value, message);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private USER_GUID getPartyLeaderGuid()
|
||||
{
|
||||
var party_attribute = getOwner().getEntityAttribute<PartyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_attribute, () => $"PartyAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
return party_attribute.PartyLeaderCharGuid;
|
||||
}
|
||||
|
||||
private async Task organizeSendAttribute()
|
||||
{
|
||||
var delete_sends = await m_party_invite_party_send_cache_request.organizeInvitePartySendCache();
|
||||
if (null == delete_sends) return;
|
||||
|
||||
var party_invite_party_send = getOwner().getEntityAttribute<PartyInvitePartySendsAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_invite_party_send, () => $"PartyInvitePartySendsAttribute is null !! - {getOwner().toBasicString()}");
|
||||
|
||||
party_invite_party_send.deleteInvitePartySends(delete_sends);
|
||||
}
|
||||
}
|
||||
50
GameServer/Entity/Party/GlobalParty.cs
Normal file
50
GameServer/Entity/Party/GlobalParty.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using PARTY_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalParty : EntityBase
|
||||
{
|
||||
public GlobalParty() : base(EntityType.GlobalParty)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
// action
|
||||
addEntityAction(new GlobalPartyAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()}";
|
||||
}
|
||||
|
||||
public GlobalPartyDetail? getParty(PARTY_GUID party_guid)
|
||||
{
|
||||
var action = getEntityAction<GlobalPartyAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(action, () => $"GlobalPartyAction is null !! - party_guid:{party_guid}");
|
||||
|
||||
var party = action.getGlobalPartyDetail(party_guid);
|
||||
|
||||
return party;
|
||||
}
|
||||
}
|
||||
73
GameServer/Entity/Party/GlobalPartyDetail.cs
Normal file
73
GameServer/Entity/Party/GlobalPartyDetail.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using Nettention.Proud;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using PARTY_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GlobalPartyDetail : EntityBase, IWithLogActor
|
||||
{
|
||||
public PARTY_GUID PartyGuid { get; }
|
||||
|
||||
public GlobalPartyDetail(GlobalParty parent, string party_guid)
|
||||
: base(EntityType.GlobalPartyDetail, parent)
|
||||
{
|
||||
PartyGuid = party_guid;
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
// attribute
|
||||
addEntityAttribute(new PartyAttribute(this, GameServerApp.getServerLogic().getProudNetListener().getNetServer()!));
|
||||
addEntityAttribute(new PartyMemberAttribute(this));
|
||||
addEntityAttribute(new PartyServerAttribute(this));
|
||||
addEntityAttribute(new PartyInstanceAttribute(this));
|
||||
addEntityAttribute(new PartyInvitePartySendsAttribute(this));
|
||||
|
||||
// action
|
||||
addEntityAction(new GlobalPartyDetailAction(this));
|
||||
addEntityAction(new GlobalPartyDetailInfoAction(this));
|
||||
addEntityAction(new GlobalPartyDetailMemberAction(this));
|
||||
addEntityAction(new GlobalPartyDetailServerAction(this));
|
||||
addEntityAction(new GlobalPartyDetailInstanceAction(this));
|
||||
addEntityAction(new GlobalPartyInvitePartySendAction(this));
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"{this.getTypeName()} - {getRootParent()?.toBasicString()}";
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
return $"{this.getTypeName()} - {getRootParent()?.toBasicString()}";
|
||||
}
|
||||
|
||||
public virtual ILogActor toLogActor()
|
||||
{
|
||||
var server_logic = ServerLogicApp.getServerLogicApp();
|
||||
|
||||
var log_info = new GlobalPartyActorLog();
|
||||
if (server_logic == null)
|
||||
return log_info;
|
||||
|
||||
log_info.initLogInfo(
|
||||
// 서버 정보
|
||||
server_logic.getServerConfig().getRegionId()
|
||||
, server_logic.getServerConfig().getWorldId()
|
||||
, server_logic.getServerType().toServerType()
|
||||
);
|
||||
|
||||
return log_info;
|
||||
}
|
||||
}
|
||||
33
GameServer/Entity/Party/Helper/PartyExtensions.cs
Normal file
33
GameServer/Entity/Party/Helper/PartyExtensions.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public static class PartyExtensions
|
||||
{
|
||||
public static async Task<Result> joinParty(this Player owner)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
// 1. 파티 정보
|
||||
var party_action = owner.getEntityAction<PersonalPartyAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(party_action, () => $"party_action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
result = await party_action.tryLoadParty();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
171
GameServer/Entity/Party/Helper/PartyHelper.cs
Normal file
171
GameServer/Entity/Party/Helper/PartyHelper.cs
Normal file
@@ -0,0 +1,171 @@
|
||||
using Nettention.Proud;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using USER_GUID = System.String;
|
||||
using PARTY_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class PartyHelper
|
||||
{
|
||||
public static void sendToClient(ClientToGame message, HostID target_client)
|
||||
{
|
||||
GameServerApp.getServerLogic().onSendPacketToHost(target_client, RmiContext.ReliableSend, message);
|
||||
}
|
||||
|
||||
public static void sendToClient(ClientToGame message, USER_GUID userGuid)
|
||||
{
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
if (!player_manager.tryGetUserByPrimaryKey(userGuid, out var player)) return;
|
||||
|
||||
sendToClient(message, player.getHostId());
|
||||
}
|
||||
|
||||
public static void BroadcastToClients(GlobalPartyDetail party, ClientToGame message, IReadOnlyList<USER_GUID> except_users)
|
||||
{
|
||||
var party_action = party.getEntityAction<GlobalPartyDetailAction>();
|
||||
ArgumentNullException.ThrowIfNull(party_action);
|
||||
|
||||
var party_member_attribute = party.getEntityAttribute<PartyMemberAttribute>();
|
||||
ArgumentNullException.ThrowIfNull(party_member_attribute);
|
||||
|
||||
var users = party_member_attribute.getPartyMembers().Select(member => member.Key).ToList();
|
||||
BroadcastToClients(users, message, except_users);
|
||||
}
|
||||
|
||||
public static void BroadcastToClients(IReadOnlyList<USER_GUID> target_users, ClientToGame message,
|
||||
IReadOnlyList<USER_GUID> except_users)
|
||||
{
|
||||
var target_clients = new List<HostID>();
|
||||
var player_manager = GameServerApp.getServerLogic().getPlayerManager();
|
||||
|
||||
foreach (var user in target_users)
|
||||
{
|
||||
if (except_users.Contains(user)) continue;
|
||||
if (!player_manager.tryGetUserByPrimaryKey(user, out var member)) continue;
|
||||
|
||||
target_clients.Add(member.getHostId());
|
||||
}
|
||||
|
||||
GameServerApp.getServerLogic().onSendPacketToHosts(target_clients.ToArray(), RmiContext.ReliableSend, message);
|
||||
}
|
||||
|
||||
public static void sendToServer(ServerMessage message, string dest_server)
|
||||
{
|
||||
var rabbit_mq = GameServerApp.getServerLogic().getRabbitMqConnector() as RabbitMqConnector;
|
||||
ArgumentNullException.ThrowIfNull(rabbit_mq);
|
||||
rabbit_mq.SendMessage(dest_server, message);
|
||||
}
|
||||
|
||||
public static async Task sendToServerByTargetClient(USER_GUID target_user_guid, ServerMessage message)
|
||||
{
|
||||
var login_cache = await getOtherUserLoginCache(target_user_guid);
|
||||
if (null == login_cache) return;
|
||||
|
||||
sendToServer(message, login_cache.CurrentServer);
|
||||
}
|
||||
|
||||
public static void BroadcastToServers(GlobalPartyDetail party, ServerMessage message, bool except_me)
|
||||
{
|
||||
var party_server_attribute = party.getEntityAttribute<PartyServerAttribute>();
|
||||
ArgumentNullException.ThrowIfNull(party_server_attribute);
|
||||
|
||||
BroadcastToServers(party_server_attribute.getPartyServers().ToList(), message, except_me);
|
||||
}
|
||||
|
||||
public static void BroadcastToServers(IReadOnlyList<PARTY_GUID> servers, ServerMessage message, bool except_me)
|
||||
{
|
||||
var rabbit_mq = GameServerApp.getServerLogic().getRabbitMqConnector() as RabbitMqConnector;
|
||||
ArgumentNullException.ThrowIfNull(rabbit_mq);
|
||||
|
||||
foreach (var server in servers)
|
||||
{
|
||||
if (except_me && server == GameServerApp.getServerLogic().getServerName()) continue;
|
||||
rabbit_mq.SendMessage(server, message);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<string?> getUserNicknameFromGuid(USER_GUID userGuid)
|
||||
{
|
||||
var find = await NicknameDoc.findNicknameFromGuid(userGuid);
|
||||
NullReferenceCheckHelper.throwIfNull(find);
|
||||
NullReferenceCheckHelper.throwIfNull(find.attrib, () => $"find.attrib is null !!!");
|
||||
return find.result.isFail() ? null : find.attrib.Nickname;
|
||||
}
|
||||
|
||||
public static LoginCacheRequest? getOwnUserLoginCacheRequest(Player player)
|
||||
{
|
||||
var game_login_action = player.getEntityAction<GameLoginAction>();
|
||||
var login_cache_request = game_login_action.getLoginCacheRequest();
|
||||
|
||||
return login_cache_request;
|
||||
}
|
||||
|
||||
public static async Task<LoginCache?> getOtherUserLoginCache(USER_GUID user_guid)
|
||||
{
|
||||
var login_cache_request =
|
||||
new LoginCacheOtherUserRequest(GameServerApp.getServerLogic(), GameServerApp.getServerLogic().getRedisConnector(), user_guid);
|
||||
var result = await login_cache_request.fetchLogin();
|
||||
|
||||
return result.isFail() ? null : login_cache_request.getLoginCache();
|
||||
}
|
||||
|
||||
public static async Task<LoginCache?> getOtherUserLoginCache(UserBase requester, USER_GUID user_guid)
|
||||
{
|
||||
var login_cache_request =
|
||||
new LoginCacheOtherUserRequest(requester, GameServerApp.getServerLogic().getRedisConnector(), user_guid);
|
||||
var result = await login_cache_request.fetchLogin();
|
||||
|
||||
return result.isFail() ? null : login_cache_request.getLoginCache();
|
||||
}
|
||||
|
||||
public static PartyMemberInfo makePartyMember(string user_guid, string nickname)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var user = new PartyMemberInfo();
|
||||
user.Summon = new();
|
||||
user.UserGuid = user_guid;
|
||||
user.Nickname = nickname;
|
||||
user.JoinTime = Timestamp.FromDateTime(DateTime.UtcNow);
|
||||
|
||||
if (false == server_logic.getPlayerManager().tryGetUserByPrimaryKey(user_guid, out var player))
|
||||
{
|
||||
user.LocationInfo = new UserLocationInfo();
|
||||
user.LocationInfo.Id = 0;
|
||||
user.LocationInfo.IsChannel = server_logic.getServerType().toServerType() == ServerType.Channel ? 1 : 0;
|
||||
user.LocationInfo.ChannelNumber = (1 == user.LocationInfo.IsChannel) ? (int)server_logic.getChannelNo() : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
user.LocationInfo = player.getUserLocationInfo();
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public static float calculateDistance(Pos standard, Pos target)
|
||||
{
|
||||
var from_vector = new System.Numerics.Vector3(standard.X, standard.Y, standard.Z);
|
||||
var to_vector = new System.Numerics.Vector3(target.X, target.Y, target.Z);
|
||||
|
||||
return Vector3Helper.distance(from_vector, to_vector);
|
||||
}
|
||||
|
||||
public static string getPartyGuidFromPartyInstanceRoomId(string roomId)
|
||||
{
|
||||
var split = roomId.Split(":");
|
||||
if (split.Length < 2) return string.Empty;
|
||||
|
||||
return split[1];
|
||||
}
|
||||
}
|
||||
258
GameServer/Entity/Player/Action/AbilityAction.cs
Normal file
258
GameServer/Entity/Player/Action/AbilityAction.cs
Normal file
@@ -0,0 +1,258 @@
|
||||
using MetaAssets;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class AbilityAction : EntityActionBase
|
||||
{
|
||||
private Dictionary<AttributeType, int> m_abilities { get; set; } = new();
|
||||
|
||||
public AbilityAction(EntityBase owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
clearAbility();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public void clearAbility()
|
||||
{
|
||||
foreach (var ability in EnumHelper.getValuesWithoutScope<AttributeType>())
|
||||
{
|
||||
m_abilities[ability] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int? getAbility(AttributeType abilityId) => m_abilities.TryGetValue(abilityId, out var ability) ? ability : null;
|
||||
|
||||
public Dictionary<AttributeType, int> getAbilities() => m_abilities;
|
||||
|
||||
public async Task<Result> forceResetAll()
|
||||
{
|
||||
clearAbility();
|
||||
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!! - {toBasicString()}");
|
||||
|
||||
|
||||
var inventory_action_base = owner.getEntityAction<InventoryActionBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(inventory_action_base, () => $"inventory_action_base is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = await inventory_action_base.tryResetAttributeByTattoo();
|
||||
if(result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var buff_action = owner.getEntityAction<BuffAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(buff_action, () => $"buff_action is null !!! - {owner.toBasicString()}");
|
||||
result = await buff_action.tryResetAttributeByBuff();
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void forceSetAbilityAll(int toSetAbility)
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!! - {toBasicString()}");
|
||||
|
||||
var attribute_types = EnumHelper.getValuesWithoutScopeAll<AttributeType>();
|
||||
foreach (var attribute_type in attribute_types)
|
||||
{
|
||||
m_abilities[attribute_type] = toSetAbility;
|
||||
}
|
||||
}
|
||||
|
||||
public void setAbility(AttributeType abilityId, int ability, bool decrease)
|
||||
{
|
||||
var change_value = decrease ? ability * -1 : ability;
|
||||
m_abilities[abilityId] += change_value;
|
||||
}
|
||||
|
||||
public async Task<Result> setAbilities(ItemBase item, Int16 level, bool decrease)
|
||||
{
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(item, () => $"item is null !!! - {toBasicString()}");
|
||||
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
var item_attribute = item.getEntityAttribute<ItemAttributeBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(item_attribute, () => $"item_attribute is null !!! - {toBasicString()}");
|
||||
|
||||
var item_meta = item.getItemMeta();
|
||||
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {toBasicString()}");
|
||||
var enchant = getEnchantData(level, item_meta);
|
||||
if (null == enchant)
|
||||
{
|
||||
err_msg = $"Fail to get enchant data : {nameof(getEnchantData)}";
|
||||
result.setFail(ServerErrorCode.ItemEnchantNotFoundInMeta, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 배열의 위치를 AttributeType으로 활용하다보니 불필요한 예외 처리 코드를 작성해야 한다. !!!
|
||||
// Key-Value 구조로 바꾸고 싶지만... 간단한 수정 범위는 아니다.
|
||||
// MetaHelper를 통해 메타 데이터를 가공하는 방법도 있다.... - kangms
|
||||
for(var i = 0; i < enchant.Count; i++)
|
||||
{
|
||||
if (false == EnumHelper.isDefined<AttributeType>(item_attribute.Attributes[i]))
|
||||
{
|
||||
Log.getLogger().warn($"Invalid Ability Enum Type : {item_attribute.Attributes[i]}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item_attribute.Attributes.Count <= i)
|
||||
{
|
||||
Log.getLogger().warn($"Ability Type outof range !!! : enchantIndex:{i} > itemAttributeIndex:{i}");
|
||||
item_attribute.Attributes.Add(0);
|
||||
}
|
||||
|
||||
setAbility((AttributeType)item_attribute.Attributes[i], enchant[i], decrease);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> changeAbilities(ItemBase item, Dictionary<int, int> slotWithAttributeIds, bool decrease)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(item, () => $"item is null !!! - {owner.toBasicString()}");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(slotWithAttributeIds, () => $"slotWithAttributeIds is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
var item_attribute = item.getEntityAttribute<ItemAttributeBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(item_attribute, () => $"item_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var item_meta = item.getItemMeta();
|
||||
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {owner.toBasicString()}");
|
||||
var enchant = getEnchantData(item_attribute.Level, item_meta);
|
||||
if (null == enchant)
|
||||
{
|
||||
err_msg = $"Fail to get enchant data : {nameof(getEnchantData)}";
|
||||
result.setFail(ServerErrorCode.ItemEnchantNotFoundInMeta, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var each in slotWithAttributeIds)
|
||||
{
|
||||
if (false == EnumHelper.isDefined<AttributeType>(each.Value))
|
||||
{
|
||||
Log.getLogger().warn($"Invalid Ability Enum Type : {each.Value}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 배열의 위치를 AttributeType으로 활용하다보니 불필요한 예외 처리 코드를 작성해야 한다. !!!
|
||||
// Key-Value 구조로 바꾸고 싶지만... MetaHelper를 통해 메타 데이터를 가공하는 방법도 있다.... - kangms
|
||||
if (each.Key >= enchant.Count)
|
||||
{
|
||||
Log.getLogger().warn($"Ability Type outof range !!! : enchantCount:{enchant.Count} > slotWithAttributeIndex:{each.Key}");
|
||||
continue;
|
||||
}
|
||||
|
||||
setAbility((AttributeType)each.Value, enchant[each.Key], decrease);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Result hasAbilities(Dictionary<string, Int32> toCheckAbilities)
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!! - {toBasicString()}");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(toCheckAbilities, () => $"toCheckAbilities is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var ability_action = owner.getEntityAction<AbilityAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ability_action, () => $"ability_action is null !!! - {toBasicString()}");
|
||||
|
||||
foreach (var each in toCheckAbilities)
|
||||
{
|
||||
var ability_name = each.Key;
|
||||
var ability_value = each.Value;
|
||||
|
||||
if (false == EnumHelper.tryParse<AttributeType>(ability_name, out var attribute_type))
|
||||
{
|
||||
err_msg = $"Invalid Ability Enum Type : {attribute_type} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ServerTypeInvalid, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
var curr_value = ability_action.getAbility(attribute_type);
|
||||
if (curr_value == null)
|
||||
{
|
||||
err_msg = $"Invalid Ability Enum Type : {attribute_type} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.ServerTypeInvalid, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (curr_value < ability_value)
|
||||
{
|
||||
err_msg = $"Not enough Ability !!! : AbilityName:{attribute_type}, currValue:{curr_value} >= reqValue:{ability_value} - {getOwner().toBasicString()}";
|
||||
result.setFail(ServerErrorCode.AbilityNotEnough, err_msg);
|
||||
Log.getLogger().info(err_msg);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private IReadOnlyList<int>? getEnchantData(int level, MetaAssets.ItemMetaData item)
|
||||
{
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(item, () => $"item is null !!! - {toBasicString()}");
|
||||
|
||||
if (false == MetaData.Instance._ItemLevelEnchantMetaTable.TryGetValue(level, out var enchant_by_level))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var enchant = enchant_by_level.GetConsumeItem(item.Rarity);
|
||||
return enchant?.AttributeValues;
|
||||
}
|
||||
|
||||
public AbilityInfo toAbilityInfo()
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ability_info = new AbilityInfo();
|
||||
foreach(var each in m_abilities)
|
||||
{
|
||||
ability_info.Values.Add((Int16)each.Key, each.Value);
|
||||
}
|
||||
|
||||
return ability_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
969
GameServer/Entity/Player/Action/PlayerAction.cs
Normal file
969
GameServer/Entity/Player/Action/PlayerAction.cs
Normal file
@@ -0,0 +1,969 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using NeoSmart.AsyncLock;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
|
||||
using static ClientToGameMessage.Types;
|
||||
using static ClientToGameReq.Types;
|
||||
using static ClientToGameRes.Types;
|
||||
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 UGC_NPC_META_GUID = System.String;
|
||||
using ITEM_GUID = System.String;
|
||||
using ANCHOR_GUID = System.String;
|
||||
using UGC_NPC_NICKNAME = System.String;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class PlayerAction : EntityActionBase
|
||||
{
|
||||
private ConcurrentDictionary<CHARACTER_GUID, Character> m_characters = new();
|
||||
private AsyncLock m_characters_lock = new();
|
||||
|
||||
private Character? m_selected_character_nullable = null;
|
||||
|
||||
private ConcurrentDictionary<UGC_NPC_META_GUID, UgcNpc> m_ugc_npcs = new();
|
||||
private AsyncLock m_ugc_npc_lock = new();
|
||||
|
||||
public PlayerAction(Player owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
m_characters.Clear();
|
||||
|
||||
m_selected_character_nullable = null;
|
||||
}
|
||||
|
||||
public async Task<Result> commitTransaction(TransactionIdType toCommitTransactionIdType)
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var found_transaction_runner = owner.findTransactionRunner(toCommitTransactionIdType);
|
||||
if(null == found_transaction_runner)
|
||||
{
|
||||
err_msg = $"Not found TransactionRunner !!! : transactionIdType:{toCommitTransactionIdType} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.TransactionRunnerNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
result = await found_transaction_runner.onCommitResults();
|
||||
if(result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public UgcNpc? findUgcNpc(UGC_NPC_META_GUID ugcNpcMetaGuid)
|
||||
{
|
||||
m_ugc_npcs.TryGetValue(ugcNpcMetaGuid, out var found_ugc_npc);
|
||||
return found_ugc_npc;
|
||||
}
|
||||
|
||||
public UgcNpc? findUgcNpcByNickname(UGC_NPC_NICKNAME ugcNpcNickname)
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
foreach (var each in m_ugc_npcs)
|
||||
{
|
||||
var ugc_npc = each.Value;
|
||||
|
||||
var ugc_npc_attribute = ugc_npc.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
if(ugc_npc_attribute.Nickname.ToLower() == ugcNpcNickname.ToLower())
|
||||
{
|
||||
return ugc_npc;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Result fillupOwnerEntities(OwnerEntityType ownerEntityType, ref Dictionary<string, EntityBase> foundOwnerEntities)
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(foundOwnerEntities, () => $"foundOwnerEntities is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var user_attribute = owner.getEntityAttribute<UserAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_attribute, () => $"user_attribute is null !!! - {toBasicString()}");
|
||||
|
||||
var user_guid = user_attribute.UserGuid;
|
||||
|
||||
if (OwnerEntityType.User == ownerEntityType)
|
||||
{
|
||||
if (false == foundOwnerEntities.TryAdd(user_guid, owner))
|
||||
{
|
||||
err_msg = $"Already added UserGuid !!! : userGuid:{user_guid} - {toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UserGuidAlreadyAdded, err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (OwnerEntityType.UgcNpc == ownerEntityType)
|
||||
{
|
||||
foreach (var each in m_ugc_npcs)
|
||||
{
|
||||
var ugc_npc_meta_guid = each.Key;
|
||||
var ugc_npc = each.Value;
|
||||
|
||||
if(false == foundOwnerEntities.TryAdd(ugc_npc_meta_guid, ugc_npc))
|
||||
{
|
||||
err_msg = $"Already added UgcNpcMetaGuid !!! : ugcNpcMetaGuid:{ugc_npc_meta_guid} - {toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcMetaGuidAlreadyAdded, err_msg);
|
||||
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (OwnerEntityType.Myhome == ownerEntityType)
|
||||
{
|
||||
var myhome_agent_action = owner.getEntityAction<MyhomeAgentAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(myhome_agent_action, () => $"myhome_agent_action is null !!! - {toBasicString()}");
|
||||
|
||||
var myhomes = myhome_agent_action.getMyHomes();
|
||||
foreach (var myhome in myhomes)
|
||||
{
|
||||
var myhome_attribute = myhome.getEntityAttribute<MyhomeAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(myhome_attribute, () => $"myhome_attribute is null !!! - {toBasicString()}");
|
||||
|
||||
var myhome_guid = myhome_attribute.MyhomeGuid;
|
||||
|
||||
if (false == foundOwnerEntities.TryAdd(myhome_guid, myhome))
|
||||
{
|
||||
err_msg = $"Already added MyhomeGuid !!! : myhomeGuid:{myhome_guid} - {toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcMetaGuidAlreadyAdded, err_msg);
|
||||
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err_msg = $"Can't fillup OwnerEntity !!!, Invalid OwnerEntityType : ownerEntityType:{ownerEntityType} - {toBasicString()}";
|
||||
result.setFail(ServerErrorCode.OwnerEntityCannotFillup, err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> tryLoadUgcNpc(UgcNpc toLoadUgcNpc, UgcNpcDoc ugcNpcDoc)
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(ugcNpcDoc, () => $"ugcNpcDoc is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var doc_ugc_npc_attrib = ugcNpcDoc.getAttrib<UgcNpcAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(doc_ugc_npc_attrib, () => $"doc_ugc_npc_attrib is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var ugc_npc_meta_guid = doc_ugc_npc_attrib.UgcNpcMetaGuid;
|
||||
|
||||
using (m_ugc_npc_lock.Lock())
|
||||
{
|
||||
var found_duplicated_ugc_npc = findUgcNpc(ugc_npc_meta_guid);
|
||||
if (null != found_duplicated_ugc_npc)
|
||||
{
|
||||
err_msg = $"Found duplicated UgcNpc from UgcNpcDoc !!! : duplicatedUgcNpc:{found_duplicated_ugc_npc.toBasicString()} - {ugcNpcDoc.toBasicString()}, {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcDocLoadDuplicatedUgcNpc, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
var ugc_npc_action = toLoadUgcNpc.getEntityAction<UgcNpcAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
result = await ugc_npc_action.createByUgcNpcDocWithMaster(ugcNpcDoc, owner);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (false == m_ugc_npcs.TryAdd(ugc_npc_meta_guid, toLoadUgcNpc))
|
||||
{
|
||||
err_msg = $"Failed to TryAdd() !!! : {toLoadUgcNpc.toBasicString()} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcDocLoadDuplicatedUgcNpc, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
owner.attachSummenedEntityGuid(ugc_npc_meta_guid);
|
||||
toLoadUgcNpc.attachMasterGuid(owner.getUserGuid());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> tryAttachUgcNpcInGameZone(UgcNpc toAttachUgcNpcInGameZone)
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(toAttachUgcNpcInGameZone, () => $"toAttachUgcNpcInGameZone is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var ugc_npc_attribute = toAttachUgcNpcInGameZone.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var ugc_npc_meta_guid = ugc_npc_attribute.UgcNpcMetaGuid;
|
||||
|
||||
using (m_ugc_npc_lock.Lock())
|
||||
{
|
||||
if (false == m_ugc_npcs.TryAdd(ugc_npc_meta_guid, toAttachUgcNpcInGameZone))
|
||||
{
|
||||
err_msg = $"Failed to TryAdd() !!! : {toAttachUgcNpcInGameZone.toBasicString()} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcDocLoadDuplicatedUgcNpc, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
owner.attachSummenedEntityGuid(ugc_npc_meta_guid);
|
||||
toAttachUgcNpcInGameZone.attachMasterGuid(owner.getUserGuid());
|
||||
}
|
||||
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
public async Task<(Result, UgcNpc?, NpcLocationInTargetDoc?)> tryLocateUgcNpcToMyhome(string myhomeGuid, int myhomeInstanceMetaId, NpcLocation npcLocation, UGC_NPC_META_GUID selectedUgcNpcMetaGuid)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"owner is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {player.toBasicString()}");
|
||||
|
||||
var dynamo_db_client = server_logic.getDynamoDbClient();
|
||||
NullReferenceCheckHelper.throwIfNull(dynamo_db_client, () => $"dynamo_db_client is null !!! - {player.toBasicString()}");
|
||||
|
||||
//예외 체크 !!!
|
||||
//1. 해당 UgcNpc의 사용 상태를 체크 한다.
|
||||
var located_ugc_npc = findUgcNpc(selectedUgcNpcMetaGuid);
|
||||
if (located_ugc_npc == null)
|
||||
{
|
||||
err_msg = $"UgcNpc Not Found UgcNpc Guid : {selectedUgcNpcMetaGuid} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var ugc_npc_attribute = located_ugc_npc.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!!");
|
||||
if (ugc_npc_attribute.State != EntityStateType.None)
|
||||
{
|
||||
err_msg = $"UgcNpc is Busy : UgcNpcGuid{selectedUgcNpcMetaGuid} - {located_ugc_npc.toBasicString()}, {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.NpcIsBusy, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
ugc_npc_attribute.LocatedInstanceGuid = myhomeGuid;
|
||||
ugc_npc_attribute.LocatedInstanceMetaId = (META_ID)myhomeInstanceMetaId;
|
||||
|
||||
var game_zone_action = player.getEntityAction<GameZoneAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var curr_map = game_zone_action.getLinkedToMap();
|
||||
NullReferenceCheckHelper.throwIfNull(curr_map, () => $"curr_map is null !!! - {player.toBasicString()}");
|
||||
|
||||
var ugc_npc_action = located_ugc_npc.getEntityAction<UgcNpcAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
ugc_npc_action.modifyStateInfo(EntityStateType.UsingByMyHome, npcLocation.CurrentPos, npcLocation.AnchorMetaGuid);
|
||||
|
||||
var location_unique_id = curr_map.makeLOCATION_UNIQUE_IDByMetaIdWithLocationTargetType(LocationTargetType.Instance, myhomeGuid);
|
||||
|
||||
//2. NpcLocationInTargetDoc를 신규 등록 설정 한다.
|
||||
var npc_location_in_target_doc = new NpcLocationInTargetDoc( location_unique_id, npcLocation.AnchorMetaGuid
|
||||
, EntityType.UgcNpc, ugc_npc_attribute.UgcNpcMetaGuid, npcLocation
|
||||
, ugc_npc_attribute.OwnerEntityType, ugc_npc_attribute.OwnerGuid );
|
||||
|
||||
result = await dynamo_db_client.simpleUpsertDocumentWithDocType(npc_location_in_target_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleUpsertDocumentWithDocType() !!! : {npc_location_in_target_doc.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
return (result, located_ugc_npc, npc_location_in_target_doc);
|
||||
}
|
||||
|
||||
public async Task<(Result, UgcNpc?, NpcLocationInTargetDoc?)> tryReleaseUgcNpcFromMyhome(string myhomeGuid, string anchorGuid, string ugcNpcGuid)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"owner is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {player.toBasicString()}");
|
||||
|
||||
var dynamo_db_client = server_logic.getDynamoDbClient();
|
||||
NullReferenceCheckHelper.throwIfNull(dynamo_db_client, () => $"dynamo_db_client is null !!! - {player.toBasicString()}");
|
||||
|
||||
var game_zone_action = player.getEntityAction<GameZoneAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var curr_map = game_zone_action.getLinkedToMap();
|
||||
NullReferenceCheckHelper.throwIfNull(curr_map, () => $"curr_map is null !!! - {player.toBasicString()}");
|
||||
|
||||
var ugc_npc = findUgcNpc(ugcNpcGuid);
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!! - {player.toBasicString()}");
|
||||
|
||||
var ugc_npc_action = ugc_npc.getEntityAction<UgcNpcAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
ugc_npc_action.modifyStateInfo(EntityStateType.None, new EntityPos(), "");
|
||||
|
||||
var ugc_npc_attribute = ugc_npc.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
ugc_npc_attribute.LocatedInstanceGuid = string.Empty;
|
||||
ugc_npc_attribute.LocatedInstanceMetaId = 0;
|
||||
|
||||
var location_unique_id = curr_map.makeLOCATION_UNIQUE_IDByMetaIdWithLocationTargetType(LocationTargetType.Instance, myhomeGuid);
|
||||
|
||||
var npc_location_in_target_doc = new NpcLocationInTargetDoc(location_unique_id, anchorGuid);
|
||||
|
||||
result = await dynamo_db_client.simpleDeleteDocumentWithDocType(npc_location_in_target_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleDeleteDocumentWithDocType() !!! : {npc_location_in_target_doc.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
return (result, ugc_npc, npc_location_in_target_doc);
|
||||
}
|
||||
|
||||
public async Task<(Result, UgcNpc?, NpcLocationInTargetDoc?)> tryModifyUgcNpcToMyhome(string myhomeGuid, NpcLocation npcLocation, UGC_NPC_META_GUID selectedUgcNpcMetaGuid, EntityStateType ugcNpcState, META_ID metaId = 0)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"owner is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {player.toBasicString()}");
|
||||
|
||||
var dynamo_db_client = server_logic.getDynamoDbClient();
|
||||
NullReferenceCheckHelper.throwIfNull(dynamo_db_client, () => $"dynamo_db_client is null !!! - {player.toBasicString()}");
|
||||
|
||||
var located_ugc_npc = findUgcNpc(selectedUgcNpcMetaGuid);
|
||||
if (located_ugc_npc == null)
|
||||
{
|
||||
err_msg = $"UgcNpc Not Found UgcNpc Guid : {selectedUgcNpcMetaGuid} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var ugc_npc_attribute = located_ugc_npc.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {player.toBasicString()}");
|
||||
if (ugc_npc_attribute.AnchorMetaGuid != npcLocation.AnchorMetaGuid)
|
||||
{
|
||||
err_msg = $"AnchorMetaGuid is not Match : UgcNpcGuid{selectedUgcNpcMetaGuid} - {located_ugc_npc.toBasicString()}, {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.AnchorIsNotInMyhome, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
var game_zone_action = player.getEntityAction<GameZoneAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var curr_map = game_zone_action.getLinkedToMap();
|
||||
NullReferenceCheckHelper.throwIfNull(curr_map, () => $"curr_map is null !!! - {player.toBasicString()}");
|
||||
|
||||
var ugc_npc_action = located_ugc_npc.getEntityAction<UgcNpcAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
ugc_npc_action.modifyStateInfo(ugcNpcState, npcLocation.CurrentPos, npcLocation.AnchorMetaGuid, metaId);
|
||||
|
||||
var location_unique_id = curr_map.makeLOCATION_UNIQUE_IDByMetaIdWithLocationTargetType(LocationTargetType.Instance, myhomeGuid);
|
||||
|
||||
var npc_location_in_target_doc = new NpcLocationInTargetDoc(location_unique_id, npcLocation.AnchorMetaGuid
|
||||
, EntityType.UgcNpc, ugc_npc_attribute.UgcNpcMetaGuid, npcLocation
|
||||
, ugc_npc_attribute.OwnerEntityType, ugc_npc_attribute.OwnerGuid);
|
||||
|
||||
result = await dynamo_db_client.simpleUpsertDocumentWithDocType(npc_location_in_target_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to simpleUpsertDocumentWithDocType() !!! : {npc_location_in_target_doc.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return (result, null, null);
|
||||
}
|
||||
|
||||
return (result, located_ugc_npc, npc_location_in_target_doc);
|
||||
}
|
||||
|
||||
public async Task<Result> tryDeleteUgcNpc(string toDeleteUgcNpcNickname)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var fn_ugc_npc_delete = async delegate ()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
UGC_NPC_META_GUID found_ugc_npc_meta_guid = string.Empty;
|
||||
UgcNpc? to_delete_ugc_npc_nullable = null;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {owner.toBasicString()}");
|
||||
|
||||
foreach (var each in m_ugc_npcs)
|
||||
{
|
||||
var ugc_npc_meta_guid = each.Key;
|
||||
var ugc_npc = each.Value;
|
||||
|
||||
var ugc_npc_action = ugc_npc.getEntityAction<UgcNpcAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
if(false == ugc_npc_action.isEqualUgcNpc(toDeleteUgcNpcNickname))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
found_ugc_npc_meta_guid = ugc_npc_meta_guid;
|
||||
|
||||
if (true == ugc_npc_action.isLocatedUgcNpc())
|
||||
{
|
||||
err_msg = $"UgcNpc located state !!! : {ugc_npc.toSummaryString()} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcLocatedState, err_msg);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
(result, _) = await ugc_npc_action.tryDelete();
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
to_delete_ugc_npc_nullable = ugc_npc;
|
||||
break;
|
||||
}
|
||||
|
||||
if (null == to_delete_ugc_npc_nullable)
|
||||
{
|
||||
err_msg = $"Not found UgcNpc !!! : ugcNpcNickname:{toDeleteUgcNpcNickname} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
|
||||
Log.getLogger().warn(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>( owner, LogActionType.ItemUse
|
||||
, server_logic.getDynamoDbClient()
|
||||
, true);
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
batch.addQuery(new QueryFinal(), async (_query) =>
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var is_success = m_ugc_npcs.TryRemove(found_ugc_npc_meta_guid, out _);
|
||||
if(false == is_success)
|
||||
{
|
||||
err_msg = $"Failed to TryRemove() !!! : {to_delete_ugc_npc_nullable.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
var found_transaction_runner = owner.findTransactionRunner(TransactionIdType.PrivateContents);
|
||||
NullReferenceCheckHelper.throwIfNull(found_transaction_runner, () => $"found_transaction_runner is null !!! - {owner.toBasicString()}");
|
||||
|
||||
UgcNpcNotifyHelper.send_GS2C_NTF_UGC_NPC_DELETION(owner, found_ugc_npc_meta_guid, found_transaction_runner.getCommonResult());
|
||||
|
||||
return QueryBatchBase.QueryResultType.Success;
|
||||
});
|
||||
}
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
result = await owner.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "UgcNpcDeletion", fn_ugc_npc_delete);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> trySellUgcNpc(UGC_NPC_META_GUID toSellUgcNpcMetaGuid)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var found_ugc_npc = findUgcNpc(toSellUgcNpcMetaGuid);
|
||||
if(null == found_ugc_npc)
|
||||
{
|
||||
err_msg = $"Not found UgcNpc !!! : ugcNpcMetaGuid:{toSellUgcNpcMetaGuid} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
|
||||
Log.getLogger().warn(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var ugc_npc_action = found_ugc_npc.getEntityAction<UgcNpcAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
if (true == ugc_npc_action.isLocatedUgcNpc())
|
||||
{
|
||||
err_msg = $"UgcNpc located state !!! : {found_ugc_npc.toSummaryString()} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcLocatedState, err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var ugc_npc_attribute = found_ugc_npc.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
if (false == MetaData.Instance.Meta.BeaconNpcMetaTable.BeaconNpcMetaDataListbyId.TryGetValue((Int32)ugc_npc_attribute.BodyItemMetaId, out var found_beacon_npc_meta))
|
||||
{
|
||||
err_msg = $"Not found BeaconNpcMetaData !!! : bodyItemMetaId:{ugc_npc_attribute.BodyItemMetaId} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcMetaDataNotFound, err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var check_item = ShopHelper.checkItemIdFromTableData(found_beacon_npc_meta.BeaconItemID);
|
||||
if (check_item.result.isFail() || null == check_item.item_data)
|
||||
{
|
||||
Log.getLogger().error(check_item.result.ResultString);
|
||||
|
||||
return check_item.result;
|
||||
}
|
||||
|
||||
var money_action = owner.getEntityAction<MoneyAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(money_action);
|
||||
|
||||
var check_currency_type = ShopHelper.checkCurrencyTypeFromCurrencyId(check_item.item_data.SellId);
|
||||
if (check_currency_type.result.isFail())
|
||||
{
|
||||
return check_currency_type.result;
|
||||
}
|
||||
|
||||
result = await money_action.earnMoney(check_currency_type.currencyType, check_item.item_data.SellPrice);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
(result, _) = await ugc_npc_action.tryDelete();
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(Result, FarmingAction?)> selectFarmingAction(FarmingSummonedEntityType entityType, OWNER_GUID ownerGuid)
|
||||
{
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
FarmingAction? seleted_farming_action = null;
|
||||
|
||||
switch (entityType)
|
||||
{
|
||||
case FarmingSummonedEntityType.User:
|
||||
{
|
||||
if(player.getUserGuid() == ownerGuid)
|
||||
{
|
||||
seleted_farming_action = player.getEntityAction<FarmingAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(seleted_farming_action, () => $"seleted_farming_action is null !!! - {player.toBasicString()}");
|
||||
}
|
||||
} break;
|
||||
|
||||
case FarmingSummonedEntityType.Beacon:
|
||||
{
|
||||
var player_action = player.getEntityAction<PlayerAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var found_ugc_npc = player_action.findUgcNpc(ownerGuid);
|
||||
if(null == found_ugc_npc)
|
||||
{
|
||||
err_msg = $"Not found UgcNpc !!! : ugcNpcGuid:{ownerGuid} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
|
||||
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
seleted_farming_action = found_ugc_npc.getEntityAction<FarmingAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(seleted_farming_action, () => $"seleted_farming_action is null !!! - {player.toBasicString()}");
|
||||
} break;
|
||||
|
||||
default:
|
||||
err_msg = $"Invalid FarmingSummonedEntityType !!! : FarmingSummonedEntityType:{entityType} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.FarmingSummonedEntityTypeInvalid, err_msg);
|
||||
return (result, null);
|
||||
|
||||
}
|
||||
|
||||
return await Task.FromResult<(Result, FarmingAction?)>((result, seleted_farming_action));
|
||||
}
|
||||
|
||||
public async Task<Result> tryLoadCharacter(Character toLoadCharacter, CharacterBaseDoc characterBaseDoc)
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(characterBaseDoc, () => $"characterBaseDoc is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var character_base_doc_attrib = characterBaseDoc.getAttrib<CharacterBaseAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_base_doc_attrib, () => $"character_base_doc_attrib is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var character_guid = character_base_doc_attrib.CharacterGuid;
|
||||
|
||||
using (m_characters_lock.Lock())
|
||||
{
|
||||
var found_duplicated_character = findCharacter(character_guid);
|
||||
if (null != found_duplicated_character)
|
||||
{
|
||||
err_msg = $"Found duplicated Character from CharacterBaseDoc !!! : duplicatedItem:{found_duplicated_character.toBasicString()} - {characterBaseDoc.toBasicString()}, {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.CharacterBaseDocLoadDuplicatedCharacter, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
result = await toLoadCharacter.createByCharacterBaseDoc(characterBaseDoc);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (false == m_characters.TryAdd(character_guid, toLoadCharacter))
|
||||
{
|
||||
err_msg = $"Failed to TryAdd() !!! : {toLoadCharacter.toBasicString()} - {owner.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.CharacterBaseDocLoadDuplicatedCharacter, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
var user_attribute = owner.getEntityAttribute<UserAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_attribute, () => $"user_attribute is null !!! - {owner.toBasicString()}");
|
||||
|
||||
if (user_attribute.SelectedCharacterGuid == character_guid)
|
||||
{
|
||||
setSelectedCharacter(toLoadCharacter);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Character? findCharacter(CHARACTER_GUID characterGuid)
|
||||
{
|
||||
if(false == m_characters.TryGetValue(characterGuid, out var found_character))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return found_character;
|
||||
}
|
||||
|
||||
public Int32 getHadUgcNpcCount()
|
||||
{
|
||||
return m_ugc_npcs.Count();
|
||||
}
|
||||
|
||||
public ConcurrentDictionary<UGC_NPC_META_GUID, UgcNpc> getHadUgcNpcs()
|
||||
{
|
||||
return m_ugc_npcs;
|
||||
}
|
||||
|
||||
public bool hasSelectedCharacter() { return 0 < m_characters.Count; }
|
||||
|
||||
public Character? getSelectedCharacter() { return m_selected_character_nullable; }
|
||||
|
||||
public void setSelectedCharacter(Character character) { m_selected_character_nullable = character; }
|
||||
|
||||
|
||||
public GameCharacter toSelectedPlayerInfo()
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"owner is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var user_craete_or_load_action = owner.getEntityAction<UserCreateOrLoadAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_craete_or_load_action, () => $"user_craete_or_load_action is null !!! - {owner.toBasicString()}");
|
||||
|
||||
var character_info = new GameCharacter();
|
||||
|
||||
try
|
||||
{
|
||||
var account_attribute = owner.getEntityAttribute<AccountAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(account_attribute);
|
||||
|
||||
character_info.CharInfo = new();
|
||||
character_info.CharInfo.LanguageInfo = (Int32)account_attribute.LanguageType;
|
||||
character_info.CharInfo.Usergroup = account_attribute.AuthAdminLevelType.ToString();
|
||||
character_info.CharInfo.Operator = (Int32)account_attribute.AuthAdminLevelType;
|
||||
|
||||
var channel_no = server_logic.getChannelNo();
|
||||
var connected_count = server_logic.getProudNetListener().getEntityWithSessions().Count();
|
||||
var reserved_count = server_logic.getReservationManager().getReservedUserCount();
|
||||
var return_count = server_logic.getReturnManager().getReturnUserCount();
|
||||
|
||||
character_info.ChannelInfo = new();
|
||||
character_info.ChannelInfo.Channel = (Int32)channel_no;
|
||||
character_info.ChannelInfo.Trafficlevel = server_logic.getChannelManager().getTrafficLevel( connected_count + reserved_count + return_count + UgcNpcCountManager.Instance.calculateNpcCount()
|
||||
, server_logic.getProudNetListener().getMaxConnectionCount() );
|
||||
|
||||
var user_attribute = owner.getEntityAttribute<UserAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_attribute);
|
||||
character_info.CharInfo.IsIntroComplete = user_attribute.IsIntroCompleted == true ? 1 : 0;
|
||||
|
||||
if (false == user_craete_or_load_action.hasUserCreateTrigger())
|
||||
{
|
||||
var nickname_attribute = owner.getEntityAttribute<NicknameAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(nickname_attribute);
|
||||
character_info.CharInfo.DisplayName = nickname_attribute.Nickname;
|
||||
|
||||
var level_attribute = owner.getEntityAttribute<LevelAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(level_attribute);
|
||||
character_info.CharInfo.Level = (Int32)level_attribute.Level;
|
||||
character_info.CharInfo.Exp = (Int32)level_attribute.Exp;
|
||||
|
||||
var money_attribute = owner.getEntityAttribute<MoneyAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(money_attribute);
|
||||
character_info.CharInfo.Gold = money_attribute.Gold;
|
||||
character_info.CharInfo.Sapphire = money_attribute.Sapphire;
|
||||
character_info.CharInfo.Calium = money_attribute.Calium;
|
||||
character_info.CharInfo.Ruby = money_attribute.Ruby;
|
||||
|
||||
character_info.CharPos = new();
|
||||
var location_action = owner.getEntityAction<LocationAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(location_action);
|
||||
character_info.CharPos.Pos = location_action.getCurrentPos();
|
||||
character_info.CharPos.MapId = location_action.getCurrentMapMId();
|
||||
|
||||
var inventory_action = owner.getEntityAction<InventoryActionBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(inventory_action);
|
||||
character_info.Inventory = inventory_action.toBagInven4Client();
|
||||
character_info.ClothInfo = inventory_action.toClothInven4Client();
|
||||
character_info.ToolSlot.AddRange(inventory_action.toToolSlotInven4Client());
|
||||
character_info.TattooInfoList.AddRange(inventory_action.toTattooSimple4Client());
|
||||
character_info.SlotCount.AddRange(inventory_action.toSlotMaxCountOfBagAll4Client());
|
||||
|
||||
var item_tool_action = owner.getEntityAction<ItemToolAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(item_tool_action, () => $"item_tool_action is null !!! - {owner.toBasicString()}");
|
||||
character_info.EquipInfo = item_tool_action.toToolAction4Client();
|
||||
}
|
||||
else
|
||||
{
|
||||
user_craete_or_load_action.fillUpUserInfo4Client(character_info.CharInfo);
|
||||
|
||||
character_info.CharPos = new();
|
||||
var location_action = owner.getEntityAction<LocationAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(location_action);
|
||||
character_info.CharPos.Pos = location_action.getCurrentPos();
|
||||
|
||||
var inventory_action = owner.getEntityAction<InventoryActionBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(inventory_action);
|
||||
character_info.ToolSlot.AddRange(inventory_action.toToolSlotInven4Client());
|
||||
character_info.TattooInfoList.AddRange(inventory_action.toTattooSimple4Client());
|
||||
character_info.SlotCount.AddRange(inventory_action.toSlotMaxCountOfBagAll4Client());
|
||||
}
|
||||
|
||||
if (true == user_craete_or_load_action.hasCharacterCreateTrigger())
|
||||
{
|
||||
var reserved_character = user_craete_or_load_action.getReservedCharacterForCreation();
|
||||
NullReferenceCheckHelper.throwIfNull(reserved_character);
|
||||
var character_attribute = reserved_character.getEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute);
|
||||
|
||||
character_info.Guid = owner.getUserGuid(); // 클라이언트는 USER_GUID를 사용 한다.
|
||||
character_info.AvatarInfo = user_craete_or_load_action.toSelectedCharacterAppearanceProfile4Client();
|
||||
}
|
||||
|
||||
{
|
||||
var selected_character = getSelectedCharacter();
|
||||
if (null != selected_character)
|
||||
{
|
||||
var character_attribute = selected_character.getEntityAttribute<CharacterAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(character_attribute);
|
||||
|
||||
character_info.Guid = owner.getUserGuid(); // 클라이언트는 USER_GUID를 사용 한다.
|
||||
character_info.AvatarInfo = character_attribute.AppearanceProfileValue.toCharacterAppearanceProfile4Client();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
var err_msg = $"Exception !!!, Failed to perfom in toSelectedPlayerInfo() !!! : exception:{e} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return character_info;
|
||||
}
|
||||
|
||||
public Dictionary<UGC_NPC_META_GUID, UgcNpcSummary> toUgcNpcSummaryAll4Client()
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_summaries = new Dictionary<UGC_NPC_META_GUID, UgcNpcSummary>();
|
||||
|
||||
foreach (var each in m_ugc_npcs)
|
||||
{
|
||||
var ugc_npc_meta_guid = each.Key;
|
||||
var ugc_npc = each.Value;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!! : ugcNpcMetaGuid:{ugc_npc_meta_guid} - {owner.toBasicString()}");
|
||||
|
||||
var ugc_npc_action = ugc_npc.getEntityAction<UgcNpcAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {ugc_npc.toBasicString()}, {owner.toBasicString()}");
|
||||
|
||||
if (false == ugc_npc_summaries.TryAdd(ugc_npc_meta_guid, ugc_npc_action.toUgcNpcSummary()))
|
||||
{
|
||||
var err_msg = $"Already added UgcNpc !!! : ugcNpcMetaGuid:{ugc_npc_meta_guid} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return ugc_npc_summaries;
|
||||
}
|
||||
|
||||
public Dictionary<UGC_NPC_META_GUID, UgcNpcItems> toUgcNpcItemsAll4Client()
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var ugc_npc_items = new Dictionary<UGC_NPC_META_GUID, UgcNpcItems>();
|
||||
|
||||
foreach (var each in m_ugc_npcs)
|
||||
{
|
||||
var ugc_npc_meta_guid = each.Key;
|
||||
var ugc_npc = each.Value;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(ugc_npc, () => $"ugc_npc is null !!! : ugcNpcMetaGuid:{ugc_npc_meta_guid} - {owner.toBasicString()}");
|
||||
|
||||
var ugc_npc_action = ugc_npc.getEntityAction<UgcNpcAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {ugc_npc.toBasicString()}, {owner.toBasicString()}");
|
||||
|
||||
if (false == ugc_npc_items.TryAdd(ugc_npc_meta_guid, ugc_npc_action.toUgcNpcItems()))
|
||||
{
|
||||
var err_msg = $"Already added UgcNpcItems !!! : ugcNpcMetaGuid:{ugc_npc_meta_guid} - {owner.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return ugc_npc_items;
|
||||
}
|
||||
|
||||
public async Task<Result> tryRegisterFailedNpcToAiChatServer()
|
||||
{
|
||||
var owner = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
|
||||
|
||||
var result = new Result();
|
||||
|
||||
foreach (var each in m_ugc_npcs)
|
||||
{
|
||||
var ugc_npc_attribute = each.Value.getEntityAttribute<UgcNpcAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute);
|
||||
|
||||
if(ugc_npc_attribute.IsRegisteredAiChatServer == true) continue;
|
||||
|
||||
var ugc_npc_action = each.Value.getEntityAction<UgcNpcAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(ugc_npc_action);
|
||||
|
||||
result = await ugc_npc_action.tryRegisterCharacterWithAiChatServer(owner);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
445
GameServer/Entity/Player/Helper/PlayerHelper.cs
Normal file
445
GameServer/Entity/Player/Helper/PlayerHelper.cs
Normal file
@@ -0,0 +1,445 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using Amazon.DynamoDBv2.Model;
|
||||
using Org.BouncyCastle.Tls.Crypto.Impl.BC;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
using UGQDatabase.Models;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using META_ID = System.UInt32;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
internal static class PlayerHelper
|
||||
{
|
||||
public static GameActor toGameActor(this Player player)
|
||||
{
|
||||
var user_create_or_load_action = player.getEntityAction<UserCreateOrLoadAction>();
|
||||
ArgumentNullException.ThrowIfNull(user_create_or_load_action);
|
||||
|
||||
var player_action = player.getEntityAction<PlayerAction>();
|
||||
ArgumentNullException.ThrowIfNull(player_action);
|
||||
|
||||
var inventory_action = player.getEntityAction<InventoryActionBase>();
|
||||
ArgumentNullException.ThrowIfNull(inventory_action);
|
||||
|
||||
var cloth_info = inventory_action.toClothInven4Client();
|
||||
NullReferenceCheckHelper.throwIfNull(cloth_info, () => $"cloth_info is null !!!");
|
||||
|
||||
var location_action = player.getEntityAction<LocationAction>();
|
||||
ArgumentNullException.ThrowIfNull(location_action);
|
||||
|
||||
var pos = location_action.getCurrentPos();
|
||||
|
||||
var buff_attribute = player.getOriginEntityAttribute<BuffAttribute>();
|
||||
ArgumentNullException.ThrowIfNull(buff_attribute);
|
||||
|
||||
var account_attribute = player.getOriginEntityAttribute<AccountAttribute>();
|
||||
ArgumentNullException.ThrowIfNull(account_attribute);
|
||||
|
||||
var user_attribute = player.getEntityAttribute<UserAttribute>();
|
||||
ArgumentNullException.ThrowIfNull(user_attribute);
|
||||
|
||||
var item_tool_action = player.getEntityAction<ItemToolAction>();
|
||||
ArgumentNullException.ThrowIfNull(item_tool_action);
|
||||
|
||||
GameActor game_actor = new();
|
||||
|
||||
game_actor.ActorGuid = player.getUserGuid();
|
||||
game_actor.Name = player.getAccountId();
|
||||
|
||||
|
||||
var selected_character = player_action.getSelectedCharacter();
|
||||
if (null != selected_character)
|
||||
{
|
||||
var character_attribute = selected_character.getEntityAttribute<CharacterAttribute>();
|
||||
ArgumentNullException.ThrowIfNull(character_attribute, $"character_attribute is null !!!");
|
||||
|
||||
game_actor.EntityStateInfo = character_attribute.StateInfo;
|
||||
game_actor.AvatarInfo = selected_character.getOriginAppearanceProfile().toCharacterAppearanceProfile4Client();
|
||||
}
|
||||
else
|
||||
{
|
||||
game_actor.AvatarInfo = user_create_or_load_action.toSelectedCharacterAppearanceProfile4Client();
|
||||
}
|
||||
|
||||
game_actor.ClothInfo = cloth_info.toClothInfoOfAnotherUser();
|
||||
game_actor.Pos = pos;
|
||||
game_actor.TattooInfoList.AddRange(inventory_action.toTattooInven4Client());
|
||||
game_actor.BuffInfo = new();
|
||||
game_actor.BuffInfo.Buff.AddRange(buff_attribute.toBuffData4Client());
|
||||
game_actor.Usergroup = account_attribute.AuthAdminLevelType.ToString();
|
||||
game_actor.Operator = (int)account_attribute.AuthAdminLevelType;
|
||||
game_actor.DisplayName = player.getUserNickname();
|
||||
game_actor.OccupiedAnchorGuid = user_attribute.OccupiedAnchorGuid;
|
||||
game_actor.EquipInfo = item_tool_action.toToolAction4Client();
|
||||
game_actor.State = (int)user_attribute.PlayerState;
|
||||
game_actor.HostId = (int)player.getHostId();
|
||||
|
||||
return game_actor;
|
||||
}
|
||||
|
||||
public static async Task<Result> checkRequirement(this Player player, int requirementMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (requirementMetaId == 0)
|
||||
return result;
|
||||
|
||||
if (!MetaData.Instance._RequirementMetaTable.TryGetValue(requirementMetaId, out var requirement_meta_data))
|
||||
{
|
||||
err_msg = $"Failed to TryGetValue() !!! : requirementMetaId:{requirementMetaId}";
|
||||
result.setFail(ServerErrorCode.RequirementMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var requireAttribute in requirement_meta_data.Attributes)
|
||||
{
|
||||
if (EnumHelper.tryParse<AttributeType>(requireAttribute.Type, out var attribute_enum) == false)
|
||||
{
|
||||
err_msg = $"Enum Pase Failed. AttributeType : {requireAttribute.Type}";
|
||||
result.setFail(ServerErrorCode.BuffInvalidAttributeType, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var ability_action = player.getEntityAction<AbilityAction>();
|
||||
ArgumentNullException.ThrowIfNull(ability_action);
|
||||
|
||||
var attribute_value = ability_action.getAbility(attribute_enum);
|
||||
if (attribute_value < requireAttribute.Value)
|
||||
{
|
||||
err_msg = $"Not Requirement Attribute Value:{requireAttribute.Value} : current:{attribute_value}";
|
||||
result.setFail(ServerErrorCode.NotRequireAttributeValue, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var requireItem in requirement_meta_data.Items)
|
||||
{
|
||||
var inventory_action = player.getEntityAction<InventoryActionBase>();
|
||||
ArgumentNullException.ThrowIfNull(inventory_action);
|
||||
|
||||
switch (requireItem.Type)
|
||||
{
|
||||
case MetaAssets.ERequirementItemType.OWNS:
|
||||
{
|
||||
var item_count = inventory_action.getBagInven().getItemStackCountAllByMetaId((uint)requireItem.ID);
|
||||
if (item_count < requireItem.Value)
|
||||
{
|
||||
err_msg = $"Not Requirement Item Owns ItemMetaId:{requireItem.ID} : value:{requireItem.Value} : currnet:{item_count}";
|
||||
result.setFail(ServerErrorCode.NotRequireAttributeValue, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MetaAssets.ERequirementItemType.EQUIP:
|
||||
{
|
||||
if (!MetaData.Instance._ItemTable.TryGetValue(requireItem.ID, out var item_meta_data))
|
||||
{
|
||||
err_msg = $"Failed to TryGetValue() !!! : itemMetaId:{requireItem.ID}";
|
||||
result.setFail(ServerErrorCode.ItemMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (item_meta_data.TypeLarge == EItemLargeType.TOOL)
|
||||
{
|
||||
var item_tool_action = player.getEntityAction<ItemToolAction>();
|
||||
ArgumentNullException.ThrowIfNull(inventory_action);
|
||||
|
||||
var current_tool_item_meta_Id = item_tool_action.getCurrentToolItemMetaId();
|
||||
if (current_tool_item_meta_Id != requireItem.ID)
|
||||
{
|
||||
err_msg = $"Not Requirement Item Equip ItemMetaId:{requireItem.ID} : currnet:{current_tool_item_meta_Id}";
|
||||
result.setFail(ServerErrorCode.NotRequireAttributeValue, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
var item_small_type = item_meta_data.TypeSmall;
|
||||
|
||||
var inven_rule = GameServerApp.getServerLogic().findRule<InventoryRule>();
|
||||
if (null == inven_rule)
|
||||
{
|
||||
err_msg = $"Not found InventoryRule !!!";
|
||||
result.setFail(ServerErrorCode.InventoryRuleNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var equip_rule_bases = inven_rule.getEquipRuleBasesByItemLargeType(item_meta_data.TypeLarge);
|
||||
if (null == equip_rule_bases)
|
||||
{
|
||||
err_msg = $"Not found EquipRuleBase !!! : ItemMetaId:{requireItem.ID}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var equip_rule in equip_rule_bases)
|
||||
{
|
||||
if (!inventory_action.getEquipInvens().TryGetValue(equip_rule.InvenEquipType, out var equip_inven_base))
|
||||
{
|
||||
err_msg = $"Not found EquipInven !!! : invenEquipType:{equip_rule.InvenEquipType}";
|
||||
result.setFail(ServerErrorCode.EquipInvenNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var inven_accessor = equip_inven_base as IWithInventoryAccessor;
|
||||
ArgumentNullException.ThrowIfNull(inven_accessor, $"inven_accessor is null !!! - {player.toBasicString()}");
|
||||
|
||||
bool is_equiped = false;
|
||||
foreach (var item_base in inven_accessor.getHasItemBases())
|
||||
{
|
||||
var item = item_base as Item;
|
||||
ArgumentNullException.ThrowIfNull(item, $"item is null !!! - {player.toBasicString}");
|
||||
|
||||
var item_attribute = item.getOriginEntityAttribute<ItemAttributeBase>();
|
||||
ArgumentNullException.ThrowIfNull(item_attribute, $"item_attribute is null !!! - {player.toBasicString}");
|
||||
|
||||
if (item_attribute.ItemMetaId == requireItem.ID)
|
||||
{
|
||||
is_equiped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (false == is_equiped)
|
||||
{
|
||||
err_msg = $"Not found require Item !!! : ItemMetaId:{requireItem.ID} - InvenEquipType:{equip_rule.InvenEquipType}, {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.NotRequireAttributeValue, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MetaAssets.ERequirementItemType.USE:
|
||||
{
|
||||
if (!MetaData.Instance._ItemTable.TryGetValue(requireItem.ID, out var item_meta_data))
|
||||
{
|
||||
err_msg = $"Failed to TryGetValue() !!! : itemMetaId:{requireItem.ID}";
|
||||
result.setFail(ServerErrorCode.ItemMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
(result, var deleted_items) = await inventory_action.tryDeleteItemByMetaId((META_ID)requireItem.ID, (ushort)requireItem.Value);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryDeleteItemByMeta() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
err_msg = $"Requirement Item Type Error !!! : type:{requireItem.Type}";
|
||||
result.setFail(ServerErrorCode.NotRequireAttributeValue, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var requireQuest in requirement_meta_data.Quests)
|
||||
{
|
||||
var quest_id = requireQuest.Value;
|
||||
|
||||
switch (requireQuest.Type)
|
||||
{
|
||||
case MetaAssets.ERequirementQuestType.ING:
|
||||
{
|
||||
var quest_action = player.getEntityAction<QuestAction>();
|
||||
ArgumentNullException.ThrowIfNull(quest_action);
|
||||
|
||||
(result, var quest_meta_all_base_info) = await QuestMetaManager.It.getQuestMeta(quest_id);
|
||||
if (result.isFail()) return result;
|
||||
var quest_base_info = quest_meta_all_base_info.m_quest_base_info;
|
||||
NullReferenceCheckHelper.throwIfNull(quest_base_info, () => $"quest_base_info is null !!!");
|
||||
|
||||
if (!quest_action.checkHasQuest(quest_base_info.QuestType, quest_id))
|
||||
{
|
||||
err_msg = $"Not Requirement Quest Ing Value:{requireQuest.Value}";
|
||||
result.setFail(ServerErrorCode.NotRequireAttributeValue, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MetaAssets.ERequirementQuestType.COMPLETED:
|
||||
{
|
||||
var end_quest_action = player.getEntityAction<EndQuestAction>();
|
||||
ArgumentNullException.ThrowIfNull(end_quest_action);
|
||||
|
||||
if (!end_quest_action.hasEndQuest(requireQuest.Value))
|
||||
{
|
||||
err_msg = $"Not Requirement Quest Complete Value:{requireQuest.Value}";
|
||||
result.setFail(ServerErrorCode.NotRequireAttributeValue, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
err_msg = $"Not Require Attribute Value !!! : type:{requireQuest.Type}";
|
||||
result.setFail(ServerErrorCode.NotRequireAttributeValue, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Result checkInstanceAccess(this Player player, int instanceMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (!MetaData.Instance._IndunTable.TryGetValue(instanceMetaId, out var instance_meta_data))
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TryGetValue() !!! : instanceMetaId:{instanceMetaId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.InstanceMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
switch (instance_meta_data.AccessType)
|
||||
{
|
||||
case MetaAssets.AccessType.Public:
|
||||
break;
|
||||
case MetaAssets.AccessType.Item:
|
||||
{
|
||||
var inventory_action = player.getEntityAction<InventoryActionBase>();
|
||||
ArgumentNullException.ThrowIfNull(inventory_action, $"inventory_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
// todo(sangyeob.kim) : 추후에 아이템 수량 변경 등이 필요한 경우 meta_data 에 AccessCount 항목이 필요함
|
||||
var item_count = inventory_action.getItemStackCountAllByMetaId((uint)instance_meta_data.AccessId);
|
||||
if (item_count < 1)
|
||||
{
|
||||
err_msg = $"Not Enough Instance Access Item !!! itemMetaId:{instance_meta_data.AccessId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.NotExistInstanceTicket, err_msg);
|
||||
// result.setFail(ServerErrorCode.InstanceAccessItemNotEnough, err_msg); // Todo(myounghwi) : 추후 에러코드 적용(클라와 이야기 필요)
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MetaAssets.AccessType.Season:
|
||||
{
|
||||
var season_action = player.getEntityAction<SeasonPassAction>();
|
||||
ArgumentNullException.ThrowIfNull(season_action, $"season_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
if (season_action.isActivatedSeasonPass() == false)
|
||||
{
|
||||
err_msg = $"Not Season Period !!! - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.SeasonPassNotAblePeriod, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
//AccessId가 0이면 시즌중이면 모두가 들어갈 수 있음. 1이면 시즌패스 구매자만 들어갈 수 있음.
|
||||
if (instance_meta_data.AccessId == 0)
|
||||
break;
|
||||
|
||||
var is_charged_season = season_action.isChargedSeasonPass();
|
||||
if (false == is_charged_season)
|
||||
{
|
||||
err_msg = $"Not Charged SeasonPass Item !!! - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.NotExistInstanceTicket, err_msg);
|
||||
// result.setFail(ServerErrorCode.InstanceAccessSeasonPassNotCharged, err_msg); // Todo(myounghwi) : 추후 에러코드 적용(클라와 이야기 필요)
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MetaAssets.AccessType.Belong:
|
||||
break;
|
||||
default:
|
||||
{
|
||||
err_msg = $"AccessType Invalid !!! : type:{instance_meta_data.AccessType}, instanceMetaId:{instance_meta_data.Id} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.InstanceAccessTypeInvalid, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task<Result> changeInstanceRoomIdAtLoginCache(this Player player, string instanceRoomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var game_login_action = player.getEntityAction<GameLoginAction>();
|
||||
ArgumentNullException.ThrowIfNull(game_login_action);
|
||||
|
||||
var login_cache_request = game_login_action.getLoginCacheRequest();
|
||||
ArgumentNullException.ThrowIfNull(login_cache_request);
|
||||
var login_cache = login_cache_request.getLoginCache();
|
||||
ArgumentNullException.ThrowIfNull(login_cache);
|
||||
|
||||
login_cache.InstanceRoomId = instanceRoomId;
|
||||
|
||||
result = await login_cache_request.upsertLogin();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to upsertLogin() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
97
GameServer/Entity/Player/Manager/PlayerManager.cs
Normal file
97
GameServer/Entity/Player/Manager/PlayerManager.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using ServerCore; using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 NICKNAME = System.String;
|
||||
using CHARACTER_GUID = System.String;
|
||||
using ITEM_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer
|
||||
{
|
||||
public class PlayerManager : UserManagerBase<USER_GUID, NICKNAME, Player>
|
||||
{
|
||||
public PlayerManager() { }
|
||||
|
||||
public async Task logoutUserAllByKick()
|
||||
{
|
||||
var users = getUsers().Values.ToList();
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
await kickUserByUserGuid(user.getUserGuid(), LogoutReasonType.ExitToService);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> kickUserByNickname(string name)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
if (false == tryGetUserBySubKey(name, out var found_user))
|
||||
{
|
||||
var err_msg = $"Already dicsonnected User !!! : nickname:{name}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
return false;
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(found_user);
|
||||
|
||||
await kickUser(found_user);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> kickUserByUserGuid(USER_GUID userGuid, LogoutReasonType reason = LogoutReasonType.DuplicatedLogin, string reasonDescription = "")
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
if (false == tryGetUserByPrimaryKey(userGuid, out var found_user))
|
||||
{
|
||||
var err_msg = $"Already dicsonnected User !!! : userGuid:{userGuid}";
|
||||
Log.getLogger().warn(err_msg);
|
||||
return false;
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(found_user);
|
||||
|
||||
await kickUser(found_user, reason, reasonDescription);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task kickUser(Player toKickUser, LogoutReasonType reason = LogoutReasonType.DuplicatedLogin, string reasonDescription = "")
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(toKickUser);
|
||||
|
||||
sendLogoutNoti(toKickUser, reason, reasonDescription);
|
||||
|
||||
var game_logout_action = toKickUser.getEntityAction<GameLogoutAction>();
|
||||
ArgumentNullException.ThrowIfNull(game_logout_action);
|
||||
|
||||
await game_logout_action.logoutUser();
|
||||
}
|
||||
|
||||
public void sendLogoutNoti(Player player, LogoutReasonType reason, string reasonDescription)
|
||||
{
|
||||
ClientToGame gs2cMessage = new ClientToGame();
|
||||
gs2cMessage.Message = new ClientToGameMessage();
|
||||
gs2cMessage.Message.NtfLogout = new ClientToGameMessage.Types.GS2C_NTF_LOGOUT();
|
||||
gs2cMessage.Message.NtfLogout.LogoutReason = reason;
|
||||
gs2cMessage.Message.NtfLogout.ReasonMessage = reasonDescription;
|
||||
|
||||
player.sendPacket(gs2cMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
423
GameServer/Entity/Player/Player.cs
Normal file
423
GameServer/Entity/Player/Player.cs
Normal file
@@ -0,0 +1,423 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Numerics;
|
||||
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Nettention.Proud;
|
||||
using StackExchange.Redis;
|
||||
using Pipelines.Sockets.Unofficial.Buffers;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using WORLD_META_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 GameServer;
|
||||
|
||||
public partial class Player : UserBase, IEntityWithSession, IMergeWithInventory, IInitNotifyPacket
|
||||
{
|
||||
private readonly CancellationTokenSource m_cts = new();
|
||||
private readonly List<(ClientToGame packet, bool isNotifyBroadcast)> notifyPackets = new();
|
||||
|
||||
public Player(NetClientInfo netClient)
|
||||
: base(EntityType.Player, netClient)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
//=====================================================================================
|
||||
// User Domain Attribute
|
||||
//=====================================================================================
|
||||
addEntityAttribute(new UserAttribute(this));
|
||||
addEntityAttribute(new NicknameAttribute(this));
|
||||
addEntityAttribute(new LevelAttribute(this));
|
||||
addEntityAttribute(new MoneyAttribute(this));
|
||||
addEntityAttribute(new LocationAttribute(this));
|
||||
|
||||
addEntityAttribute(new BuffAttribute(this));
|
||||
addEntityAttribute(new GameOptionAttribute(this));
|
||||
addEntityAttribute(new CharacterProfileAttribute(this));
|
||||
addEntityAttribute(new MailProfileAttribute(this));
|
||||
addEntityAttribute(new CraftHelpAttribute(this));
|
||||
|
||||
addEntityAttribute(new PartyInvitePartyRecvsAttribute(this));
|
||||
|
||||
addEntityAttribute(new FriendFolderAttribute(this));
|
||||
addEntityAttribute(new RepeatQuestAttribute(this));
|
||||
|
||||
addEntityAttribute(new EscapePositionAttribute(this));
|
||||
addEntityAttribute(new SeasonPassAttribute(this));
|
||||
|
||||
addEntityAttribute(new UserContentsSettingAttribute(this));
|
||||
addEntityAttribute(new PackageLastOrderRecodeAttribute(this));
|
||||
addEntityAttribute(new AiChatAttribute(this));
|
||||
|
||||
addEntityAttribute(new UgqDailyRewardCountAttribute(this));
|
||||
addEntityAttribute(new RentalInstanceVisitAttribute(this));
|
||||
|
||||
addEntityAttribute(new DailyQuestCheckAttribute(this));//legacy
|
||||
addEntityAttribute(new SwitchingPropAttribute(this));
|
||||
addEntityAttribute(new QuestPeriodRepeatCheckAttribute(this));
|
||||
|
||||
//=====================================================================================
|
||||
// Game Domain Attribute
|
||||
//=====================================================================================
|
||||
addEntityAttribute(new CaliumAttribute(this));
|
||||
|
||||
//=====================================================================================
|
||||
// User Domain Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new PlayerAction(this));
|
||||
addEntityAction(new AbilityAction(this));
|
||||
addEntityAction(new NicknameAction(this));
|
||||
addEntityAction(new LocationAction(this));
|
||||
addEntityAction(new MoneyAction(this));
|
||||
addEntityAction(new UserContentsSettingAction(this));
|
||||
|
||||
//=====================================================================================
|
||||
// Inventory 관련 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new UserInventoryAction(this));
|
||||
|
||||
|
||||
//=====================================================================================
|
||||
// Item 관리적인 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new ItemBuyAction(this));
|
||||
addEntityAction(new ItemClothAction(this));
|
||||
addEntityAction(new ItemToolAction(this));
|
||||
addEntityAction(new ItemTattooAction(this));
|
||||
|
||||
addEntityAction(new RandomBoxItemUseAction(this));
|
||||
|
||||
|
||||
//=====================================================================================
|
||||
// GameZone Domain Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new GameZoneAction(this));
|
||||
addEntityAction(new GameZoneMoveAction(this));
|
||||
|
||||
// room 관련 action
|
||||
addEntityAction(new RoomAction(this));
|
||||
|
||||
|
||||
// shop 관련 action
|
||||
addEntityAction(new ShopAction(this));
|
||||
|
||||
// Party 관련 action
|
||||
addEntityAction(new PersonalPartyAction(this));
|
||||
addEntityAction(new PartyInvitePartyRecvAction(this));
|
||||
|
||||
addEntityAction(new FriendAgentAction(this));
|
||||
addEntityAction(new FriendFolderAction(this));
|
||||
addEntityAction(new SendFriendRequestAction(this));
|
||||
addEntityAction(new FriendInviteMyhomeAction(this));
|
||||
addEntityAction(new FriendReplyInviteMyhomeAction(this));
|
||||
addEntityAction(new ReplyReceivedFriendRequestAction(this));
|
||||
addEntityAction(new KickFriendsFromMyHomeAction(this));
|
||||
addEntityAction(new BlockUserAgentAction(this));
|
||||
addEntityAction(new QuestAction(this));
|
||||
addEntityAction(new QuestCheatAction(this));
|
||||
addEntityAction(new RepeatQuestAction(this));
|
||||
addEntityAction(new EndQuestAction(this));
|
||||
addEntityAction(new QuestAcceptAction(this));
|
||||
addEntityAction(new QuestMailAction(this));
|
||||
addEntityAction(new QuestRefuseAction(this));
|
||||
addEntityAction(new QuestAbandonAction(this));
|
||||
addEntityAction(new QuestTaskUpdateAction(this));
|
||||
addEntityAction(new QuestRewardAction(this));
|
||||
addEntityAction(new QuestNPCDialogueAction(this));
|
||||
addEntityAction(new ClaimAction(this));
|
||||
addEntityAction(new ClaimRewardAction(this));
|
||||
addEntityAction(new UgqInfoAction(this));
|
||||
addEntityAction(new UgqAssignAction(this));
|
||||
addEntityAction(new UgqTestAction(this));
|
||||
addEntityAction(new UgqAbortAction(this));
|
||||
addEntityAction(new UgqRewardAction(this));
|
||||
addEntityAction(new SwitchingPropAction(this));
|
||||
|
||||
addEntityAction(new OwnedBuildingAgentAction(this));
|
||||
addEntityAction(new OwnedLandAgentAction(this));
|
||||
addEntityAction(new MyhomeAgentAction(this));
|
||||
addEntityAction(new RentalAgentAction(this));
|
||||
addEntityAction(new UserSocialActionExecutorAction(this));
|
||||
addEntityAction(new MinimapMarkerAgentAction(this));
|
||||
addEntityAction(new ItemFirstPurchaseHistoryAgentAction(this));
|
||||
addEntityAction(new SearchNicknameAction(this));
|
||||
|
||||
addEntityAction(new ChatAction(this));
|
||||
addEntityAction(new CharacterProfileAction(this));
|
||||
addEntityAction(new ChannelAction(this));
|
||||
addEntityAction(new CartAction(this));
|
||||
addEntityAction(new BuffAction(this));
|
||||
addEntityAction(new GameOptionAction(this));
|
||||
addEntityAction(new LanguageAction(this));
|
||||
addEntityAction(new MailAction(this));
|
||||
addEntityAction(new StateAction(this));
|
||||
addEntityAction(new UserReportAction(this));
|
||||
addEntityAction(new EscapeAction(this));
|
||||
addEntityAction(new PackageAction(this));
|
||||
|
||||
addEntityAction(new CraftAction(this));
|
||||
addEntityAction(new CraftHelpAction(this));
|
||||
addEntityAction(new CraftRecipeAction(this));
|
||||
addEntityAction(new SeasonPassAction(this));
|
||||
addEntityAction(new RentalVisitAction(this));
|
||||
addEntityAction(new P2PDataAction(this));
|
||||
addEntityAction(new BeaconShopAction(this));
|
||||
|
||||
//=====================================================================================
|
||||
// AI Chat 관련 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new AIChatAction(this));
|
||||
|
||||
//=====================================================================================
|
||||
// Task Reservation 관련 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new TaskReservationAction(this));
|
||||
|
||||
//=====================================================================================
|
||||
// Npc 상호작용 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new NpcInteractionAction(this));
|
||||
|
||||
|
||||
//=====================================================================================
|
||||
// Ugc Npc 관련 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new UgcNpcCreationOrLoadAction(this));
|
||||
|
||||
|
||||
//=====================================================================================
|
||||
// Farming 관련 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new FarmingAction(this));
|
||||
|
||||
|
||||
//=====================================================================================
|
||||
// Game LogInOut 관련 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new GameLoginAction(this));
|
||||
addEntityAction(new GameLogoutAction(this));
|
||||
|
||||
|
||||
//=====================================================================================
|
||||
// User Create or Load 관련 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new UserCreateOrLoadAction(this));
|
||||
|
||||
|
||||
//=====================================================================================
|
||||
// Custom Ui or Data 관련 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new CustomDefinedUiAction(this));
|
||||
|
||||
//=====================================================================================
|
||||
// Calium 관련 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new CaliumConverterAction(this));
|
||||
addEntityAction(new CaliumExchangerAction(this));
|
||||
|
||||
//=====================================================================================
|
||||
// AI Chat 관련 Action
|
||||
//=====================================================================================
|
||||
|
||||
//=====================================================================================
|
||||
// 랜드 경매 관련 Action
|
||||
//=====================================================================================
|
||||
addEntityAction(new UserLandAuctionAction(this));
|
||||
|
||||
|
||||
return await base.onInit();
|
||||
}
|
||||
|
||||
public async Task onResetUser()
|
||||
{
|
||||
foreach(var each in getEntityAttributes())
|
||||
{
|
||||
var to_clear_attribute = each.Value;
|
||||
|
||||
var account_attribute = to_clear_attribute as AccountAttribute;
|
||||
if (null != account_attribute) { continue; }
|
||||
var user_attribute = to_clear_attribute as UserAttribute;
|
||||
if (null != user_attribute) { continue; }
|
||||
|
||||
to_clear_attribute.onClear();
|
||||
}
|
||||
|
||||
foreach (var each in getEntityActions())
|
||||
{
|
||||
var to_clear_action = each.Value;
|
||||
|
||||
to_clear_action.onClear();
|
||||
}
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
// override IMergeWithInventory
|
||||
public async Task<Result> onMerge(List<ReservedSlotOnInven> reservedSlotOnInvens, TransactionRunner transactionRunner)
|
||||
{
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(reservedSlotOnInvens, () => $"reservedSlotOnInvens is null !!! - {toBasicString()}");
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(transactionRunner, () => $"transactionRunner is null !!! - {toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
|
||||
var inventory_action = getEntityAction<InventoryActionBase>();
|
||||
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!! - {toBasicString()}");
|
||||
|
||||
result = await inventory_action.onMergeInventory(reservedSlotOnInvens, transactionRunner);
|
||||
if(result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addNotifyMessage(ClientToGame message, bool isNotifyBroadcast) { notifyPackets.Add((message, isNotifyBroadcast)); }
|
||||
public void InitNotifyMessage() { notifyPackets.Clear(); }
|
||||
public void sendNotifyMessage()
|
||||
{
|
||||
foreach ((ClientToGame packet, bool isNotifyBroadcast) notifyInfo in notifyPackets)
|
||||
{
|
||||
if (notifyInfo.isNotifyBroadcast == true)
|
||||
{
|
||||
var game_zone_action = this.getEntityAction<GameZoneAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!! - {toBasicString()}");
|
||||
game_zone_action.broadcast(this, notifyInfo.packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(this, notifyInfo.packet))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override TAction getEntityAction<TAction>()
|
||||
{
|
||||
if (typeof(TAction) == typeof(InventoryActionBase))
|
||||
{
|
||||
var inventory_action = base.getEntityAction<UserInventoryAction>() as TAction;
|
||||
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!!");
|
||||
return inventory_action;
|
||||
}
|
||||
else if (typeof(TAction) == typeof(SocialActionLoadAction))
|
||||
{
|
||||
var social_action = base.getEntityAction<UserSocialActionExecutorAction>() as TAction;
|
||||
NullReferenceCheckHelper.throwIfNull(social_action, () => $"social_action is null !!!");
|
||||
return social_action;
|
||||
}
|
||||
|
||||
var action = base.getEntityAction<TAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(action, () => $"action is null !!!");
|
||||
return action;
|
||||
}
|
||||
|
||||
public override Type onGetAvailableItemAttributeType()
|
||||
{
|
||||
return typeof(UserItemAttribute);
|
||||
}
|
||||
|
||||
public override OWNER_GUID onGetGuidOfOwnerEntityType()
|
||||
{
|
||||
var user_attribute = getEntityAttribute<UserAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_attribute, () => $"user_attribute is null !!! - {toBasicString()}");
|
||||
|
||||
return user_attribute.UserGuid;
|
||||
}
|
||||
|
||||
public bool sendPacket(ClientToGame msg)
|
||||
{
|
||||
return GameServerApp.getServerLogic().onSendPacket(this, msg);
|
||||
}
|
||||
|
||||
public bool hasOtpForServerConnect()
|
||||
{
|
||||
var account_attribute = getEntityAttribute<AccountAttribute>();
|
||||
if (null == account_attribute)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 >= account_attribute.OtpForServerConnect.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public CancellationTokenSource getCancelToken() => m_cts;
|
||||
|
||||
|
||||
public override string onGetDbGuid()
|
||||
{
|
||||
return getUserGuid();
|
||||
}
|
||||
|
||||
public CommonResult? getCommonResult()
|
||||
{
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var found_transaction_runner = findTransactionRunner(TransactionIdType.PrivateContents);
|
||||
if (null == found_transaction_runner)
|
||||
{
|
||||
err_msg = $"Not found TransactionRunner !!! : {toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return found_transaction_runner.getCommonResult();
|
||||
}
|
||||
|
||||
public override ILogActor toLogActor()
|
||||
{
|
||||
var user_actor_log = base.toLogActor() as UserActorLog;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(user_actor_log, () => $"user_actor_log is null !!!");
|
||||
|
||||
var nickname_attribute = getEntityAttribute<NicknameAttribute>();
|
||||
if(null != nickname_attribute)
|
||||
{
|
||||
user_actor_log.UserNickname = nickname_attribute.Nickname;
|
||||
}
|
||||
|
||||
return user_actor_log;
|
||||
}
|
||||
|
||||
public override string toSummaryString()
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var public_ip = server_logic.getProudNetListener().getNetServer().getNetClientPublicIp(this.getHostId());
|
||||
|
||||
var account_attribute = getOriginEntityAttribute<AccountAttribute>();
|
||||
return toBasicString() + $"accountCreationType:{account_attribute?.AccountCreationType}, authAdminLevelType:{account_attribute?.AuthAdminLevelType}, publicIp:{public_ip}, {base.toSummaryString()}";
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user