초기커밋

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,563 @@
using Newtonsoft.Json;
using ServerCore; using ServerBase;
using ServerCommon;
using static ServerCommon.MetaHelper;
using META_ID = System.UInt32;
using Amazon.S3.Model;
namespace GameServer
{
public class AIChatAction : EntityActionBase
{
private string user_jwt = string.Empty;
public AIChatAction(Player owner)
: base(owner)
{
}
public override Task<Result> onInit()
{
var result = new Result();
return Task.FromResult(result);
}
public override void onClear()
{
user_jwt = string.Empty;
}
//-------------인증 JWT 관련 API-------------
//특정 유저의 JWT를 검증합니다.
public async Task<(Result, AIChatJwtInfo?)> jwtverify(string user_jwt)
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
if (server_logic.getServerConfig().OfflineMode == true)
{
result.setFail(ServerErrorCode.AiChatServerInactive);
return (result, null);
}
var url = $"/api/auth/jwt/verify";
(result, string resMsg) = await AIChatServerConnector.sendAIChatServer("GET", url, user_jwt, null);
if (result.isFail())
{
Log.getLogger().error($"Failed ai chat server action : jwtverify, msg : {resMsg}");
return (result, null);
}
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatJwtVerify);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
try
{
var aichat_jwt_info = JsonConvert.DeserializeObject<AIChatJwtInfo>(resMsg);
return (result, aichat_jwt_info);
}
catch(Exception ex)
{
Log.getLogger().error($"Exception !!!, DeserializeObject : exception:{ex}, resMsg:{resMsg}");
return (result, null);
}
}
//특정 유저의 JWT를 발행합니다.
public async Task<(Result, string?)> jwtIssue(string user_guid)
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
if (server_logic.getServerConfig().OfflineMode == true)
{
result.setFail(ServerErrorCode.AiChatServerInactive);
return (result, string.Empty);
}
var url = $"/api/auth/jwt/issue/{user_guid}";
var body = AIChatServerConnector.getUserJwtJson();
(result, string resMsg) = await AIChatServerConnector.sendAIChatServer("POST", url, null, body);
if (result.isFail())
{
Log.getLogger().error($"Failed ai chat server action : jwtIssue, msg : {resMsg}");
return (result, string.Empty);
}
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatJwtIssue);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
try
{
var ai_chat_issue_jwt = JsonConvert.DeserializeObject<AIChatIssueJwt>(resMsg);
NullReferenceCheckHelper.throwIfNull(ai_chat_issue_jwt, () => $"ai_chat_issue_jwt is null !!! - {toBasicString()}");
user_jwt = ai_chat_issue_jwt.jwt == null ? string.Empty : ai_chat_issue_jwt.jwt;
return (result, user_jwt);
}
catch (Exception ex)
{
Log.getLogger().error($"Exception !!!, DeserializeObject : exception:{ex}, resMsg:{resMsg}");
return (result, null);
}
}
//포인트 충전
public async Task<Result> pointCharge(AIChatPointCharge aIChatPointCharge)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var url = $"/api/point/charge";
var body = JsonConvert.SerializeObject(aIChatPointCharge);
(var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("PUT", url, body);
if (result.isFail())
{
if (result.ErrorCode == ServerErrorCode.AiChatServerInactive)
return result;
result.setFail(ServerErrorCode.AiChatServerRetryChargePoint);
Log.getLogger().error($"Failed ai chat server action : pointCharge, msg : {resMsg}");
return result;
}
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatPointCharge);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
//포인트 충전 확인
public async Task<Result> pointChargeCheckByOrderGuid(string order_guid)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var aIPointVerify = new AIChatPointVerify() { orderGuid = order_guid };
var url = $"/api/point/charge";
var body = JsonConvert.SerializeObject(aIPointVerify);
(var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("GET", url, body);
if (result.isFail()) return result;
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatPointChargeVerify);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
//어제까지의 벌어들인 미청구 포인트 조회
public async Task<(Result, AIChatPointClaimables?)> pointClaimables(int page, int num_per_page, string user_guid)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var url = $"/api/point/claimables/{user_guid}?page={page}&numPerPage={num_per_page}";
(var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("GET", url, null);
if (result.isFail())
{
if (result.ErrorCode == ServerErrorCode.AiChatServerUserNotFound)
{
result = await registerUser(player.getUserGuid(), player.getUserNickname());
if (result.isFail())
{
return (result, null);
}
(result, resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("GET", url, null);
if (result.isFail())
{
return (result, null);
}
}
}
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatIncentiveSearch);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
try
{
var aichat_point_claim_ables = JsonConvert.DeserializeObject<AIChatPointClaimables>(resMsg);
return (result, aichat_point_claim_ables);
}
catch (Exception ex)
{
Log.getLogger().error($"Exception !!!, DeserializeObject : exception:{ex}, resMsg:{resMsg}");
return (result, null);
}
}
//인센티브 수령 완료 표시
public async Task<Result> pointMarkClaimed(string user_guid, int marking_day)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"server_logic is null !!!");
var url = $"/api/point/mark-as-claimed/{user_guid}?aggregationEndTime={marking_day}";
(var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("POST", url, null);
if (result.isFail())
{
Log.getLogger().error($"Failed ai chat server action : pointMarkClaimed, msg : {resMsg}");
return result;
}
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatIncentiveMarking);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
//신규 유저 등록
public async Task<Result> registerUser(string user_guid, string name)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var url = $"/api/user/{user_guid}";
var aIRegisterUser = new AIChatRegisterUser() { nick = name };
var body = JsonConvert.SerializeObject(aIRegisterUser);
(var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("POST", url, body);
if (result.isFail())
{
Log.getLogger().error($"Failed ai chat server action : registerUser, user_guid : {user_guid}, name : {name}, msg : {resMsg}");
return result;
}
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatRegisterUser);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
//유저 등록 제거
public async Task<Result> deleteUser(string user_guid)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var url = $"/api/user/{user_guid}";
(var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("DELETE", url, null);
if (result.isFail()) return result;
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatDeleteUser);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
//특정 캐릭터 조회
public async Task<(Result, AIChatCharacter?)> getCharacterByTargetGuid(string target_guid)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var url = $"/api/character/{target_guid}";
(var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("GET", url, null);
if (result.isFail()) return (result, null);
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatGetCharacter);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
try
{
var aichat_character = JsonConvert.DeserializeObject<AIChatCharacter>(resMsg);
return (result, aichat_character);
}
catch (Exception ex)
{
Log.getLogger().error($"Exception !!!, DeserializeObject : exception:{ex}, resMsg:{resMsg}");
return (result, null);
}
}
//-------------유저 권한 API-------------
//신규 캐릭터 등록
public async Task<Result> registerCharacter(AIChatRegisterCharacter aIChatRegisterCharacter)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var url = $"/api/character";
var body = JsonConvert.SerializeObject(aIChatRegisterCharacter);
(var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("POST", url, body);
if (result.isFail())
{
Log.getLogger().error($"Failed ai chat server action : registerCharacter, msg : {resMsg}");
return result;
}
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatRegisterCharacter);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
//캐릭터 수정
public async Task<Result> updateCharacter(AIChatRegisterCharacter aIChatRegisterCharacter)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var url = $"/api/character/locale/{aIChatRegisterCharacter.guid}";
var body = JsonConvert.SerializeObject(aIChatRegisterCharacter);
(var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("PUT", url, body);
if (result.isFail()) return result;
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatUpdateCharacter);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, body);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
//캐릭터 등록 제거
public async Task<Result> deleteCharacter(string character_guid)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var url = $"/api/character/{character_guid}";
(var result, string resMsg) = await AIChatServerConnector.sendAIChatServerWithServerJwt("DELETE", url, null);
if (result.isFail()) return result;
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.AIChatDeleteCharacter);
var task_log_data = AIChatBusinessLogHelper.toLogInfo(url, string.Empty);
invokers.Add(new AIChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
/// <summary>
/// 데이터 수집 기간 : 월요일 00:00:00 ~ 일요일 23:59:59(KST 기준 - UTC+9)
/// 인센티브 보상 지급 날짜 및 시각 : 매주 월요일 05:00 (KST 기준 - UTC+9)
/// </summary>
public async Task<Result> updateTickOfIncentivePoint()
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var current_time = DateTimeHelper.Current;
var incentive_collect_time = current_time.AddDays(Convert.ToInt32(DayOfWeek.Monday) - Convert.ToInt32(current_time.DayOfWeek)).Date;
var incentive_provide_time = incentive_collect_time.AddHours(5);
var ai_chat_attribute = player.getEntityAttribute<AiChatAttribute>();
NullReferenceCheckHelper.throwIfNull(ai_chat_attribute, () => $"ai_chat_attribute is null !!! - {player.toBasicString()}");
var last_incentive_provide_time = ai_chat_attribute.LastIncentiveProvideTime;
if (last_incentive_provide_time != default ||
last_incentive_provide_time == incentive_provide_time ||
incentive_provide_time > current_time)
{
return result;
}
result = await TakeIncentivePoint(incentive_provide_time);
if(result.isFail()) return result;
return result;
}
public async Task<Result> TakeIncentivePoint(DateTime new_incentive_provide_time)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var dynamo_db_client = server_logic.getDynamoDbClient();
var mail_action = player.getEntityAction<MailAction>();
NullReferenceCheckHelper.throwIfNull(mail_action, () => $"mail_action is null !!!");
var ai_chat_attribute = player.getEntityAttribute<AiChatAttribute>();
NullReferenceCheckHelper.throwIfNull(ai_chat_attribute, () => $"ai_chat_attribute is null !!! - {player.toBasicString()}");
if (MetaData.Instance._CurrencyMetaTableByCurrencyType.TryGetValue(CurrencyType.Beam, out var currencyMetaData) == false)
{
result.setFail(ServerErrorCode.CurrencyNotFoundData, err_msg);
return result;
}
(result, var pointClaim) = await pointClaimables(0, 100, player.getUserGuid());
if (result.isFail())
{
return result;
}
NullReferenceCheckHelper.throwIfNull(pointClaim, () => $"pointClaim is null !!! - {toBasicString()}");
if (pointClaim.items.Count == 0)
{
ai_chat_attribute.LastIncentiveProvideTime = new_incentive_provide_time;
ai_chat_attribute.modifiedEntityAttribute();
(result, var ai_chat_doc) = await ai_chat_attribute.toDocBase();
if (result.isFail()) return result;
NullReferenceCheckHelper.throwIfNull(ai_chat_doc, () => $"ai_chat_doc is null !!! - {player.toBasicString()}");
result = await dynamo_db_client.simpleUpdateDocumentWithDocType(ai_chat_doc);
if (result.isFail())
{
err_msg = $"Failed to simpleUpdateDocumentWithDocType ai_chat_doc !!! - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
return result;
}
var IncentivePointList = new List<int>();
int maxPoint = GameConfigMeta.AiChatInsentiveMax;
int last_incentive_period = 0;
foreach (var pointInfo in pointClaim.items)
{
int amount = pointInfo.amount;
if(maxPoint < amount)
{
amount = maxPoint;
}
IncentivePointList.Add(amount);
if(last_incentive_period < pointInfo.end_time)
{
last_incentive_period = pointInfo.end_time;
}
}
var fn_send_system_mail = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var receivedMailDocs = new List<DynamoDbDocBase>();
foreach (var amount in IncentivePointList)
{
var mail_items = new List<ServerCommon.MailItem>() { new ServerCommon.MailItem() { ItemId = (META_ID)currencyMetaData.ItemId, Count = amount } };
(result, var receivedMailDoc) = await mail_action.tryMakeNewSystemMail(mail_items, ServerCommon.Constant.NPC_INSENTIVE_META_KEY, GameConfigMeta.AiChatInsentivePeriod, string.Empty);
if (result.isFail())
{
return result;
}
NullReferenceCheckHelper.throwIfNull(receivedMailDoc, () => $"receivedMailDoc is null !!! - {toBasicString()}");
receivedMailDocs.Add(receivedMailDoc);
}
ai_chat_attribute.LastIncentiveProvideTime = new_incentive_provide_time;
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.MailAiChatIncentivePoint
, dynamo_db_client);
{
batch.addQuery(new DBQEntityWrite(receivedMailDocs));
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
return result;
}
result = await pointMarkClaimed(player.getUserGuid(), last_incentive_period);
if (result.isFail())
{
return result;
}
mail_action.NewReceivedMail();
return result;
};
var transaction_name = "provideIncentivePoint";
result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid()
, TransactionIdType.PrivateContents, transaction_name
, fn_send_system_mail);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()} - transactionName:{transaction_name}, {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
}
}

View File

@@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServerCommon;
using META_ID = System.UInt32;
namespace GameServer;
public class AIChatJwt
{
public string messageBase64 { get; set; } = string.Empty;
public string signatureBase64 { get; set; } = string.Empty;
}
public class AIChatPointVerify
{
public string orderGuid { get; set; } = string.Empty;
}
public class AIChatError
{
public int code { get; set; } = 0;
public string name { get; set; } = string.Empty;
public string message { get; set; } = string.Empty;
}
public class AIChatJwtInfo
{
public string guid { get; set; } = string.Empty;
public string role { get; set; } = string.Empty;
public int iat { get; set; } = 0;
public int exp { get; set; } = 0;
}
public class AIChatRegisterCharacter
{
public string guid { get; set; } = string.Empty;
public string ownerUserGuid { get; set; } = string.Empty;
public string lang { get; set; } = string.Empty;
public string name { get; set; } = string.Empty;
public string persona { get; set; } = string.Empty;
public string firstMes { get; set; } = string.Empty;
public string secrets { get; set; } = string.Empty; // Not Used
public string shortDesc { get; set; } = string.Empty;
public List<META_ID> tags { get; set; } = new();
public bool isOfficial { get; set; } = false;
public List<AIChatSocialActionConfig> socialActionConfig = new();
public AIChatCharacterAttribute attributes { get; set; } = new();
}
public class AIChatCharacterAttribute
{
public int gender { get; set; } = 0;
}
public class AIChatIssueJwt
{
public string jwt { get; set; } = string.Empty;
}
public class AIChatSocialActionConfig
{
public int id { get; set; } = 0;
public float weight { get; set; } = 0;
}
public class AIChatPointClaimables
{
public int page { get; set; } = 0;
public int numPerPage { get; set; } = 0;
public int total { get; set; } = 0;
public List<AIChatPointClaimablesItems> items { get; set; } = new();
}
public class AIChatPointClaimablesItems
{
public int start_time { get; set; } = 0;
public int end_time { get; set; } = 0;
public int amount { get; set; } = 0;
public int log_count { get; set; } = 0;
}
public class AIChatPointHistory
{
public int page { get; set; } = 0;
public int numPerPage { get; set; } = 0;
public int total { get; set; } = 0;
public List<AIChatPointHistoryItems> items { get; set; } = new();
}
public class AIChatPointHistoryItems
{
public string created_date { get; set; } = string.Empty;
public int sum_of_spend_free { get; set; } = 0;
public int sum_of_earn_free { get; set; } = 0;
public int sum_of_charge_free { get; set; } = 0;
public int sum_of_spend_nonfree { get; set; } = 0;
public int sum_of_earn_nonfree { get; set; } = 0;
public int sum_of_charge_nonfree { get; set; } = 0;
public int free_points_balance { get; set; } = 0;
public int nonfree_points_balance { get; set; } = 0;
}
public class AIChatPointCharge
{
public double points { get; set; } = 0;
public string pointType { get; set; } = string.Empty;
public string userGuid { get; set; } = string.Empty;
public string orderGuid { get; set; } = string.Empty;
public string description { get; set; } = string.Empty;
}
public class AIChatSetting
{
public string id { get; set; } = string.Empty;
public string model { get; set; } = string.Empty;
public AIChatPoint point { get; set; } = new AIChatPoint();
public bool enabled { get; set; } = false;
public int token_limit { get; set; } = 0;
public AIChatOptions options { get; set; } = new AIChatOptions();
}
public class AIChatPoint
{
public int cost { get; set; } = 0;
public int share { get; set; } = 0;
}
public class AIChatOptions
{
public float temperature { get; set; } = 0;
public float top_p { get; set; } = 0;
}
public class AIChatRegisterUser
{
public string nick { get; set; } = string.Empty;
public AIChatRegisterUserSetting settings { get; set; } = new();
}
public class AIChatRegisterUserSetting
{
public string defaultModel { get; set; } = ServerCommon.Constant.AI_CHAT_DEFAULT_MODEL;
}
public class AIChatRanking
{
public List<AIChatRankingData> items { get; set; } = new();
public int page { get; set; } = 0;
public int numPerPage { get; set; } = 0;
public int total { get; set; } = 0;
public int start_at { get; set; } = 0;
public int end_at { get; set; } = 0;
}
public class AIChatRankingData
{
public string char_guid { get; set; } = string.Empty;
public string owner_guid { get; set; } = string.Empty;
public string owner_nick { get; set; } = string.Empty;
public string char_name { get; set; } = string.Empty;
public int total_chat_count { get; set; } = 0;
}
public class AIChatCharacter
{
public string itemId { get; set; } = string.Empty;
public AIChatCharacterInfo data { get; set; } = new();
}
public class AIChatCharacterInfo
{
public string guid { get; set; } = string.Empty;
public string owner_guid { get; set; } = string.Empty;
public Int64 chat_count { get; set; } = 0;
public List<AIChatSocialActionConfig> socialActionConfig = new();
public string created_at { get; set; } = string.Empty;
public string updated_at { get; set; } = string.Empty;
public bool is_official { get; set; } = false;
public AiChatCharacterLocales locale { get; set; } = new();
public List<META_ID> tags { get; set; } = new();
}
public class AiChatCharacterLocales
{
AiChatCharacterLocale en = new();
AiChatCharacterLocale ko = new();
AiChatCharacterLocale ja = new();
}
public class AiChatCharacterLocale
{
public string id { get; set; } = string.Empty;
public string lang { get; set; } = string.Empty;
public string name { get; set; } = string.Empty;
public string persona { get; set; } = string.Empty;
public string first_mes { get; set; } = string.Empty;
public string secrets { get; set; } = string.Empty;
public string short_desc { get; set; } = string.Empty;
public string created_at { get; set; } = string.Empty;
public string updated_at { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,32 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class AIChatBusinessLog : ILogInvokerEx
{
private AIChatLogData m_data_to_log;
public AIChatBusinessLog(AIChatLogData log_data_param)
: base(LogDomainType.AIChat)
{
m_data_to_log = log_data_param;
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(new AIChatLogData(this, m_data_to_log));
}
}

View File

@@ -0,0 +1,25 @@
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using META_ID = System.UInt32;
namespace GameServer
{
static public class AIChatBusinessLogHelper
{
static public AIChatLogData toLogInfo(string URL, string bodyParamJson)
{
var logData = new AIChatLogData();
logData.setInfo(URL, bodyParamJson);
return logData;
}
static public void setInfo(this AIChatLogData logData, string URL, string bodyParamJson)
{
logData.AIChatURL = URL;
logData.AIChatBodyParamJson = bodyParamJson;
}
}
}

View File

@@ -0,0 +1,97 @@
using Google.Protobuf;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler
{
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_AICHAT_AUTH), typeof(AIChatAuthPacketHandler), typeof(GameLoginListener))]
public class AIChatAuthPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_AICHAT_AUTH(Player player, Result result, string? jwt = null, int leftTime = 0)
{
var err_msg = string.Empty;
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.AckAIChatAuth = new GS2C_ACK_AICHAT_AUTH();
ack_packet.Response.AckAIChatAuth.Jwt = jwt ?? string.Empty;
ack_packet.Response.AckAIChatAuth.LeftTime = leftTime;
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var player_action = player.getEntityAction<PlayerAction>();
NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {player.toBasicString()}");
var ai_chat_action = player.getEntityAction<AIChatAction>();
NullReferenceCheckHelper.throwIfNull(ai_chat_action, () => $"ai_chat_action is null !!! - {player.toBasicString()}");
(result, var jwt) = await ai_chat_action.jwtIssue(player.getUserGuid());
if(result.ErrorCode == ServerErrorCode.AiChatServerUserNotFound)
{
result = await ai_chat_action.registerUser(player.getUserGuid(), player.getUserNickname());
if (result.isFail())
{
err_msg = $"Failed Register User : {player.getUserGuid()}";
Log.getLogger().error(err_msg);
send_S2C_ACK_AICHAT_AUTH(player, result);
return result;
}
(result, jwt) = await ai_chat_action.jwtIssue(player.getUserGuid());
}
if(result.isFail() || string.IsNullOrEmpty(jwt))
{
send_S2C_ACK_AICHAT_AUTH(player, result);
return result;
}
(result, var jwtInfo) = await ai_chat_action.jwtverify(jwt);
if (result.isFail() || jwt == null)
{
send_S2C_ACK_AICHAT_AUTH(player, result);
return result;
}
NullReferenceCheckHelper.throwIfNull(jwtInfo, () => $"jwtInfo is null !!");
send_S2C_ACK_AICHAT_AUTH(player, result, jwt, jwtInfo.exp - jwtInfo.iat);
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_AICHAT_AUTH(player, errorResult);
}
}
}

View File

@@ -0,0 +1,69 @@
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json.Nodes;
using static System.Net.Mime.MediaTypeNames;
using static System.Runtime.InteropServices.JavaScript.JSType;
using Newtonsoft.Json;
using Amazon.Runtime.Internal.Endpoints.StandardLibrary;
using Amazon.Runtime.Internal.Transform;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using ServerCore; using ServerBase;
using ServerCommon;
using static ServerCommon.MetaHelper;
using static ServerCommon.BusinessLogDomain.MailLogData;
using GameServer.PacketHandler;
namespace GameServer
{
public class AdvertisementAction : EntityActionBase
{
public AdvertisementAction(Player owner)
: base(owner)
{
}
public override Task<Result> onInit()
{
var result = new Result();
return Task.FromResult(result);
}
public override void onClear()
{
}
public async Task<(Result, int)> selectAdvertisement(int interiorId)
{
await Task.CompletedTask;
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
if (MetaData.Instance._InteriorMetaTable.TryGetValue(interiorId, out var interiorMeta) == false)
{
result.setFail(ServerErrorCode.InteriorMetaDataNotFound, err_msg);
return (result, -1);
}
int index = Random.Shared.Next(interiorMeta.AdPath.Count);
return (result, index);
}
}
}

View File

@@ -0,0 +1,56 @@
using Google.Protobuf;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_SELECT_ADVERTISEMENT), typeof(AdvertisementPacketHandler), typeof(GameLoginListener))]
public class AdvertisementPacketHandler : PacketRecvHandler
{
public static bool send_GS2C_ACK_SELECT_ADVERTISEMENT(Player player, Result result, int index)
{
var err_msg = string.Empty;
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.AckSelectAdvertisement = new GS2C_ACK_SELECT_ADVERTISEMENT();
ack_packet.Response.AckSelectAdvertisement.Index = index;
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var request = (recvMessage as ClientToGame)?.Request.ReqSelectAdvertisement;
NullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!!");
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var advertisement_action = player.getEntityAction<AdvertisementAction>();
NullReferenceCheckHelper.throwIfNull(advertisement_action, () => $"ai_chat_action is null !!! - {player.toBasicString()}");
(result, int index) = await advertisement_action.selectAdvertisement(request.InteriorId);
send_GS2C_ACK_SELECT_ADVERTISEMENT(player, result, index);
return result;
}
}

View File

@@ -0,0 +1,141 @@

using ServerCore;
using ServerBase;
using ServerCommon;
namespace GameServer;
public class BeaconAppearanceCustomizeAction : EntityActionBase
{
public BeaconAppearanceCustomizeAction(UgcNpc 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> tryLoadAppearanceCustomizeFromDoc(AppearanceCustomizeDoc appearanceCustomizeDoc)
{
var beacon = getOwner() as UgcNpc;
NullReferenceCheckHelper.throwIfNull(beacon, () => $"beacon is null !!!");
NullReferenceCheckHelper.throwIfNull(appearanceCustomizeDoc, () => $"appearanceCustomizeDoc is null !!! - {beacon.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
var appearance_customize_attrib = appearanceCustomizeDoc.getAttrib<AppearanceCustomizeAttrib>();
NullReferenceCheckHelper.throwIfNull(appearance_customize_attrib, () => $"appearance_customize_attrib is null !!! - {beacon.toBasicString()}");
var appearance_customize_attribute = beacon.getEntityAttribute<AppearanceCustomizeAttribute>();
NullReferenceCheckHelper.throwIfNull(appearance_customize_attribute, () => $"appearance_customize_attribute is null !!!");
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromDocs(appearance_customize_attribute, new List<DynamoDbDocBase>() { appearanceCustomizeDoc });
if (result.isFail())
{
err_msg = $"Failed to copyEntityAttributeFromDocs() !!!, to:{appearance_customize_attribute.getTypeName()}, from:{appearanceCustomizeDoc.getTypeName()} : {result.toBasicString()} - {beacon.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
return result;
}
public async Task<Result> tryCustomizeAppearance(AppearanceCustomization appearCustomize)
{
var beacon = getOwner() as UgcNpc;
NullReferenceCheckHelper.throwIfNull(beacon, () => $"beacon is null !!!");
var player = beacon.onGetMasterEntity();
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
ArgumentNullReferenceCheckHelper.throwIfNull(appearCustomize, () => $"appearCustomize is null !!!");
var result = new Result();
var err_msg = string.Empty;
var ugcn_npc_action = beacon.getEntityAction<UgcNpcAction>();
NullReferenceCheckHelper.throwIfNull(ugcn_npc_action, () => $"ugcn_npc_action is null !!! - {player.toBasicString()}");
//=====================================================================================
// 1. 비컨의 배치 상태를 체크 한다.
//=====================================================================================
if (true == ugcn_npc_action.isLocatedUgcNpc())
{
err_msg = $"UgcNpc located state !!! : {beacon.toSummaryString()} - {player.toBasicString()}";
result.setFail(ServerErrorCode.UgcNpcLocatedState, err_msg);
return result;
}
//=====================================================================================
// 2. 금전을 소모 한다.
//=====================================================================================
var money_action = player.getEntityAction<MoneyAction>();
NullReferenceCheckHelper.throwIfNull(money_action, () => $"money_action is null !!! - {player.toBasicString()}");
var req_currency_type = (CurrencyType)ServerCommon.MetaHelper.GameConfigMeta.NpcCustomizeCostType;
result = await money_action.spendMoney(req_currency_type, ServerCommon.MetaHelper.GameConfigMeta.NpcCustomizeCost);
if (result.isFail())
{
return result;
}
//=====================================================================================
// 3. 비컨 외형 커스마이징 정보를 갱신 한다.
//=====================================================================================
updateAppearanceCustomize(appearCustomize);
return result;
}
private void updateAppearanceCustomize(AppearanceCustomization appearCustomize)
{
ArgumentNullReferenceCheckHelper.throwIfNull(appearCustomize, () => $"appearCustomize is null !!!");
var beacon = getOwner() as UgcNpc;
NullReferenceCheckHelper.throwIfNull(beacon, () => $"beacon is null !!!");
var player = beacon.onGetMasterEntity();
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var appearance_customize_attribute = beacon.getEntityAttribute<AppearanceCustomizeAttribute>();
NullReferenceCheckHelper.throwIfNull(appearance_customize_attribute, () => $"appearance_customize_attribute is null !!!");
appearance_customize_attribute.BasicStyle = appearCustomize.BasicStyle;
appearance_customize_attribute.BodyShape = appearCustomize.BodyShape;
appearance_customize_attribute.HairStyle = appearCustomize.HairStyle;
appearance_customize_attribute.CustomValues = appearCustomize.CustomValues.ToList();
appearance_customize_attribute.modifiedEntityAttribute(true);
}
public AppearanceCustomization toAppearanceCustomization()
{
var beacon = getOwner() as UgcNpc;
NullReferenceCheckHelper.throwIfNull(beacon, () => $"beacon is null !!!");
var appearance_customize_attribute = beacon.getEntityAttribute<AppearanceCustomizeAttribute>();
NullReferenceCheckHelper.throwIfNull(appearance_customize_attribute, () => $"appearance_customize_attribute is null !!!");
var appearance_customize = new AppearanceCustomization();
appearance_customize.BasicStyle = appearance_customize_attribute.BasicStyle;
appearance_customize.BodyShape = appearance_customize_attribute.BodyShape;
appearance_customize.HairStyle = appearance_customize_attribute.HairStyle;
appearance_customize.CustomValues.AddRange(appearance_customize_attribute.CustomValues.ToList());
return appearance_customize;
}
}

View File

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static StackExchange.Redis.Role;
using ServerCore; using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using static ServerCommon.MetaHelper;
using GameServer;
namespace GameServer
{
public class CharacterAppearanceCustomizeAction : EntityActionBase
{
public CharacterAppearanceCustomizeAction(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 async Task<(Result, CharacterAttribute.AppearanceProfile?)> tryCustomizeAppearance(AppearanceCustomization appearCustomize)
{
ArgumentNullReferenceCheckHelper.throwIfNull(appearCustomize, () => $"appearCustomize is null !!!");
var character = getOwner() as Character;
NullReferenceCheckHelper.throwIfNull(character, () => $"character is null !!!");
var player = character.getRootParent() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var result = new Result();
var err_msg = string.Empty;
//=====================================================================================
// 1. 금전을 소모 한다.
//=====================================================================================
var money_action = player.getEntityAction<MoneyAction>();
NullReferenceCheckHelper.throwIfNull(money_action, () => $"money_action is null !!! - {player.toBasicString()}");
var req_currency_type = (CurrencyType)ServerCommon.MetaHelper.GameConfigMeta.CharacterCustomizeCostType;
result = await money_action.spendMoney(req_currency_type, GameConfigMeta.CharacterCustomizeCost);
if (result.isFail())
{
return (result, null);
}
//=====================================================================================
// 2. 캐릭터 외형 커스마이징 정보를 갱신 한다.
//=====================================================================================
var appearance_profile = updateAppearanceCustomize(appearCustomize);
NullReferenceCheckHelper.throwIfNull(appearance_profile, () => $"appearance_profile is null !!! - {player.toBasicString()}");
return (result, appearance_profile);
}
private CharacterAttribute.AppearanceProfile updateAppearanceCustomize(AppearanceCustomization appearCustomize)
{
ArgumentNullReferenceCheckHelper.throwIfNull(appearCustomize, () => $"appearCustomize is null !!!");
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.BasicStyle = (UInt32)appearCustomize.BasicStyle;
appearance_profile.BodyShape = (UInt32)appearCustomize.BodyShape;
appearance_profile.HairStyle = (UInt32)appearCustomize.HairStyle;
appearance_profile.CustomValues = appearCustomize.CustomValues.ToList();
character_attribute.modifiedEntityAttribute();
return appearance_profile;
}
}
}

View File

@@ -0,0 +1,189 @@
using System.Collections.Concurrent;
using Amazon.S3.Model;
using ServerCore; using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
namespace GameServer;
[ChatCommandAttribute("charappearcustom", typeof(ChatCharacterCustomize), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
public class ChatCharacterCustomize : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"Call charappearcustom !!! - {player.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
if (args.Length < 3)
{
err_msg = $"Not enough argument !!! : argCount:{args.Length} == 1 - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
var read_params = new List<int>();
for (var i = 0; i < 3; i++)
{
var param = args[i];
if (true == param.isNullOrWhiteSpace())
{
err_msg = $"Arg {i} is Empty !!! - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
if (false == int.TryParse(param, out var value))
{
err_msg = $"Failed to TryParse() !!! - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
read_params.Add(value);
}
var player_action = player.getEntityAction<PlayerAction>();
NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!!");
var selected_character = player_action.getSelectedCharacter();
NullReferenceCheckHelper.throwIfNull(selected_character, () => $"selected_character is null !!!");
var character_attribute = selected_character.getEntityAttribute<CharacterAttribute>();
NullReferenceCheckHelper.throwIfNull(character_attribute, () => $"character_attribute is null !!!");
var to_change_character_guid = character_attribute.CharacterGuid;
var appearance_customize = new AppearanceCustomization();
appearance_customize.BasicStyle = read_params[0];
appearance_customize.BodyShape = read_params[1];
appearance_customize.HairStyle = read_params[2];
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {player.toBasicString()}");
var session = player as IEntityWithSession;
NullReferenceCheckHelper.throwIfNull(session, () => $"session is null !!! - {player.toBasicString()}");
//=====================================================================================
// 패킷 구성
//=====================================================================================
var packet = new ClientToGame();
packet.Request = new ClientToGameReq();
var req_msg = new C2GS_REQ_CHARACTER_APPEARANCE_CUSTOMIZE();
packet.Request.ReqCharacterAppearanceCustomize = req_msg;
req_msg.ToChangeCharacterGuid = to_change_character_guid;
req_msg.ToApplyAppearCustomize = appearance_customize;
result = await server_logic.onCallProtocolHandler(session, packet);
if (result.isFail())
{
err_msg = $"Failed to onCallProtocolHandler() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
}
}
[ChatCommandAttribute("beaconappearcustom", typeof(BeaconCharacterCustomize), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
public class BeaconCharacterCustomize : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"Call beaconappearcustom !!! - {player.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
if (args.Length < 3)
{
err_msg = $"Not enough argument !!! : argCount:{args.Length} == 1 - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
var read_params = new List<int>();
for (var i = 0; i < 3; i++)
{
var param = args[i];
if (true == param.isNullOrWhiteSpace())
{
err_msg = $"Arg {i} is Empty !!! - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
if (false == int.TryParse(param, out var value))
{
err_msg = $"Failed to TryParse() !!! - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
read_params.Add(value);
}
var player_action = player.getEntityAction<PlayerAction>();
NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!!");
var had_ugc_npcs = player_action.getHadUgcNpcs().Values.ToList();
NullReferenceCheckHelper.throwIfNull(had_ugc_npcs, () => $"had_ugc_npcs is null !!!");
if(0 >= had_ugc_npcs.Count)
{
err_msg = $"Had not Beacon !!! : 0 < hadCount:{had_ugc_npcs.Count} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
var selected_seq = RandomHelper.next(0, had_ugc_npcs.Count() - 1);
var selected_ugc_npc = had_ugc_npcs[selected_seq];
var beacon_attribute = selected_ugc_npc.getEntityAttribute<UgcNpcAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_attribute, () => $"beacon_attribute is null !!!");
var to_change_beacon_meta_guid = beacon_attribute.UgcNpcMetaGuid;
var appearance_customize = new AppearanceCustomization();
appearance_customize.BasicStyle = read_params[0];
appearance_customize.BodyShape = read_params[1];
appearance_customize.HairStyle = read_params[2];
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {player.toBasicString()}");
var session = player as IEntityWithSession;
NullReferenceCheckHelper.throwIfNull(session, () => $"session is null !!! - {player.toBasicString()}");
//=====================================================================================
// 패킷 구성
//=====================================================================================
var packet = new ClientToGame();
packet.Request = new ClientToGameReq();
var req_msg = new C2GS_REQ_BEACON_APPEARANCE_CUSTOMIZE();
packet.Request.ReqBeaconAppearanceCustomize = req_msg;
req_msg.ToChangeUgcNpcMetaGuid = to_change_beacon_meta_guid;
req_msg.ToApplyAppearCustomize = appearance_customize;
result = await server_logic.onCallProtocolHandler(session, packet);
if (result.isFail())
{
err_msg = $"Failed to onCallProtocolHandler() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
}
}

View File

@@ -0,0 +1,177 @@
using Google.Protobuf;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameRes.Types;
using BEACON_META_GUID = System.String;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_BEACON_APPEARANCE_CUSTOMIZE), typeof(BeaconAppearanceCustomizePacketHandler), typeof(GameLoginListener))]
public class BeaconAppearanceCustomizePacketHandler : PacketRecvHandler
{
public override async Task onProcessPacketException( ISession entityWithSession, Google.Protobuf.IMessage recvMessage
, Result errorResult )
{
await Task.CompletedTask;
ArgumentNullReferenceCheckHelper.throwIfNull(entityWithSession);
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
var recv_msg = recvMessage as ClientToGame;
NullReferenceCheckHelper.throwIfNull(recv_msg, () => $"recv_msg is null !!! - {player.toBasicString()}");
var request = recv_msg.Request.ReqBeaconAppearanceCustomize;
NullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {player.toBasicString()}");
send_GS2C_ACK_BEACON_APPEARANCE_CUSTOMIZE(player, errorResult, request.ToChangeUgcNpcMetaGuid);
}
private static bool send_GS2C_ACK_BEACON_APPEARANCE_CUSTOMIZE( Player owner, Result result
, BEACON_META_GUID beaconMetaGuid
, AppearanceCustomization? appearCustomize = null )
{
ArgumentNullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
ArgumentNullReferenceCheckHelper.throwIfNull(result, () => $"result is null !!!");
var server_logic = GameServerApp.getServerLogic();
var err_msg = string.Empty;
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
var ack_msg = new GS2C_ACK_BEACON_APPEARANCE_CUSTOMIZE();
ack_packet.Response.AckBeaconAppearanceCustomize = ack_msg;
ack_msg.ToChangeUgcNpcMetaGuid = beaconMetaGuid;
if (result.isSuccess())
{
ArgumentNullReferenceCheckHelper.throwIfNull(appearCustomize, () => $"appearCustomize is null !!!");
ack_msg.AppearCustomize = appearCustomize;
var found_transaction_runner = owner.findTransactionRunner(TransactionIdType.PrivateContents);
if (null == found_transaction_runner)
{
err_msg = $"Not found TransactionRunner !!! : {owner.toBasicString()}";
Log.getLogger().error(err_msg);
}
else
{
ack_msg.CommonResult = found_transaction_runner.getCommonResult();
}
}
if (false == server_logic.onSendPacket(owner, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, Google.Protobuf.IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var recv_msg = recvMessage as ClientToGame;
NullReferenceCheckHelper.throwIfNull(recv_msg, () => $"recv_msg is null !!! - {player.toBasicString()}");
var request = recv_msg.Request.ReqBeaconAppearanceCustomize;
NullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {player.toBasicString()}");
var to_change_beacon_meta_guid = request.ToChangeUgcNpcMetaGuid;
var player_action = player.getEntityAction<PlayerAction>();
NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {player.toBasicString()}");
var selected_character = player_action.getSelectedCharacter();
if (null == selected_character)
{
err_msg = $"Not selected Character !!! - {player.toBasicString()}";
result.setFail(ServerErrorCode.CharacterNotSelected, err_msg);
Log.getLogger().error(result.toBasicString());
send_GS2C_ACK_BEACON_APPEARANCE_CUSTOMIZE(player, result, to_change_beacon_meta_guid);
return result;
}
var server_logic = GameServerApp.getServerLogic();
var fn_beacon_appearance_customize = async delegate ()
{
var result = new Result();
var found_beacon = player_action.findUgcNpc(to_change_beacon_meta_guid);
if(null == found_beacon)
{
err_msg = $"Not found Beacon !!! : BeaconMetaGuid:{to_change_beacon_meta_guid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
send_GS2C_ACK_BEACON_APPEARANCE_CUSTOMIZE(player, result, to_change_beacon_meta_guid);
return result;
}
var appearance_customize_action = found_beacon.getEntityAction<BeaconAppearanceCustomizeAction>();
NullReferenceCheckHelper.throwIfNull(appearance_customize_action, () => $"appearance_customize_action is null !!! - {player.toBasicString()}");
result = await appearance_customize_action.tryCustomizeAppearance(request.ToApplyAppearCustomize);
if (result.isFail())
{
err_msg = $"Failed to tryCustomizeAppearance() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
send_GS2C_ACK_BEACON_APPEARANCE_CUSTOMIZE(player, result, to_change_beacon_meta_guid);
return result;
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>( player, LogActionType.BeaconAppearanceCustomize
, server_logic.getDynamoDbClient()
, true );
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
batch.addQuery(new QueryFinal());
}
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
send_GS2C_ACK_BEACON_APPEARANCE_CUSTOMIZE(player, result, to_change_beacon_meta_guid);
return result;
}
send_GS2C_ACK_BEACON_APPEARANCE_CUSTOMIZE( player, result
, to_change_beacon_meta_guid
, appearance_customize_action.toAppearanceCustomization());
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "BeaconAppearanceCostomize", fn_beacon_appearance_customize);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
return result;
}
}

View File

@@ -0,0 +1,174 @@
using Google.Protobuf;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameRes.Types;
using CHARACTER_GUID = System.String;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_CHARACTER_APPEARANCE_CUSTOMIZE), typeof(CharacterAppearanceCustomizePacketHandler), typeof(GameLoginListener))]
public class CharacterAppearanceCustomizePacketHandler : PacketRecvHandler
{
public override async Task onProcessPacketException( ISession entityWithSession, Google.Protobuf.IMessage recvMessage
, Result errorResult )
{
await Task.CompletedTask;
ArgumentNullReferenceCheckHelper.throwIfNull(entityWithSession);
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
var recv_msg = recvMessage as ClientToGame;
NullReferenceCheckHelper.throwIfNull(recv_msg, () => $"recv_msg is null !!! - {player.toBasicString()}");
var request = recv_msg.Request.ReqCharacterAppearanceCustomize;
NullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {player.toBasicString()}");
send_GS2C_ACK_CHARACTER_APPEARANCE_CUSTOMIZE(player, errorResult, request.ToChangeCharacterGuid);
}
private static bool send_GS2C_ACK_CHARACTER_APPEARANCE_CUSTOMIZE( Player owner, Result result
, CHARACTER_GUID characterGuid
, AppearanceCustomization? appearCustomize = null)
{
ArgumentNullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
ArgumentNullReferenceCheckHelper.throwIfNull(result, () => $"owner is null !!!");
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!!");
var err_msg = string.Empty;
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
var ack_msg = new GS2C_ACK_CHARACTER_APPEARANCE_CUSTOMIZE();
ack_packet.Response.AckCharacterAppearanceCustomize = ack_msg;
ack_msg.ToChangeCharacterGuid = characterGuid;
if (result.isSuccess())
{
ArgumentNullReferenceCheckHelper.throwIfNull(appearCustomize, () => $"appearCustomize is null !!!");
ack_msg.AppearCustomize = appearCustomize;
var found_transaction_runner = owner.findTransactionRunner(TransactionIdType.PrivateContents);
if (null == found_transaction_runner)
{
err_msg = $"Not found TransactionRunner !!! : {owner.toBasicString()}";
Log.getLogger().error(err_msg);
}
else
{
ack_msg.CommonResult = found_transaction_runner.getCommonResult();
}
}
if (false == server_logic.onSendPacket(owner, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, Google.Protobuf.IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var recv_msg = recvMessage as ClientToGame;
NullReferenceCheckHelper.throwIfNull(recv_msg, () => $"recv_msg is null !!! - {player.toBasicString()}");
var request = recv_msg.Request.ReqCharacterAppearanceCustomize;
NullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {player.toBasicString()}");
var to_change_character_guid = request.ToChangeCharacterGuid; // 클라이언트는 USER_GUID를 사용 한다.
var player_action = player.getEntityAction<PlayerAction>();
NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {player.toBasicString()}");
var selected_character = player_action.getSelectedCharacter();
if (null == selected_character)
{
err_msg = $"Not selected Character !!! - {player.toBasicString()}";
result.setFail(ServerErrorCode.CharacterNotSelected, err_msg);
Log.getLogger().error(result.toBasicString());
send_GS2C_ACK_CHARACTER_APPEARANCE_CUSTOMIZE(player, result, to_change_character_guid);
return result;
}
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!!");
var fn_character_appearance_customize = async delegate ()
{
var result = new Result();
var character_action = selected_character.getEntityAction<CharacterAction>();
NullReferenceCheckHelper.throwIfNull(character_action, () => $"character_action is null !!! - {player.toBasicString()}");
var appearance_customize_action = selected_character.getEntityAction<CharacterAppearanceCustomizeAction>();
NullReferenceCheckHelper.throwIfNull(appearance_customize_action, () => $"appearance_customize_action is null !!! - {player.toBasicString()}");
(result, var aprearance_profile) = await appearance_customize_action.tryCustomizeAppearance(request.ToApplyAppearCustomize);
NullReferenceCheckHelper.throwIfNull(aprearance_profile, () => $"aprearance_profile is null !!!");
if (result.isFail())
{
err_msg = $"Failed to tryCustomizeAppearance() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
send_GS2C_ACK_CHARACTER_APPEARANCE_CUSTOMIZE(player, result, to_change_character_guid);
return result;
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>( player, LogActionType.CharacterAppearanceCustomize
, server_logic.getDynamoDbClient()
, true);
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
batch.addQuery(new QueryFinal());
}
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
send_GS2C_ACK_CHARACTER_APPEARANCE_CUSTOMIZE(player, result, to_change_character_guid);
return result;
}
send_GS2C_ACK_CHARACTER_APPEARANCE_CUSTOMIZE( player, result
, to_change_character_guid
, aprearance_profile.toCharacterAppearanceCustomize4Client() );
// 주변 엔티티들에게 통지 한다.
character_action.broadcastCharacterInfo();
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "CharacterAppearanceCostomize", fn_character_appearance_customize);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
return result;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,266 @@
using ServerCommon;
using ServerCore; using ServerBase;
using System.Net.WebSockets;
using static ServerCommon.MetaHelper;
namespace GameServer;
[ChatCommandAttribute("beaconshopregisteritem", typeof(CheatBeaconShopregisterItem), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class CheatBeaconShopregisterItem : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"CheatBeaconShopregisterItem");
if (args.Length < 1)
{
Log.getLogger().error($"Invalid Argument");
return;
}
if (uint.TryParse(args[0], out uint item_meta_id) == false)
return;
var beacon_shop_action = player.getEntityAction<BeaconShopAction>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_action, () => $"beacon_shop_action is null !!! - {player.toBasicString()}");
var inventory_action = player.getEntityAction<InventoryActionBase>();
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!! - {player.toBasicString()}");
var item_list = inventory_action.tryGetItemAllByItemMetaId(item_meta_id);
if (item_list.Count == 0)
return;
var item_attribute = item_list[0].getEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(item_attribute, () => $"item_attribute is null !!! - {player.toBasicString()}");
var player_action = player.getEntityAction<PlayerAction>();
var ugc_npc_dictionary = player_action.getHadUgcNpcs();
if (ugc_npc_dictionary.Count == 0)
{
return;
}
var npc_attribute = ugc_npc_dictionary.First().Value.getEntityAttribute<UgcNpcAttribute>();
NullReferenceCheckHelper.throwIfNull(npc_attribute, () => $"npc_attribute is null !!! - {player.toBasicString()}");
var result = await beacon_shop_action.tryRegisterItemToBeaconShop(item_attribute.ItemGuid, 1, 0.1, npc_attribute.UgcNpcMetaGuid);
if (result.isFail())
{
return;
}
return;
}
}
[ChatCommandAttribute("beaconshopreturn", typeof(CheatBeaconShopReturn), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class CheatBeaconShopReturn : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"CheatBeaconShopReturn");
if (args.Length < 2)
{
Log.getLogger().error($"Invalid Argument");
return;
}
var itemGuid = args[0];
var beaconGuid = args[1];
var beacon_shop_action = player.getEntityAction<BeaconShopAction>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_action, () => $"beacon_shop_action is null !!! - {player.toBasicString()}");
var result = await beacon_shop_action.BeaconShopReturnItem(itemGuid, beaconGuid);
if (result.isFail())
{
return;
}
return;
}
}
[ChatCommandAttribute("beaconshoppurchaseitem", typeof(CheatBeaconShopPurchaseItem), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class CheatBeaconShopPurchaseItem : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"CheatBeaconShopreturn");
if (args.Length < 4)
{
Log.getLogger().error($"Invalid Argument");
return;
}
var itemGuid = args[0];
if (ushort.TryParse(args[1], out ushort itemAmount) == false)
return;
var beaconGuid = args[2];
var beaconOwnerGuid = args[3];
var beacon_shop_action = player.getEntityAction<BeaconShopAction>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_action, () => $"beacon_shop_action is null !!! - {player.toBasicString()}");
var result = await beacon_shop_action.BeaconShopPurchaseItem(itemGuid, itemAmount, beaconGuid, beaconOwnerGuid);
if (result.isFail())
{
return;
}
return;
}
}
[ChatCommandAttribute("beaconshopreceivepayment", typeof(CheatBeaconShopReceivePayment), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class CheatBeaconShopReceivePayment : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"CheatBeaconShopReceivePayment");
if (args.Length < 1)
{
Log.getLogger().error($"Invalid Argument");
return;
}
var beaconGuid = args[0];
var beacon_shop_action = player.getEntityAction<BeaconShopAction>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_action, () => $"beacon_shop_action is null !!! - {player.toBasicString()}");
var result = await beacon_shop_action.BeaconShopReceivePaymentForSales(beaconGuid);
if (result.isFail())
{
return;
}
return;
}
}
[ChatCommandAttribute("beaconshopitemtimechange", typeof(CheatBeaconShopItemTimeChange), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class CheatBeaconShopItemTimeChange : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"CheatBeaconShopItemTimeChange");
var result = new Result();
var err_msg = string.Empty;
if (args.Length < 1)
{
Log.getLogger().error($"Invalid Argument");
return;
}
if (int.TryParse(args[0], out int minutes) == false)
return;
var server_logic = GameServerApp.getServerLogic();
var fn_start = async delegate ()
{
var player_action = player.getEntityAction<PlayerAction>();
var npcs = player_action.getHadUgcNpcs();
foreach (var npc in npcs)
{
var ugc_npc_beacon_shop_action = npc.Value.getEntityAction<UgcNpcBeaconShopAction>();
var beaconShopItems = ugc_npc_beacon_shop_action.getHasBeaconShopItem();
foreach (var beaconShopItem in beaconShopItems)
{
var beacon_shop_item_attribute = beaconShopItem.getEntityAttribute<BeaconShopItemAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_item_attribute, () => $"beacon_shop_item_attribute is null !!!");
var cheat_selling_finish_time = DateTime.UtcNow.AddMinutes(minutes);
beacon_shop_item_attribute.SellingFinishTime = cheat_selling_finish_time;
beacon_shop_item_attribute.modifiedEntityAttribute();
}
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CheatCommandBeaconShopItemTimeChange
, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
var result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
return result;
}
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "CheatBeaconShopItemTimeChange", fn_start);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return;
}
}
[ChatCommandAttribute("beaconshopdailylimitinit", typeof(CheatBeaconShopDailyLimitInit), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class CheatBeaconShopDailyLimitInit : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"CheatBeaconShopdailylimitinit");
var result = new Result();
var err_msg = string.Empty;
var server_logic = GameServerApp.getServerLogic();
var fn_start = async delegate ()
{
var player_action = player.getEntityAction<PlayerAction>();
var npcs = player_action.getHadUgcNpcs();
foreach (var npc in npcs)
{
var beacon_shop_profile_attribute = npc.Value.getEntityAttribute<BeaconShopProfileAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_profile_attribute, () => $"beacon_shop_item_attribute is null !!!");
beacon_shop_profile_attribute.DailyRegisterCount = 0;
beacon_shop_profile_attribute.modifiedEntityAttribute();
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CheatCommandDailyLimitInit
, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
var result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
return result;
}
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "CheatBeaconShopdailylimitinit", fn_start);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return;
}
}

View File

@@ -0,0 +1,140 @@
using Google.Protobuf.WellKnownTypes;
using ServerCommon;
using ServerCore; using ServerBase;
using BEACON_GUID = System.String;
using USER_GUID = System.String;
namespace GameServer
{
public class BeaconShopItem : Item
{
public BeaconShopItem(UgcNpc owner)
: base(owner)
{
}
public override async Task<Result> onInit()
{
var direct_parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(direct_parent, () => $"direct_parent is null !!!");
addEntityAttribute(new BeaconShopItemAttribute(this, direct_parent));
return await base.onInit();
}
public override string toBasicString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public override string toSummaryString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public static async Task<(Result, BeaconShopItem?)> createBeaconShopFromDoc(UgcNpc owner, BeaconShopItemDoc doc)
{
var beacon_shop_item = new BeaconShopItem(owner);
var result = await beacon_shop_item.onInit();
if (result.isFail())
{
return (result, null);
}
var err_msg = string.Empty;
var beacon_shop_attribute = beacon_shop_item.getEntityAttribute<BeaconShopItemAttribute>();
if (beacon_shop_attribute == null)
{
err_msg = $"Failed to get beacon shop attribute : {nameof(BeaconShopItemAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
if (beacon_shop_attribute.copyEntityAttributeFromDoc(doc) == false)
{
err_msg = $"Failed to copyEntityAttributeFromDoc !!! : doc_type {doc.GetType()} - {beacon_shop_item.getRootParent().toBasicString()}";
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
return (result, beacon_shop_item);
}
public static async Task<(Result, BeaconShopItem?)> createBeaconShop(UgcNpc owner, USER_GUID user_guid, BEACON_GUID beacon_guid, DateTime selling_finish_time, double price_for_unit, ushort amount, ItemAttributeBase deleted_item_attribute)
{
var err_msg = string.Empty;
var beacon_shop_item = new BeaconShopItem(owner);
var result = await beacon_shop_item.onInit();
if (result.isFail())
{
err_msg = $"Failed to create onInit!!";
Log.getLogger().error(err_msg);
return (result, null);
}
var beacon_shop_attribute = beacon_shop_item.getEntityAttribute<BeaconShopItemAttribute>();
if (beacon_shop_attribute == null)
{
err_msg = $"Failed to get beacon shop attribute : {nameof(BeaconShopItemAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
beacon_shop_attribute.UserGuid = user_guid;
beacon_shop_attribute.BeaconGuid = beacon_guid;
beacon_shop_attribute.SellingFinishTime = selling_finish_time;
beacon_shop_attribute.PriceForUnit = price_for_unit;
beacon_shop_attribute.ItemMetaId = deleted_item_attribute.ItemMetaId;
beacon_shop_attribute.ItemStackCount = amount;
beacon_shop_attribute.Level = deleted_item_attribute.Level;
beacon_shop_attribute.Attributes = deleted_item_attribute.Attributes.Select(x => x).ToList();
beacon_shop_attribute.EquipedIvenType = deleted_item_attribute.EquipedIvenType;
beacon_shop_attribute.EquipedPos = deleted_item_attribute.EquipedPos;
beacon_shop_attribute.newEntityAttribute();
return (result, beacon_shop_item);
}
public override MetaAssets.ItemMetaData? getItemMeta()
{
var parent = getRootParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var beacon_shop_item_attribute = getEntityAttribute<BeaconShopItemAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_item_attribute, () => $"beacon_shop_item_attribute is null !!! - {parent.toBasicString()}");
if (!MetaData.Instance._ItemTable.TryGetValue((int)beacon_shop_item_attribute.ItemMetaId, out var found_item_meta_data))
{
var err_msg = $"Not found meta of Item !!! : itemMetaId:{beacon_shop_item_attribute.ItemMetaId} - {parent.toBasicString()}";
Log.getLogger().error(err_msg);
return null;
}
return found_item_meta_data;
}
public BeaconShopInfo toBeaconShopData4Client()
{
var beacon_shop_4_client = new BeaconShopInfo();
var beacon_shop_attribute = getEntityAttribute<BeaconShopItemAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_attribute, () => $"beacon_shop_attribute is null !!!");
beacon_shop_4_client.BeaconGuid = beacon_shop_attribute.BeaconGuid;
beacon_shop_4_client.ItemGuid = beacon_shop_attribute.ItemGuid;
beacon_shop_4_client.ItemMetaid = (int)beacon_shop_attribute.ItemMetaId;
beacon_shop_4_client.SellingFinishTime = Timestamp.FromDateTime(beacon_shop_attribute.SellingFinishTime);
beacon_shop_4_client.PriceForUnit = beacon_shop_attribute.PriceForUnit;
beacon_shop_4_client.Amount = beacon_shop_attribute.ItemStackCount;
return beacon_shop_4_client;
}
}
}

View File

@@ -0,0 +1,62 @@

using ServerCore;
using ServerBase;
using ServerCommon;
namespace GameServer;
public class BeaconShopSoldPrice : EntityBase
{
public BeaconShopSoldPrice(EntityBase owner)
: base(EntityType.BeaconShopSoldPrice, owner)
{
}
public override async Task<Result> onInit()
{
addEntityAttribute(new BeaconShopSoldPriceAttribute(this));
return await base.onInit();
}
public override string toBasicString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public override string toSummaryString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public static async Task<(Result, BeaconShopSoldPrice?)> createBeaconShopSoldPriceFromDoc(Player owner, BeaconShopSoldPriceDoc doc)
{
var beacon_shop_sold_price = new BeaconShopSoldPrice(owner);
var result = await beacon_shop_sold_price.onInit();
if (result.isFail())
{
return (result, null);
}
var err_msg = string.Empty;
var beacon_shop_sold_price_attribute = beacon_shop_sold_price.getEntityAttribute<BeaconShopSoldPriceAttribute>();
if (beacon_shop_sold_price_attribute == null)
{
err_msg = $"Failed to get beacon shop sold price attribute : {nameof(BeaconShopSoldPriceAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
if (beacon_shop_sold_price_attribute.copyEntityAttributeFromDoc(doc) == false)
{
err_msg = $"Failed to copyEntityAttributeFromDoc !!! : doc_type {doc.GetType()} - {beacon_shop_sold_price.getRootParent().toBasicString()}";
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
return (result, beacon_shop_sold_price);
}
}

View File

@@ -0,0 +1,83 @@
using Google.Protobuf.WellKnownTypes;
using ServerCommon;
using ServerCore; using ServerBase;
using BEACON_GUID = System.String;
using META_ID = System.UInt32;
namespace GameServer
{
public class BeaconShopSoldRecord : EntityBase
{
public BeaconShopSoldRecord(EntityBase owner)
: base(EntityType.BeaconShopSoldRecord, owner)
{
}
public override async Task<Result> onInit()
{
addEntityAttribute(new BeaconShopSoldRecordAttribute(this));
return await base.onInit();
}
public override string toBasicString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public override string toSummaryString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public static async Task<(Result, BeaconShopSoldRecord?)> createBeaconShopSoldRecordFromDoc(Player owner, BeaconShopSoldRecordDoc doc)
{
var beacon_shop_sold_record_item = new BeaconShopSoldRecord(owner);
var result = await beacon_shop_sold_record_item.onInit();
if (result.isFail())
{
return (result, null);
}
var err_msg = string.Empty;
var beacon_shop_sold_record_attribute = beacon_shop_sold_record_item.getEntityAttribute<BeaconShopSoldRecordAttribute>();
if (beacon_shop_sold_record_attribute == null)
{
err_msg = $"Failed to get beacon shop sold record attribute : {nameof(BeaconShopSoldRecordAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
if (beacon_shop_sold_record_attribute.copyEntityAttributeFromDoc(doc) == false)
{
err_msg = $"Failed to copyEntityAttributeFromDoc !!! : doc_type {doc.GetType()} - {beacon_shop_sold_record_item.getRootParent().toBasicString()}";
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
return (result, beacon_shop_sold_record_item);
}
public BeaconShopSoldRecordInfo toBeaconShopSoldRecordData4Client()
{
var beacon_shop_sold_record_4_client = new BeaconShopSoldRecordInfo();
var beacon_shop_sold_record_attribute = getEntityAttribute<BeaconShopSoldRecordAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_sold_record_attribute, () => $"beacon_shop_sold_record_attribute is null !!!");
beacon_shop_sold_record_4_client.BeaconGuid = beacon_shop_sold_record_attribute.BeaconGuid;
beacon_shop_sold_record_4_client.ItemMetaid = (int)beacon_shop_sold_record_attribute.ItemMetaId;
beacon_shop_sold_record_4_client.BuyerNickName = beacon_shop_sold_record_attribute.BuyerNickName;
beacon_shop_sold_record_4_client.PriceForUnit = beacon_shop_sold_record_attribute.PriceForUnit;
beacon_shop_sold_record_4_client.Amount = beacon_shop_sold_record_attribute.Amount;
beacon_shop_sold_record_4_client.SoldPrice = beacon_shop_sold_record_attribute.SoldPrice;
beacon_shop_sold_record_4_client.TaxPrice = beacon_shop_sold_record_attribute.TaxPrice;
beacon_shop_sold_record_4_client.GivenPrice = beacon_shop_sold_record_attribute.GivenPrice;
return beacon_shop_sold_record_4_client;
}
}
}

View File

@@ -0,0 +1,143 @@
using System.Globalization;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.DynamoDBv2.Model;
using ServerCore; using ServerBase;
using ServerCommon;
namespace GameServer;
public class DBQBeaconShopItemDelete : QueryExecutorBase
{
private string m_combination_key_for_pk = string.Empty;
private string m_combination_key_for_sk = string.Empty;
private double m_item_count { get; set; }
private PrimaryKey m_primary_key = new();
public DBQBeaconShopItemDelete(string combinationKeyForPK, string combinationKeyForSK, int itemCount) : base(nameof(DBQBeaconShopItemDelete))
{
m_item_count = itemCount;
m_combination_key_for_pk = combinationKeyForPK;
m_combination_key_for_sk = combinationKeyForSK;
}
//=====================================================================================
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
//=====================================================================================
public override async Task<Result> onPrepareQuery()
{
var owner = getOwner();
var (result, make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<BeaconShopItemDoc>(m_combination_key_for_pk, m_combination_key_for_sk);
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 table = db_connector.getTableByDoc<BeaconShopItemDoc>();
var delete = makeDeleteItemRequestBeaconShopItem(table, m_primary_key.toKeyWithAttributeValue(), JsonHelper.getJsonPropertyName<BeaconShopItemAttrib>(nameof(BeaconShopItemAttrib.ItemStackCount)));
if (delete.result.isFail()) return delete.result;
NullReferenceCheckHelper.throwIfNull(delete.deleteRequest, () => $"deleteRequest is null !!! - {owner.toBasicString()}");
var exception_handler = new DynamoDbQueryExceptionNotifier.ExceptionHandler(DynamoDbQueryExceptionNotifier.ConditionalCheckFailed, ServerErrorCode.BeaconShopUpdateNewData);
var query_context = delete.deleteRequest.createItemRequestQueryContext(QueryType.Delete, 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, DeleteItemRequest? deleteRequest) makeDeleteItemRequestBeaconShopItem( Table table
, 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 query_builder = new DynamoDbItemRequestHelper.DeleteItemRequestBuilder(table.TableName);
query_builder.withKeys(attributeValueWithPrimaryKey);
query_builder.withConditionExpression($"attribute_exists({PrimaryKey.PK_Define}) AND attribute_exists({PrimaryKey.SK_Define})");
var target_doc = new BeaconShopItemDoc();
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);
query_builder.withConditionExpression($"{attribute_expression} = :changeValue");
var expression_attribute_values = new Dictionary<string, AttributeValue>
{
{ ":changeValue", new AttributeValue { N = Math.Abs(m_item_count).ToString(CultureInfo.InvariantCulture) } }
};
query_builder.withExpressionAttributeValues(expression_attribute_values);
query_builder.withReturnValues(ReturnValue.ALL_NEW);
return (result, query_builder.build());
}
}

View File

@@ -0,0 +1,158 @@
using System.Globalization;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DocumentModel;
using Amazon.DynamoDBv2.Model;
using ServerCore; using ServerBase;
using ServerCommon;
namespace GameServer;
public class DBQBeaconShopItemUpdate : QueryExecutorBase
{
private string m_combination_key_for_pk = string.Empty;
private string m_combination_key_for_sk = string.Empty;
private double m_delta { get; set; }
private PrimaryKey m_primary_key = new();
//=====================================================================================
// 0 < deltaCount => 증가
// 0 > deltaCount => 감소
//=====================================================================================
public DBQBeaconShopItemUpdate(string combinationKeyForPK, string combinationKeyForSK, double delta) : base(nameof(DBQBeaconShopItemUpdate))
{
m_delta = delta;
m_combination_key_for_pk = combinationKeyForPK;
m_combination_key_for_sk = combinationKeyForSK;
}
//=====================================================================================
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
//=====================================================================================
public override async Task<Result> onPrepareQuery()
{
var owner = getOwner();
var (result, make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey<BeaconShopItemDoc>(m_combination_key_for_pk, m_combination_key_for_sk);
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 table = db_connector.getTableByDoc<BeaconShopItemDoc>();
var update = makeUpdateItemRequestUpdateBeaconShopItemCount(table, m_primary_key.toKeyWithAttributeValue(), JsonHelper.getJsonPropertyName<BeaconShopItemAttrib>(nameof(BeaconShopItemAttrib.ItemStackCount)));
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.BeaconShopUpdateNewData);
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) makeUpdateItemRequestUpdateBeaconShopItemCount( Table table
, 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 query_builder = new DynamoDbItemRequestHelper.UpdateItemRequestBuilder(table.TableName);
query_builder.withKeys(attributeValueWithPrimaryKey);
var target_doc = new BeaconShopItemDoc();
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);
query_builder.withReturnValues(ReturnValue.ALL_NEW);
return query_builder.build();
}
}

View File

@@ -0,0 +1,148 @@
using Amazon.DynamoDBv2.DocumentModel;
using ServerCore;
using ServerBase;
using ServerCommon;
namespace GameServer;
public class DBQBeaconShopSoldReadAll : QueryExecutorBase
{
private string m_combination_key_for_pk = string.Empty;
private string m_recoed_pk = string.Empty;
private string m_price_pk = string.Empty;
private List<BeaconShopSoldRecordDoc> m_to_read_beacon_shop_sold_record_docs = new();
private List<BeaconShopSoldPriceDoc> m_to_read_beacon_shop_sold_price_docs = new();
public DBQBeaconShopSoldReadAll(string combinationKeyForPK)
: base(typeof(DBQBeaconShopSoldReadAll).Name)
{
m_combination_key_for_pk = combinationKeyForPK;
}
//=====================================================================================
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
//=====================================================================================
public override Task<Result> onPrepareQuery()
{
var result = new Result();
var err_msg = string.Empty;
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
var record_doc = new BeaconShopSoldRecordDoc();
record_doc.setCombinationKeyForPK(m_combination_key_for_pk);
var error_code = record_doc.onApplyPKSK();
if (error_code.isFail())
{
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_recoed_pk = record_doc.getPK();
var price_doc = new BeaconShopSoldPriceDoc();
price_doc.setCombinationKeyForPK(m_combination_key_for_pk);
error_code = price_doc.onApplyPKSK();
if (error_code.isFail())
{
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_price_pk = price_doc.getPK();
return Task.FromResult(result);
}
//=====================================================================================
// onPrepareQuery()를 성공할 경우 호출된다.
//=====================================================================================
public override async Task<Result> onQuery()
{
var result = new Result();
var err_msg = string.Empty;
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_recoed_pk);
(result, var record_read_docs) = await db_connector.simpleQueryDocTypesWithQueryOperationConfig<BeaconShopSoldRecordDoc>(query_config, eventTid: query_batch.getTransId());
if (result.isFail())
{
return result;
}
var beacon_shop_inventory_action = owner.getEntityAction<BeaconShopAction>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_inventory_action, () => "beacon_shop_inventory_action is null !!!");
result = await beacon_shop_inventory_action.AddBeaconShopSoldRecordsFromDocs(record_read_docs);
if (result.isFail())
{
return result;
}
var price_query_config = db_connector.makeQueryConfigForReadByPKOnly(m_price_pk);
(result, var price_read_docs) = await db_connector.simpleQueryDocTypesWithQueryOperationConfig<BeaconShopSoldPriceDoc>(price_query_config, eventTid: query_batch.getTransId());
if (result.isFail())
{
return result;
}
result = await beacon_shop_inventory_action.AddBeaconShopSoldPriceFromDocs(price_read_docs);
if (result.isFail())
{
return result;
}
result = await beacon_shop_inventory_action.ProcessBeaconShopDeleteRecord();
if (result.isFail())
{
return result;
}
m_to_read_beacon_shop_sold_record_docs = record_read_docs;
m_to_read_beacon_shop_sold_price_docs = price_read_docs;
return await Task.FromResult(result);
}
public List<BeaconShopSoldRecordDoc> getToReadItemDocs() => m_to_read_beacon_shop_sold_record_docs;
//=====================================================================================
// 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;
}
public new Player? getOwner() => getQueryBatch()?.getLogActor() as Player;
}

View File

@@ -0,0 +1,114 @@
using Amazon.DynamoDBv2.DocumentModel;
using GameServer;
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 DBQBeaconShopSoldRecordReadAll : QueryExecutorBase
{
private string m_combination_key_for_pk = string.Empty;
private string m_pk = string.Empty;
private List<BeaconShopSoldRecordDoc> m_to_read_beacon_shop_sold_record_docs = new();
public DBQBeaconShopSoldRecordReadAll(string combinationKeyForPK)
: base(typeof(DBQBeaconShopSoldRecordReadAll).Name)
{
m_combination_key_for_pk = combinationKeyForPK;
}
//=====================================================================================
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
//=====================================================================================
public override Task<Result> onPrepareQuery()
{
var result = new Result();
var err_msg = string.Empty;
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
var doc = new BeaconShopSoldRecordDoc();
doc.setCombinationKeyForPK(m_combination_key_for_pk);
var error_code = doc.onApplyPKSK();
if (error_code.isFail())
{
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 err_msg = string.Empty;
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<BeaconShopSoldRecordDoc>(query_config, eventTid: query_batch.getTransId());
if (result.isFail())
{
return result;
}
var beacon_shop_inventory_action = owner.getEntityAction<BeaconShopAction>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_inventory_action, () => "beacon_shop_inventory_action is null !!!");
result = await beacon_shop_inventory_action.AddBeaconShopSoldRecordsFromDocs(read_docs);
if (result.isFail())
{
return result;
}
m_to_read_beacon_shop_sold_record_docs = read_docs;
return await Task.FromResult(result);
}
public List<BeaconShopSoldRecordDoc> getToReadItemDocs() => m_to_read_beacon_shop_sold_record_docs;
//=====================================================================================
// 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;
}
public new Player? getOwner() => getQueryBatch()?.getLogActor() as Player;
}
}

View File

@@ -0,0 +1,121 @@
using Google.Protobuf.WellKnownTypes;
using ServerCommon;
using USER_GUID = System.String;
using BEACON_GUID = System.String;
using META_ID = System.UInt32;
using ServerCore; using ServerBase;
using static ServerMessage.Types;
namespace GameServer
{
internal static class BeaconShopHelper
{
public static BeaconShopItemBoardInfo toBeaconShopItemMongoDataClient(this BeaconShopMongoDoc beaconShopMongoDoc)
{
var beacon_shop_4_client = new BeaconShopItemBoardInfo();
beacon_shop_4_client.ItemGuid = beaconShopMongoDoc.ItemGuid;
beacon_shop_4_client.ItemMetaid = (int)beaconShopMongoDoc.TagId;
beacon_shop_4_client.BeaconGuid = beaconShopMongoDoc.BeaconGuid;
beacon_shop_4_client.BeaconNickName = beaconShopMongoDoc.BeaconNickName;
beacon_shop_4_client.BeaconTitle = beaconShopMongoDoc.BeaconTitle;
beacon_shop_4_client.BeaconBodyItemMetaId = beaconShopMongoDoc.BeaconBodyItemMetaId;
beacon_shop_4_client.PriceForUnit = beaconShopMongoDoc.PriceForUnit;
beacon_shop_4_client.Amount = beaconShopMongoDoc.Amount;
beacon_shop_4_client.OwnerGuid = beaconShopMongoDoc.OwnerGuid;
beacon_shop_4_client.OwnerNickName = beaconShopMongoDoc.OwnerNickName;
beacon_shop_4_client.BeaconMyHomeGuid = beaconShopMongoDoc.BeaconMyHomeGuid;
beacon_shop_4_client.SellingFinishTime = Timestamp.FromDateTime(beaconShopMongoDoc.SellingFinishTime);
return beacon_shop_4_client;
}
public async static Task<BeaconShopSoldRecordDoc?> CreateBeaconShopSoldRecord(BeaconShopItemAttribute beaconShopItemAttribute, string buyerNickName, int amount, double soldPrice, double taxPrice, double givenPrice)
{
DateTime now = DateTimeHelper.Current;
var beacon_shop_sold_record_doc = new BeaconShopSoldRecordDoc(beaconShopItemAttribute.UserGuid, now);
var beacon_shop_sold_record_attrib = beacon_shop_sold_record_doc.getAttrib<BeaconShopSoldRecordAttrib>();
if (beacon_shop_sold_record_attrib == null)
{
return null;
}
beacon_shop_sold_record_attrib.UserGuid = beaconShopItemAttribute.UserGuid;
beacon_shop_sold_record_attrib.BeaconGuid = beaconShopItemAttribute.BeaconGuid;
beacon_shop_sold_record_attrib.ItemMetaId = beaconShopItemAttribute.ItemMetaId;
beacon_shop_sold_record_attrib.BuyerNickName = buyerNickName;
beacon_shop_sold_record_attrib.PriceForUnit = beaconShopItemAttribute.PriceForUnit;
beacon_shop_sold_record_attrib.Amount = amount;
beacon_shop_sold_record_attrib.SalesTime = now;
beacon_shop_sold_record_attrib.SoldPrice = soldPrice;
beacon_shop_sold_record_attrib.TaxPrice = taxPrice;
beacon_shop_sold_record_attrib.GivenPrice = givenPrice;
var result = await beacon_shop_sold_record_doc.newDoc4Query();
if (result.isFail())
{
return null;
}
return beacon_shop_sold_record_doc;
}
public static void send_GS2GS_NTF_UPDATE_SOLD_RECORD(string targetServer, USER_GUID targetUserGuid)
{
ConditionValidCheckHelper.throwIfFalseWithCondition(() => true != targetServer.isNullOrWhiteSpace()
, () => $"targetServer is NullOrWhiteSpace !!! - targetServer:{targetServer}, targetUserGuid:{targetUserGuid}");
var server_logic = GameServerApp.getServerLogic();
var rabbit_mq_4_game = server_logic.getRabbitMqConnector() as RabbitMQ4Game;
NullReferenceCheckHelper.throwIfNull(rabbit_mq_4_game, () => $"rabbit_mq_4_game is null !!");
var ntf_packet = new ServerMessage();
var ntf_update_sold_record = new GS2GS_NTF_UPDATE_SOLD_RECORD();
ntf_packet.NtfUpdateSoldRecord = ntf_update_sold_record;
ntf_update_sold_record.TargetUserGuid = targetUserGuid;
rabbit_mq_4_game.SendMessage(targetServer, ntf_packet);
}
public static void send_GS2GS_NTF_UPDATE_BEACON_SHOP_ITEM(USER_GUID targetUserGuid, BEACON_GUID targetBeaconGuid)
{
var server_logic = GameServerApp.getServerLogic();
var rabbit_mq_4_game = server_logic.getRabbitMqConnector() as RabbitMQ4Game;
NullReferenceCheckHelper.throwIfNull(rabbit_mq_4_game, () => $"rabbit_mq_4_game is null !!");
var ntf_packet = new ServerMessage();
var ntf_update_beacon_shop_item = new GS2GS_NTF_UPDATE_BEACON_SHOP_ITEM();
ntf_packet.NtfUpdateBeaconShopItem = ntf_update_beacon_shop_item;
ntf_update_beacon_shop_item.TargetUserGuid = targetUserGuid;
ntf_update_beacon_shop_item.TargetBeaconGuid = targetBeaconGuid;
rabbit_mq_4_game.sendMessageToExchangeAllGame(ntf_packet);
}
public static ItemDoc toItemDocFromBeaconShopItemDoc(BeaconShopItemDoc beaconShopItemDoc, ushort itemStackCount)
{
var beacon_shop_item_attrib = beaconShopItemDoc.getAttrib<BeaconShopItemAttrib>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_item_attrib, () => $"beacon_shop_item_attrib is null !!");
var item_guid = Guid.NewGuid().ToString("N");
var itemDoc = new ItemDoc(beacon_shop_item_attrib.OwnerEntityType, beacon_shop_item_attrib.UserGuid, item_guid);
var item_attrib = itemDoc.getAttrib<ItemAttrib>();
NullReferenceCheckHelper.throwIfNull(item_attrib, () => $"item_attrib is null !!!");
item_attrib.ItemMetaId = beacon_shop_item_attrib.ItemMetaId;
item_attrib.ItemStackCount = itemStackCount;
item_attrib.Level = beacon_shop_item_attrib.Level;
item_attrib.Attributes = beacon_shop_item_attrib.Attributes.Select(x => x).ToList();
item_attrib.EquipedIvenType = beacon_shop_item_attrib.EquipedIvenType;
item_attrib.EquipedPos = beacon_shop_item_attrib.EquipedPos;
return itemDoc;
}
}
}

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 class BeaconShopBusinessLog : ILogInvokerEx
{
private BeaconShopLogData m_data_to_log;
public BeaconShopBusinessLog(BeaconShopLogData log_data_param)
: base(LogDomainType.BeaconShop)
{
m_data_to_log = log_data_param;
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(new BeaconShopLogData(this, m_data_to_log));
}
}

View File

@@ -0,0 +1,89 @@
using ServerCommon.BusinessLogDomain;
using ServerCommon;
using META_ID = System.UInt32;
namespace GameServer
{
static public class BeaconShopBusinessLogHelper
{
static public BeaconShopLogData toLogInfo(BeaconShopMongoDoc beaconShopMongoDoc)
{
var logData = new BeaconShopLogData();
logData.setInfo(beaconShopMongoDoc);
return logData;
}
static public void setInfo(this BeaconShopLogData logData, BeaconShopMongoDoc beaconShopMongoDoc)
{
logData.ItemGuid = beaconShopMongoDoc.ItemGuid;
logData.TagId = beaconShopMongoDoc.TagId;
logData.BeaconGuid = beaconShopMongoDoc.BeaconGuid;
logData.BeaconNickName = beaconShopMongoDoc.BeaconNickName;
logData.BeaconTitle = beaconShopMongoDoc.BeaconTitle;
logData.BeaconBodyItemMetaId = beaconShopMongoDoc.BeaconBodyItemMetaId;
logData.PriceForUnit = beaconShopMongoDoc.PriceForUnit;
logData.Amount = beaconShopMongoDoc.Amount;
logData.OwnerGuid = beaconShopMongoDoc.OwnerGuid;
logData.OwnerNickName = beaconShopMongoDoc.OwnerNickName;
logData.BeaconMyHomeGuid = beaconShopMongoDoc.BeaconMyHomeGuid;
logData.SellingFinishTime = beaconShopMongoDoc.SellingFinishTime;
logData.BuyerGuid = string.Empty;
}
static public BeaconShopLogData toLogInfo(BeaconShopItemAttribute beaconShopItemAttribute, UgcNpcAttribute ugcNpcAttribute, string buyerGuid)
{
var logData = new BeaconShopLogData();
logData.setInfo(beaconShopItemAttribute, ugcNpcAttribute, buyerGuid);
return logData;
}
static public void setInfo(this BeaconShopLogData logData, BeaconShopItemAttribute beaconShopItemAttribute, UgcNpcAttribute ugcNpcAttribute, string buyerGuid)
{
logData.ItemGuid = beaconShopItemAttribute.ItemGuid;
logData.TagId = (int)beaconShopItemAttribute.ItemMetaId;
logData.BeaconGuid = beaconShopItemAttribute.BeaconGuid;
logData.BeaconNickName = ugcNpcAttribute.Nickname;
logData.BeaconTitle = ugcNpcAttribute.Title;
logData.BeaconBodyItemMetaId = (int)ugcNpcAttribute.BodyItemMetaId;
logData.PriceForUnit = beaconShopItemAttribute.PriceForUnit;
logData.Amount = beaconShopItemAttribute.ItemStackCount;
logData.OwnerGuid = beaconShopItemAttribute.UserGuid;
logData.BeaconMyHomeGuid = ugcNpcAttribute.LocatedInstanceGuid;
logData.SellingFinishTime = beaconShopItemAttribute.SellingFinishTime;
logData.BuyerGuid = buyerGuid;
}
static public BeaconShopSoldRecordLogData toLogInfo(BeaconShopSoldRecordAttribute beaconShopSoldRecordAttribute)
{
var logData = new BeaconShopSoldRecordLogData();
logData.setInfo(beaconShopSoldRecordAttribute);
return logData;
}
static public void setInfo(this BeaconShopSoldRecordLogData logData, BeaconShopSoldRecordAttribute beaconShopSoldRecordAttribute)
{
logData.UserGuid = beaconShopSoldRecordAttribute.UserGuid;
logData.BeaconGuid = beaconShopSoldRecordAttribute.BeaconGuid;
logData.ItemMetaId = beaconShopSoldRecordAttribute.ItemMetaId;
logData.BuyerNickName = beaconShopSoldRecordAttribute.BuyerNickName;
logData.PriceForUnit = beaconShopSoldRecordAttribute.PriceForUnit;
logData.Amount = beaconShopSoldRecordAttribute.Amount;
logData.SalesTime = beaconShopSoldRecordAttribute.SalesTime;
}
static public BeaconShopSoldPriceLogData toLogInfo(string userGuid, string beaconGuid, double deltaPrice, double deltaTaxPrice)
{
var logData = new BeaconShopSoldPriceLogData();
logData.setInfo(userGuid, beaconGuid, deltaPrice, deltaTaxPrice);
return logData;
}
static public void setInfo(this BeaconShopSoldPriceLogData logData, string userGuid, string beaconGuid, double deltaPrice, double deltaTaxPrice)
{
logData.UserGuid = userGuid;
logData.BeaconGuid = beaconGuid;
logData.deltaPrice = deltaPrice;
logData.deltaTaxPrice = deltaTaxPrice;
}
}
}

View File

@@ -0,0 +1,29 @@

using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
namespace GameServer;
public class BeaconShopSoldPriceBusinessLog : ILogInvokerEx
{
private BeaconShopSoldPriceLogData m_data_to_log;
public BeaconShopSoldPriceBusinessLog(BeaconShopSoldPriceLogData log_data_param)
: base(LogDomainType.BeaconShopSoldPrice)
{
m_data_to_log = log_data_param;
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(new BeaconShopSoldPriceLogData(this, m_data_to_log));
}
}

View File

@@ -0,0 +1,32 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class BeaconShopSoldRecordBusinessLog : ILogInvokerEx
{
private BeaconShopSoldRecordLogData m_data_to_log;
public BeaconShopSoldRecordBusinessLog(BeaconShopSoldRecordLogData log_data_param)
: base(LogDomainType.BeaconShopSoldRecord)
{
m_data_to_log = log_data_param;
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(new BeaconShopSoldRecordLogData(this, m_data_to_log));
}
}

View File

@@ -0,0 +1,26 @@
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace GameServer;
public class BeaconShopMongoDoc
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; } = null!;
public string ItemGuid { get; set; } = null!;
public int TagId { get; set; } = 0;
public string BeaconGuid { get; set; } = null!;
public string BeaconNickName { get; set; } = null!;
public string BeaconTitle { get; set; } = string.Empty;
public int BeaconBodyItemMetaId { get; set; } = 0;
public double PriceForUnit { get; set; } = 0;
public int Amount { get; set; } = 0;
public string OwnerGuid { get; set; } = null!;
public string OwnerNickName { get; set; } = null!;
public string BeaconMyHomeGuid { get; set; } = null!;
[BsonRequired]
public DateTime SellingFinishTime { get; set; } = new();
}

View File

@@ -0,0 +1,134 @@

using MongoDB.Driver;
using ServerBase;
using ServerCore;
using BEACON_GUID = System.String;
using META_ID = System.UInt32;
using USER_GUID = System.String;
using ITEM_GUID = System.String;
namespace GameServer;
public class BeaconShopRepository : MongoDbRepository<BeaconShopMongoDoc>
{
private const string CollectionName = "BeaconShop";
public BeaconShopRepository(IMongoClient mongoClient, MongoDbConf settings) :
base(mongoClient, settings.DatabaseName, CollectionName)
{
}
public async Task<(Result, List<BeaconShopMongoDoc>?)> get(int tagId)
{
var result = new Result();
var err_msg = string.Empty;
var builder = Builders<BeaconShopMongoDoc>.Filter;
var filter = builder.Eq(x => x.TagId, tagId);
try
{
var findData = await m_collection.FindAsync(filter);
return (result, findData.ToList());
}
catch (Exception ex)
{
err_msg = $"MongoDB Write Exception Error: {ex.Message}";
result.setFail(ServerErrorCode.BeaconShopFailedGetBoardItem, err_msg);
return (result, null);
}
}
public async Task<Result> insert(BeaconShopMongoDoc beaconShopEntity)
{
var result = new Result();
var err_msg = string.Empty;
try
{
await m_collection.InsertOneAsync(beaconShopEntity);
}
catch (Exception ex)
{
err_msg = $"MongoDB Write Exception Error: {ex.Message}";
result.setFail(ServerErrorCode.BeaconShopFailedRegisterBoard, err_msg);
Log.getLogger().error(err_msg);
return result;
}
return result;
}
public async Task<(Result, BeaconShopMongoDoc?)> updateAmount(string id, int amount)
{
var result = new Result();
var err_msg = string.Empty;
try
{
var filter = Builders<BeaconShopMongoDoc>.Filter
.Eq(x => x.ItemGuid, id);
var update = Builders<BeaconShopMongoDoc>.Update
.Inc(x => x.Amount, amount);
var options = new FindOneAndUpdateOptions<BeaconShopMongoDoc>
{
ReturnDocument = ReturnDocument.After,
};
var updated = await m_collection.FindOneAndUpdateAsync(filter, update, options);
if (updated == null)
{
err_msg = $"MongoDB is already empty. Error";
result.setFail(ServerErrorCode.BeaconShopFailedToFindOrUpdate, err_msg);
return (result, null);
}
if (updated.Amount == 0)
{
return (await delete(id), updated);
}
return (result, updated);
}
catch (Exception ex)
{
err_msg = $"MongoDB Write Exception Error: {ex.Message}";
result.setFail(ServerErrorCode.BeaconShopDbException, err_msg);
return (result, null);
}
}
public async Task<Result> delete(ITEM_GUID item_guid)
{
var result = new Result();
var err_msg = string.Empty;
var builder = Builders<BeaconShopMongoDoc>.Filter;
var filter = builder.Eq(x => x.ItemGuid, item_guid);
try
{
var db_result = await m_collection.DeleteOneAsync(filter);
if (db_result.DeletedCount == 0)
{
result.setFail(ServerErrorCode.BeaconShopNotFoundItemFromBoard, err_msg);
return result;
}
}
catch (Exception ex)
{
err_msg = $"MongoDB Delete Exception Error : {ex.Message}";
result.setFail(ServerErrorCode.BeaconShopFailedDeleteBoard, err_msg);
return result;
}
return result;
}
}

View File

@@ -0,0 +1,105 @@
using Google.Protobuf;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameRes.Types;
using META_ID = System.UInt32;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_BEACON_SHOP_GET_ITEM_INFOS), typeof(BeaconShopGetItemInfosPacketHandler), typeof(GameLoginListener))]
public class BeaconShopGetItemInfosPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_BEACON_SHOP_GET_ITEM_INFOS(Player player, Result result, List<BeaconShopItem>? beaconShopItem = null, int dailyRegisterCount = 0, int numOfReceiptNotReceived = 0)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.AckBeaconShopGetItemInfos = new GS2C_ACK_BEACON_SHOP_GET_ITEM_INFOS();
if (result.isSuccess() && beaconShopItem != null)
{
ack_packet.Response.AckBeaconShopGetItemInfos.BeaconShopInfos.AddRange(beaconShopItem.Select<BeaconShopItem, BeaconShopInfo>(x => x.toBeaconShopData4Client()).ToList());
ack_packet.Response.AckBeaconShopGetItemInfos.DailyRegisterCount = dailyRegisterCount;
ack_packet.Response.AckBeaconShopGetItemInfos.NumOfReceiptNotReceived = numOfReceiptNotReceived;
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => $"entity_player is null !!!");
var beacon_shop_action = entity_player.getEntityAction<BeaconShopAction>();
if (beacon_shop_action == null)
{
err_msg = $"Failed to get beacon shop action : {nameof(BeaconShopAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_BEACON_SHOP_GET_ITEM_INFOS(entity_player, result);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.ReqBeaconShopGetItemInfos)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_GET_ITEM_INFOS(entity_player, result);
return result;
}
var request = game_msg.Request.ReqBeaconShopGetItemInfos;
if (request.BeaconGuid == string.Empty && request.BeaconOwnerGuid == string.Empty)
{
err_msg = $"Invalid Request Argument !!! : BeaconGuid : {request.BeaconGuid}, BeaconOwnerGuid : {request.BeaconOwnerGuid}";
result.setFail(ServerErrorCode.BeaconShopInvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_GET_ITEM_INFOS(entity_player, result);
return result;
}
result = await beacon_shop_action.BeaconShopGetItemInfos(request.BeaconGuid, request.BeaconOwnerGuid);
if (result.isFail())
{
send_S2C_ACK_BEACON_SHOP_GET_ITEM_INFOS(entity_player, result);
return result;
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_BEACON_SHOP_GET_ITEM_INFOS(player, errorResult);
}
}

View File

@@ -0,0 +1,31 @@
using ServerCore; using ServerBase;
using BEACON_GUID = System.String;
namespace GameServer
{
public static class BeaconShopNotifyHelper
{
public static bool send_S2C_NTF_BEACON_SHOP_REFRESH(this Player player, BEACON_GUID beaconGuid)
{
var noti_packet = makeAckBeaconShopRefreshPacket(beaconGuid);
if (false == GameServerApp.getServerLogic().onSendPacket(player, noti_packet))
{
return false;
}
return true;
}
public static ClientToGame makeAckBeaconShopRefreshPacket(BEACON_GUID beaconGuid)
{
var noti_packet = new ClientToGame();
noti_packet.Message = new();
noti_packet.Message.NtfBeaconShopRefresh = new();
noti_packet.Message.NtfBeaconShopRefresh.BeaconGuid = beaconGuid;
return noti_packet;
}
}
}

View File

@@ -0,0 +1,107 @@
using Google.Protobuf;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_BEACON_SHOP_PURCHASE_ITEM), typeof(BeaconShopPurchaseItemPacketHandler), typeof(GameLoginListener))]
public class BeaconShopPurchaseItemPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(Player player, Result result, string itemGuid = "", string beaconGuid = "", int itemAmount = 0, CommonResult? commonResult = null)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.AckBeaconShopPurchaseItem = new GS2C_ACK_BEACON_SHOP_PURCHASE_ITEM();
if (result.isSuccess())
{
ack_packet.Response.AckBeaconShopPurchaseItem.ItemGuid = itemGuid;
ack_packet.Response.AckBeaconShopPurchaseItem.BeaconGuid = beaconGuid;
ack_packet.Response.AckBeaconShopPurchaseItem.ItemAmount = itemAmount;
ack_packet.Response.AckBeaconShopPurchaseItem.CommonResult = commonResult;
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => $"entity_player is null !!!" );
var beacon_shop_action = entity_player.getEntityAction<BeaconShopAction>();
if (beacon_shop_action == null)
{
err_msg = $"Failed to get beacon shop action : {nameof(BeaconShopAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(entity_player, result);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.ReqBeaconShopPurchaseItem)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(entity_player, result);
return result;
}
var request = game_msg.Request.ReqBeaconShopPurchaseItem;
if(request.ItemGuid == string.Empty ||
request.BeaconGuid == string.Empty ||
request.ItemAmount <= 0 ||
request.BeaconOwnerGuid == string.Empty)
{
err_msg = $"Invalid Request Argument !!! : ItemGuid : {request.ItemGuid}, BeaconGuid : {request.BeaconGuid}, ItemAmount : {request.ItemAmount}";
result.setFail(ServerErrorCode.BeaconShopInvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(entity_player, result);
return result;
}
result = await beacon_shop_action.BeaconShopPurchaseItem(request.ItemGuid, (UInt16)request.ItemAmount, request.BeaconGuid, request.BeaconOwnerGuid);
if (result.isFail())
{
send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(entity_player, result);
return result;
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, errorResult);
}
}

View File

@@ -0,0 +1,103 @@
using Google.Protobuf;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES), typeof(BeaconShopReceivePaymentForSalesPacketHandler), typeof(GameLoginListener))]
public class BeaconShopReceivePaymentForSalesPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES(Player player, Result result, string beaconGuid = "", CommonResult? commonResult = null)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.AckBeaconShopReceivePaymentForSales = new GS2C_ACK_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES();
if (result.isSuccess())
{
ack_packet.Response.AckBeaconShopReceivePaymentForSales.BeaconGuid = beaconGuid;
ack_packet.Response.AckBeaconShopReceivePaymentForSales.CommonResult = commonResult;
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => $"entity_player is null !!!" );
var beacon_shop_action = entity_player.getEntityAction<BeaconShopAction>();
if (beacon_shop_action == null)
{
err_msg = $"Failed to get beacon shop action : {nameof(BeaconShopAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES(entity_player, result);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.ReqBeaconShopReceivePaymentForSales)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES(entity_player, result);
return result;
}
var request = game_msg.Request.ReqBeaconShopReceivePaymentForSales;
if (request.BeaconGuid == string.Empty)
{
err_msg = $"Invalid Request Argument !!! : BeaconGuid : {request.BeaconGuid}";
result.setFail(ServerErrorCode.BeaconShopInvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES(entity_player, result);
return result;
}
result = await beacon_shop_action.BeaconShopReceivePaymentForSales(request.BeaconGuid);
if (result.isFail())
{
send_S2C_ACK_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES(entity_player, result);
return result;
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES(player, errorResult);
}
}

View File

@@ -0,0 +1,116 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_BEACON_SHOP_REGISTER_ITEM), typeof(BeaconShopRegisterItemPacketHandler), typeof(GameLoginListener))]
public class BeaconShopRegisterItemPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(Player player, Result result, BeaconShopItem? beaconShopItem, CommonResult? commonResult = null)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.AckBeaconShopRegisterItem = new GS2C_ACK_BEACON_SHOP_REGISTER_ITEM();
if (result.isSuccess() && beaconShopItem != null)
{
var beacon_shop_attribute = beaconShopItem.getEntityAttribute<BeaconShopItemAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_attribute, () => $"beacon_shop_attribute is null !!!");
ack_packet.Response.AckBeaconShopRegisterItem.ItemGuid = beacon_shop_attribute.ItemGuid;
ack_packet.Response.AckBeaconShopRegisterItem.ItemMetaId = (int)beacon_shop_attribute.ItemMetaId;
ack_packet.Response.AckBeaconShopRegisterItem.ItemAmount = beacon_shop_attribute.ItemStackCount;
ack_packet.Response.AckBeaconShopRegisterItem.SellingPrice = beacon_shop_attribute.PriceForUnit;
ack_packet.Response.AckBeaconShopRegisterItem.BeaconGuid = beacon_shop_attribute.BeaconGuid;
ack_packet.Response.AckBeaconShopRegisterItem.SellingFinishTime = Timestamp.FromDateTime(beacon_shop_attribute.SellingFinishTime);
ack_packet.Response.AckBeaconShopRegisterItem.CommonResult = commonResult;
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => $"entity_player is null !!!" );
var beacon_shop_action = entity_player.getEntityAction<BeaconShopAction>();
if (beacon_shop_action == null)
{
err_msg = $"Failed to get beacon shop action : {nameof(BeaconShopAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(entity_player, result, null);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.ReqBeaconShopRegisterItem)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(entity_player, result, null);
return result;
}
var request = game_msg.Request.ReqBeaconShopRegisterItem;
if (request.ItemGuid == string.Empty ||
request.BeaconGuid == string.Empty ||
request.ItemAmount <= 0 ||
request.SellingPrice <= 0)
{
err_msg = $"Invalid Request Argument !!! : ItemGuid : {request.ItemGuid}, BeaconGuid : {request.BeaconGuid}, ItemAmount : {request.ItemAmount}, SellingPrice : {request.SellingPrice}";
result.setFail(ServerErrorCode.BeaconShopInvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(entity_player, result, null);
return result;
}
result = await beacon_shop_action.tryRegisterItemToBeaconShop(request.ItemGuid, (UInt16)request.ItemAmount, request.SellingPrice, request.BeaconGuid);
if (result.isFail())
{
send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(entity_player, result, null);
return result;
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(player, errorResult, null);
}
}

View File

@@ -0,0 +1,103 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_BEACON_SHOP_RETURN_ITEM), typeof(BeaconShopReturnItemPacketHandler), typeof(GameLoginListener))]
public class BeaconShopReturnItemPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(Player player, Result result, string itemGuid = "", string beaconGuid = "", CommonResult? commonResult = null)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.AckBeaconShopReturnItem = new GS2C_ACK_BEACON_SHOP_RETURN_ITEM();
if (result.isSuccess())
{
ack_packet.Response.AckBeaconShopReturnItem.ItemGuid = itemGuid;
ack_packet.Response.AckBeaconShopReturnItem.BeaconGuid = beaconGuid;
ack_packet.Response.AckBeaconShopReturnItem.CommonResult = commonResult;
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => $"entity_player is null !!!" );
var beacon_shop_action = entity_player.getEntityAction<BeaconShopAction>();
if (beacon_shop_action == null)
{
err_msg = $"Failed to get beacon shop action : {nameof(BeaconShopAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(entity_player, result);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.ReqBeaconShopReturnItem)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(entity_player, result);
return result;
}
var request = game_msg.Request.ReqBeaconShopReturnItem;
if (request.ItemGuid == string.Empty ||
request.BeaconGuid == string.Empty)
{
err_msg = $"Invalid Request Argument !!! : ItemGuid : {request.ItemGuid}, BeaconGuid : {request.BeaconGuid}";
result.setFail(ServerErrorCode.BeaconShopInvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(entity_player, result);
return result;
}
result = await beacon_shop_action.BeaconShopReturnItem(request.ItemGuid, request.BeaconGuid);
if (result.isFail())
{
send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(entity_player, result);
return result;
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(player, errorResult);
}
}

View File

@@ -0,0 +1,105 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
using META_ID = System.UInt32;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_BEACON_SHOP_SEARCH_ITEM), typeof(BeaconShopSearchItemPacketHandler), typeof(GameLoginListener))]
public class BeaconShopSearchItemPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_BEACON_SHOP_SEARCH_ITEM(Player player, Result result, List<BeaconShopMongoDoc>? beaconShopMongoDocs)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.AckBeaconShopSearchItem = new GS2C_ACK_BEACON_SHOP_SEARCH_ITEM();
if (result.isSuccess() && beaconShopMongoDocs != null)
{
ack_packet.Response.AckBeaconShopSearchItem.BeaconShopItemBoardInfos.AddRange(beaconShopMongoDocs.Select<BeaconShopMongoDoc, BeaconShopItemBoardInfo>(x => x.toBeaconShopItemMongoDataClient()).ToList());
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => $"entity_player is null !!!" );
var beacon_shop_action = entity_player.getEntityAction<BeaconShopAction>();
if (beacon_shop_action == null)
{
err_msg = $"Failed to get beacon shop action : {nameof(BeaconShopAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_BEACON_SHOP_SEARCH_ITEM(entity_player, result, null);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.ReqBeaconShopSearchItem)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_SEARCH_ITEM(entity_player, result, null);
return result;
}
var request = game_msg.Request.ReqBeaconShopSearchItem;
if (request.ItemMetaid == 0)
{
err_msg = $"Invalid Request Argument !!! : ItemMetaid : {request.ItemMetaid}";
result.setFail(ServerErrorCode.BeaconShopInvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_SEARCH_ITEM(entity_player, result, null);
return result;
}
result = await beacon_shop_action.BeaconShopSearchItem((META_ID)request.ItemMetaid);
if (result.isFail())
{
send_S2C_ACK_BEACON_SHOP_SEARCH_ITEM(entity_player, result, null);
return result;
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_BEACON_SHOP_SEARCH_ITEM(player, errorResult, null);
}
}

View File

@@ -0,0 +1,106 @@
using Google.Protobuf;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameRes.Types;
using META_ID = System.UInt32;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_BEACON_SHOP_GET_SOLD_RECORDS), typeof(BeaconShopSoldRecordInfoPacketHandler), typeof(GameLoginListener))]
public class BeaconShopSoldRecordInfoPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_BEACON_SHOP_GET_SOLD_RECORDS(Player player, Result result, List<BeaconShopSoldRecord>? beaconShopSoldRecords, double totalGivenPrice = 0)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.AckBeaconShopGetSoldRecords = new GS2C_ACK_BEACON_SHOP_GET_SOLD_RECORDS();
if (result.isSuccess() && beaconShopSoldRecords != null)
{
ack_packet.Response.AckBeaconShopGetSoldRecords.BeaconShopSoldRecordInfos.AddRange(beaconShopSoldRecords.Select<BeaconShopSoldRecord, BeaconShopSoldRecordInfo>(x => x.toBeaconShopSoldRecordData4Client()).ToList());
ack_packet.Response.AckBeaconShopGetSoldRecords.TotalGivenPrice = totalGivenPrice;
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => $"entity_player is null !!!");
var beacon_shop_action = entity_player.getEntityAction<BeaconShopAction>();
if (beacon_shop_action == null)
{
err_msg = $"Failed to get beacon shop action : {nameof(BeaconShopAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_BEACON_SHOP_GET_SOLD_RECORDS(entity_player, result, null);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.ReqBeaconShopGetSoldRecords)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_GET_SOLD_RECORDS(entity_player, result, null);
return result;
}
var request = game_msg.Request.ReqBeaconShopGetSoldRecords;
if (request.BeaconGuid == string.Empty)
{
err_msg = $"Invalid Request Argument !!! : BeaconGuid : {request.BeaconGuid}";
result.setFail(ServerErrorCode.BeaconShopInvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BEACON_SHOP_GET_SOLD_RECORDS(entity_player, result, null);
return result;
}
result = await beacon_shop_action.BeaconShopGetSoldRecords(request.BeaconGuid);
if (result.isFail())
{
send_S2C_ACK_BEACON_SHOP_GET_SOLD_RECORDS(entity_player, result, null);
return result;
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_BEACON_SHOP_GET_SOLD_RECORDS(player, errorResult, null);
}
}

View File

@@ -0,0 +1,689 @@
using ServerCore;
using ServerCommon;
using MetaAssets;
using META_ID = System.UInt32;
using ServerBase;
namespace GameServer;
public class BuffAction : EntityActionBase
{
private BuffCacheRequest? m_buff_cache_request = null;
public BuffAction(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> loadBuff()
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!!");
var buff_attribute = player.getOriginEntityAttribute<BuffAttribute>();
NullReferenceCheckHelper.throwIfNull(buff_attribute, () => $"buff_attribute is null !!!");
m_buff_cache_request = new BuffCacheRequest(player, server_logic.getRedisConnector());
result = await m_buff_cache_request.fetchBuff();
if (result.isFail())
{
return result;
}
var buff_cache = m_buff_cache_request.getBuffCache();
if (buff_cache == null)
{
return result;
}
result = await ServerBase.DataCopyHelper.copyEntityAttributeFromCaches(buff_attribute, (new List<CacheBase>() { buff_cache }));
if (result.isFail())
{
return result;
}
foreach (var buff_channel in buff_attribute.BuffInfos)
{
foreach (var buff in buff_channel.Value)
{
changeAttribute(buff.Value.BuffMetaID, false);
}
}
return result;
}
public (Result result, BuffAttribute.BuffInfo? addBuff, BuffAttribute.BuffInfo? delBuff, BuffAttribute.BuffInfo? delStopBuff) UseEqipedBuff(META_ID buff_meta_id, int clientUIStep)
{
var result = new Result();
var err_msg = string.Empty;
BuffAttribute.BuffInfo? add_buff_attribute = null;
BuffAttribute.BuffInfo? del_buff_attribute = null;
BuffAttribute.BuffInfo? del_step_buff_attribute = null;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
if (!MetaData.Instance._BuffTable.TryGetValue((int)buff_meta_id, out var buffData))
{
err_msg = $"Not Exisxt BuffId : {buff_meta_id} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BuffMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null, null);
}
if (buffData.BuffCategory != MetaAssets.EBuffCategory.TOOL)
{
err_msg = $"BuffType is not TOOL : {buffData.BuffId} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BuffInvalidBuffCategoryType, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null, null);
}
result = GetBuffFromAttribute(buffData.BuffCategory, buffData.BuffChannel, out var buff);
if (result.isFail() || buff == null)
{
return (result, null, null, null);
}
if (buff.BuffMetaID != buff_meta_id)
{
err_msg = $"Not Found Buff buff_meta_id : {buff_meta_id} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BuffNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null, null);
}
if (buffData.BuffEndCondition == EBuffEndCondition.ACTIONSTEP)
{
if (clientUIStep >= buffData.BuffEndConditionValue)
{
(result, del_step_buff_attribute) = DelBuffProcess(buff_meta_id);
if (result.isFail())
return (result, null, null, null);
}
if (buffData.ActionBuffId != 0)
{
(result, add_buff_attribute, del_buff_attribute) = AddBuffProcess((META_ID)buffData.ActionBuffId);
if (result.isFail())
return (result, null, null, null);
}
}
else
{
(result, del_buff_attribute) = DelBuffProcess(buff_meta_id);
if (result.isFail())
return (result, null, null, null);
}
return (result, add_buff_attribute, del_buff_attribute, del_step_buff_attribute);
}
public Result GetBuffFromAttribute(EBuffCategory category, int channel, out BuffAttribute.BuffInfo? buff)
{
buff = null;
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {toBasicString()}");
var buff_attribute = player.getOriginEntityAttribute<BuffAttribute>();
if (buff_attribute == null)
{
err_msg = $"Failed to get buff attribute : {nameof(BuffAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
if (buff_attribute.BuffInfos[category].TryGetValue(channel, out buff) == false)
{
err_msg = $"Failed to get buff. category : {category}, channel : {channel}";
result.setFail(ServerErrorCode.BuffNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
return result;
}
public (Result result, BuffAttribute.BuffInfo? add_buff_attribute, BuffAttribute.BuffInfo? del_buff_attribute) AddBuffProcess(META_ID buff_meta_id)
{
BuffAttribute.BuffInfo? add_buff_attribute = null;
BuffAttribute.BuffInfo? del_buff_attribute = null;
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {toBasicString()}");
if (!MetaData.Instance._BuffTable.TryGetValue((int)buff_meta_id, out var buffData))
{
err_msg = $"Not found buffMeta !!! : buffMetaId:{buff_meta_id} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BuffMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null);
}
var buff_attribute = player.getOriginEntityAttribute<BuffAttribute>();
if (buff_attribute == null)
{
err_msg = $"Failed to get buff attribute : {nameof(BuffAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null, null);
}
var copy_buff_attribute = buff_attribute.onCloned() as BuffAttribute;
NullReferenceCheckHelper.throwIfNull(copy_buff_attribute, () => $"copy_buff_attribute is null !!! - {player.toBasicString()}");
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.BuffAdd);
//카테고리별 버프
if (copy_buff_attribute.BuffInfos.TryGetValue(buffData.BuffCategory, out var buffchannelInfo) == false)
{
err_msg = $"Not Registry Buff Category !!! : buffMetaId:{buff_meta_id} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BuffNotRegistryCategory, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null);
}
//이미 동일한 채널의 버프가 있는경우
if (buffchannelInfo.TryGetValue(buffData.BuffChannel, out var buffInfo) == true)
{
if (!MetaData.Instance._BuffTable.TryGetValue((int)buffInfo.BuffMetaID, out var curBuffData))
{
err_msg = $"Not found buffMeta !!! : buffMetaId:{buff_meta_id} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BuffMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null);
}
//새로운것이 더 높거나 같으면 교체
if (curBuffData.BuffPriority <= buffData.BuffPriority)
{
(result, del_buff_attribute) = DelBuff(buffData.BuffCategory, buffData.BuffChannel, ref invokers);
if (result.isFail())
{
return (result, null, null);
}
(result, add_buff_attribute) = AddBuff(buffData, ref invokers);
if (result.isFail())
{
return (result, null, null);
}
BusinessLogger.collectLogs(log_action, player, invokers);
}
return (result, add_buff_attribute, del_buff_attribute);
}
string MaxBuffCategoty = "";
switch (buffData.BuffCategory)
{
case MetaAssets.EBuffCategory.NORMAL: MaxBuffCategoty = "MaxNormalBuffNum"; break;
case MetaAssets.EBuffCategory.INSTANCE: MaxBuffCategoty = "MaxInstanceBuffNum"; break;
case MetaAssets.EBuffCategory.EVENT: MaxBuffCategoty = "MaxEventBuffNum"; break;
case MetaAssets.EBuffCategory.TOOL: MaxBuffCategoty = "MaxToolBuffNum"; break;
case MetaAssets.EBuffCategory.WEAR: MaxBuffCategoty = "MaxWearBuffNum"; break;
default:
break;
}
if (!MetaData.Instance._GameConfigMetaTable.TryGetValue(MaxBuffCategoty, out var strMaxBuffCount))
{
err_msg = $"Not found MaxBuffCategoty !!! : MaxBuffCategoty:{MaxBuffCategoty} - {player.toBasicString()}";
result.setFail(ServerErrorCode.GameConfigMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null);
}
if (false == strMaxBuffCount.toInt32(out var maxBuffCount))
{
err_msg = $"string to int parse failed. data : MaxBuffCount:{strMaxBuffCount} - {player.toBasicString()}";
result.setFail(ServerErrorCode.InvalidMetaData, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null);
}
DateTime? removeBuffStartTime = null;
int removeBuffChannel = -1;
//최대 버퍼수량을 초과했을경우 가장 오래된 버프 제거
if (buffchannelInfo.Count >= maxBuffCount)
{
foreach (var curBuffInfo in buffchannelInfo)
{
if (removeBuffStartTime == null || removeBuffStartTime > curBuffInfo.Value.BuffStartTime)
{
removeBuffStartTime = curBuffInfo.Value.BuffStartTime;
removeBuffChannel = curBuffInfo.Key;
}
}
if (removeBuffStartTime != null)
{
(result, del_buff_attribute) = DelBuff(buffData.BuffCategory, buffData.BuffChannel, ref invokers);
if (result.isFail())
{
return (result, null, null);
}
}
}
(result, add_buff_attribute) = AddBuff(buffData, ref invokers);
if (result.isFail())
{
return (result, null, null);
}
BusinessLogger.collectLogs(log_action, player, invokers);
return (result, add_buff_attribute, del_buff_attribute);
}
public (Result result, BuffAttribute.BuffInfo? del_buff_attribute) DelBuffProcess(META_ID buff_meta_id)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {toBasicString()}");
if (!MetaData.Instance._BuffTable.TryGetValue((int)buff_meta_id, out var buffData))
{
err_msg = $"Not found buffMeta !!! : buffMetaId:{buff_meta_id} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BuffMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null);
}
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.BuffDelete);
(result, var del_buff_attribute) = DelBuff(buffData.BuffCategory, buffData.BuffChannel, ref invokers);
if (result.isFail())
{
return (result, null);
}
BusinessLogger.collectLogs(log_action, player, invokers);
return (result, del_buff_attribute);
}
public async Task<Result> MoveServer(EPlaceType toMove)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {toBasicString()}");
var buff_attribute = player.getOriginEntityAttribute<BuffAttribute>();
if (buff_attribute == null)
{
err_msg = $"Failed to get buff attribute : {nameof(BuffAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
var copy_buff_attribute = buff_attribute.onCloned() as BuffAttribute;
NullReferenceCheckHelper.throwIfNull(copy_buff_attribute, () => $"copy_buff_attribute is null !!! - {player.toBasicString()}");
var delBuff = new List<BuffAttribute.BuffInfo>();
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.BuffDelete);
foreach (var ChannelBuff in copy_buff_attribute.BuffInfos)
{
foreach (var buff in ChannelBuff.Value)
{
if (!MetaData.Instance._BuffTable.TryGetValue((int)buff.Value.BuffMetaID, out var buffData))
{
err_msg = $"Not found ItemMeta !!! : buffMetaId:{buff.Value.BuffMetaID} - {player.toBasicString()}";
result.setFail(ServerErrorCode.ItemMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
continue;
}
if (isRemainBuff(toMove, buffData) == true)
{
continue;
}
delBuff.Add(buff.Value);
ChannelBuff.Value.Remove(buff.Key);
}
}
result = await SaveBuffToCache(copy_buff_attribute);
if (result.isFail())
{
return result;
}
foreach (var buff in delBuff)
{
changeAttribute(buff.BuffMetaID, true);
var task_log_data = BuffBusinessLogHelper.toLogInfo(buff, true);
invokers.Add(new BuffBusinessLog(task_log_data));
}
BusinessLogger.collectLogs(log_action, player, invokers);
BuffNotifyHelper.send_S2C_NTF_DELETE_BUFF_LIST(player, delBuff);
return result;
}
private async Task<Result> SaveBuffToCache(BuffAttribute buff_attribute)
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {toBasicString()}");
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {toBasicString()}");
NullReferenceCheckHelper.throwIfNull(m_buff_cache_request, () => $"m_buff_cache_request is null !!!");
var buff_cache = m_buff_cache_request.newBuffCache();
NullReferenceCheckHelper.throwIfNull(buff_cache, () => $"buff_cache is null !!! - {toBasicString()}");
result = await ServerBase.DataCopyHelper.copyCacheFromEntityAttributes(buff_cache, new List<EntityAttributeBase>() { buff_attribute });
if (result.isFail())
{
return result;
}
result = await m_buff_cache_request.UpsertBuff();
if (result.isFail())
{
return result;
}
return result;
}
private void changeAttribute(META_ID buff_meta_id, bool isDelete)
{
var result = new Result();
var err_msg = string.Empty;
if (!MetaData.Instance._BuffTable.TryGetValue((int)buff_meta_id, out var buffData))
{
err_msg = $"Not found buffMeta !!! : buffMetaId:{buff_meta_id} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.BuffMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return;
}
foreach (var buffAttribute in buffData.Traits)
{
if (buffAttribute.Operation == MetaAssets.ECVArithmeticOperation.Sub)
{
isDelete = isDelete == true ? false : true;
}
var owner = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!! - {toBasicString()}");
var ability_action = owner.getEntityAction<AbilityAction>();
if (ability_action == null)
{
err_msg = $"Failed to get ability action : {nameof(AbilityAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return;
}
if (EnumHelper.tryParse<AttributeType>(buffAttribute.Attribute, out var attribute_enum) == false)
{
err_msg = $"Enum Pase Failed. AttributeType : {buffAttribute.Attribute}";
result.setFail(ServerErrorCode.BuffInvalidAttributeType, err_msg);
Log.getLogger().error(err_msg);
return;
}
ability_action.setAbility(attribute_enum, buffAttribute.Value, isDelete);
}
}
public async Task<Result> tryResetAttributeByBuff()
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {toBasicString()}");
var buff_attribute = player.getOriginEntityAttribute<BuffAttribute>();
NullReferenceCheckHelper.throwIfNull(buff_attribute, () => $"buff_attribute is null !!! - {toBasicString()}");
foreach (var buff_channel in buff_attribute.BuffInfos)
{
foreach (var buff in buff_channel.Value)
{
changeAttribute(buff.Value.BuffMetaID, false);
}
}
return await Task.FromResult(result);
}
private bool isRemainBuff(EPlaceType toMove, MetaAssets.BuffMetaData buffData)
{
switch (toMove)
{
case EPlaceType.Concert: return buffData.IsConcertRemain;
case EPlaceType.Meeting: return buffData.IsMeetingRemain;
case EPlaceType.MyHome: return buffData.IsMyhomeRemain;
case EPlaceType.Movie: return buffData.IsMovieRemain;
case EPlaceType.World: return buffData.IsNormalRemain;
case EPlaceType.BeaconCreateRoom: return buffData.is_beacon_remain;
case EPlaceType.DressRoom: return buffData.is_dressroom_remain;
default:
return false;
}
}
private (Result result, BuffAttribute.BuffInfo? add_buff_attribute) AddBuff(MetaAssets.BuffMetaData buffData, ref List<ILogInvoker> invokers)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {toBasicString()}");
var buff_attribute = player.getOriginEntityAttribute<BuffAttribute>();
if (buff_attribute == null)
{
err_msg = $"Failed to get buff attribute : {nameof(BuffAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
if (buff_attribute.AddBuff(buffData.BuffCategory, buffData.BuffChannel, buffData.BuffId, out var add_buff_attribute_info) == false)
{
err_msg = $"AddBuff failed !!! : buffMetaId:{buffData.BuffId} - {player.toBasicString()}";
result.setFail(ServerErrorCode.ItemMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null);
}
changeAttribute((META_ID)buffData.BuffId, false);
var task_log_data = BuffBusinessLogHelper.toLogInfo(add_buff_attribute_info, false);
invokers.Add(new BuffBusinessLog(task_log_data));
return (result, add_buff_attribute_info);
}
private (Result result, BuffAttribute.BuffInfo? del_buff_attribute) DelBuff(MetaAssets.EBuffCategory category, int channel, ref List<ILogInvoker> invokers)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {toBasicString()}");
var buff_attribute = player.getOriginEntityAttribute<BuffAttribute>();
if (buff_attribute == null)
{
err_msg = $"Failed to get buff attribute : {nameof(BuffAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
if (buff_attribute.RemoveBuff(category, channel, out var del_buff_attribute_info) == false)
{
err_msg = $"Failed Found Buff : BuffCategory:{category} channel:{channel} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BuffNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null);
}
changeAttribute(del_buff_attribute_info.BuffMetaID, true);
var task_log_data = BuffBusinessLogHelper.toLogInfo(del_buff_attribute_info, true);
invokers.Add(new BuffBusinessLog(task_log_data));
return (result, del_buff_attribute_info);
}
public override async Task onTick()
{
updateBuff();
await Task.CompletedTask;
}
public Result updateBuff()
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
try
{
var listDeleteChannel = new List<int>();
var buff_attribute = player.getOriginEntityAttribute<BuffAttribute>();
if (buff_attribute == null)
{
err_msg = $"Failed to get buff attribute : {nameof(BuffAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return result;
}
var copy_buff_attribute = buff_attribute.onCloned() as BuffAttribute;
NullReferenceCheckHelper.throwIfNull(copy_buff_attribute, () => $"copy_buff_attribute is null !!!");
var it = copy_buff_attribute.BuffInfos.GetEnumerator();
while (it.MoveNext() == true)
{
var buffDirectory = it.Current;
var iter = buffDirectory.Value.GetEnumerator();
while (iter.MoveNext() == true)
{
var buff = iter.Current;
if (!MetaData.Instance._BuffTable.TryGetValue((int)buff.Value.BuffMetaID, out MetaAssets.BuffMetaData? buffData))
{
err_msg = $"Not found BuffMetaID : {buff.Value.BuffMetaID}";
Log.getLogger().error(err_msg);
continue;
}
if (buffData.BuffChannel != buff.Key)
{
err_msg = $"Not found BuffChannel : {buffData.BuffChannel}";
Log.getLogger().error(err_msg);
continue;
}
if (buffData.DurationTime == 0) // 무한
{
continue;
}
DateTime endTime = buff.Value.BuffStartTime.AddSeconds(buffData.DurationTime);
if (DateTime.UtcNow >= endTime)
{
(result, var del_buff_attribute) = DelBuffProcess((META_ID)buffData.BuffId);
if (result.isFail()) continue;
Log.getLogger().debug($"DelBuff Ticker. buff meta id : {buffData.BuffId}");
BuffNotifyHelper.send_S2C_NTF_DELETE_BUFF(player, del_buff_attribute);
if (buffData.BuffEndExecutionType == EBuffEndExecution.GETBUFF)
{
int newBuffId = buffData.BuffEndExecutionValue;
if (MetaData.Instance._BuffTable.TryGetValue(newBuffId, out MetaAssets.BuffMetaData? newData))
{
if (newData.BuffChannel != buffData.BuffChannel)
{
err_msg = $"Buff Channel newBuffId:{newBuffId} newData.BuffChannel:{newData.BuffChannel} data.BuffChannel:{buffData.BuffChannel} BuffMetaID:{buff.Value.BuffMetaID}";
Log.getLogger().error(result.toBasicString());
continue;
}
(result, var add_buff_attribute, del_buff_attribute) = AddBuffProcess((META_ID)newBuffId);
BuffNotifyHelper.send_S2C_NTF_DELETE_BUFF(player, del_buff_attribute);
BuffNotifyHelper.send_S2C_NTF_START_BUFF(player, add_buff_attribute);
}
}
}
}
}
return result;
}
catch (Exception e)
{
Log.getLogger().error(e.Message);
result.setFail(ServerErrorCode.TryCatchException, err_msg);
return result;
}
}
}

View File

@@ -0,0 +1,38 @@
using ServerCommon;
using ServerCore; using ServerBase;
namespace GameServer;
[ChatCommandAttribute("startbuff", typeof(ChatCommandStartBuff), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class ChatCommandStartBuff : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
await Task.CompletedTask;
Log.getLogger().info($"HandleStartBuff");
if (args.Length < 1)
{
Log.getLogger().error($"Invalid Argument");
return;
}
if (!uint.TryParse(args[0], out var buff_meta_id))
{
Log.getLogger().error($"questcomplete param parsing Error args : {args[0]}");
return;
}
var buff_action = player.getEntityAction<BuffAction>();
(var result, var add_buff_attribute, var del_buff_attribute) = buff_action.AddBuffProcess(buff_meta_id);
if (result.isFail())
{
Log.getLogger().error($"Failed to AddBuffProcess() !!! : {result.toBasicString()} - {player.toBasicString()}");
return;
}
BuffNotifyHelper.send_S2C_NTF_DELETE_BUFF(player, del_buff_attribute);
BuffNotifyHelper.send_S2C_NTF_START_BUFF(player, add_buff_attribute);
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using ServerCommon;
namespace GameServer
{
public static class BuffHelper
{
public static List<Buff> toBuffData4Client(this BuffAttribute buffAttribute)
{
var buff_list_4_client = new List<Buff>();
foreach (var buff_info in buffAttribute.BuffInfos)
{
foreach (var info in buff_info.Value)
{
Buff buff = new Buff();
buff.BuffId = (Int32)info.Value.BuffMetaID;
buff.BuffStartTime = info.Value.BuffStartTime.ToTimestamp();
buff_list_4_client.Add(buff);
}
}
return buff_list_4_client;
}
}
}

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 class BuffBusinessLog : ILogInvokerEx
{
private BuffLogData m_data_to_log;
public BuffBusinessLog(BuffLogData log_data_param)
: base(LogDomainType.Buff)
{
m_data_to_log = log_data_param;
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(new BuffLogData(this, m_data_to_log));
}
}

View File

@@ -0,0 +1,25 @@
using ServerCommon.BusinessLogDomain;
using ServerCommon;
using META_ID = System.UInt32;
namespace GameServer
{
static public class BuffBusinessLogHelper
{
static public BuffLogData toLogInfo(BuffAttribute.BuffInfo buffInfo, bool isDeleteBuff)
{
var logData = new BuffLogData();
logData.setInfo(buffInfo, isDeleteBuff);
return logData;
}
static public void setInfo(this BuffLogData logData, BuffAttribute.BuffInfo buffInfo, bool isDeleteBuff)
{
logData.BuffMetaID = buffInfo.BuffMetaID;
logData.BuffStartTime = buffInfo.BuffStartTime;
logData.BuffEndTime = DateTime.MinValue;
if (isDeleteBuff == true) logData.BuffEndTime = DateTime.UtcNow;
}
}
}

View File

@@ -0,0 +1,172 @@
using ServerCommon;
using static ClientToGameRes.Types;
using USER_GUID = System.String;
using META_ID = System.UInt32;
using Google.Protobuf.WellKnownTypes;
using ServerCore; using ServerBase;
namespace GameServer
{
public static class BuffNotifyHelper
{
public static bool send_S2C_NTF_START_BUFF(Player player, BuffAttribute.BuffInfo? buffAttributeInfo)
{
if (buffAttributeInfo == null)
{
return false;
}
var noti_packet = makeNotiStartBuffPacket(buffAttributeInfo, player.getUserGuid());
var game_zone_action = player.getEntityAction<GameZoneAction>();
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!!");
game_zone_action.broadcast(player, noti_packet);
QuestManager.It.QuestCheck(player, new QuestBuff(EQuestEventTargetType.BUFF, EQuestEventNameType.USED, (int)buffAttributeInfo.BuffMetaID)).Wait();
return true;
}
public static ClientToGame makeAckStartBuffPacket()
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = ServerErrorCode.Success;
ack_packet.Response.StartBuffRes = new StartBuffRes();
return ack_packet;
}
public static ClientToGame makeNotiStartBuffPacket(BuffAttribute.BuffInfo buffAttributeInfo, USER_GUID user_Guid)
{
var noti_packet = new ClientToGame();
noti_packet.Message = new();
noti_packet.Message.StartBuffNoti = new();
noti_packet.Message.StartBuffNoti.ActorGuid = user_Guid;
noti_packet.Message.StartBuffNoti.Buf = new();
noti_packet.Message.StartBuffNoti.Buf.BuffId = (int)buffAttributeInfo.BuffMetaID;
noti_packet.Message.StartBuffNoti.Buf.BuffStartTime = buffAttributeInfo.BuffStartTime.ToTimestamp();
return noti_packet;
}
//이 패킷으로 stop모두 처리해도 되지 않을까
public static bool send_S2C_NTF_DELETE_BUFF(Player player, BuffAttribute.BuffInfo? buffAttributeInfo)
{
if(buffAttributeInfo == null)
{
return false;
}
var noti_packet = makeNotiDeleteBuffPacket(buffAttributeInfo, player.getUserGuid());
var game_zone_action = player.getEntityAction<GameZoneAction>();
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!!");
game_zone_action.broadcast(player, noti_packet);
return true;
}
public static ClientToGame makeAckDeleteBuffPacket()
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = ServerErrorCode.Success;
ack_packet.Response.StopBuffRes = new StopBuffRes();
return ack_packet;
}
public static ClientToGame makeNotiDeleteBuffPacket(BuffAttribute.BuffInfo buffInfo, USER_GUID user_Guid)
{
var noti_packet = new ClientToGame();
noti_packet.Message = new();
noti_packet.Message.StopBuffNoti = new();
noti_packet.Message.StopBuffNoti.ActorGuid = user_Guid;
noti_packet.Message.StopBuffNoti.Buf = new();
noti_packet.Message.StopBuffNoti.Buf.BuffId = (int)buffInfo.BuffMetaID;
noti_packet.Message.StopBuffNoti.Buf.BuffStartTime = buffInfo.BuffStartTime.ToTimestamp();
return noti_packet;
}
public static bool send_S2C_NTF_DELETE_BUFF_LIST(Player player, List<BuffAttribute.BuffInfo>? buffAttributeInfo)
{
if (buffAttributeInfo == null)
{
return false;
}
var noti_packet = new ClientToGame();
noti_packet.Message = new ();
noti_packet.Message.DelBuffListNoti = new ();
foreach (var buff_attribute in buffAttributeInfo)
{
var buff_info = new Buff();
buff_info.BuffId = (int)buff_attribute.BuffMetaID;
buff_info.BuffStartTime = buff_attribute.BuffStartTime.ToTimestamp();
noti_packet.Message.DelBuffListNoti.DelBuffList.Add(buff_info);
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, noti_packet))
{
return false;
}
return true;
}
public static bool send_S2C_NTF_USE_EQUIPED_BUFF(Player player, USER_GUID user_guid, META_ID buff_meta_id, int client_buff_step, int client_buff_random_state, Int64 client_buff_action_start_time)
{
var noti_packet = new ClientToGame();
noti_packet.Message = new();
noti_packet.Message.UseEquipedBuffNoti = new();
noti_packet.Message.UseEquipedBuffNoti.ActorGuid = user_guid;
noti_packet.Message.UseEquipedBuffNoti.EquipedBuffId = (int)buff_meta_id;
noti_packet.Message.UseEquipedBuffNoti.EquipedBuffStep = client_buff_step;
noti_packet.Message.UseEquipedBuffNoti.EquipedBuffRandomState = client_buff_random_state;
noti_packet.Message.UseEquipedBuffNoti.ActionStartTime = client_buff_action_start_time;
if (false == GameServerApp.getServerLogic().onSendPacket(player, noti_packet))
{
return false;
}
var game_zone_action = player.getEntityAction<GameZoneAction>();
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!!");
game_zone_action.broadcast(player, noti_packet);
return true;
}
public static bool send_S2C_NTF_LOGIN_BUFF(this Player player)
{
var buffAttribute = player.getEntityAttribute<BuffAttribute>();
NullReferenceCheckHelper.throwIfNull(buffAttribute, () => $"buffAttribute is null !!!");
var noti_packet = new ClientToGame();
noti_packet.Message = new();
noti_packet.Message.LoginBuffNoti = new();
noti_packet.Message.LoginBuffNoti.BuffInfo = new();
if(buffAttribute != null)
{
noti_packet.Message.LoginBuffNoti.BuffInfo.Buff.AddRange(buffAttribute.toBuffData4Client());
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, noti_packet))
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,94 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
using META_ID = System.UInt32;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.StartBuffReq), typeof(StartBuffPacketHandler), typeof(GameLoginListener))]
public class StartBuffPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_START_BUFF(Player player, Result result)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.StartBuffRes = new StartBuffRes();
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var player = entityWithSession as Player;
ArgumentNullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var game_msg = recvMessage as ClientToGame;
ArgumentNullReferenceCheckHelper.throwIfNull(game_msg, () => $"game_msg is null !!! - {player.toBasicString()}");
var request = game_msg.Request.StartBuffReq;
ArgumentNullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {player.toBasicString()}");
var player_action = player.getEntityAction<PlayerAction>();
NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {player.toBasicString()}");
// 1. 캐릭터 선택 상태 체크
var selected_character = player_action.getSelectedCharacter();
if (null == selected_character)
{
err_msg = $"Not selected Character !!! - {player.toBasicString()}";
result.setFail(ServerErrorCode.CharacterNotSelected, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_START_BUFF(player, result);
return Task.FromResult(result);
}
var buff_action = player.getEntityAction<BuffAction>();
NullReferenceCheckHelper.throwIfNull(buff_action, () => $"buff_action is null !!! - {player.toBasicString()}");
(result, var add_buff_attribute, var del_buff_attribute) = buff_action.AddBuffProcess((META_ID)request.BuffId);
if (result.isFail())
{
err_msg = $"Failed to AddBuffProcess() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
send_S2C_ACK_START_BUFF(player, result);
return Task.FromResult(result);
}
send_S2C_ACK_START_BUFF(player, result);
BuffNotifyHelper.send_S2C_NTF_DELETE_BUFF(player, del_buff_attribute);
BuffNotifyHelper.send_S2C_NTF_START_BUFF(player, add_buff_attribute);
return Task.FromResult(result);
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_START_BUFF(player, errorResult);
}
}

View File

@@ -0,0 +1,93 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
using META_ID = System.UInt32;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.StopBuffReq), typeof(StopBuffPacketHandler), typeof(GameLoginListener))]
public class StopBuffPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_STOP_BUFF(Player player, Result result)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.StopBuffRes = new StopBuffRes();
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
ArgumentNullException.ThrowIfNull(entity_player, $"entity_player is null !!!");
var buff_action = entity_player.getEntityAction<BuffAction>();
if (buff_action == null)
{
err_msg = $"Failed to get buff action : {nameof(BuffAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_STOP_BUFF(entity_player, result);
return Task.FromResult(result);
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.StopBuffReq)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_STOP_BUFF(entity_player, result);
return Task.FromResult(result);
}
var request = game_msg.Request.StopBuffReq;
(result, var del_buff_attribute) = buff_action.DelBuffProcess((META_ID)request.BuffId);
if (result.isFail())
{
err_msg = $"Failed to DelBuffProcess() !!! : {result.toBasicString()} - {entity_player.toBasicString()}";
Log.getLogger().error(err_msg);
send_S2C_ACK_STOP_BUFF(entity_player, result);
return Task.FromResult(result);
}
send_S2C_ACK_STOP_BUFF(entity_player, result);
BuffNotifyHelper.send_S2C_NTF_DELETE_BUFF(entity_player, del_buff_attribute);
return Task.FromResult(result);
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_STOP_BUFF(player, errorResult);
}
}

View File

@@ -0,0 +1,84 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
using META_ID = System.UInt32;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.UseEquipedBuffReq), typeof(UseEquipedBuffPacketHandler), typeof(GameLoginListener))]
public class UseEquipedBuffPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_USE_EQUIPED_BUFF(Player player, Result result)
{
var err_msg = string.Empty;
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.UseEquipedBuffRes = new UseEquipedBuffRes();
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var player = entityWithSession as Player;
ArgumentNullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var req_msg = recvMessage as ClientToGame;
ArgumentNullReferenceCheckHelper.throwIfNull(req_msg, () => $"req_msg is null !!! - {player.toBasicString()}");
var request = req_msg.Request.UseEquipedBuffReq;
ArgumentNullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {player.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
var server_logic = GameServerApp.getServerLogic();
var buff_action = player.getEntityAction<BuffAction>();
NullReferenceCheckHelper.throwIfNull(buff_action, () => $"buff_action is null !!! - {player.toBasicString()}");
(result, var add_buff_attribute, var del_buff_attribute, var del_step_buff_attribute) = buff_action.UseEqipedBuff((META_ID)request.EquopedBuffId, request.EquipedBuffStep);
if (result.isFail())
{
err_msg = $"Failed to UseEqipedBuff() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
send_S2C_ACK_USE_EQUIPED_BUFF(player, result);
return await Task.FromResult(result);
}
send_S2C_ACK_USE_EQUIPED_BUFF(player, result);
BuffNotifyHelper.send_S2C_NTF_USE_EQUIPED_BUFF(player, player.getUserGuid(), (META_ID)request.EquopedBuffId, request.EquipedBuffStep, request.EquipedBuffRandomState, request.ActionStartTime);
BuffNotifyHelper.send_S2C_NTF_DELETE_BUFF(player, del_step_buff_attribute);
BuffNotifyHelper.send_S2C_NTF_DELETE_BUFF(player, del_buff_attribute);
BuffNotifyHelper.send_S2C_NTF_START_BUFF(player, add_buff_attribute);
return await Task.FromResult(result);
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_USE_EQUIPED_BUFF(player, errorResult);
}
}

View File

@@ -0,0 +1,218 @@

using ServerCore;
using ServerBase;
using ServerCommon;
namespace GameServer;
public class CaliumConverterAction : EntityActionBase
{
public CaliumConverterAction(Player owner) : base(owner)
{
}
public override async Task<Result> onInit() => await Task.FromResult(new Result());
public override void onClear()
{
return;
}
public async Task<(double calium, double currency)> calculationConvertCalium(Dictionary<int, int> useMaterials)
{
var total_fluxEtheron = 0.0;
// 1. 플럭스 에테론 변환 처리
foreach (var material in useMaterials)
{
if (!MetaData.Instance._CaliumConverterMaterialTable.TryGetValue(material.Key, out var material_data)) continue;
var fluxEtheron = material_data.Value * material.Value;
total_fluxEtheron = CaliumStorageHelper.AddDoubleByLong(total_fluxEtheron, fluxEtheron);
}
// 2. calium 계산 : fluxEtheron * 기본 변환율 * 에너지 효율 / 소수점 버림 처리
var calium_storage_entity = GameServerApp.getServerLogic().findGlobalEntity<CaliumStorageEntity>();
NullReferenceCheckHelper.throwIfNull(calium_storage_entity, () => $"calium_storage_entity is null !!! : {getOwner().toBasicString()}");
var calium_storage_action = calium_storage_entity.getEntityAction<CaliumStorageAction>();
NullReferenceCheckHelper.throwIfNull(calium_storage_action, () => $"calium_storage_action is null !!! : {getOwner().toBasicString()}");
var efficiency = await calium_storage_action.getCaliumConverterEfficiency();
var calium = total_fluxEtheron * (double)MetaHelper.GameConfigMeta.CaliumConverterConversionRate * efficiency;
calium = CaliumStorageHelper.roundDownDefaultDigitsFromDouble(calium);
// 3. 요구 재화 계산 : 소수점 올림 처리
var currency = total_fluxEtheron * (double)ServerCommon.MetaHelper.GameConfigMeta.CaliumConverterCommissionRate;
currency = Math.Ceiling(currency);
return (calium, currency);
}
public Result checkConvertConditions(Dictionary<int, int> useMaterials, double convertCalium, double currency)
{
var server_logic = GameServerApp.getServerLogic();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var result = new Result();
string err_msg;
var calium_storage_entity = server_logic.findGlobalEntity<CaliumStorageEntity>();
var calium_storage_action = calium_storage_entity?.getEntityAction<CaliumStorageAction>();
NullReferenceCheckHelper.throwIfNull(calium_storage_action, () => $"calium_storage_action is null !!!");
// 1. Calium 총량 체크
var total_calium = calium_storage_action.getTotalCalium(CaliumStorageType.Converter);
if (total_calium < 0)
{
err_msg = $"fail to convert calium!!! : loading calium - {checkConvertConditions}";
result.setFail(ServerErrorCode.FailToLoadCalium, err_msg);
Log.getLogger().error(err_msg);
return result;
}
if (convertCalium > total_calium)
{
err_msg = $"fail to convert calium!!! : lack of total calium - calium[{convertCalium}] / total[{total_calium}]";
result.setFail(ServerErrorCode.LackOfTotalCalium, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 2. 1일 제한 용량 체크
var user_calium_attribute = player.getEntityAttribute<CaliumAttribute>();
NullReferenceCheckHelper.throwIfNull(user_calium_attribute, () => $"user_calium_attribute is null !!! - {player.toBasicString()}");
var daily_calium = CaliumStorageHelper.roundHalfUpDefaultDigitsFromDouble(user_calium_attribute.DailyCalium);
if (convertCalium > daily_calium)
{
err_msg = $"fail to convert calium!!! : lack of daily calium - calium[{convertCalium}] / daily[{user_calium_attribute.DailyCalium}] / roundUp[{daily_calium}]";
result.setFail(ServerErrorCode.LackOfDailyCalium, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 3. 재화 보유 체크
if (! checkCurrencyForConvertCalium(currency))
{
err_msg = $"fail to convert calium!!! : lack of currency - currency[{currency}]";
result.setFail(ServerErrorCode.LackOfCommissionCurrency, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 4. 아이템 보유 체크
if (!checkItemForConvertCalium(useMaterials))
{
err_msg = $"fail to convert calium!!! : lack of meterial - useMaterials[{useMaterials}]";
result.setFail(ServerErrorCode.LackOfCommissionMaterials, err_msg);
Log.getLogger().error(err_msg);
return result;
}
return result;
}
private bool checkCurrencyForConvertCalium(double currency)
{
var money_attribute = getOwner().getEntityAttribute<MoneyAttribute>();
NullReferenceCheckHelper.throwIfNull(money_attribute, () => $"money_attribute is null !!!");
var owner_currency = MetaHelper.GameConfigMeta.CaliumConverterCommissionType switch
{
CurrencyType.Gold => money_attribute.Gold,
CurrencyType.Sapphire => money_attribute.Sapphire,
CurrencyType.Ruby => money_attribute.Ruby,
_ => 0.0
};
return currency <= owner_currency;
}
private bool checkItemForConvertCalium(Dictionary<int, int> useMaterials)
{
foreach (var material in useMaterials)
{
var inventory_action = getOwner().getEntityAction<InventoryActionBase>();
if (!MetaData.Instance._CaliumConverterMaterialTable.TryGetValue(material.Key, out var material_data))
{
return false;
}
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!!");
var own_count = inventory_action.getItemStackCountAllByMetaId((uint)material_data.ItemId);
if (material.Value > own_count) return false;
}
return true;
}
public async Task<(Result result, IEnumerable<GameServer.Item>? items)> deleteMaterials(Dictionary<int, int> useMaterials)
{
var result = new Result();
string err_msg;
var inventory_action = getOwner().getEntityAction<InventoryActionBase>();
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!!");
var items = new List<GameServer.Item>();
foreach (var material in useMaterials)
{
if (!MetaData.Instance._CaliumConverterMaterialTable.TryGetValue(material.Key, out var material_data))
{
err_msg = $"fail to convert calium !!! : invalid material slot id - input slotId[{material.Key}]";
result.setFail(ServerErrorCode.InvalidMaterialSlotId, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null);
}
(result, var item) = await inventory_action.tryDeleteItemByMetaId((uint)material_data.ItemId, (ushort)material.Value);
if (result.isFail())
{
err_msg = $"fail to convert calium !!! : lack of material count - input slotId[{material.Key}] / cout[{material.Value}]";
result.setFail(ServerErrorCode.LackOfCommissionMaterials, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null);
}
items.AddRange(item);
}
return (result, items);
}
public async Task<Result> changeCurrency(double obtainCalium, CurrencyType currencyType, double spendCurrency)
{
var result = new Result();
var money_action = getOwner().getEntityAction<MoneyAction>();
NullReferenceCheckHelper.throwIfNull(money_action, () => $"money_action is null !!!");
// 1. calium 획득
result = await money_action.changeMoney(CurrencyType.Calium, obtainCalium, useCaliumEvent: false);
if (result.isFail()) return result;
// 2. 변환을 위한 재화 소모
result = await money_action.changeMoney(currencyType, -1 * spendCurrency, useCaliumEvent: false);
return result;
}
public Result changeDailyCalium(Player player, double calium)
{
var result = new Result();
// 1. 개인 daily calium 수량 수정
var user_calium_attribute = player.getEntityAttribute<CaliumAttribute>();
NullReferenceCheckHelper.throwIfNull(user_calium_attribute, () => $"user_calium_attribute is null !!! - calium:{calium} / {player.toBasicString()}");
user_calium_attribute.DailyCalium -= calium;
user_calium_attribute.modifiedEntityAttribute();
return result;
}
}

View File

@@ -0,0 +1,69 @@
using ServerCore;
using ServerBase;
using ServerCommon;
namespace GameServer;
public class CaliumExchangerAction : EntityActionBase
{
private const double BaseExchangeValue = 0.01;
public CaliumExchangerAction(Player owner) : base(owner)
{
}
public override async Task<Result> onInit() => await Task.FromResult(new Result());
public override void onClear()
{
return;
}
public async Task<double> calculationConvertCalium(double sapphire)
{
var calium = await CaliumStorageHelper.calculateCaliumFromSapphire(sapphire);
if (calium < BaseExchangeValue) calium = 0;
return calium;
}
public Result checkConvertConditions(double sapphire)
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
// 1. 재화 보유 체크
var money_attribute = getOwner().getEntityAttribute<MoneyAttribute>();
NullReferenceCheckHelper.throwIfNull(money_attribute, () => $"money_attribute is null !!!");
if (money_attribute.Sapphire < sapphire)
{
var err_msg = $"fail to convert calium!!! : lack of currency - currency[{sapphire}]";
result.setFail(ServerErrorCode.LackOfCommissionCurrency, err_msg);
Log.getLogger().error(err_msg);
}
return result;
}
public async Task<Result> changeCurrency(double obtainCalium, CurrencyType currencyType, double spendCurrency)
{
var result = new Result();
var money_action = getOwner().getEntityAction<MoneyAction>();
NullReferenceCheckHelper.throwIfNull(money_action, () => $"money_action is null !!!");
// 1. calium 획득
result = await money_action.changeMoney(CurrencyType.Calium, obtainCalium, useCaliumEvent: false);
if (result.isFail()) return result;
// 2. 변환을 위한 재화 소모
result = await money_action.changeMoney(currencyType, -1 * spendCurrency, useCaliumEvent: false);
return result;
}
}

View File

@@ -0,0 +1,50 @@
using ServerCommon;
using ServerCore; using ServerBase;
namespace GameServer.Contents.Calium;
[ChatCommandAttribute("caliumexchanger", typeof(ChatCommandCaliumExchanger), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
public class ChatCommandCaliumExchanger : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"ChatCommandCaliumExchanger");
var message = new ClientToGame();
message.Request = new ClientToGameReq();
message.Request.ReqCaliumExchangerInfo = new();
var result = await GameServerApp.getServerLogic().onCallProtocolHandler(player, message);
if (result.isFail())
{
Log.getLogger().error($"fail to run ChatCommandCaliumExchanger!! : {result.toBasicString()}");
}
}
}
[ChatCommandAttribute("exchangecalium", typeof(ChatCommandConvertExchangeCalium), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
public class ChatCommandConvertExchangeCalium : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"ChatCommandConvertExchangeCalium");
if (args.Length < 1 ||false == double.TryParse(args[0], out var sapphire))
{
var err_msg = $"Not enough argument !!! : argCount:{args.Length} == 1 - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
var message = new ClientToGame();
message.Request = new ClientToGameReq();
message.Request.ReqConvertExchangerCalium = new();
message.Request.ReqConvertExchangerCalium.Sapphire = sapphire;
var result = await GameServerApp.getServerLogic().onCallProtocolHandler(player, message);
if (result.isFail())
{
Log.getLogger().error($"fail to run ChatCommandConvertExchangeCalium!! : {result.toBasicString()}");
}
}
}

View File

@@ -0,0 +1,200 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_CONVERT_EXCHANGER_CALIUM), typeof(ConvertExchangerCaliumPacketHandler), typeof(GameLoginListener))]
public class ConvertExchangerCaliumPacketHandler : PacketRecvHandler
{
private async Task send_S2C_ACK_CONVERT_EXCHANGER_CALIUM(Player owner, Result result)
{
var ack_packet = new ClientToGame
{
Response = new ClientToGameRes
{
ErrorCode = result.ErrorCode,
AckConvertExchangerCalium = new ()
}
};
if (result.isSuccess())
{
var account_attribute = owner.getOriginEntityAttribute<AccountAttribute>();
var level_attribute = owner.getOriginEntityAttribute<LevelAttribute>();
var money_attribute = owner.getOriginEntityAttribute<MoneyAttribute>();
var nickname_attribute = owner.getOriginEntityAttribute<NicknameAttribute>();
var char_info = new CharInfo
{
Level = (int)level_attribute!.Level,
Exp = (int)level_attribute.Exp,
Gold = money_attribute!.Gold,
Sapphire = money_attribute.Sapphire,
Calium = money_attribute.Calium,
Ruby = money_attribute.Ruby,
Usergroup = account_attribute!.AuthAdminLevelType.ToString(),
Operator = (int)account_attribute.AuthAdminLevelType,
DisplayName = nickname_attribute!.Nickname,
LanguageInfo = (int)account_attribute.LanguageType,
IsIntroComplete = 1
};
ack_packet.Response.AckConvertExchangerCalium.CurrencyInfo = char_info;
}
GameServerApp.getServerLogic().onSendPacket(owner, ack_packet);
await Task.CompletedTask;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
string err_msg;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
// 1. 기본 정보 체크
var request = (recvMessage as ClientToGame)?.Request.ReqConvertExchangerCalium;
if (null == request)
{
err_msg = $"Failed to get request type !!! : {nameof(ClientToGame.Request.ReqConvertExchangerCalium)}";
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
await send_S2C_ACK_CONVERT_EXCHANGER_CALIUM(player, result);
return result;
}
// 2. 변환 로직 시행
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents,
"CaliumConverterConvertSapphireToCalium", convertSapphireToCaliumDelegate);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
await send_S2C_ACK_CONVERT_EXCHANGER_CALIUM(player, result);
}
return result;
async Task<Result> convertSapphireToCaliumDelegate() => await convertSapphireToCalium(player, request.Sapphire);
}
private async Task<Result> convertSapphireToCalium(Player player, double sapphire)
{
var result = new Result();
var user_calium_exchager_action = player.getEntityAction<CaliumExchangerAction>();
NullReferenceCheckHelper.throwIfNull(user_calium_exchager_action, () => $"user_calium_exchager_action is null !!!");
var calium_storage_entity = GameServerApp.getServerLogic().findGlobalEntity<CaliumStorageEntity>();
NullReferenceCheckHelper.throwIfNull(calium_storage_entity, () => $"calium_storage_entity is null !!! - {player.toBasicString()}");
var calium_storage_action = calium_storage_entity.getEntityAction<CaliumStorageAction>();
NullReferenceCheckHelper.throwIfNull(calium_storage_action, () => $"calium_storage_action is null !!! - {player.toBasicString()}");
// 0. calium storage 체크
result = await calium_storage_action.enableCaliumStorage();
if (result.isFail()) return result;
// 1. Convert 수량 계산
var calium = await user_calium_exchager_action.calculationConvertCalium(sapphire);
if (calium <= 0)
{
var err_msg = $"failed to convert calium !!! - lack of convert calium:[{calium}] / {player.toBasicString()}]";
result.setFail(ServerErrorCode.LackOfConvertCalium, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
// 2. Convert 조건 체크
result = user_calium_exchager_action.checkConvertConditions(sapphire);
if (result.isFail()) return result;
// 3. 재화 변경
result = await user_calium_exchager_action.changeCurrency(calium, CurrencyType.Sapphire, sapphire);
if (result.isFail()) return result;
// 4. DB 갱신 - player
{
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.ConvertExchangeCalium, GameServerApp.getServerLogic().getDynamoDbClient(), true);
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail()) return result;
}
// 5. 변경사항 전송
var calium_event_action = calium_storage_entity.getEntityAction<CaliumEventAction>();
NullReferenceCheckHelper.throwIfNull(calium_event_action, () => $"calium_event_action is null !!! - {player.toBasicString()}");
var send = await calium_event_action.sendCaliumEventFromPlayer(player, CaliumEventType.calium_get, "교환소 교환", -1 * sapphire, calium, false);
// 6. 실패시 재화 롤백
if (false == send.is_success)
{
result = await rollbackCurrency(player, calium, sapphire, send.event_data);
// 6-1. 롤백 성공시 패킷 실패 처리
if (result.isSuccess())
{
var err_msg = $"failed to send echoSystem: sapphire[{sapphire}] / {player.toBasicString()}";
result.setFail(ServerErrorCode.FailToSendEchoSystem, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 6-2. 롤백 실패시 변경사항 전송 재시도 ( 패킷 성공 처리 )
_ = await calium_event_action.sendCaliumEventFromPlayer(player, CaliumEventType.calium_get, "교환소 교환", -1 * sapphire, calium);
}
// 7. Response 응답
await send_S2C_ACK_CONVERT_EXCHANGER_CALIUM(player, result);
return result;
}
private async Task<Result> rollbackCurrency(Player player, double calium, double sapphire, CaliumEventData eventData)
{
var user_calium_exchanger_action = player.getEntityAction<CaliumExchangerAction>();
NullReferenceCheckHelper.throwIfNull(user_calium_exchanger_action, () => $"user_calium_exchanger_action is null !!!");
var result = new Result();
string err_msg;
try
{
// 1. 재화 변경
result = await user_calium_exchanger_action.changeCurrency(-1 * calium, CurrencyType.Sapphire, -1 * sapphire);
if (result.isFail()) return result;
// 2. DB 갱신
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.ConvertExchangeCalium,
GameServerApp.getServerLogic().getDynamoDbClient(), true);
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail()) return result;
}
catch (Exception e)
{
err_msg = $"failed to rollback currency !!! - calium[{calium}] sapphire[{sapphire}] / {e} / {player.toBasicString()}";
result.setFail(ServerErrorCode.FailToSendEchoSystem, err_msg);
Log.getLogger().error(result.toBasicString());
}
return result;
}
}

View File

@@ -0,0 +1,199 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_CONVERT_MATERIAL_TO_CALIUM), typeof(ConvertMaterialToCaliumPacketHandler), typeof(GameLoginListener))]
public class ConvertMaterialToCaliumPacketHandler : PacketRecvHandler
{
private async Task send_S2C_ACK_CONVERT_MATERIAL_TO_CALIUM(Player owner, Result result, double totalCalium, float caliumForUser, List<Item>? items)
{
var ack_packet = new ClientToGame
{
Response = new ClientToGameRes
{
ErrorCode = result.ErrorCode,
AckConvertMaterialToCalium = new()
}
};
if (result.isSuccess())
{
ack_packet.Response.AckConvertMaterialToCalium.TotalCalium = totalCalium;
ack_packet.Response.AckConvertMaterialToCalium.CaliumForUser = caliumForUser;
if (null != items)
{
ack_packet.Response.AckConvertMaterialToCalium.DelItem.AddRange(items.Select(item => item.toItemData4Client()));
}
// char info 획득
var account_attribute = owner.getOriginEntityAttribute<AccountAttribute>();
var level_attribute = owner.getOriginEntityAttribute<LevelAttribute>();
var money_attribute = owner.getOriginEntityAttribute<MoneyAttribute>();
var nickname_attribute = owner.getOriginEntityAttribute<NicknameAttribute>();
var char_info = new CharInfo
{
Level = (int)level_attribute!.Level,
Exp = (int)level_attribute.Exp,
Gold = money_attribute!.Gold,
Sapphire = money_attribute.Sapphire,
Calium = money_attribute.Calium,
Ruby = money_attribute.Ruby,
Usergroup = account_attribute!.AuthAdminLevelType.ToString(),
Operator = (int)account_attribute.AuthAdminLevelType,
DisplayName = nickname_attribute!.Nickname,
LanguageInfo = (int)account_attribute.LanguageType,
IsIntroComplete = 1
};
ack_packet.Response.AckConvertMaterialToCalium.CurrencyInfo = char_info;
}
GameServerApp.getServerLogic().onSendPacket(owner, ack_packet);
await Task.CompletedTask;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
string err_msg;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
// 1. 기본 정보 체크
var request = (recvMessage as ClientToGame)?.Request.ReqConvertMaterialToCalium;
if (null == request)
{
err_msg = $"Failed to get request type !!! : {nameof(ClientToGame.Request.ReqConvertMaterialToCalium)}";
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
await send_S2C_ACK_CONVERT_MATERIAL_TO_CALIUM(player, result, -1, -1, null);
return result;
}
// 2. 변환 로직 시행
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "CaliumConverterConvertMaterialToCalium", convertMaterialToCaliumDelegate);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
await send_S2C_ACK_CONVERT_MATERIAL_TO_CALIUM(player, result, -1, -1, null);
}
return result;
async Task<Result> convertMaterialToCaliumDelegate() => await convertMaterialToCalium(player, request.UseMaterials.ToDictionary());
}
private async Task<Result> convertMaterialToCalium(Player player, Dictionary<int, int> useMaterials)
{
var server_logic = GameServerApp.getServerLogic();
var result = new Result();
var user_calium_action = player.getEntityAction<CaliumConverterAction>();
NullReferenceCheckHelper.throwIfNull(user_calium_action, () => $"action is null !!!");
var calium_storage_entity = GameServerApp.getServerLogic().findGlobalEntity<CaliumStorageEntity>();
NullReferenceCheckHelper.throwIfNull(calium_storage_entity, () => $"caliuim_storage_entity is null !!! - {player.toBasicString()}");
var calium_storage_action = calium_storage_entity.getEntityAction<CaliumStorageAction>();
NullReferenceCheckHelper.throwIfNull(calium_storage_action, () => $"calium_storage_action is null !!! - {player.toBasicString()}");
// 0. calium storage 체크
result = await calium_storage_action.enableCaliumStorage();
if (result.isFail()) return result;
// 1. Convert 수량 계산
var convert = await user_calium_action.calculationConvertCalium(useMaterials);
// 2. Convert 조건 체크
result = user_calium_action.checkConvertConditions(useMaterials, convert.calium, convert.currency);
if (result.isFail()) return result;
// 3. Item 제거
var delete_materials = await user_calium_action.deleteMaterials(useMaterials);
if (delete_materials.result.isFail()) return delete_materials.result;
NullReferenceCheckHelper.throwIfNull(delete_materials.items, () => $"delete_materials.items is null !!!");
// 4. 재화 변경
result = await user_calium_action.changeCurrency(convert.calium, MetaHelper.GameConfigMeta.CaliumConverterCommissionType, convert.currency);
if (result.isFail()) return result;
// 5. 개인 calium converter 정보 수정
result = user_calium_action.changeDailyCalium(player, convert.calium);
if (result.isFail()) return result;
var delta = -1 * convert.calium;
var total_calium = CaliumStorageHelper.AddDoubleByLong(calium_storage_action.getTotalCalium(CaliumStorageType.Converter), delta);
// 6. DB 갱신
{
var batch = new QueryBatchEx<QueryRunnerWithItemRequest>(player, LogActionType.ConvertCalium, GameServerApp.getServerLogic().getDynamoDbClient(), true);
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
batch.addQuery(new DBQStorageCaliumUpdate(CaliumStorageType.Converter, delta));
writeBusinessLog(player, batch, total_calium, convert.calium);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail()) return result;
}
// 7. Calium Storage 재로딩
_ = await calium_storage_action.loadStorageAttribute();
// 8. 변경사항 전송
var calium_event_action = calium_storage_entity.getEntityAction<CaliumEventAction>();
NullReferenceCheckHelper.throwIfNull(calium_event_action, () => $"calium_event_action is null !!! - {player.toBasicString()}");
await calium_event_action.sendCaliumEventFromPlayer(player, CaliumEventType.extra_get, "컨버터 교환", -1 * convert.currency, 0);
// 9. Response 응답
var user_calium_attribute = player.getEntityAttribute<CaliumAttribute>();
NullReferenceCheckHelper.throwIfNull(user_calium_attribute, () => $"user_calium_attribute is null !!! - {player.toBasicString()}");
await send_S2C_ACK_CONVERT_MATERIAL_TO_CALIUM(player, result, total_calium, (float)user_calium_attribute.DailyCalium, delete_materials.items.ToList());
// 10. 정보 변경 통보
calium_storage_action.sendChangeStorageInfo();
return result;
}
private void writeBusinessLog(Player player, QueryBatchBase queryBatchBase, double converterTotalCalium, double obtainCalium)
{
var user_calium_attribute = player.getEntityAttribute<CaliumAttribute>();
NullReferenceCheckHelper.throwIfNull(user_calium_attribute, () => $"CaliumAttribute is null !!! - {player.toBasicString()}");
// Converter Calium 변화량 기록
var calium_log_data = new CaliumConverterLogData();
calium_log_data.CurrentDailyCalium = user_calium_attribute.DailyCalium;
calium_log_data.CurrentTotalCalium = converterTotalCalium;
calium_log_data.DeltaDailyCalium = obtainCalium;
calium_log_data.DeltaTotalCalium = obtainCalium;
calium_log_data.AmountDeltaType = AmountDeltaType.Consume;
var calium_business_log = new CaliumBusinessLog(calium_log_data);
queryBatchBase.appendBusinessLog(calium_business_log);
}
}

View File

@@ -0,0 +1,150 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_CALIUM_CONVERTER), typeof(GetCaliumConverterInfoPacketHandler), typeof(GameLoginListener))]
public class GetCaliumConverterInfoPacketHandler : PacketRecvHandler
{
private static void send_S2C_ACK_CALIUM_CONVERTER(Player owner, Result result, double calium, float caliumForUser, float caliumEfficiency)
{
var ack_packet = new ClientToGame
{
Response = new ClientToGameRes
{
ErrorCode = result.ErrorCode,
AckCaliumConverter = new()
}
};
if (result.isSuccess())
{
ack_packet.Response.AckCaliumConverter.Calium = calium;
ack_packet.Response.AckCaliumConverter.CaliumEfficiency = caliumEfficiency;
ack_packet.Response.AckCaliumConverter.CaliumForUser = caliumForUser;
}
GameServerApp.getServerLogic().onSendPacket(owner, ack_packet);
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
string err_msg;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!");
// 1. 기본 정보 체크
var request = (recvMessage as ClientToGame)?.Request.ReqCaliumConverter;
if (null == request)
{
err_msg = $"Failed to get request type !!! : {nameof(ClientToGame.Request.ReqCaliumConverter)}";
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_CALIUM_CONVERTER(player, result, 0, 0, 0);
return result;
}
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "GetCaliumConverterInfo", getCaliumConverterInfoDelegase);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
send_S2C_ACK_CALIUM_CONVERTER(player, result, 0, 0, 0);
return result;
}
// 2. 총 칼리움 잔여량 체크
var calium_converter = GameServerApp.getServerLogic().findGlobalEntity<CaliumStorageEntity>();
NullReferenceCheckHelper.throwIfNull(calium_converter, () => $"calium converter is null !!!");
var calium_storage_action = calium_converter.getEntityAction<CaliumStorageAction>();
NullReferenceCheckHelper.throwIfNull(calium_storage_action, () => $"calium_storage_action is null !!! - {calium_converter.toBasicString()}");
var calium = calium_storage_action.getTotalCalium(CaliumStorageType.Converter);
if (calium < 0)
{
err_msg = $"Failed to load calium !!! : {nameof(calium_storage_action.getTotalCalium)}";
result.setFail(ServerErrorCode.FailToLoadCalium, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_CALIUM_CONVERTER(player, result, 0, 0, 0);
return result;
}
// 3. 변환 에너지 효율 체크
var calium_efficiency = await calium_storage_action.getCaliumConverterEfficiency();
// 4. 일일 제공 잔여량 체크
var user_calium_attribute = player.getEntityAttribute<CaliumAttribute>();
NullReferenceCheckHelper.throwIfNull(user_calium_attribute, () => $"user_calium_attribute is null !!! - {player.toBasicString()}");
send_S2C_ACK_CALIUM_CONVERTER(player, result, calium, (float)user_calium_attribute.DailyCalium, (float)calium_efficiency);
return result;
async Task<Result> getCaliumConverterInfoDelegase() => await getCaliumConverterInfoAsync(player);
}
private async Task<Result> getCaliumConverterInfoAsync(Player player)
{
var result = new Result();
var current_pivot_date = CaliumStorageHelper.CurrentPivotTimeDate();
var is_create = false;
// 1. attribute 가져오기
var attribute = player.getEntityAttribute<CaliumAttribute>();
NullReferenceCheckHelper.throwIfNull(attribute, () => $"CaliumAttribute is null !!! - {player.toBasicString()}");
// 2. origin doc 이 없으면 신규 생성 처리
var origin_doc = attribute.getOriginDocBase<CaliumAttribute>();
if (null == origin_doc)
{
var new_doc = new CaliumDoc(player.getUserGuid());
var attrib = new_doc.getAttrib<CaliumAttrib>();
NullReferenceCheckHelper.throwIfNull(attrib, () => $"CaliumAttrib is null !!! - {player.toBasicString()}");
attrib.DailyCalium = (double)MetaHelper.GameConfigMeta.CaliumConverterLimitPerPerson;
attrib.ProvidedDate = current_pivot_date;
attribute.copyEntityAttributeFromDoc(new_doc);
attribute.newEntityAttribute();
is_create = true;
}
// 3. 일일 지급 갱신 주기 체크
if (null != origin_doc && attribute.ProvidedDate >= current_pivot_date)
{
return result;
}
if (false == is_create)
{
attribute.DailyCalium = (double)MetaHelper.GameConfigMeta.CaliumConverterLimitPerPerson;
attribute.ProvidedDate = current_pivot_date;
attribute.modifiedEntityAttribute();
}
// 4. db 갱신
var batch = new QueryBatchEx<QueryRunnerWithDocument>( player, LogActionType.ChangeConvertCaliumInfo, GameServerApp.getServerLogic().getDynamoDbClient(), true);
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
batch.addQuery(new QueryFinal());
}
result = await QueryHelper.sendQueryAndBusinessLog(batch);
return result;
}
}

View File

@@ -0,0 +1,76 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_CALIUM_EXCHANGER_INFO), typeof(GetCaliumExchangerInfoPacketHandler), typeof(GameLoginListener))]
public class GetCaliumExchangerInfoPacketHandler : PacketRecvHandler
{
private async Task send_S2C_ACK_CALIUM_EXCHANGER_INFO(Player owner, Result result, double inflationRate, DateTime nextEpochTime)
{
var ack_packet = new ClientToGame
{
Response = new ClientToGameRes
{
ErrorCode = result.ErrorCode,
AckCaliumExchangerInfo = new ()
}
};
if (result.isSuccess())
{
ack_packet.Response.AckCaliumExchangerInfo.InflationRate = inflationRate;
ack_packet.Response.AckCaliumExchangerInfo.FixedExchangeRate = CaliumStorageHelper.FixedExchangeRate;
var time = new DateTime(nextEpochTime.Year, nextEpochTime.Month, nextEpochTime.Day, nextEpochTime.Hour, nextEpochTime.Minute, nextEpochTime.Second, DateTimeKind.Utc);
ack_packet.Response.AckCaliumExchangerInfo.NextEpochTime = time.ToTimestamp();
}
GameServerApp.getServerLogic().onSendPacket(owner, ack_packet);
await Task.CompletedTask;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
string err_msg;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
// 1. 기본 정보 체크
var request = (recvMessage as ClientToGame)?.Request.ReqCaliumExchangerInfo;
if (null == request)
{
err_msg = $"Failed to get request type !!! : {nameof(ClientToGame.Request.ReqCaliumExchangerInfo)}";
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
await send_S2C_ACK_CALIUM_EXCHANGER_INFO(player, result, 0, DateTimeHelper.MinTime);
return result;
}
// 2. 정보 조회
var calium_storage_entity = GameServerApp.getServerLogic().findGlobalEntity<CaliumStorageEntity>();
NullReferenceCheckHelper.throwIfNull(calium_storage_entity, () => $"calium_storage_entity is null !!! - {player.toBasicString()}");
var calium_storage_action = calium_storage_entity.getEntityAction<CaliumStorageAction>();
NullReferenceCheckHelper.throwIfNull(calium_storage_action, () => $"calium_storage_action is null !!! - {calium_storage_entity.toBasicString()} / {player.toBasicString()}");
var info = await calium_storage_action.getCaliumStorageInfo();
await send_S2C_ACK_CALIUM_EXCHANGER_INFO(player, result, info.DailyInflationRate, info.DailyPivotDate.AddDays(1));
return result;
}
}

View File

@@ -0,0 +1,541 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
using GameServer.PacketHandler;
using META_ID = System.UInt32;
namespace GameServer;
public class CartAction : EntityActionBase
{
private Cart? m_Cart = null;
public CartAction(Player owner)
: base(owner)
{
}
public override async Task<Result> onInit()
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
m_Cart = new(player);
await m_Cart.onInit();
return result;
}
public override void onClear()
{
NullReferenceCheckHelper.throwIfNull(m_Cart, () => $"m_Cart is null !!!");
m_Cart.onCearAll();
}
public Result AddCartFromDoc(CartDoc? cartDoc)
{
var result = new Result();
var err_msg = string.Empty;
if (cartDoc == null) return result;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
NullReferenceCheckHelper.throwIfNull(m_Cart, () => $"m_Cart is null !!!");
var cart_attribute = m_Cart.getEntityAttribute<CartAttribute>();
if (cart_attribute == null)
{
err_msg = $"Failed to get cart attribute : {nameof(CartAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return result;
}
if(cart_attribute.copyEntityAttributeFromDoc(cartDoc) == false)
{
err_msg = $"Failed copyEntityAttributeFromDoc !!! - {typeof(CartAction).Name}";
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
return result;
}
public Result GetCart4Client()
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
GetCartPacketHandler.send_S2C_ACK_GET_CART(player, result, m_Cart);
return result;
}
public async Task<Result> AddCartProcess(META_ID item_meta_id, int count, CurrencyType currency_type)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!!");
var fn_add_cart = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
(result, int item_sum_count) = AddCart(item_meta_id, count, currency_type);
if (result.isFail())
{
PacketHandler.AddCartPacketHandler.send_S2C_ACK_ADD_CART(player, result, 0, 0);
return result;
}
List<(META_ID, int)> deltaCartList = new List<(META_ID, int)>() { (item_meta_id, count) };
var task_log_data = CartBusinessLogHelper.toLogInfo(deltaCartList);
invokers.Add(new CartBusinessLog(task_log_data));
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CartAdd
, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
AddCartPacketHandler.send_S2C_ACK_ADD_CART(player, result, 0, 0);
return result;
}
AddCartPacketHandler.send_S2C_ACK_ADD_CART(player, result, item_meta_id, item_sum_count);
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "AddCart", fn_add_cart);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
public async Task<Result> DeleteCartProcess(List<CartItemInfo> req_del_cart_items)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!!");
var fn_delete_cart = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
(result, var isRemoveItem) = DeleteCart(req_del_cart_items);
if (result.isFail())
{
DelCartPacketHandler.send_S2C_ACK_DEL_CART(player, result, false);
return result;
}
List<(META_ID, int)> deltaCartList = req_del_cart_items.Select(x => ((META_ID)x.ItemId, x.Count)).ToList();
var task_log_data = CartBusinessLogHelper.toLogInfo(deltaCartList);
invokers.Add(new CartBusinessLog(task_log_data));
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CartDelete
, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
DelCartPacketHandler.send_S2C_ACK_DEL_CART(player, result, false);
return result;
}
DelCartPacketHandler.send_S2C_ACK_DEL_CART(player, result, isRemoveItem);
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "DeleteCart", fn_delete_cart);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
public async Task<Result> BuyCartProcess(List<CartItemInfo> req_buy_cart_items)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
if (req_buy_cart_items.Count == 0)
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
var fn_buy_cart = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
// 카트에서 제거
var deleteResult = DeleteCart(req_buy_cart_items);
if (deleteResult.result.isFail())
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
List<(META_ID, int)> deltaCartList = req_buy_cart_items.Select(x => ((META_ID)x.ItemId, x.Count)).ToList();
var task_log_data = CartBusinessLogHelper.toLogInfo(deltaCartList);
invokers.Add(new CartBusinessLog(task_log_data));
// 재화 차감
result = await PayCurrencyForItem(req_buy_cart_items);
if (result.isFail())
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
// 아이템 지급
var takeItemResult = await TakeCartItem(req_buy_cart_items);
if (takeItemResult.result.isFail())
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
result = await updateItemFirstPurchaseHistory(req_buy_cart_items);
if (result.isFail())
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CartPurchase
, server_logic.getDynamoDbClient(), true);
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, takeItemResult.changed_Items);
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "BuyCart", fn_buy_cart);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
private (Result result, Int32 item_sum_count) AddCart(META_ID item_meta_id, int count, CurrencyType currency_type)
{
var result = new Result();
var err_msg = string.Empty;
NullReferenceCheckHelper.throwIfNull(m_Cart, () => $"m_Cart is null !!!");
var cart_attribute = m_Cart.getEntityAttribute<CartAttribute>();
if (cart_attribute == null)
{
err_msg = $"Failed to get cart attribute : {nameof(CartAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, 0);
}
cart_attribute.CartItems.TryGetValue(currency_type, out var category_cart_items);
NullReferenceCheckHelper.throwIfNull(category_cart_items, () => $"category_cart_items is null !!!");
if (category_cart_items.Count >= 20)
{
err_msg = $"cart is Full. currency_type : {currency_type}";
result.setFail(ServerErrorCode.CartMaxCountExceed, err_msg);
Log.getLogger().error(err_msg);
return (result, 0);
}
int sum_count = count;
if (category_cart_items.TryGetValue(item_meta_id, out var cur_count) == false)
{
category_cart_items.TryAdd(item_meta_id, count);
}
else
{
sum_count += cur_count;
category_cart_items[item_meta_id] = sum_count;
}
var player = m_Cart.getRootParent() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
result = player.checkItemFirstPurchaseItemCount((int)item_meta_id, sum_count);
if (result.isFail())
{
return (result, 0);
}
if (sum_count > 99)
{
err_msg = $"FullStack of this item in cart. itemId : {item_meta_id}";
result.setFail(ServerErrorCode.CartStackCountInvalid, err_msg);
Log.getLogger().error(err_msg);
return (result, 0);
}
cart_attribute.modifiedEntityAttribute();
return (result, sum_count);
}
private (Result result, bool isRemovedItem) DeleteCart(List<CartItemInfo> del_cart_items)
{
var result = new Result();
var err_msg = string.Empty;
bool isRemovedItem = false;
NullReferenceCheckHelper.throwIfNull(m_Cart, () => $"m_Cart is null !!!");
var cart_attribute = m_Cart.getEntityAttribute<CartAttribute>();
if (cart_attribute == null)
{
err_msg = $"Failed to get cart attribute : {nameof(CartAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, isRemovedItem);
}
foreach (var del_cart_item in del_cart_items)
{
if (EnumHelper.tryParse<CurrencyType>(del_cart_item.BuyType, out var currencyType) == false)
{
err_msg = $"Enum Pase Failed. BuyType : {del_cart_item.BuyType}";
result.setFail(ServerErrorCode.CartInvalidCurrencyType, err_msg);
Log.getLogger().error(err_msg);
return (result, isRemovedItem);
}
if(MetaData.Instance._ItemTable.TryGetValue(del_cart_item.ItemId, out var itemData) == false)
{
err_msg = $"Not found meta of Item !!! : ItemMetaId:{del_cart_item.ItemId} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CartMetaDataNotFound, err_msg);
Log.getLogger().error(err_msg);
return (result, isRemovedItem);
}
int cur_count = 0;
foreach(var category_cart_items in cart_attribute.CartItems.Values)
{
if (category_cart_items.TryGetValue((META_ID)del_cart_item.ItemId, out cur_count) == false)
continue;
if (del_cart_item.Count > cur_count)
{
err_msg = $"Argument count is bigger then cart Item count. cur_count : {cur_count}, req_buy_count : {del_cart_item.Count}";
result.setFail(ServerErrorCode.CartStackCountNotEnough, err_msg);
Log.getLogger().error(err_msg);
return (result, isRemovedItem);
}
category_cart_items[(META_ID)del_cart_item.ItemId] = cur_count - del_cart_item.Count;
if (cur_count - del_cart_item.Count == 0)
{
category_cart_items.Remove((META_ID)del_cart_item.ItemId);
isRemovedItem = true;
}
break;
}
if(cur_count == 0)
{
err_msg = $"Not found itemid from category_cart_items. itemId : {del_cart_item.ItemId}";
result.setFail(ServerErrorCode.CartItemNotFound, err_msg);
Log.getLogger().error(err_msg);
return (result, isRemovedItem);
}
}
cart_attribute.modifiedEntityAttribute();
return (result, isRemovedItem);
}
private async Task<Result> PayCurrencyForItem(List<CartItemInfo> buy_cart_items)
{
var result = new Result();
var my_shop_product = getOwner();
var player = my_shop_product.getRootParent() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var money_action = player.getEntityAction<MoneyAction>();
if (null == money_action)
{
var err_msg = $"Fail to get Money Action : {nameof(MoneyAction)}.";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
return result;
}
Dictionary<CurrencyType, double> changeMoneys = new Dictionary<CurrencyType, double>();
foreach(var buy_item in buy_cart_items)
{
if(MetaData.Instance._ItemTable.TryGetValue(buy_item.ItemId, out var item_data) == false)
{
var err_msg = $"Not Found ItemDataTable Item Id : {buy_item.ItemId}";
result.setFail(ServerErrorCode.CartMetaDataNotFound, err_msg);
Log.getLogger().error(err_msg);
return result;
}
result = player.checkItemFirstPurchaseItemCount(buy_item.ItemId, buy_item.Count);
if (result.isFail()) return result;
var check_currency_type = ShopHelper.checkCurrencyTypeFromCurrencyId(item_data.Buy_id);
if (check_currency_type.result.isFail()) return check_currency_type.result;
if (changeMoneys.TryGetValue(check_currency_type.currencyType, out var price) == false)
{
changeMoneys.Add(check_currency_type.currencyType, 0);
}
var item_first_purchase_history_agent_action = player.getEntityAction<ItemFirstPurchaseHistoryAgentAction>();
NullReferenceCheckHelper.throwIfNull(item_first_purchase_history_agent_action, () => $"item_first_purchase_history_agent_action is null !!!");
var item_price = item_data.BuyPrice;
if (item_first_purchase_history_agent_action.isItemFirstPurchase(buy_item.ItemId))
{
item_price = ((item_data.BuyPrice * 100) - (item_data.BuyPrice * item_data.Buy_Discount_Rate)) / 100;
}
changeMoneys[check_currency_type.currencyType] += (-1 * item_price * buy_item.Count);
}
foreach(var changeMoney in changeMoneys)
{
result = await money_action.changeMoney(changeMoney.Key, changeMoney.Value);
if (result.isFail()) return result;
}
return result;
}
private async Task<(Result result, List<Item>? changed_Items)> TakeCartItem(List<CartItemInfo> buy_cart_items)
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var inventory_action = player.getEntityAction<InventoryActionBase>();
if (null == inventory_action)
{
var err_msg = $"Fail to get Inventory Action : {nameof(InventoryActionBase)}.";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
List<Item> buy_changed_items = new List<Item>();
foreach(var buy_item in buy_cart_items)
{
(result, var changed_items) = await inventory_action.tryTakalbleToBag((META_ID)buy_item.ItemId, (ushort)buy_item.Count);
if (result.isFail()) return (result, null);
buy_changed_items.AddRange(changed_items);
}
return (result, buy_changed_items);
}
public Cart getCart()
{
NullReferenceCheckHelper.throwIfNull(m_Cart, () => $"m_Cart is null !!!");
return m_Cart;
}
async Task<Result> updateItemFirstPurchaseHistory(List<CartItemInfo> buy_cart_items)
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var item_first_purchase_history_agent_action = player.getEntityAction<ItemFirstPurchaseHistoryAgentAction>();
NullReferenceCheckHelper.throwIfNull(item_first_purchase_history_agent_action, () => $"item_first_purchase_history_agent_action is null !!!");
foreach (var buy_item in buy_cart_items)
{
if (!item_first_purchase_history_agent_action.isItemFirstPurchase(buy_item.ItemId))
continue;
result = await item_first_purchase_history_agent_action.tryAddItemFirstPurchaseHistoryFromMetaId(buy_item.ItemId);
if (result.isFail())
{
return result;
}
}
return result;
}
}

View File

@@ -0,0 +1,58 @@
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 Cart : EntityBase
{
public Cart(Player parent)
: base(EntityType.Cart, parent)
{
}
public override async Task<Result> onInit()
{
var direct_parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(direct_parent, () => $"direct_parent is null !!!");
addEntityAttribute(new CartAttribute(this, direct_parent));
return await base.onInit();
}
public override string toBasicString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public override string toSummaryString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public List<CartItemInfo> toCartItemData4Client()
{
var cart_item_list_4_client = new List<CartItemInfo>();
var cart_attribute = getEntityAttribute<CartAttribute>();
NullReferenceCheckHelper.throwIfNull(cart_attribute, () => $"cart_attribute is null !!!");
foreach (var cart_category_item in cart_attribute.CartItems)
{
foreach(var cartitem in cart_category_item.Value)
{
CartItemInfo cart_item = new CartItemInfo();
cart_item.BuyType = cart_category_item.Key.ToString();
cart_item.ItemId = (Int32)cartitem.Key;
cart_item.Count = cartitem.Value;
cart_item_list_4_client.Add(cart_item);
}
}
return cart_item_list_4_client;
}
}
}

View File

@@ -0,0 +1,117 @@
using Amazon.DynamoDBv2.DocumentModel;
using GameServer;
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 DBQCartReadAll : QueryExecutorBase
{
private string m_combination_key_for_pk = string.Empty;
private string m_pk = string.Empty;
private CartDoc m_to_read_cart_docs = new();
public DBQCartReadAll(string combinationKeyForPK)
: base(typeof(DBQCartReadAll).Name)
{
m_combination_key_for_pk = combinationKeyForPK;
}
//=====================================================================================
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
//=====================================================================================
public override Task<Result> onPrepareQuery()
{
var result = new Result();
var err_msg = string.Empty;
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
var doc = new CartDoc();
doc.setCombinationKeyForPK(m_combination_key_for_pk);
var error_code = doc.onApplyPKSK();
if (error_code.isFail())
{
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 err_msg = string.Empty;
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<CartDoc>(query_config, eventTid: query_batch.getTransId());
if (result.isFail())
{
return result;
}
if (read_docs.Count == 1)
{
var cart_action = owner.getEntityAction<CartAction>();
NullReferenceCheckHelper.throwIfNull(cart_action, () => "cart_action is null !!!");
result = cart_action.AddCartFromDoc(read_docs[0]);
if (result.isFail())
{
return result;
}
m_to_read_cart_docs = read_docs[0];
}
return await Task.FromResult(result);
}
public CartDoc getToReadItemDocs() => m_to_read_cart_docs;
//=====================================================================================
// 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;
}
public new Player? getOwner() => getQueryBatch()?.getLogActor() as Player;
}
}

View File

@@ -0,0 +1,32 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class CartBusinessLog : ILogInvokerEx
{
private CartLogData m_data_to_log;
public CartBusinessLog(CartLogData log_data_param)
: base(LogDomainType.Cart)
{
m_data_to_log = log_data_param;
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(new CartLogData(this, m_data_to_log));
}
}

View File

@@ -0,0 +1,21 @@
using ServerCommon.BusinessLogDomain;
using ServerCommon;
using META_ID = System.UInt32;
namespace GameServer
{
static public class CartBusinessLogHelper
{
static public CartLogData toLogInfo(List<(META_ID, int)> deltaCartData)
{
var logData = new CartLogData();
logData.setInfo(deltaCartData);
return logData;
}
static public void setInfo(this CartLogData logData, List<(META_ID, int)> deltaCartData)
{
logData.deltaItemDataList = deltaCartData;
}
}
}

View File

@@ -0,0 +1,108 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
using META_ID = System.UInt32;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.AddCartReq), typeof(AddCartPacketHandler), typeof(GameLoginListener))]
public class AddCartPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_ADD_CART(Player player, Result result, META_ID item_meta_id = 0, Int32 count = 0)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.AddCartRes = new AddCartRes();
if(count != 0 && item_meta_id != 0)
{
ack_packet.Response.AddCartRes.ChangeItem = new();
ack_packet.Response.AddCartRes.ChangeItem.ItemId = (Int32)item_meta_id;
ack_packet.Response.AddCartRes.ChangeItem.Count = count;
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => $"entity_player is null !!!");
var cart_action = entity_player.getEntityAction<CartAction>();
if (cart_action == null)
{
err_msg = $"Failed to get cart action : {nameof(CartAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_ADD_CART(entity_player, result);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.AddCartReq)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_ADD_CART(entity_player, result);
return result;
}
var request = game_msg.Request.AddCartReq;
if(EnumHelper.tryParse<CurrencyType>(request.ItemInfo.BuyType, out var currency_type) == false)
{
err_msg = $"is Not Defined currencyType !!! currencyType : {request.ItemInfo.BuyType} - {entity_player.toBasicString()}";
result.setFail(ServerErrorCode.CartInvalidCurrencyType, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_ADD_CART(entity_player, result);
return result;
}
result = await cart_action.AddCartProcess((META_ID)request.ItemInfo.ItemId, request.ItemInfo.Count, currency_type);
if (result.isFail())
{
err_msg = $"Failed to AddCartProcess() !!! : {result.toBasicString()} - {entity_player.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_ADD_CART(player, errorResult);
}
}

View File

@@ -0,0 +1,120 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.BuyCartReq), typeof(BuyCartPacketHandler), typeof(GameLoginListener))]
public class BuyCartPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_BUY_CART(Player player, Result result, List<Item>? items = null)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.BuyCartRes = new BuyCartRes();
if (result.isSuccess() && items != null)
{
var account_attribute = player.getEntityAttribute<AccountAttribute>();
var level_attribute = player.getEntityAttribute<LevelAttribute>();
var money_attribute = player.getEntityAttribute<MoneyAttribute>();
var nickname_attribute = player.getEntityAttribute<NicknameAttribute>();
var char_info = new CharInfo
{
Level = (int)level_attribute!.Level,
Exp = (int)level_attribute.Exp,
Gold = money_attribute!.Gold,
Sapphire = money_attribute.Sapphire,
Calium = money_attribute.Calium,
Ruby = money_attribute.Ruby,
Usergroup = account_attribute!.AuthAdminLevelType.ToString(),
Operator = (int)account_attribute.AuthAdminLevelType,
DisplayName = nickname_attribute!.Nickname,
LanguageInfo = (int)account_attribute.LanguageType,
IsIntroComplete = 1
};
ack_packet.Response.BuyCartRes.CurrencyInfo = char_info;
ack_packet.Response.BuyCartRes.Items.AddRange(items.Select(info => info.toItemData4Client()));
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => $"entity_player is null !!!");
var cart_action = entity_player.getEntityAction<CartAction>();
if (cart_action == null)
{
err_msg = $"Failed to get cart action : {nameof(CartAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_BUY_CART(entity_player, result);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.BuyCartReq)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_BUY_CART(entity_player, result);
return result;
}
var request = game_msg.Request.BuyCartReq;
result = await cart_action.BuyCartProcess(request.ItemInfos.ToList());
if (result.isFail())
{
err_msg = $"Failed to BuyCartProcess() !!! : {result.toBasicString()} - {entity_player.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
foreach (var cart_item_info in request.ItemInfos.ToList())
{
await QuestManager.It.QuestCheck(entity_player, new QuestItem(EQuestEventTargetType.ITEM, EQuestEventNameType.BOUGHT, cart_item_info.ItemId));
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_BUY_CART(player, errorResult);
}
}

View File

@@ -0,0 +1,36 @@
using ServerCore; using ServerBase;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GameServer
{
public static class CartNotifyHelper
{
public static bool send_S2C_NTF_CART(this Player player)
{
var cart_action = player.getEntityAction<CartAction>();
NullReferenceCheckHelper.throwIfNull(cart_action, () => $"cart_action is null !!!");
var noti_packet = new ClientToGame();
noti_packet.Message = new();
noti_packet.Message.CartNoti = new();
var cart = cart_action.getCart();
if (cart != null)
{
noti_packet.Message.CartNoti.ItemList.AddRange(cart.toCartItemData4Client());
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, noti_packet))
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,92 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.DelCartReq), typeof(DelCartPacketHandler), typeof(GameLoginListener))]
public class DelCartPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_DEL_CART(Player player, Result result, bool isRemoveItem = false)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.DelCartRes = new DelCartRes();
ack_packet.Response.DelCartRes.IsRemoveItem = isRemoveItem ? 1 : 0;
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => $"entity_player is null !!!");
var cart_action = entity_player.getEntityAction<CartAction>();
if (cart_action == null)
{
err_msg = $"Failed to get cart action : {nameof(CartAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_DEL_CART(entity_player, result);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.DelCartReq)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_DEL_CART(entity_player, result);
return result;
}
var request = game_msg.Request.DelCartReq;
result = await cart_action.DeleteCartProcess(request.ItemInfos.ToList());
if (result.isFail())
{
err_msg = $"Failed to DelCartProcess() !!! : {result.toBasicString()} - {entity_player.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_DEL_CART(player, errorResult);
}
}

View File

@@ -0,0 +1,82 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.GetCartReq), typeof(GetCartPacketHandler), typeof(GameLoginListener))]
public class GetCartPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_GET_CART(Player player, Result result, Cart? cart = null)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.GetCartRes = new GetCartRes();
if(cart != null)
{
ack_packet.Response.GetCartRes.ItemList.AddRange(cart.toCartItemData4Client());
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => "player is null !!!");
var cart_action = entity_player.getEntityAction<CartAction>();
if (cart_action == null)
{
err_msg = $"Failed to get cart action : {nameof(CartAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_GET_CART(entity_player, result);
return Task.FromResult(result);
}
result = cart_action.GetCart4Client();
if (result.isFail())
{
err_msg = $"Failed to GetCart4Client() !!! : {result.toBasicString()} - {entity_player.toBasicString()}";
Log.getLogger().error(err_msg);
send_S2C_ACK_GET_CART(entity_player, result);
return Task.FromResult(result);
}
return Task.FromResult(result);
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_GET_CART(player, errorResult);
}
}

View File

@@ -0,0 +1,180 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using GameServer.PacketHandler;
using USER_GUID = System.String;
namespace GameServer;
public class ChannelAction : EntityActionBase
{
public ChannelAction(EntityBase owner)
: base(owner)
{
}
public override Task<Result> onInit()
{
var result = new Result();
return Task.FromResult(result);
}
public override void onClear()
{
return;
}
public Result tryGetChannelList()
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var channel_list = server_logic.getChannelManager().getWholeChannels();
GetChannelListPacketHandler.send_S2C_ACK_GET_CHANNEL_LIST(player, result, channel_list);
return result;
}
public async Task<(Result result, int possible_remaining_time)> tryMoveChannel(int move_channel) // TODO: chan redis간 transaction 처리가 되어있지 않다.
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var config = server_logic.getServerConfig();
if (move_channel == config.getChannelNo())
{
err_msg = $"Select Same Channel. !!! - {player.toBasicString()}";
result.setFail(ServerErrorCode.ChannelMoveSameChannel, err_msg);
Log.getLogger().error(err_msg);
return (result, 0);
}
(result, var serverInfo) = await server_logic.getServerInfoByChannel(config.getWorldId(), move_channel);
if (serverInfo == null)
{
err_msg = $"Failed ValidServerNotFound WorldServerName : {server_logic.getServerName()} move_channel : {move_channel} - {player.toBasicString()}";
result.setFail(ServerErrorCode.ValidServerNotFound, err_msg);
Log.getLogger().error(err_msg);
return (result, 0);
}
if (serverInfo.Sessions + serverInfo.Reservation + serverInfo.ReturnCount >= serverInfo.Capacity)
{
err_msg = $"Server is Full : {server_logic.getServerName()}, Channel : {move_channel}";
result.setFail(ServerErrorCode.TargetServerUserCountExceed, err_msg);
Log.getLogger().error(err_msg);
return (result, 0);
}
// 0. 채널 이동시 조건 체크
var location_attribute = getOwner().getEntityAttribute<LocationAttribute>();
NullReferenceCheckHelper.throwIfNull(location_attribute, () => $"location_attribute is null !!!");
var last_move_time = location_attribute.MoveChannelTime.ToDateTime();
var possible_remaining_time = last_move_time.AddSeconds(ServerCommon.MetaHelper.GameConfigMeta.ChannelChangeCoolTime) - DateTimeHelper.Current;
if (possible_remaining_time.TotalSeconds > 0)
{
err_msg = $"fail to move channel !!! : invalid channel cool time - {ServerCommon.MetaHelper.GameConfigMeta.ChannelChangeCoolTime} / possible_remaining_time - {possible_remaining_time.TotalSeconds}";
result.setFail(ServerErrorCode.ChannelInvalidMoveCoolTime, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, (int)possible_remaining_time.TotalSeconds);
}
// 1. 예약 요청
var message = new ServerMessage.Types.GS2GS_REQ_RESERVATION_ENTER_TO_SERVER();
message.MoveType = ServerMoveType.Force;
message.RequestServerName = server_logic.getServerName();
message.RequestUserGuid = player.getUserGuid();
var reserved = await server_logic.getReservationManager().registerReservationEnterToServer(message, serverInfo.Name);
// 2. 예약 실패 체크
if (null == reserved)
{
err_msg = $"Failed to reservation enter to game server!!! - {nameof(tryMoveChannel)}";
Log.getLogger().error(err_msg);
result.setFail(ServerErrorCode.FailedToReservationEnter, err_msg);
return (result, 0);
}
// 3. 이동 처리
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "MoveChannel", moveChannelDelegate);
if (result.isFail())
{
err_msg = $"Failed to runTransaction() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return (result, 0);
async Task<Result> moveChannelDelegate() => await moveChannelAsync(player, serverInfo);
}
private async Task<Result> moveChannelAsync(Player player, ServerInfo serverInfo)
{
var result = new Result();
var err_msg = string.Empty;
var server_logic = GameServerApp.getServerLogic();
var location_attribute = player.getEntityAttribute<LocationAttribute>();
NullReferenceCheckHelper.throwIfNull(location_attribute, () => $"location_attribute is null !!! - {player.toBasicString()}");
location_attribute.MoveChannelTime = DateTimeHelper.Current.ToTimestamp();
result = await GameZoneMoveHelper.moveToAnotherChannel(player, serverInfo, null);
if (result.isFail())
{
err_msg = $"Failed to moveToAnotherChannel() !!! : {result.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
var account_attribute = player.getEntityAttribute<AccountAttribute>();
NullReferenceCheckHelper.throwIfNull(account_attribute, () => $"account attribute is null !!! - {player.toBasicString()}");
var gameServer_connection_info = new ServerConnectInfo
{
ServerAddr = serverInfo.Address,
ServerPort = serverInfo.Port,
Otp = account_attribute.OtpForServerConnect,
};
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.None, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
batch.addQuery(new QueryFinal());
}
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
MoveChannelPacketHandler.send_S2C_ACK_MOVE_CHANNEL(player, result, gameServer_connection_info, 0);
return result;
}
}

View File

@@ -0,0 +1,81 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.GetChannelListReq), typeof(GetChannelListPacketHandler), typeof(GameLoginListener))]
public class GetChannelListPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_GET_CHANNEL_LIST(Player player, Result result, List<GameChannel>? channel_list)
{
var err_msg = string.Empty;
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.GetChannelListRes = new GetChannelListRes();
if(channel_list != null)
{
var client_ui_channel_list = channel_list.Select(x => new ChannelInfo() { Channel = x.channel, Trafficlevel = x.trafficlevel }).ToList();
ack_packet.Response.GetChannelListRes.ChannelInfoList.AddRange(client_ui_channel_list);
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => "player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var channel_action = entity_player.getEntityAction<ChannelAction>();
if (channel_action == null)
{
err_msg = $"Failed to get chat action : {nameof(ChannelAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_GET_CHANNEL_LIST(entity_player, result, null);
return Task.FromResult(result);
}
result = channel_action.tryGetChannelList();
if (result.isFail())
{
send_S2C_ACK_GET_CHANNEL_LIST(entity_player, result, null);
return Task.FromResult(result);
}
return Task.FromResult(result);
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_GET_CHANNEL_LIST(player, errorResult, null);
}
}

View File

@@ -0,0 +1,108 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.MoveChannelReq), typeof(MoveChannelPacketHandler), typeof(GameLoginListener))]
public class MoveChannelPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_MOVE_CHANNEL(Player player, Result result, ServerConnectInfo? serverConnectInfo, int possibleRemainingTime)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.MoveChannelRes = new MoveChannelRes();
ack_packet.Response.MoveChannelRes.PossibleRemainingTime = possibleRemainingTime;
if(serverConnectInfo != null)
{
ack_packet.Response.MoveChannelRes.GameServerConnectInfo = serverConnectInfo;
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var recv_msg = recvMessage as ClientToGame;
ArgumentNullReferenceCheckHelper.throwIfNull(recv_msg, () => $"recv_msg is null !!! - {player.toBasicString()}");
var request = recv_msg.Request.MoveChannelReq;
ArgumentNullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {player.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
var player_action = player.getEntityAction<PlayerAction>();
NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {player.toBasicString()}");
var selected_character = player_action.getSelectedCharacter();
if (null == selected_character)
{
err_msg = $"Not selected Character !!! - {player.toBasicString()}";
result.setFail(ServerErrorCode.CharacterNotSelected, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_MOVE_CHANNEL(player, result, null, 0);
return result;
}
var character_action = selected_character.getEntityAction<CharacterAction>();
NullReferenceCheckHelper.throwIfNull(character_action, () => $"character_action is null !!! - {selected_character.toBasicString()}");
if (character_action.isFarming())
{
err_msg = $"Character is Farming !!! - {selected_character.toBasicString()}, {player.toBasicString()}";
result.setFail(ServerErrorCode.FarimgState, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_MOVE_CHANNEL(player, result, null, 0);
return result;
}
var channel_action = player.getEntityAction<ChannelAction>();
NullReferenceCheckHelper.throwIfNull(channel_action, () => $"channel_action is null !!! - {player.toBasicString()}");
(result, var possible_remaining_time) = await channel_action.tryMoveChannel(request.Channel);
if (result.isFail())
{
err_msg = $"Failed to tryMoveChannel() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
send_S2C_ACK_MOVE_CHANNEL(player, result, null, possible_remaining_time);
return result;
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_MOVE_CHANNEL(player, errorResult, null, 0);
}
}

View File

@@ -0,0 +1,215 @@
using Amazon.Runtime.Internal.Endpoints.StandardLibrary;
using GameServer.PacketHandler;
using ServerCommon;
using ServerCore; using ServerBase;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static ClientToGameRes.Types;
namespace GameServer
{
public class CharacterProfileAction : EntityActionBase
{
public CharacterProfileAction(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> saveCharacterProfile(string sns_link, string message)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var fn_save_character_profile = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
var character_profile_attribute = player.getEntityAttribute<CharacterProfileAttribute>();
if (character_profile_attribute == null)
{
err_msg = $"Failed to get character profile attribute : {nameof(CharacterProfileAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
SaveCharacterProfilePacketHandler.send_S2C_ACK_SAVE_CHARACTER_PROFILE(player, result);
return result;
}
character_profile_attribute.SNSLick = sns_link;
character_profile_attribute.Message = message;
character_profile_attribute.modifiedEntityAttribute();
var task_log_data = CharacterProfileBusinessLogHelper.toLogInfo(character_profile_attribute);
invokers.Add(new CharacterProfileBusinessLog(task_log_data));
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.UpdateCharacterProfile
, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
SaveCharacterProfilePacketHandler.send_S2C_ACK_SAVE_CHARACTER_PROFILE(player, result);
return result;
}
SaveCharacterProfilePacketHandler.send_S2C_ACK_SAVE_CHARACTER_PROFILE(player, result);
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "SaveCharacterProfile", fn_save_character_profile);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
public async Task<Result> getTargetCharacterProfile(string target_nickname)
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var player_manager = server_logic.getPlayerManager();
player_manager.tryGetUserBySubKey(target_nickname, out var target_player);
GetCharProfileRes? res = null;
if (target_player == null)
{
(result, res) = await getOtherServerCharacterProfile(target_nickname);
if (result.isFail())
{
GetCharacterProfilePacketHandler.send_S2C_ACK_GET_CHARACTER_PROFILE(player, result, null);
return result;
}
}
else
{
(result, res) = getSameServerCharacterProfile(target_player);
if (result.isFail())
{
GetCharacterProfilePacketHandler.send_S2C_ACK_GET_CHARACTER_PROFILE(player, result, null);
return result;
}
}
GetCharacterProfilePacketHandler.send_S2C_ACK_GET_CHARACTER_PROFILE(player, result, res);
return result;
}
private async Task<(Result, GetCharProfileRes?)> getOtherServerCharacterProfile(string target_nickname)
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var dynamo_db_client = server_logic.getDynamoDbClient();
(result, var nickname_attrib) = await NicknameHelper.findNickname(target_nickname);
if (result.isFail()) return (result, null);
NullReferenceCheckHelper.throwIfNull(nickname_attrib, () => $"nickname_attrib is null !!!");
(result, var found_account_attrib) = await dynamo_db_client.simpleQueryDocTypeToAttrib<AccountBaseDoc, AccountBaseAttrib>(nickname_attrib.AccountId);
if (result.isFail()) return (result, null);
NullReferenceCheckHelper.throwIfNull(found_account_attrib, () => $"found_account_attrib is null !!!");
(result, var found_character_profile_attrib) = await dynamo_db_client.simpleQueryDocTypeToAttrib<CharacterProfileDoc, CharacterProfileAttrib>(nickname_attrib.UserGuid);
if (result.isFail()) return (result, null);
NullReferenceCheckHelper.throwIfNull(found_character_profile_attrib, () => $"found_character_profile_attrib is null !!!");
var res = new GetCharProfileRes();
res.PublicGuid = ServerCore.EncryptionHelper.encryptTextByDES(found_account_attrib.UserGuid, EncryptData.DESEncryptKey, EncryptData.DESEncryptIv);
res.NickName = target_nickname;
res.SNSLink = found_character_profile_attrib.SNSLick;
res.Message = found_character_profile_attrib.Message;
res.Language = (int)found_account_attrib.LanguageType;
return (result, res);
}
private (Result, GetCharProfileRes?) getSameServerCharacterProfile(Player target_player)
{
var result = new Result();
var err_msg = string.Empty;
var character_profile_attribute = target_player.getEntityAttribute<CharacterProfileAttribute>();
if (character_profile_attribute == null)
{
err_msg = $"Failed to get character profile attribute : {nameof(CharacterProfileAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
var account_attribute = target_player.getEntityAttribute<AccountAttribute>();
if (account_attribute == null)
{
err_msg = $"Failed to get account attribute : {nameof(AccountAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
var ability_action = target_player.getEntityAction<AbilityAction>();
if (ability_action == null)
{
err_msg = $"Failed to get ability action : {nameof(AbilityAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
var target_abilities = ability_action.getAbilities();
var res = new GetCharProfileRes();
res.PublicGuid = EncryptionHelper.encryptTextByDES(account_attribute.UserGuid, EncryptData.DESEncryptKey, EncryptData.DESEncryptIv);
res.NickName = target_player.getUserNickname();
res.SNSLink = character_profile_attribute.SNSLick;
res.Message = character_profile_attribute.Message;
res.Language = (int)account_attribute.LanguageType;
foreach(var ability in target_abilities)
{
res.Attributeinfo.Add(new AttributeInfo() { Attributeid = (int)ability.Key, Value = ability.Value });
}
return (result, res);
}
}
}

View File

@@ -0,0 +1,32 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class CharacterProfileBusinessLog : ILogInvokerEx
{
private CharacterProfileLogData m_data_to_log;
public CharacterProfileBusinessLog(CharacterProfileLogData log_data_param)
: base(LogDomainType.Craft)
{
m_data_to_log = log_data_param;
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(new CharacterProfileLogData(this, m_data_to_log));
}
}

View File

@@ -0,0 +1,22 @@
using ServerCommon.BusinessLogDomain;
using ServerCommon;
using META_ID = System.UInt32;
namespace GameServer
{
static public class CharacterProfileBusinessLogHelper
{
static public CharacterProfileLogData toLogInfo(CharacterProfileAttribute attribute)
{
var logData = new CharacterProfileLogData();
logData.setInfo(attribute);
return logData;
}
static public void setInfo(this CharacterProfileLogData logData, CharacterProfileAttribute attribute)
{
logData.SNSLick = attribute.SNSLick;
logData.Message = attribute.Message;
}
}
}

View File

@@ -0,0 +1,93 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.GetCharProfileReq), typeof(GetCharacterProfilePacketHandler), typeof(GameLoginListener))]
public class GetCharacterProfilePacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_GET_CHARACTER_PROFILE(Player player, Result result, GetCharProfileRes? res = null)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
if(res != null)
{
ack_packet.Response.GetCharProfileRes = res;
}
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => "player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var character_profile_action = entity_player.getEntityAction<CharacterProfileAction>();
if (character_profile_action == null)
{
err_msg = $"Failed to get character profile action : {nameof(CharacterProfileAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_GET_CHARACTER_PROFILE(entity_player, result);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.GetCharProfileReq)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_GET_CHARACTER_PROFILE(entity_player, result);
return result;
}
var request = game_msg.Request.GetCharProfileReq;
result = await character_profile_action.getTargetCharacterProfile(request.NickName);
if(result.isFail())
{
err_msg = $"Failed to getTargetCharacterProfile() !!! : {result.toBasicString()} - {entity_player.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_GET_CHARACTER_PROFILE(player, errorResult);
}
}

View File

@@ -0,0 +1,91 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.SaveCharProfileReq), typeof(SaveCharacterProfilePacketHandler), typeof(GameLoginListener))]
public class SaveCharacterProfilePacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_SAVE_CHARACTER_PROFILE(Player player, Result result)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.SaveCharProfileRes = new();
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
ArgumentNullException.ThrowIfNull(entity_player);
var server_logic = GameServerApp.getServerLogic();
var character_profile_action = entity_player.getEntityAction<CharacterProfileAction>();
if (character_profile_action == null)
{
err_msg = $"Failed to get character profile action : {nameof(CharacterProfileAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_SAVE_CHARACTER_PROFILE(entity_player, result);
return result;
}
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.SaveCharProfileReq)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_SAVE_CHARACTER_PROFILE(entity_player, result);
return result;
}
var request = game_msg.Request.SaveCharProfileReq;
result = await character_profile_action.saveCharacterProfile(request.SNSLink, request.Message);
if (result.isFail())
{
err_msg = $"Failed to saveCharacterProfile() !!! : {result.toBasicString()} - {entity_player.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
await QuestManager.It.QuestCheck(entity_player, new QuestAvatarProfile(EQuestEventTargetType.AVATARPROFILE, EQuestEventNameType.EDITED));
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
send_S2C_ACK_SAVE_CHARACTER_PROFILE(player, errorResult);
}
}

View File

@@ -0,0 +1,271 @@

using ServerCore;
using ServerBase;
using ServerCommon;
namespace GameServer;
public class ChatAction : EntityActionBase
{
public ChatAction(EntityBase owner)
: base(owner)
{
}
public override Task<Result> onInit()
{
var result = new Result();
return Task.FromResult(result);
}
public override void onClear()
{
return;
}
// 일반 주변 채팅
public Result NormalChat(string message)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var game_zone_action = player.getEntityAction<GameZoneAction>();
ChatNotifyHelper.send_S2C_NTF_CHAT_BROADCAST(player, ChatType.Normal, player.getUserNickname(), string.Empty, PlayerStateType.None, message);
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.ChatNormal);
var cellPos = game_zone_action.GetPlayerCellPos(player);
var task_log_data = ChatBusinessLogHelper.toLogInfo(message, cellPos);
invokers.Add(new ChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
// 채널 서버 내 채팅
public Result ChannelChat(string message)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"server_logic is null !!!");
var server_logic = GameServerApp.getServerLogic();
var receivers = server_logic.getPlayerManager().getUsers();
foreach(var receiver in receivers)
{
ChatNotifyHelper.send_S2C_NTF_CHAT(receiver.Value, ChatType.Channel, player.getUserNickname(), string.Empty, PlayerStateType.None, message);
}
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.ChatChannel);
var task_log_data = ChatBusinessLogHelper.toLogInfo(message, string.Empty);
invokers.Add(new ChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
// 전서버 채팅
public Result NoticeChat(string message)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"server_logic is null !!!");
var server_logic = GameServerApp.getServerLogic();
// GM인지 확인
//if (AccountAuthorityManager.Instance.IsWhiteListUser(player.getAccountId()) == false)
//{
// err_msg = $"Not Enough Authority to NoticeChat : player - {player.toBasicString()}";
// result.setFail(ServerErrorCode.NotEnoughAuthority, err_msg);
// Log.getLogger().error(err_msg);
// ChatPacketHandler.send_S2C_ACK_CHAT(player, result, ChatType.Notice, player.getUserNickname(), string.Empty, string.Empty, PlayerStateType.None, message);
// return result;
//}
var rabbitMQ4Game = server_logic.getRabbitMqConnector() as RabbitMQ4Game;
NullReferenceCheckHelper.throwIfNull(rabbitMQ4Game, () => $"rabbitMQ4Game is null !!!");
rabbitMQ4Game.sendChat(message, player.getUserNickname(), ChatType.Notice);
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.ChatNotice);
var task_log_data = ChatBusinessLogHelper.toLogInfo(message, string.Empty);
invokers.Add(new ChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
// 귓속말 채팅
public async Task<Result> WhisperChat(string receiver_nickname, string message)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var rabbitMQ4Game = server_logic.getRabbitMqConnector() as RabbitMQ4Game;
NullReferenceCheckHelper.throwIfNull(rabbitMQ4Game, () => $"rabbitMQ4Game is null !!!");
var dynamo_db_client = server_logic.getDynamoDbClient();
if (receiver_nickname == player.getUserNickname())
{
err_msg = $"Can't Send Chat to Self. nickname : {receiver_nickname}";
result.setFail(ServerErrorCode.ChatSendSelfFailed, err_msg);
Log.getLogger().error(err_msg);
PacketHandler.ChatPacketHandler.send_S2C_ACK_CHAT(player, result, receiver_nickname, ChatType.Whisper, player.getUserNickname(), string.Empty, (int)PlayerStateType.None, message);
return result;
}
(result, var nickname_attrib) = await NicknameHelper.findNickname(receiver_nickname);
if (result.isFail())
{
err_msg = $"Not Found Target. nickname : {receiver_nickname}";
result.setFail(ServerErrorCode.TargetUserNotFound, err_msg);
Log.getLogger().error(err_msg);
PacketHandler.ChatPacketHandler.send_S2C_ACK_CHAT(player, result, receiver_nickname, ChatType.Whisper, player.getUserNickname(), string.Empty, (int)PlayerStateType.None, message);
return result;
}
NullReferenceCheckHelper.throwIfNull(nickname_attrib, () => $"nickname_attrib is null !!!");
var receiver_user_guid = nickname_attrib.UserGuid;
var login_cache_request = new LoginCacheOtherUserRequest(player, server_logic.getRedisConnector(), nickname_attrib.UserGuid);
result = await login_cache_request.fetchLogin();
var login_cache = login_cache_request.getLoginCache();
if (result.isFail() || login_cache == null)
{
err_msg = $"Logoff user : target_usenicknamer - {receiver_nickname}";
result.setFail(ServerErrorCode.TargetUserNotLogIn, err_msg);
Log.getLogger().error(err_msg);
PacketHandler.ChatPacketHandler.send_S2C_ACK_CHAT(player, result, receiver_nickname, ChatType.Whisper, player.getUserNickname(), string.Empty, (int)PlayerStateType.None, message);
return result;
}
var user_block_action = player.getEntityAction<BlockUserAgentAction>();
if (user_block_action == null)
{
err_msg = $"Failed to get user block action : {nameof(BlockUserAgentAction)}";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
PacketHandler.ChatPacketHandler.send_S2C_ACK_CHAT(player, result, receiver_nickname, ChatType.Whisper, player.getUserNickname(), string.Empty, (int)PlayerStateType.None, message);
return result;
}
//내가 차단한경우
if (user_block_action.isBlockUser(receiver_user_guid))
{
err_msg = $"Failed chat with blocked user.";
result.setFail(ServerErrorCode.ChatBlockUserCannotWhisper, err_msg);
PacketHandler.ChatPacketHandler.send_S2C_ACK_CHAT(player, result, receiver_nickname, ChatType.Whisper, player.getUserNickname(), string.Empty, (int)PlayerStateType.None, message);
return result;
}
//상대방이 차단한경우 상대방에겐 보내지 않고 정상 처리 되도록
(result, bool isblocked) = await user_block_action.amIBockedFromOthers(receiver_user_guid);
if (result.isFail())
{
return result;
}
if (isblocked == true)
{
PacketHandler.ChatPacketHandler.send_S2C_ACK_CHAT(player, result, receiver_nickname, ChatType.Whisper, player.getUserNickname(), receiver_user_guid, login_cache.State, message);
return result;
}
if (login_cache.CurrentServer != server_logic.getServerName())
{
ServerMessage chatMessage = new();
chatMessage.Chat = new();
chatMessage.Chat.Type = ChatType.Whisper;
chatMessage.Chat.SenderNickName = player.getUserNickname();
chatMessage.Chat.ReceiverGuid = receiver_user_guid;
chatMessage.Chat.Receiverstate = login_cache.State;
chatMessage.Chat.Message = message;
rabbitMQ4Game.SendMessage(login_cache.CurrentServer, chatMessage);
}
else
{
if(server_logic.getPlayerManager().tryGetUserByPrimaryKey(receiver_user_guid, out var receiver) == false)
{
err_msg = $"Failed to get player from player manager : receiver_user_guid - {receiver_user_guid}";
result.setFail(ServerErrorCode.TargetUserNotLogIn, err_msg);
Log.getLogger().error(err_msg);
PacketHandler.ChatPacketHandler.send_S2C_ACK_CHAT(player, result, receiver_nickname, ChatType.Whisper, player.getUserNickname(), string.Empty, (int)PlayerStateType.None, message);
return result;
}
if(receiver == null)
{
err_msg = $"Failed to get player from player manager : receiver_user_guid - {receiver_user_guid}";
result.setFail(ServerErrorCode.TargetUserNotLogIn, err_msg);
Log.getLogger().error(err_msg);
PacketHandler.ChatPacketHandler.send_S2C_ACK_CHAT(player, result, receiver_nickname, ChatType.Whisper, player.getUserNickname(), string.Empty, (int)PlayerStateType.None, message);
return result;
}
ChatNotifyHelper.send_S2C_NTF_CHAT(receiver, ChatType.Whisper, player.getUserNickname(), receiver_nickname, login_cache.State, message);
}
ChatNotifyHelper.send_S2C_NTF_CHAT(player, ChatType.Whisper, player.getUserNickname(), receiver_nickname, login_cache.State, message);
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.ChatWhisper);
var task_log_data = ChatBusinessLogHelper.toLogInfo(message, receiver_nickname);
invokers.Add(new ChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
// 파티 채팅
public async Task<Result> PartyChat(string message)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var personal_party_action = player.getEntityAction<PersonalPartyAction>();
NullReferenceCheckHelper.throwIfNull(personal_party_action, () => $"personal_party_action is null !!!");
var result = await personal_party_action.sendPartyChat(message);
var invokers = new List<ILogInvoker>();
var log_action = new LogActionEx(LogActionType.ChatParty);
//personal_party_action.getPersonalParty().
var task_log_data = ChatBusinessLogHelper.toLogInfo(message, string.Empty);
invokers.Add(new ChatBusinessLog(task_log_data));
BusinessLogger.collectLogs(log_action, player, invokers);
return result;
}
}

View File

@@ -0,0 +1,278 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Claims;
using Amazon.DynamoDBv2.Model;
using Amazon.DynamoDBv2;
using Microsoft.AspNetCore.Authentication.OAuth.Claims;
using Google.Protobuf;
using ServerCore;
using ServerBase;
using ServerCommon;
using GameServer.PacketHandler;
using MetaAssets;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
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;
namespace GameServer;
public class ChatCommand : Attribute
{
Dictionary<string, ChatCommandBase> command_base_map = new Dictionary<string, ChatCommandBase>();
public ChatCommand()
{
loadChatCommand();
}
private void loadChatCommand()
{
// ChatCommand 클래스의 모든 메서드를 가져옵니다.
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
foreach (Type type in assembly.GetTypes())
{
ChatCommandAttribute[] attributes = (ChatCommandAttribute[])type.GetCustomAttributes(typeof(ChatCommandAttribute), false);
foreach (var attrib in attributes)
{
var command_key = attrib.getCommand();
if (command_key == null)
{
Log.getLogger().error($"ChatCommand Key is null !!!, in ChatCommandAttributes : {attrib.getHandlerClass().FullName}");
continue;
}
var handler_class = Activator.CreateInstance(attrib.getHandlerClass()) as ChatCommandBase;
if (handler_class == null)
{
Log.getLogger().error($"Failed to create ChatCommand !!! : commandKey:{command_key}");
continue;
}
handler_class.setAuthAdminLevelType(attrib.getAdminLevel());
handler_class.setClassName(attrib.getHandlerClass().Name);
if (command_base_map.TryAdd(command_key, handler_class) == false)
{
Log.getLogger().error($"Failed to TryAdd() !!!, Already added CommandKey !!! : commandKey:{command_key}");
continue;
}
}
}
}
}
public bool isCheatCommand(string input)
{
return input.StartsWith("//");
}
public async Task<bool> HandleCommand(Player player, string input)
{
var tokenArr = input.Split(" ", 2);
try
{
var command = tokenArr[0].Remove(0, 2);
if (command_base_map.TryGetValue(command.ToLower(), out var handler_class) == false)
{
Log.getLogger().error($"Command Not Exist Command : {command.ToLower()}");
return false;
}
if (await hasAuthority(handler_class, player) == false)
{
return false;
}
if (tokenArr.Length > 1)
{
var args = tokenArr[1].Split(" ", StringSplitOptions.RemoveEmptyEntries);
await handler_class.invoke(player, tokenArr[1], args);
}
else
{
await handler_class.invoke(player, String.Empty, new string[] { });
}
}
catch (TaskCanceledException e)
{
Log.getLogger().error($"TaskCanceledException !!!, Failed to perform in HandleCommand() !!! : exception:{e}, inputString:{input} - {player.toBasicString()}");
}
catch (Exception e)
{
Log.getLogger().error($"Exception !!!, Failed to perform in HandleCommand() !!! : exception:{e}, inputString:{input} - {player.toBasicString()}");
return false;
}
return true;
}
private async Task<bool> hasAuthority(ChatCommandBase handlerClass, Player player)
{
await Task.CompletedTask;
var server_config = ServerConfigHelper.getServerConfig();
NullReferenceCheckHelper.throwIfNull(server_config, () => $"server_config is null !!!");
// ServiceType.Dev 타입일 경우 무조건 치트 사용이 가능 하다. !!!
if (server_config.ServiceType.Equals(ServiceType.Dev.ToString()))
{
return true;
}
// CheatCommandAlwaysAllow == true 일 경우 무조건 치트 사용이 가능 하다. !!!
if (true == server_config.CheatCommandAlwaysAllow)
{
return true;
}
var account_attribute = player.getEntityAttribute<AccountAttribute>();
NullReferenceCheckHelper.throwIfNull(account_attribute, () => $"account_attribute is null !!!");
var admin_level_type = account_attribute.AuthAdminLevelType;
//여기에 유저 레벨이랑, 클래스에 할당된 레벨이랑 비교 필요
var class_admin_level_type = handlerClass.getAuthAddminLevelType();
if (class_admin_level_type.Contains(admin_level_type) == false)
{
Log.getLogger().info($"Not Match Admin LevelType !!! : className = {handlerClass.getAuthAddminLevelType().ToString()}, className:{handlerClass.getClassName()} - {player.toBasicString()}");
return false;
}
return true;
}
}
[AttributeUsage(AttributeTargets.Class)]
internal class ChatCommandAttribute : Attribute
{
readonly string m_cheat_comment;
private readonly Type m_handler_class;
private readonly HashSet<AuthAdminLevelType> m_auth_admin_level_type;
public ChatCommandAttribute(string cheatCommend, Type handlerClass, params AuthAdminLevelType[] authAdminLevelType)
{
m_cheat_comment = cheatCommend;
m_handler_class = handlerClass;
m_auth_admin_level_type = new HashSet<AuthAdminLevelType>(authAdminLevelType);
}
public string getCommand()
{
return m_cheat_comment;
}
public HashSet<AuthAdminLevelType> getAdminLevel()
{
return m_auth_admin_level_type;
}
public Type getHandlerClass()
{
return m_handler_class;
}
}
public abstract class ChatCommandBase
{
private HashSet<AuthAdminLevelType> m_auth_admin_level_type = new();
private string m_class_name = string.Empty;
public void setAuthAdminLevelType(HashSet<AuthAdminLevelType> typeSet)
{
m_auth_admin_level_type = typeSet;
}
public HashSet<AuthAdminLevelType> getAuthAddminLevelType()
{
return m_auth_admin_level_type;
}
public void setClassName(string className)
{
m_class_name = className;
}
public string getClassName()
{
return m_class_name;
}
public virtual async Task invoke(Player player, string token, string[] args)
{
await Task.CompletedTask;
}
}
[ChatCommandAttribute("sessionkeepalivetime", typeof(ChatCommandSessionKeepAliveTime), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class ChatCommandSessionKeepAliveTime : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
await Task.CompletedTask;
Log.getLogger().info($"Call sessionkeepalivetime !!! - {player.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
if (args.Length < 1)
{
err_msg = $"Not enough argument !!! : argCount:{args.Length} == 3 - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
var keep_alive_minutes = int.Parse(args[0]);
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {player.toBasicString()}");
var session = player as IEntityWithSession;
NullReferenceCheckHelper.throwIfNull(session, () => $"session is null !!! - {player.toBasicString()}");
var timeout_ms = keep_alive_minutes * ConstValue.default_1_min_to_sec * ConstValue.default_1_sec_to_milisec;
var net_server = server_logic.getProudNetListener().getNetServer();
NullReferenceCheckHelper.throwIfNull(net_server, () => $"net_server is null !!!");
net_server.SetTimeoutTimeMs(session.getHostId(), timeout_ms);
}
}

View File

@@ -0,0 +1,73 @@
using ServerCore; using ServerBase;
using ServerCommon;
using GameServer.PacketHandler;
namespace GameServer.ChatCommandHandler;
[ChatCommandAttribute("warp", typeof(WarpCommandHandler), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class WarpCommandHandler : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
if (args.Length < 1) return;
if (!int.TryParse(args[0], out var warp_id)) return;
var result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "CheetWarp", warpDelegate);
if (result.isFail())
{
var err_msg = $"Failed to runTransactionRunnerSafely : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
async Task<Result> warpDelegate() => await warpAsync(player, warp_id);
}
private async Task<Result> warpAsync(Player player, int warpId)
{
var result = new Result();
string err_msg;
var server_logic = GameServerApp.getServerLogic();
var res = new ClientToGameRes.Types.WarpRes();
var game_zone_move_action = player.getEntityAction<GameZoneMoveAction>();
NullReferenceCheckHelper.throwIfNull(game_zone_move_action, () => $"game_zone_move_action is null !!! - {player.toBasicString()}");
(result, res, var business_logs) = await game_zone_move_action.tryWarp(warpId);
if (result.isFail())
{
err_msg = $"Failed to tryWarp() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
WarpPacketHandler.send_S2C_ACK_WARP(player, result, res);
return result;
}
NullReferenceCheckHelper.throwIfNull(business_logs, () => $"business_logs is null !!! - warpId:{warpId}, {player.toBasicString()}");
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.Warp, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
batch.addQuery(new QueryFinal());
}
batch.appendBusinessLogs(business_logs);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
WarpPacketHandler.send_S2C_ACK_WARP(player, result, res);
return result;
}
WarpPacketHandler.send_S2C_ACK_WARP(player, result, res);
if (res.PlaceCase == ClientToGameRes.Types.WarpRes.PlaceOneofCase.Pos)
{
player.send_S2C_NTF_SET_LOCATION();
}
return result;
}
}

View File

@@ -0,0 +1,32 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class ChatBusinessLog : ILogInvokerEx
{
private ChatLogData m_data_to_log;
public ChatBusinessLog(ChatLogData log_data_param)
: base(LogDomainType.Chat)
{
m_data_to_log = log_data_param;
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(new ChatLogData(this, m_data_to_log));
}
}

View File

@@ -0,0 +1,39 @@

using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public static class ChatBusinessLogHelper
{
static public ChatLogData toLogInfo(string chatMessage, CellPos cellpos)
{
var logData = new ChatLogData();
logData.setInfo(chatMessage, cellpos);
return logData;
}
static public ChatLogData toLogInfo(string chatMessage, string targetUser = "")
{
var logData = new ChatLogData();
logData.setInfo(chatMessage, targetUser);
return logData;
}
static public void setInfo(this ChatLogData logData, string chatMessage, string targetUser)
{
logData.TargetUser = targetUser;
logData.ChatMessage = chatMessage;
}
static public void setInfo(this ChatLogData logData, string chatMessage, CellPos cellpos)
{
logData.ChatMessage = chatMessage;
logData.cellPosX = cellpos.CellX;
logData.cellPosX = cellpos.CellY;
}
}

View File

@@ -0,0 +1,81 @@
using ServerCore; using ServerBase;
using static ServerMessage.Types;
namespace GameServer
{
public class ChatNotifyHelper
{
public static ClientToGame makeChatMessage(ChatType chat_type, string sender_nickname, string receiver_nickname, PlayerStateType receiver_state, string message)
{
var noti_packet = new ClientToGame();
noti_packet.Message = new();
noti_packet.Message.Chat = new();
noti_packet.Message.Chat.Type = chat_type;
noti_packet.Message.Chat.Sender = sender_nickname;
noti_packet.Message.Chat.Receiver = receiver_nickname;
noti_packet.Message.Chat.Receiverstate = receiver_state;
noti_packet.Message.Chat.Message = message;
return noti_packet;
}
public static bool send_S2C_NTF_CHAT(Player player, ChatType chat_type, string sender_nickname, string receiver_nickname, PlayerStateType receiver_state, string message)
{
var noti_packet = makeChatMessage(chat_type, sender_nickname, receiver_nickname, receiver_state, message);
if (false == GameServerApp.getServerLogic().onSendPacket(player, noti_packet))
{
return false;
}
return true;
}
public static bool send_S2C_NTF_CHAT_BROADCAST(Player player, ChatType chat_type, string sender_nickname, string receiver_nickname, PlayerStateType receiver_state, string message)
{
var noti_packet = makeChatMessage(chat_type, sender_nickname, receiver_nickname, receiver_state, message);
var game_zone_action = player.getEntityAction<GameZoneAction>();
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!!");
game_zone_action.broadcast(player, noti_packet);
return true;
}
public static void send_S2C_NTF_MQ_CHAT(Chat chat)
{
var server_logic = GameServerApp.getServerLogic();
var player_manager = server_logic.getPlayerManager();
switch (chat.Type)
{
case ChatType.Notice:
{
var players = player_manager.getUsers();
foreach (var player in players)
{
ChatNotifyHelper.send_S2C_NTF_CHAT(player.Value, chat.Type, chat.SenderNickName, "", PlayerStateType.None, chat.Message);
}
break;
}
case ChatType.Whisper:
{
if (player_manager.tryGetUserByPrimaryKey(chat.ReceiverGuid, out var found_user) == false) return;
if (found_user == null) return;
ChatNotifyHelper.send_S2C_NTF_CHAT(found_user, chat.Type, chat.SenderNickName, found_user.getUserNickname(), PlayerStateType.None, chat.Message);
break;
}
case ChatType.Party:
{
//await PartyManager.Instance.ChatBroadcast(chat.Receiver, clientToGame);
break;
}
default:
break;
}
}
}
}

View File

@@ -0,0 +1,180 @@
using Google.Protobuf;
using ServerCore;
using ServerBase;
using ServerCommon;
using static ClientToGameReq.Types;
using static ClientToGameRes.Types;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.ChatReq), typeof(ChatPacketHandler), typeof(GameLoginListener))]
public class ChatPacketHandler : PacketRecvHandler
{
public static bool send_S2C_ACK_CHAT(Player player, Result result, string receiver_nickname, ChatType chat_type = ChatType.None, string sender_nickname = "", string receiver_guid = "", PlayerStateType receiver_state = PlayerStateType.None, string message = "")
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.ChatRes = new ChatRes();
ack_packet.Response.ChatRes.Type = chat_type;
ack_packet.Response.ChatRes.Sender = sender_nickname;
ack_packet.Response.ChatRes.Receiver = receiver_nickname;
ack_packet.Response.ChatRes.Receiverid = receiver_guid;
ack_packet.Response.ChatRes.Receiverstate = receiver_state;
ack_packet.Response.ChatRes.Message = message;
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
{
return false;
}
return true;
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
var err_msg = string.Empty;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => $"entity_player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var chat_action = entity_player.getEntityAction<ChatAction>();
NullReferenceCheckHelper.throwIfNull(chat_action, () => $"chat_action is null !!!");
// 1. 메시지 체크
var game_msg = recvMessage as ClientToGame;
if (game_msg == null)
{
err_msg = $"Failed to cast ClientToGame !!! : {nameof(ClientToGame.Request.ChatReq)}";
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_CHAT(entity_player, result, "");
return result;
}
var request = game_msg.Request.ChatReq;
// 2. 유저 block 체크
var account_attribute = entity_player.getEntityAttribute<AccountAttribute>();
NullReferenceCheckHelper.throwIfNull(account_attribute, () => $"account_attribute is null !!! - {entity_player.toBasicString()}");
var account_base_doc = account_attribute.getOriginDocBase<AccountAttribute>() as AccountBaseDoc;
NullReferenceCheckHelper.throwIfNull(account_base_doc, () => $"account_base_doc is null !!!");
var doc_account_base_attrib = account_base_doc.getAttrib<AccountBaseAttrib>();
NullReferenceCheckHelper.throwIfNull(doc_account_base_attrib, () => $"doc_account_base_attrib is null !!!");
var block_policy = UserBlockHelper.convertBlockPolicyToJavaPolicy(doc_account_base_attrib.BlockPolicy);
if (block_policy.Contains(UserBlockPolicyType.ChattingRestrictions.ToString()))
{
//여기서 강제로 리턴
send_S2C_ACK_CHAT(entity_player, result, request.ToNickName);
return result;
}
// 3. cheat 체크
if (server_logic.ChatCommand.isCheatCommand(request.Message) == true)
{
await server_logic.ChatCommand.HandleCommand(entity_player, request.Message);
send_S2C_ACK_CHAT(entity_player, result, request.ToNickName);
return result;
}
// 4. chat 기본 조건 체크
result = checkChatConditions(request.Message);
if (result.isFail())
{
send_S2C_ACK_CHAT(entity_player, result, request.ToNickName);
return result;
}
var chat_type = request.Type;
// 5. 채팅 처리
switch (chat_type)
{
case ChatType.Normal:
result = chat_action.NormalChat(request.Message);
break;
case ChatType.Channel:
result = chat_action.ChannelChat(request.Message);
break;
case ChatType.Notice:
result = chat_action.NoticeChat(request.Message);
break;
case ChatType.Whisper:
result = await chat_action.WhisperChat(request.ToNickName, request.Message);
break;
case ChatType.Party:
result = await chat_action.PartyChat(request.Message);
break;
default:
err_msg = $"Invalid EChatType !!! EChatType : {request.Type} - {entity_player.toBasicString()}";
result.setFail(ServerErrorCode.ChatInvalidChatType, err_msg);
Log.getLogger().error(err_msg);
break;
}
if (result.isFail())
{
err_msg = $"Failed to trySendMail() !!! : {result.toBasicString()} - {entity_player.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
await QuestManager.It.QuestCheck(entity_player, new QuestChat(EQuestEventTargetType.CHAT, EQuestEventNameType.USED, chat_type.ToString(), request.Message));
return result;
}
private Result checkChatConditions(string message)
{
var result = new Result();
string err_msg;
// 1. 총 길이 체크
if (message.Length > MetaHelper.GameConfigMeta.ChatStringInputMax)
{
err_msg = $"fail to send chat !!! : invalid chat message length - {message.Length}";
result.setFail(ServerErrorCode.ChatInvalidMessageLength, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 2. 금칙어 체크 ( Client 에서 처리함 )
/*if (ServerUtil.isBanWorld(message, false))
{
err_msg = $"fail to send chat !!! : include ban word - {message}";
result.setFail(ServerErrorCode.ChatIncludeBanWord, err_msg);
Log.getLogger().error(err_msg);
return result;
}*/
return result;
}
public override async Task onProcessPacketException(ISession entityWithSession, IMessage recvMessage
, Result errorResult)
{
await Task.CompletedTask;
var player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!! - {entityWithSession.toBasicString()}");
var recv_msg = recvMessage as ClientToGame;
NullReferenceCheckHelper.throwIfNull(recv_msg, () => $"recv_msg is null !!! - {player.toBasicString()}");
var request = recv_msg.Request.ChatReq;
NullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {player.toBasicString()}");
send_S2C_ACK_CHAT(player, errorResult, request.ToNickName);
}
}

View File

@@ -0,0 +1,116 @@
using Newtonsoft.Json;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class RabbitNoticeChatHandler
{
public void MOS2GS_noticeChatSend(ServerMessage.Types.MOS2GS_NTF_NOTICE_CHAT chatMsg)
{
//OperationSystemNoticeChatType
Log.getLogger().debug("MOS2GS_noticeChatSend call start");
// 1. 메시지 체크
if (chatMsg == null)
{
var err_msg = $"chatMsg is null !!! : {nameof(ServerMessage.Types.MOS2GS_NTF_NOTICE_CHAT)}";
Log.getLogger().error(err_msg);
return;
}
//await server_logic.getNoticeChatManager().LoadDB();
var notice_type = chatMsg.NoticeType.ToString();
var chat_msgs = chatMsg.ChatMessage;
var senders = chatMsg.Sender;
Dictionary<int, string> dic_msg_by_lang = new();
Dictionary<int, string> dic_sender_by_lang = new();
foreach(var chat_msg in chat_msgs)
{
var txt = StringRuleHelper.convertStringFromBase64(chat_msg.Text);
dic_msg_by_lang.Add((int)chat_msg.LanguageType, txt);
}
foreach(var sender in senders)
{
var sender_txt = StringRuleHelper.convertStringFromBase64(sender.Text);
dic_sender_by_lang.Add((int)sender.LanguageType, sender_txt);
}
var server_logic = GameServerApp.getServerLogic();
var player_manager = server_logic.getPlayerManager();
// if (notice_type.Equals(OperationSystemNoticeChatType.CHATTING.ToString()))
// {
//일단 채팅이든 토스트든 전부 notice로 전달한다.
var users = player_manager.getUsers();
foreach (var user in users)
{
var player = user.Value;
var account_attribute = player.getEntityAttribute<AccountAttribute>();
if(account_attribute == null) continue;
if(dic_msg_by_lang.TryGetValue((int)account_attribute.LanguageType, out var chat_msg) == false)
{
var err_msg = $"dic_msg_by_lang error accountid : {account_attribute.AccountId}, langtype : {account_attribute.LanguageType}, {JsonConvert.SerializeObject(dic_msg_by_lang)}";
Log.getLogger().error(err_msg);
continue;
}
if (dic_sender_by_lang.TryGetValue((int)account_attribute.LanguageType, out var sender) == false)
{
var err_msg = $"dic_sender_by_lang error accountid : {account_attribute.AccountId}, langtype : {account_attribute.LanguageType}, {JsonConvert.SerializeObject(dic_sender_by_lang)}";
Log.getLogger().error(err_msg);
continue;
}
ChatNotifyHelper.send_S2C_NTF_CHAT(player, ChatType.Notice, sender, player.getUserNickname(), PlayerStateType.None, chat_msg);
}
Log.getLogger().debug($"MOS2GS_noticeChatSend call end userCount = {users.Count}, lang_msg : {JsonConvert.SerializeObject(dic_msg_by_lang)}, sender_msg : {JsonConvert.SerializeObject(dic_sender_by_lang)}");
// }
// else if (notice_type.Equals(OperationSystemNoticeChatType.CHATTING_TOAST.ToString()))
// {
// var err_msg = $"CHATTING_TOAST not implement !!!";
// return;
// }
//메시지에 대한 필터링을 어떻게 해야하지?
// 4. 채팅 처리
// switch (chat_type)
// {
// case ChatType.Normal:
// result = chat_action.NormalChat(request.Message);
// break;
// case ChatType.Channel:
// result = chat_action.ChannelChat(request.Message);
// break;
// case ChatType.Notice:
//result = chat_action.NoticeChat(request.Message);
// break;
// case ChatType.Whisper:
// result = await chat_action.WhisperChat(request.ToNickName, request.Message);
// break;
// case ChatType.Party:
// result = await chat_action.PartyChat(request.Message);
// break;
// if (result.isFail())
// {
// err_msg = $"Failed to trySendMail() !!! : {result.toBasicString()} - {entity_player.toBasicString()}";
// Log.getLogger().error(err_msg);
// return result;
// }
// return result;
}
}

View File

@@ -0,0 +1,592 @@
using Amazon.S3.Model;
using Google.Protobuf.WellKnownTypes;
using RabbitMQ.Client;
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.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace GameServer
{
public class ClaimAction : EntityActionBase
{
private ConcurrentDictionary<Int32, ServerCommon.Claim> m_normal_claim { get; set; } = new();
private ConcurrentDictionary<Int32, ServerCommon.Claim> m_membership_claim { get; set; } = new();
private bool m_data_load = false;
public ClaimAction(EntityBase owner) : base(owner)
{
}
public override Task<Result> onInit()
{
var result = new Result();
return Task.FromResult(result);
}
public void setDataLoad(bool isLoad)
{
m_data_load = isLoad;
}
public bool getDataLoad()
{
return m_data_load;
}
public Result setClaimFromDoc(ClaimDoc doc)
{
var result = new Result();
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
EntityBase claim;
var claim_attrib = doc.getAttrib<ClaimAttrib>();
NullReferenceCheckHelper.throwIfNull(claim_attrib, () => $"claim_attrib is null !!!");
claim = new ServerCommon.Claim(owner, claim_attrib.ClaimType);
var claim_attribute = claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(claim_attribute, () => $"claim_attribute is null !!!");
if (false == doc.getAttribWrappers().TryGetValue(typeof(ClaimAttrib), out var to_copy_doc_attrib))
{
var err_msg = $"Fail to get ClaimAttrib";
result.setFail(ServerErrorCode.EntityAttributeNotFound, err_msg);
return result;
}
var attrib_base = to_copy_doc_attrib.getAttribBase();
var doc_attrib = attrib_base as ClaimAttrib;
if (doc_attrib is null)
{
var err_msg = $"Fail to get ClaimAttrib";
result.setFail(ServerErrorCode.EntityAttributeNotFound, err_msg);
return result;
}
claim_attribute.ClaimType = doc_attrib.ClaimType;
claim_attribute.ActiveRewardIdx = doc_attrib.ActiveRewardIdx;
claim_attribute.ActiveTime = doc_attrib.ActiveTime;
claim_attribute.CreateTime = doc_attrib.CreateTime;
claim_attribute.CompleteTime = doc_attrib.CompleteTime;
claim_attribute.IsComplete = doc_attrib.IsComplete;
claim_attribute.syncOriginDocBaseWithNewDoc<ClaimAttribute>(doc);
Int32 claim_id = claim_attribute.ClaimId = doc_attrib.ClaimId;
var casted_claim = claim as ServerCommon.Claim;
NullReferenceCheckHelper.throwIfNull(casted_claim, () => $"casted_claim is null !!!");
if (claim_attrib.ClaimType == MetaAssets.ClaimType.Normal)
{
m_normal_claim.TryAdd(claim_id, casted_claim);
}
else
{
m_membership_claim.TryAdd(claim_id, casted_claim);
}
return result;
}
public async Task<(Result, List<ClaimMetaData>, List<Int32>)> update()
{
var result = new Result();
var owner = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
(var acceptable_claims, var old_claims) = getUpdatableClaims();
if (acceptable_claims.Count == 0 && old_claims.Count == 0) return (result, new(), new());
result = await owner.runTransactionRunnerSafelyWithTransGuid( owner.getUserGuid()
, TransactionIdType.PrivateContents, "ClaimUpdate", delegateUpdateClaim);
if (result.isFail())
{
string err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()} - {owner.toBasicString()}";
Log.getLogger().error(err_msg);
return (result, new(), new());
}
return (result, acceptable_claims, old_claims);
async Task<Result> delegateUpdateClaim() => await updateClaim(owner, acceptable_claims, old_claims);
}
public (List<ClaimMetaData>, List<Int32>) getUpdatableClaims()
{
var acceptable_claims = getAcceptableClaims();
var old_claims = getOldClaim();
return (acceptable_claims, old_claims);
}
public static List<ClaimMetaData> getOldClaims()
{
List<ClaimMetaData> rets = new();
DateTime nowDt = DateTimeHelper.Current;
foreach (ClaimMetaData metaData in MetaData.Instance._ClaimMetaTable.Values)
{
if (metaData.EndTime < nowDt)
{
rets.Add(metaData);
}
}
return rets;
}
private async Task<Result> updateClaim(Player owner, List<ClaimMetaData> acceptableClaim, List<Int32> oldClaim)
{
(var result, var new_claims) = updateClaims(acceptableClaim, oldClaim);
if (result.isFail()) return result;
var server_logic = GameServerApp.getServerLogic();
var batch = new QueryBatchEx<QueryRunnerWithDocument>(owner, LogActionType.None, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
return result;
}
foreach (var new_claim in new_claims)
{
var claim_attribute = new_claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(claim_attribute, () => $"claim_attribute is null !!!");
if (claim_attribute.ClaimType == MetaAssets.ClaimType.Normal)
{
m_normal_claim.TryAdd(claim_attribute.ClaimId, new_claim as ServerCommon.Claim);
}
else
{
m_membership_claim.TryAdd(claim_attribute.ClaimId, new_claim as ServerCommon.Claim);
}
}
foreach (var old_claim in oldClaim)
{
m_normal_claim.TryRemove(old_claim, out _);
m_membership_claim.TryRemove(old_claim, out _);
}
return result;
}
private (Result, List<ServerCommon.Claim>) updateClaims(List<ClaimMetaData> acceptable_claims, List<Int32> oldClaims)
{
var result = new Result();
DateTime now = DateTimeHelper.Current;
List<ServerCommon.Claim> claims = new();
foreach (var meta in acceptable_claims)
{
var claim_id = meta.ClaimId;
var claim_type = meta.ClaimType;
if (claim_type == MetaAssets.ClaimType.Normal)
{
if (m_normal_claim.ContainsKey(claim_id)) continue;
}
else
{
if (m_membership_claim.ContainsKey(claim_id)) continue;
}
var new_claim = makeNewClaim(now, meta);
claims.Add(new_claim);
//m_normal_claim.TryAdd(claim_id, normal_claim);
}
foreach (var old_claim in oldClaims)
{
if (false == m_normal_claim.TryGetValue(old_claim, out var normal_claim)) continue;
NullReferenceCheckHelper.throwIfNull(normal_claim, () => $"normal_claim is null !!!");
var normal_claim_attribute = normal_claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(normal_claim_attribute, () => $"normal_claim_attribute is null !!!");
normal_claim_attribute.deleteEntityAttribute();
}
foreach (var old_claim in oldClaims)
{
if (false == m_membership_claim.TryGetValue(old_claim, out var membership_claim)) continue;
NullReferenceCheckHelper.throwIfNull(membership_claim, () => $"membership_claim is null !!!");
var membership_claim_attribute = membership_claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(membership_claim_attribute, () => $"membership_claim_attribute is null !!!");
membership_claim_attribute.deleteEntityAttribute();
}
return (result, claims);
}
private ServerCommon.Claim resetClaim(ServerCommon.Claim claim, ClaimMetaData metaData)
{
var owner = getOwner() as Player;
DateTime now = DateTimeHelper.Current;
var claim_attribute = claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(claim_attribute, () => $"claim_attribute is null !!!");
claim_attribute.ActiveRewardIdx = metaData.DetailInfo.First().Value.Idx;
claim_attribute.ActiveTime = now;
claim_attribute.CreateTime = now;
claim_attribute.CompleteTime = now;
claim_attribute.IsComplete = 0;
claim_attribute.modifiedEntityAttribute();
return claim;
}
private ServerCommon.Claim updateClaimRewardable(ServerCommon.Claim claim, ClaimMetaData metaData)
{
var owner = getOwner() as Player;
DateTime now = DateTimeHelper.Current;
var claim_attribute = claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(claim_attribute, () => $"claim_attribute is null !!!");
claim_attribute.ActiveTime = now.AddSeconds(-86400);
claim_attribute.modifiedEntityAttribute();
return claim;
}
private ServerCommon.Claim makeNewClaim(DateTime now, ClaimMetaData metaData)
{
var owner = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
var claim = new ServerCommon.Claim(getOwner(), metaData.ClaimType);
var claim_attribute = claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(claim_attribute, () => $"claim_attribute is null !!!");
claim_attribute.ClaimId = metaData.ClaimId;
claim_attribute.ClaimType = metaData.ClaimType;
claim_attribute.ActiveRewardIdx = metaData.DetailInfo.First().Value.Idx;
claim_attribute.ActiveTime = now;
claim_attribute.CreateTime = now;
claim_attribute.CompleteTime = now;
claim_attribute.IsComplete = 0;
var new_claim_doc = new ClaimDoc(owner.getUserGuid(), metaData.ClaimType, metaData.ClaimId);
claim_attribute.syncOriginDocBaseWithNewDoc<ClaimAttribute>(new_claim_doc);
var claim_attrib = new_claim_doc.getAttrib<ClaimAttrib>();
NullReferenceCheckHelper.throwIfNull(claim_attrib, () => $"claim_attrib is null !!!");
claim_attrib.ClaimId = metaData.ClaimId;
claim_attrib.ClaimType = metaData.ClaimType;
claim_attrib.ActiveRewardIdx = metaData.DetailInfo.First().Value.Idx;
claim_attrib.ActiveTime = now;
claim_attrib.CreateTime = now;
claim_attrib.CompleteTime = now;
claim_attrib.IsComplete = 0;
claim_attribute.newEntityAttribute();
return claim;
}
private List<ClaimMetaData> getAcceptableClaims()
{
var owner = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
List<ClaimMetaData> rets = new();
var current_metas = ClaimRewardHelper.getCurrentClaims();
foreach (var metaData in current_metas)
{
var claim_id = metaData.GetMetaId();
if (m_normal_claim.ContainsKey(claim_id)) continue;
rets.Add(metaData);
}
return rets;
}
public List<Int32> getOldClaim()
{
List<ClaimMetaData> old_metas = getOldClaims();
List<Int32> old_claims = new();
foreach (var meta in old_metas)
{
var claim_id = meta.ClaimId;
if (m_normal_claim.ContainsKey(claim_id))
{
old_claims.Add(claim_id);
}
}
return old_claims;
}
public async Task cheatClaimReset()
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var result = new Result();
var fn_reset_claim = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
List<ILogInvoker> log_invokers = new();
foreach (var normal_claim in m_normal_claim.Values)
{
var normal_claim_attribute = normal_claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(normal_claim_attribute, () => $"normal_claim_attribute is null !!!");
var claim_id = normal_claim_attribute.ClaimId;
(result, var claim_meta) = ClaimRewardHelper.getClaimMeta(claim_id, MetaAssets.ClaimType.Normal);
if (result.isFail())continue;
NullReferenceCheckHelper.throwIfNull(claim_meta, () => $"claim_meta is null !!!");
resetClaim(normal_claim, claim_meta);
var log_invoker = new CheatClaimResetBusinessLog(MetaAssets.ClaimType.Normal, claim_id, normal_claim_attribute.ActiveRewardIdx);
log_invokers.Add(log_invoker);
}
foreach (var membership_claim in m_membership_claim.Values)
{
var membership_claim_attribute = membership_claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(membership_claim_attribute, () => $"normal_claim_attribute is null !!!");
var claim_id = membership_claim_attribute.ClaimId;
(result, var claim_meta) = ClaimRewardHelper.getClaimMeta(claim_id, MetaAssets.ClaimType.Membership);
if (result.isFail()) continue;
NullReferenceCheckHelper.throwIfNull(claim_meta, () => $"claim_meta is null !!!");
resetClaim(membership_claim, claim_meta);
var log_invoker = new CheatClaimResetBusinessLog(MetaAssets.ClaimType.Membership, claim_id, membership_claim_attribute.ActiveRewardIdx);
log_invokers.Add(log_invoker);
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CheatCommandClaimReset, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
return result;
}
foreach (var normal_claim in m_normal_claim.Values)
{
var normal_claim_attribute = normal_claim.getEntityAttribute<ClaimAttribute>();
if (normal_claim_attribute is null) continue;
var claim_id = normal_claim_attribute.ClaimId;
}
send_GS2C_NTF_CLAIM_UPDATE();
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "CheatResetClaim", fn_reset_claim);
if (result.isFail())
{
var err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
}
public async Task cheatClaimUpdateRewardable()
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"server_logic is null !!!");
var server_logic = GameServerApp.getServerLogic();
var result = new Result();
var fn_claim_update_rewardable = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
List<ILogInvoker> log_invokers = new();
foreach (var normal_claim in m_normal_claim.Values)
{
var normal_claim_attribute = normal_claim.getEntityAttribute<ClaimAttribute>();
if (normal_claim_attribute is null) continue;
var claim_id = normal_claim_attribute.ClaimId;
(result, var claim_meta) = ClaimRewardHelper.getClaimMeta(claim_id, MetaAssets.ClaimType.Normal);
if (result.isFail()) continue;
NullReferenceCheckHelper.throwIfNull(claim_meta, () => $"claim_meta is null !!!");
updateClaimRewardable(normal_claim, claim_meta);
var log_invoker = new CheatClaimRewardableBusinessLog(MetaAssets.ClaimType.Normal, claim_id, normal_claim_attribute.ActiveRewardIdx);
log_invokers.Add(log_invoker);
}
foreach (var membership_claim in m_membership_claim.Values)
{
var membership_claim_attribute = membership_claim.getEntityAttribute<ClaimAttribute>();
if (membership_claim_attribute is null) continue;
var claim_id = membership_claim_attribute.ClaimId;
(result, var claim_meta) = ClaimRewardHelper.getClaimMeta(claim_id, MetaAssets.ClaimType.Membership);
if (result.isFail()) continue;
NullReferenceCheckHelper.throwIfNull(claim_meta, () => $"claim_meta is null !!!");
updateClaimRewardable(membership_claim, claim_meta);
var log_invoker = new CheatClaimRewardableBusinessLog(MetaAssets.ClaimType.Membership, claim_id, membership_claim_attribute.ActiveRewardIdx);
log_invokers.Add(log_invoker);
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CheatCommandClaimUpdate, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(log_invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
return result;
}
foreach (var normal_claim in m_normal_claim.Values)
{
var normal_claim_attribute = normal_claim.getEntityAttribute<ClaimAttribute>();
if(normal_claim_attribute is null) continue;
var claim_id = normal_claim_attribute.ClaimId;
}
send_GS2C_NTF_CLAIM_UPDATE();
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "CheatClaimUpdateRewardable", fn_claim_update_rewardable);
if (result.isFail())
{
var err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return;
}
}
public ConcurrentDictionary<Int32, ServerCommon.Claim> getClaims(MetaAssets.ClaimType type)
{
if (type == MetaAssets.ClaimType.Normal)
{
return m_normal_claim;
}
else
{
return m_membership_claim;
}
}
public Result getClaim(Int32 claimId, MetaAssets.ClaimType type, [MaybeNullWhen(false)] out ServerCommon.Claim? claim)
{
var result = new Result();
if (type == MetaAssets.ClaimType.Normal)
{
result = getNormalClaim(claimId, out claim);
}
else
{
result = getMembershipClaim(claimId, out claim);
}
return result;
}
public ConcurrentDictionary<Int32, ServerCommon.Claim> getNormalClaims()
{
return m_normal_claim;
}
public Result getNormalClaim(Int32 claimId, [MaybeNullWhen(false)] out ServerCommon.Claim? claim)
{
var result = new Result();
if (false == m_normal_claim.TryGetValue(claimId, out claim))
{
var err_msg = $"m_normal_claim claimId : {claimId} not exist, {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.ClaimInfoNotExist, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
NullReferenceCheckHelper.throwIfNull(claim, () => $"claim is null !!!");
return result;
}
public ConcurrentDictionary<Int32, ServerCommon.Claim> getMembershipClaims()
{
return m_membership_claim;
}
public Result getMembershipClaim(Int32 claimId, [MaybeNullWhen(false)] out ServerCommon.Claim? claim)
{
var result = new Result();
if (false == m_membership_claim.TryGetValue(claimId, out claim))
{
var err_msg = $"m_membership_claim claimId : {claimId} not exist, {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.ClaimInfoNotExist, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
NullReferenceCheckHelper.throwIfNull(claim, () => $"claim is null !!!");
return result;
}
public override void onClear()
{
return;
}
public void send_GS2C_NTF_CLAIM_UPDATE()
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!!");
var normal_claim_infos = ClaimRewardHelper.MakeClaimSendInfo(player, MetaAssets.ClaimType.Normal);
var membership_claim_infos = ClaimRewardHelper.MakeClaimSendInfo(player, MetaAssets.ClaimType.Membership);
foreach (var info in normal_claim_infos)
{
ClientToGame ntf_packet = new();
ntf_packet.Message = new();
ntf_packet.Message.ClaimUpdateNoti = new();
ntf_packet.Message.ClaimUpdateNoti.ClaimId = info.Key;
ntf_packet.Message.ClaimUpdateNoti.NormalInfo = info.Value;
ntf_packet.Message.ClaimUpdateNoti.MembershipInfo = membership_claim_infos.TryGetValue(info.Key, out var membership_info) ? membership_info : new();
if (false == server_logic.onSendPacket(player, ntf_packet))
{
Log.getLogger().error($"SendPacket Fail");
continue;
}
}
}
}
}

View File

@@ -0,0 +1,193 @@
using GameServer.Reward;
using ServerCommon;
using ServerControlCenter;
using ServerCore; using ServerBase;
namespace GameServer
{
public class ClaimRewardReference
{
public string m_user_guid { get; set; } = string.Empty;
public Int32 m_claim_id { get; set; } = 0;
public MetaAssets.ClaimType m_claim_type { get; set; } = MetaAssets.ClaimType.Normal;
public Int32 m_reward_group_id { get; set; } = 0;
public List<MetaAssets.Reward> m_reward_data { get; set; } = new();
public ClaimMetaData? m_meta_data { get; set; } = null;
public ServerCommon.Claim? m_claim { get; set; } = null;
public List<MetaAssets.Reward> m_rewared_money { get; set; } = new();
public List<Item> m_rewarded_items { get; set; } = new();
public CommonResult m_common_result { get; set; } = new();
}
public class ClaimRewardAction : EntityActionBase
{
public ClaimRewardAction(EntityBase 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> rewardClaim(ClaimRewardReference claimRewardRef)
{
var owner = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
setActiveIdx(claimRewardRef);
IReward reward_proc = new RewardClaim(owner, claimRewardRef.m_user_guid, claimRewardRef);
var result = await RewardManager.It.proceedRewardProcess(reward_proc);
if (result.isFail())
{
return result;
}
RewardManager.It.postRewardProcess(reward_proc);
return new();
}
private void setActiveIdx(ClaimRewardReference claimRewardRef)
{
DateTime now = DateTimeHelper.Current;
NullReferenceCheckHelper.throwIfNull(claimRewardRef.m_meta_data, () => $"claimRewardRef.m_meta_data is null !!!");
NullReferenceCheckHelper.throwIfNull(claimRewardRef.m_claim, () => $"claimRewardRef.m_claim is null !!!");
int lastRewarIdx = claimRewardRef.m_meta_data.DetailInfo.Last().Value.Idx;
var claimAttribute = claimRewardRef.m_claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(claimAttribute, () => $"claimAttribute is null !!!");
claimAttribute.ActiveTime = now;
int nextActiveIdx = claimAttribute.ActiveRewardIdx + 1;
if (nextActiveIdx > lastRewarIdx)
{
claimAttribute.IsComplete = 1;
nextActiveIdx = 0;
}
claimAttribute.ActiveRewardIdx = nextActiveIdx;
claimAttribute.modifiedEntityAttribute();
}
public Result claimRewardConditionCheck(ref ClaimRewardReference claimRewardRef)
{
var owner = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
MetaAssets.ClaimType type = claimRewardRef.m_claim_type;
(var result, var claim_meta) = ClaimRewardHelper.getClaimMeta(claimRewardRef.m_claim_id, type);
if (result.isFail()) return result;
claimRewardRef.m_meta_data = claim_meta;
var claim_action = owner.getEntityAction<ClaimAction>();
result = claim_action.getClaim(claimRewardRef.m_claim_id, type, out var claim);
if (result.isFail()) return result;
claimRewardRef.m_claim = claim;
result = timeConditionCheck(ref claimRewardRef);
if (result.isFail()) return result;
result = rewardConditionCheck(ref claimRewardRef);
if (result.isFail()) return result;
return result;
}
private Result timeConditionCheck(ref ClaimRewardReference claimRewardRef)
{
var result = new Result();
NullReferenceCheckHelper.throwIfNull(claimRewardRef.m_claim, () => $"claimRewardRef.m_claim is null !!!");
NullReferenceCheckHelper.throwIfNull(claimRewardRef.m_meta_data, () => $"claimRewardRef.m_meta_data is null !!!");
var attribute = claimRewardRef.m_claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
var active_idx = attribute.ActiveRewardIdx;
if (false == claimRewardRef.m_meta_data.DetailInfo.TryGetValue(active_idx, out var detailInfo))
{
var err_msg = $"detailInfo activeIdx = {active_idx} Data not exist";
result.setFail(ServerErrorCode.ClaimInfoNotExist, err_msg);
return result;
}
var cool_time = detailInfo.CoolTime;
var now_dt = DateTimeHelper.Current;
var active_time = attribute.ActiveTime;
if (now_dt < claimRewardRef.m_meta_data.StartTime || claimRewardRef.m_meta_data.EndTime < now_dt)
{
var err_msg = $"Claim Not Correct Time activeIdx = {active_idx} metaData.StartTime : {claimRewardRef.m_meta_data.StartTime}, metaData.EndTime : {claimRewardRef.m_meta_data.EndTime} ";
result.setFail(ServerErrorCode.ClaimRewardEventEnd, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
var apply_cool_second = active_time.AddSeconds(cool_time);
if (apply_cool_second > now_dt)
{
var err_msg = $"HandleClaimRewardReq not enough Time to activeIdx = {active_idx} Data not exist";
result.setFail(ServerErrorCode.ClaimRewardNotEnoughTime, err_msg);
return result;
}
return result;
}
private Result rewardConditionCheck(ref ClaimRewardReference claimRewardRef)
{
var result = new Result();
NullReferenceCheckHelper.throwIfNull(claimRewardRef.m_claim, () => $"claimRewardRef.m_claim is null !!!");
NullReferenceCheckHelper.throwIfNull(claimRewardRef.m_meta_data, () => $"claimRewardRef.m_meta_data is null !!!");
var attribute = claimRewardRef.m_claim.getEntityAttribute<ClaimAttribute>();
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
var active_idx = attribute.ActiveRewardIdx;
if (false == claimRewardRef.m_meta_data.DetailInfo.TryGetValue(active_idx, out var detailInfo))
{
var err_msg = $"detailInfo activeIdx = {active_idx} Data not exist";
result.setFail(ServerErrorCode.ClaimInfoNotExist, err_msg);
return result;
}
int rewardGroupId = detailInfo.RewardGroupId;
if (!MetaData.Instance._RewardMetaTable.TryGetValue(rewardGroupId, out var rewardList))
{
var err_msg = $"_RewardDataTable not exist info rewardGroupId = {rewardGroupId}";
result.setFail(ServerErrorCode.RewardInfoNotExist, err_msg);
return result;
}
claimRewardRef.m_reward_group_id = rewardGroupId;
claimRewardRef.m_reward_data.Clear();
foreach (var reward in rewardList)
{
claimRewardRef.m_reward_data.Add(reward.Reward);
}
return result;
}
}
}

View File

@@ -0,0 +1,24 @@

namespace GameServer;
[ChatCommandAttribute("resetclaim", typeof(ChatCommandResetClaim), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class ChatCommandResetClaim : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
var claim_action = player.getEntityAction<ClaimAction>();
await claim_action.cheatClaimReset();
}
}
[ChatCommandAttribute("claimupdaterewardable", typeof(ChatCommandRewardClaim), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class ChatCommandRewardClaim : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
var claim_action = player.getEntityAction<ClaimAction>();
await claim_action.cheatClaimUpdateRewardable();
}
}

View File

@@ -0,0 +1,107 @@
using ServerCommon;
using ServerCore; using ServerBase;
namespace GameServer
{
public class DBQClaimReadAll : QueryExecutorBase
{
private MetaAssets.ClaimType m_claim_type { get; set; } = MetaAssets.ClaimType.None;
private string m_pk { get; set; } = string.Empty;
private string m_sk { get; set; } = string.Empty;
private readonly string m_combination_key_for_pk;
public DBQClaimReadAll(string combinationKeyForPk)
: base(typeof(DBQClaimReadAll).Name)
{
m_combination_key_for_pk = combinationKeyForPk;
}
//===================================================================================================
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
//===================================================================================================
public override Task<Result> onPrepareQuery()
{
var result = new Result();
var owner = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
var doc = new ClaimDoc(owner.getUserGuid());
doc.setCombinationKeyForPK(m_combination_key_for_pk);
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 err_msg = string.Empty;
var owner = getOwner() as Player;
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<ClaimDoc>(query_config, eventTid: query_batch.getTransId());
if (result.isFail()) return result;
var claim_action = owner.getEntityAction<ClaimAction>();
NullReferenceCheckHelper.throwIfNull(claim_action, () => "claim_action is null !!!");
foreach (var read_doc in read_docs)
{
var set_result = claim_action.setClaimFromDoc(read_doc);
if (set_result.isFail())
{
Log.getLogger().error(result.toBasicString());
continue;
}
}
claim_action.setDataLoad(true);
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 Player? getOwner() => getQueryBatch()?.getLogActor() as Player;
}
}

View File

@@ -0,0 +1,36 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class CheatClaimResetBusinessLog : ILogInvokerEx
{
CheatClaimResetLogInfo m_info;
public CheatClaimResetBusinessLog(MetaAssets.ClaimType claimType, Int32 claimId, Int32 ActiveRewardIdx)
: base(LogDomainType.ClaimReward)
{
m_info = CheatClaimResetLogInfo.creatCheatClaimResetLogInfo(this, claimType, claimId, ActiveRewardIdx);
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(m_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 class CheatClaimRewardableBusinessLog : ILogInvokerEx
{
CheatClaimRewardableLogInfo m_info;
public CheatClaimRewardableBusinessLog(MetaAssets.ClaimType claimType, Int32 claimId, Int32 ActiveRewardIdx)
: base(LogDomainType.ClaimReward)
{
m_info = CheatClaimRewardableLogInfo.creatCheatClaimRewardableLogInfo(this, claimType, claimId, ActiveRewardIdx);
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(m_info);
}
}

View File

@@ -0,0 +1,35 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class ClaimRewardBusinessLog : ILogInvokerEx
{
ClaimRewardLogInfo m_info;
public ClaimRewardBusinessLog(int claimId, int claimType, int rewardDataId)
: base(LogDomainType.ClaimReward)
{
m_info = new ClaimRewardLogInfo(this, claimId, claimType, rewardDataId);
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(m_info);
}
}

View File

@@ -0,0 +1,131 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.ClaimRewardReq), typeof(ClaimRewardPacketHandler), typeof(GameLoginListener))]
public class ClaimRewardPacketHandler : PacketRecvHandler
{
public override async Task<Result> onProcessPacket(ISession session, IMessage recvMessage)
{
var owner = session as Player;
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!");
var recv_msg = recvMessage as ClientToGame;
NullReferenceCheckHelper.throwIfNull(recv_msg, () => $"recv_msg is null !!!");
var request = recv_msg.Request.ClaimRewardReq;
var claim_type = request.ClaimType;
var claim_id = request.ClaimId;
ClaimRewardReference claim_reward_ref = new();
claim_reward_ref.m_claim_id = claim_id;
System.Enum.TryParse(claim_type.ToString(), out MetaAssets.ClaimType parsedType);
claim_reward_ref.m_claim_type = parsedType;
claim_reward_ref.m_user_guid = owner.getUserGuid();
var result = await claimReward(owner, claim_reward_ref);
if (result.isFail())
{
send_GS2C_ACK_CLAIM_REWARD_FAIL(owner, result);
return result;
}
send_GS2C_ACK_CLAIM_REWARD(owner, result, claim_reward_ref);
NullReferenceCheckHelper.throwIfNull(claim_reward_ref.m_meta_data, () => $"claim_reward_ref.m_meta_data is null !!!");
var rewards = claim_reward_ref.m_meta_data.DetailInfo.Values.ToList();
foreach (var reward in rewards)
{
await QuestManager.It.QuestCheck(owner, new QuestReward(EQuestEventTargetType.REWARD, EQuestEventNameType.RECEIVED, reward.RewardGroupId));
}
return result;
}
private async Task<Result> claimReward(Player owner, ClaimRewardReference claimRewardRef)
{
var claim_reward_action = owner.getEntityAction<ClaimRewardAction>();
var result = claim_reward_action.claimRewardConditionCheck(ref claimRewardRef);
if (result.isFail()) return result;
result = await owner.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "RewardClaim", delegateRewardClaim);
if (result.isFail())
{
string err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {owner.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
return result;
async Task<Result> delegateRewardClaim() => await rewardClaim(owner, claimRewardRef);
}
private async Task<Result> rewardClaim(Player owner, ClaimRewardReference claimRewardRef)
{
var claim_reward_action = owner.getEntityAction<ClaimRewardAction>();
var result = await claim_reward_action.rewardClaim(claimRewardRef);
var server_logic = GameServerApp.getServerLogic();
var batch = new QueryBatchEx<QueryRunnerWithDocument>(owner, LogActionType.ClaimReward, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
var log_invoker = new ClaimRewardBusinessLog(claimRewardRef.m_claim_id, (int)claimRewardRef.m_claim_type, claimRewardRef.m_reward_group_id);
batch.appendBusinessLog(log_invoker);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail()) return result;
var found_transaction_runner = owner.findTransactionRunner(TransactionIdType.PrivateContents);
NullReferenceCheckHelper.throwIfNull(found_transaction_runner, () => $"found_transaction_runner is null !!! - {owner.toBasicString()}");
var common_result = found_transaction_runner.getCommonResult();
claimRewardRef.m_common_result = common_result;
return result;
}
private static bool send_GS2C_ACK_CLAIM_REWARD_FAIL(Player owner, Result result)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.ClaimRewardRes = new();
if (false == GameServerApp.getServerLogic().onSendPacket(owner, ack_packet)) return false;
return true;
}
private static bool send_GS2C_ACK_CLAIM_REWARD(Player owner, Result result, ClaimRewardReference claimRewardRef)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.ClaimRewardRes = new();
ack_packet.Response.ClaimRewardRes.ClaimId = claimRewardRef.m_claim_id;
ack_packet.Response.ClaimRewardRes.CommonResult = claimRewardRef.m_common_result;
//var rewarded_items = claimRewardRef.m_rewarded_items;
//var rewarded_money = claimRewardRef.m_rewared_money;
//var items = RewardManager.Instance.convertItemAndMoneyToItem(rewarded_items, rewarded_money);
//ack_packet.Response.ClaimRewardRes.RewardItems.AddRange(items);
if (false == GameServerApp.getServerLogic().onSendPacket(owner, ack_packet)) return false;
return true;
}
}

View File

@@ -0,0 +1,80 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.GetClaimInfoReq), typeof(GetClaimInfoPacketHandler), typeof(GameLoginListener))]
public class GetClaimInfoPacketHandler : PacketRecvHandler
{
public override async Task<Result> onProcessPacket(ISession session, IMessage recvMessage)
{
var owner = session as Player;
NullReferenceCheckHelper.throwIfNull(owner, () => "player is null !!!");
var claim_action = owner.getEntityAction<ClaimAction>();
NullReferenceCheckHelper.throwIfNull(claim_action, () => $"claim action is null !!! - {owner.toBasicString()}");
//var result = await claim_action.loadClaim();
// if (result.isFail())
// {
// send_GS2C_ACK_GET_CLAIM_ERROR(owner, result);
// }
send_GS2C_ACK_GET_CLAIM_SUCCESS(owner);
return await Task.FromResult(new Result());
}
private static bool send_GS2C_ACK_GET_CLAIM_SUCCESS(Player owner)
{
var normal_claim_infos = ClaimRewardHelper.MakeClaimSendInfo(owner, MetaAssets.ClaimType.Normal);
var membership_claim_infos = ClaimRewardHelper.MakeClaimSendInfo(owner, MetaAssets.ClaimType.Membership);
foreach (var normal_info in normal_claim_infos)
{
var claim_id = normal_info.Key;
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.GetClaimInfoRes = new();
ack_packet.Response.GetClaimInfoRes.ClaimId = claim_id;
ack_packet.Response.GetClaimInfoRes.NormalInfo = normal_info.Value;
ack_packet.Response.GetClaimInfoRes.MembershipInfo = new();
if (true == membership_claim_infos.TryGetValue(claim_id, out var membership_info))
{
ack_packet.Response.GetClaimInfoRes.MembershipInfo = membership_info;
}
GameServerApp.getServerLogic().onSendPacket(owner, ack_packet);
}
if (normal_claim_infos.Count == 0)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.GetClaimInfoRes = new();
ack_packet.Response.GetClaimInfoRes.ClaimId = 0;
ack_packet.Response.GetClaimInfoRes.NormalInfo = new();
ack_packet.Response.GetClaimInfoRes.MembershipInfo = new();
GameServerApp.getServerLogic().onSendPacket(owner, ack_packet);
}
return true;
}
private static bool send_GS2C_ACK_GET_CLAIM_ERROR(Player owner, Result result)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new ClientToGameRes();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.GetClaimInfoRes = new();
if (false == GameServerApp.getServerLogic().onSendPacket(owner, ack_packet)) return false;
return true;
}
}

View File

@@ -0,0 +1,921 @@
using MetaAssets;
using ServerCommon;
using ServerCore; using ServerBase;
using System.Collections.Concurrent;
using NeoSmart.AsyncLock;
using GameServer.PacketHandler;
using UGCNPC_GUID = System.String;
using META_ID = System.UInt32;
using ANCHOR_GUID = System.String;
using LOCATION_UNIQUE_ID = System.String;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace GameServer
{
public class CraftAction : EntityActionBase
{
private ConcurrentDictionary<ANCHOR_GUID, Craft> m_Crafts = new();
private bool m_isUpdateCraft = false;
public CraftAction(Player owner)
: base(owner)
{
}
public override Task<Result> onInit()
{
var result = new Result();
return Task.FromResult(result);
}
public override void onClear()
{
m_Crafts.Clear();
}
public bool isCraftingHome()
{
if(m_Crafts.Count == 0)
{
return false;
}
return true;
}
public void setUpdateCraft(bool isUpdateCraft)
{
m_isUpdateCraft = isUpdateCraft;
}
public bool isAnchorCrafting(string anchorGuid)
{
return m_Crafts.ContainsKey(anchorGuid);
}
public List<CraftInfo> getCraftInfoList()
{
return m_Crafts.Values.Select(x => x.toCraftData4Client()).ToList();
}
public bool getCraftInfo(string anchorGuid, [MaybeNullWhen(false)] out CraftInfo craftInfo )
{
craftInfo = default;
if (!m_Crafts.TryGetValue(anchorGuid, out var craft))
return false;
craftInfo = craft.toCraftData4Client();
return true;
}
public async Task<Result> AddCraftFromDocs(List<CraftDoc> craftDocs)
{
var result = new Result();
var err_msg = string.Empty;
m_Crafts.Clear();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
foreach (var craft_doc in craftDocs)
{
(result, var craft) = await Craft.createCraftFromDoc(player, craft_doc);
if(craft is null)
{
err_msg = $"Failed to create craft from doc";
Log.getLogger().error(err_msg);
continue;
}
var craft_attribute = craft.getEntityAttribute<CraftAttribute>();
if (craft_attribute is null)
{
err_msg = $"craft_attribute is null";
Log.getLogger().error(err_msg);
continue;
}
if (m_Crafts.TryAdd(craft_attribute.AnchorGuid, craft) == false)
{
err_msg = $"Failed to get craft attribute : {nameof(CraftAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
}
return result;
}
public async Task<Result> ReloadCraft()
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var craft_doc = new CraftDoc();
craft_doc.setCombinationKeyForPK(player.getUserGuid());
craft_doc.onApplyPKSK();
var query_config = server_logic.getDynamoDbClient().makeQueryConfigForReadByPKOnly(craft_doc.getPK());
(result, var craft_docs) = await server_logic.getDynamoDbClient().simpleQueryDocTypesWithQueryOperationConfig<CraftDoc>(query_config);
if (result.isFail())
{
return result;
}
result = await AddCraftFromDocs(craft_docs);
if (result.isFail())
{
return result;
}
return result;
}
public async Task<Result> StartCraftProcess(ANCHOR_GUID anchor_guid, META_ID craft_meta_id, UGCNPC_GUID beacon_guid, Pos beacon_pos, int craft_count)
{
var result = new Result();
var err_msg = string.Empty;
if(m_isUpdateCraft == true)
{
await ReloadCraft();
}
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var game_zone_action = player.getEntityAction<GameZoneAction>();
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!!");
if (MetaData.Instance._CraftingMetaTable.TryGetValue((int)craft_meta_id, out var crafting_meta_data) == false)
{
err_msg = $"Not found meta of crafting !!! : craft_meta_id : {craft_meta_id} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingMetaDataNotFound, err_msg);
Log.getLogger().error(err_msg);
StartCraftPacketHandler.send_S2C_ACK_START_CRAFT(player, result);
return result;
}
result = checkStartCrafting(anchor_guid, crafting_meta_data, beacon_guid, craft_count);
if (result.isFail())
{
StartCraftPacketHandler.send_S2C_ACK_START_CRAFT(player, result);
return result;
}
var inventory_action = player.getEntityAction<InventoryActionBase>();
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!!");
var player_action = player.getEntityAction<PlayerAction>();
NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!!");
var myhome_agent_action = player.getEntityAction<MyhomeAgentAction>();
NullReferenceCheckHelper.throwIfNull(myhome_agent_action, () => $"myhome_agent_action is null !!!");
DateTime now = DateTimeHelper.Current;
DateTime craft_finish_date = now.AddSeconds(crafting_meta_data.CraftingTime * craft_count);
string myhome_guid = string.Empty;
UgcNpc? ugc_npc = null;
if (beacon_guid != string.Empty)
{
ugc_npc = player_action.findUgcNpc(beacon_guid);
if (ugc_npc == null)
{
err_msg = $"UgcNpc Not Found UgcNpc Guid : {beacon_guid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
Log.getLogger().error(err_msg);
StartCraftPacketHandler.send_S2C_ACK_START_CRAFT(player, result);
return result;
}
craft_finish_date = craft_finish_date.AddSeconds(-1 * crafting_meta_data.Beacon_ReduceTime * craft_count);
myhome_guid = myhome_agent_action.getMyHomeGuidByAnchorGuid(anchor_guid);
if(myhome_guid.isNullOrWhiteSpace())
{
err_msg = $"Failed to get Myhome Guid. anchor_guid : {anchor_guid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.AnchorIsNotInMyhome, err_msg);
Log.getLogger().error(err_msg);
StartCraftPacketHandler.send_S2C_ACK_START_CRAFT(player, result);
return result;
}
}
var fn_start_craft_profile = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
DynamoDbDocBase? dynamoDbDocBase = null;
if (ugc_npc != null)
{
EntityPos entityPos = beacon_pos == null ? new EntityPos() : new EntityPos() { X = beacon_pos.X, Y = beacon_pos.Y, Z = beacon_pos.Z, FacingAngle = beacon_pos.Angle };
modifyNpcData(player, ugc_npc, anchor_guid, entityPos);
dynamoDbDocBase = MakeNewNpcLocationDoc(ugc_npc, entityPos, anchor_guid, myhome_guid);
}
List<Item> decrease_changed_items = new List<Item>();
foreach (var material in crafting_meta_data.Material)
{
(result, var found_delete_item) = await inventory_action.tryDeleteItemByMetaId((META_ID)material.ItemId, (ushort)(material.ItemValue * craft_count));
if (result.isFail())
{
StartCraftPacketHandler.send_S2C_ACK_START_CRAFT(player, result);
return result;
}
decrease_changed_items.AddRange(found_delete_item);
}
(result, var craft) = await Craft.createCraft(player, anchor_guid, craft_meta_id, beacon_guid, now, craft_finish_date, craft_count);
if (result.isFail())
{
StartCraftPacketHandler.send_S2C_ACK_START_CRAFT(player, result);
return result;
}
NullReferenceCheckHelper.throwIfNull(craft, () => $"craft is null !!!");
var craft_attribute = craft.getEntityAttribute<CraftAttribute>();
NullReferenceCheckHelper.throwIfNull(craft_attribute, () => $"craft_attribute is null !!!");
var task_log_data = CraftBusinessLogHelper.toCraftLogInfo(craft_attribute);
invokers.Add(new CraftBusinessLog(task_log_data));
var batch = new QueryBatchEx<QueryRunnerWithDocument>( player, LogActionType.CraftStart
, server_logic.getDynamoDbClient() );
{
if(dynamoDbDocBase != null) batch.addQuery(new DBQEntityWrite(new List<DynamoDbDocBase>() { dynamoDbDocBase }));
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
StartCraftPacketHandler.send_S2C_ACK_START_CRAFT(player, result);
return result;
}
m_Crafts.TryAdd(anchor_guid, craft);
if (ugc_npc != null)
{
var ugc_npc_action = ugc_npc.getEntityAction<UgcNpcAction>();
ugc_npc_action.setCountingAsConnectedUser(false);
var game_zone_action = player.getEntityAction<GameZoneAction>();
var map = game_zone_action.getLinkedToMap();
NullReferenceCheckHelper.throwIfNull(map, () => $"map is null !!!");
result = await ugc_npc_action.tryLocateInGameZone(map, myhome_guid);
if(result.isSuccess())
{
UgcNpcNotifyHelper.send_GS2C_NTF_BEACON_COMPACT_UPDATE(player, ugc_npc, ugc_npc_action.toUgcNpcCompact());
}
}
StartCraftPacketHandler.send_S2C_ACK_START_CRAFT(player, result, craft, decrease_changed_items, beacon_pos);
game_zone_action.broadcast(player, CraftNotifyHelper.makeNotiCraftInfoPacket(m_Crafts.Select(x => x.Value.toCraftData4Client()).ToList(), player.getUserGuid()));
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "StartCraft", fn_start_craft_profile);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
private void modifyNpcData(Player player, UgcNpc ugc_npc, string anchor_guid, EntityPos currPos)
{
var anchor_meta_id = getAnchorMetaId(player, anchor_guid);
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.UsingByCrafting
, currPos
, anchor_guid, (META_ID)anchor_meta_id );
}
private int getAnchorMetaId(Player player, string anchor_guid)
{
var game_zone_action = player.getEntityAction<GameZoneAction>();
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!!");
var crafting_anchor = game_zone_action.GetAnchor(anchor_guid);
if (crafting_anchor == null)
{
return 0;
}
return crafting_anchor.AnchorProp.TableId;
}
private Result checkStartCrafting(ANCHOR_GUID anchor_guid, CraftingMetaData crafting_meta_data, UGCNPC_GUID beacon_guid, int craft_count)
{
var result = new Result();
var err_msg = string.Empty;
if (m_Crafts.TryGetValue(anchor_guid, out var craft) == true)
{
err_msg = $"this Anchor is already Crafting now. anchor_guid : {anchor_guid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingAlreadyCrafting, err_msg);
Log.getLogger().error(err_msg);
return result;
}
if (beacon_guid != string.Empty)
{
result = checkNpcState(beacon_guid);
if (result.isFail()) { return result; }
}
result = checkAbility(crafting_meta_data,beacon_guid);
if (result.isFail()) { return result; }
result = checkAnchor(crafting_meta_data, anchor_guid);
if(result.isFail()) { return result; }
//레시피 확인
if (crafting_meta_data.RecipeType == ERecipeType.Add)
{
result = checkRecipe((META_ID)crafting_meta_data.Id);
if (result.isFail()) { return result; }
}
if(crafting_meta_data.max_craft_limit < craft_count || craft_count < 1)
{
err_msg = $"craft limit is over. craft meta ID : {crafting_meta_data.Id} - max_craft_limit : {crafting_meta_data.max_craft_limit} - request craft_count : {craft_count} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftInvalidRequestCount, err_msg);
Log.getLogger().error(err_msg);
return result;
}
return result;
}
private Result checkRecipe(META_ID craft_meta_id)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var craft_recipe_action = player.getEntityAction<CraftRecipeAction>();
if (craft_recipe_action.HasRecipe((META_ID)craft_meta_id) == false)
{
err_msg = $"Recipe is not register. Craft_meta_id : {craft_meta_id} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingRecipeIsNotRegister, err_msg);
Log.getLogger().error(err_msg);
return result;
}
return result;
}
private Result checkNpcState(UGCNPC_GUID ugcNpc_guid)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var player_action = player.getEntityAction<PlayerAction>();
var ugc_npc = player_action.findUgcNpc(ugcNpc_guid);
if (ugc_npc == null)
{
err_msg = $"UgcNpc Not Found UgcNpc Guid : {ugcNpc_guid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
Log.getLogger().error(err_msg);
return result;
}
var ugc_ncp_attribute = ugc_npc.getEntityAttribute<UgcNpcAttribute>();
NullReferenceCheckHelper.throwIfNull(ugc_ncp_attribute, () => $"ugc_ncp_attribute is null !!!");
if (ugc_ncp_attribute.State != EntityStateType.None)
{
result.setFail(ServerErrorCode.NpcIsBusy, err_msg);
return result;
}
return result;
}
private Result checkAbility(CraftingMetaData crafting_meta_data, UGCNPC_GUID ugcNpc_guid)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var ability_action = player.getEntityAction<AbilityAction>();
if (ugcNpc_guid != string.Empty)
{
var player_action = player.getEntityAction<PlayerAction>();
var ugc_npc = player_action.findUgcNpc(ugcNpc_guid);
if (ugc_npc == null)
{
err_msg = $"UgcNpc Not Found UgcNpc Guid : {ugcNpc_guid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
Log.getLogger().error(err_msg);
return result;
}
ability_action = ugc_npc.getEntityAction<AbilityAction>();
}
foreach (var attribute in crafting_meta_data.Attribute)
{
if (false == EnumHelper.tryParse<AttributeType>(attribute.AttributeName, out var attribute_type))
{
err_msg = $"Invalid Ability Enum Type : {attribute_type} - {player.toBasicString()}";
result.setFail(ServerErrorCode.ServerTypeInvalid, err_msg);
Log.getLogger().error(err_msg);
return result;
}
var attribute_value = ability_action.getAbility(attribute_type);
if (attribute_value == null)
{
err_msg = $"Invalid Ability Enum Type : {attribute_type} - {player.toBasicString()}";
result.setFail(ServerErrorCode.ServerTypeInvalid, err_msg);
Log.getLogger().error(err_msg);
return result;
}
if (attribute_value < attribute.AttributeValue)
{
err_msg = $"Not Enough Attribute for Craft. attribute name : {attribute_type}, need attribute : {attribute_value}, current attribute : {attribute.AttributeValue} - {player.toBasicString()}";
result.setFail(ServerErrorCode.NotEnoughAttribute, err_msg);
Log.getLogger().info(err_msg);
return result;
}
}
return result;
}
private Result checkAnchor(CraftingMetaData crafting_meta_data, ANCHOR_GUID anchor_guid)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() 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 crafting_anchor = game_zone_action.GetAnchor(anchor_guid);
if (crafting_anchor == null)
{
err_msg = $"anchor is not placed !!! - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingAnchorIsNotPlaced, err_msg);
Log.getLogger().error(err_msg);
HelpCraftPacketHandler.send_S2C_ACK_HELP_CRAFT(player, result);
return result;
}
if (MetaData.Instance._ItemTable.TryGetValue(crafting_anchor.AnchorProp.TableId, out var item_meta_data) == false)
{
err_msg = $"Not found meta of Item !!! : item_meta_id : {crafting_anchor.AnchorProp.TableId} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.ItemMetaDataNotFound, err_msg);
Log.getLogger().error(err_msg);
return result;
}
if (item_meta_data.PropSmallType != crafting_meta_data.PropSmallType)
{
err_msg = $"Group ID Not match with recipe. item PropSmallType : {item_meta_data.PropSmallType}, crafting PropSmallType : {crafting_meta_data.PropSmallType} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingAnchorIsNotMatchWithRecipe, err_msg);
Log.getLogger().error(err_msg);
return result;
}
return result;
}
private NpcLocationInTargetDoc MakeNewNpcLocationDoc(UgcNpc ugcNpc, EntityPos currPos, string anchorMetaGuid, string myhomeMetaGuid)
{
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
ArgumentNullReferenceCheckHelper.throwIfNull(ugcNpc, () => $"ugcNpc 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_action = ugcNpc.getEntityAction<UgcNpcAction>();
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {player.toBasicString()}");
var ugc_npc_attribute = ugcNpc.getEntityAttribute<UgcNpcAttribute>();
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {player.toBasicString()}");
var location_unique_id = curr_map.makeLOCATION_UNIQUE_IDByMetaId(myhomeMetaGuid);
var npcLocation = new NpcLocation() { AnchorMetaGuid = anchorMetaGuid, CurrentPos = currPos };
var doc = new NpcLocationInTargetDoc(location_unique_id, anchorMetaGuid
, EntityType.UgcNpc, ugc_npc_attribute.UgcNpcMetaGuid, npcLocation
, ugc_npc_attribute.OwnerEntityType, ugc_npc_attribute.OwnerGuid);
doc.setQueryType(QueryType.Insert);
return doc;
}
private NpcLocationInTargetDoc MakeDeleteNpcLocationDoc(string anchorMetaGuid, string myhomeMetaGuid)
{
var player = getOwner() 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 !!! - {player.toBasicString()}");
var curr_map = game_zone_action.getLinkedToMap();
NullReferenceCheckHelper.throwIfNull(curr_map, () => $"curr_map is null !!! - {player.toBasicString()}");
var location_unique_id = curr_map.makeLOCATION_UNIQUE_IDByMetaId(myhomeMetaGuid);
return new NpcLocationInTargetDoc(location_unique_id, anchorMetaGuid);
}
public async Task<Result> StopCraftProcess(ANCHOR_GUID anchor_guid)
{
var result = new Result();
var err_msg = string.Empty;
if (m_isUpdateCraft == true)
{
await ReloadCraft();
}
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {player.toBasicString()}");
var game_zone_action = player.getEntityAction<GameZoneAction>();
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!!");
if (m_Crafts.TryGetValue(anchor_guid, out var craft) == false)
{
err_msg = $"this Anchor is not Crafting now. anchor_guid : {anchor_guid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingNotCraftingAnchor, err_msg);
Log.getLogger().error(err_msg);
StopCraftPacketHandler.send_S2C_ACK_STOP_CRAFT(player, result);
return result;
}
Int32 craft_meta_id = 0;
var fn_stop_craft_profile = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
DynamoDbDocBase? dynamoDbDocBase = null;
var craft_attribute = craft.getEntityAttribute<CraftAttribute>();
NullReferenceCheckHelper.throwIfNull(craft_attribute, () => $"craft_attribute is null !!!");
craft_attribute.deleteEntityAttribute();
UgcNpc? ugc_npc = null;
if (craft_attribute.BeaconGuid != string.Empty)
{
var player_action = player.getEntityAction<PlayerAction>();
ugc_npc = player_action.findUgcNpc(craft_attribute.BeaconGuid);
if (ugc_npc == null)
{
err_msg = $"UgcNpc Not Found UgcNpc Guid : {craft_attribute.BeaconGuid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
Log.getLogger().error(err_msg);
StopCraftPacketHandler.send_S2C_ACK_STOP_CRAFT(player, result);
return result;
}
var ugc_npc_action = ugc_npc.getEntityAction<UgcNpcAction>();
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null - {player.toBasicString()}");
var myhome_agent_action = player.getEntityAction<MyhomeAgentAction>();
NullReferenceCheckHelper.throwIfNull(myhome_agent_action, () => $"myhome_agent_action is null !!!");
var myhome_guid = myhome_agent_action.getMyHomeGuidByAnchorGuid(anchor_guid);
if (myhome_guid.isNullOrWhiteSpace())
{
err_msg = $"Failed to get Myhome Guid. anchor_guid : {anchor_guid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.AnchorIsNotInMyhome, err_msg);
Log.getLogger().error(err_msg);
StopCraftPacketHandler.send_S2C_ACK_STOP_CRAFT(player, result);
return result;
}
ugc_npc_action.modifyStateInfo(EntityStateType.None, new EntityPos(), "");
dynamoDbDocBase = MakeDeleteNpcLocationDoc(anchor_guid, myhome_guid);
}
var inventory_action = player.getEntityAction<InventoryActionBase>();
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!!");
if (MetaData.Instance._CraftingMetaTable.TryGetValue((int)craft_attribute.CraftMetaId, out var crafting_meta_data) == false)
{
err_msg = $"Not found meta of Item !!! : CraftingMetaId:{craft_attribute.CraftMetaId} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingMetaDataNotFound, err_msg);
Log.getLogger().error(err_msg);
StopCraftPacketHandler.send_S2C_ACK_STOP_CRAFT(player, result);
return result;
}
List<Item> Increase_changed_items = new List<Item>();
foreach(var material in crafting_meta_data.Material)
{
(result, var crafting_items) = await inventory_action.tryTakalbleToBag((META_ID)material.ItemId, (ushort)(material.ItemValue * craft_attribute.CraftCount));
if (result.isFail())
{
StopCraftPacketHandler.send_S2C_ACK_STOP_CRAFT(player, result);
return result;
}
Increase_changed_items.AddRange(crafting_items);
}
var task_log_data = CraftBusinessLogHelper.toCraftLogInfo(craft_attribute);
invokers.Add(new CraftBusinessLog(task_log_data));
var batch = new QueryBatchEx<QueryRunnerWithDocument>( player, LogActionType.CraftStop
, server_logic.getDynamoDbClient() );
{
if(dynamoDbDocBase != null) batch.addQuery(new DBQEntityDelete(dynamoDbDocBase));
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
StopCraftPacketHandler.send_S2C_ACK_STOP_CRAFT(player, result);
return result;
}
m_Crafts.TryRemove(anchor_guid, out craft);
if (ugc_npc != null)
{
var ugc_npc_action = ugc_npc.getEntityAction<UgcNpcAction>();
var game_zone_action = player.getEntityAction<GameZoneAction>();
result = await ugc_npc_action.tryRemoveInGameZone();
if(result.isSuccess())
{
UgcNpcNotifyHelper.send_GS2C_NTF_BEACON_COMPACT_UPDATE(player, ugc_npc, ugc_npc_action.toUgcNpcCompact());
}
}
StopCraftPacketHandler.send_S2C_ACK_STOP_CRAFT(player, result, anchor_guid, craft_attribute.BeaconGuid, Increase_changed_items);
game_zone_action.broadcast(player, CraftNotifyHelper.makeNotiCraftInfoPacket(m_Crafts.Select(x => x.Value.toCraftData4Client()).ToList(), player.getUserGuid()));
craft_meta_id = (Int32)craft_attribute.CraftMetaId;
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "StopCraft", fn_stop_craft_profile);
if (result.isFail())
{
err_msg = $"Failed to runTransaction() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
if (craft_meta_id > 0)
{
await QuestManager.It.QuestCheck(player, new QuestCrafting(EQuestEventTargetType.CRAFTING, EQuestEventNameType.STOPPED, craft_meta_id));
}
return result;
}
public async Task<Result> FinishCraftProcess(ANCHOR_GUID anchor_guid)
{
var result = new Result();
var err_msg = string.Empty;
if (m_isUpdateCraft == true)
{
await ReloadCraft();
}
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var game_zone_action = player.getEntityAction<GameZoneAction>();
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!!");
if (m_Crafts.TryGetValue(anchor_guid, out var craft) == false)
{
err_msg = $"this Anchor is not Crafting now. anchor_guid : {anchor_guid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingNotCraftingAnchor, err_msg);
Log.getLogger().error(err_msg);
return result;
}
var craft_attribute = craft.getOriginEntityAttribute<CraftAttribute>();
NullReferenceCheckHelper.throwIfNull(craft_attribute, () => $"craft_attribute is null !!!");
DateTime now = DateTimeHelper.Current;
if (craft_attribute.CraftFinishTime > now)
{
err_msg = $"Crafting Not Finish Time : now : {now} - craftFinishTime : {craft_attribute.CraftFinishTime} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingNotFinish, err_msg);
Log.getLogger().error(err_msg);
return result;
}
if (MetaData.Instance._CraftingMetaTable.TryGetValue((int)craft_attribute.CraftMetaId, out var crafting_meta_data) == false)
{
err_msg = $"Not found meta of Item !!! : CraftingMetaId:{craft_attribute.CraftMetaId} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingMetaDataNotFound, err_msg);
Log.getLogger().error(err_msg);
return result;
}
var fn_finish_craft_profile = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
DynamoDbDocBase? dynamoDbDocBase = null;
var inventory_action = player.getEntityAction<InventoryActionBase>();
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!!");
var craft_attribute = craft.getEntityAttribute<CraftAttribute>();
NullReferenceCheckHelper.throwIfNull(craft_attribute, () => $"craft_attribute is null !!!");
craft_attribute.deleteEntityAttribute();
List<Item> Increase_changed_items = new List<Item>();
(result, var crafting_items) = await inventory_action.tryTakalbleToBag((META_ID)crafting_meta_data.Crafting_ItemId, (ushort)(crafting_meta_data.Crafting_ItemValue * craft_attribute.CraftCount));
if (result.isFail())
{
FinishCraftPacketHandler.send_S2C_ACK_FINISH_CRAFT(player, result);
return result;
}
Increase_changed_items.AddRange(crafting_items);
UgcNpc? ugc_npc = null;
if (craft_attribute.BeaconGuid != string.Empty)
{
var player_action = player.getEntityAction<PlayerAction>();
ugc_npc = player_action.findUgcNpc(craft_attribute.BeaconGuid);
if (ugc_npc == null)
{
err_msg = $"UgcNpc Not Found UgcNpc Guid : {craft_attribute.BeaconGuid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
Log.getLogger().error(err_msg);
FinishCraftPacketHandler.send_S2C_ACK_FINISH_CRAFT(player, result);
return result;
}
var myhome_agent_action = player.getEntityAction<MyhomeAgentAction>();
NullReferenceCheckHelper.throwIfNull(myhome_agent_action, () => $"myhome_agent_action is null !!!");
var myhome_guid = myhome_agent_action.getMyHomeGuidByAnchorGuid(anchor_guid);
if (myhome_guid.isNullOrWhiteSpace())
{
err_msg = $"Failed to get Myhome Guid. anchor_guid : {anchor_guid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.AnchorIsNotInMyhome, err_msg);
Log.getLogger().error(err_msg);
FinishCraftPacketHandler.send_S2C_ACK_FINISH_CRAFT(player, result);
return result;
}
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(), "");
dynamoDbDocBase = MakeDeleteNpcLocationDoc(anchor_guid, myhome_guid);
(result, var bonus_items) = await inventory_action.tryTakalbleToBag((META_ID)crafting_meta_data.Beacon_BonusItemId, (ushort)(1 * craft_attribute.CraftCount));
if (result.isFail())
{
FinishCraftPacketHandler.send_S2C_ACK_FINISH_CRAFT(player, result);
return result;
}
Increase_changed_items.AddRange(bonus_items);
}
var task_log_data = CraftBusinessLogHelper.toCraftLogInfo(craft_attribute);
invokers.Add(new CraftBusinessLog(task_log_data));
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CraftFinish
, server_logic.getDynamoDbClient());
{
if (dynamoDbDocBase != null) batch.addQuery(new DBQEntityDelete(dynamoDbDocBase));
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
FinishCraftPacketHandler.send_S2C_ACK_FINISH_CRAFT(player, result);
return result;
}
m_Crafts.TryRemove(anchor_guid, out craft);
if (ugc_npc != null)
{
var ugc_npc_action = ugc_npc.getEntityAction<UgcNpcAction>();
var game_zone_action = player.getEntityAction<GameZoneAction>();
result = await ugc_npc_action.tryRemoveInGameZone();
if (result.isFail())
{
string room_id = string.Empty;
LOCATION_UNIQUE_ID unique_id = string.Empty;
int map_id = 0;
var map = game_zone_action.getLinkedToMap();
if (map is not null)
{
room_id = map.m_room_id;
unique_id = map.getLocationUniqueId();
map_id = map.MapMId;
}
err_msg = $"Failed to tryRemoveInGameZone Player room_id : {room_id}, Player Map Location id : {unique_id}, Player MapMid : {map_id}, BeaconGuid : {craft_attribute.BeaconGuid} - {getOwner().toBasicString()}";
Log.getLogger().error(err_msg);
}
}
FinishCraftPacketHandler.send_S2C_ACK_FINISH_CRAFT(player, result, anchor_guid, craft_attribute.BeaconGuid, Increase_changed_items);
game_zone_action.broadcast(player, CraftNotifyHelper.makeNotiCraftInfoPacket(m_Crafts.Select(x => x.Value.toCraftData4Client()).ToList(), player.getUserGuid()));
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "FinishCraft", fn_finish_craft_profile);
if (result.isFail())
{
err_msg = $"Failed to runTransaction() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
if (crafting_meta_data.Crafting_ItemId > 0)
{
await QuestManager.It.QuestCheck(player, new QuestCrafting(EQuestEventTargetType.CRAFTING, EQuestEventNameType.COMPLETED, crafting_meta_data.Crafting_ItemId));
}
return result;
}
public Result cheatAllCraftFinish()
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var craftList = m_Crafts.Select(x => x.Value).ToList();
foreach (var craft in craftList)
{
var craft_attribute = craft.getOriginEntityAttribute<CraftAttribute>();
NullReferenceCheckHelper.throwIfNull(craft_attribute, () => $"craft_attribute is null !!!");
craft_attribute.CraftFinishTime = DateTimeHelper.Current;
craft_attribute.modifiedEntityAttribute();
}
return result;
}
}
}

View File

@@ -0,0 +1,356 @@
using ServerCommon;
using ServerCore; using ServerBase;
using META_ID = System.UInt32;
using ANCHOR_GUID = System.String;
using USER_GUID = System.String;
using Google.Protobuf.WellKnownTypes;
using GameServer.PacketHandler;
namespace GameServer
{
public class CraftHelpAction : EntityActionBase
{
public CraftHelpAction(Player 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> CraftHelpProcess(ANCHOR_GUID anchor_guid)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var dynamo_db_client = server_logic.getDynamoDbClient();
var game_zone_action = player.getEntityAction<GameZoneAction>();
NullReferenceCheckHelper.throwIfNull(game_zone_action, () => $"game_zone_action is null !!! - {player.toBasicString()}");
var crafting_anchor = game_zone_action.GetAnchor(anchor_guid);
if (crafting_anchor == null)
{
err_msg = $"anchor is not placed !!! - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingAnchorIsNotPlaced, err_msg);
Log.getLogger().error(err_msg);
HelpCraftPacketHandler.send_S2C_ACK_HELP_CRAFT(player, result);
return result;
}
var room_id = player.getCurrentInstanceRoomId();
result = MyhomeHelper.getMyhomeOwnerUserGuidAndMyhomeGuidFromRoomId(room_id, out var target_guid, out var myhome_guid);
var fn_craft_help = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
//대상 CraftDoc의 FinishTime값 변경
(result, var target_craft_doc) = await changeTargetCraftTime(target_guid, anchor_guid);
if (result.isFail()) { HelpCraftPacketHandler.send_S2C_ACK_HELP_CRAFT(player, result); return result; }
NullReferenceCheckHelper.throwIfNull(target_craft_doc, () => $"target_craft_doc is null !!! - {player.toBasicString()}");
var craft_attrib = target_craft_doc.getAttrib<CraftAttrib>();
NullReferenceCheckHelper.throwIfNull(craft_attrib, () => $"craft_attrib is null !!! - {player.toBasicString()}");
var finish_time = Timestamp.FromDateTime(craft_attrib.CraftFinishTime);
var task_craft_log_data = CraftBusinessLogHelper.toCraftLogInfo(craft_attrib);
invokers.Add(new CraftBusinessLog(task_craft_log_data));
//나의 CraftHelpDoc 변경
result = changeCraftHelp(target_guid);
if (result.isFail()) { HelpCraftPacketHandler.send_S2C_ACK_HELP_CRAFT(player, result); return result; }
var craft_help_attribute = player.getEntityAttribute<CraftHelpAttribute>();
NullReferenceCheckHelper.throwIfNull(craft_help_attribute, () => $"craft_help_attribute is null !!! - {player.toBasicString()}");
var task_log_data = CraftBusinessLogHelper.toCraftHelpLogInfo(craft_help_attribute);
invokers.Add(new CraftHelpBusinessLog(task_log_data));
//대상 CraftHelpDoc 변경
(result, var target_craft_help_doc) = await changeTargetCraftHelp(target_guid);
if (result.isFail()) { HelpCraftPacketHandler.send_S2C_ACK_HELP_CRAFT(player, result); return result; }
NullReferenceCheckHelper.throwIfNull(target_craft_help_doc, () => $"target_craft_help_doc is null !!! - {player.toBasicString()}");
var target_craft_help_attrib = target_craft_help_doc.getAttrib<CraftHelpAttrib>();
NullReferenceCheckHelper.throwIfNull(target_craft_help_attrib, () => $"target_craft_help_attrib is null !!! - {player.toBasicString()}");
var task_target_log_data = CraftBusinessLogHelper.toCraftHelpLogInfo(target_craft_help_attrib);
invokers.Add(new CraftHelpBusinessLog(task_target_log_data));
//도움 보상 처리
(result, var received_item_list) = await TakeHelpReward();
if (result.isFail()) { HelpCraftPacketHandler.send_S2C_ACK_HELP_CRAFT(player, result); return result; }
//동기화를 위한 redis작업
var request = new CraftHelpCacheRequest(player, server_logic.getRedisConnector(), target_guid);
result = await request.UpsertCraftHelp(player.getUserGuid());
if (result.isFail()) { HelpCraftPacketHandler.send_S2C_ACK_HELP_CRAFT(player, result); return result; }
//타 서버 패킷 전송을 위한 데이터 받아오기
(result, var myhome_instance_room_infos) = await getInstanceRoomInfos(target_guid, myhome_guid);
if (result.isFail()) { HelpCraftPacketHandler.send_S2C_ACK_HELP_CRAFT(player, result); return result; }
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CraftHelp
, dynamo_db_client, true);
{
batch.addQuery(new DBQEntityWrite(new List<DynamoDbDocBase>() { target_craft_help_doc, target_craft_doc }));
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
HelpCraftPacketHandler.send_S2C_ACK_HELP_CRAFT(player, result);
return result;
}
HelpCraftPacketHandler.send_S2C_ACK_HELP_CRAFT(player, result, received_item_list, craft_help_attribute.HelpUserGuids.Count);
game_zone_action.broadcast(player, CraftNotifyHelper.makeNtfCraftUpdatePacket(anchor_guid, finish_time));
var player_manager = server_logic.getPlayerManager();
if (player_manager.tryGetUserByPrimaryKey(target_guid, out var found_user) == true)
{
var craft_action = found_user.getEntityAction<CraftAction>();
NullReferenceCheckHelper.throwIfNull(craft_action, () => $"craft_action is null !!! - {player.toBasicString()}");
craft_action.setUpdateCraft(true);
}
foreach (var myhome_instance_room_info in myhome_instance_room_infos)
{
var server_name = ServerBase.ServerHelper.makeServerNameByNetworkAddress(ServerType.Indun, myhome_instance_room_info.InstanceAddress, (ushort)myhome_instance_room_info.InstancePort);
CraftNotifyHelper.send_GS2GS_NTF_CraftUpdate(server_name, room_id, anchor_guid, finish_time, target_guid, target_craft_help_attrib.HelpedUserGuids.Count, player.getUserNickname());
}
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "CraftHelp", fn_craft_help);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
private async Task<(Result, List<InstanceRoomInfo>)> getInstanceRoomInfos(string myhomeOwnerGuid, string myhomeGuid)
{
var result = new Result();
var err_msg = string.Empty;
var myhome_instance_room_infos = new List<InstanceRoomInfo>();
(result, myhome_instance_room_infos) = await InstanceRoomHandler.tryGetMyhomeInstanceRoomInfos(myhomeOwnerGuid, myhomeGuid);
if (result.isFail())
{
err_msg = $"Failed to tryGetMyhomeServers() !!! : {result.toBasicString()}";
Log.getLogger().error(err_msg);
return (result, myhome_instance_room_infos);
}
return (result, myhome_instance_room_infos);
}
public async Task<(Result, List<Item>)> TakeHelpReward()
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var inventory_action = player.getEntityAction<InventoryActionBase>();
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!! - {player.toBasicString()}");
var received_item_list = new List<Item>();
(result, var new_item_list) = await inventory_action.tryTakalbleToBag((META_ID)MetaHelper.GameConfigMeta.CraftingHelpGetItemId, (ushort)MetaHelper.GameConfigMeta.CraftingHelpGetItemValue);
if (result.isFail())
{
return (result, received_item_list);
}
received_item_list.AddRange(new_item_list);
return (result, received_item_list);
}
public async Task<(Result, DynamoDbDocBase?)> changeTargetCraftTime(USER_GUID target_guid, ANCHOR_GUID anchor_guid)
{
var result = new Result();
var err_msg = string.Empty;
var server_logic = GameServerApp.getServerLogic();
var dynamo_db_client = server_logic.getDynamoDbClient();
var doc = new CraftDoc(target_guid, anchor_guid);
var query_config = dynamo_db_client.makeQueryConfigForReadByPKSK(doc.getPK(), doc.getSK());
(result, var target_craft_docs) = await dynamo_db_client.simpleQueryDocTypesWithQueryOperationConfig<CraftDoc>(query_config);
if (target_craft_docs.Count == 0)
{
err_msg = $"Crafting Doc is empty !!! target userGuid:{target_guid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftDocIsEmpty, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
var target_craft_attrib = target_craft_docs[0].getAttrib<CraftAttrib>();
NullReferenceCheckHelper.throwIfNull(target_craft_attrib, () => $"target_craft_attrib is null !!!");
if (target_craft_attrib.CraftFinishTime <= DateTimeHelper.Current)
{
err_msg = $"Crafting Already Finish, can't help the craft !!! : target guid :{target_guid} anchor_guid :{anchor_guid}- {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingAlreadyFinish, err_msg);
Log.getLogger().info(err_msg);
return (result, null);
}
target_craft_attrib.CraftFinishTime = target_craft_attrib.CraftFinishTime.AddMinutes(MetaHelper.GameConfigMeta.CraftingHelpReduceTime * -1);
target_craft_docs[0].setQueryType(QueryType.Update);
return (result, target_craft_docs[0]);
}
public Result changeCraftHelp(USER_GUID target_guid)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var craft_help_attribute = player.getEntityAttribute<CraftHelpAttribute>();
NullReferenceCheckHelper.throwIfNull(craft_help_attribute, () => $"craft_help_attribute is null !!! - {player.toBasicString()}");
if (craft_help_attribute.CraftHelpUpdateDay < DateTime.UtcNow.Date)
{
craft_help_attribute.HelpUserGuids.Clear();
craft_help_attribute.HelpedUserGuids.Clear();
craft_help_attribute.CraftHelpUpdateDay = DateTime.UtcNow.Date;
craft_help_attribute.modifiedEntityAttribute();
}
int same_User_Count = 1;
foreach (var user_guid in craft_help_attribute.HelpUserGuids)
{
if (user_guid == target_guid)
{
same_User_Count += 1;
break;
}
}
if (craft_help_attribute.HelpUserGuids.Count >= MetaHelper.GameConfigMeta.CraftingHelpLimitCount)
{
err_msg = $"Crafting help Count Over !!! - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingHelpCountOver, err_msg);
Log.getLogger().info(err_msg);
return result;
}
if (same_User_Count > MetaHelper.GameConfigMeta.CraftingHelpLimitCountSameUser)
{
err_msg = $"Crafting help Same User Count Over !!! : target guid :{target_guid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingHelpSameUserCountOver, err_msg);
Log.getLogger().info(err_msg);
return result;
}
craft_help_attribute.HelpUserGuids.Add(target_guid);
craft_help_attribute.modifiedEntityAttribute();
return result;
}
public async Task<(Result, DynamoDbDocBase?)> changeTargetCraftHelp(USER_GUID target_guid)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
var dynamo_db_client = server_logic.getDynamoDbClient();
var doc = new CraftHelpDoc(target_guid);
var query_config = dynamo_db_client.makeQueryConfigForReadByPKOnly(doc.getPK());
(result, var read_docs) = await dynamo_db_client.simpleQueryDocTypesWithQueryOperationConfig<CraftHelpDoc>(query_config);
if (read_docs.Count == 0)
{
err_msg = $"Crafting help Doc is empty !!! target userGuid:{target_guid} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftHelpDocIsEmpty, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
var target_craft_help_attrib = read_docs[0].getAttrib<CraftHelpAttrib>();
NullReferenceCheckHelper.throwIfNull(target_craft_help_attrib, () => $"pltarget_craft_help_attribayer is null !!! - {player.toBasicString()}");
if (target_craft_help_attrib.CraftHelpUpdateDay < DateTime.UtcNow.Date)
{
target_craft_help_attrib.HelpUserGuids.Clear();
target_craft_help_attrib.HelpedUserGuids.Clear();
}
if (target_craft_help_attrib.HelpedUserGuids.Count >= MetaHelper.GameConfigMeta.CraftingHelpLimitCountReceive)
{
err_msg = $"Crafting help Same User Count Over !!! : target guid :{target_guid}- {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingHelpReceivedCountOver, err_msg);
Log.getLogger().info(err_msg);
return (result, null);
}
target_craft_help_attrib.HelpedUserGuids.Add(player.getUserGuid());
target_craft_help_attrib.CraftHelpUpdateDay = DateTime.UtcNow.Date;
read_docs[0].setQueryType(QueryType.Update);
return (result, read_docs[0]);
}
public Result cheatChangeCraftHelpInit()
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var craft_help_attribute = player.getEntityAttribute<CraftHelpAttribute>();
NullReferenceCheckHelper.throwIfNull(craft_help_attribute, () => $"craft_help_attribute is null !!! - {player.toBasicString()}");
craft_help_attribute.HelpUserGuids.Clear();
craft_help_attribute.HelpedUserGuids.Clear();
craft_help_attribute.CraftHelpUpdateDay = DateTime.UtcNow.Date;
craft_help_attribute.modifiedEntityAttribute();
return result;
}
}
}

View File

@@ -0,0 +1,119 @@
using Amazon.S3.Model.Internal.MarshallTransformations;
using ServerCommon;
using ServerCore; using ServerBase;
using System.Collections.Concurrent;
using META_ID = System.UInt32;
namespace GameServer
{
public class CraftRecipeAction : EntityActionBase
{
private ConcurrentDictionary<META_ID, CraftRecipe> m_Recipes = new();
public CraftRecipeAction(Player owner)
: base(owner)
{
}
public override Task<Result> onInit()
{
var result = new Result();
return Task.FromResult(result);
}
public override void onClear()
{
m_Recipes.Clear();
}
public List<META_ID> getRecipeMetaIds()
{
var recipe_meta_ids = new List<META_ID>();
foreach (var recipe in m_Recipes.Values)
{
var recipe_attribute = recipe.getEntityAttribute<CraftRecipeAttribute>();
NullReferenceCheckHelper.throwIfNull(recipe_attribute, () => $"recipe_attribute is null !!!");
recipe_meta_ids.Add(recipe_attribute.CraftMetaId);
}
return recipe_meta_ids;
}
public async Task<Result> AddRecipeFromDocs(List<CraftRecipeDoc> recipeDocs)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
foreach (var recipe_doc in recipeDocs)
{
(result, var recipe) = await CraftRecipe.createRecipeFromDoc(player, recipe_doc);
if (result.isFail() || recipe == null)
{
err_msg = $"Failed to createRecipeFromDoc() !!! : {result.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
var recipe_attribute = recipe.getEntityAttribute<CraftRecipeAttribute>();
NullReferenceCheckHelper.throwIfNull(recipe_attribute, () => $"recipe_attribute is null !!! - {player.toBasicString()}");
if (m_Recipes.TryAdd(recipe_attribute.CraftMetaId, recipe) == false)
{
err_msg = $"Failed to get recipe attribute : {nameof(CraftRecipeAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
}
return result;
}
public async Task<Result> RegisterRecipe(META_ID craft_meta_id)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
if (HasRecipe(craft_meta_id) == true)
{
err_msg = $"Already Registered Recipe Failed. !!! - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CraftingRecipeIsAlreadyRegister, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
(result, var craft_recipe) = await CraftRecipe.createRecipe(player, craft_meta_id);
if (result.isFail() || craft_recipe == null)
{
err_msg = $"Create Craft Recipe Failed. !!! - {getOwner().toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
m_Recipes.TryAdd(craft_meta_id, craft_recipe);
return result;
}
public bool HasRecipe(META_ID craft_meta_id)
{
if(m_Recipes.TryGetValue(craft_meta_id, out var result) == false)
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,120 @@
using Google.Protobuf.WellKnownTypes;
using ServerCommon;
using ServerCore; using ServerBase;
using BEACON_GUID = System.String;
using META_ID = System.UInt32;
using ANCHOR_GUID = System.String;
namespace GameServer
{
public class Craft : EntityBase
{
public Craft(EntityBase parent)
: base(EntityType.Craft, parent)
{
}
public override async Task<Result> onInit()
{
var direct_parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(direct_parent, () => $"direct_parent is null !!!");
addEntityAttribute(new CraftAttribute(this, direct_parent));
return await base.onInit();
}
public override string toBasicString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public override string toSummaryString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public static async Task<(Result, Craft?)> createCraftFromDoc(EntityBase parent, CraftDoc doc)
{
var craft = new Craft(parent);
var result = await craft.onInit();
if (result.isFail())
{
return (result, null);
}
var err_msg = string.Empty;
var craft_attribute = craft.getEntityAttribute<CraftAttribute>();
if (craft_attribute == null)
{
err_msg = $"Failed to get craft attribute : {nameof(CraftAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
if (craft_attribute.copyEntityAttributeFromDoc(doc) == false)
{
err_msg = $"Failed to copyEntityAttributeFromDoc !!! : doc_type {doc.GetType()} - {craft.getRootParent().toBasicString()}";
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
return (result, craft);
}
public static async Task<(Result, Craft?)> createCraft(EntityBase parent, ANCHOR_GUID anchor_guid, META_ID craft_meta_id, BEACON_GUID beacon_guid, DateTime now, DateTime craft_finish_time, int craft_count)
{
var craft = new Craft(parent);
var result = await craft.onInit();
if (result.isFail())
{
return (result, null);
}
var err_msg = string.Empty;
var craft_attribute = craft.getEntityAttribute<CraftAttribute>();
if (craft_attribute == null)
{
err_msg = $"Failed to get craft attribute : {nameof(CraftAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
craft_attribute.AnchorGuid = anchor_guid;
craft_attribute.CraftMetaId = craft_meta_id;
craft_attribute.CraftStartTime = now;
craft_attribute.CraftFinishTime = craft_finish_time;
craft_attribute.BeaconGuid = beacon_guid;
craft_attribute.CraftCount = craft_count;
craft_attribute.newEntityAttribute();
return (result, craft);
}
public CraftInfo toCraftData4Client()
{
var craft_4_client = new CraftInfo();
var craft_attribute = getEntityAttribute<CraftAttribute>();
NullReferenceCheckHelper.throwIfNull(craft_attribute, () => $"craft_attribute is null !!!");
craft_4_client.AnchorGuid = craft_attribute.AnchorGuid;
craft_4_client.CraftMetaId = (int)craft_attribute.CraftMetaId;
craft_4_client.CraftStartTime = new Timestamp();
if (craft_attribute.CraftStartTime != new DateTime())
{
craft_4_client.CraftStartTime = Timestamp.FromDateTime(craft_attribute.CraftStartTime);
}
craft_4_client.CraftFinishTime = Timestamp.FromDateTime(craft_attribute.CraftFinishTime);
craft_4_client.BeaconGuid = craft_attribute.BeaconGuid;
craft_4_client.CraftCount = craft_attribute.CraftCount;
return craft_4_client;
}
}
}

View File

@@ -0,0 +1,144 @@
using ServerCommon;
using ServerCore; using ServerBase;
namespace GameServer;
[ChatCommandAttribute("crafthelpinit", typeof(CheatCraftHelpInit), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class CheatCraftHelpInit : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"CraftHelpInit");
var craft_help_action = player.getEntityAction<CraftHelpAction>();
NullReferenceCheckHelper.throwIfNull(craft_help_action, () => $"craft_help_action is null !!! - {player.toBasicString()}");
var server_logic = GameServerApp.getServerLogic();
var fn_start = async delegate ()
{
craft_help_action.cheatChangeCraftHelpInit();
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CheatCommandCraftHelpInit
, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
var result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
return result;
}
return result;
};
var transaction_name = "CheatCommandCraftHelpInit";
var result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid()
, TransactionIdType.PrivateContents, transaction_name
, fn_start);
if (result.isFail())
{
var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()} - transactionName:{transaction_name}, {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
}
}
[ChatCommandAttribute("registercraftrecipe", typeof(CheatRegisterCraftRecipe), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class CheatRegisterCraftRecipe : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"CheatRegisterCraftRecipe");
var craft_recipe_action = player.getEntityAction<CraftRecipeAction>();
NullReferenceCheckHelper.throwIfNull(craft_recipe_action, () => $"craft_recipe_action is null !!! - {player.toBasicString()}");
var server_logic = GameServerApp.getServerLogic();
if (args.Length < 1)
{
Log.getLogger().error($"Invalid Argument");
return;
}
if (uint.TryParse(args[0], out uint recipe_meta_id) == false)
return;
var fn_start = async delegate ()
{
var result = await craft_recipe_action.RegisterRecipe(recipe_meta_id);
if (result.isFail()) return result;
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CheatCommandRegisterCraftRecipe
, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
return result;
}
return result;
};
var transaction_name = "Cheat.CommandRegisterCraftRecipe";
var result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid()
, TransactionIdType.PrivateContents, transaction_name
, fn_start);
if (result.isFail())
{
var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()} - transactionName:{transaction_name}, {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
}
}
[ChatCommandAttribute("craftfinish", typeof(CheatAllCraftFinish), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
internal class CheatAllCraftFinish : ChatCommandBase
{
public override async Task invoke(Player player, string token, string[] args)
{
Log.getLogger().info($"CheatAllCraftFinish");
var craft_action = player.getEntityAction<CraftAction>();
NullReferenceCheckHelper.throwIfNull(craft_action, () => $"craft_action is null !!! - {player.toBasicString()}");
var server_logic = GameServerApp.getServerLogic();
var fn_start = async delegate ()
{
var result = craft_action.cheatAllCraftFinish();
if (result.isFail()) return result;
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CheatAllCraftFinish
, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
return result;
}
return result;
};
var transaction_name = "Cheat.CommandAllCraftFinish";
var result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid()
, TransactionIdType.PrivateContents, transaction_name
, fn_start);
if (result.isFail())
{
var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()} - transactionName:{transaction_name}, {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
}
}

View File

@@ -0,0 +1,93 @@
using Amazon.S3.Model;
using ServerCommon;
using ServerCore; using ServerBase;
using META_ID = System.UInt32;
namespace GameServer
{
public class CraftRecipe : EntityBase
{
public CraftRecipe(EntityBase parent)
: base(EntityType.Recipe, parent)
{
}
public override async Task<Result> onInit()
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
addEntityAttribute(new CraftRecipeAttribute(this, parent));
return await base.onInit();
}
public override string toBasicString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public override string toSummaryString()
{
return $"{this.getTypeName()} - {getRootParent().toBasicString()}";
}
public static async Task<(Result, CraftRecipe?)> createRecipeFromDoc(EntityBase parent, CraftRecipeDoc doc)
{
var recipe = new CraftRecipe(parent);
var result = await recipe.onInit();
if (result.isFail())
{
return (result, null);
}
var err_msg = string.Empty;
var recipe_attribute = recipe.getEntityAttribute<CraftRecipeAttribute>();
if (recipe_attribute == null)
{
err_msg = $"Failed to get recipe attribute : {nameof(CraftRecipeAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
if (recipe_attribute.copyEntityAttributeFromDoc(doc) == false)
{
err_msg = $"Failed to copyEntityAttributeFromDoc !!! : doc_type {doc.GetType()} - {recipe.getRootParent().toBasicString()}";
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
return (result, recipe);
}
public static async Task<(Result, CraftRecipe?)> createRecipe(EntityBase parent, META_ID craft_meta_id)
{
var recipe = new CraftRecipe(parent);
var result = await recipe.onInit();
if (result.isFail())
{
return (result, null);
}
var err_msg = string.Empty;
var recipe_attribute = recipe.getEntityAttribute<CraftRecipeAttribute>();
if (recipe_attribute == null)
{
err_msg = $"Failed to get recipe attribute : {nameof(CraftRecipeAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
recipe_attribute.CraftMetaId = craft_meta_id;
recipe_attribute.newEntityAttribute();
return (result, recipe);
}
}
}

View File

@@ -0,0 +1,106 @@
using ServerCommon;
using ServerCore; using ServerBase;
using META_ID = System.UInt32;
namespace GameServer
{
public class DBQCraftReadAll : QueryExecutorBase
{
private string m_combination_key_for_pk = string.Empty;
private string m_craft_pk = string.Empty;
private readonly List<CraftDoc> m_to_read_craft_docs = new();
public DBQCraftReadAll(string combinationKeyForPK)
: base(typeof(DBQCraftReadAll).Name)
{
m_combination_key_for_pk = combinationKeyForPK;
}
//=====================================================================================
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
//=====================================================================================
public override Task<Result> onPrepareQuery()
{
var result = new Result();
var err_msg = string.Empty;
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
var craft_doc = new CraftDoc();
craft_doc.setCombinationKeyForPK(m_combination_key_for_pk);
var error_code = craft_doc.onApplyPKSK();
if (error_code.isFail())
{
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_craft_pk = craft_doc.getPK();
return Task.FromResult(result);
}
//=====================================================================================
// onPrepareQuery()를 성공할 경우 호출된다.
//=====================================================================================
public override async Task<Result> onQuery()
{
var result = new Result();
var err_msg = string.Empty;
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 craft_query_config = db_connector.makeQueryConfigForReadByPKOnly(m_craft_pk);
var craft_action = owner.getEntityAction<CraftAction>();
NullReferenceCheckHelper.throwIfNull(craft_action, () => "craft_action is null !!!");
(result, var craft_read_docs) = await db_connector.simpleQueryDocTypesWithQueryOperationConfig<CraftDoc>(craft_query_config, eventTid: query_batch.getTransId());
if (result.isFail())
{
return result;
}
result = await craft_action.AddCraftFromDocs(craft_read_docs);
if (result.isFail()) return result;
m_to_read_craft_docs.AddRange(craft_read_docs);
return await Task.FromResult(result);
}
public List<CraftDoc> getToReadItemDocs() => m_to_read_craft_docs;
//=====================================================================================
// 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;
}
public new Player? getOwner() => getQueryBatch()?.getLogActor() as Player;
}
}

View File

@@ -0,0 +1,104 @@
using ServerCommon;
using ServerCore; using ServerBase;
using META_ID = System.UInt32;
namespace GameServer
{
public class DBQCraftRecipeReadAll : QueryExecutorBase
{
private string m_combination_key_for_pk = string.Empty;
private string m_craft_recipe_pk = string.Empty;
private readonly Dictionary<META_ID, CraftRecipeDoc> m_to_read_craft_recipe_docs = new();
public DBQCraftRecipeReadAll(string combinationKeyForPK)
: base(typeof(DBQCraftRecipeReadAll).Name)
{
m_combination_key_for_pk = combinationKeyForPK;
}
//=====================================================================================
// DB 쿼리 직전에 준비해야 할 로직들을 작성한다.
//=====================================================================================
public override Task<Result> onPrepareQuery()
{
var result = new Result();
var err_msg = string.Empty;
var owner = getOwner();
NullReferenceCheckHelper.throwIfNull(owner, () => "owner is null !!!");
var recipe_doc = new CraftRecipeDoc();
recipe_doc.setCombinationKeyForPK(m_combination_key_for_pk);
var error_code = recipe_doc.onApplyPKSK();
if (error_code.isFail())
{
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_craft_recipe_pk = recipe_doc.getPK();
return Task.FromResult(result);
}
//=====================================================================================
// onPrepareQuery()를 성공할 경우 호출된다.
//=====================================================================================
public override async Task<Result> onQuery()
{
var result = new Result();
var err_msg = string.Empty;
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 craft_recipe_query_config = db_connector.makeQueryConfigForReadByPKOnly(m_craft_recipe_pk);
var craft_recipe_action = owner.getEntityAction<CraftRecipeAction>();
NullReferenceCheckHelper.throwIfNull(craft_recipe_action, () => "craft_recipe_action is null !!!");
(result, var craft_recipe_read_docs) = await db_connector.simpleQueryDocTypesWithQueryOperationConfig<CraftRecipeDoc>(craft_recipe_query_config, eventTid: query_batch.getTransId());
if (result.isFail())
{
return result;
}
result = await craft_recipe_action.AddRecipeFromDocs(craft_recipe_read_docs);
if (result.isFail()) return result;
return await Task.FromResult(result);
}
public Dictionary<META_ID, CraftRecipeDoc> getToReadItemDocs() => m_to_read_craft_recipe_docs;
//=====================================================================================
// 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;
}
public new Player? getOwner() => getQueryBatch()?.getLogActor() as Player;
}
}

View File

@@ -0,0 +1,31 @@
using ServerCommon;
using ServerCore; using ServerBase;
namespace GameServer
{
internal static class CraftHelper
{
public static Result checkAnchorCrafting(Player player, List<string> anchorGuids)
{
var result = new Result();
var err_msg = string.Empty;
var crafting_action = player.getEntityAction<CraftAction>();
NullReferenceCheckHelper.throwIfNull(crafting_action, () => $"crafting_action is null !!! - {player.toBasicString()}");
foreach (var anchor_guid in anchorGuids)
{
if (crafting_action.isAnchorCrafting(anchor_guid))
{
err_msg = $"Anchor is Already Crafting !!! : AnchorGuid:{anchor_guid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.CraftingAlreadyCrafting, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
}
return result;
}
}
}

View File

@@ -0,0 +1,32 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class CraftBusinessLog : ILogInvokerEx
{
private CraftLogData m_data_to_log;
public CraftBusinessLog(CraftLogData log_data_param)
: base(LogDomainType.Craft)
{
m_data_to_log = log_data_param;
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(new CraftLogData(this, m_data_to_log));
}
}

View File

@@ -0,0 +1,83 @@
using ServerCommon.BusinessLogDomain;
using ServerCommon;
using META_ID = System.UInt32;
namespace GameServer
{
static public class CraftBusinessLogHelper
{
static public CraftLogData toCraftLogInfo(CraftAttribute craftAttribute)
{
var logData = new CraftLogData();
logData.setCraftInfo(craftAttribute);
return logData;
}
static public CraftLogData toCraftLogInfo(CraftAttrib craftAttrib)
{
var logData = new CraftLogData();
logData.setCraftInfo(craftAttrib);
return logData;
}
static public void setCraftInfo(this CraftLogData logData, CraftAttribute craftAttribute)
{
logData.AnchorGuid = craftAttribute.AnchorGuid;
logData.CraftMetaId = craftAttribute.CraftMetaId;
logData.CraftStartTime = craftAttribute.CraftStartTime;
logData.CraftFinishTime = craftAttribute.CraftFinishTime;
logData.BeaconGuid = craftAttribute.BeaconGuid;
logData.CraftCount = craftAttribute.CraftCount;
}
static public void setCraftInfo(this CraftLogData logData, CraftAttrib craftAttrib)
{
logData.AnchorGuid = craftAttrib.AnchorGuid;
logData.CraftMetaId = craftAttrib.CraftMetaId;
logData.CraftStartTime = craftAttrib.CraftStartTime;
logData.CraftFinishTime = craftAttrib.CraftFinishTime;
logData.BeaconGuid = craftAttrib.BeaconGuid;
logData.CraftCount = craftAttrib.CraftCount;
}
static public CraftHelpLogData toCraftHelpLogInfo(CraftHelpAttrib craftHelpAttrib)
{
var logData = new CraftHelpLogData();
logData.setCraftHelpInfo(craftHelpAttrib);
return logData;
}
static public CraftHelpLogData toCraftHelpLogInfo(CraftHelpAttribute craftHelpAttribute)
{
var logData = new CraftHelpLogData();
logData.setCraftHelpInfo(craftHelpAttribute);
return logData;
}
static public void setCraftHelpInfo(this CraftHelpLogData logData, CraftHelpAttrib craftHelpAttrib)
{
logData.HelpUserGuids = craftHelpAttrib.HelpUserGuids;
logData.HelpedUserGuids = craftHelpAttrib.HelpedUserGuids;
logData.CraftHelpUpdateDay = craftHelpAttrib.CraftHelpUpdateDay;
}
static public void setCraftHelpInfo(this CraftHelpLogData logData, CraftHelpAttribute craftHelpAttribute)
{
logData.HelpUserGuids = craftHelpAttribute.HelpUserGuids;
logData.HelpedUserGuids = craftHelpAttribute.HelpedUserGuids;
logData.CraftHelpUpdateDay = craftHelpAttribute.CraftHelpUpdateDay;
}
static public CraftRecipeLogData toCraftRecipeLogInfo(int recipe_meta_id)
{
var logData = new CraftRecipeLogData();
logData.setCraftRecipeInfo(recipe_meta_id);
return logData;
}
static public void setCraftRecipeInfo(this CraftRecipeLogData logData, int recipe_meta_id)
{
logData.recipe_meta_id = (META_ID)recipe_meta_id;
}
}
}

View File

@@ -0,0 +1,32 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class CraftHelpBusinessLog : ILogInvokerEx
{
private CraftHelpLogData m_data_to_log;
public CraftHelpBusinessLog(CraftHelpLogData log_data_param)
: base(LogDomainType.CraftHelp)
{
m_data_to_log = log_data_param;
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(new CraftHelpLogData(this, m_data_to_log));
}
}

View File

@@ -0,0 +1,32 @@
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public class CraftRecipeBusinessLog : ILogInvokerEx
{
private CraftRecipeLogData m_data_to_log;
public CraftRecipeBusinessLog(CraftRecipeLogData log_data_param)
: base(LogDomainType.Craft)
{
m_data_to_log = log_data_param;
}
public override bool hasLog()
{
return true;
}
protected override void fillup(ref BusinessLog.LogBody body)
{
body.append(new CraftRecipeLogData(this, m_data_to_log));
}
}

Some files were not shown because too many files have changed in this diff Show More