using ServerCore; using ServerBase; using ServerCommon; namespace GameServer; public class MoneyAction : EntityActionBase, IRemoteTransaction { public MoneyAction(Player owner) : base(owner) { } public override async Task onInit() { await Task.CompletedTask; var result = new Result(); return result; } public override void onClear() { return; } //============================================================================================= // delta 만큼 금전을 쓴다. //============================================================================================= public async Task spendMoney(CurrencyType currencyType, double delta, bool isTrimExcess = false, bool useCaliumEvent = true) { var result = new Result(); if (ServerCore.TypeHelper.NumericSignType.Positive == ServerCore.TypeHelper.checkNumericSignType(delta)) { delta *= -1; } if (0 > delta) { result = await changeMoney(currencyType, delta, isTrimExcess, useCaliumEvent); if (result.isFail()) { return result; } } return result; } //============================================================================================= // delta 만큼 금전을 얻는다. //============================================================================================= public async Task earnMoney(CurrencyType currencyType, double delta, bool isTrimExcess = false) { var result = new Result(); if (ServerCore.TypeHelper.NumericSignType.Negative == ServerCore.TypeHelper.checkNumericSignType(delta)) { delta *= -1; } if (0 < delta) { result = await changeMoney(currencyType, delta, isTrimExcess); if (result.isFail()) { return result; } } return result; } //============================================================================================= // delta 만큼 금전을 변경(음수, 양수) 한다. //============================================================================================= public async Task 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(); 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(); 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(); 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(); 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 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(); 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(); 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 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(); NullReferenceCheckHelper.throwIfNull(calium_storage_entity, () => $"calium_storage_entity"); var calium_event_action = calium_storage_entity.getEntityAction(); 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; } }