초기커밋

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

View File

@@ -0,0 +1,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;
}
}

View 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()}";
}
}
}

View File

@@ -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
);
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View 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()}";
}
}
}

View File

@@ -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);
}
}
}

View 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;
}
}
}

View File

@@ -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;
}
}
}

View 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()}";
}
}
}

View File

@@ -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;
}
}
}

View 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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View 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 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()}";
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View 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 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()}";
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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() {}
}

View 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();
}
}

View 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;
}
}

View 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();
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View 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);
}
}

View 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;
}
}

View 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;
}
}

View 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;
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View 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;
}
}

View 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()}";
}
}
}

View File

@@ -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;
}
}
}

View 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()}";
}
}
}

File diff suppressed because it is too large Load Diff

View 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;
}
}

View 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;
}
}

View 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;
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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()}";
}
}
}

View 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()}";
}
}
}

View 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()}";
}
}
}

View 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;
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);
}
}

View File

@@ -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;
}
}
}

View 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);
}
}
}

View 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);
}
}
}
}

View 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();
}
}
}

View 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;
}
}
}

View 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)
{
}
}
}

View 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;
}
}
}

View 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)
{
}
}
}

View 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;
}
}
}

View 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)
{
}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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()}";
}
}
}

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

View File

@@ -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;
}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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()}";
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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()}";
}
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}
}

View 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()}";
}
}
}

View 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();
}
}
}

View 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);
}
}

View 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);
}
}

View File

@@ -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>());
}
}

View 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>());
}
}

View 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());
}
}

View File

@@ -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);
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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];
}
}

View 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;
}
}
}

View 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;
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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