using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Text.RegularExpressions; using Amazon.S3.Model; using ServerCore; using ServerBase; using ServerCommon; using ServerCommon.BusinessLogDomain; using static ServerCommon.MetaHelper; using MetaAssets; using static ClientToGameMessage.Types; using static ClientToGameReq.Types; using static ClientToGameRes.Types; using SESSION_ID = System.Int32; using WORLD_META_ID = System.UInt32; using META_ID = System.UInt32; using ENTITY_GUID = System.String; using ACCOUNT_ID = System.String; using OWNER_GUID = System.String; using USER_GUID = System.String; using CHARACTER_GUID = System.String; using UGC_NPC_META_GUID = System.String; using ITEM_GUID = System.String; namespace GameServer { public class UgcNpcCreationOrLoadAction : EntityActionBase { private UgcNpc? m_reserved_ugc_npc_for_creation_nullable; private readonly Dictionary> m_reserved_slot_types = new(); private ServerCommon.BusinessLogDomain.BeaconCreateLogInfo m_beacon_create_log_info = new(); private ServerCommon.BusinessLogDomain.BeaconLogInfo m_beacon_log_info = new(); public UgcNpcCreationOrLoadAction(Player owner) : base(owner) { } public override Task onInit() { var result = new Result(); return Task.FromResult(result); } public override void onClear() { return; } public void clearReservedSlotTypes() { m_reserved_slot_types.Clear(); } public void resetReserved4UgcNpcCreation() { m_reserved_ugc_npc_for_creation_nullable = null; } public async Task tryLoadUgcNpcFromDoc(UgcNpcDoc ugcNpcDoc) { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(ugcNpcDoc, () => $"ugcNpcDoc is null !!! - {owner.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; var to_load_ugc_npc = new UgcNpc(owner.getUserGuid()); result = await to_load_ugc_npc.onInit(); if (result.isFail()) { return result; } var player_action = owner.getEntityAction(); ArgumentNullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {owner.toBasicString()}"); result = await player_action.tryLoadUgcNpc(to_load_ugc_npc, ugcNpcDoc); if (result.isFail()) { return result; } var ugc_npc_attribute = to_load_ugc_npc.getEntityAttribute(); ArgumentNullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}"); m_beacon_log_info.setInfo(ugc_npc_attribute.toBeaconLogInfo()); return result; } public async Task tryLoadUgcNpcInGameZone(UgcNpc ugcNpcInGameZone) { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(ugcNpcInGameZone, () => $"ugcNpcInGameZone is null !!! - {owner.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; var player_action = owner.getEntityAction(); NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {owner.toBasicString()}"); result = await player_action.tryAttachUgcNpcInGameZone(ugcNpcInGameZone); if (result.isFail()) { return result; } return result; } public async Task tryLoadApprearanceCustomize(DynamoDbClient dbClient, UGC_NPC_META_GUID ugcNpcMetaGuid) { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(dbClient, () => $"dbClient is null !!! - {owner.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; (result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey(ugcNpcMetaGuid); if (result.isFail()) { return result; } NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - {owner.toBasicString()}"); var appearance_customize_query_config = dbClient.makeQueryConfigForReadByPKSK(make_primary_key.PK); // DB에 AppearanceCustomize 정보 없는 경우도 있을 수 있다 !!! (var appearance_customize_result, var appearance_customize_read_doc) = await dbClient.simpleQueryDocTypeWithQueryOperationConfig(appearance_customize_query_config); if (appearance_customize_result.isSuccess()) { NullReferenceCheckHelper.throwIfNull(appearance_customize_read_doc, () => $"appearance_customize_read_doc is null !!! - {owner.toBasicString()}"); appearance_customize_result = await tryLoadApprearanceCustomizeFromDoc(ugcNpcMetaGuid, appearance_customize_read_doc); if (appearance_customize_result.isFail()) { return result; } } return result; } protected async Task tryLoadApprearanceCustomizeFromDoc(UGC_NPC_META_GUID ugcNpcMetaGuid, AppearanceCustomizeDoc appearanceCustomizeDoc) { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(appearanceCustomizeDoc, () => $"appearanceCustomizeDoc is null !!! - {owner.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; var player_action = owner.getEntityAction(); ArgumentNullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {owner.toBasicString()}"); var found_ugc_npc = player_action.findUgcNpc(ugcNpcMetaGuid); if(null == found_ugc_npc) { err_msg = $"Not found UgcNpc !!! : UgcNpcMetaGuid:{ugcNpcMetaGuid} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg); return result; } var beacon_appearance_customize_action = found_ugc_npc.getEntityAction(); ArgumentNullReferenceCheckHelper.throwIfNull(beacon_appearance_customize_action, () => $"beacon_appearance_customize_action is null !!! - {owner.toBasicString()}"); result = await beacon_appearance_customize_action.tryLoadAppearanceCustomizeFromDoc(appearanceCustomizeDoc); if(result.isFail()) { return result; } return result; } public async Task tryLoadBeaconShopItem(DynamoDbClient dbClient, UGC_NPC_META_GUID ugcNpcMetaGuid) { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(dbClient, () => $"dbClient is null !!! - {owner.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; (result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey(ugcNpcMetaGuid); if (result.isFail()) { return result; } NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - {owner.toBasicString()}"); var beacon_shop_item_query_config = dbClient.makeQueryConfigForReadByPKOnly(make_primary_key.PK); (var beacon_shop_item_result, var beacon_shop_item_read_docs) = await dbClient.simpleQueryDocTypesWithQueryOperationConfig(beacon_shop_item_query_config); if (beacon_shop_item_result.isSuccess()) { NullReferenceCheckHelper.throwIfNull(beacon_shop_item_read_docs, () => $"beacon_shop_item_read_docs is null !!! - {owner.toBasicString()}"); beacon_shop_item_result = await tryLoadBeaconShopItemDocFromDoc(beacon_shop_item_read_docs, ugcNpcMetaGuid); if (beacon_shop_item_result.isFail()) { return result; } } return result; } protected async Task tryLoadBeaconShopItemDocFromDoc(List beaconShopItemDocs, UGC_NPC_META_GUID ugcNpcMetaGuid) { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(beaconShopItemDocs, () => $"beaconShopItemDocs is null !!! - {owner.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; var player_action = owner.getEntityAction(); ArgumentNullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {owner.toBasicString()}"); var found_ugc_npc = player_action.findUgcNpc(ugcNpcMetaGuid); if (null == found_ugc_npc) { err_msg = $"Not found UgcNpc !!! : UgcNpcMetaGuid:{ugcNpcMetaGuid} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg); return result; } var ugc_npc_beacon_shop_action = found_ugc_npc.getEntityAction(); foreach (var read_doc in beaconShopItemDocs) { result = await ugc_npc_beacon_shop_action.addBeaconShopItem(read_doc); if (result.isFail()) { return result; } } return result; } public async Task tryLoadBeaconShopProfile(DynamoDbClient dbClient, UGC_NPC_META_GUID ugcNpcMetaGuid) { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(dbClient, () => $"dbClient is null !!! - {owner.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; (result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey(ugcNpcMetaGuid); if (result.isFail()) { return result; } NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - {owner.toBasicString()}"); var beacon_shop_item_query_config = dbClient.makeQueryConfigForReadByPKOnly(make_primary_key.PK); (var beacon_shop_item_result, var beacon_shop_profile_read_docs) = await dbClient.simpleQueryDocTypesWithQueryOperationConfig(beacon_shop_item_query_config); if (beacon_shop_item_result.isSuccess()) { NullReferenceCheckHelper.throwIfNull(beacon_shop_profile_read_docs, () => $"beacon_shop_profile_read_docs is null !!! - {owner.toBasicString()}"); if (beacon_shop_profile_read_docs.Count <= 0) { var beaconShopProfileDoc = new BeaconShopProfileDoc(ugcNpcMetaGuid); var beaconShopProfileAttrib = beaconShopProfileDoc.getAttrib(); NullReferenceCheckHelper.throwIfNull(beaconShopProfileAttrib, () => $"beaconShopProfileAttrib is null !!! - {owner.toBasicString()}"); beaconShopProfileAttrib.BeaconGuid = ugcNpcMetaGuid; result = await dbClient.simpleInsertDocumentWithDocType(beaconShopProfileDoc); if (result.isFail()) { err_msg = $"Failed to simpleUpsertDocumentWithDocType !!! - {owner.toBasicString()}"; Log.getLogger().error(err_msg); return result; } (beacon_shop_item_result, beacon_shop_profile_read_docs) = await dbClient.simpleQueryDocTypesWithQueryOperationConfig(beacon_shop_item_query_config); } beacon_shop_item_result = tryLoadBeaconShopProfileDocFromDoc(beacon_shop_profile_read_docs, ugcNpcMetaGuid); if (beacon_shop_item_result.isFail()) { return result; } } return result; } protected Result tryLoadBeaconShopProfileDocFromDoc(List beaconShopProfileDocs, UGC_NPC_META_GUID ugcNpcMetaGuid) { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(beaconShopProfileDocs, () => $"beaconShopProfileDocs is null !!! - {owner.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; var player_action = owner.getEntityAction(); ArgumentNullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {owner.toBasicString()}"); var found_ugc_npc = player_action.findUgcNpc(ugcNpcMetaGuid); if (null == found_ugc_npc) { err_msg = $"Not found UgcNpc !!! : UgcNpcMetaGuid:{ugcNpcMetaGuid} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg); return result; } var beacon_shop_profile_attribute = found_ugc_npc.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(beacon_shop_profile_attribute, () => $"beacon_shop_profile_attribute is null !!! - {found_ugc_npc.toBasicString()}"); beacon_shop_profile_attribute.copyEntityAttributeFromDoc(beaconShopProfileDocs[0]); beacon_shop_profile_attribute.copyEntityAttributeFromDoc(beaconShopProfileDocs[0]); if (beacon_shop_profile_attribute.BeaconGuid == string.Empty) beacon_shop_profile_attribute.BeaconGuid = ugcNpcMetaGuid; return result; } private async Task checkCreateConditions(C2GS_REQ_UGC_NPC_CREATION request) { await Task.CompletedTask; var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {owner.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; var user_inventory_action = owner.getEntityAction(); NullReferenceCheckHelper.throwIfNull(user_inventory_action, () => $"user_inventory_action is null !!! - {owner.toBasicString()}"); //===================================================================================== // 1. Body Item 보유 확인 하기 //===================================================================================== var found_body_item = user_inventory_action.tryGetItemByItemGuid(request.BodyItemGuid); if (null == found_body_item) { err_msg = $"Not found Body Item !!! : bodyItemGuid:{request.BodyItemGuid} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.ItemNotFound, err_msg); return result; } var item_meta_data = found_body_item.getItemMeta(); NullReferenceCheckHelper.throwIfNull(item_meta_data, () => $"item_meta_data is null !!! - {owner.toBasicString()}"); if(item_meta_data.TypeSmall != EItemSmallType.BEACON_BODY) { err_msg = $"Not Beacon Body Item !!! : EItemSmallType.BEACON_BODY == {item_meta_data.TypeSmall}, bodyItemGuid:{request.BodyItemGuid} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.BeaconBodyItemInvalid, err_msg); return result; } //===================================================================================== // 2. 중복된 ITEM_GUID 존재 체크 하기 //===================================================================================== var found_duplicated_guids = InventoryRuleHelper.findContainDuplicatedItemGuid(request.MaterialItemGuids.ToList()); if (0 < found_duplicated_guids.Count) { err_msg = $"ItemGuid duplicated !!! - {owner.toBasicString()}"; result.setFail(ServerErrorCode.ItemGuidDuplicated, err_msg); return result; } var player_action = owner.getEntityAction(); NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {owner.toBasicString()}"); //===================================================================================== // 3. Ugc Npc 개수 제한 체크 하기 //===================================================================================== if (player_action.getHadUgcNpcCount() >= GameConfigMeta.BeaconCreateMaxCount) { err_msg = $"UgcNpc max count exceed !!! : currCount:{player_action.getHadUgcNpcCount()} <= maxCount:{GameConfigMeta.BeaconCreateMaxCount} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcMaxCountExceed, err_msg); return result; } //===================================================================================== // 4. Ugc Npc 닉네임 제한 체크 하기 //===================================================================================== var error_code = isValidNickname(request.Nickname); if (error_code.isFail()) { err_msg = $"Not valid UgcNpc Nickname !!! : {error_code.toBasicString()}, nick:{request.Nickname} - {owner.toBasicString()}"; result.setFail(error_code, err_msg); Log.getLogger().error(result.toBasicString()); return result; } //===================================================================================== // 5. 문자열 길이 제한 체크 하기 //===================================================================================== if (request.Description.Length > GameConfigMeta.MaxNpcDescriptionChar) { err_msg = $"UgcNpc Description max count exceed !!! : currCount:{request.Description.Length} < maxCount:{GameConfigMeta.MaxNpcDescriptionChar} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcDescriptionLengthExceed, err_msg); return result; } if (request.WorldScenario.Length > GameConfigMeta.MaxNpcBackGroundChar) { err_msg = $"UgcNpc WorldScenario max count exceed !!! : currCount:{request.WorldScenario.Length} < maxCount:{GameConfigMeta.MaxNpcBackGroundChar} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcWordScenarioLengthExceed, err_msg); return result; } if (request.Greeting.Length > GameConfigMeta.MaxNpcGreetingChar) { err_msg = $"UgcNpc Greeting max count exceed !!! : currCount:{request.Greeting.Length} < maxCount:{GameConfigMeta.MaxNpcGreetingChar} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcGreetingLengthExceed, err_msg); return result; } if (request.Introduction.Length > GameConfigMeta.MaxNpcIntroductionChar) { err_msg = $"UgcNpc Introduction max count exceed !!! : currCount:{request.Introduction.Length} < maxCount:{GameConfigMeta.MaxNpcIntroductionChar} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcIntroductionLengthExceed, err_msg); return result; } //===================================================================================== // 6. 재료 아이템 체크 하기 : 의상 & 타투 //===================================================================================== var to_chek_cloth_item_count = GameConfigMeta.NpcCreateDressRequirement; var to_chek_tattoo_item_count = GameConfigMeta.NpcCreateTattooRequirement; var found_user_item_attribute = found_body_item.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(found_user_item_attribute, () => $"found_user_item_attribute is null !!! - {owner.toBasicString()}"); if(false == MetaData.Instance.Meta.BeaconNpcMetaTable.BeaconNpcMetaDataListbyId.TryGetValue((Int32)found_user_item_attribute.ItemMetaId, out var found_beacon_npc_meta)) { err_msg = $"Not found BeaconNpcMetaData !!! : bodyItemMetaId:{found_user_item_attribute.ItemMetaId} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcMetaDataNotFound, err_msg); return result; } var default_cloth_item_meta_ids = found_beacon_npc_meta.DefaultWears.toMetaIds(); var default_cloth_item_count = default_cloth_item_meta_ids.Count; var selected_cloth_item_count = 0; var selected_tattoo_item_count = 0; foreach (var material_item_guid in request.MaterialItemGuids) { var found_item = user_inventory_action.tryGetItemByItemGuid(material_item_guid); if (null == found_item) { err_msg = $"Not found Material Item for UgcNpc create !!! - {owner.toBasicString()}"; result.setFail(ServerErrorCode.ItemNotFound, err_msg); return result; } var item_meta = found_item.getItemMeta(); NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {owner.toBasicString()}"); if (true == item_meta.isClothType()) { selected_cloth_item_count++; to_chek_cloth_item_count--; Int32.Max(to_chek_cloth_item_count, 0); } else if (true == item_meta.isTattooType()) { selected_tattoo_item_count++; to_chek_tattoo_item_count--; Int32.Max(to_chek_tattoo_item_count, 0); } if(0 == to_chek_cloth_item_count && 0 == to_chek_tattoo_item_count) { break; } } if (0 < Int32.Max(to_chek_cloth_item_count - default_cloth_item_count, 0)) { err_msg = $"Not enough Cloth Item for Ugc Npc !!!" + $" : defaultClothItemCount:{default_cloth_item_count} + selectedClothItemCount:{selected_cloth_item_count} <= toCheckClothItemCount:{to_chek_cloth_item_count} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcClothItemNotEnough, err_msg); return result; } if (0 < to_chek_tattoo_item_count) { err_msg = $"Not enough Tattoo Item for Ugc Npc !!!" + $" : selectedTattooItemCount:{selected_tattoo_item_count} <= toCheckTattooItemCount:{to_chek_tattoo_item_count} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcTattooItemNotEnough, err_msg); return result; } //===================================================================================== // 6. 소셜 액션 체크 하기 //===================================================================================== if (false == MetaData.Instance._SocialActionTable.TryGetValue(request.DefaultSocialActionId, out var social_action_meta_data)) { err_msg = $"Not found Default SocialAction MetaId !!! : SocialMetaId:{request.DefaultSocialActionId} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.SocialActionMetaDataNotFound, err_msg); Log.getLogger().error(result.toBasicString()); return result; } if (request.HabitSocialActionIds.Count > GameConfigMeta.MaxNpcFrequentSocial) { err_msg = $"Ugc Npc Habit SocialAction Count Exceed !!! : currCount:{request.HabitSocialActionIds.Count} < maxCount:{GameConfigMeta.MaxNpcFrequentSocial} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcHabitSocialActionCountExceed, err_msg); Log.getLogger().error(result.toBasicString()); return result; } foreach (var social_action_meta_id in request.HabitSocialActionIds) { if (false == MetaData.Instance._SocialActionTable.TryGetValue(social_action_meta_id, out social_action_meta_data)) { err_msg = $"Not found Habit SocialAction MetaId !!! : SocialMetaId:{social_action_meta_id} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.SocialActionMetaDataNotFound, err_msg); Log.getLogger().error(result.toBasicString()); return result; } } if (request.DialogueSocialActionIds.Count > GameConfigMeta.MaxNpcDialogueSocial) { err_msg = $"Ugc Npc Dialogue SocialAction Count Exceed !!! : currCount:{request.DialogueSocialActionIds.Count} < maxCount:{GameConfigMeta.MaxNpcDialogueSocial} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcDialogueSocialActionCountExceed, err_msg); Log.getLogger().error(result.toBasicString()); return result; } foreach (var social_action_meta_id in request.DialogueSocialActionIds) { if (false == MetaData.Instance._SocialActionTable.TryGetValue(social_action_meta_id, out social_action_meta_data)) { err_msg = $"Not found Inaction SocialAction MetaId !!! : SocialMetaId:{social_action_meta_id} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.SocialActionMetaDataNotFound, err_msg); Log.getLogger().error(result.toBasicString()); return result; } } //===================================================================================== // 7. Npc Tag 체크 하기 //===================================================================================== if (request.HashTagMetaIds.Count > GameConfigMeta.MaxNpcTag) { err_msg = $"Ugc Npc Tag Count Exceed !!! : currCount:{request.HashTagMetaIds.Count} < maxCount:{GameConfigMeta.MaxNpcTag} - {owner.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcMaxTagExceed, err_msg); Log.getLogger().error(result.toBasicString()); return result; } return result; } public async Task<(Result, UgcNpc?)> tryCreateUgcNpc(C2GS_REQ_UGC_NPC_CREATION request) { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {owner.toBasicString()}"); // 직전에 예약되어 있는 슬롯을 모두 초기화 한다. clearReservedSlotTypes(); var result = new Result(); var err_msg = string.Empty; var account_attribute = owner.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(account_attribute, () => $"account_attribute is null !!! - {owner.toBasicString()}"); var user_inventory_action = owner.getEntityAction(); NullReferenceCheckHelper.throwIfNull(user_inventory_action, () => $"user_inventory_action is null !!! - {owner.toBasicString()}"); //===================================================================================== // 1. 기본적인 생성 조건 체크 하기 //===================================================================================== result = await checkCreateConditions(request); if (result.isFail()) { return (result, null); } //===================================================================================== // 2. 금전 소모 처리 //===================================================================================== var money_action = owner.getEntityAction(); NullReferenceCheckHelper.throwIfNull(money_action, () => $"money_action is null !!! - {owner.toBasicString()}"); var req_currency_type = (CurrencyType)ServerCommon.MetaHelper.GameConfigMeta.NpcCreateCurrency; var req_cost = GameConfigMeta.NpcCreateCost * -1; result = await money_action.changeMoney(req_currency_type, req_cost); if(result.isFail()) { return (result, null); } //===================================================================================== // 3. 바디 아이템 소모 처리 //===================================================================================== (result, Item? deleted_body_item) = await user_inventory_action.tryDeleteItemByGuid(request.BodyItemGuid); if (result.isFail()) { return (result, null); } NullReferenceCheckHelper.throwIfNull(deleted_body_item, () => $"deleted_body_item is null !!! - {owner.toBasicString()}"); var body_item_attribute_base = deleted_body_item.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(body_item_attribute_base, () => $"body_item_attribute_base is null !!! - {owner.toBasicString()}"); //===================================================================================== // 4. UgcNpc 생성 //===================================================================================== var ugc_npc = new UgcNpc(owner.getUserGuid()); result = await ugc_npc.onInit(); if (result.isFail()) { return (result, null); } //===================================================================================== // 5. ugc npc 생성 정보 설정 하기 //===================================================================================== var ugc_npc_attribute = ugc_npc.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}"); ugc_npc_attribute.OwnerEntityType = OwnerEntityType.User; ugc_npc_attribute.OwnerGuid = owner.getUserGuid(); ugc_npc_attribute.LanguageType = account_attribute.LanguageType; ugc_npc_attribute.UgcNpcMetaGuid = request.BodyItemGuid; ugc_npc_attribute.Nickname = request.Nickname; ugc_npc_attribute.Title = request.Title; ugc_npc_attribute.Greeting = request.Greeting; ugc_npc_attribute.Introduction = request.Introduction; ugc_npc_attribute.Description = request.Description; ugc_npc_attribute.WorldScenario = request.WorldScenario; ugc_npc_attribute.DefaultSocialActionMetaId = (META_ID)request.DefaultSocialActionId; ugc_npc_attribute.HabitSocialActionMetaIds = request.HabitSocialActionIds.Select(x => (META_ID)x).ToList(); ugc_npc_attribute.DialogueSocialActionMetaIds = request.DialogueSocialActionIds.Select(x => (META_ID)x).ToList(); ugc_npc_attribute.HashTagMetaIds = request.HashTagMetaIds.Select(x => (META_ID)x).ToList(); ugc_npc_attribute.BodyItemMetaId = body_item_attribute_base.ItemMetaId; ugc_npc_attribute.newEntityAttribute(); //===================================================================================== // 6. User의 보유 아이템들을 ugc npc로 소유권 이전 시킨다. (의상 & 타투 아이템 및 타투 Visible 설정) //===================================================================================== var ugc_npc_action = ugc_npc.getEntityAction(); NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {owner.toBasicString()}"); result = await ugc_npc_action.tryTakableItemFromUser( request.MaterialItemGuids.ToList() , request.TattooSlotVisibles.ToDictionary() , m_reserved_slot_types , owner ); if (result.isFail()) { return (result, null); } m_reserved_ugc_npc_for_creation_nullable = ugc_npc; return (result, ugc_npc); } public async Task completedUgcNpcCreation(QueryExecutorBase queryExecutorBase) { await Task.CompletedTask; var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); ArgumentNullReferenceCheckHelper.throwIfNull(queryExecutorBase, () => $"queryExecutorBase is null !!! - {owner.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; var player_action = owner.getEntityAction(); NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {owner.toBasicString()}"); var reserved_to_create_ugc_npc = getReservedUgcNpcForCreation(); NullReferenceCheckHelper.throwIfNull(reserved_to_create_ugc_npc, () => $"reserved_to_create_ugc_npc is null !!! - {owner.toBasicString()}"); var ugc_npc_attribute = reserved_to_create_ugc_npc.getOriginEntityAttribute(); NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}"); var origin_ugc_npc_doc = ugc_npc_attribute.getOriginDocBase() as UgcNpcDoc; NullReferenceCheckHelper.throwIfNull(origin_ugc_npc_doc, () => $"origin_ugc_npc_doc is null !!! - {owner.toBasicString()}"); result = await player_action.tryLoadUgcNpc(reserved_to_create_ugc_npc, origin_ugc_npc_doc); if (result.isFail()) { Log.getLogger().error(result.toBasicString()); } var ugc_npc_action = reserved_to_create_ugc_npc.getEntityAction(); NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {owner.toBasicString()}"); // AiChatServer에 UgcNpc를 등록 시도 한다. result = await ugc_npc_action.tryRegisterCharacterWithAiChatServer(owner); if (result.isFail()) { err_msg = $"Failed to tryRegisterCharacterWithAiChatServer() !!! : {result.toBasicString()} - {owner.toBasicString()}"; Log.getLogger().error(err_msg); } // origin 메모리에 반영한다. result = await player_action.commitTransaction(TransactionIdType.PrivateContents); if (result.isFail()) { err_msg = $"Failed to commitTransaction() !!! : {result.toBasicString()} - {owner.toBasicString()}"; Log.getLogger().error(err_msg); } var query_batch = queryExecutorBase.getQueryBatch(); NullReferenceCheckHelper.throwIfNull(query_batch, () => $"query_batch is null !!! - {owner.toBasicString()}"); var log_action = query_batch.getLogAction(); NullReferenceCheckHelper.throwIfNull(log_action, () => $"log_action is null !!! - {owner.toBasicString()}"); // 비즈니스 로그 추가 queryExecutorBase.appendBusinessLog(new BeaconCreateBusinessLog(log_action, DateTimeHelper.Current, m_beacon_create_log_info)); queryExecutorBase.appendBusinessLog(new BeaconBusinessLog(log_action, reserved_to_create_ugc_npc.toBeaconLogInfo())); return QueryBatchBase.QueryResultType.Success; } public ServerErrorCode isValidNickname(string nickName) { // 첫번째 글자가 숫자인지 체크 한다. if (Regex.IsMatch(nickName[0].ToString(), "[0-9]") == true) { return ServerErrorCode.UserNicknameNotAllowedNumberAtFirstChars; } // 특수문자가 포함되어 있는지 체크 한다. if (true == nickName.isContainSpecialChars(out _)) { return ServerErrorCode.UserNicknameNotAllowWithSpecialChars; } // 길이 체크 if (nickName.Length < MetaHelper.GameConfigMeta.UserNicknameMinLength || nickName.Length > MetaHelper.GameConfigMeta.UserNicknameMaxLength) { return ServerErrorCode.UserNicknameAllowedMin2ToMax12; } // 금지어 여부를 체크 한다. if (StringRuleHelper.isBanWord(nickName, true) == true) { Log.getLogger().info($"User Nickname is Ban !!! : nickname:{nickName}"); return ServerErrorCode.UserNicknameBan; } return ServerErrorCode.Success; } public async Task> getDocs4UgcNpcCreation() { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var to_create_docs = new List(); var user_attribute = owner.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(user_attribute, () => $"user_attribute is null !!! - {owner.toBasicString()}"); var reserved_ugc_npc_for_creation = getReservedUgcNpcForCreation(); NullReferenceCheckHelper.throwIfNull(reserved_ugc_npc_for_creation, () => $"reserved_ugc_npc_for_creation is null !!! - {owner.toBasicString()}"); var ugc_npc_attribute = reserved_ugc_npc_for_creation.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}"); // UgcNpc 닉네임 관련 DB 정보를 생성 한다. { var to_create_doc = new UgcNpcNicknameRegistryDoc(OwnerEntityType.User, user_attribute.UserGuid, ugc_npc_attribute.Nickname, ugc_npc_attribute.UgcNpcMetaGuid); await to_create_doc.newDoc4Query(); to_create_docs.Add(to_create_doc); } // UgcNpc 좋아요 선택받은 개수 관련 DB 정보를 생성 한다. { var to_create_doc = new UgcNpcLikeSelecteeCountDoc(OwnerEntityType.UgcNpc, ugc_npc_attribute.UgcNpcMetaGuid); await to_create_doc.newDoc4Query(); to_create_docs.Add(to_create_doc); } return to_create_docs; } public GS2C_ACK_UGC_NPC_CREATION toAckUgcNpcCreation() { var owner = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); NullReferenceCheckHelper.throwIfNull(m_reserved_ugc_npc_for_creation_nullable, () => $"m_reserved_ugc_npc_for_creation_nullable is null !!! - {owner.toBasicString()}"); var ugc_npc_attribute = m_reserved_ugc_npc_for_creation_nullable.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {owner.toBasicString()}"); var ugc_npc_inventory_action = m_reserved_ugc_npc_for_creation_nullable.getEntityAction(); NullReferenceCheckHelper.throwIfNull(ugc_npc_inventory_action, () => $"ugc_npc_inventory_action is null !!! - {owner.toBasicString()}"); var ack = new GS2C_ACK_UGC_NPC_CREATION(); ack.UgcNpcMetaGuid = ugc_npc_attribute.UgcNpcMetaGuid; ack.Nickname = ugc_npc_attribute.Nickname; ack.Title = ugc_npc_attribute.Title; ack.Greeting = ugc_npc_attribute.Greeting; ack.Introduction = ugc_npc_attribute.Introduction; ack.Description = ugc_npc_attribute.Description; ack.WorldScenario = ugc_npc_attribute.WorldScenario; ack.DefaultSocialActionId = (Int32)ugc_npc_attribute.DefaultSocialActionMetaId; ack.HabitSocialActionIds.AddRange(ugc_npc_attribute.HabitSocialActionMetaIds.Select(x => (Int32)x).ToList()); ack.DialogueSocialActionIds.AddRange(ugc_npc_attribute.DialogueSocialActionMetaIds.Select(x => (Int32)x).ToList()); ack.TattooSlotInfos.Add(ugc_npc_inventory_action.toTattooAll4Client().toMapField()); ack.HashTagMetaIds.Add(ugc_npc_attribute.HashTagMetaIds.Select(x => (Int32)x).ToList()); resetReserved4UgcNpcCreation(); var found_transaction_runner = owner.findTransactionRunner(TransactionIdType.PrivateContents); if(null == found_transaction_runner) { var err_msg = $"Not found TransactionRunner !!! : {toBasicString()} - {owner.toBasicString()}"; Log.getLogger().warn(err_msg); return ack; } ack.CommonResult = found_transaction_runner.getCommonResult(); return ack; } public UgcNpc? getReservedUgcNpcForCreation() => m_reserved_ugc_npc_for_creation_nullable; } }