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 BattleInstanceRoomHandler { private string m_user_guid = string.Empty; private InstanceMetaData m_instance_meta_data = new(new InstanceMetaDataMutable()); public BattleInstanceRoomHandler(string userGuid, InstanceMetaData instanceMetaData) { m_user_guid = userGuid; m_instance_meta_data = instanceMetaData; } public async Task<(Result, string)> joinBattleInstance(string userGuid, Int32 eventId, Timestamp eventStartTS, Int32 instanceMetaId) //BattleInstanceType battleInstanceType { var result = new Result(); var err_msg = string.Empty; var server_logic = GameServerApp.getServerLogic(); var instance_room_storage = new InstanceRoomStorage(); instance_room_storage.Init(server_logic.getRedisDb(), ""); var instance_room_id = string.Empty; (result, instance_room_id) = await joinBattleInstanceRoom(userGuid, eventId, eventStartTS); if (result.isFail()) { err_msg = $"Failed to joinInstanceRoom() !!! : {result.toBasicString()}"; Log.getLogger().error(err_msg); return (result, string.Empty); } return (result, instance_room_id); } public async Task<(Result, string)> joinBattleInstanceRoom(string userGuid, Int32 eventId, Timestamp eventStartTS) { var result = new Result(); string err_msg; var server_logic = GameServerApp.getServerLogic(); var instance_room_storage = new InstanceRoomStorage(); instance_room_storage.Init(server_logic.getRedisDb(), ""); long timestampInSeconds = eventStartTS.Seconds; //long start_seqs_num = timestampInSeconds / 100; //방의 시퀀스번호를 정하는 시작 번호 int start_seqs_num = 1; //방의 시퀀스번호를 정하는 시작 번호 //인스턴스 이름 base로 들어가는 문자열 생성 var instance_room_id_base = makeBattleInstanceRoomIdBase(eventId, timestampInSeconds, m_instance_meta_data.Id); var instance_room_id = string.Empty; //1.전체 roomList,와 스코어를 먼저 가져온다. var battle_instance_room_storage = new BattleInstanceRoomStorage(); battle_instance_room_storage.Init(server_logic.getRedisDb(), ""); (result, var total_room_list) = await battle_instance_room_storage.getBattleInstanceTotalRoomListWithScore(instance_room_id_base, m_instance_meta_data.LimitCount); if (result.isFail() || total_room_list == null) { return (result, string.Empty); } var ordered_available_room = await battle_instance_room_storage.getBattleInstanceRoomList(instance_room_id_base, m_instance_meta_data.LimitCount); var total_room_length = total_room_list.Length; Log.getLogger().info($"join battle instance.. room capacity state.. " + $"totalroomlist : {JsonConvert.SerializeObject(total_room_list)}, available room : {JsonConvert.SerializeObject(ordered_available_room)}"); //total_room_list가 없고 비어있는 방도 없으면, 신규 생성 if(total_room_length == 0 && ordered_available_room.Count == 0) { (result, instance_room_id) = await createAndJoinBattleInstance(instance_room_id_base, start_seqs_num, userGuid); if (result.isFail()) return (result, instance_room_id); Log.getLogger().info($"join battle instance..make new first room instance_room_id : {instance_room_id}"); } //기존 방은 있으나 지금 입장 가능한 방이 없는경우 모든 방이 풀방이므로 비어있는 시퀀스 찾아서 방생성 else if (total_room_length > 0 && ordered_available_room.Count == 0) { //total_room_list 에서 생성되어 있는 roomSeq를 확인한다. HashSet using_room_seqs = new(); foreach (var room_entry in total_room_list) { var room_id = room_entry.Element.ToString(); var room_element = room_id.Split(":"); if (false == int.TryParse(room_element[^1], out var seq)) { err_msg = $"Failed to try parse room_element !!! room_id : {room_id}"; Log.getLogger().error(err_msg); result.setFail(ServerErrorCode.BattleInstanceSeqParseError, err_msg); return (result, string.Empty); } using_room_seqs.Add(seq); } var not_using_seq = findNotUsingSeqNum(using_room_seqs, start_seqs_num); (result, instance_room_id) = await createAndJoinBattleInstance(instance_room_id_base, not_using_seq, userGuid); if (result.isFail()) return (result, instance_room_id); Log.getLogger().info($"join battle instance..make new another room instance_room_id : {instance_room_id}"); } //비어 있는 방이 있는 경우 else if(ordered_available_room.Count > 0) { //빈방이 있는 경우 로직 처리 foreach (var room_id in ordered_available_room) { var instance_room_Info = await instance_room_storage.GetInstanceRoomInfo(room_id); if (instance_room_Info == null) { await InstanceRoomHandler.deleteInstanceRoom(room_id); continue; } result = await joinBattleInstanceRoomFromRedis(userGuid, room_id, instance_room_id_base); if (result.isSuccess()) { instance_room_id = room_id; break; } } Log.getLogger().info($"join battle instance..join exists room instance_room_id : {instance_room_id}"); } if (instance_room_id == string.Empty) { var new_seq = total_room_length + 1; //위 로직을 전부 태웠는데도 방이 안만들어졌으면 전체 방수 + 1해서 만든다... Log.getLogger().warn($"instance room id is still empty... so make new instance instance_room_id_base : {instance_room_id_base}, new_seq : {new_seq}"); (result, instance_room_id) = await createAndJoinBattleInstance(instance_room_id_base, new_seq, userGuid); } return (result, instance_room_id); } private async Task<(Result, string)> createAndJoinBattleInstance(string instanceRoomIdBase, int seq, string userGuid) { string err_msg = string.Empty; (var result, var instance_room_id) = await createBattleInstanceRoomFromRedis(instanceRoomIdBase, m_instance_meta_data.Id, seq); if (result.isFail()) { err_msg = $"Failed to createInstanceRoomFromRedis() !!! : {result.toBasicString()} - userGuid:{userGuid}"; Log.getLogger().error(err_msg); return (result, string.Empty); } result = await joinBattleInstanceRoomFromRedis(userGuid, instance_room_id, instanceRoomIdBase); if (result.isFail()) { err_msg = $"Failed to joinInstanceRoomFromRedis() !!! : {result.toBasicString()}"; Log.getLogger().error(err_msg); return (result, string.Empty); } Log.getLogger().info($"create and join battle instance instanceRoomIdBase : {instanceRoomIdBase}, seq : {seq}, userGuid : {userGuid}"); return (result, instance_room_id); } private int findNotUsingSeqNum(HashSet usingRoomSeqs, int startSeqNum) { var loop_count = usingRoomSeqs.Count + 1; var start_seq = startSeqNum; for (int i = 1; i <= loop_count; i++) { if (usingRoomSeqs.Contains(start_seq)) { start_seq++; continue; } return start_seq; } return start_seq; } public async Task<(Result, string)> createBattleInstanceRoomFromRedis(string instanceRoomIdBase, int instanceMetaId, int startSeqsNum) { var result = new Result(); var err_msg = string.Empty; var server_logic = GameServerApp.getServerLogic(); var instance_room_storage = new InstanceRoomStorage(); instance_room_storage.Init(server_logic.getRedisDb(), ""); (result, var instance_server_info) = await InstanceRoomHandler.getBestInstanceServerForCreateInstance(m_instance_meta_data.LimitCount); if (result.isFail() || instance_server_info == null) { err_msg = $"Failed to getBestInstanceServerForCreateInstance() !!! : {result.toBasicString()}"; Log.getLogger().error(err_msg); return (result, string.Empty); } if (instance_server_info.Address == string.Empty || instance_server_info.Port == 0) { err_msg = $"ServerInfo is invalid !!! Address:{instance_server_info.Address}, Port:{instance_server_info.Port}"; result.setFail(ServerErrorCode.ValidServerNotFound, err_msg); Log.getLogger().error(result.toBasicString()); return (result, string.Empty); } var instance_room_id = makeBattleInstanceRoomId(instanceRoomIdBase, startSeqsNum); (result, var is_created) = await instance_room_storage.createInstanceRoom(instance_room_id, instance_server_info.Address, instance_server_info.Port, instanceMetaId); if (result.isFail()) { err_msg = $"Failed to createInstanceRoom() !!! : {result.toBasicString()}"; Log.getLogger().error(err_msg); return (result, string.Empty); } if (is_created) { var battle_instance_room_storage = new BattleInstanceRoomStorage(); battle_instance_room_storage.Init(server_logic.getRedisDb(), ""); result = await battle_instance_room_storage.addBattleInstanceRoomList(instanceRoomIdBase, instance_room_id); if (result.isFail()) { err_msg = $"Failed to addInstanceRoomList() !!! : {result.toBasicString()}"; Log.getLogger().error(err_msg); return (result, string.Empty); } } return (result, instance_room_id); } public static string makeBattleInstanceRoomIdBase(Int32 eventId, long timestampInSeconds, Int32 instanceId) { if (eventId == 0) { return $"{BattleConstant.PREFIX_BATTLE_INSTANCE_ROOM_ID}:{eventId}_1234567890_{instanceId}"; } return $"{BattleConstant.PREFIX_BATTLE_INSTANCE_ROOM_ID}:{eventId}_{timestampInSeconds}_{instanceId}"; } static string makeBattleInstanceRoomId(string instanceRoomIdBase, int startSeqsNum) { //var server_logic = GameServerApp.getServerLogic(); //var instance_room_storage = new InstanceRoomStorage(); // instance_room_storage.Init(server_logic.getRedisDb(), ""); // var room_id_seq = await instance_room_storage.getRoomIdSeq(); // if (room_id_seq == 0) // return string.Empty; return $"{instanceRoomIdBase}:{startSeqsNum}"; } // async Task<(Result, string)> joinBattleInstanceRoom(string userGuid, BattleInstanceType instanceType, int instanceMetaId) // { // var result = new Result(); // string err_msg; // // var server_logic = GameServerApp.getServerLogic(); // // var battle_instance_room_storage = new BattleInstanceRoomStorage(); // battle_instance_room_storage.Init(server_logic.getRedisDb(), ""); // // if (!MetaData.Instance._IndunTable.TryGetValue(instanceMetaId, out var instance_meta_data)) // { // err_msg = $"Failed to MetaData.TryGetValue() !!! : instanceMetaId:{instanceMetaId} - userGuid:{userGuid}"; // result.setFail(ServerErrorCode.InstanceMetaDataNotFound, err_msg); // Log.getLogger().error(result.toBasicString()); // // return (result, string.Empty); // } // var instance_room_id_base = makeBattleInstanceRoomIdBase(instanceType, instanceMetaId); // var instance_room_id = string.Empty; // // //인스턴스 정보가 redis에 없으면 roomlist에서 제거 처리 // var room_list = await instance_room_storage.GetInstanceRoomList(instance_room_id_base, instance_meta_data.LimitCount); // foreach (var room_id in room_list) // { // var instance_room_Info = await instance_room_storage.GetInstanceRoomInfo(room_id); // if (instance_room_Info == null) // { // await InstanceRoomHandler.deleteInstanceRoom(room_id); // continue; // } // // result = await joinBattleInstanceRoomFromRedis(userGuid, room_id, instanceMetaId, instance_room_id_base, instance_room_Info.UgcNpcCount); // if (result.isSuccess()) // { // instance_room_id = room_id; // break; // } // } // // if (instance_room_id == string.Empty) // { // (result, instance_room_id) = await createBattleInstanceRoomFromRedis(instance_room_id_base, instanceMetaId); // if (result.isFail()) // { // err_msg = $"Failed to createInstanceRoomFromRedis() !!! : {result.toBasicString()} - userGuid:{userGuid}"; // Log.getLogger().error(err_msg); // // return (result, string.Empty); // } // // result = await joinBattleInstanceRoomFromRedis(userGuid, instance_room_id, instanceMetaId, instance_room_id_base, 0); // if (result.isFail()) // { // err_msg = $"Failed to joinInstanceRoomFromRedis() !!! : {result.toBasicString()}"; // Log.getLogger().error(err_msg); // // return (result, string.Empty); // } // } // // return (result, instance_room_id); // } public async Task joinBattleInstanceRoomFromRedis(string userGuid, string instanceRoomId, string instanceRoomIdBase) { var result = new Result(); var err_msg = string.Empty; var server_logic = GameServerApp.getServerLogic(); var instance_room_storage = new InstanceRoomStorage(); instance_room_storage.Init(server_logic.getRedisDb(), ""); result = await instance_room_storage.joinInstanceRoom(userGuid, instanceRoomId, m_instance_meta_data.LimitCount); if (result.isFail()) { err_msg = $"Failed to TryJoinInstanceRoom() !!! : {result.toBasicString()}"; Log.getLogger().debug(err_msg); return result; } result = await instance_room_storage.increaseInstanceRoomScore(instanceRoomIdBase, instanceRoomId); if (result.isFail()) { await instance_room_storage.leaveInstanceRoom(userGuid, instanceRoomId); err_msg = $"Failed to increaseInstanceRoomScore() !!! : {result.toBasicString()} - userGuid:{userGuid}"; Log.getLogger().debug(err_msg); return result; } return result; } public static async Task leaveBattleInstanceRoom(string userGuid, string instanceRoomId) { var result = new Result(); var err_msg = string.Empty; var server_logic = GameServerApp.getServerLogic(); var instance_room_storage = new InstanceRoomStorage(); instance_room_storage.Init(server_logic.getRedisDb(), ""); await instance_room_storage.leaveInstanceRoom(userGuid, instanceRoomId); var instance_room_id_base = getInstanceRoomIdBaseFromInstanceRoomId(instanceRoomId); await instance_room_storage.decreaseInstanceRoomScore(instance_room_id_base, instanceRoomId); return result; } public static string getInstanceRoomIdBaseFromInstanceRoomId(string instanceRoomId) { var instance_room_Id_element = instanceRoomId.Split(":"); if (instance_room_Id_element.Length >= 2) { return $"{instance_room_Id_element[0]}:{instance_room_Id_element[1]}"; } Log.getLogger().error($"Instance room id weired : {instanceRoomId}"); return string.Empty; } }