using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.Model; using Nettention.Proud; using ServerCore; using ServerBase; using ServerCommon; using ServerCommon.BusinessLogDomain; using MetaAssets; using DYNAMO_DB_TABLE_FULL_NAME = System.String; using Guid = System.Guid; namespace GameServer; public class UgcNpcRankHelper { public const string RankKeySplit = "_"; public static string makeRankKey(string ownerGuid, string ugcNpcMetaGuid) => $"{ownerGuid}{RankKeySplit}{ugcNpcMetaGuid}"; public static DateTime getCurrentRankDate() { return makeCurrentOrganizationDate().AddDays(-1); } public static DateTime makeCurrentOrganizationDate() { var current_time = DateTimeHelper.Current; var compare_current = Convert.ToDateTime(current_time.ToString("HH:mm:ss")); var organizationTime = MetaHelper.GameConfigMeta.NpcRankingCalculateTime; var check_time = compare_current < organizationTime ? current_time.AddDays(-1) : current_time; var organization = new DateTime(check_time.Year, check_time.Month, check_time.Day, organizationTime.Hour, organizationTime.Minute, organizationTime.Second, DateTimeKind.Utc); return organization; } public static Int64 getUgcNpcRankDocTtlSeconds(DateTime? startDate = null) { var current = DateTimeHelper.Current; var delta_period = 0; if (null != startDate) { if (startDate > current) startDate = current; var current_time = new DateTime(current.Year, current.Month, current.Day); var delta = current_time - startDate; delta_period = (int)delta.Value.TotalSeconds; } // retention period 는 Hour 단위임 var retention_period = MetaHelper.GameConfigMeta.NpcRankingRetentionPeriod; return retention_period * 60 * 60 - delta_period; } public static (string ownerGuid, string ugcNpcMetaGuid) getDetailRankKey(string key) { var split = key.Split(RankKeySplit); if (split.Length < 2) return (string.Empty, string.Empty); return (split[0], split[1]); } public static async Task> getUgcNpcSummaryFromMetaGuid(List<(string guid, long score)> ranks) { var list = new List(ranks.Count); var ranking = 1; foreach (var rank in ranks) { var guids = UgcNpcRankHelper.getDetailRankKey(rank.guid); var ugc_npc_attrib = await getUgcNpcFromMetaGuid(guids.ownerGuid, guids.ugcNpcMetaGuid); if (ugc_npc_attrib == null) continue; list.Add(await makeUgcNpcAttribToUgcNpcRank(ugc_npc_attrib, ranking, rank.score)); ranking++; } return list; } public static async Task BroadcastToAllClients(ClientToGame message) { var target_clients = new List(); var users = GameServerApp.getServerLogic().getPlayerManager().getUsers(); foreach (var user in users) { target_clients.Add(user.Value.getHostId()); } GameServerApp.getServerLogic().onSendPacketToHosts(target_clients.ToArray(), RmiContext.ReliableSend, message); return await Task.FromResult(new Result()); } public static async Task BroadcastToAllServers(ServerMessage message, bool except_me) { var server_logic = GameServerApp.getServerLogic(); var rabbit_mq = server_logic.getRabbitMqConnector() as RabbitMqConnector; NullReferenceCheckHelper.throwIfNull(rabbit_mq, () => $"rabbit_mq is null !!!"); (var result, var server_infos) = await server_logic.getServerInfoAll(); foreach (var server in server_infos) { if (except_me && server.Name == server_logic.getServerName()) continue; rabbit_mq.SendMessage(server.Name, message); } return await Task.FromResult(new Result()); } private static async Task getUgcNpcFromMetaGuid(string ownerGuid, string ugcNpcMetaGuid) { var dynamo_db_client = GameServerApp.getServerLogic().getDynamoDbClient(); // ugcNpcMeta 정보 획득 var ugc_npc_doc = new UgcNpcDoc(OwnerEntityType.User, ownerGuid, ugcNpcMetaGuid); var ugc_npc_query_config = dynamo_db_client.makeQueryConfigForReadByPKSK(ugc_npc_doc.getPK(), ugc_npc_doc.getSK()); var (result, docs) = await dynamo_db_client.simpleQueryDocTypesWithQueryOperationConfig(ugc_npc_query_config); if (result.isFail() || docs.Count <= 0) { var err_msg = $"Failed to find UgcNpc. OwnerGuid: {ownerGuid} / NpcGuid : {ugcNpcMetaGuid}"; result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg); Log.getLogger().error(result.toBasicString()); return null; } return docs[0].getAttrib(); } private static async Task makeUgcNpcAttribToUgcNpcRank(UgcNpcAttrib docAttrib, int ranking, long score) { var rank = new UgcNpcRank(); rank.Rank = ranking; rank.Score = (int)score; rank.Title = docAttrib.Title; rank.NpcNickname = docAttrib.Nickname; rank.UgcNpcMetaGuid = docAttrib.UgcNpcMetaGuid; rank.OwnerUserGuid = docAttrib.OwnerGuid; rank.BodyItemMetaId = (int)docAttrib.BodyItemMetaId; var (result, nickname_doc_attrib) = await NicknameDoc.findNicknameFromGuid(rank.OwnerUserGuid); if (result.isFail() || nickname_doc_attrib == null) rank.OwnerUserNickname = string.Empty; else rank.OwnerUserNickname = nickname_doc_attrib.Nickname; return rank; } public static async Task updateUgcNpcRank(UgcNpcRankState state, UgcNpcRankType type, string guid, int delta, DateTime? rankDate) { var dynamo_client = GameServerApp.getServerLogic().getDynamoDbClient(); var rank_date = rankDate?.ToString("yyyy-MM-dd"); var doc = new UgcNpcRankDoc(state, type, rank_date); var primary_key = doc.getPrimaryKey(); primary_key.fillUpPrimaryKey(doc.getPK(), doc.getSK()); // data 변경 var update = makeUpdateItemRequestForUgcNpcRank( dynamo_client , primary_key.toKeyWithAttributeValue(), nameof(UgcNpcRankAttrib.ranks), guid, delta); NullReferenceCheckHelper.throwIfNull(update, () => $"update is null !!!"); var request = update.Item2; NullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!!"); var (result, _) = await dynamo_client.simpleQueryDocTypesWithUpdateItemRequest(request, Guid.NewGuid().ToString("N")); return result; } private static (Result, UpdateItemRequest?) makeUpdateItemRequestForUgcNpcRank( DynamoDbClient dbClient , Dictionary attributeValueWithPrimaryKey , string targetAttribName , string guid , double deltaCount ) { var result = new Result(); var table = dbClient.getTableByName(ServerBase.DynamoDbDefine.TableNames.Main); var query_builder = new DynamoDbItemRequestHelper.UpdateItemRequestBuilder(table.TableName); query_builder.withKeys(attributeValueWithPrimaryKey); var target_doc = new UgcNpcRankDoc(); var attrib_path_json_string = target_doc.toJsonStringOfAttribs(); var target_key = JsonHelper.getJsonPropertyName(targetAttribName); (var is_success, var attribute_expression) = DynamoDbClientHelper.toAttributeExpressionFromJson(attrib_path_json_string, target_key); if (false == is_success) { var err_msg = $"Failed to DynamoDbClientHelper.toAttributeExpressionFromJson() !!! : attribPath:{attrib_path_json_string}, targetKey:{target_key}"; result.setFail(ServerErrorCode.AttribPathMakeFailed, err_msg); Log.getLogger().error(result.toBasicString()); return (result, null); } var attributeNames = DynamoDbClientHelper.toExpressionAttributeNamesFromJson(attrib_path_json_string, target_key); attributeNames.Add($"#{guid}", guid); query_builder.withExpressionAttributeNames(attributeNames); attribute_expression += $".#{guid}"; var update_expression = (deltaCount >= 0) ? $"SET {attribute_expression} = if_not_exists({attribute_expression}, :start) + :changeValue" : $"SET {attribute_expression} = if_not_exists({attribute_expression}, :start) - :changeValue"; query_builder.withUpdateExpression(update_expression); var expression_attribute_values = new Dictionary { { ":changeValue", new AttributeValue { N = Math.Abs(deltaCount).ToString() } }, { ":start", new AttributeValue { N = "0" } } }; query_builder.withExpressionAttributeValues(expression_attribute_values); query_builder.withReturnValues(ReturnValue.ALL_NEW); return query_builder.build(); } }