using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ServerCore; using ServerBase; using ServerCommon; using ServerCommon.BusinessLogDomain; using MetaAssets; using SESSION_ID = System.Int32; using WORLD_META_ID = System.UInt32; using META_ID = System.UInt32; using ENTITY_GUID = System.String; using ACCOUNT_ID = System.String; using OWNER_GUID = System.String; using USER_GUID = System.String; using CHARACTER_GUID = System.String; using ITEM_GUID = System.String; using NPC_UNIQUE_ID = System.String; using UGC_NPC_META_GUID = System.String; namespace GameServer; public static class UgcNpcHelper { public static async Task<(Result, Int64)> getLikeCountOfUgcNpc(UGC_NPC_META_GUID ugcNpcMetaGuid, Player player) { var server_logic = GameServerApp.getServerLogic(); ArgumentNullException.ThrowIfNull(server_logic, $"server_logic is null !!! - {player.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; var dynamo_db_client = server_logic.getDynamoDbClient(); var selectee_count_doc = new UgcNpcLikeSelecteeCountDoc(OwnerEntityType.UgcNpc, ugcNpcMetaGuid); var selectee_count_query_config = dynamo_db_client.makeQueryConfigForReadByPKSK(selectee_count_doc.getPK(), selectee_count_doc.getSK()); (result, var npc_like_selectee_count_doc) = await dynamo_db_client.simpleQueryDocTypeWithQueryOperationConfig(selectee_count_query_config); if (result.isFail()) { err_msg = $"Failed to simpleQueryDocTypeWithQueryOperationConfig() !!!, Not found UgcNpcLikeSelecteeCountDoc : {selectee_count_doc.toBasicString()} - {player.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcLikeSelecteeCountNotFound, err_msg); Log.getLogger().error(result.toBasicString()); return (result, 0); } NullReferenceCheckHelper.throwIfNull(npc_like_selectee_count_doc, () => $"npc_like_selectee_count_doc is null !!! - {player.toBasicString()}"); var ugc_npc_like_selectee_count_attrib = npc_like_selectee_count_doc.getAttrib(); NullReferenceCheckHelper.throwIfNull(ugc_npc_like_selectee_count_attrib, () => $"ugc_npc_like_selectee_count_attrib is null !!! - {player.toBasicString()}"); return (result, ugc_npc_like_selectee_count_attrib.LikeCount); } public static async Task<(Result, Int64)> getDialogCountOfUgcNpc(UGC_NPC_META_GUID ugcNpcMetaGuid, Player player) { var result = new Result(); var err_msg = string.Empty; var ai_chat_action = player.getEntityAction(); NullReferenceCheckHelper.throwIfNull(ai_chat_action, () => $"ai_chat_action is null !!! - {player.toBasicString()}"); (result, var ai_chat_character) = await ai_chat_action.getCharacterByTargetGuid(ugcNpcMetaGuid); if(result.isFail()) return (result, 0); NullReferenceCheckHelper.throwIfNull(ai_chat_character, () => $"ai_chat_character is null !!! - {player.toBasicString()}"); return (result, ai_chat_character.data.chat_count); } public static async Task<(Result, BoolType)> getLikeCheckFlagOfUgcNpc(UGC_NPC_META_GUID ugcNpcMetaGuid, Player player) { var server_logic = GameServerApp.getServerLogic(); var result = new Result(); var err_msg = string.Empty; var dynamo_db_client = server_logic.getDynamoDbClient(); var selected_flag_doc = new UgcNpcLikeSelectedFlagDoc(OwnerEntityType.User, player.getUserGuid(), ugcNpcMetaGuid); var selected_flag_query_config = dynamo_db_client.makeQueryConfigForReadByPKSK(selected_flag_doc.getPK(), selected_flag_doc.getSK()); (result, var npc_like_selected_flag_docs) = await dynamo_db_client.simpleQueryDocTypesWithQueryOperationConfig(selected_flag_query_config); if (result.isFail() || npc_like_selected_flag_docs.Count == 0) { err_msg = $"Failed to simpleQueryDocTypeWithQueryOperationConfig() !!!, Not found UgcNpcLikeSelectedFlagDoc : {selected_flag_doc.toBasicString()} - {player.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcLikeSelectedFlagNotFound, err_msg); Log.getLogger().error(result.toBasicString()); return (result, 0); } var npc_like_selected_flag_attrib = npc_like_selected_flag_docs[0].getAttrib(); NullReferenceCheckHelper.throwIfNull(npc_like_selected_flag_attrib, () => $"npc_like_selected_flag_attrib is null !!! - {player.toBasicString()}"); return (result, npc_like_selected_flag_attrib.IsSelectedFlag == true ? BoolType.True : BoolType.False); } public static async Task<(Result, List?)> loadUgcNpcFromMyhome(Map currMap, string myhomeGuid) { ArgumentNullReferenceCheckHelper.throwIfNull(currMap, () => $"currMap is null !!! - myHomeGuid:{myhomeGuid}"); var result = new Result(); var err_msg = string.Empty; var ugc_npcs = new List(); var server_logic = GameServerApp.getServerLogic(); var db_client = server_logic.getDynamoDbClient(); var location_unique_id = currMap.makeLOCATION_UNIQUE_IDByMetaId(myhomeGuid); var event_tid = Guid.NewGuid().ToString("N"); var npc_location_in_target_doc = new NpcLocationInTargetDoc(location_unique_id, myhomeGuid); var query_config = db_client.makeQueryConfigForReadByPKOnly(npc_location_in_target_doc.getPK()); (result, var read_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig(query_config); if (result.isFail()) { return (result, null); } NullReferenceCheckHelper.throwIfNull(read_docs, () => $"read_docs is null !!! - myHomeGuid:{myhomeGuid}"); NpcLocationInTargetAttrib? npc_location_in_target_attrib; foreach (var doc in read_docs) { npc_location_in_target_attrib = doc.getAttrib(); NullReferenceCheckHelper.throwIfNull(npc_location_in_target_attrib, () => $"npc_location_in_target_attrib is null !!!"); var owner_entity_type = npc_location_in_target_attrib.OwnerEntityType; var owner_guid = npc_location_in_target_attrib.OwnerGuid; var ugc_npc_guid = npc_location_in_target_attrib.NpcUniqueId; /////////////////////////////////////////////////////////////////////////////////////// // 1. Player가 로드한 or GameZone에 배치된 UgcNpc 객체를 찾는다. /////////////////////////////////////////////////////////////////////////////////////// (result, var found_ugc_npc, var ugc_npc_owner) = await NpcHelper.findUgcNpc(ugc_npc_guid, owner_guid); if (found_ugc_npc != null) { var found_ugc_npc_attribute = found_ugc_npc.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(found_ugc_npc_attribute, () => $"found_ugc_npc_attribute is null !!!"); if (found_ugc_npc_attribute.AnchorMetaGuid != npc_location_in_target_attrib.AnchorMetaGuid) { await db_client.simpleDeleteDocumentWithDocType(doc, event_tid); continue; } found_ugc_npc_attribute.setCurrentPos(npc_location_in_target_attrib.NpcLocation.CurrentPos); ugc_npcs.Add(found_ugc_npc); continue; } /////////////////////////////////////////////////////////////////////////////////////// // 2. DB에서 UgcNpc 정보를 읽는다. /////////////////////////////////////////////////////////////////////////////////////// (result, var loaded_ugc_npc) = await tryLoadUgcNpcInfoFromDb(owner_entity_type, owner_guid, ugc_npc_guid); if(result.isSuccess()) { NullReferenceCheckHelper.throwIfNull(loaded_ugc_npc, () => $"loaded_ugc_npc is null !!! - myHomeGuid:{myhomeGuid}"); var loaded_ugc_npc_attribute = loaded_ugc_npc.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(loaded_ugc_npc_attribute, () => $"loaded_ugc_npc_attribute is null !!! - myHomeGuid:{myhomeGuid}"); if (loaded_ugc_npc_attribute.AnchorMetaGuid != npc_location_in_target_attrib.AnchorMetaGuid) { await db_client.simpleDeleteDocumentWithDocType(doc, event_tid); err_msg = $"UgcNpc located not match anchor meta guid !!! : UgcNpc.AnchorMetaGuid:{loaded_ugc_npc_attribute.AnchorMetaGuid} != NpcLocation.AnchorMetaGuid:{npc_location_in_target_attrib.AnchorMetaGuid} - {loaded_ugc_npc.toBasicString()}"; Log.getLogger().error(err_msg); continue; } loaded_ugc_npc_attribute.setCurrentPos(npc_location_in_target_attrib.NpcLocation.CurrentPos); ugc_npcs.Add(loaded_ugc_npc); } } return (result, ugc_npcs); } public static async Task<(Result, UgcNpc?)> tryLoadUgcNpcInfoFromDb( OwnerEntityType ownerEntityType, OWNER_GUID ownerGuid , UGC_NPC_META_GUID ugcNpcMetaGuid ) { var server_logic = GameServerApp.getServerLogic(); var db_client = server_logic.getDynamoDbClient(); var result = new Result(); var err_msg = string.Empty; /////////////////////////////////////////////////////////////////////////////////////// // 1. UgcNpcDoc 정보를 읽는다. /////////////////////////////////////////////////////////////////////////////////////// (result, var make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey(ownerGuid, ugcNpcMetaGuid); if (result.isFail()) { return (result, null); } NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - ugcNpcMetaGuid:{ugcNpcMetaGuid}, ownerGuid:{ownerGuid}"); var ugc_npc_query_config = db_client.makeQueryConfigForReadByPKSK(make_primary_key.PK, make_primary_key.SK); NullReferenceCheckHelper.throwIfNull(ugc_npc_query_config, () => $"ugc_npc_query_config is null !!! - ugcNpcMetaGuid:{ugcNpcMetaGuid}, ownerGuid:{ownerGuid}"); (result, var ugc_npc_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig(ugc_npc_query_config); if (result.isFail() || ugc_npc_docs.Count <= 0 || ugc_npc_docs.Count > 1) { return (result, null); } NullReferenceCheckHelper.throwIfNull(ugc_npc_docs, () => $"ugc_npc_docs is null !!! - ugcNpcMetaGuid:{ugcNpcMetaGuid}, ownerGuid:{ownerGuid}"); var read_ugc_npc_doc_from_db = ugc_npc_docs[0]; NullReferenceCheckHelper.throwIfNull(read_ugc_npc_doc_from_db, () => $"read_ugc_npc_doc_from_db is null !!! - ugcNpcMetaGuid:{ugcNpcMetaGuid}, ownerGuid:{ownerGuid}"); var ugc_npc = new UgcNpc(ownerGuid); await ugc_npc.onInit(); var ugc_npc_attribute = ugc_npc.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - ugcNpcMetaGuid:{ugcNpcMetaGuid}, ownerGuid:{ownerGuid}"); if (false == ugc_npc_attribute.copyEntityAttributeFromDoc(read_ugc_npc_doc_from_db)) { err_msg = $"Failed to copyEntityAttributeFromDoc() !!! to:{ugc_npc_attribute.getTypeName()}, from:{read_ugc_npc_doc_from_db.getTypeName()}"; result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg); Log.getLogger().error(result.toBasicString()); return (result, null); } /////////////////////////////////////////////////////////////////////////////////////// // 2. ItemDoc 정보를 읽는다. /////////////////////////////////////////////////////////////////////////////////////// var combination_key_for_pk = ugcNpcMetaGuid; (result, make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey(combination_key_for_pk); if (result.isFail()) { return (result, null); } NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - {ugc_npc.toBasicString()}"); var item_query_config = db_client.makeQueryConfigForReadByPKOnly(make_primary_key.PK); NullReferenceCheckHelper.throwIfNull(item_query_config, () => $"make_primary_key is null !!! - {ugc_npc.toBasicString()}"); (result, var item_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig(item_query_config); if (result.isFail()) { return (result, null); } NullReferenceCheckHelper.throwIfNull(item_docs, () => $"make_primary_key is null !!! - {ugc_npc.toBasicString()}"); var inventory_action = ugc_npc.getEntityAction(); NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!! : {ugc_npc.toBasicString()}"); var reserved_slots_of_equip = new Dictionary>(); var retry_equip_items = new List(); foreach (var item_doc in item_docs) { (var equip_result, var to_add_item) = await inventory_action.tryTakableToBagWithEquip(item_doc, reserved_slots_of_equip); if (equip_result.isFail()) { if (null != to_add_item) { retry_equip_items.Add(to_add_item); } continue; } } /////////////////////////////////////////////////////////////////////////////////////// // 2.1. 장착을 실패한 아이템을 장착이 가능한 빈슬롯에 장착 시킨다. /////////////////////////////////////////////////////////////////////////////////////// foreach (var retry_item in retry_equip_items) { var item_meta = retry_item.getItemMeta(); ArgumentNullException.ThrowIfNull(item_meta, $"item_meta is null !!! - {ugc_npc.toBasicString()}"); (var equip_result, var equipable_slot) = inventory_action.getEquipableSlotOfEquipInven(item_meta, reserved_slots_of_equip); if (equip_result.isFail()) { continue; } equip_result = await inventory_action.tryTakableToEquip(retry_item, (Int16)equipable_slot); if (equip_result.isFail()) { continue; } } /////////////////////////////////////////////////////////////////////////////////////// // 3. AppearanceCustomizeDoc 정보를 읽는다. /////////////////////////////////////////////////////////////////////////////////////// var appearance_customize_action = ugc_npc.getEntityAction(); ArgumentNullException.ThrowIfNull(appearance_customize_action, $"appearance_customize_action is null !!! - {ugc_npc.toBasicString()}"); (result, make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey(ugcNpcMetaGuid); if (result.isFail()) { return (result, null); } NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - {ugc_npc.toBasicString()}"); var appearance_customize_query_config = db_client.makeQueryConfigForReadByPKSK(make_primary_key.PK); // DB에 AppearanceCustomize 정보 없는 경우도 있을 수 있다 !!! (var appearance_customize_result, var appearance_customize_read_doc) = await db_client.simpleQueryDocTypeWithQueryOperationConfig(appearance_customize_query_config); if(appearance_customize_result.isSuccess()) { NullReferenceCheckHelper.throwIfNull(appearance_customize_read_doc, () => $"appearance_customize_read_doc is null !!! - {ugc_npc.toBasicString()}"); var beacon_appearance_customize_action = ugc_npc.getEntityAction(); NullReferenceCheckHelper.throwIfNull(beacon_appearance_customize_action, () => $"beacon_appearance_customize_action is null !!! - {ugc_npc.toBasicString()}"); appearance_customize_result = await beacon_appearance_customize_action.tryLoadAppearanceCustomizeFromDoc(appearance_customize_read_doc); if (appearance_customize_result.isFail()) { err_msg = $"Failed to tryLoadAppearanceCustomizeFromDoc() !!! : {appearance_customize_result.toBasicString()} - {ugc_npc.toBasicString()}"; Log.getLogger().error(err_msg); } } /////////////////////////////////////////////////////////////////////////////////////// // 4. BeaconShopItemDoc 정보를 읽는다. /////////////////////////////////////////////////////////////////////////////////////// var beacon_shop_item_combination_key_for_pk = ugcNpcMetaGuid; (result, make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey(beacon_shop_item_combination_key_for_pk); if (result.isFail()) { return (result, null); } NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - {ugc_npc.toBasicString()}"); var beacon_shop_item_query_config = db_client.makeQueryConfigForReadByPKOnly(make_primary_key.PK); NullReferenceCheckHelper.throwIfNull(beacon_shop_item_query_config, () => $"make_primary_key is null !!! - {ugc_npc.toBasicString()}"); (result, var beacon_item_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig(beacon_shop_item_query_config); if (result.isFail()) { return (result, null); } NullReferenceCheckHelper.throwIfNull(beacon_item_docs, () => $"make_primary_key is null !!! - {ugc_npc.toBasicString()}"); var ugc_npc_beacon_shop_action = ugc_npc.getEntityAction(); foreach (var item_doc in beacon_item_docs) { result = await ugc_npc_beacon_shop_action.addBeaconShopItem(item_doc); if (result.isFail()) { return (result, null); } } /////////////////////////////////////////////////////////////////////////////////////// // 5. BeaconShopProfileDoc 정보를 읽는다. /////////////////////////////////////////////////////////////////////////////////////// var beacon_shop_profile_combination_key_for_pk = ugcNpcMetaGuid; (result, make_primary_key) = await DynamoDBDocBaseHelper.makePrimaryKey(beacon_shop_profile_combination_key_for_pk); if (result.isFail()) { return (result, null); } NullReferenceCheckHelper.throwIfNull(make_primary_key, () => $"make_primary_key is null !!! - {ugc_npc.toBasicString()}"); var beacon_shop_profile_query_config = db_client.makeQueryConfigForReadByPKOnly(make_primary_key.PK); NullReferenceCheckHelper.throwIfNull(beacon_shop_profile_query_config, () => $"beacon_shop_profile_query_config is null !!! - {ugc_npc.toBasicString()}"); (result, var beacon_profile_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig(beacon_shop_profile_query_config); if (result.isFail()) { return (result, null); } NullReferenceCheckHelper.throwIfNull(beacon_profile_docs, () => $"beacon_profile_docs is null !!! - {ugc_npc.toBasicString()}"); var beacon_shop_profile_attribute = ugc_npc.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(beacon_shop_profile_attribute, () => $"beacon_shop_profile_attribute is null !!! - {ugc_npc.toBasicString()}"); if (beacon_profile_docs.Count <= 0) { var beaconShopProfileDoc = new BeaconShopProfileDoc(ugcNpcMetaGuid); var beaconShopProfileAttrib = beaconShopProfileDoc.getAttrib(); NullReferenceCheckHelper.throwIfNull(beaconShopProfileAttrib, () => $"beaconShopProfileAttrib is null !!! - {ugc_npc.toBasicString()}"); beaconShopProfileAttrib.BeaconGuid = ugcNpcMetaGuid; result = await db_client.simpleInsertDocumentWithDocType(beaconShopProfileDoc); if (result.isFail()) { err_msg = $"Failed to simpleUpsertDocumentWithDocType !!! - {ugc_npc.toBasicString()}"; Log.getLogger().error(err_msg); return (result, null); } (result, beacon_profile_docs) = await db_client.simpleQueryDocTypesWithQueryOperationConfig(beacon_shop_profile_query_config); if (result.isFail()) { return (result, null); } } beacon_shop_profile_attribute.copyEntityAttributeFromDoc(beacon_profile_docs[0]); return (result, ugc_npc); } public static string toPersonaWithJsonString(string WorldScenario, string Description) { var world_scenario = $"WorldScenario"; var description = $"description"; var persona = $"{{\"{world_scenario}\":\"{WorldScenario}\", \"{description}\":\"{Description}\"}}"; return persona; } public static List toSocialActionConfigWithAIChatServer(META_ID DefaultSocialActionMetaId, List HabitSocialActionMetaIds) { int social_action_weight = 0; var social_action_config = new List(); foreach (var social_action_data in MetaData.Instance._SocialActionTable.Values) { if (social_action_data.is_ingame == false) continue; social_action_weight = ServerCommon.Constant.DEFAULT_SOCIAL_ACTION_WEIGHT; foreach (var incation_data in HabitSocialActionMetaIds) { if (incation_data == social_action_data.SocialActionId) { social_action_weight = ServerCommon.Constant.HABIT_SOCIAL_ACTION_WEIGHT; break; } } if (social_action_data.is_ai_default == false && DefaultSocialActionMetaId != social_action_data.SocialActionId && social_action_weight == ServerCommon.Constant.DEFAULT_SOCIAL_ACTION_WEIGHT) { continue; } social_action_config.Add(new AIChatSocialActionConfig() { id = social_action_data.SocialActionId, weight = social_action_weight }); } return social_action_config; } public static string makeBeaconAppProfileS3Key(string serviceFolderName, string beaconGuid) { return $"{serviceFolderName}/{beaconGuid}/profile.png"; } public static async Task<(Result, string)> getBeaconAppProfileUploadPresignedUrl(string beaconGuid) { var result = new Result(); var err_msg = string.Empty; var presinged_url = string.Empty; var server_logic = GameServerApp.getServerLogic(); if (server_logic.getServerConfig().OfflineMode) { err_msg = $"Server is Offline Mode !!!"; result.setFail(ServerErrorCode.FunctionNotImplemented, err_msg); Log.getLogger().error(result.toBasicString()); return (result, presinged_url); } else { var server_config = server_logic.getServerConfig(); var bucket_name = server_config.AWS.S3.BeaconAppProfileBucketName; var service_folder_name = server_config.AWS.S3.ServiceFolderName; var beacon_app_profile_s3_key = makeBeaconAppProfileS3Key(service_folder_name, beaconGuid); var s3_client = server_logic.getS3Connector(); (result, presinged_url) = await s3_client.getBeaconAppProfileUploadPresignedUrl(bucket_name, beacon_app_profile_s3_key); if (result.isFail()) { err_msg = $"Failed to getBeaconAppProfileUploadPresignedUrl() !!! : {result.toBasicString()}"; Log.getLogger().error(err_msg); return (result, presinged_url); } } return (result, presinged_url); } public static Result checkBeaconShopItem(Player player, List ugcNpcAnchorInfos) { var result = new Result(); var err_msg = string.Empty; var player_action = player.getEntityAction(); foreach (var ugc_npc_anchor_info in ugcNpcAnchorInfos) { var ugc_npc_guid = ugc_npc_anchor_info.EntityGuid; var ugc_npc = player_action.findUgcNpc(ugc_npc_guid); ArgumentNullException.ThrowIfNull(ugc_npc, $"ugc_npc is null !!! - {player.toBasicString()}"); var ugc_npc_beacon_shop_action = ugc_npc.getEntityAction(); if (ugc_npc_beacon_shop_action.hasBeaconShopItem()) { err_msg = $"UgcNpc has Beacon Shop Item !!! : ugcNpcGuid:{ugc_npc_guid} - {player.toBasicString()}"; result.setFail(ServerErrorCode.UgcNpcHasBeaconShopItem, err_msg); Log.getLogger().error(result.toBasicString()); return result; } } return result; } }