365 lines
13 KiB
C#
365 lines
13 KiB
C#
using System.Collections.Concurrent;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using GameServer.Contents.Battle.Tickers;
|
|
using GameServer.Contents.GameMode.Mode_Battle.Manage;
|
|
using Google.Protobuf.WellKnownTypes;
|
|
|
|
using NeoSmart.AsyncLock;
|
|
using Newtonsoft.Json;
|
|
|
|
|
|
|
|
using ServerCore;
|
|
using ServerBase;
|
|
using ServerCommon;
|
|
using Constant = System.Reflection.Metadata.Constant;
|
|
|
|
|
|
namespace GameServer;
|
|
|
|
public class BattleInstanceManager : Singleton<BattleInstanceManager>
|
|
{
|
|
private AsyncLock m_lock_init = new();
|
|
//private ConcurrentDictionary<string, BattleInstanceRoom> m_battle_instances = new(); //인스턴스 생성 삭제를 주로 관리 하기 위한 Dictionary ... 아...이거 구조 별론데,....
|
|
|
|
private ConcurrentDictionary<Int32 /*event_id*/, SystemBattleEvent> m_battle_events = new();
|
|
|
|
public async Task onInit()
|
|
{
|
|
//1. 이벤트 관리하는 Task 추가
|
|
var result = await createBattleEventCheckerTask();
|
|
|
|
}
|
|
|
|
public async Task tryLeaveBattelInstance(Player player, string instanceRoomId)
|
|
{
|
|
Log.getLogger().debug($"tryLeaveBattelInstance start instanceRoomId : {instanceRoomId}");
|
|
|
|
var location_attribute = player.getEntityAttribute<LocationAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(location_attribute, () => $"location attribute is null !!! - {player.toBasicString()}");
|
|
|
|
//var instanceRoomId = location_attribute.CurrentIndunLocation.InstanceRoomId;
|
|
if (instanceRoomId == string.Empty)
|
|
{
|
|
Log.getLogger().warn($"tryLeaveBattelInstance IntanceRoomId is Empty");
|
|
return;
|
|
}
|
|
|
|
if (false == GameModeManager.It.tryGetGameMode(instanceRoomId, out var gameMode))
|
|
{
|
|
return;
|
|
}
|
|
|
|
var ffa = gameMode as GameModeTPSFreeForAll<GameModeTPSFreeForAllData>;
|
|
NullReferenceCheckHelper.throwIfNull(ffa, () => $"ffa is null !!! - {player.toBasicString()}");
|
|
|
|
await ffa.removePodCombat(player);
|
|
|
|
var host_user_guid = ffa.m_host_migrator.getHostUserGuid();
|
|
if (player.getUserGuid().Equals(host_user_guid))
|
|
{
|
|
using (var releaser = await ffa.getAsyncLock())
|
|
{
|
|
ffa.m_host_migrator.removeHost();
|
|
}
|
|
}
|
|
|
|
|
|
//여기서 instanceroom 이 is Destroy 면 DestroyBattleRoom 호출 해줄것
|
|
if (ffa.getInstanceRoom().isDestroy)
|
|
{
|
|
//kihoon todo : 이부분 수정 필요
|
|
//m_battle_instances.TryRemove(instanceRoomId, out var _);
|
|
//await battleInstanceRoom.destroyBattleRoom();
|
|
Log.getLogger().debug($"tryLeaveBattelInstance destroy battle room instanceRoomId : {instanceRoomId}");
|
|
}
|
|
}
|
|
|
|
// public async Task tryDestroyBattleRoom(string instanceRoomId)
|
|
// {
|
|
// await Task.CompletedTask;
|
|
// if (false == instanceRoomId.Contains(BattleConstant.PREFIX_BATTLE_INSTANCE_ROOM_ID)) return;
|
|
//
|
|
// // if (false == m_battle_instances.TryGetValue(instanceRoomId, out var battleInstanceRoom))
|
|
// // {
|
|
// // Log.getLogger().error($"instanceRoomId : {instanceRoomId} is not exist instnaces");
|
|
// // return;
|
|
// // }
|
|
//
|
|
// // var is_destroy = battleInstanceRoom.m_instance_room.isDestroy;
|
|
// // if (is_destroy)
|
|
// // {
|
|
// // await battleInstanceRoom.destroyBattleRoom();
|
|
// // //m_battle_instances.TryRemove(instanceRoomId, out _);
|
|
// // }
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
public async Task<bool> LeaveBattleRoom(Player player, string instanceRoomId, bool disconnected = false)
|
|
{
|
|
(var result, var leeave_handler) = GameModeHelper.getGameModeLeaveHandler(player, instanceRoomId);
|
|
if (result.isFail() || leeave_handler is null) return false;
|
|
|
|
await leeave_handler.gameModeLeave();
|
|
Log.getLogger().debug($"leave battle room player : {player.toBasicString()}, instanceRoomId : {instanceRoomId}");
|
|
|
|
return true;
|
|
}
|
|
|
|
public async Task<Result> sendNtfAboutBattleInstance(GameModeTPSFreeForAll<GameModeTPSFreeForAllData> battieInstanceRoom, Player player)
|
|
{
|
|
var result = new Result();
|
|
|
|
BattleRoomNotifyHelper.send_GS2C_NTF_BATTLE_INSTANCE_STATE(battieInstanceRoom, player);
|
|
BattleRoomNotifyHelper.send_GS2C_NTF_POD_COMBAT_STATE(battieInstanceRoom, player);
|
|
sendNtfBattleObjectsState(battieInstanceRoom, player);
|
|
|
|
var host_user_guid = battieInstanceRoom.m_host_migrator.getHostUserGuid();
|
|
if (!host_user_guid.Equals(string.Empty))
|
|
{
|
|
BattleRoomNotifyHelper.send_GS2C_NTF_P2P_HOST_UPDATE(player, host_user_guid);
|
|
}
|
|
|
|
await Task.CompletedTask;
|
|
return result;
|
|
}
|
|
|
|
|
|
private void sendNtfBattleObjectsState(GameModeTPSFreeForAll<GameModeTPSFreeForAllData> battleInstanceRoom, Player player)
|
|
{
|
|
List<BattleObjectInfo> infos = new();
|
|
var attribute = battleInstanceRoom.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
|
|
|
var now = DateTimeHelper.Current;
|
|
|
|
foreach (var weapon in attribute.m_combat_pod_mode.m_weapons.Values)
|
|
{
|
|
BattleObjectInfo info = new();
|
|
info.AnchorGuid = weapon.m_anchor_guid;
|
|
info.IsActive = weapon.m_active_time <= now ? BoolType.True : BoolType.False;
|
|
infos.Add(info);
|
|
}
|
|
|
|
foreach (var buff in attribute.m_combat_pod_mode.m_buffs.Values)
|
|
{
|
|
BattleObjectInfo info = new();
|
|
info.AnchorGuid = buff.m_anchor_guid;
|
|
info.IsActive = buff.m_active_time <= now ? BoolType.True : BoolType.False;
|
|
infos.Add(info);
|
|
}
|
|
|
|
foreach (BattleObjectPodStorage storage in attribute.m_combat_pod_mode.m_pod_storages.Values)
|
|
{
|
|
//storage.m_is_active = true;
|
|
BattleObjectInfo info = new();
|
|
info.AnchorGuid = storage.m_anchor_guid;
|
|
info.IsActive = storage.m_is_active ? BoolType.True : BoolType.False;
|
|
infos.Add(info);
|
|
}
|
|
|
|
foreach (BattleObjectPickupPod pickup in attribute.m_combat_pod_mode.m_pickup_pods.Values)
|
|
{
|
|
BattleObjectInfo info = new();
|
|
info.AnchorGuid = pickup.m_anchor_guid;
|
|
info.IsActive = pickup.m_is_active ? BoolType.True : BoolType.False;
|
|
infos.Add(info);
|
|
Log.getLogger().info($"pickup pod info anchor_guid : {info.AnchorGuid}, is Active : {info.IsActive}");
|
|
}
|
|
|
|
BattleRoomNotifyHelper.send_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(infos, player);
|
|
}
|
|
|
|
public bool isBattleInstance(Player player)
|
|
{
|
|
var location_action = player.getEntityAction<LocationAction>();
|
|
NullReferenceCheckHelper.throwIfNull(location_action, () => $"location_action is null !!! - {player.toBasicString()}");
|
|
|
|
var current_indun_location = location_action.getCurrentLocation() as IndunLocation;
|
|
NullReferenceCheckHelper.throwIfNull(current_indun_location, () => $"current_indun_location is null !!! - {player.toBasicString()}");
|
|
|
|
var instance_room_Id = current_indun_location.InstanceRoomId;
|
|
if (instance_room_Id == string.Empty) return false;
|
|
|
|
Log.getLogger().debug($"is Battle Instance check : instance room id : {instance_room_Id}");
|
|
if (instance_room_Id.Contains("battle_instance"))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
//result.setFail(ServerErrorCode.BattleInstnaceNotUsedPacket, "");
|
|
|
|
}
|
|
|
|
|
|
public List<BattleEventInfo> getAllProtoBattleEvents()
|
|
{
|
|
List<BattleEventInfo> infos = new();
|
|
foreach(var system_battle_event in m_battle_events.Values.ToList())
|
|
{
|
|
BattleEventInfo battle_event_info = new();
|
|
|
|
battle_event_info.EventId = system_battle_event.m_event_id;
|
|
battle_event_info.InstanceId = system_battle_event.m_instance_id;
|
|
battle_event_info.StartTime = Timestamp.FromDateTime(system_battle_event.m_start_time);
|
|
battle_event_info.ConfigDataId = system_battle_event.m_ffa_config_data_id;
|
|
battle_event_info.RewardGroupId = system_battle_event.m_ffa_reward_group_id;
|
|
battle_event_info.HotTime = system_battle_event.m_ffa_hot_time;
|
|
battle_event_info.RoundCount = system_battle_event.m_round_count;
|
|
infos.Add(battle_event_info);
|
|
}
|
|
|
|
return infos;
|
|
}
|
|
|
|
public BattleEventInfo makeProtoBattleEvent(SystemBattleEvent battleEvent)
|
|
{
|
|
BattleEventInfo battle_event_info = new();
|
|
|
|
battle_event_info.EventId = battleEvent.m_event_id;
|
|
battle_event_info.InstanceId = battleEvent.m_instance_id;
|
|
battle_event_info.StartTime = Timestamp.FromDateTime(battleEvent.m_start_time);
|
|
battle_event_info.ConfigDataId = battleEvent.m_ffa_config_data_id;
|
|
battle_event_info.RewardGroupId = battleEvent.m_ffa_reward_group_id;
|
|
battle_event_info.HotTime = battleEvent.m_ffa_hot_time;
|
|
battle_event_info.RoundCount = battleEvent.m_round_count;
|
|
|
|
return battle_event_info;
|
|
}
|
|
|
|
// public async Task setBattleEventAttribs(List<BattleEventAttrib> battleEventAttribs)
|
|
// {
|
|
// using (await m_lock_data_load.LockAsync())
|
|
// {
|
|
// m_battle_event_attribs.Clear();
|
|
// m_battle_event_attribs = battleEventAttribs;
|
|
// }
|
|
//
|
|
// }
|
|
|
|
|
|
// public async Task<List<BattleEventAttrib>> copyBattleEventAttribs()
|
|
// {
|
|
// List<BattleEventAttrib> attribs = new();
|
|
// using (await m_lock_data_load.LockAsync())
|
|
// {
|
|
// foreach (var attrib in m_battle_event_attribs)
|
|
// {
|
|
// attribs.Add(attrib.clone());
|
|
// }
|
|
// }
|
|
//
|
|
// return attribs;
|
|
// }
|
|
|
|
|
|
public ConcurrentDictionary<Int32 /*event_id*/, SystemBattleEvent> getSystemBattleEvents()
|
|
{
|
|
return m_battle_events;
|
|
}
|
|
|
|
public bool getSystemBattleEvent(Int32 eventId, [MaybeNullWhen(false)]out SystemBattleEvent battleEvent)
|
|
{
|
|
if (false == m_battle_events.TryGetValue(eventId, out battleEvent))
|
|
{
|
|
Log.getLogger($"Not exsist Battle event !!! eventId : {eventId}");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public void removeSystemBattleEvents(List<Int32> events)
|
|
{
|
|
foreach (var event_id in events)
|
|
{
|
|
if (false == m_battle_events.TryRemove(event_id, out var ev))
|
|
{
|
|
Log.getLogger().warn($"remove battle event fali event_id : {event_id}");
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool existSystemBattleEvent(Int32 eventId)
|
|
{
|
|
return m_battle_events.ContainsKey(eventId);
|
|
}
|
|
|
|
public void logSystemBattleEvents()
|
|
{
|
|
Log.getLogger().info($"updated system battle events : {JsonConvert.SerializeObject(m_battle_events)}");
|
|
}
|
|
|
|
public void setSystemBattleEvents(ConcurrentDictionary<Int32 /*event_id*/, SystemBattleEvent> newEvents)
|
|
{
|
|
m_battle_events = newEvents;
|
|
}
|
|
|
|
public bool addNewSystemBattleEvent(SystemBattleEvent ev, bool needErrroLog)
|
|
{
|
|
if (false == m_battle_events.TryAdd(ev.m_event_id, ev))
|
|
{
|
|
if (needErrroLog)
|
|
{
|
|
Log.getLogger().error($"System battle Event try Add Fail, eventId : {ev.m_event_id}, events : {JsonConvert.SerializeObject(m_battle_events)}");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private async Task<Result> createBattleEventCheckerTask()
|
|
{
|
|
|
|
var result = new Result();
|
|
|
|
var battle_entity_ticker_initializers = new Initializers();
|
|
|
|
//채널 인던 다 필요한가?
|
|
//이벤트 인스턴스 관련 생성 삭제에 대한 관리 Ticker
|
|
|
|
//battle_entity_ticker_initializers.appendInitializer(new BattleEventCheckTicker(1000, null));
|
|
//battle_entity_ticker_initializers.appendInitializer(new BattleEventNotifyTicker(Constant.EVENT_UPDATE_INTERVAL_MMIN, null));
|
|
|
|
result = await battle_entity_ticker_initializers.init("BattleEntityTickers");
|
|
if (result.isFail())
|
|
{
|
|
Log.getLogger().error($"Failed to init() !!! : {result.toBasicString()}");
|
|
return result;
|
|
}
|
|
|
|
var battle_event_check_ticker = new BattleEventCheckTicker(BattleConstant.BATTLE_EVENT_CHECK_INTERVAL, null);
|
|
await battle_event_check_ticker.onInit();
|
|
await createTask(battle_event_check_ticker);
|
|
var battle_event_notify_ticker = new BattleEventNotifyTicker(ServerCommon.Constant.EVENT_UPDATE_INTERVAL_MMIN, null);
|
|
await battle_event_check_ticker.onInit();
|
|
await createTask(battle_event_notify_ticker);
|
|
|
|
return result;
|
|
}
|
|
|
|
private async Task<Result> createTask(EntityTicker ticker)
|
|
{
|
|
var result = new Result();
|
|
|
|
await Task.CompletedTask;
|
|
try
|
|
{
|
|
|
|
new PeriodicTaskTimer( ticker.getTypeName() , ticker.getOnTickIntervalMilliseconds(), ticker.getCancelToken(), ticker.onTaskTick);
|
|
Log.getLogger().debug("createTask done");
|
|
}
|
|
catch(Exception e)
|
|
{
|
|
var err_msg = $"Exception !!!, new PeriodicTaskTimer() : exception:{e}";
|
|
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
|
return result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
} |