초기커밋
This commit is contained in:
71
GameServer/Contents/GameMode/Helper/GameModeHelper.cs
Normal file
71
GameServer/Contents/GameMode/Helper/GameModeHelper.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
public class GameModeHelper
|
||||
{
|
||||
public static (Result, IGameModeJoinHandler) getGameModeJoinHandler(InstanceRoom instanceRoom, EPlaceType placeType)
|
||||
{
|
||||
var result = new Result();
|
||||
switch (placeType)
|
||||
{
|
||||
case EPlaceType.BattleRoom:
|
||||
return (result, new BattleInstanceJoinHandler(instanceRoom));
|
||||
case EPlaceType.ArcadeRunning:
|
||||
return (result, new ArcadeRunningInstanceJoinHandler(instanceRoom));
|
||||
case EPlaceType.GameRoom:
|
||||
return (result, new GameRoomJoinHandler(instanceRoom));
|
||||
default:
|
||||
var err_msg = $"invalid placeType in this mode!!!! placeType : {placeType}";
|
||||
result.setFail(ServerErrorCode.GameModeJoinHandlerNotExist, err_msg);
|
||||
return (result, new BattleInstanceJoinHandler(instanceRoom));
|
||||
}
|
||||
}
|
||||
|
||||
public static (Result, IGameModeInitHandler) getGameModeInitHandler(InstanceRoom instanceRoom, EPlaceType placeType)
|
||||
{
|
||||
var result = new Result();
|
||||
switch (placeType)
|
||||
{
|
||||
case EPlaceType.BattleRoom:
|
||||
return (result, new BattleInstanceInitHandler(instanceRoom));
|
||||
case EPlaceType.ArcadeRunning:
|
||||
return (result, new ArcadeRunningInstanceInitHandler(instanceRoom));
|
||||
case EPlaceType.GameRoom:
|
||||
return (result, new GameRoomInitHandler(instanceRoom));
|
||||
default:
|
||||
var err_msg = $"getGameModeInitHandler not!!!! placeType : {placeType}";
|
||||
result.setFail(ServerErrorCode.GameModeInitHandlerNotExist, err_msg);
|
||||
return (result, new BattleInstanceInitHandler(instanceRoom));
|
||||
}
|
||||
}
|
||||
|
||||
public static (Result, IGameModeJoinSuccessHandler?) getGameModeJoinSuccessHandler(Player player, InstanceRoom instanceRoom, EPlaceType placeType)
|
||||
{
|
||||
var result = new Result();
|
||||
switch (placeType)
|
||||
{
|
||||
case EPlaceType.BattleRoom:
|
||||
return (result, new BattleInstanceJoinSuccessHandler(player, instanceRoom));
|
||||
case EPlaceType.ArcadeRunning:
|
||||
return (result, new ArcadeRunningInstanceJoinSuccessHandler(player, instanceRoom));
|
||||
case EPlaceType.GameRoom:
|
||||
return (result, new GameRoomJoinSuccessHandler(player, instanceRoom));
|
||||
default:
|
||||
var err_msg = $"getGameModeInitHandler not!!!! placeType : {placeType}";
|
||||
result.setFail(ServerErrorCode.GameModeJoinSuccessHandlerNotExist, err_msg);
|
||||
return (result, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
239
GameServer/Contents/GameMode/Helper/HostMigrationFactory.cs
Normal file
239
GameServer/Contents/GameMode/Helper/HostMigrationFactory.cs
Normal file
@@ -0,0 +1,239 @@
|
||||
using Nettention.Proud;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
public class HostMigrationFactory
|
||||
{
|
||||
public static IHostMigrator createCommonHostMigrator(int battleModeId, GameServerLogic gameServerLogic)
|
||||
{
|
||||
// battleModeId <- 게임 모드 ID 테이블 참조용
|
||||
// TODO: battleModeId를 사용하여 HostMigrationPolicy 생성하는 것으로 변경 예정
|
||||
int game_mode_option_data_id = 1;
|
||||
var host_migration_policy = createHostMigrationPolicyByMeta(game_mode_option_data_id);
|
||||
|
||||
var net_server = gameServerLogic.getProudNetListener().getNetServer();
|
||||
NullReferenceCheckHelper.throwIfNull(net_server, () => $"net_server is null !!!!");
|
||||
var host_migration_system = new HostMigrationSystem(net_server, host_migration_policy);
|
||||
var host_migrator = new CommonHostMigrator(host_migration_system, gameServerLogic);
|
||||
return host_migrator;
|
||||
}
|
||||
|
||||
private static HostMigrationPolicy createHostMigrationPolicyByMeta(int gameModeOptionDataId)
|
||||
{
|
||||
var meta = getMeta(gameModeOptionDataId);
|
||||
return new HostMigrationPolicy
|
||||
{
|
||||
HostKickFpsThreshold = meta.HostKickFpsThreshold,
|
||||
HostKickFpsDuration = TimeSpan.FromSeconds(meta.HostKickFpsDuration),
|
||||
HostKickPingThreshold = meta.HostKickPingThreshold,
|
||||
HostKickPingDuration = TimeSpan.FromSeconds(meta.HostKickPingDuration),
|
||||
};
|
||||
|
||||
GameModeOptionMetaData getMeta(int gameModeOptionDataId)
|
||||
{
|
||||
var game_mode_option_meta_table = MetaData.Instance.Meta.GameModeOptionMetaTable;
|
||||
game_mode_option_meta_table.GameModeOptionDataListbyGameModeOptionId.TryGetValue(gameModeOptionDataId,
|
||||
out var game_mode_option_meta);
|
||||
NullReferenceCheckHelper.throwIfNull(game_mode_option_meta, () => $"game_mode_option_meta is null !!!!");
|
||||
return game_mode_option_meta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CommonHostMigrator : IHostMigrator
|
||||
{
|
||||
private readonly HostMigrationSystem m_host_migration_system;
|
||||
private string m_host_user_guid = string.Empty;
|
||||
private readonly GameServerLogic m_game_server_logic;
|
||||
private DateTime m_last_loop_time = DateTime.MinValue;
|
||||
private readonly TimeSpan m_loop_interval = TimeSpan.FromSeconds(1);
|
||||
|
||||
public HostID SuperPeerHostId => m_host_migration_system.SuperPeerHostId;
|
||||
public HostMigrationSystem HostMigrationSystem => m_host_migration_system;
|
||||
|
||||
public CommonHostMigrator(HostMigrationSystem hostMigrationSystem, GameServerLogic gameServerLogic)
|
||||
{
|
||||
m_host_migration_system = hostMigrationSystem;
|
||||
m_game_server_logic = gameServerLogic;
|
||||
}
|
||||
|
||||
public (Result, bool) migrateCheck(bool ignoreInterval = false)
|
||||
{
|
||||
if (!ignoreInterval && isOnMigrationLoopInterval())
|
||||
{
|
||||
return (new Result(), false);
|
||||
}
|
||||
|
||||
var (is_migrated, new_super_peer_id) = m_host_migration_system.migrateCheck();
|
||||
if (is_migrated)
|
||||
{
|
||||
var (result, user_guid) = getUserGuidByHostId(new_super_peer_id);
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, is_migrated);
|
||||
}
|
||||
|
||||
var host_change_success = m_host_migration_system.changeSuperPeerHostId(new_super_peer_id);
|
||||
if (!host_change_success)
|
||||
{
|
||||
return (new Result
|
||||
{
|
||||
ErrorCode = ServerErrorCode.NotFoundUser, ResultString = "Failed to change super peer."
|
||||
}, is_migrated);
|
||||
}
|
||||
m_host_user_guid = user_guid;
|
||||
return (result, is_migrated);
|
||||
}
|
||||
return (new Result(), false);
|
||||
}
|
||||
|
||||
public void setGroupHostId(HostID groupId)
|
||||
{
|
||||
m_host_migration_system.setGroupHostId(groupId);
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 삭제 예정
|
||||
//=================================================================
|
||||
public Result defineHost(HostID p2pGroupId = HostID.HostID_None, SuperPeerSelectionPolicy policy = null!, HostID[] excludes = null!)
|
||||
{
|
||||
// m_host_migration_system.setGroupHostId(p2pGroupId);
|
||||
//
|
||||
// var (is_migrated, new_super_peer_id) = m_host_migration_system.migrateCheck();
|
||||
//
|
||||
// if (is_migrated)
|
||||
// {
|
||||
// var (result, user_guid) = getUserGuidByHostId(new_super_peer_id);
|
||||
// if (result.isFail())
|
||||
// {
|
||||
// return result;
|
||||
// }
|
||||
//
|
||||
// var host_change_success = m_host_migration_system.changeSuperPeerHostId(new_super_peer_id);
|
||||
// if (!host_change_success)
|
||||
// {
|
||||
// return new Result
|
||||
// {
|
||||
// ErrorCode = ServerErrorCode.NotFoundUser, ResultString = "Failed to change super peer."
|
||||
// };
|
||||
// }
|
||||
// m_host_user_guid = user_guid;
|
||||
// return result;
|
||||
// }
|
||||
return new Result();
|
||||
}
|
||||
|
||||
public Result modifyHost(string userGuid)
|
||||
{
|
||||
var (result, host_id) = getHostIdByUserGuid(userGuid);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (m_host_migration_system.changeSuperPeerHostId(host_id))
|
||||
{
|
||||
m_host_user_guid = userGuid;
|
||||
return result;
|
||||
}
|
||||
|
||||
return new Result { ErrorCode = ServerErrorCode.NotFoundUser, ResultString = "Failed to change super peer." };
|
||||
}
|
||||
|
||||
public Result removeHost()
|
||||
{
|
||||
m_host_migration_system.changeSuperPeerHostId(HostID.HostID_None);
|
||||
m_host_user_guid = string.Empty;
|
||||
return new Result();
|
||||
}
|
||||
|
||||
public string getHostUserGuid()
|
||||
{
|
||||
return m_host_user_guid;
|
||||
}
|
||||
|
||||
private (Result, string) getUserGuidByHostId(HostID hostId)
|
||||
{
|
||||
string err_msg;
|
||||
var result = new Result();
|
||||
if (hostId == HostID.HostID_None)
|
||||
{
|
||||
err_msg = $"there is not suitable super peer !!!! host_id : {hostId}";
|
||||
result.setFail(ServerErrorCode.NotFoundUser, err_msg);
|
||||
return (result, string.Empty);
|
||||
}
|
||||
|
||||
var session = m_game_server_logic.getProudNetListener().onLookupEntityWithSession((int)hostId);
|
||||
if (session is null)
|
||||
{
|
||||
err_msg = $"session is null!!!! host_id : {hostId}";
|
||||
result.setFail(ServerErrorCode.NotFoundUser, err_msg);
|
||||
return (result, string.Empty);
|
||||
}
|
||||
|
||||
var player = session as Player;
|
||||
if (player is null)
|
||||
{
|
||||
err_msg = $"player is null!!!! host_id : {hostId}";
|
||||
result.setFail(ServerErrorCode.NotFoundUser, err_msg);
|
||||
return (result, string.Empty);
|
||||
}
|
||||
|
||||
return (result, player.getUserGuid());
|
||||
}
|
||||
|
||||
private (Result, HostID) getHostIdByUserGuid(string userGuid)
|
||||
{
|
||||
string err_msg;
|
||||
var result = new Result();
|
||||
// todo: 임시 다른 방법 모색 - 비용이 비쌀 수 있음
|
||||
var session_pair = m_game_server_logic.getProudNetListener()
|
||||
.getEntityWithSessions()
|
||||
.FirstOrDefault(x => x.Value.getUserGuid() == userGuid);
|
||||
var session = session_pair.Value;
|
||||
if (session is null)
|
||||
{
|
||||
err_msg = $"session is null!!!! user_guid : {userGuid}";
|
||||
result.setFail(ServerErrorCode.NotFoundUser, err_msg);
|
||||
return (result, HostID.HostID_None);
|
||||
}
|
||||
|
||||
if (session is not Player player)
|
||||
{
|
||||
err_msg = $"player is null!!!! user_guid : {userGuid}";
|
||||
result.setFail(ServerErrorCode.NotFoundUser, err_msg);
|
||||
return (result, HostID.HostID_None);
|
||||
}
|
||||
|
||||
return (result, player.getHostId());
|
||||
}
|
||||
|
||||
|
||||
//=================================================================
|
||||
// 호스트 마이그레이션 루프 인터벌 중인지 여부
|
||||
//=================================================================
|
||||
private bool isOnMigrationLoopInterval()
|
||||
{
|
||||
if (m_last_loop_time == DateTime.MinValue)
|
||||
{
|
||||
m_last_loop_time = DateTime.UtcNow;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_last_loop_time.Add(m_loop_interval) < DateTime.UtcNow)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
m_last_loop_time = DateTime.UtcNow;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
522
GameServer/Contents/GameMode/Helper/HostMigrationSystem.cs
Normal file
522
GameServer/Contents/GameMode/Helper/HostMigrationSystem.cs
Normal file
@@ -0,0 +1,522 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using Nettention.Proud;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
//===================================================================
|
||||
// 호스트 마이그레이션 정책 - 기획서 기반
|
||||
//===================================================================
|
||||
public class HostMigrationPolicy
|
||||
{
|
||||
// 현재 호스트의 Ping이 너무 높을 경우, 호스트를 교체(마이그레이션)하기 위한 임계값(ms).
|
||||
public int HostKickPingThreshold { get; set; } = 500;
|
||||
|
||||
// PingKickThreshold를 초과한 상태가 몇 초(sec) 동안 지속되면 호스트 마이그레이션이 일어나는 지를 설정. 도중에 정상 복귀하면 타이머 리셋.
|
||||
public TimeSpan HostKickPingDuration { get; set; } = TimeSpan.FromSeconds(30);
|
||||
|
||||
// 호스트의 FPS가 이 값 이하면 마이그레이션 타이머 발동.
|
||||
public int HostKickFpsThreshold { get; set; } = 30;
|
||||
|
||||
// HostFpsThreshold를 초과한 상태가 몇 초(sec) 동안 지속되면 호스트 마이그레이션이 일어나는 지를 설정. 도중에 정상 복귀하면 타이머 리셋.
|
||||
public TimeSpan HostKickFpsDuration { get; set; } = TimeSpan.FromSeconds(30);
|
||||
|
||||
// 한 번 호스트 마이그레이션이 발생한 후, 다시 마이그레이션이 일어나기까지의 최소 대기 시간(쿨다운, min)으로 아예 응답이 없는 경우 쿨다운을 무시하고 즉시 호스트 마이그레이션 발동.
|
||||
public TimeSpan MigrationCooldown { get; set; } = TimeSpan.FromSeconds(60);
|
||||
|
||||
// 입장 후 호스트 변경 유예 시간 ms
|
||||
public long ExcludeNewJoineeDurationTimeMs { get; set; } = 0;
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// 호스트 마이그레이션 정책을 적용해서 호스트를 마이그레이션을 진행하는 클래스
|
||||
//===================================================================
|
||||
public class HostMigrationSystem
|
||||
{
|
||||
public enum MigrationStateType
|
||||
{
|
||||
None,
|
||||
Ping,
|
||||
Fps
|
||||
}
|
||||
|
||||
public class MigrationState
|
||||
{
|
||||
public enum CheckType
|
||||
{
|
||||
None,
|
||||
Greater,
|
||||
Less
|
||||
}
|
||||
|
||||
private readonly CheckType m_check_type;
|
||||
private readonly int m_policy_threshold_value = 0;
|
||||
private readonly TimeSpan m_policy_duration;
|
||||
|
||||
public MigrationState(MigrationStateType migrationStateType, CheckType checkType, int thresholdValue,
|
||||
TimeSpan duration)
|
||||
{
|
||||
m_check_type = checkType;
|
||||
m_policy_threshold_value = thresholdValue;
|
||||
m_policy_duration = duration;
|
||||
StateType = migrationStateType;
|
||||
reset();
|
||||
}
|
||||
|
||||
public MigrationStateType StateType { get; set; }
|
||||
|
||||
private DateTime m_trigger_time = DateTime.MinValue;
|
||||
|
||||
// public StateType State { get; set; } = StateType.None;
|
||||
private int m_sum;
|
||||
private int m_sum_count;
|
||||
|
||||
public void reset()
|
||||
{
|
||||
m_trigger_time = DateTime.MinValue;
|
||||
m_sum = 0;
|
||||
m_sum_count = 0;
|
||||
}
|
||||
|
||||
public bool isHostKicked()
|
||||
{
|
||||
if (m_sum_count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var value = (int)Math.Round((double)m_sum / m_sum_count);
|
||||
return shouldTrigger(value);
|
||||
}
|
||||
|
||||
public bool isHostKickDurationExceeded()
|
||||
{
|
||||
return isHostKickCheckTriggered() && DateTime.UtcNow > m_trigger_time.Add(m_policy_duration);
|
||||
}
|
||||
|
||||
|
||||
public void setTriggerTime(DateTime? triggerTime = null)
|
||||
{
|
||||
if (triggerTime == null)
|
||||
{
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (m_trigger_time == DateTime.MinValue)
|
||||
{
|
||||
m_trigger_time = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
|
||||
public void update(int value)
|
||||
{
|
||||
if (shouldTrigger(value))
|
||||
{
|
||||
setTriggerTime();
|
||||
}
|
||||
|
||||
// TriggerTime이 설정된 경우에만 Sum을 계산
|
||||
if (isHostKickCheckTriggered())
|
||||
{
|
||||
m_sum += value;
|
||||
m_sum_count++;
|
||||
}
|
||||
}
|
||||
|
||||
private bool isHostKickCheckTriggered()
|
||||
{
|
||||
return m_trigger_time != DateTime.MinValue;
|
||||
}
|
||||
|
||||
private bool shouldTrigger(int value)
|
||||
{
|
||||
return m_check_type switch
|
||||
{
|
||||
CheckType.Greater => value > m_policy_threshold_value,
|
||||
CheckType.Less => value < m_policy_threshold_value,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private readonly HostMigrationPolicy m_host_migration_policy;
|
||||
private readonly NetServer m_server;
|
||||
private HostID m_group_host_id = HostID.HostID_None;
|
||||
private HostID m_super_peer_host_id = HostID.HostID_None;
|
||||
private readonly List<MigrationState> m_migration_states;
|
||||
private DateTime m_last_migration_time = DateTime.MinValue;
|
||||
private bool m_ignore_migration_condition;
|
||||
|
||||
public HostMigrationPolicy HostMigrationPolicy => m_host_migration_policy;
|
||||
public HostID SuperPeerHostId => m_super_peer_host_id;
|
||||
public HostID GroupHostHostId => m_group_host_id;
|
||||
public NetClientInfo? CurrentSuperPeerInfo => m_server.GetClientInfo(m_super_peer_host_id);
|
||||
|
||||
// StartServerParameter.enablePingTest = true 옵션이 필요함
|
||||
public HostMigrationSystem(NetServer server, HostMigrationPolicy hostMigrationPolicy)
|
||||
{
|
||||
m_server = server;
|
||||
m_host_migration_policy = hostMigrationPolicy;
|
||||
m_migration_states =
|
||||
[
|
||||
new MigrationState(MigrationStateType.Fps, MigrationState.CheckType.Less,
|
||||
m_host_migration_policy.HostKickFpsThreshold,
|
||||
m_host_migration_policy.HostKickFpsDuration),
|
||||
new MigrationState(MigrationStateType.Ping, MigrationState.CheckType.Greater,
|
||||
m_host_migration_policy.HostKickPingThreshold,
|
||||
m_host_migration_policy.HostKickPingDuration)
|
||||
];
|
||||
|
||||
var proudnet_policy = SuperPeerSelectionPolicy.GetOrdinary();
|
||||
|
||||
// 클라이언트가 로딩하는 시간동안 프레임 측정이 정화하지 않을 수 있기 때문에 오차가 발생할 수 있음
|
||||
// 게임 시작 기준에 따라 설정이나 migrate() 호출 시점을 변경해야할 수 있음
|
||||
proudnet_policy.m_excludeNewJoineeDurationTimeMs = hostMigrationPolicy.ExcludeNewJoineeDurationTimeMs;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// P2P 그룹 아이디 설정 - 최초 한번만 설정됨
|
||||
//=================================================================
|
||||
public void setGroupHostId(HostID groupHostId)
|
||||
{
|
||||
if (m_group_host_id == HostID.HostID_None && groupHostId != HostID.HostID_None)
|
||||
{
|
||||
m_group_host_id = groupHostId;
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 현재 수퍼 피어 아이디 설정
|
||||
// - getMostSuitableSuperPeer() 호출 후
|
||||
// - 클라이언트에 호스트 변경 요청
|
||||
// - 클라이언트 응답을 받은 후, changeSuperPeerId() 호출
|
||||
//=================================================================
|
||||
public bool changeSuperPeerHostId(HostID superPeerId)
|
||||
{
|
||||
if (!isHostIdInP2PGroup(superPeerId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_super_peer_host_id = superPeerId;
|
||||
return true;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 호스트 변경 요청
|
||||
// migrate() 호출 시점에 따라 마이그레이션이 발생하지 않을 수 있음
|
||||
// migrate()가 처리되지 않아도 에러가 아니기 때문에 bool을 반환함
|
||||
//=================================================================
|
||||
public (bool, HostID) migrateCheck()
|
||||
{
|
||||
if (m_ignore_migration_condition)
|
||||
{
|
||||
return migrateCheckIgnoreCondition();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// P2P 그룹이 설정돼 있는 지 확인
|
||||
if (!isValidGroup())
|
||||
{
|
||||
return (false, m_super_peer_host_id);
|
||||
}
|
||||
|
||||
// 최초에 수퍼 피어가 설정되지 않은 경우
|
||||
var super_peer_id = m_super_peer_host_id;
|
||||
if (m_super_peer_host_id == HostID.HostID_None)
|
||||
{
|
||||
super_peer_id = m_server.GetMostSuitableSuperPeerInGroup(m_group_host_id);
|
||||
changeSuperPeerHostId(super_peer_id);
|
||||
return (true, super_peer_id);
|
||||
}
|
||||
|
||||
if (!isValidSuperPeer())
|
||||
{
|
||||
return (false, m_super_peer_host_id);
|
||||
}
|
||||
|
||||
// 설정 시간만큼 설정 시간 유지
|
||||
if (isOnMigrationCooldown())
|
||||
{
|
||||
return (false, m_super_peer_host_id);
|
||||
}
|
||||
|
||||
hostMigrationStateUpdate();
|
||||
|
||||
if (!isHostKickDurationExceeded())
|
||||
{
|
||||
return (false, m_super_peer_host_id);
|
||||
}
|
||||
|
||||
// 마이그레이션이 발생할 수 있는 조건인지 체크
|
||||
if (isHostKicked())
|
||||
{
|
||||
super_peer_id = findSuperPeer();
|
||||
}
|
||||
|
||||
resetMigrationState();
|
||||
|
||||
return (true, super_peer_id);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Log.getLogger().error($"HostMigrationSystem.migrateCheck => {e}");
|
||||
}
|
||||
return (false, m_super_peer_host_id);
|
||||
}
|
||||
|
||||
private void resetMigrationState()
|
||||
{
|
||||
foreach (var state in m_migration_states)
|
||||
{
|
||||
state.reset();
|
||||
}
|
||||
|
||||
m_last_migration_time = DateTime.MinValue;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 호스트 변경 요청 - 무조건
|
||||
//=================================================================
|
||||
public (bool, HostID) getMostSuitableSuperPeerIgnoreCondition()
|
||||
{
|
||||
// P2P 그룹이 설정돼 있는 지 확인
|
||||
if (!isValidGroup())
|
||||
{
|
||||
return (false, m_super_peer_host_id);
|
||||
}
|
||||
|
||||
// checkAndValidateSuperPeer();
|
||||
|
||||
// if (isValidSuperPeer())
|
||||
// {
|
||||
// // 설정 시간만큼 설정 시간 유지
|
||||
// if (isOnMigrationCooldown())
|
||||
// {
|
||||
// return (false, m_super_peer_id);
|
||||
// }
|
||||
//
|
||||
// // 마이그레이션이 발생할 수 있는 조건인지 체크
|
||||
// if (!isHostMigrateCondition())
|
||||
// {
|
||||
// return (false, m_super_peer_id);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// resetMigrationState();
|
||||
|
||||
var super_peer_id = m_server.GetMostSuitableSuperPeerInGroup(m_group_host_id);
|
||||
if (super_peer_id == m_super_peer_host_id)
|
||||
{
|
||||
return (false, m_super_peer_host_id);
|
||||
}
|
||||
|
||||
m_last_migration_time = DateTime.UtcNow;
|
||||
return (true, super_peer_id);
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 호스트 변경 요청
|
||||
// getMostSuitableSuperPeerAsync() 호출 시점에 따라 마이그레이션이 발생하지 않을 수 있음
|
||||
// getMostSuitableSuperPeerAsync()가 처리되지 않아도 에러가 아니기 때문에 bool을 반환함
|
||||
//=================================================================
|
||||
public async Task<(bool, HostID)> migrateCheckAsync()
|
||||
{
|
||||
return await Task.Run(migrateCheck);
|
||||
}
|
||||
|
||||
private (bool, HostID) migrateCheckIgnoreCondition()
|
||||
{
|
||||
try
|
||||
{
|
||||
// P2P 그룹이 설정돼 있는 지 확인
|
||||
if (!isValidGroup())
|
||||
{
|
||||
return (false, m_super_peer_host_id);
|
||||
}
|
||||
|
||||
var super_peer_id = findSuperPeer();
|
||||
resetMigrationState();
|
||||
return (true, super_peer_id);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Log.getLogger().error($"HostMigrationSystem.migrateCheckIgnoreCondition => {e}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_ignore_migration_condition = false;
|
||||
}
|
||||
return (true, m_super_peer_host_id);
|
||||
}
|
||||
|
||||
private void hostMigrationStateUpdate()
|
||||
{
|
||||
var info = m_server.GetClientInfo(m_super_peer_host_id);
|
||||
m_migration_states.ForEach(state =>
|
||||
{
|
||||
switch (state.StateType)
|
||||
{
|
||||
case MigrationStateType.Fps:
|
||||
state.update((int)info.recentFrameRate);
|
||||
break;
|
||||
case MigrationStateType.Ping:
|
||||
state.update(info.recentPingMs);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private bool isHostKicked()
|
||||
{
|
||||
return m_migration_states.Any(state => state.isHostKicked());
|
||||
}
|
||||
|
||||
private bool isHostKickDurationExceeded()
|
||||
{
|
||||
return m_migration_states.Any(state => state.isHostKickDurationExceeded());
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 호스트 변경 유예 조건 체크
|
||||
//=================================================================
|
||||
private bool isOnMigrationCooldown()
|
||||
{
|
||||
// 설정 시간 만큼 유지
|
||||
return m_last_migration_time.Add(m_host_migration_policy.MigrationCooldown) > DateTime.UtcNow;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 호스트 그룹이 삭제됐는 지 확인
|
||||
//=================================================================
|
||||
private bool isValidGroup()
|
||||
{
|
||||
// 호스트 그룹 아이디가 설정되지 않은 경우
|
||||
if (m_group_host_id == HostID.HostID_None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 호스트 그룹 아이디가 설정되어 있지만, P2P 그룹 정보가 없는 경우
|
||||
if (m_group_host_id != HostID.HostID_None && m_server.GetP2PGroupInfo(m_group_host_id) == null)
|
||||
{
|
||||
m_group_host_id = HostID.HostID_None;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 그룹에 속한 호스트가 없는 경우
|
||||
if (m_group_host_id != HostID.HostID_None && m_server.GetP2PGroupInfo(m_group_host_id).members.GetCount() == 0)
|
||||
{
|
||||
m_group_host_id = HostID.HostID_None;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 수퍼 피어가 설정되어 있는지 체크
|
||||
//=================================================================
|
||||
private bool isValidSuperPeer()
|
||||
{
|
||||
// 수퍼 피어가 퇴장한 경우 등을 체크
|
||||
if (m_super_peer_host_id != HostID.HostID_None && m_server.GetClientInfo(m_super_peer_host_id) == null)
|
||||
{
|
||||
m_super_peer_host_id = HostID.HostID_None;
|
||||
}
|
||||
return m_super_peer_host_id != HostID.HostID_None;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// HostID가 p2pGroup에 속해 있는지 체크
|
||||
//=================================================================
|
||||
private bool isHostIdInP2PGroup(HostID hostId)
|
||||
{
|
||||
if (!isValidGroup())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Enumerable.Range(0, m_server.GetP2PGroupInfo(m_group_host_id).members.GetCount())
|
||||
.Any(i => m_server.GetP2PGroupInfo(m_group_host_id).members.At(i) == hostId);
|
||||
}
|
||||
|
||||
private HostID findSuperPeer()
|
||||
{
|
||||
var peer_infos = new SortedList<HostID, NetClientInfo>();
|
||||
var group_info = m_server.GetP2PGroupInfo(m_group_host_id);
|
||||
Enumerable.Range(0, group_info.members.GetCount()).ToList().ForEach(i =>
|
||||
{
|
||||
var host_id = group_info.members.At(i);
|
||||
if (host_id == m_super_peer_host_id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var info = m_server.GetClientInfo(host_id);
|
||||
if (info == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
peer_infos.Add(info.hostID, info);
|
||||
});
|
||||
|
||||
var recommend_super_peer_id = m_server.GetMostSuitableSuperPeerInGroup(m_group_host_id);
|
||||
// peer_infos.TryGetValue(recommend_super_peer_id, out var recommend_super_peer_info);
|
||||
var recommend_super_peer_info = m_server.GetClientInfo(recommend_super_peer_id);
|
||||
NullReferenceCheckHelper.throwIfNull(recommend_super_peer_info, () => "recommend_super_peer_info is null");
|
||||
if (!isValidPolicy(recommend_super_peer_info))
|
||||
{
|
||||
// 추천된 수퍼 피어가 마이그레이션 조건을 만족하지 않는 경우
|
||||
// 커스텀 추천 로직 구현
|
||||
// recentPingMs > HostKickPingThreshold && recentFrameRate < HostKickFpsThreshold
|
||||
var custom_super_peer_info = peer_infos
|
||||
.OrderBy(x => x.Value.recentPingMs)
|
||||
.FirstOrDefault(x => isValidPolicy(x.Value));
|
||||
|
||||
if (custom_super_peer_info.Value != null)
|
||||
{
|
||||
Log.getLogger().info($"Host Migration Custom - recommend_super_peer_id: {recommend_super_peer_id}");
|
||||
recommend_super_peer_id = custom_super_peer_info.Key;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 정책에 맞는 수퍼 피어가 없는 경우 ping이 가장 낮은 수퍼 피어를 추천
|
||||
var second_super_peer_info = peer_infos.OrderBy(x => x.Value.recentPingMs).FirstOrDefault();
|
||||
if (second_super_peer_info.Value != null)
|
||||
{
|
||||
Log.getLogger().info($"Host Migration Second - recommend_super_peer_id: {recommend_super_peer_id}");
|
||||
recommend_super_peer_id = second_super_peer_info.Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_last_migration_time = DateTime.UtcNow;
|
||||
Log.getLogger().info($"Host Migration ProudNet - recommend_super_peer_id: {recommend_super_peer_id}");
|
||||
return recommend_super_peer_id;
|
||||
|
||||
bool isValidPolicy(NetClientInfo info)
|
||||
{
|
||||
return info.recentFrameRate > m_host_migration_policy.HostKickFpsThreshold &&
|
||||
info.recentPingMs < m_host_migration_policy.HostKickPingThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 호스트 마이그레이션 조건을 무시할 지 설정 - 이슈 방지를 위해서 1회성으로 제안함
|
||||
//=================================================================
|
||||
public void setIgnoreMigrationCondition(bool ignore)
|
||||
{
|
||||
m_ignore_migration_condition = ignore;
|
||||
}
|
||||
}
|
||||
162
GameServer/Contents/GameMode/Helper/PingLatencyKicker.cs
Normal file
162
GameServer/Contents/GameMode/Helper/PingLatencyKicker.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
namespace GameServer.Contents.GameMode.Helper;
|
||||
|
||||
using Nettention.Proud;
|
||||
|
||||
public class PingLatencyPolicy
|
||||
{
|
||||
public int PingKickThreshold { get; set; } = 600;
|
||||
public TimeSpan PingKickDuration { get; set; } = TimeSpan.FromSeconds(30);
|
||||
}
|
||||
|
||||
//=====================================================================
|
||||
// LatencyChecker - 플레이가 불가능한 핑 지연을 체크한다. super peer와의 핑을 체크
|
||||
//=====================================================================
|
||||
public class PingLatencyKicker
|
||||
{
|
||||
public class ClientLatency
|
||||
{
|
||||
public HostID HostId { get; set; }
|
||||
public int PingSum { get; set; }
|
||||
public int PingCheckCount { get; set; }
|
||||
public DateTime PingCheckBeginTime { get; set; } = DateTime.UtcNow;
|
||||
public int PingAverage => PingCheckCount > 0 ? PingSum / PingCheckCount: 0;
|
||||
}
|
||||
|
||||
private readonly PingLatencyPolicy m_ping_latency_policy;
|
||||
private readonly SortedList<HostID, ClientLatency> m_host_latencies = new();
|
||||
private HostID m_group_id;
|
||||
private HostID m_super_peer_id;
|
||||
private readonly NetServer m_server;
|
||||
|
||||
public PingLatencyKicker(NetServer server, PingLatencyPolicy pingLatencyPolicy)
|
||||
{
|
||||
m_ping_latency_policy = pingLatencyPolicy;
|
||||
m_server = server;
|
||||
}
|
||||
|
||||
public void setGroupHostId(HostID groupId)
|
||||
{
|
||||
m_group_id = groupId;
|
||||
}
|
||||
|
||||
public void setSuperPeerId(HostID superPeerId)
|
||||
{
|
||||
m_super_peer_id = superPeerId;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 호스트 그룹에 속한 클라이언트의 핑 지연을 체크하여, 게임이 불가한 지연이 발생한 경우 해당 호스트를 반환
|
||||
//==============================================================
|
||||
public IEnumerable<HostID> shouldKick()
|
||||
{
|
||||
if (!isValidGroup())
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
checkAndValidateSuperPeer();
|
||||
|
||||
if (!isValidSuperPeer())
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var kick_host_ids = getGroupMemberHostIds().Where(x => checkLatency(x) == true);
|
||||
return kick_host_ids;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<HostID>> shouldKickAsync()
|
||||
{
|
||||
return await Task.Run(shouldKick);
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 핑 지연 체크
|
||||
//=================================================================
|
||||
private bool checkLatency(HostID hostId)
|
||||
{
|
||||
var ping_to_super_peer = getP2PRecentPingMs(hostId);
|
||||
m_host_latencies.TryGetValue(hostId, out var client_latency);
|
||||
if (ping_to_super_peer > m_ping_latency_policy.PingKickThreshold)
|
||||
{
|
||||
if (client_latency == null)
|
||||
{
|
||||
client_latency = new ClientLatency
|
||||
{
|
||||
HostId = hostId, PingSum = 0, PingCheckCount = 0, PingCheckBeginTime = DateTime.UtcNow
|
||||
};
|
||||
m_host_latencies.Add(hostId, client_latency);
|
||||
}
|
||||
}
|
||||
|
||||
if (client_latency != null)
|
||||
{
|
||||
if (client_latency.PingCheckBeginTime + m_ping_latency_policy.PingKickDuration > DateTime.UtcNow)
|
||||
{
|
||||
if (client_latency.PingAverage > m_ping_latency_policy.PingKickThreshold)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
m_host_latencies.Remove(hostId);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int getP2PRecentPingMs(HostID hostId)
|
||||
{
|
||||
return m_server.GetP2PRecentPingMs(hostId, m_super_peer_id);
|
||||
}
|
||||
|
||||
private IEnumerable<HostID> getGroupMemberHostIds()
|
||||
{
|
||||
var host_ids = new List<HostID>();
|
||||
var group_info = m_server.GetP2PGroupInfo(m_group_id);
|
||||
for (int i = 0; i < group_info.members.GetCount(); i++)
|
||||
{
|
||||
host_ids.Add(group_info.members.At(i));
|
||||
}
|
||||
|
||||
return host_ids;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 호스트 그룹이 삭제됐는 지 확인
|
||||
//=================================================================
|
||||
private bool isValidGroup()
|
||||
{
|
||||
if (m_group_id == HostID.HostID_None)
|
||||
return false;
|
||||
|
||||
var group_info = m_server.GetP2PGroupInfo(m_group_id);
|
||||
if (group_info == null || group_info.members.GetCount() == 0)
|
||||
{
|
||||
m_group_id = HostID.HostID_None;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 수퍼 피어가 퇴장한 경우 등을 체크
|
||||
//=================================================================
|
||||
private void checkAndValidateSuperPeer()
|
||||
{
|
||||
// 수퍼 피어가 퇴장한 경우 등을 체크
|
||||
if (m_super_peer_id != HostID.HostID_None && m_server.GetClientInfo(m_super_peer_id) == null)
|
||||
{
|
||||
m_super_peer_id = HostID.HostID_None;
|
||||
}
|
||||
}
|
||||
|
||||
//=================================================================
|
||||
// 수퍼 피어가 설정되어 있는지 체크
|
||||
//=================================================================
|
||||
private bool isValidSuperPeer()
|
||||
{
|
||||
return m_super_peer_id != HostID.HostID_None;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
public abstract class GameModeInitHandlerBase : IGameModeInitHandler
|
||||
{
|
||||
protected readonly EPlaceType m_place_type;
|
||||
protected readonly InstanceRoom m_instance_room;
|
||||
|
||||
public GameModeInitHandlerBase(InstanceRoom instanceRoom, EPlaceType placeType)
|
||||
{
|
||||
m_instance_room = instanceRoom;
|
||||
m_place_type = placeType;
|
||||
|
||||
}
|
||||
|
||||
public abstract Result gamedModeInstanceInitValidate();
|
||||
|
||||
public abstract Result gamedModeInstanceInit();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
public abstract class GameModeJoinHandlerBase : IGameModeJoinHandler
|
||||
{
|
||||
protected readonly InstanceRoom m_instance_room;
|
||||
protected readonly EPlaceType m_place_type = EPlaceType.NONE;
|
||||
|
||||
public GameModeJoinHandlerBase(InstanceRoom instanceRoom, EPlaceType placeType)
|
||||
{
|
||||
m_instance_room = instanceRoom;
|
||||
m_place_type = placeType;
|
||||
}
|
||||
|
||||
public abstract Result gamedModeInstanceJoinValidate(EPlaceType placeType); //kihoon todo : 여기에 나중에 EPlaceType 대신 GameModeType이란걸 넣어야 한다.
|
||||
public abstract Result gamedModeInstanceJoin(Player player);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public abstract class GameModeJoinSuccessHandlerBase : IGameModeJoinSuccessHandler
|
||||
{
|
||||
protected Player m_player;
|
||||
//protected InstanceRoom m_instance_room;
|
||||
protected EPlaceType m_place_type;
|
||||
protected List<ILogInvoker> m_log_invorkers;
|
||||
|
||||
public GameModeJoinSuccessHandlerBase(Player player, EPlaceType placeType)
|
||||
{
|
||||
m_player = player;
|
||||
//m_instance_room = instanceRoom;
|
||||
m_place_type = placeType;
|
||||
m_log_invorkers = new();
|
||||
}
|
||||
|
||||
public async Task<Result> joinSuccess()
|
||||
{
|
||||
var result = joinSuccessValidate();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = await joinSuccessConfirmation();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = joinSuccessNotify().Result;
|
||||
if (result.isFail()) return result;
|
||||
|
||||
joinSuccessWriteLog();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public abstract Result joinSuccessValidate();
|
||||
public abstract Task<Result> joinSuccessConfirmation();
|
||||
public abstract Task<Result> joinSuccessNotify();
|
||||
|
||||
public abstract void joinSuccessWriteLog();
|
||||
|
||||
}
|
||||
24
GameServer/Contents/GameMode/Manage/GameRoomInitHandler.cs
Normal file
24
GameServer/Contents/GameMode/Manage/GameRoomInitHandler.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
public class GameRoomInitHandler : GameModeInitHandlerBase
|
||||
{
|
||||
public GameRoomInitHandler(InstanceRoom instanceRoom) : base(instanceRoom, EPlaceType.GameRoom)
|
||||
{
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceInitValidate()
|
||||
{
|
||||
var result = new Result();
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
27
GameServer/Contents/GameMode/Manage/GameRoomJoinHandler.cs
Normal file
27
GameServer/Contents/GameMode/Manage/GameRoomJoinHandler.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class GameRoomJoinHandler : GameModeJoinHandlerBase
|
||||
{
|
||||
public GameRoomJoinHandler(InstanceRoom instanceRoom) : base(instanceRoom, EPlaceType.GameRoom)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceJoinValidate(EPlaceType placeType)
|
||||
{
|
||||
var result = new Result();
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceJoin(Player player)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg = string.Empty;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
public class GameRoomJoinSuccessHandler: GameModeJoinSuccessHandlerBase
|
||||
{
|
||||
public GameRoomJoinSuccessHandler(Player player, InstanceRoom instanceRoom) : base(player, EPlaceType.GameRoom)
|
||||
{
|
||||
}
|
||||
|
||||
public override Result joinSuccessValidate()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Task<Result> joinSuccessConfirmation()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override Task<Result> joinSuccessNotify()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void joinSuccessWriteLog()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace GameServer;
|
||||
|
||||
public interface IGameModeInitHandler
|
||||
{
|
||||
public Result gamedModeInstanceInitValidate();
|
||||
public Result gamedModeInstanceInit();
|
||||
}
|
||||
13
GameServer/Contents/GameMode/Manage/IGameModeJoinHandler.cs
Normal file
13
GameServer/Contents/GameMode/Manage/IGameModeJoinHandler.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public interface IGameModeJoinHandler
|
||||
{
|
||||
public Result gamedModeInstanceJoinValidate(EPlaceType placeType); //kihoon todo : 여기에 나중에 EPlaceType 대신 GameModeType이란걸 넣어야 한다.
|
||||
public Result gamedModeInstanceJoin(Player player);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public interface IGameModeJoinSuccessHandler
|
||||
{
|
||||
public Task<Result> joinSuccess();
|
||||
}
|
||||
@@ -0,0 +1,417 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleInstanceAction : EntityActionBase
|
||||
{
|
||||
public BattleInstanceAction(EntityBase owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
public override void onClear() { }
|
||||
|
||||
|
||||
public async Task<Result> loadOrCreateSnapshot()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var battle_instance_room = getOwner() as BattleInstanceRoom;
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room, () => $"battle_instance_room_owner is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var dynamodb_client = server_logic.getDynamoDbClient();
|
||||
|
||||
string room_id = battle_instance_room.m_instance_room.getMap().m_room_id;
|
||||
|
||||
var config = dynamodb_client.makeQueryConfigForReadByPKSK(BattleInstanceSnapshotDoc.pk, room_id);
|
||||
(result, var read_docs) = await dynamodb_client.simpleQueryDocTypesWithQueryOperationConfig<BattleInstanceSnapshotDoc>(config);
|
||||
if(result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var event_id = BattleRoomHelper.getBattleEventIdFromRoomId(room_id);
|
||||
BattleInstanceSnapshotDoc doc = new(room_id);
|
||||
string snapshot_load_type = "LOAD";
|
||||
if (read_docs.Count == 0 || event_id == 0)
|
||||
{
|
||||
//데이터가 없으므로 생성 처리
|
||||
result = await createBattleInstanceSnapshot(room_id);
|
||||
if (result.isFail()) return result;
|
||||
snapshot_load_type = "CREATE";
|
||||
}
|
||||
else if (read_docs.Count > 0)
|
||||
{
|
||||
doc = read_docs[0];
|
||||
var battle_instance_action = battle_instance_room.getEntityAction<BattleInstanceAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_action, () => $"battle_instance_action is null !!!");
|
||||
result = battle_instance_action.setSnapshotFromDoc(doc);
|
||||
}
|
||||
|
||||
|
||||
if (result.isFail()) return result;
|
||||
|
||||
Log.getLogger().debug($"loadOrCreateSnapshot room_id : {battle_instance_room.toBasicString()}");
|
||||
|
||||
|
||||
var attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
|
||||
var invokers = new List<ILogInvoker>();
|
||||
var log_action = new LogActionEx(LogActionType.BattleInstanceSnapshotCreate);
|
||||
BattleSnapShotBusinessLog business_log = new(battle_instance_room, snapshot_load_type);
|
||||
invokers.Add(business_log);
|
||||
BusinessLogger.collectLogs(log_action, battle_instance_room, invokers);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> createBattleInstanceSnapshot(string roomId)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
await Task.CompletedTask;
|
||||
|
||||
BattleInstanceSnapshotDoc doc = new(roomId);
|
||||
|
||||
var battle_instance_room = getOwner() as BattleInstanceRoom;
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room, () => $"battle_instance_room is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var fn_create_battle_instance_snapshot = async delegate()
|
||||
{
|
||||
var battle_instance_snaptshot_attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_snaptshot_attribute, () => $"battle_instance_snaptshot_attribute is null !!!");
|
||||
|
||||
battle_instance_snaptshot_attribute.m_room_id = roomId;
|
||||
battle_instance_snaptshot_attribute.m_combat_pod_mode.m_current_state_start_time = battle_instance_room.m_battle_instance_event_start_time;
|
||||
|
||||
addRespawnPosInfoFromMeta(battle_instance_room, battle_instance_snaptshot_attribute);
|
||||
addStorageInfoFromMeta(battle_instance_room, battle_instance_snaptshot_attribute);
|
||||
addPickupPodInfoFromMeta(battle_instance_room, battle_instance_snaptshot_attribute);
|
||||
|
||||
|
||||
var anchors = battle_instance_room.m_instance_room.getMap().getAnchors();
|
||||
foreach (var anchor in anchors)
|
||||
{
|
||||
addBattleObjectWeapon(battle_instance_snaptshot_attribute, anchor.Value);
|
||||
addBattleObjectBuff(battle_instance_snaptshot_attribute, anchor.Value);
|
||||
}
|
||||
|
||||
var result = await createBattleObjectCombatPod(battle_instance_room, battle_instance_snaptshot_attribute);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
result = await createBattleObjectPickupPodReward(battle_instance_room, battle_instance_snaptshot_attribute);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
battle_instance_snaptshot_attribute.modifiedEntityAttribute(true);
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(battle_instance_room, LogActionType.BattleInstanceSnapshotCreate, server_logic.getDynamoDbClient());
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
}
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
return result;
|
||||
};
|
||||
|
||||
result = await battle_instance_room.runTransactionRunnerSafelyWithTransGuid(battle_instance_room.m_instance_room.getMap().m_room_id,
|
||||
TransactionIdType.PrivateContents, BattleConstant.BATTLE_INSTANCE_TRANSACTION_NAME, fn_create_battle_instance_snapshot);
|
||||
if (result.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()} - CreateBattleInstanceSnapshot, {battle_instance_room.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private Result setSnapshotFromDoc(BattleInstanceSnapshotDoc doc)
|
||||
{
|
||||
var result = new Result();
|
||||
var battle_instance_snapshot_attrib = doc.getAttrib<BattleInstanceSnapshotAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_snapshot_attrib, () => $"battle_instance_snapshot_attrib is null !!!");
|
||||
|
||||
var battle_instance_room = getOwner() as BattleInstanceRoom;
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room, () => $"battle_instance_room is null !!!");
|
||||
|
||||
var attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
attribute.copyEntityAttributeFromDoc(doc);
|
||||
attribute.syncOriginDocBaseWithNewDoc<BattleInstanceSnapshotAttribute>(doc);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void deleteChangedGuidAnchor(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, BattleInstanceSnapshotAttrib attrib)
|
||||
{
|
||||
deleteChangedBattleObjectPodStorageAnchor(battleInstanceRoom, attribute, attrib);
|
||||
deleteChangedBattleObjectPickupPodAnchor(battleInstanceRoom, attribute, attrib);
|
||||
deleteChangedRespawnAnchor(battleInstanceRoom, attribute, attrib);
|
||||
deleteChangedBattleObjectWeaponAnchor(battleInstanceRoom, attribute, attrib);
|
||||
deleteChangedBattleObjectBuffAnchor(battleInstanceRoom, attribute, attrib);
|
||||
|
||||
//pod combat은 timer에서 처리해준다.
|
||||
}
|
||||
|
||||
private void setNewGuidAnchor(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
addRespawnPosInfoFromMeta(battleInstanceRoom, attribute);
|
||||
addStorageInfoFromMeta(battleInstanceRoom, attribute);
|
||||
addPickupPodInfoFromMeta(battleInstanceRoom, attribute);
|
||||
|
||||
|
||||
var anchors = battleInstanceRoom.m_instance_room.getMap().getAnchors();
|
||||
foreach (var anchor in anchors)
|
||||
{
|
||||
addBattleObjectWeapon(attribute, anchor.Value);
|
||||
addBattleObjectBuff(attribute, anchor.Value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void deleteChangedBattleObjectPodStorageAnchor(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, BattleInstanceSnapshotAttrib attrib)
|
||||
{
|
||||
List<string> delete_keys = new();
|
||||
foreach (var stand in attrib.m_combat_pod_attrib.m_pod_storages)
|
||||
{
|
||||
//기존에 들고 있던 guid 가 map에서 없어지거나 바뀌었을 경우가 있을수 있으므로 예외 처리
|
||||
if (false == battleInstanceRoom.m_instance_room.getMap().getAnchors().ContainsKey(stand.Key))
|
||||
{
|
||||
Log.getLogger().warn($"stand : {stand.Key} is not exist.. so don't add attribute.... roomId : {battleInstanceRoom.m_instance_room.getMap().m_room_id}");
|
||||
delete_keys.Add(stand.Key);
|
||||
continue;
|
||||
}
|
||||
attribute.m_combat_pod_mode.m_pod_storages.TryAdd(stand.Key, stand.Value);
|
||||
}
|
||||
|
||||
foreach (var delete_key in delete_keys)
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_pod_storages.TryRemove(delete_key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteChangedBattleObjectPickupPodAnchor(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, BattleInstanceSnapshotAttrib attrib)
|
||||
{
|
||||
List<string> delete_keys = new();
|
||||
foreach (var box in attrib.m_combat_pod_attrib.m_pickup_pods)
|
||||
{
|
||||
//기존에 들고 있던 guid 가 map에서 없어지거나 바뀌었을 경우가 있을수 있으므로 예외 처리
|
||||
if (false == battleInstanceRoom.m_instance_room.getMap().getAnchors().ContainsKey(box.Key))
|
||||
{
|
||||
Log.getLogger().info($"box : {box.Key} is not exist.. so don't add attribute.... roomId : {battleInstanceRoom.m_instance_room.getMap().m_room_id}");
|
||||
delete_keys.Add(box.Key);
|
||||
continue;
|
||||
}
|
||||
attribute.m_combat_pod_mode.m_pickup_pods.TryAdd(box.Key, box.Value);
|
||||
}
|
||||
|
||||
foreach (var delete_key in delete_keys)
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_pickup_pods.TryRemove(delete_key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteChangedRespawnAnchor(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, BattleInstanceSnapshotAttrib attrib)
|
||||
{
|
||||
List<string> delete_keys = new();
|
||||
foreach (var each in attrib.m_combat_pod_attrib.m_respawns)
|
||||
{
|
||||
//map에 respawn pos가 없어지거나 바뀌었을 경우가 있을수 있으므로 예외 처리
|
||||
if (false == battleInstanceRoom.m_respawn_pos_anchors_meta.Contains(each.Key))
|
||||
{
|
||||
Log.getLogger().warn($"spawn idx : {each.Key} is not exist.. so don't add attribute.... roomId : {battleInstanceRoom.m_instance_room.getMap().m_room_id}");
|
||||
delete_keys.Add(each.Key);
|
||||
continue;
|
||||
}
|
||||
attribute.m_combat_pod_mode.m_respawns.TryAdd(each.Key, each.Value);
|
||||
}
|
||||
foreach (var delete_key in delete_keys)
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_respawns.TryRemove(delete_key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteChangedBattleObjectWeaponAnchor(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, BattleInstanceSnapshotAttrib attrib)
|
||||
{
|
||||
List<string> delete_keys = new();
|
||||
foreach (var weapon in attrib.m_combat_pod_attrib.m_weapons)
|
||||
{
|
||||
//기존에 들고 있던 guid 가 map에서 없어지거나 바뀌었을 경우가 있을수 있으므로 예외 처리
|
||||
if (false == battleInstanceRoom.m_instance_room.getMap().getAnchors().ContainsKey(weapon.Key))
|
||||
{
|
||||
Log.getLogger().warn($"weapon : {weapon.Key} is not exist.. so don't add attribute.... roomId : {battleInstanceRoom.m_instance_room.getMap().m_room_id}");
|
||||
delete_keys.Add(weapon.Key);
|
||||
continue;
|
||||
}
|
||||
attribute.m_combat_pod_mode.m_weapons.TryAdd(weapon.Key, weapon.Value);
|
||||
}
|
||||
|
||||
foreach (var delete_key in delete_keys)
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_weapons.TryRemove(delete_key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteChangedBattleObjectBuffAnchor(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, BattleInstanceSnapshotAttrib attrib)
|
||||
{
|
||||
List<string> delete_keys = new();
|
||||
foreach (var buff in attrib.m_combat_pod_attrib.m_buffs)
|
||||
{
|
||||
//map에 respawn pos가 없어지거나 바뀌었을 경우가 있을수 있으므로 예외 처리
|
||||
if (false == battleInstanceRoom.m_instance_room.getMap().getAnchors().ContainsKey(buff.Key))
|
||||
{
|
||||
Log.getLogger().warn($"buff : {buff.Key} is not exist.. so don't add attribute.... roomId : {battleInstanceRoom.m_instance_room.getMap().m_room_id}");
|
||||
delete_keys.Add(buff.Key);
|
||||
continue;
|
||||
}
|
||||
attribute.m_combat_pod_mode.m_buffs.TryAdd(buff.Key, buff.Value);
|
||||
}
|
||||
|
||||
foreach (var delete_key in delete_keys)
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_buffs.TryRemove(delete_key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
private void addRespawnPosInfoFromMeta(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
var now = DateTimeHelper.Current;
|
||||
|
||||
foreach (var anchor_guid in battleInstanceRoom.m_respawn_pos_anchors_meta)
|
||||
{
|
||||
if (attribute.m_combat_pod_mode.m_respawns.ContainsKey(anchor_guid)) continue;
|
||||
attribute.m_combat_pod_mode.m_respawns.TryAdd(anchor_guid, now);
|
||||
}
|
||||
}
|
||||
|
||||
private void addStorageInfoFromMeta(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
foreach (var storage_group in battleInstanceRoom.m_battle_pod_storage_guid_group.Values)
|
||||
{
|
||||
foreach (var anchor_guid in storage_group)
|
||||
{
|
||||
addBattleObjectPodStorage(attribute, anchor_guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addPickupPodInfoFromMeta(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
foreach (var pickup_pod_group in battleInstanceRoom.m_battle_pickup_pod_guid_group.Values)
|
||||
{
|
||||
foreach (var anchor_guid in pickup_pod_group)
|
||||
{
|
||||
addBattleObjectPickupPod(attribute, anchor_guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void addBattleObjectWeapon(BattleInstanceSnapshotAttribute attribute, AnchorInfo anchorInfo)
|
||||
{
|
||||
if (attribute.m_combat_pod_mode.m_weapons.ContainsKey(anchorInfo.AnchorGuid)) return;
|
||||
|
||||
var talbe_id = anchorInfo.AnchorProp.TableId;
|
||||
|
||||
if (false == MetaData.Instance._BattleObjectMetaTable.TryGetValue(talbe_id, out var battle_object)) return;
|
||||
if (false == battle_object.ObjectType.Equals(EBattleObjectType.Weapon)) return;
|
||||
|
||||
BattleObjectWeapon weapon = new(anchorInfo.AnchorGuid);
|
||||
attribute.m_combat_pod_mode.m_weapons.TryAdd(anchorInfo.AnchorGuid, weapon);
|
||||
}
|
||||
|
||||
private void addBattleObjectBuff(BattleInstanceSnapshotAttribute attribute, AnchorInfo anchorInfo)
|
||||
{
|
||||
if (attribute.m_combat_pod_mode.m_buffs.ContainsKey(anchorInfo.AnchorGuid)) return;
|
||||
|
||||
var talbe_id = anchorInfo.AnchorProp.TableId;
|
||||
|
||||
if (false == MetaData.Instance._BattleObjectMetaTable.TryGetValue(talbe_id, out var battle_object)) return;
|
||||
if (false == battle_object.ObjectType.Equals(EBattleObjectType.Buff)) return;
|
||||
|
||||
BattleObjectBuff buff = new(anchorInfo.AnchorGuid);
|
||||
attribute.m_combat_pod_mode.m_buffs.TryAdd(anchorInfo.AnchorGuid, buff);
|
||||
}
|
||||
|
||||
private void addBattleObjectPodStorage(BattleInstanceSnapshotAttribute attribute, string anchorGuid)
|
||||
{
|
||||
if (attribute.m_combat_pod_mode.m_pod_storages.ContainsKey(anchorGuid)) return;
|
||||
|
||||
BattleObjectPodStorage storage = new(anchorGuid);
|
||||
attribute.m_combat_pod_mode.m_pod_storages.TryAdd(anchorGuid, storage);
|
||||
}
|
||||
|
||||
private void addBattleObjectPickupPod(BattleInstanceSnapshotAttribute attribute, string anchorGuid)
|
||||
{
|
||||
if (attribute.m_combat_pod_mode.m_pickup_pods.ContainsKey(anchorGuid)) return;
|
||||
|
||||
//신규 생성이라 false로
|
||||
BattleObjectPickupPod pickup = new(anchorGuid);
|
||||
pickup.m_is_active = false;
|
||||
attribute.m_combat_pod_mode.m_pickup_pods.TryAdd(anchorGuid, pickup);
|
||||
}
|
||||
|
||||
|
||||
private async Task<Result> createBattleObjectPickupPodReward(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var battle_update_action = battleInstanceRoom.getEntityAction<BattleInstanceUpdateAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_update_action, () => $"battle_update_action is null !!!");
|
||||
|
||||
await battle_update_action.createPickupPodReward(battleInstanceRoom, attribute);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> createBattleObjectCombatPod(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
var battle_update_action = battleInstanceRoom.getEntityAction<BattleInstanceUpdateAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_update_action, () => $"battle_update_action is null !!!");
|
||||
|
||||
var result = await battle_update_action.createCombatPod(battleInstanceRoom, attribute);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
|
||||
//여기서 PodCombatState 패킷전송
|
||||
//BattleRoomNotifyHelper.send_GS2C_NTF_POD_COMBAT_STATE();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// private void setBattleObjectPodCombat(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, BattleInstanceSnapshotAttrib attrib)
|
||||
// {
|
||||
//
|
||||
// foreach (var pod_combat in attrib.m_combat_pod_attrib.m_combat_pods)
|
||||
// {
|
||||
// //var pod_combat_guid = pod_combat.Key;
|
||||
// //attribute.m_pod_combat_mode.m_pod_combats.AddOrUpdate(pod_combat.Key, pod_combat.Value, (key, old) => pod_combat.Value);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,516 @@
|
||||
using Newtonsoft.Json;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public partial class BattleInstanceUpdateAction
|
||||
{
|
||||
|
||||
private async Task<Result> battleInstanceStateUpdate(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
var result = new Result();
|
||||
var round_state = attribute.m_combat_pod_mode.m_round_state_type;
|
||||
switch (round_state)
|
||||
{
|
||||
case BattleRoundStateType.Rounding:
|
||||
//라운드가 끝났을때 Wait 혹은 End 처리
|
||||
result = await battleInstanceRoundingStateUpdate(battleInstanceRoom, attribute);
|
||||
break;
|
||||
case BattleRoundStateType.RoundWait:
|
||||
//시간 됐을때 Rounding 처리
|
||||
result = await battleInstanceWaitStateUpdate(battleInstanceRoom, attribute);
|
||||
break;
|
||||
case BattleRoundStateType.RoundEndAll:
|
||||
//시간 지났을때 kick 처리
|
||||
result = await battleInstanceEndStateUpdate(battleInstanceRoom, attribute);
|
||||
break;
|
||||
case BattleRoundStateType.Destroyed:
|
||||
break;
|
||||
default:
|
||||
Log.getLogger().error($"BattleRoundStateType None error room_id : {battleInstanceRoom.m_instance_room.getMap().m_room_id}");
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> battleInstanceWaitStateUpdate(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
var result = new Result();
|
||||
await Task.CompletedTask;
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
|
||||
var state_start_time = attribute.m_combat_pod_mode.m_current_state_start_time;
|
||||
var wait_end_time = state_start_time.AddSeconds(battleInstanceRoom.m_ffa_config_meta.NextRoundWaitTime);
|
||||
|
||||
//시간이 지났을 경우 state 바꿔주는 처리 필요
|
||||
if (now < wait_end_time) return result;
|
||||
|
||||
|
||||
using (var releaser = await battleInstanceRoom.getAsyncLock())
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.Rounding;
|
||||
attribute.m_combat_pod_mode.m_current_state_start_time = wait_end_time;
|
||||
attribute.m_combat_pod_mode.m_current_round += 1;
|
||||
attribute.m_combat_pod_mode.m_charged_step = 0;
|
||||
attribute.m_combat_pod_mode.m_rewarded_step = 0;
|
||||
|
||||
attribute.m_combat_pod_mode.m_pod_combat.setActive(now);
|
||||
|
||||
|
||||
(result, var anchor_guid) = BattleRoomHelper.getRandomCombatPodAnchorGuid(attribute, battleInstanceRoom);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().Error("get Random pod combat anchor guid faile !!! ");
|
||||
return result;
|
||||
}
|
||||
|
||||
attribute.m_combat_pod_mode.m_pod_combat.m_source_storage_anchor_guid = anchor_guid;
|
||||
|
||||
|
||||
}
|
||||
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom);
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battleInstanceRoom);
|
||||
battleObjectStateInitAndNotify(battleInstanceRoom, attribute);
|
||||
|
||||
|
||||
//로그 추가
|
||||
var invokers = new List<ILogInvoker>();
|
||||
var log_action = new LogActionEx(LogActionType.BattleRoundStateUpdate);
|
||||
|
||||
var room_id = battleInstanceRoom.m_instance_room.getMap().m_room_id;
|
||||
var ended_round = attribute.m_combat_pod_mode.m_current_round;
|
||||
var round_state = attribute.m_combat_pod_mode.m_round_state_type;
|
||||
var users = battleInstanceRoom.m_instance_room.tryGetInstanceExistUserForLog();
|
||||
BattleRoundUpdateBusinessLog business_log = new(room_id, ended_round, round_state, users);
|
||||
invokers.Add(business_log);
|
||||
BusinessLogger.collectLogs(log_action, battleInstanceRoom, invokers);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private async Task<Result> battleInstanceRoundingStateUpdate(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
var round_start_time = attribute.m_combat_pod_mode.m_current_state_start_time;
|
||||
var round_end_time = round_start_time.AddSeconds(battleInstanceRoom.m_ffa_config_meta.RoundTime);
|
||||
|
||||
//라운드에 대한 시간이 지났을 경우 state 바꿔주는 처리 필요
|
||||
if (round_end_time <= now)
|
||||
{
|
||||
await roundingUpdate(battleInstanceRoom, round_end_time);
|
||||
}
|
||||
else
|
||||
{
|
||||
await podCombatRewardUpdate(battleInstanceRoom, attribute, now);
|
||||
await stepUpdate(battleInstanceRoom, attribute, now);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task roundingUpdate(BattleInstanceRoom battleInstanceRoom, DateTime roundEndTime)
|
||||
{
|
||||
var result = new Result();
|
||||
string occupier_guid = string.Empty;
|
||||
|
||||
|
||||
using (var releaser = await battleInstanceRoom.getAsyncLock())
|
||||
{
|
||||
var attribute = battleInstanceRoom.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!! - {battleInstanceRoom.toBasicString()}");
|
||||
occupier_guid = attribute.m_combat_pod_mode.m_pod_combat.m_current_occupier_guid;
|
||||
|
||||
Player? rewarded_player = null;
|
||||
if (!occupier_guid.Equals(string.Empty))
|
||||
{
|
||||
if (false == battleInstanceRoom.m_instance_room.tryGetInstanceMember(occupier_guid, out rewarded_player))
|
||||
{
|
||||
//보상은 안되더라도 라운드는 진행 가능하게 처리해야할듯...
|
||||
var err_msg = $"not exist user in instance_room !!! user_guid : {occupier_guid}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
}
|
||||
if (rewarded_player is null)
|
||||
{
|
||||
result = await roundingUpdateWithoutReward(battleInstanceRoom, roundEndTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = await roundingUpdateWithReward(battleInstanceRoom, roundEndTime, rewarded_player);
|
||||
}
|
||||
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Result> roundingUpdateWithReward(BattleInstanceRoom battleInstanceRoom, DateTime roundEndTime, Player player)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
//bool need_battle_end_result_noti = false;
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
List<BattleObjectInfo> infos = new();
|
||||
|
||||
CommonResult common_result = new();
|
||||
|
||||
var fn_battle_round_update = async delegate()
|
||||
{
|
||||
|
||||
var attribute = battleInstanceRoom.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!! - {battleInstanceRoom.toBasicString()}");
|
||||
|
||||
if (battleInstanceRoom.m_round_count <= attribute.m_combat_pod_mode.m_current_round)
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.RoundEndAll;
|
||||
//배틍 종료에 대한 정보를 알려줄지 말지에 대한 noti
|
||||
//need_battle_end_result_noti = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.RoundWait;
|
||||
}
|
||||
|
||||
attribute.m_combat_pod_mode.m_current_state_start_time = roundEndTime;
|
||||
|
||||
(result, var rewards, var reward_start_step, var reward_end_step) = await podCombatUpdateIfHasOccupier(battleInstanceRoom, attribute, player);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
//모든 픽업포드 비활성화, 모든 스토리지 비활성화
|
||||
infos.AddRange(battleObjectPickupPodsDeactive(attribute));
|
||||
infos.AddRange(battleObjectPodStoragesDeactive(attribute));
|
||||
attribute.m_combat_pod_mode.m_pod_combat.setDeactive();
|
||||
attribute.modifiedEntityAttribute(true);
|
||||
|
||||
Log.getLogger().debug($"roundingUpdateWithReward attribute info : {JsonConvert.SerializeObject(attribute)}");
|
||||
|
||||
(result, var doc) = await attribute.toDocBase();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
//batch 처리
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.BattleRoundStateUpdate, server_logic.getDynamoDbClient());
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
if (doc is not null)
|
||||
{
|
||||
batch.addQuery(new DBQEntityWrite(doc));
|
||||
}
|
||||
}
|
||||
|
||||
//로그 추가
|
||||
var room_id = battleInstanceRoom.m_instance_room.getMap().m_room_id;
|
||||
var ended_round = attribute.m_combat_pod_mode.m_current_round;
|
||||
var round_state = attribute.m_combat_pod_mode.m_round_state_type;
|
||||
var users = battleInstanceRoom.m_instance_room.tryGetInstanceExistUserForLog();
|
||||
BattleRoundUpdateBusinessLog business_log = new(room_id, ended_round, round_state, users);
|
||||
batch.appendBusinessLog(business_log);
|
||||
|
||||
BattlePodCombatRewardBusinessLog combat_business_log = new(room_id, ended_round, round_state
|
||||
, player.getUserGuid(), player.getUserNickname()
|
||||
, reward_start_step, reward_end_step, rewards);
|
||||
batch.appendBusinessLog(combat_business_log);
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
|
||||
if (result.isFail()) return result;
|
||||
|
||||
//보상 내용 가져올것
|
||||
var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents);
|
||||
NullReferenceCheckHelper.throwIfNull(found_transaction_runner, () => $"found_transaction_runner is null !!! - {battleInstanceRoom.toBasicString()}");
|
||||
common_result = found_transaction_runner.getCommonResult();
|
||||
return result;
|
||||
};
|
||||
|
||||
result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid(), TransactionIdType.PrivateContents, BattleConstant.BATTLE_INSTANCE_TRANSACTION_NAME, fn_battle_round_update);
|
||||
if (result.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()}, {battleInstanceRoom.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom);
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(battleInstanceRoom, infos);
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battleInstanceRoom);
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_REWARD(battleInstanceRoom, player.getUserGuid(), common_result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private async Task<Result> roundingUpdateWithoutReward(BattleInstanceRoom battleInstanceRoom, DateTime roundEndTime)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
bool need_battle_end_result_noti = false;
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
List<BattleObjectInfo> infos = new();
|
||||
|
||||
var fn_battle_round_update = async delegate()
|
||||
{
|
||||
|
||||
var attribute = battleInstanceRoom.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!! - {battleInstanceRoom.toBasicString()}");
|
||||
|
||||
if (battleInstanceRoom.m_round_count <= attribute.m_combat_pod_mode.m_current_round)
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.RoundEndAll;
|
||||
//배틍 종료에 대한 정보를 알려줄지 말지에 대한 noti
|
||||
need_battle_end_result_noti = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.RoundWait;
|
||||
}
|
||||
|
||||
attribute.m_combat_pod_mode.m_current_state_start_time = roundEndTime;
|
||||
|
||||
//모든 픽업포드 비활성화, 모든 스토리지 비활성화
|
||||
infos.AddRange(battleObjectPickupPodsDeactive(attribute));
|
||||
infos.AddRange(battleObjectPodStoragesDeactive(attribute));
|
||||
attribute.m_combat_pod_mode.m_pod_combat.setDeactive();
|
||||
|
||||
attribute.modifiedEntityAttribute(true);
|
||||
|
||||
//batch 처리
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(battleInstanceRoom, LogActionType.BattleRoundStateUpdate, server_logic.getDynamoDbClient());
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
}
|
||||
|
||||
//로그 추가
|
||||
var room_id = battleInstanceRoom.m_instance_room.getMap().m_room_id;
|
||||
var ended_round = attribute.m_combat_pod_mode.m_current_round;
|
||||
var round_state = attribute.m_combat_pod_mode.m_round_state_type;
|
||||
var users = battleInstanceRoom.m_instance_room.tryGetInstanceExistUserForLog();
|
||||
BattleRoundUpdateBusinessLog business_log = new(room_id, ended_round, round_state, users);
|
||||
batch.appendBusinessLog(business_log);
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
|
||||
if (result.isFail()) return result;
|
||||
|
||||
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
result = await battleInstanceRoom.runTransactionRunnerSafelyWithTransGuid(battleInstanceRoom.m_instance_room.getMap().m_room_id,
|
||||
TransactionIdType.PrivateContents, BattleConstant.BATTLE_INSTANCE_TRANSACTION_NAME, fn_battle_round_update);
|
||||
if (result.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()}, {battleInstanceRoom.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom);
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(battleInstanceRoom, infos);
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battleInstanceRoom);
|
||||
|
||||
if (need_battle_end_result_noti)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task stepUpdate(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, DateTime now)
|
||||
{
|
||||
var max_charge_level = battleInstanceRoom.m_ffa_reward_meta
|
||||
.Where(kvp => kvp.Key == battleInstanceRoom.m_ffa_reward_meta.Keys.Max())
|
||||
.Select(kvp => kvp.Key)
|
||||
.FirstOrDefault();
|
||||
|
||||
//최대 스텝이면 알려줄것 없다.
|
||||
if (max_charge_level <= attribute.m_combat_pod_mode.m_charged_step) return;
|
||||
|
||||
//시간이 아직 안지났을 경우는 m_charged_step 시간을 체크 해줘야 된다...
|
||||
var round_start_time = attribute.m_combat_pod_mode.m_current_state_start_time;
|
||||
|
||||
var current_charge_level = attribute.m_combat_pod_mode.m_charged_step;
|
||||
var next_charge_level = current_charge_level + 1;
|
||||
|
||||
//다음 충전까지 필요한 시간의 합
|
||||
var next_charge_time_total = battleInstanceRoom.m_ffa_reward_meta
|
||||
.Where(kvp => kvp.Key <= next_charge_level)
|
||||
.Sum(kvp => kvp.Value.ChargeTime);
|
||||
|
||||
//여기도 using만 사용 로그만 남길것...
|
||||
using (var releaser = await battleInstanceRoom.getAsyncLock())
|
||||
{
|
||||
var next_step_active_time = round_start_time.AddSeconds(next_charge_time_total);
|
||||
if (next_step_active_time <= now)
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_charged_step = next_charge_level;
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task podCombatRewardUpdate(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, DateTime now)
|
||||
{
|
||||
var occupier_guid = string.Empty;
|
||||
CommonResult common_result = new();
|
||||
bool need_pod_combat_noti = false;
|
||||
using (var releaser = await battleInstanceRoom.getAsyncLock())
|
||||
{
|
||||
occupier_guid = attribute.m_combat_pod_mode.m_pod_combat.m_current_occupier_guid;
|
||||
if (occupier_guid.Equals(string.Empty)) return;
|
||||
|
||||
if (false == battleInstanceRoom.m_instance_room.tryGetInstanceMember(occupier_guid, out var player))
|
||||
{
|
||||
Log.getLogger().error($"Not Exist Player in battle instance room occupier_guid : {occupier_guid}");
|
||||
return;
|
||||
}
|
||||
|
||||
var charged_step = attribute.m_combat_pod_mode.m_charged_step;
|
||||
var rewarded_step = attribute.m_combat_pod_mode.m_rewarded_step;
|
||||
if (charged_step <= rewarded_step) return;
|
||||
|
||||
var accupied_time = attribute.m_combat_pod_mode.m_pod_combat.m_occupied_time;
|
||||
|
||||
|
||||
var rewadable_time = accupied_time.AddSeconds(battleInstanceRoom.m_ffa_config_meta.GetRewardTime);
|
||||
if (rewadable_time > now) return;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
var fn_pod_combat_reward_update = async delegate()
|
||||
{
|
||||
//여기서 보상처리 가능하다.
|
||||
var rewards = makePodCombatOccupyReward(rewarded_step, charged_step, battleInstanceRoom);
|
||||
result = await addPodCommbatOccupyReward(player, battleInstanceRoom, rewards);
|
||||
if (result.isFail())
|
||||
{
|
||||
string err_msg = $"addPodCommbatOccupyReward return fail.. error : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
attribute.m_combat_pod_mode.m_rewarded_step = charged_step;
|
||||
attribute.m_combat_pod_mode.m_pod_combat.m_occupied_time = rewadable_time;
|
||||
|
||||
var max_charge_level = battleInstanceRoom.m_ffa_reward_meta
|
||||
.Where(kvp => kvp.Key == battleInstanceRoom.m_ffa_reward_meta.Keys.Max())
|
||||
.Select(kvp => kvp.Key)
|
||||
.FirstOrDefault();
|
||||
if (max_charge_level <= charged_step)
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_pod_combat.setDeactive();
|
||||
need_pod_combat_noti = true;
|
||||
}
|
||||
|
||||
|
||||
attribute.modifiedEntityAttribute(true);
|
||||
(result, var doc) = await attribute.toDocBase();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
//batch 처리
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.BattlePodCombatOccupyReward, server_logic.getDynamoDbClient());
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
if (doc is not null)
|
||||
{
|
||||
batch.addQuery(new DBQEntityWrite(doc));
|
||||
}
|
||||
}
|
||||
BattleObjectLogInfo info = new();
|
||||
info.m_battle_object_type = EBattleObjectType.Pod_Combat;
|
||||
|
||||
List<BattleObjectLogInfo> log_infos = new();
|
||||
var room_id = battleInstanceRoom.m_instance_room.getMap().m_room_id;
|
||||
var current_round = attribute.m_combat_pod_mode.m_current_round;
|
||||
var round_state_type = attribute.m_combat_pod_mode.m_round_state_type;
|
||||
var business_log = new BattlePodCombatRewardBusinessLog(room_id, current_round, round_state_type
|
||||
, player.getUserGuid(), player.getUserNickname(), charged_step, rewarded_step, rewards);
|
||||
|
||||
batch.appendBusinessLog(business_log);
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
|
||||
if (result.isFail()) return result;
|
||||
|
||||
//보상 내용 가져올것
|
||||
var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents);
|
||||
NullReferenceCheckHelper.throwIfNull(found_transaction_runner, () => $"found_transaction_runner is null !!! - {player.toBasicString()}");
|
||||
common_result = found_transaction_runner.getCommonResult();
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid(),
|
||||
TransactionIdType.PrivateContents, BattleConstant.BATTLE_INSTANCE_TRANSACTION_NAME, fn_pod_combat_reward_update);
|
||||
if (result.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()}, {battleInstanceRoom.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom);
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_REWARD(battleInstanceRoom, occupier_guid, common_result);
|
||||
if (need_pod_combat_noti)
|
||||
{
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battleInstanceRoom);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Result> battleInstanceEndStateUpdate(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
var result = new Result();
|
||||
await Task.CompletedTask;
|
||||
|
||||
var all_round_end_time = attribute.m_combat_pod_mode.m_current_state_start_time;
|
||||
var end_time = all_round_end_time.AddSeconds(battleInstanceRoom.m_ffa_config_meta.ResultUIWaitTime);
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
if (now < end_time) return result;
|
||||
|
||||
using (var releaser = await battleInstanceRoom.getAsyncLock())
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.Destroyed;
|
||||
attribute.m_combat_pod_mode.m_current_state_start_time = end_time;
|
||||
}
|
||||
|
||||
var users = battleInstanceRoom.m_instance_room.tryGetInstanceExistUserForLog();
|
||||
|
||||
//여기서 배틀 인스턴스가 완전히 shutdown 됐다는 Noti 전달
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom);
|
||||
|
||||
//log 추가
|
||||
var invokers = new List<ILogInvoker>();
|
||||
var log_action = new LogActionEx(LogActionType.BattleRoundStateUpdate);
|
||||
|
||||
var room_id = battleInstanceRoom.m_instance_room.getMap().m_room_id;
|
||||
var ended_round = attribute.m_combat_pod_mode.m_current_round;
|
||||
var round_state = attribute.m_combat_pod_mode.m_round_state_type;
|
||||
BattleRoundUpdateBusinessLog business_log = new(room_id, ended_round, round_state, users);
|
||||
invokers.Add(business_log);
|
||||
BusinessLogger.collectLogs(log_action, battleInstanceRoom, invokers);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Nettention.Proud;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public partial class BattleInstanceUpdateAction : EntityActionBase
|
||||
{
|
||||
public BattleInstanceUpdateAction(EntityBase owner) : base(owner)
|
||||
{
|
||||
}
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
public override void onClear()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task<Result> update()
|
||||
{
|
||||
var battle_instance_room = getOwner() as BattleInstanceRoom;
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room, () => $"battle_instance_room is null !!!");
|
||||
var attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
var result = await battleObjectStateUpdate(battle_instance_room, attribute);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error($"battleObjectStateUpdate result error !!! result : {result.toBasicString()}");
|
||||
return result;
|
||||
}
|
||||
|
||||
result = await battleInstanceStateUpdate(battle_instance_room, attribute);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error($"battleInstanceStateUpdate result error !!! result : {result.toBasicString()}");
|
||||
return result;
|
||||
}
|
||||
|
||||
result = await battleInstancHostUpdate(battle_instance_room);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error($"battleInstancHostUpdate result error !!! result : {result.toBasicString()}");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> battleInstancHostUpdate(BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
var result = new Result();
|
||||
string host_user_guid = string.Empty;
|
||||
var is_migrated = false;
|
||||
using (var releaser = await battleInstanceRoom.getAsyncLock())
|
||||
{
|
||||
//이미 host 지정이 끝났으면 리턴
|
||||
//kihoon todo : 일단 계속 체크해서 호스트가 얼마나 바뀌는지 확인 해보고 적절한 주기 찾아볼것
|
||||
//if (!battleInstanceRoom.m_host_migrator.getHostUserGuid().Equals(string.Empty)) return result;
|
||||
var host_migrator = battleInstanceRoom.m_host_migrator;
|
||||
// TODO : 인터페이스 변경 예정
|
||||
(result, is_migrated) = host_migrator.migrateCheck();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
if (is_migrated)
|
||||
{
|
||||
host_user_guid = host_migrator.getHostUserGuid();
|
||||
}
|
||||
}
|
||||
|
||||
if (is_migrated)
|
||||
{
|
||||
Log.getLogger().info($"battleInstancHost set complete host_user_guid : {host_user_guid}");
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_P2P_HOST_UPDATE(battleInstanceRoom.m_instance_room, host_user_guid);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> battleObjectStateUpdate(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
var result = new Result();
|
||||
await Task.CompletedTask;
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
List<BattleObjectInfo> infos = new();
|
||||
List<BattleObjectLogInfo> log_infos = new();
|
||||
using (var releaser = await battleInstanceRoom.getAsyncLock())
|
||||
{
|
||||
(var weapon_info, var weapon_log_info) = battleObjectWeaponStateUpdate(attribute, now);
|
||||
infos.AddRange(weapon_info);
|
||||
log_infos.AddRange(weapon_log_info);
|
||||
|
||||
(var buff_info, var buff_log_info) = battleObjectBuffStateUpdate(attribute, now);
|
||||
infos.AddRange(buff_info);
|
||||
log_infos.AddRange(buff_log_info);
|
||||
|
||||
|
||||
(var pickup_pod_info, var pickup_pod_log_info) = battleObjectPickupPodUpdate(attribute, now);
|
||||
infos.AddRange(pickup_pod_info);
|
||||
log_infos.AddRange(pickup_pod_log_info);
|
||||
}
|
||||
|
||||
if (infos.Count > 0)
|
||||
{
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(battleInstanceRoom, infos);
|
||||
|
||||
var invokers = new List<ILogInvoker>();
|
||||
var log_action = new LogActionEx(LogActionType.BattleObjectStateUpdate);
|
||||
var business_log = new BattleObjectStateUpdateBusinessLog(battleInstanceRoom.m_instance_room.getMap().m_room_id, log_infos);
|
||||
invokers.Add(business_log);
|
||||
BusinessLogger.collectLogs(log_action, battleInstanceRoom, invokers);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private (List<BattleObjectInfo>, List<BattleObjectLogInfo>) battleObjectPickupPodUpdate(BattleInstanceSnapshotAttribute attribute, DateTime now)
|
||||
{
|
||||
// if (attribute.m_combat_pod_mode.m_round_state_type.Equals(BattleRoundStateType.RoundEndAll) ||
|
||||
// attribute.m_combat_pod_mode.m_round_state_type.Equals(BattleRoundStateType.Destroyed)) return new();
|
||||
|
||||
List<BattleObjectInfo> infos = new();
|
||||
List<BattleObjectLogInfo> log_infos = new();
|
||||
var battle_instance_room = getOwner() as BattleInstanceRoom;
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room, () => $"battle_instance_room is null !!!");
|
||||
|
||||
foreach (var generated_info in attribute.m_combat_pod_mode.m_pickup_pod_generated_info)
|
||||
{
|
||||
var group_id = generated_info.Key.Item1;
|
||||
var idx = generated_info.Key.Item2;
|
||||
|
||||
if (false == attribute.m_combat_pod_mode.m_pickup_pod_generated_info.TryGetValue(generated_info.Key, out var generatedInfo))
|
||||
{
|
||||
Log.getLogger().error($"m_pickup_pod_generated_info i : {idx} not exist!!!");
|
||||
continue;
|
||||
}
|
||||
|
||||
var anchor_guid = generatedInfo.m_anchor_guid;
|
||||
var next_generated_time = generatedInfo.m_next_generate_time;
|
||||
|
||||
//아직 시간이 안됐거나, 할당된게 있으면 continue;
|
||||
if (now < next_generated_time || anchor_guid.Equals(string.Empty) == false) continue;
|
||||
|
||||
//비어 있으면 할당 해준다. 시간체크는 보상 받았을때 해준다.
|
||||
(var result, var allocated_anchor_guid) = BattleRoomHelper.getRandomPickupPod(group_id, idx, battle_instance_room, attribute);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger(result.toBasicString());
|
||||
continue;
|
||||
}
|
||||
|
||||
if(false == battle_instance_room.m_instance_room.getMap().getAnchors().TryGetValue(allocated_anchor_guid, out var anchorInfo))
|
||||
{
|
||||
Log.getLogger().error($"not exist anchor anchor_guid : {allocated_anchor_guid}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var table_id = anchorInfo.AnchorProp.TableId;
|
||||
if (false == MetaData.Instance._BattleObjectSpawnGroupMetaTable.TryGetValue(table_id, out var battle_object_spawn_group))
|
||||
{
|
||||
Log.getLogger().error($"not exist _BattleObjectSpawnGroupMetaTable anchor_guid : {allocated_anchor_guid}, tableid : {table_id}");
|
||||
continue;
|
||||
}
|
||||
|
||||
PickupPodGeneratedInfo new_generated_info = new(generated_info.Key.Item1, generated_info.Key.Item2, allocated_anchor_guid, generatedInfo.m_anchor_guid, generatedInfo.m_next_generate_time);
|
||||
|
||||
attribute.m_combat_pod_mode.m_pickup_pod_generated_info.AddOrUpdate(generated_info.Key, new_generated_info, (i, tuple) => new_generated_info);
|
||||
if (false == attribute.m_combat_pod_mode.m_pickup_pods.TryGetValue(allocated_anchor_guid, out var pickupPod))
|
||||
{
|
||||
var err_msg = $"pickup pod date not exist !! allocated_anchor_guid : {allocated_anchor_guid}, roomId : {battle_instance_room.m_instance_room.getMap().m_room_id}";
|
||||
Log.getLogger().error(err_msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
pickupPod.m_is_active = true;
|
||||
|
||||
BattleObjectInfo info = new();
|
||||
info.AnchorGuid = allocated_anchor_guid;
|
||||
info.IsActive = pickupPod.m_is_active ? BoolType.True : BoolType.False;
|
||||
infos.Add(info);
|
||||
|
||||
BattleObjectLogInfo log_info = new();
|
||||
log_info.m_anchor_guid = pickupPod.m_anchor_guid;
|
||||
log_info.m_battle_object_type = pickupPod.m_type;
|
||||
log_info.m_active_time = pickupPod.m_active_time;
|
||||
log_infos.Add(log_info);
|
||||
}
|
||||
|
||||
|
||||
return (infos, log_infos);
|
||||
}
|
||||
|
||||
private (List<BattleObjectInfo>, List<BattleObjectLogInfo>) battleObjectBuffStateUpdate(BattleInstanceSnapshotAttribute attribute, DateTime now)
|
||||
{
|
||||
List<BattleObjectInfo> infos = new();
|
||||
List<BattleObjectLogInfo> log_infos = new();
|
||||
foreach (BattleObjectBuff buff in attribute.m_combat_pod_mode.m_buffs.Values)
|
||||
{
|
||||
if (buff.m_active_time <= now && buff.m_is_active == false)
|
||||
{
|
||||
buff.m_is_active = true;
|
||||
|
||||
BattleObjectInfo info = new();
|
||||
info.AnchorGuid = buff.m_anchor_guid;
|
||||
info.IsActive = BoolType.True;
|
||||
infos.Add(info);
|
||||
|
||||
BattleObjectLogInfo log_info = new();
|
||||
log_info.m_anchor_guid = buff.m_anchor_guid;
|
||||
log_info.m_battle_object_type = buff.m_type;
|
||||
log_info.m_active_time = buff.m_active_time;
|
||||
log_infos.Add(log_info);
|
||||
}
|
||||
}
|
||||
|
||||
return (infos, log_infos);
|
||||
}
|
||||
|
||||
private (List<BattleObjectInfo>, List<BattleObjectLogInfo>) battleObjectWeaponStateUpdate(BattleInstanceSnapshotAttribute attribute, DateTime now)
|
||||
{
|
||||
List<BattleObjectInfo> infos = new();
|
||||
List<BattleObjectLogInfo> log_infos = new();
|
||||
foreach (BattleObjectWeapon weapon in attribute.m_combat_pod_mode.m_weapons.Values)
|
||||
{
|
||||
if (weapon.m_active_time <= now && weapon.m_is_active == false)
|
||||
{
|
||||
weapon.m_is_active = true;
|
||||
|
||||
BattleObjectInfo info = new();
|
||||
info.AnchorGuid = weapon.m_anchor_guid;
|
||||
info.IsActive = BoolType.True;
|
||||
infos.Add(info);
|
||||
|
||||
BattleObjectLogInfo log_info = new();
|
||||
log_info.m_anchor_guid = weapon.m_anchor_guid;
|
||||
log_info.m_battle_object_type = weapon.m_type;
|
||||
log_info.m_active_time = weapon.m_active_time;
|
||||
log_infos.Add(log_info);
|
||||
}
|
||||
}
|
||||
|
||||
return (infos, log_infos);
|
||||
}
|
||||
|
||||
public Result battleObjectStateInitAndNotify(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
var infos = new List<BattleObjectInfo>();
|
||||
var result = new Result();
|
||||
|
||||
foreach (BattleObjectPodStorage storage in attribute.m_combat_pod_mode.m_pod_storages.Values)
|
||||
{
|
||||
storage.m_reward_cnt = 0;
|
||||
|
||||
storage.m_is_active = true;
|
||||
BattleObjectInfo info = new();
|
||||
info.AnchorGuid = storage.m_anchor_guid;
|
||||
info.IsActive = BoolType.True;
|
||||
infos.Add(info);
|
||||
}
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(battleInstanceRoom, infos);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public async Task<Result> createCombatPod(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
var result = new Result();
|
||||
var combat_pod_guid = System.Guid.NewGuid().ToString("N");
|
||||
|
||||
(result, var anchor_guid) = BattleRoomHelper.getRandomCombatPodAnchorGuid(attribute, battleInstanceRoom);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
attribute.m_combat_pod_mode.m_pod_combat = new BattleObjectPodCombat(combat_pod_guid, anchor_guid, DateTimeHelper.Current);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public async Task<Result> createPickupPodReward(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
var result = new Result();
|
||||
|
||||
var max_reward_count = 0;
|
||||
foreach (var pickup_pod_group in battleInstanceRoom.m_battle_pickup_pod_guid_group)
|
||||
{
|
||||
var group_id = pickup_pod_group.Key;
|
||||
|
||||
var pickup_pod_guids = pickup_pod_group.Value;
|
||||
|
||||
foreach (var guid in pickup_pod_guids)
|
||||
{
|
||||
if (false == battleInstanceRoom.m_instance_room.getMap().getAnchors().TryGetValue(guid, out var anchorInfo))
|
||||
{
|
||||
var err_msg = $"Not exitst anchorInfo guid : {guid}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceNotExistAnchors, err_msg);
|
||||
Log.getLogger(result.toBasicString());
|
||||
continue;
|
||||
}
|
||||
|
||||
var table_id = anchorInfo.AnchorProp.TableId;
|
||||
if (false == MetaData.Instance._BattleObjectSpawnGroupMetaTable.TryGetValue(table_id, out var objectSpawnGroupMetaData))
|
||||
{
|
||||
var err_msg = $"Not exitst objectSpawnGroupMetaData guid : {guid}, tableId : {table_id}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceObjectMetaNotExist, err_msg);
|
||||
Log.getLogger(result.toBasicString());
|
||||
continue;
|
||||
}
|
||||
|
||||
max_reward_count = objectSpawnGroupMetaData.MaxSpawnQuantity;
|
||||
break;
|
||||
}
|
||||
|
||||
await createPickupPodRewardByGroup(battleInstanceRoom, attribute, group_id, max_reward_count);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task<Result> createPickupPodRewardByGroup(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, Int32 groupId, Int32 maxRewardCount)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
for (int i = 0; i < maxRewardCount; i++)
|
||||
{
|
||||
(result, var anchor_guid) = BattleRoomHelper.getRandomPickupPod(groupId, i, battleInstanceRoom, attribute);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
PickupPodGeneratedInfo new_generated_info = new(groupId, i, anchor_guid, string.Empty, DateTimeHelper.Current);
|
||||
|
||||
if(false == attribute.m_combat_pod_mode.m_pickup_pod_generated_info.TryGetValue((groupId, i), out var generatedInfo))
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_pickup_pod_generated_info.TryAdd((groupId, i), new_generated_info);
|
||||
}
|
||||
if (generatedInfo is not null)
|
||||
{
|
||||
new_generated_info.m_before_anchor_guid = generatedInfo.m_anchor_guid;
|
||||
}
|
||||
|
||||
Log.getLogger().info($"create pickup pod generation info new_generated_info : {JsonConvert.SerializeObject(new_generated_info)}");
|
||||
|
||||
attribute.m_combat_pod_mode.m_pickup_pod_generated_info.AddOrUpdate((groupId, i), new_generated_info, (key, tuple) => new_generated_info);
|
||||
if (false == attribute.m_combat_pod_mode.m_pickup_pods.TryGetValue(anchor_guid, out var pickupPod))
|
||||
{
|
||||
Log.getLogger().error($"create pickup pod reward not exista anchor guid : {anchor_guid} origin keys : {JsonConvert.SerializeObject(attribute.m_combat_pod_mode.m_pickup_pods.Keys)}");
|
||||
continue;
|
||||
}
|
||||
pickupPod.m_is_active = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<(Result, List<MetaAssets.Reward>, int, int)> podCombatUpdateIfHasOccupier(BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, Player player)
|
||||
{
|
||||
var result = new Result();
|
||||
var occupier_guid = attribute.m_combat_pod_mode.m_pod_combat.m_current_occupier_guid;
|
||||
if (occupier_guid.Equals(string.Empty)) return (result, new(), 0, 0);
|
||||
|
||||
var max_charge_level = battleInstanceRoom.m_ffa_reward_meta
|
||||
.Where(kvp => kvp.Key == battleInstanceRoom.m_ffa_reward_meta.Keys.Max())
|
||||
.Select(kvp => kvp.Key)
|
||||
.FirstOrDefault();
|
||||
|
||||
var rewardable_step_start = attribute.m_combat_pod_mode.m_rewarded_step;
|
||||
var rewardable_step_end = max_charge_level;
|
||||
|
||||
var rewards = makePodCombatOccupyReward(rewardable_step_start, rewardable_step_end, battleInstanceRoom);
|
||||
result = await addPodCommbatOccupyReward(player, battleInstanceRoom, rewards);
|
||||
if (result.isFail()) return (result, new(), 0, 0);
|
||||
|
||||
attribute.m_combat_pod_mode.m_rewarded_step = max_charge_level;
|
||||
attribute.m_combat_pod_mode.m_charged_step = max_charge_level;
|
||||
|
||||
return (result, rewards, rewardable_step_start, rewardable_step_end);
|
||||
|
||||
}
|
||||
|
||||
private async Task<Result> addPodCommbatOccupyReward(Player player, BattleInstanceRoom battleInstanceRoom, List<MetaAssets.Reward> rewards)
|
||||
{
|
||||
IReward reward_proc = new RewardPodCombat(player, player.getUserGuid(), rewards);
|
||||
var result = await RewardManager.It.proceedRewardProcess(reward_proc);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
RewardManager.It.postRewardProcess(reward_proc);
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<MetaAssets.Reward> makePodCombatOccupyReward(int start, int end, BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
List<MetaAssets.Reward> rewards = new();
|
||||
|
||||
for (int i = start + 1; i <= end; i++)
|
||||
{
|
||||
if (i == 0) continue;
|
||||
if (false == battleInstanceRoom.m_ffa_reward_meta.TryGetValue(i, out var ffaRewardData))
|
||||
{
|
||||
Log.getLogger().error($"m_ffa_reward_meta not exist battleInstanceRoom i : {i}, meta : {JsonConvert.SerializeObject(battleInstanceRoom.m_ffa_reward_meta)}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var item_id = ffaRewardData.RewardItemID;
|
||||
var item_count = ffaRewardData.RewardCount * battleInstanceRoom.m_hot_time_reward;
|
||||
|
||||
RewardMutable reward_metable = new();
|
||||
reward_metable.Item = new();
|
||||
reward_metable.Item.Id = item_id;
|
||||
reward_metable.Item.Count = item_count;
|
||||
|
||||
MetaAssets.Reward reward = new MetaAssets.Reward(reward_metable);
|
||||
|
||||
rewards.Add(reward);
|
||||
|
||||
Log.getLogger().Debug($"pod Combat reward Added step : {i}, ItemId : {item_id}, itemCount : {item_count}");
|
||||
}
|
||||
|
||||
|
||||
return rewards;
|
||||
}
|
||||
|
||||
private List<BattleObjectInfo> battleObjectPickupPodsDeactive(BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
List<BattleObjectInfo> infos = new();
|
||||
|
||||
foreach (var pickup in attribute.m_combat_pod_mode.m_pickup_pods.Values)
|
||||
{
|
||||
pickup.m_is_active = false;
|
||||
BattleObjectInfo info = new();
|
||||
info.AnchorGuid = pickup.m_anchor_guid;
|
||||
info.IsActive = BoolType.False;
|
||||
infos.Add(info);
|
||||
}
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
foreach(var generated_info in attribute.m_combat_pod_mode.m_pickup_pod_generated_info)
|
||||
{
|
||||
var idx = generated_info.Key;
|
||||
var anchor_guid = generated_info.Value.m_anchor_guid;
|
||||
var next_generated_time = generated_info.Value.m_next_generate_time;
|
||||
|
||||
PickupPodGeneratedInfo new_info = new(idx.Item1, idx.Item2, string.Empty, string.Empty, now);
|
||||
|
||||
attribute.m_combat_pod_mode.m_pickup_pod_generated_info.AddOrUpdate(idx, new_info, (i, tuple) => new_info);
|
||||
}
|
||||
|
||||
return infos;
|
||||
}
|
||||
|
||||
|
||||
private List<BattleObjectInfo> battleObjectPodStoragesDeactive(BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
List<BattleObjectInfo> infos = new();
|
||||
foreach (var sotrage in attribute.m_combat_pod_mode.m_pod_storages.Values)
|
||||
{
|
||||
sotrage.m_is_active = false;
|
||||
BattleObjectInfo info = new();
|
||||
info.AnchorGuid = sotrage.m_anchor_guid;
|
||||
info.IsActive = BoolType.False;
|
||||
infos.Add(info);
|
||||
}
|
||||
|
||||
return infos;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using Newtonsoft.Json;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
internal partial class LocationAction
|
||||
{
|
||||
public async Task<Result> tryMoveToBattleIndun(InstanceRoomInfo instanceRoomInfo, Pos? enterPos = null, bool isReturn = false)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var location_attribute = player.getEntityAttribute<LocationAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(location_attribute, () => $"location_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
NullReferenceCheckHelper.throwIfNull(m_current_loaction, () => $"m_current_loaction is null !!! - {player.toBasicString()}");
|
||||
NullReferenceCheckHelper.throwIfNull(m_location_cache_request_nullable, () => "Current Location Cache is null !!");
|
||||
|
||||
if (!MetaData.Instance._IndunTable.TryGetValue(instanceRoomInfo.InstanceId, out var indun_data))
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TryGetValue() !!! : instanceMetaId:{instanceRoomInfo.InstanceId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.InstanceMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (server_logic.getServerType().toServerType() == ServerType.Channel)
|
||||
{
|
||||
location_attribute.LastestChannelServerLocation.ServerName = server_logic.getServerName();
|
||||
location_attribute.LastestChannelServerLocation.WorldMetaId = (int)server_logic.getWorldId();
|
||||
location_attribute.LastestChannelServerLocation.SpawnPos = m_current_loaction.SpawnPos;
|
||||
location_attribute.LastestChannelServerLocation.ForwardAngle = m_current_loaction.ForwardAngle;
|
||||
|
||||
server_logic.getReturnManager().addReturnUser(player.getUserGuid());
|
||||
}
|
||||
else if (isReturn == false)
|
||||
{
|
||||
IndunLocation indun_location = new();
|
||||
|
||||
indun_location.InstanceRoomId = location_attribute.CurrentIndunLocation.InstanceRoomId;
|
||||
indun_location.InstanceMetaId = location_attribute.CurrentIndunLocation.InstanceMetaId;
|
||||
indun_location.SpawnPos = m_current_loaction.SpawnPos;
|
||||
indun_location.ForwardAngle = m_current_loaction.ForwardAngle;
|
||||
|
||||
location_attribute.ReturnIndunLocations.Add(indun_location);
|
||||
|
||||
server_logic.getReturnManager().addReturnUser(player.getUserGuid());
|
||||
}
|
||||
|
||||
if (enterPos != null)
|
||||
{
|
||||
enterPos.Z += 100;
|
||||
}
|
||||
|
||||
location_attribute.EnterIndunLocation.InstanceRoomId = instanceRoomInfo.roomId;
|
||||
location_attribute.EnterIndunLocation.InstanceMetaId = instanceRoomInfo.InstanceId;
|
||||
location_attribute.EnterIndunLocation.fromPos(enterPos == null ? MapManager.Instance.GetStartPos(indun_data.RoomFile) : enterPos);
|
||||
location_attribute.modifiedEntityAttribute();
|
||||
|
||||
var location_cache = m_location_cache_request_nullable.getLocationCache();
|
||||
NullReferenceCheckHelper.throwIfNull(location_cache, () => $"location_cache is null !!! - {player.toBasicString()}");
|
||||
|
||||
location_cache.copyCacheFromEntityAttribute(location_attribute);
|
||||
|
||||
result = await m_location_cache_request_nullable.upsertLocation();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to upsertLocation() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public LocationCacheRequest? getBattleLocationCacheRequestNullable()
|
||||
{
|
||||
return m_location_cache_request_nullable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
using MetaAssets;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleObjectInteractAction : EntityActionBase
|
||||
{
|
||||
public BattleObjectInteractAction(EntityBase owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
public override void onClear()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task<Result> interactCommonBattleObject(BattleObjectInteractionLogicHandler handler, Player player)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
var result = new Result();
|
||||
updateBattleObjectActiveInfo(handler);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public async Task<Result> interactPickupPod(BattleObjectInteractionLogicHandler handler, Player player)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
var result = new Result();
|
||||
|
||||
updateBattleObjectActiveInfo(handler);
|
||||
|
||||
Log.getLogger().info($"interaction pickup pod player : {player.toBasicString()}, guid : {handler.m_interaction_anchor_guid}, next active time : {handler.m_battle_object.m_active_time}");
|
||||
|
||||
var battle_instance_room = getOwner() as BattleInstanceRoom;
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room, () => $"battle_instance_room is null !!!");
|
||||
var attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
//보상처리
|
||||
var reward_action = battle_instance_room.getEntityAction<BattleObjectRewardAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(reward_action, () => $"handler.m_pod_combat is null !!!");
|
||||
result = await reward_action.pickupPodReward(player, attribute, handler);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> interactPodStorage(BattleObjectInteractionLogicHandler handler, Player player)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
var result = new Result();
|
||||
|
||||
var battle_instance_room = getOwner() as BattleInstanceRoom;
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room, () => $"battle_instance_room is null !!!");
|
||||
var attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
|
||||
bool has_pod_combat = hasPodCombat(handler.m_interaction_anchor_guid, attribute, handler);
|
||||
|
||||
handler.m_interaction_log_info.m_has_pod_combat = has_pod_combat;
|
||||
handler.m_interaction_log_info.m_pod_type = ECombatPodType.Storage;
|
||||
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
if (has_pod_combat)
|
||||
{
|
||||
NullReferenceCheckHelper.throwIfNull(handler.m_pod_combat, () => $"handler.m_pod_combat is null !!!");
|
||||
var pod_combat = handler.m_pod_combat;
|
||||
handler.m_is_need_combat_pod_noti = true;
|
||||
pod_combat.m_state = PodCombatStateType.Possesion;
|
||||
pod_combat.m_currenct_Pos = player.getCurrentPositionInfo().Pos;
|
||||
pod_combat.m_state_change_time = now;
|
||||
pod_combat.m_active_time = now;
|
||||
pod_combat.m_current_occupier_guid = player.getUserGuid();
|
||||
pod_combat.m_occupied_time = now;
|
||||
|
||||
foreach (var stand in attribute.m_combat_pod_mode.m_pod_storages.Values)
|
||||
{
|
||||
stand.m_is_active = false;
|
||||
handler.m_need_noti_objects.Add(stand);
|
||||
}
|
||||
|
||||
handler.m_interaction_log_info.m_pod_combat_pos = pod_combat.m_currenct_Pos;
|
||||
handler.m_interaction_log_info.m_pod_combat_state = pod_combat.m_state;
|
||||
}
|
||||
else
|
||||
{
|
||||
//보상 줘야되면 보상 처리
|
||||
var reward_action = battle_instance_room.getEntityAction<BattleObjectRewardAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(reward_action, () => $"handler.m_pod_combat is null !!!");
|
||||
result = await reward_action.podStorageReward(player, attribute, handler);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void updateBattleObjectActiveInfo(BattleObjectInteractionLogicHandler handler)
|
||||
{
|
||||
var now = DateTimeHelper.Current;
|
||||
var next_active_time = now.AddSeconds(handler.m_battle_object_meta.RespawnTime);
|
||||
handler.m_object_active_time = handler.m_interaction_log_info.m_object_next_active_time = handler.m_battle_object.m_active_time = next_active_time;
|
||||
handler.m_battle_object.m_is_active = handler.m_interaction_log_info.m_is_active = false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public async Task<Result> interactPodCombat(BattleObjectInteractionLogicHandler handler, Player player)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
|
||||
var battle_instance_room = getOwner() as BattleInstanceRoom;
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room, () => $"battle_instance_room is null !!!");
|
||||
|
||||
string err_msg = string.Empty;
|
||||
var attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"battle_instance_attribute is null !!!");
|
||||
|
||||
var combat_pod = handler.m_pod_combat = attribute.m_combat_pod_mode.m_pod_combat;
|
||||
|
||||
if (false == combat_pod.m_current_occupier_guid.Equals(string.Empty) && false == combat_pod.m_state.Equals(PodCombatStateType.Dropped))
|
||||
{
|
||||
//다른 유저가 소유중일때는 상호 작용 할수 없다.
|
||||
err_msg = $"Pod Combat Already accupied Player : {player.toBasicString()}, possessioned user : {combat_pod.m_current_occupier_guid}";
|
||||
result.setFail(ServerErrorCode.BattleInstancePodCombatAlreadyOccupy, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
handler.m_is_need_combat_pod_noti = true;
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
combat_pod.m_state = PodCombatStateType.Possesion;
|
||||
combat_pod.m_currenct_Pos = player.getCurrentPositionInfo().Pos;
|
||||
combat_pod.m_state_change_time = now;
|
||||
combat_pod.m_current_occupier_guid = player.getUserGuid();
|
||||
combat_pod.m_occupied_time = now;
|
||||
|
||||
|
||||
handler.m_interaction_log_info.m_battle_object_type = EBattleObjectType.Pod_Combat;
|
||||
handler.m_interaction_log_info.m_pod_type = ECombatPodType.Pod;
|
||||
handler.m_interaction_log_info.m_pod_combat_pos = combat_pod.m_currenct_Pos;
|
||||
handler.m_interaction_log_info.m_pod_combat_state = combat_pod.m_state;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private bool hasPodCombat(string anchorGuid, BattleInstanceSnapshotAttribute attribute, BattleObjectInteractionLogicHandler handler)
|
||||
{
|
||||
var pod_combat = attribute.m_combat_pod_mode.m_pod_combat;
|
||||
if (pod_combat.m_source_storage_anchor_guid.Equals(anchorGuid) && pod_combat.m_state.Equals(PodCombatStateType.Active))
|
||||
{
|
||||
handler.m_pod_combat = pod_combat;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
using GameServer.Contents.Battle.Reward;
|
||||
using MetaAssets;
|
||||
using Newtonsoft.Json;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleObjectRewardAction : EntityActionBase
|
||||
{
|
||||
public BattleObjectRewardAction(EntityBase owner) : base(owner)
|
||||
{
|
||||
}
|
||||
public override Task<Result> onInit()
|
||||
{
|
||||
var result = new Result();
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
public override void onClear() { }
|
||||
|
||||
|
||||
public async Task<Result> podStorageReward(Player player, BattleInstanceSnapshotAttribute attribute, BattleObjectInteractionLogicHandler handler)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
if (false == attribute.m_combat_pod_mode.m_pod_storages.TryGetValue(handler.m_interaction_anchor_guid, out var podStorage))
|
||||
{
|
||||
Log.getLogger().error($"Not exist pod storage anchor : {handler.m_interaction_anchor_guid}, player : {player.toBasicString()}");
|
||||
result.setFail(ServerErrorCode.BattleInstanceObjectMetaNotExist, result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
if (1 <= podStorage.m_reward_cnt)
|
||||
{
|
||||
return result; //이건 에러는 아니다.
|
||||
}
|
||||
podStorage.m_reward_cnt++;
|
||||
|
||||
var pod_storage_meta = MetaData.Instance._BattlePodStorageMeta;
|
||||
|
||||
var reward_id = pod_storage_meta.TypeID;
|
||||
var reward_count = pod_storage_meta.ObjectValue;
|
||||
|
||||
var battle_instance_room = getOwner() as BattleInstanceRoom;
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room, () => $"battle_instance_room is null !!!");
|
||||
|
||||
RewardMutable reward_metable = new();
|
||||
reward_metable.Item = new();
|
||||
reward_metable.Item.Id = reward_id;
|
||||
reward_metable.Item.Count = reward_count * battle_instance_room.m_hot_time_reward;
|
||||
MetaAssets.Reward reward = new MetaAssets.Reward(reward_metable);
|
||||
List<MetaAssets.Reward> rewards = new(){reward};
|
||||
|
||||
IReward reward_proc = new RewardPodStorage(player, player.getUserGuid(), rewards);
|
||||
result = await RewardManager.It.proceedRewardProcess(reward_proc);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
handler.m_interaction_log_info.m_rewards.AddRange(rewards);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> pickupPodReward(Player player, BattleInstanceSnapshotAttribute attribute, BattleObjectInteractionLogicHandler handler)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
string err_msg = string.Empty;
|
||||
|
||||
if (false == attribute.m_combat_pod_mode.m_pickup_pods.TryGetValue(handler.m_interaction_anchor_guid, out var pickupPod))
|
||||
{
|
||||
err_msg = $"Not exist pickup pod anchor : {handler.m_interaction_anchor_guid}, player : {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.BattleInstanceObjectMetaNotExist, err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
var battle_instance_room = getOwner() as BattleInstanceRoom;
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room, () => $"battle_instance_room is null !!!");
|
||||
|
||||
Int32 idx = Int32.MinValue;
|
||||
Int32 group_id = 0;
|
||||
string rewarded_anchor_guid = String.Empty;
|
||||
foreach (var generated_info in attribute.m_combat_pod_mode.m_pickup_pod_generated_info)
|
||||
{
|
||||
var generated_info_tuple = generated_info.Value;
|
||||
|
||||
|
||||
if (false == handler.m_interaction_anchor_guid.Equals(generated_info_tuple.m_anchor_guid))
|
||||
{
|
||||
Log.getLogger().info($"m_pickup_pod_generated_info data interaction anchor_guid : {handler.m_interaction_anchor_guid}, reward setted anchor_guid : {generated_info_tuple.m_anchor_guid} ");
|
||||
continue;
|
||||
}
|
||||
|
||||
(group_id, idx) = generated_info.Key;
|
||||
rewarded_anchor_guid = generated_info_tuple.m_anchor_guid;
|
||||
Log.getLogger().info($"rewarded_anchor_guid rewarded_anchor_guid : {rewarded_anchor_guid}, groupId : {group_id}, idx : {idx}");
|
||||
break;
|
||||
}
|
||||
|
||||
if (idx == Int32.MinValue) return result; //보상줄게 없다는 얘기이므로 그량 리턴
|
||||
if(false == battle_instance_room.m_instance_room.getMap().getAnchors().TryGetValue(handler.m_interaction_anchor_guid, out var anchorInfo))
|
||||
{
|
||||
err_msg = $"not exist anchor anchor_guid : {handler.m_interaction_anchor_guid}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.BattleInstanceNotExistAnchors, err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
var table_id = anchorInfo.AnchorProp.TableId;
|
||||
if (false == MetaData.Instance._BattleObjectSpawnGroupMetaTable.TryGetValue(table_id, out var battle_object_spawn_group))
|
||||
{
|
||||
err_msg = $"not exist _BattleObjectSpawnGroupMetaTable anchor_guid : {handler.m_interaction_anchor_guid}, tableid : {table_id}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.BattleInstanceObjectMetaNotExist, err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
var next_gen_time = now.AddSeconds(battle_object_spawn_group.RespawnTime);
|
||||
PickupPodGeneratedInfo assigned_generated_info = new(group_id, idx, string.Empty, rewarded_anchor_guid, next_gen_time);
|
||||
attribute.m_combat_pod_mode.m_pickup_pod_generated_info.AddOrUpdate((group_id, idx), assigned_generated_info, (key, existingValue) => assigned_generated_info);
|
||||
|
||||
var pickup_pod_meta = MetaData.Instance._BattlePickupPodMeta;
|
||||
RewardMutable reward_metable = new();
|
||||
reward_metable.Item = new();
|
||||
reward_metable.Item.Id = pickup_pod_meta.TypeID;
|
||||
reward_metable.Item.Count = pickup_pod_meta.ObjectValue * battle_instance_room.m_hot_time_reward;
|
||||
MetaAssets.Reward reward = new MetaAssets.Reward(reward_metable);
|
||||
List<MetaAssets.Reward> rewards = new(){reward};
|
||||
|
||||
Log.getLogger().info($"pickup pods reward : {JsonConvert.SerializeObject(rewards)}");
|
||||
IReward reward_proc = new RewardPickupPod(player, player.getUserGuid(), rewards);
|
||||
result = await RewardManager.It.proceedRewardProcess(reward_proc);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
handler.m_interaction_log_info.m_rewards.AddRange(rewards);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public partial class GameZoneMoveAction
|
||||
{
|
||||
public async Task<(Result, ServerConnectInfo?, List<ILogInvoker>)> tryJoinBattleInstance(USER_GUID userGuid, Int32 eventId, Timestamp eventStartTS, InstanceMetaData instanceMetaData)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_connect_info = new ServerConnectInfo();
|
||||
var business_logs = new List<ILogInvoker>();
|
||||
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!");
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
//아이템 혹은 재화 사용해서 입장하는건지, 퍼블릭인지 그에 맞게 조건을 체크하는 함수. 아직 기획적인 내용은 없어서 주석처리..
|
||||
// result = player.checkInstanceAccess(instanceMetaId);
|
||||
// if (result.isFail())
|
||||
// {
|
||||
// err_msg = $"Failed to checkInstanceAccess() !!! : {result.toBasicString()}";
|
||||
// Log.getLogger().error(err_msg);
|
||||
//
|
||||
// return (result, null, business_logs);
|
||||
// }
|
||||
|
||||
//현재 포지션은 departure pos 가 된다. 관련한 로그 처리
|
||||
var departure_position_info = player.getCurrentPositionInfo();
|
||||
var departure_position_log_info = PositionBusinessLogHelper.toPositionLogInfo(PositionMoveType.Departure, departure_position_info);
|
||||
var departure_position_business_log = new PositionBusinessLog(departure_position_log_info);
|
||||
business_logs.Add(departure_position_business_log);
|
||||
|
||||
BattleInstanceRoomHandler battle_instance_room_handler = new(player.getUserGuid(), instanceMetaData);
|
||||
//적절한 인스턴스 가져오고, 없으면 생성해서 Join처리
|
||||
(result, var instance_room_id) = await battle_instance_room_handler.joinBattleInstance(player.getUserGuid(), eventId, eventStartTS, instanceMetaData.Id);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to joinInstance() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, business_logs);
|
||||
}
|
||||
|
||||
var instance_room_storage = new InstanceRoomStorage();
|
||||
instance_room_storage.Init(server_logic.getRedisDb(), "");
|
||||
|
||||
var instance_room_info = await instance_room_storage.GetInstanceRoomInfo(instance_room_id);
|
||||
if (instance_room_info == null)
|
||||
{
|
||||
err_msg = $"Failed to GetInstanceRoomInfo() !!! : instanceRoomId:{instance_room_id} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.NotExistRoomInfoForEnter, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, business_logs);
|
||||
}
|
||||
|
||||
var server_name = ServerType.Indun.toServerName(instance_room_info.InstanceAddress, (ushort)instance_room_info.InstancePort);
|
||||
|
||||
// 이동 예약 걸기
|
||||
var message = new ServerMessage.Types.GS2GS_REQ_RESERVATION_ENTER_TO_SERVER();
|
||||
message.MoveType = ServerMoveType.Force;
|
||||
message.RequestUserGuid = userGuid;
|
||||
message.RequestServerName = server_logic.getServerName();
|
||||
|
||||
var reserved = await server_logic.getReservationManager().registerReservationEnterToServer(message, server_name);
|
||||
|
||||
// 예약 실패 체크
|
||||
if (null == reserved)
|
||||
{
|
||||
err_msg = $"Failed to Reservation Enter to server !!! : {server_name} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.FailedToReservationEnter, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, null, business_logs);
|
||||
}
|
||||
|
||||
var location_action = player.getEntityAction<LocationAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(location_action, () => $"location_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
result = await location_action.tryMoveToBattleIndun(instance_room_info);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryMoveToIndun() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, business_logs);
|
||||
}
|
||||
|
||||
var buff_action = player.getEntityAction<BuffAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(buff_action, () => $"buff_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
result = await buff_action.MoveServer(instanceMetaData.placeType());
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to MoveServer() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, business_logs);
|
||||
}
|
||||
|
||||
(result, var reserved_to_switch_server) = await ServerConnectionSwitchHelper.startServerSwitch(player, server_logic.getRedisConnector(), server_name);
|
||||
if (result.isFail() || null == reserved_to_switch_server)
|
||||
{
|
||||
err_msg = $"Failed to startServerSwitch() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, null, business_logs);
|
||||
}
|
||||
|
||||
var game_login_action = player.getEntityAction<GameLoginAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(game_login_action, () => $"game_login_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var login_cache = game_login_action.getLoginCacheRequest()?.getLoginCache();
|
||||
NullReferenceCheckHelper.throwIfNull(login_cache, () => $"login_cache is null !! player: {player.toBasicString()}");
|
||||
login_cache.ReservedToSwitchServer = reserved_to_switch_server;
|
||||
|
||||
server_connect_info.ServerAddr = instance_room_info.InstanceAddress;
|
||||
server_connect_info.ServerPort = instance_room_info.InstancePort;
|
||||
server_connect_info.Otp = reserved_to_switch_server.OneTimeKey;
|
||||
server_connect_info.RoomId = instance_room_info.roomId;
|
||||
|
||||
//배틀 인스턴스 같은 경우는 실제 인스턴스 진입시에 Pos를 정해야 하기 때문에 여기서는 빈값으로 처리
|
||||
//var start_pos = MapManager.Instance.GetBattleInstnaceStartPos(indun_meta_data.RoomFile, instance_room_id);
|
||||
var arrival_position_log_info = PositionBusinessLogHelper.toPositionLogInfo(PositionMoveType.Arrival, server_name, instance_room_info.roomId, MapFileType.Instance, instance_room_info.InstanceId, new());
|
||||
var arrival_position_business_log = new PositionBusinessLog(arrival_position_log_info);
|
||||
business_logs.Add(arrival_position_business_log);
|
||||
|
||||
Log.getLogger().debug($"tryJoinBattleInstance server connect info : {JsonConvert.SerializeObject(server_connect_info)}");
|
||||
|
||||
return (result, server_connect_info, business_logs);
|
||||
}
|
||||
|
||||
public async Task<(Result, ClientToGameRes.Types.GS2C_ACK_LEAVE_BATTLE_INSTANCE)> tryLeaveBattleInstanceRoom()
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var res = new ClientToGameRes.Types.GS2C_ACK_LEAVE_BATTLE_INSTANCE();
|
||||
|
||||
var player = getOwner() as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!");
|
||||
|
||||
var user_attribute = player.getEntityAttribute<UserAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_attribute, () => $"user_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
var farming_action = player.getEntityAction<FarmingAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(user_attribute, () => $"user_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
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 (result, res);
|
||||
|
||||
if (!await BattleInstanceManager.It.LeaveBattleRoom(player, instance_room_Id))
|
||||
{
|
||||
err_msg = $"Fail to LeaveBattleRoom() !!! : instanceRoomId:{instance_room_Id}";
|
||||
result.setFail(ServerErrorCode.NotExistInstanceRoom, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, res);
|
||||
}
|
||||
|
||||
Log.getLogger().debug($"try leave battle instancr room done instance_room_Id : {instance_room_Id}");
|
||||
|
||||
return (result, res);
|
||||
}
|
||||
|
||||
}
|
||||
179
GameServer/Contents/GameMode/Mode-Battle/Cheat/BattleCheat.cs
Normal file
179
GameServer/Contents/GameMode/Mode-Battle/Cheat/BattleCheat.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
using Nettention.Proud;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
|
||||
|
||||
[ChatCommandAttribute("battleinstanceinit", typeof(CheatBattleInstanceInit), AuthAdminLevelType.Developer,
|
||||
AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
|
||||
public class CheatBattleInstanceInit : ChatCommandBase
|
||||
{
|
||||
public override async Task invoke(Player player, string token, string[] args)
|
||||
{
|
||||
Log.getLogger().info($"battleinstanceinit");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var room_id = player.getCurrentInstanceRoomId();
|
||||
if (room_id.Equals(string.Empty))
|
||||
{
|
||||
Log.getLogger().error($"cheat:battleinstanceinit.... this cheat only use in instance");
|
||||
return;
|
||||
}
|
||||
|
||||
var battle_instance_room = BattleInstanceManager.It.getBattleInstanceRoom(room_id);
|
||||
if (battle_instance_room is null)
|
||||
{
|
||||
Log.getLogger().error($"cheat:battleinstanceinit.... battle_instance_room is null room_id : {room_id}");
|
||||
return;
|
||||
}
|
||||
|
||||
using (var releaser = await battle_instance_room.getAsyncLock())
|
||||
{
|
||||
var attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
if (false == attribute.m_combat_pod_mode.m_round_state_type.Equals(BattleRoundStateType.RoundEndAll) &&
|
||||
false == attribute.m_combat_pod_mode.m_round_state_type.Equals(BattleRoundStateType.Destroyed))
|
||||
{
|
||||
Log.getLogger().error($"cheat:battleinstanceinit.... this cheat only RoundEndAll room_id : {room_id}");
|
||||
return;
|
||||
}
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
battle_instance_room.setEventStartTime(now);
|
||||
|
||||
attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.Rounding;
|
||||
attribute.m_combat_pod_mode.m_current_state_start_time = now;
|
||||
attribute.m_combat_pod_mode.m_current_round = 1;
|
||||
attribute.m_combat_pod_mode.m_charged_step = 0;
|
||||
attribute.m_combat_pod_mode.m_rewarded_step = 0;
|
||||
|
||||
attribute.m_combat_pod_mode.m_pod_combat.setActive(now);
|
||||
|
||||
|
||||
(Result result, var anchor_guid) =
|
||||
BattleRoomHelper.getRandomCombatPodAnchorGuid(attribute, battle_instance_room);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error("get Random pod combat anchor guid faile !!! ");
|
||||
return;
|
||||
}
|
||||
|
||||
attribute.m_combat_pod_mode.m_pod_combat.m_source_storage_anchor_guid = anchor_guid;
|
||||
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battle_instance_room);
|
||||
|
||||
var update_action = battle_instance_room.getEntityAction<BattleInstanceUpdateAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(update_action, () => $"attribute is null !!!");
|
||||
update_action.battleObjectStateInitAndNotify(battle_instance_room, attribute);
|
||||
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battle_instance_room);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ChatCommandAttribute("gamemodeoccupyhost", typeof(BattleHostOccupy), AuthAdminLevelType.Developer,
|
||||
AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
|
||||
public class BattleHostOccupy : ChatCommandBase
|
||||
{
|
||||
public override async Task invoke(Player player, string token, string[] args)
|
||||
{
|
||||
//Log.getLogger().info($"battleinstanceinit");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var room_id = player.getCurrentInstanceRoomId();
|
||||
if (room_id.Equals(string.Empty))
|
||||
{
|
||||
Log.getLogger().error($"cheat:gamemodeoccupyhost.... this cheat only use in instance");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//kihoon todo : 임시 분기 처리
|
||||
//나중에 게임모드로 분리되면 그때 재작업
|
||||
if (room_id.Contains("battle"))
|
||||
{
|
||||
var battle_instance_room = BattleInstanceManager.It.getBattleInstanceRoom(room_id);
|
||||
if (battle_instance_room is null)
|
||||
{
|
||||
Log.getLogger().error($"cheat:gamemodeoccupyhost.... battle_instance_room is null room_id : {room_id}");
|
||||
return;
|
||||
}
|
||||
|
||||
using (var releaser = await battle_instance_room.getAsyncLock())
|
||||
{
|
||||
battle_instance_room.m_host_migrator.modifyHost(player.getUserGuid());
|
||||
}
|
||||
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_P2P_HOST_UPDATE(battle_instance_room.m_instance_room,
|
||||
player.getUserGuid());
|
||||
}
|
||||
else if (room_id.Contains("1017101"))
|
||||
{
|
||||
var instance_room = InstanceRoomManager.Instance.getInstanceRoomByRoomId(room_id);
|
||||
if (instance_room is null)
|
||||
{
|
||||
Log.getLogger().error($"cheat:gamemodeoccupyhost.... instance_room is null room_id : {room_id}");
|
||||
return;
|
||||
}
|
||||
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_P2P_HOST_UPDATE(instance_room, player.getUserGuid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================================================================
|
||||
//
|
||||
//======================================================================================================================
|
||||
[ChatCommandAttribute("gamehostmigration", typeof(BattleHostMigration), AuthAdminLevelType.Developer,
|
||||
AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)]
|
||||
public class BattleHostMigration : ChatCommandBase
|
||||
{
|
||||
public override async Task invoke(Player player, string token, string[] args)
|
||||
{
|
||||
Log.getLogger().info($"gamehostmigration");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var room_id = player.getCurrentInstanceRoomId();
|
||||
if (room_id.Equals(string.Empty))
|
||||
{
|
||||
Log.getLogger().error($"cheat:gamehostmigration.... this cheat only use in instance");
|
||||
return;
|
||||
}
|
||||
|
||||
var battle_instance_room = BattleInstanceManager.It.getBattleInstanceRoom(room_id);
|
||||
if (battle_instance_room is null)
|
||||
{
|
||||
Log.getLogger().error($"cheat:gamehostmigration.... battle_instance_room is null room_id : {room_id}");
|
||||
return;
|
||||
}
|
||||
|
||||
using var releaser = await battle_instance_room.getAsyncLock();
|
||||
if (battle_instance_room.m_host_migrator is CommonHostMigrator common_hot_migrator)
|
||||
{
|
||||
common_hot_migrator.HostMigrationSystem.setIgnoreMigrationCondition(true);
|
||||
common_hot_migrator.migrateCheck(true);
|
||||
var super_peer_guid_id = common_hot_migrator.getHostUserGuid();
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_P2P_HOST_UPDATE(
|
||||
battle_instance_room.m_instance_room, super_peer_guid_id);
|
||||
common_hot_migrator.HostMigrationSystem.setIgnoreMigrationCondition(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.getLogger()
|
||||
.error(
|
||||
$"cheat:gamehostmigration.... battle_instance_room is not CommonHostMigrator room_id : {room_id}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using MetaAssets;
|
||||
using Newtonsoft.Json;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer.Contents.Battle.Doc;
|
||||
|
||||
|
||||
public class BattleEventAttrib : AttribBase
|
||||
{
|
||||
public BattleEventAttrib() : base(typeof(BattleEventAttrib).Name) { }
|
||||
|
||||
[JsonProperty("event_id")] public Int32 m_event_id { get; set; } = 0;
|
||||
[JsonProperty("is_active")] public bool m_is_active { get; set; } = false;
|
||||
|
||||
[JsonProperty("start_day")] public DateTime m_start_day = DateTimeHelper.Current.Date;//2025-01-01T00:00:00
|
||||
[JsonProperty("start_hour")] public Int32 m_start_hour = 0; //00 ~ 23;
|
||||
[JsonProperty("start_min")] public Int32 m_start_min = 0; //00 ~ 59;
|
||||
|
||||
[JsonProperty("end_date")] public DateTime m_end_date = DateTimeHelper.Current.Date.AddHours(12); //이시간이 지나면 더이상 이벤트 열지 않는다.
|
||||
|
||||
//[JsonProperty("sequence_id")] public Int32 m_sequence_id { get; set; } = 0;
|
||||
[JsonProperty("instance_id")] public Int32 m_instance_id { get; set; } = 0;
|
||||
[JsonProperty("once_period_type")] public OncePeriodRangeType m_period { get; set; } = OncePeriodRangeType.NONE;
|
||||
[JsonProperty("day_of_week_type")] public HashSet<DayOfWeekType> m_day_of_week_type { get; set; } = new();
|
||||
//[JsonProperty("battle_play_mode")] public BattlePlayMode m_battle_playe_mode { get; set; } = BattlePlayMode.None;
|
||||
[JsonProperty("ffa_config_data_id")] public Int32 m_ffa_config_data_id { get; set; } = 4;
|
||||
[JsonProperty("ffa_reward_group_id")] public Int32 m_ffa_reward_group_id { get; set; } = 7;
|
||||
[JsonProperty("ffa_hot_time")] public Int32 m_ffa_hot_time { get; set; } = 1;
|
||||
[JsonProperty("round_count")] public Int32 m_round_count { get; set; } = 1;
|
||||
|
||||
|
||||
public BattleEventAttrib clone()
|
||||
{
|
||||
BattleEventAttrib new_attrib = new();
|
||||
new_attrib.m_event_id = this.m_event_id;
|
||||
new_attrib.m_is_active = this.m_is_active;
|
||||
new_attrib.m_start_day = this.m_start_day;
|
||||
new_attrib.m_start_hour = this.m_start_hour;
|
||||
new_attrib.m_start_min = this.m_start_min;
|
||||
new_attrib.m_instance_id = this.m_instance_id;
|
||||
new_attrib.m_period = this.m_period;
|
||||
new_attrib.m_day_of_week_type = this.m_day_of_week_type;
|
||||
new_attrib.m_ffa_config_data_id = this.m_ffa_config_data_id;
|
||||
new_attrib.m_ffa_reward_group_id = this.m_ffa_reward_group_id;
|
||||
new_attrib.m_ffa_hot_time = this.m_ffa_hot_time;
|
||||
|
||||
new_attrib.m_end_date = this.m_end_date;
|
||||
new_attrib.m_round_count = this.m_round_count;
|
||||
|
||||
return new_attrib;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================================
|
||||
// PK(Partition Key) : "management_battle_event#global"
|
||||
// SK(Sort Key) : "event_id"
|
||||
// DocType : BattleEventDoc
|
||||
// SystemMailAttrib : {}
|
||||
// ...
|
||||
//=============================================================================================
|
||||
public class BattleEventDoc : DynamoDbDocBase
|
||||
{
|
||||
public BattleEventDoc()
|
||||
: base(typeof(BattleEventDoc).Name)
|
||||
{
|
||||
setCombinationKeyForPK(DynamoDbClient.PK_GLOBAL);
|
||||
appendAttribWrapperAll();
|
||||
fillUpPrimaryKey(onMakePK(), onMakeSK());
|
||||
}
|
||||
|
||||
public BattleEventDoc(string event_id)
|
||||
: base(typeof(BattleEventDoc).Name)
|
||||
{
|
||||
setCombinationKeyForPKSK(DynamoDbClient.PK_GLOBAL, event_id);
|
||||
appendAttribWrapperAll();
|
||||
fillUpPrimaryKey(onMakePK(), onMakeSK());
|
||||
}
|
||||
|
||||
private void appendAttribWrapperAll()
|
||||
{
|
||||
appendAttribWrapper(new AttribWrapper<BattleEventAttrib>());
|
||||
}
|
||||
|
||||
protected override string onGetPrefixOfPK()
|
||||
{
|
||||
return "management_battle_event#";
|
||||
}
|
||||
|
||||
protected override ServerErrorCode onCheckAndSetSK(string sortKey)
|
||||
{
|
||||
getPrimaryKey().fillUpSK(sortKey);
|
||||
setCombinationKeyForSK(sortKey);
|
||||
return ServerErrorCode.Success;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
|
||||
using Axion.Collections.Concurrent;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
public class BattleInstanceRoom : EntityBase, IWithLogActor
|
||||
{
|
||||
//public string m_instance_room_guid { get; } = string.Empty;
|
||||
public bool m_is_load_complete { get; private set; } = false;
|
||||
public InstanceRoom m_instance_room { get; }
|
||||
|
||||
private readonly CancellationTokenSource m_cancel_token = new();
|
||||
|
||||
public readonly IHostMigrator m_host_migrator; //생성자에서 모드에 맞춰서 할당한다.
|
||||
|
||||
|
||||
public BattlePlayMode m_play_mode { get; set; } = BattlePlayMode.PodCombat;
|
||||
|
||||
public DateTime m_battle_instance_event_start_time { get; private set; } = DateTimeHelper.Current; //실제 이벤트 시작시간
|
||||
//public DateTime m_battle_instance_load_time { get; } = DateTimeHelper.Current; //이벤트 시작시간과 관계 없이 메모리에 로드 될때의 시간 이 변수가 필요할지 모르겠다.
|
||||
|
||||
|
||||
//todo : 모드별 관리 메타를 따로 구성해야할듯...
|
||||
//todo : 제네릭으로 받아도 되려나?.. 고민 필요 우선 임시데이터
|
||||
public Int32 m_pod_combat_reward_group_id = 1;
|
||||
public Int32 m_pod_combat_ffa_id = 1;
|
||||
public BattleFFAConfigData m_ffa_config_meta;
|
||||
public Dictionary<int, BattleFFARewardData> m_ffa_reward_meta = new();
|
||||
public Int32 m_hot_time_reward = 1;
|
||||
public Int32 m_round_count = 8;
|
||||
//public Int32 m_pickup_pod_reward_max_count { get; } = 2;
|
||||
//public int m_max_step_per_round { get; set; } = 10;
|
||||
|
||||
public ConcurrentHashSet<string /*anchor_guid*/> m_respawn_pos_anchors_meta { get; private set; } = new(); //이건 랜덤 돌릴 일이 잦아서 그냥 들고 있는다...
|
||||
public ConcurrentDictionary<int /*battle_group_id*/ , HashSet<string>> m_battle_pod_storage_guid_group { get; private set; } = new(); //pod combat을 생성해줄때 필요
|
||||
public ConcurrentDictionary<int /*battle_group_id*/ , HashSet<string>> m_battle_pickup_pod_guid_group { get; private set; } = new();
|
||||
|
||||
|
||||
public BattleInstanceRoom(InstanceRoom room, DateTime eventStartTime, Int32 configId, Int32 rewardId, Int32 hotTime, Int32 roundCount)
|
||||
: base(EntityType.BattleInstance)
|
||||
{
|
||||
m_instance_room = room;
|
||||
NullReferenceCheckHelper.throwIfNull(m_instance_room, () => $"m_instance_room is null !!!");
|
||||
|
||||
m_battle_instance_event_start_time = eventStartTime;
|
||||
m_play_mode = BattlePlayMode.PodCombat;
|
||||
|
||||
m_host_migrator = BattleRoomHelper.createHostMigrator(m_play_mode);
|
||||
|
||||
m_pod_combat_ffa_id = configId;
|
||||
m_pod_combat_reward_group_id = rewardId;
|
||||
m_hot_time_reward = hotTime;
|
||||
m_round_count = roundCount;
|
||||
|
||||
//m_instance_room_guid = BattleConstant.PREFIX_BATTLE_TRANSACTION_GUID + System.Guid.NewGuid();
|
||||
|
||||
// BattleFFAConfigData
|
||||
if (false == MetaData.Instance._BattleFFAConfigMetaTable.TryGetValue(m_pod_combat_ffa_id, out var configData))
|
||||
{
|
||||
var err_msg = $"Not exist Battle Conig Data id : {m_pod_combat_ffa_id}";
|
||||
Log.getLogger().error(err_msg);
|
||||
NullReferenceCheckHelper.throwIfNull(configData, () => $"configData is null !!!");
|
||||
}
|
||||
|
||||
m_ffa_config_meta = new BattleFFAConfigData(new BattleFFAConfigDataMutable()
|
||||
{
|
||||
Id = configData.Id,
|
||||
Description = configData.Description,
|
||||
PlayerRespawnTime = configData.PlayerRespawnTime,
|
||||
DefaultRoundCount = configData.DefaultRoundCount,
|
||||
RoundTime = configData.RoundTime,
|
||||
NextRoundWaitTime = configData.NextRoundWaitTime,
|
||||
ResultUIWaitTime = configData.ResultUIWaitTime,
|
||||
GetRewardTime = configData.GetRewardTime,
|
||||
EntranceClosingTime = configData.EntranceClosingTime,
|
||||
CurrencyType = configData.CurrencyType,
|
||||
CurrencyCount = configData.CurrencyCount,
|
||||
TPSGuideURL = configData.TPSGuideURL
|
||||
});
|
||||
|
||||
|
||||
if (false == MetaData.Instance._BattleFFARewardMetaTable.TryGetValue(m_pod_combat_reward_group_id, out var rewardMeta))
|
||||
{
|
||||
var err_msg = $"Not exist reward Meta Data id : {m_pod_combat_ffa_id}";
|
||||
Log.getLogger().error(err_msg);
|
||||
NullReferenceCheckHelper.throwIfNull(rewardMeta, () => $"rewardMeta is null !!!");
|
||||
}
|
||||
|
||||
foreach (var meta_set in rewardMeta)
|
||||
{
|
||||
var val = meta_set.Value;
|
||||
var key = meta_set.Key;
|
||||
|
||||
BattleFFARewardData data = new BattleFFARewardData(new BattleFFARewardDataMutable()
|
||||
{
|
||||
Id = val.Id,
|
||||
GroupID = val.GroupID,
|
||||
ChargeLevel = val.ChargeLevel,
|
||||
ChargeTime = val.ChargeTime,
|
||||
RewardItemID = val.RewardItemID,
|
||||
RewardCount = val.RewardCount
|
||||
});
|
||||
|
||||
m_ffa_reward_meta.TryAdd(key, data);
|
||||
}
|
||||
Log.getLogger().info($"BattleInstanceRoom construct done roomId : " +
|
||||
$"{room.getMap().m_room_id}, eventStartTime : {eventStartTime}, configId : {configId}, rewardId : {rewardId}, hotTime : {hotTime}, roundCount : {roundCount}");
|
||||
}
|
||||
|
||||
|
||||
public async Task<Result> init()
|
||||
{
|
||||
string err_msg = string.Empty;
|
||||
|
||||
//Action 추가
|
||||
addEntityAction(new BattleInstanceAction(this));
|
||||
addEntityAction(new BattleInstanceUpdateAction(this));
|
||||
addEntityAction(new BattleObjectInteractAction(this));
|
||||
addEntityAction(new BattleObjectRewardAction(this));
|
||||
|
||||
|
||||
//Attribute 추가
|
||||
addEntityAttribute(new BattleInstanceSnapshotAttribute(this));
|
||||
|
||||
//Anchor 정보 로드
|
||||
loadAnchorPos();
|
||||
|
||||
//스냅샷 데이터 로드, 없으면 신규 생성
|
||||
var battle_instance_action = getEntityAction<BattleInstanceAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_action, () => $"battle_instance_action is null !!!");
|
||||
var result = await battle_instance_action.loadOrCreateSnapshot();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"loadSnapshot error instanceId : {m_instance_room.getInstanceId()}, roomId : {m_instance_room.getMap().m_room_id}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
Log.getLogger().info($"load Snapshot done instanceId : {m_instance_room.getInstanceId()}, roomId : {m_instance_room.getMap().m_room_id}");
|
||||
|
||||
//태스크 생성
|
||||
result = await createTask();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"battle instance room onCreateTask error instanceId : {m_instance_room.getInstanceId()}, roomId : {m_instance_room.getMap().m_room_id}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
Log.getLogger().info($"createTask done instanceId : {m_instance_room.getInstanceId()}, roomId : {m_instance_room.getMap().m_room_id}");
|
||||
|
||||
m_is_load_complete = true;
|
||||
|
||||
// P2P Host Migrator p2p 그룹 id 설정
|
||||
m_host_migrator.setGroupHostId(m_instance_room.getMap().getP2PGroupId());
|
||||
return result;
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
var result = new Result();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private async Task<Result> createTask()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
//Timer에서 사용할 Action 초기화
|
||||
var battle_update_action = getEntityAction<BattleInstanceUpdateAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_update_action, () => $"battle_update_action is null !!!");
|
||||
|
||||
try
|
||||
{
|
||||
//임시로 0.8초로 처리 나중에 이거 Meta로 빼야 된다.
|
||||
new PeriodicTaskTimer( GetType().Name, BattleConstant.BATTLE_ROOM_CHECK_INTERVAL, m_cancel_token, onTaskTick);
|
||||
|
||||
await battle_update_action.onInit();
|
||||
Log.getLogger().debug("battle_update_action.onInit() dome");
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
var err_msg = $"Exception !!!, new PeriodicTaskTimer() : exception:{e} - {toBasicString()}";
|
||||
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private void loadAnchorPos()
|
||||
{
|
||||
foreach (var anchor_info_dict in m_instance_room.getMap().getAnchors())
|
||||
{
|
||||
var anchor_guid = anchor_info_dict.Key;
|
||||
var anchor_info = anchor_info_dict.Value;
|
||||
|
||||
if (!MapDataTable.Instance.getAnchor(anchor_guid, out var anchor))
|
||||
{
|
||||
Log.getLogger().error($"anchr_guid not MapDataTable.Instance.getAnchor, anchorGuid : {anchor_guid}");
|
||||
continue;
|
||||
}
|
||||
|
||||
var type = anchor.Type;
|
||||
var table_id = anchor_info.AnchorProp.TableId;
|
||||
loadRespawnPos(type, anchor_guid);
|
||||
loadBattleObjectGroups(type, anchor_guid, table_id);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void loadRespawnPos(string type, string anchorGuid)
|
||||
{
|
||||
if (!type.Equals(BattleConstant.RESPAWN_POS_ANCHOR_NAME)) return;
|
||||
|
||||
if (false == m_respawn_pos_anchors_meta.Add(anchorGuid))
|
||||
{
|
||||
Log.getLogger().warn($"respawnPos add fail type : {type}, anchorGuid : {anchorGuid}");
|
||||
}
|
||||
Log.getLogger().info($"respawnPos add success type : {type}, anchorGuid : {anchorGuid}");
|
||||
}
|
||||
|
||||
// private void loadBattleObject(string type, string anchorGuid)
|
||||
// {
|
||||
// if (!type.Equals(BattleConstant.BATTLE_OBJECT_ANCHOR_NAME)) return;
|
||||
//
|
||||
// if (false == m_battle_object_anchors_meta.Add(anchorGuid))
|
||||
// {
|
||||
// Log.getLogger().warn($"m_battle_object_anchors add fail type : {type}, anchorGuid : {anchorGuid}");
|
||||
// }
|
||||
// Log.getLogger().info($"m_battle_object_anchors add success type : {type}, anchorGuid : {anchorGuid}");
|
||||
// }
|
||||
|
||||
private bool loadBattleObjectGroups(string type, string anchorGuid, Int32 tableID)
|
||||
{
|
||||
if (!type.Equals(BattleConstant.BATTLE_OBJECT_GROUP_ANCHOR_NAME)) return true;
|
||||
|
||||
// if (false == m_battle_object_group_anchors_meta.Add(anchorGuid))
|
||||
// {
|
||||
// Log.getLogger().warn($"m_battle_object_group_anchors add fail type : {type}, anchorGuid : {anchorGuid}");
|
||||
// }
|
||||
// Log.getLogger().info($"m_battle_object_group_anchors add success type : {type}, anchorGuid : {anchorGuid}");
|
||||
|
||||
|
||||
if (false == MetaData.Instance._BattleObjectSpawnGroupMetaTable.TryGetValue(tableID, out var battle_object_spawn_meta))
|
||||
{
|
||||
Log.getLogger().warn($"battle_object_group add fail type : {type}, anchorGuid : {anchorGuid}, table_id : {tableID}");
|
||||
return false;
|
||||
}
|
||||
|
||||
var battle_object_id = battle_object_spawn_meta.BattleObjectID;
|
||||
if (false == MetaData.Instance._BattleObjectMetaTable.TryGetValue(battle_object_id, out var battle_object_meta))
|
||||
{
|
||||
Log.getLogger().warn($"battle_object_group add fail type : {type}, anchorGuid : {anchorGuid}, table_id : {tableID}, battle_object_id : {battle_object_id}");
|
||||
return false;
|
||||
}
|
||||
|
||||
EBattleObjectType object_type = battle_object_meta.ObjectType;
|
||||
|
||||
var group_id = battle_object_spawn_meta.GroupID;
|
||||
if (object_type.Equals(EBattleObjectType.Pod_Combat) && battle_object_meta.Name.Equals(BattleConstant.BATTLE_POD_STORAGE_NAME))
|
||||
{
|
||||
loadBattleObjectPodStorageGroup(anchorGuid, group_id);
|
||||
}
|
||||
else if (object_type.Equals(EBattleObjectType.Pod_Box))
|
||||
{
|
||||
loadBattleObjectPickupPodGroup(anchorGuid, group_id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void loadBattleObjectPodStorageGroup(string anchorGuid, int groupId)
|
||||
{
|
||||
if (false == m_battle_pod_storage_guid_group.ContainsKey(groupId))
|
||||
{
|
||||
m_battle_pod_storage_guid_group.TryAdd(groupId, new());
|
||||
}
|
||||
|
||||
if (false == m_battle_pod_storage_guid_group.TryGetValue(groupId, out var poses))
|
||||
{
|
||||
Log.getLogger().error($"m_battle_pod_stand_group_pos_meta get fail anchorGuid : {anchorGuid}, group_id : {groupId}");
|
||||
return;
|
||||
}
|
||||
poses.Add(anchorGuid);
|
||||
|
||||
Log.getLogger().info($"m_battle_pod_stand_group_pos_meta Add anchorGuid : {anchorGuid}, group_id : {groupId}");
|
||||
}
|
||||
|
||||
private void loadBattleObjectPickupPodGroup(string anchorGuid, int groupId)
|
||||
{
|
||||
if (false == m_battle_pickup_pod_guid_group.ContainsKey(groupId))
|
||||
{
|
||||
m_battle_pickup_pod_guid_group.TryAdd(groupId, new());
|
||||
}
|
||||
if (false == m_battle_pickup_pod_guid_group.TryGetValue(groupId, out var poses))
|
||||
{
|
||||
Log.getLogger().error($"m_battle_pod_box_group_pos_meta get fail anchorGuid : {anchorGuid}, group_id : {groupId}");
|
||||
return;
|
||||
}
|
||||
poses.Add(anchorGuid);
|
||||
|
||||
Log.getLogger().info($"m_battle_pod_box_group_pos_meta Add anchorGuid : {anchorGuid}, group_id : {groupId}");
|
||||
}
|
||||
|
||||
public Result AddOrUpdatePlayer(Player player)
|
||||
{
|
||||
var result = new Result();
|
||||
// if (false == m_battle_players.TryAdd(player.getUserGuid(), new BattlePlayer(player)))
|
||||
// {
|
||||
// string err_msg = $"Player tryAdd fail guid : {player.getUserGuid()}";
|
||||
// result.setFail(ServerErrorCode.BattleInstanceJoinPlayerError, err_msg);
|
||||
// Log.getLogger().error(result.toBasicString());
|
||||
// return result;
|
||||
// }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private async Task onTaskTick()
|
||||
{
|
||||
if (!m_is_load_complete) return;
|
||||
|
||||
var battle_update_action = getEntityAction<BattleInstanceUpdateAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_update_action, () => $"battle_update_action is null !!!");
|
||||
|
||||
|
||||
var result = await battle_update_action.update();
|
||||
if (result.isFail())
|
||||
{
|
||||
var err_msg = $"playr mode hander update error : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ILogActor toLogActor()
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var region_id = server_logic.getServerConfig().getRegionId();
|
||||
var server_name = server_logic.getServerName();
|
||||
|
||||
var log_info = new BattleInstanceActorLog(region_id, server_name, m_instance_room.getMap().m_room_id, m_instance_room.getInstanceId());
|
||||
return log_info;
|
||||
}
|
||||
|
||||
public async Task removePodCombat(Player player)
|
||||
{
|
||||
var attribute = getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
if (attribute.m_combat_pod_mode.m_pod_combat.m_current_occupier_guid.Equals(player.getUserGuid()))
|
||||
{
|
||||
using (var releaser = await getAsyncLock())
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_pod_combat.changeDropState(player.getCurrentPositionInfo().Pos);
|
||||
}
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void removeBattlePlayerIfExist(string userGuid)
|
||||
{
|
||||
// if (true == m_battle_players.ContainsKey(userGuid))
|
||||
// {
|
||||
// if (false == m_battle_players.TryRemove(userGuid, out var player))
|
||||
// {
|
||||
// Log.getLogger().warn($"m_battle_players try remove faial userGuid : {userGuid}");
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public async Task<bool> LeaveBattleRoom(Player player, string roomId, bool disconnected = false)
|
||||
{
|
||||
//BattleRoom에서 먼저 빼준다.
|
||||
//m_battle_players.TryRemove(player.getUserGuid(), out _);
|
||||
|
||||
Log.getLogger().info($"LeaveBattleRoom, player : {player.toBasicString()}, roomId : {roomId}, disconnected : {disconnected}");
|
||||
await m_instance_room.LeaveBattleInstanceRoom(player, disconnected);
|
||||
|
||||
if (m_instance_room.isDestroy)
|
||||
{
|
||||
Log.getLogger().info($"m_instance_room.isDestroy, so destroyBattleRoom : {player.toBasicString()}, roomId : {roomId}, disconnected : {disconnected}");
|
||||
await destroyBattleRoom();
|
||||
InstanceRoomManager.Instance.DestroyRoom(roomId);
|
||||
Log.getLogger().info($"destroy InstanceRoomManager room Player : {player.toBasicString()}, roomId : {roomId}, disconnected : {disconnected}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task destroyBattleRoom()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
//여기서 timer 종료 처리
|
||||
m_cancel_token.Cancel();
|
||||
Log.getLogger().debug($"battle instance room token canceled m_room_id :{m_instance_room.getMap().m_room_id}");
|
||||
|
||||
var fn_save_battle_instance = async delegate()
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var fn_result = new Result();
|
||||
using (var releaser = await getAsyncLock())
|
||||
{
|
||||
//여기서 battleRoomSnapshot 저장
|
||||
var battle_instance_snapshot_attribute = getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_snapshot_attribute, () => $"battle_instance_snapshot_attribute is null !!!");
|
||||
if (!battle_instance_snapshot_attribute.m_combat_pod_mode.m_pod_combat.m_current_occupier_guid.Equals(string.Empty))
|
||||
{
|
||||
battle_instance_snapshot_attribute.m_combat_pod_mode.m_pod_combat.m_current_occupier_guid = string.Empty;
|
||||
}
|
||||
|
||||
battle_instance_snapshot_attribute.modifiedEntityAttribute(true);
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(this, LogActionType.BattleInstanceSnapshotSave, server_logic.getDynamoDbClient(), true);
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
}
|
||||
|
||||
BattleSnapShotBusinessLog business_log = new(this, "");
|
||||
batch.appendBusinessLog(business_log);
|
||||
|
||||
fn_result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
|
||||
if (fn_result.isSuccess())
|
||||
{
|
||||
Log.getLogger().info($"save battle instance snapshot done attribute : {JsonConvert.SerializeObject(battle_instance_snapshot_attribute)}");
|
||||
}
|
||||
}
|
||||
|
||||
return fn_result;
|
||||
};
|
||||
|
||||
|
||||
|
||||
var result = await runTransactionRunnerSafely(TransactionIdType.PrivateContents, "SaveBattleInstanceByDestroy", fn_save_battle_instance);
|
||||
if (result.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string toBasicString()
|
||||
{
|
||||
return $"BattleInstanceRoom room_id : {m_instance_room.getMap().m_room_id}";
|
||||
}
|
||||
|
||||
|
||||
public void setEventStartTime(DateTime t)
|
||||
{
|
||||
m_battle_instance_event_start_time = t;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using Amazon.DynamoDBv2.Model;
|
||||
using Newtonsoft.Json;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleInstanceSnapshotPlayModePodCombat
|
||||
{
|
||||
//Respawn 정보
|
||||
[JsonProperty]
|
||||
public ConcurrentDictionary<string /*anchor_guid*/, DateTime> m_respawns {get; set;} = new ();
|
||||
[JsonProperty]
|
||||
public ConcurrentDictionary<string /*anchor_guid*/, BattleObjectPodStorage> m_pod_storages {get; set;} = new ();
|
||||
[JsonProperty] public BattleObjectPodCombat m_pod_combat { get; set; } = new();
|
||||
|
||||
[JsonProperty]
|
||||
public ConcurrentDictionary<string /*anchor_guid*/, BattleObjectPickupPod> m_pickup_pods {get; set;} = new ();
|
||||
|
||||
|
||||
[JsonProperty] public ConcurrentDictionary<(Int32, Int32) /*(group_id, idx)*/, PickupPodGeneratedInfo> m_pickup_pod_generated_info { get; set; } = new();
|
||||
|
||||
[JsonProperty]
|
||||
public ConcurrentDictionary<string /*anchor_guid*/, BattleObjectWeapon> m_weapons {get; set;} = new ();
|
||||
|
||||
[JsonProperty]
|
||||
public ConcurrentDictionary<string /*anchor_guid*/, BattleObjectBuff> m_buffs {get; set;} = new ();
|
||||
|
||||
[JsonProperty] public BattleRoundStateType m_round_state_type { get; set; } = BattleRoundStateType.Rounding;
|
||||
[JsonProperty] public int m_current_round { get; set; } = 1;
|
||||
[JsonProperty] public DateTime m_current_state_start_time { get; set; } = DateTimeHelper.Current;
|
||||
|
||||
[JsonProperty] public int m_charged_step { get; set; } = 0;
|
||||
[JsonProperty] public int m_rewarded_step { get; set; } = 0;
|
||||
|
||||
|
||||
|
||||
[JsonProperty] public ConcurrentDictionary<string /*user_guid*/, BattleTacticalBoardInfo> m_tactical_board = new(); //결과 표시에서 보여줄것
|
||||
|
||||
|
||||
/*
|
||||
m_respawns
|
||||
m_pod_storages
|
||||
m_pod_combat
|
||||
m_pickup_pods
|
||||
m_pickup_pod_reward_max_count
|
||||
m_pickup_pod_generated_info
|
||||
m_weapons
|
||||
m_buffs
|
||||
m_round_state_type
|
||||
m_current_round
|
||||
m_current_state_start_time
|
||||
m_charged_step
|
||||
m_rewarded_step
|
||||
m_max_step
|
||||
m_tactical_board
|
||||
*/
|
||||
|
||||
public void clear()
|
||||
{
|
||||
m_respawns.Clear();
|
||||
m_pod_storages.Clear();
|
||||
m_pod_combat.setDeactive();
|
||||
m_pickup_pods.Clear();
|
||||
m_pickup_pod_generated_info.Clear();
|
||||
m_weapons.Clear();
|
||||
m_buffs.Clear();
|
||||
m_round_state_type = BattleRoundStateType.None;
|
||||
m_current_round = 1;
|
||||
m_current_state_start_time = DateTimeHelper.Current;
|
||||
m_charged_step = 0;
|
||||
m_rewarded_step = 0;
|
||||
m_tactical_board.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public class BattleInstanceSnapshotAttribute : EntityAttributeBase, ICopyEntityAttributeFromDoc, IMergeWithEntityAttribute
|
||||
{
|
||||
[JsonProperty]
|
||||
public string m_room_id { get; set; } = string.Empty;
|
||||
|
||||
//아래 데이터들은 일반화 혹은 모드별로 관리 필요
|
||||
//public BattlePlayMode m_play_mode = BattlePlayMode.PodCombat;
|
||||
|
||||
//public DateTime m_create_time { get; set; } = DateTimeHelper.Current;
|
||||
//public DateTime m_destroy_time { get; set; } = DateTimeHelper.MaxTime;
|
||||
|
||||
//todo : 이 코드 들어간 부분은 전부 리펙토링 대상
|
||||
public BattleInstanceSnapshotPlayModePodCombat m_combat_pod_mode { get; set; } = new();
|
||||
|
||||
|
||||
|
||||
public BattleInstanceSnapshotAttribute(EntityBase owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public override void onClear()
|
||||
{
|
||||
m_room_id = string.Empty;
|
||||
m_combat_pod_mode.clear();
|
||||
|
||||
getAttributeState().reset();
|
||||
}
|
||||
|
||||
public override async Task<(Result, DynamoDbDocBase?)> toDocBase(bool isForQuery = true)
|
||||
{
|
||||
var owner = getOwner();
|
||||
|
||||
var result = new Result();
|
||||
|
||||
//=====================================================================================
|
||||
// Attribute => try pending Doc
|
||||
//=====================================================================================
|
||||
var try_pending_doc = getTryPendingDocBase() as BattleInstanceSnapshotDoc;
|
||||
if (null == try_pending_doc)
|
||||
{
|
||||
var to_copy_doc = new BattleInstanceSnapshotDoc(m_room_id);
|
||||
|
||||
var origin_doc = getOriginDocBase<BattleInstanceSnapshotAttribute>();
|
||||
if (null != origin_doc)
|
||||
{
|
||||
to_copy_doc.copyTimestampsFromOriginDocBase(origin_doc);
|
||||
}
|
||||
|
||||
try_pending_doc = to_copy_doc;
|
||||
|
||||
setTryPendingDocBase(try_pending_doc);
|
||||
}
|
||||
|
||||
var to_copy_battle_instance_snapshot_attrib = try_pending_doc.getAttrib<BattleInstanceSnapshotAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(to_copy_battle_instance_snapshot_attrib, () => $"to_copy_battle_instance_snapshot_attrib is null !!!");
|
||||
|
||||
to_copy_battle_instance_snapshot_attrib.m_room_id = m_room_id;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_respawns = m_combat_pod_mode.m_respawns;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_pod_storages = m_combat_pod_mode.m_pod_storages;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_pod_combat = m_combat_pod_mode.m_pod_combat;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_pickup_pods = m_combat_pod_mode.m_pickup_pods;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_pickup_pod_generated_info.AddRange(m_combat_pod_mode.m_pickup_pod_generated_info.Values);
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_weapons = m_combat_pod_mode.m_weapons;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_buffs = m_combat_pod_mode.m_buffs;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_round_state_type = m_combat_pod_mode.m_round_state_type;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_current_round = m_combat_pod_mode.m_current_round;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_current_state_start_time = m_combat_pod_mode.m_current_state_start_time;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_charged_step = m_combat_pod_mode.m_charged_step;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_rewarded_step = m_combat_pod_mode.m_rewarded_step;
|
||||
to_copy_battle_instance_snapshot_attrib.m_combat_pod_attrib.m_tactical_board = m_combat_pod_mode.m_tactical_board;
|
||||
|
||||
if (false == isForQuery)
|
||||
{
|
||||
return (result, try_pending_doc);
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// Doc QueryType 반영
|
||||
//=====================================================================================
|
||||
(result, var to_query_doc) = await applyDoc4Query(try_pending_doc);
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, null);
|
||||
}
|
||||
|
||||
return (result, to_query_doc);
|
||||
}
|
||||
|
||||
|
||||
public override EntityAttributeBase onCloned()
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!! - {toBasicString()}");
|
||||
|
||||
var cloned = new BattleInstanceSnapshotAttribute(owner);
|
||||
cloned.deepCopyFromBase(this);
|
||||
|
||||
cloned.m_room_id = m_room_id;
|
||||
// Respawn 처리
|
||||
foreach (var respawn in m_combat_pod_mode.m_respawns)
|
||||
{
|
||||
var key = respawn.Key;
|
||||
var val = respawn.Value;
|
||||
cloned.m_combat_pod_mode.m_respawns.TryAdd(key, val);
|
||||
}
|
||||
|
||||
// PodStorage 처리
|
||||
foreach (var storage in m_combat_pod_mode.m_pod_storages)
|
||||
{
|
||||
var key = storage.Key;
|
||||
BattleObjectPodStorage battle_object_pod_storage = storage.Value;
|
||||
|
||||
BattleObjectPodStorage new_storage = new(key);
|
||||
new_storage.m_is_active = battle_object_pod_storage.m_is_active;
|
||||
new_storage.m_type = battle_object_pod_storage.m_type;
|
||||
new_storage.m_anchor_guid = battle_object_pod_storage.m_anchor_guid;
|
||||
new_storage.m_active_time = battle_object_pod_storage.m_active_time;
|
||||
new_storage.m_reward_cnt = battle_object_pod_storage.m_reward_cnt;
|
||||
|
||||
cloned.m_combat_pod_mode.m_pod_storages.TryAdd(key, new_storage);
|
||||
}
|
||||
|
||||
// Combat Pod 처리
|
||||
cloned.m_combat_pod_mode.m_pod_combat = new();
|
||||
cloned.m_combat_pod_mode.m_pod_combat.m_type = m_combat_pod_mode.m_pod_combat.m_type;
|
||||
cloned.m_combat_pod_mode.m_pod_combat.m_anchor_guid = m_combat_pod_mode.m_pod_combat.m_anchor_guid;
|
||||
cloned.m_combat_pod_mode.m_pod_combat.m_active_time = m_combat_pod_mode.m_pod_combat.m_active_time;
|
||||
cloned.m_combat_pod_mode.m_pod_combat.m_is_active = m_combat_pod_mode.m_pod_combat.m_is_active;
|
||||
cloned.m_combat_pod_mode.m_pod_combat.m_source_storage_anchor_guid = m_combat_pod_mode.m_pod_combat.m_source_storage_anchor_guid;
|
||||
cloned.m_combat_pod_mode.m_pod_combat.m_state = m_combat_pod_mode.m_pod_combat.m_state;
|
||||
cloned.m_combat_pod_mode.m_pod_combat.m_state_change_time = m_combat_pod_mode.m_pod_combat.m_state_change_time;
|
||||
cloned.m_combat_pod_mode.m_pod_combat.m_currenct_Pos = m_combat_pod_mode.m_pod_combat.m_currenct_Pos.Clone();
|
||||
cloned.m_combat_pod_mode.m_pod_combat.m_current_occupier_guid = m_combat_pod_mode.m_pod_combat.m_current_occupier_guid;
|
||||
cloned.m_combat_pod_mode.m_pod_combat.m_occupied_time = m_combat_pod_mode.m_pod_combat.m_occupied_time;
|
||||
|
||||
//Pickup pod 처리
|
||||
foreach (var pickup_pod in m_combat_pod_mode.m_pickup_pods)
|
||||
{
|
||||
var key = pickup_pod.Key;
|
||||
cloned.m_combat_pod_mode.m_pickup_pods.TryAdd(key, pickup_pod.Value.clone());
|
||||
}
|
||||
|
||||
foreach (var generation_info in m_combat_pod_mode.m_pickup_pod_generated_info)
|
||||
{
|
||||
var key = generation_info.Key;
|
||||
cloned.m_combat_pod_mode.m_pickup_pod_generated_info.TryAdd((key.Item1, key.Item2), generation_info.Value.clone());
|
||||
}
|
||||
|
||||
//Weapon 처리
|
||||
foreach (var weapon in m_combat_pod_mode.m_weapons)
|
||||
{
|
||||
var key = weapon.Key;
|
||||
cloned.m_combat_pod_mode.m_weapons.TryAdd(key, weapon.Value.clone());
|
||||
}
|
||||
|
||||
//Buff 처리
|
||||
foreach (var buff in m_combat_pod_mode.m_buffs)
|
||||
{
|
||||
var key = buff.Key;
|
||||
cloned.m_combat_pod_mode.m_buffs.TryAdd(key, buff.Value.clone());
|
||||
}
|
||||
|
||||
//기타 진행 상황
|
||||
cloned.m_combat_pod_mode.m_round_state_type = m_combat_pod_mode.m_round_state_type;
|
||||
cloned.m_combat_pod_mode.m_current_round = m_combat_pod_mode.m_current_round;
|
||||
cloned.m_combat_pod_mode.m_current_state_start_time = m_combat_pod_mode.m_current_state_start_time;
|
||||
cloned.m_combat_pod_mode.m_charged_step = m_combat_pod_mode.m_charged_step;
|
||||
cloned.m_combat_pod_mode.m_rewarded_step = m_combat_pod_mode.m_rewarded_step;
|
||||
|
||||
//택틱컬 보드 정보
|
||||
foreach (var board in m_combat_pod_mode.m_tactical_board)
|
||||
{
|
||||
var key = board.Key;
|
||||
cloned.m_combat_pod_mode.m_tactical_board.TryAdd(key, board.Value.clone());
|
||||
}
|
||||
|
||||
return cloned;
|
||||
|
||||
}
|
||||
|
||||
public Result onMerge(EntityAttributeBase otherEntityAttribute)
|
||||
{
|
||||
var owner = getOwner();
|
||||
NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!! - {toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (null == otherEntityAttribute)
|
||||
{
|
||||
err_msg = $"Invalid Param !!!, otherEntityAttribute is null";
|
||||
result.setFail(ServerErrorCode.FunctionParamNull, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
var other_attribute = otherEntityAttribute as BattleInstanceSnapshotAttribute;
|
||||
if (null == other_attribute)
|
||||
{
|
||||
err_msg = $"Failed to cast BattleInstanceSnapshotAttribute !!!, other_attribute is null";
|
||||
result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// OtherAttribute => Attribute
|
||||
//=====================================================================================
|
||||
m_room_id = other_attribute.m_room_id;
|
||||
|
||||
m_combat_pod_mode.m_respawns = other_attribute.m_combat_pod_mode.m_respawns;
|
||||
m_combat_pod_mode.m_pod_storages = other_attribute.m_combat_pod_mode.m_pod_storages;
|
||||
m_combat_pod_mode.m_pod_combat = other_attribute.m_combat_pod_mode.m_pod_combat;
|
||||
m_combat_pod_mode.m_pickup_pods = other_attribute.m_combat_pod_mode.m_pickup_pods;
|
||||
m_combat_pod_mode.m_pickup_pod_generated_info = other_attribute.m_combat_pod_mode.m_pickup_pod_generated_info;
|
||||
|
||||
m_combat_pod_mode.m_weapons = other_attribute.m_combat_pod_mode.m_weapons;
|
||||
m_combat_pod_mode.m_buffs = other_attribute.m_combat_pod_mode.m_buffs;
|
||||
m_combat_pod_mode.m_round_state_type = other_attribute.m_combat_pod_mode.m_round_state_type;
|
||||
m_combat_pod_mode.m_current_round = other_attribute.m_combat_pod_mode.m_current_round;
|
||||
m_combat_pod_mode.m_current_state_start_time = other_attribute.m_combat_pod_mode.m_current_state_start_time;
|
||||
m_combat_pod_mode.m_charged_step = other_attribute.m_combat_pod_mode.m_charged_step;
|
||||
m_combat_pod_mode.m_rewarded_step = other_attribute.m_combat_pod_mode.m_rewarded_step;
|
||||
m_combat_pod_mode.m_tactical_board = other_attribute.m_combat_pod_mode.m_tactical_board;
|
||||
|
||||
|
||||
|
||||
//=====================================================================================
|
||||
// Attribute Try Pending Doc => Origin Doc
|
||||
//=====================================================================================
|
||||
var try_pending_doc = other_attribute.getTryPendingDocBase() as BattleInstanceSnapshotDoc;
|
||||
if (null != try_pending_doc)
|
||||
{
|
||||
other_attribute.resetTryPendingDocBase();
|
||||
|
||||
syncOriginDocBaseWithNewDoc<BattleInstanceSnapshotAttribute>(try_pending_doc);
|
||||
}
|
||||
|
||||
var origin_doc_base = getOriginDocBase<BattleInstanceSnapshotAttribute>();
|
||||
if (null == origin_doc_base)
|
||||
{
|
||||
// DB 에 저장되어 있지 않는 경우 OriginDoc은 null 이다 !!!
|
||||
return result;
|
||||
}
|
||||
|
||||
var battle_instance_snapshot_attrib = origin_doc_base.getAttrib<BattleInstanceSnapshotAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_snapshot_attrib, () => $"battle_instance_snapshot_attrib is null !!! - {owner.toBasicString()}");
|
||||
|
||||
battle_instance_snapshot_attrib.m_room_id = m_room_id;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_respawns = m_combat_pod_mode.m_respawns;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_pod_storages = m_combat_pod_mode.m_pod_storages;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_pod_combat = m_combat_pod_mode.m_pod_combat;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_pickup_pods = m_combat_pod_mode.m_pickup_pods;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_pickup_pod_generated_info.AddRange(m_combat_pod_mode.m_pickup_pod_generated_info.Values);
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_weapons = m_combat_pod_mode.m_weapons;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_buffs = m_combat_pod_mode.m_buffs;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_round_state_type = m_combat_pod_mode.m_round_state_type;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_current_round = m_combat_pod_mode.m_current_round;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_current_state_start_time = m_combat_pod_mode.m_current_state_start_time;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_charged_step = m_combat_pod_mode.m_charged_step;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_rewarded_step = m_combat_pod_mode.m_rewarded_step;
|
||||
battle_instance_snapshot_attrib.m_combat_pod_attrib.m_tactical_board = m_combat_pod_mode.m_tactical_board;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public bool copyEntityAttributeFromDoc(DynamoDbDocBase? docBase)
|
||||
{
|
||||
var battle_instance_snapshot_doc_base = docBase as BattleInstanceSnapshotDoc;
|
||||
if (null == battle_instance_snapshot_doc_base)
|
||||
{
|
||||
var to_cast_string = typeof(BattleInstanceSnapshotDoc).Name;
|
||||
var err_msg = $"Failed to copyEntityAttributeFromDoc() !!!, item_doc_base is null :{to_cast_string}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// New Doc => Origin Doc
|
||||
//=====================================================================================
|
||||
syncOriginDocBaseWithNewDoc<BattleInstanceSnapshotAttribute>(battle_instance_snapshot_doc_base);
|
||||
|
||||
//=====================================================================================
|
||||
// Doc => Attribute
|
||||
//=====================================================================================
|
||||
var doc_attrib = battle_instance_snapshot_doc_base.getAttrib<BattleInstanceSnapshotAttrib>();
|
||||
NullReferenceCheckHelper.throwIfNull(doc_attrib, () => $"doc_attrib is null !!! - {toBasicString()}");
|
||||
|
||||
m_room_id = doc_attrib.m_room_id;
|
||||
m_combat_pod_mode.m_respawns = doc_attrib.m_combat_pod_attrib.m_respawns;
|
||||
m_combat_pod_mode.m_pod_storages = doc_attrib.m_combat_pod_attrib.m_pod_storages;
|
||||
m_combat_pod_mode.m_pod_combat = doc_attrib.m_combat_pod_attrib.m_pod_combat;
|
||||
m_combat_pod_mode.m_pickup_pods = doc_attrib.m_combat_pod_attrib.m_pickup_pods;
|
||||
|
||||
foreach (var generated_info in doc_attrib.m_combat_pod_attrib.m_pickup_pod_generated_info)
|
||||
{
|
||||
m_combat_pod_mode.m_pickup_pod_generated_info.AddOrUpdate((generated_info.m_group_id, generated_info.m_idx), generated_info, (key, old) => generated_info);
|
||||
}
|
||||
|
||||
m_combat_pod_mode.m_weapons = doc_attrib.m_combat_pod_attrib.m_weapons;
|
||||
m_combat_pod_mode.m_buffs = doc_attrib.m_combat_pod_attrib.m_buffs;
|
||||
m_combat_pod_mode.m_round_state_type = doc_attrib.m_combat_pod_attrib.m_round_state_type;
|
||||
m_combat_pod_mode.m_current_round = doc_attrib.m_combat_pod_attrib.m_current_round;
|
||||
m_combat_pod_mode.m_current_state_start_time = doc_attrib.m_combat_pod_attrib.m_current_state_start_time;
|
||||
m_combat_pod_mode.m_charged_step = doc_attrib.m_combat_pod_attrib.m_charged_step;
|
||||
m_combat_pod_mode.m_rewarded_step = doc_attrib.m_combat_pod_attrib.m_rewarded_step;
|
||||
m_combat_pod_mode.m_tactical_board = doc_attrib.m_combat_pod_attrib.m_tactical_board;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override IEntityAttributeTransactor onNewEntityAttributeTransactor()
|
||||
{
|
||||
return new BattleInstanceSnapshotAttributeTransactor(getOwner());
|
||||
}
|
||||
|
||||
|
||||
public class BattleInstanceSnapshotAttributeTransactor :
|
||||
EntityAttributeTransactorBase<BattleInstanceSnapshotAttribute>,
|
||||
ICopyEntityAttributeTransactorFromEntityAttribute
|
||||
{
|
||||
|
||||
public BattleInstanceSnapshotAttributeTransactor(EntityBase owner) : base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public bool copyEntityAttributeTransactorFromEntityAttribute(EntityAttributeBase entityAttributeBase)
|
||||
{
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var copy_from_attribute = entityAttributeBase as BattleInstanceSnapshotAttribute;
|
||||
if (null == copy_from_attribute)
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeTransactorFromEntityAttribute() !!!, copy_from_craft_attribute is null : BattleInstanceSnapshotAttribute";
|
||||
Log.getLogger().error(err_msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
var copy_to_attribute = getClonedEntityAttribute() as BattleInstanceSnapshotAttribute;
|
||||
if (null == copy_to_attribute)
|
||||
{
|
||||
err_msg = $"Failed to copyEntityAttributeTransactorFromEntityAttribute() !!!, copy_to_craft_attribute is null : BattleInstanceSnapshotAttribute";
|
||||
Log.getLogger().error(err_msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
copy_to_attribute.m_room_id = copy_from_attribute.m_room_id;
|
||||
|
||||
copy_to_attribute.m_combat_pod_mode.m_respawns = copy_from_attribute.m_combat_pod_mode.m_respawns;
|
||||
copy_to_attribute.m_combat_pod_mode.m_pod_storages = copy_from_attribute.m_combat_pod_mode.m_pod_storages;
|
||||
copy_to_attribute.m_combat_pod_mode.m_pod_combat = copy_from_attribute.m_combat_pod_mode.m_pod_combat;
|
||||
copy_to_attribute.m_combat_pod_mode.m_pickup_pods = copy_from_attribute.m_combat_pod_mode.m_pickup_pods;
|
||||
copy_to_attribute.m_combat_pod_mode.m_pickup_pod_generated_info = copy_from_attribute.m_combat_pod_mode.m_pickup_pod_generated_info;
|
||||
copy_to_attribute.m_combat_pod_mode.m_weapons = copy_from_attribute.m_combat_pod_mode.m_weapons;
|
||||
copy_to_attribute.m_combat_pod_mode.m_buffs = copy_from_attribute.m_combat_pod_mode.m_buffs;
|
||||
copy_to_attribute.m_combat_pod_mode.m_round_state_type = copy_from_attribute.m_combat_pod_mode.m_round_state_type;
|
||||
copy_to_attribute.m_combat_pod_mode.m_current_round = copy_from_attribute.m_combat_pod_mode.m_current_round;
|
||||
copy_to_attribute.m_combat_pod_mode.m_current_state_start_time = copy_from_attribute.m_combat_pod_mode.m_current_state_start_time;
|
||||
copy_to_attribute.m_combat_pod_mode.m_charged_step = copy_from_attribute.m_combat_pod_mode.m_charged_step;
|
||||
copy_to_attribute.m_combat_pod_mode.m_rewarded_step = copy_from_attribute.m_combat_pod_mode.m_rewarded_step;
|
||||
copy_to_attribute.m_combat_pod_mode.m_tactical_board = copy_from_attribute.m_combat_pod_mode.m_tactical_board;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
using System.Collections.Concurrent;
|
||||
using Newtonsoft.Json;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleInstanceSnapshotPlayModePodCombatAttrib
|
||||
{
|
||||
[JsonProperty("respawns")]
|
||||
public ConcurrentDictionary<string, DateTime> m_respawns {get; set;} = new ();
|
||||
|
||||
[JsonProperty("pod_storages")]
|
||||
public ConcurrentDictionary<string /*anchor_guid*/, BattleObjectPodStorage> m_pod_storages {get; set;} = new ();
|
||||
[JsonProperty("pod_combat")]
|
||||
public BattleObjectPodCombat m_pod_combat {get; set;} = new ();
|
||||
|
||||
[JsonProperty("pickup_pods")]
|
||||
public ConcurrentDictionary<string /*anchor_guid*/, BattleObjectPickupPod> m_pickup_pods {get; set;} = new ();
|
||||
|
||||
|
||||
[JsonProperty("pickup_pods_generation_info")] public List<PickupPodGeneratedInfo> m_pickup_pod_generated_info { get; set; } = new();
|
||||
|
||||
[JsonProperty("weapons")]
|
||||
public ConcurrentDictionary<string /*anchor_guid*/, BattleObjectWeapon> m_weapons {get; set;} = new ();
|
||||
|
||||
[JsonProperty("buffs")]
|
||||
public ConcurrentDictionary<string /*anchor_guid*/, BattleObjectBuff> m_buffs {get; set;} = new ();
|
||||
|
||||
[JsonProperty("state")] public BattleRoundStateType m_round_state_type { get; set; } = BattleRoundStateType.Rounding;
|
||||
[JsonProperty("round")] public int m_current_round { get; set; } = 1;
|
||||
[JsonProperty("state_start_time")] public DateTime m_current_state_start_time { get; set; } = DateTimeHelper.Current;
|
||||
|
||||
[JsonProperty("charged_step")] public int m_charged_step { get; set; } = 0;
|
||||
[JsonProperty("rewarded_step")] public int m_rewarded_step { get; set; } = 0;
|
||||
|
||||
[JsonProperty("tactical_board")] public ConcurrentDictionary<string /*user_guid*/, BattleTacticalBoardInfo> m_tactical_board = new();
|
||||
}
|
||||
|
||||
public class BattleInstanceSnapshotAttrib : AttribBase
|
||||
{
|
||||
[JsonProperty("room_id")]
|
||||
public string m_room_id { get; set; } = string.Empty;
|
||||
|
||||
[JsonProperty("combat_pod_attrib")]
|
||||
public BattleInstanceSnapshotPlayModePodCombatAttrib m_combat_pod_attrib { get; set; } = new();
|
||||
|
||||
public BattleInstanceSnapshotAttrib()
|
||||
: base(typeof(BattleInstanceSnapshotAttrib).Name)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================================
|
||||
// PK(Partition Key) : "battle_instance_snapshot#global"
|
||||
// SK(Sort Key) : "date#room_id"
|
||||
// DocType : BattleInstanceSnapshotDoc
|
||||
// BlockUserAttrib : {}
|
||||
// ...
|
||||
//=============================================================================================
|
||||
public class BattleInstanceSnapshotDoc : DynamoDbDocBase
|
||||
{
|
||||
public static readonly string pk = "battle_instance_snapshot#global";
|
||||
|
||||
public BattleInstanceSnapshotDoc()
|
||||
: base(typeof(BattleInstanceSnapshotDoc).Name)
|
||||
{
|
||||
appendAttribWrapper(new AttribWrapper<BattleInstanceSnapshotAttrib>());
|
||||
}
|
||||
|
||||
public BattleInstanceSnapshotDoc(string combinationKeyForSk)
|
||||
: base(typeof(BattleInstanceSnapshotDoc).Name)
|
||||
{
|
||||
setCombinationKeyForSK(combinationKeyForSk);
|
||||
appendAttribWrapper(new AttribWrapper<BattleInstanceSnapshotAttrib>());
|
||||
fillUpPrimaryKey(onMakePK(), onMakeSK());
|
||||
}
|
||||
|
||||
protected override string onGetPrefixOfPK()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
protected override string onMakePK()
|
||||
{
|
||||
return pk;
|
||||
}
|
||||
|
||||
// protected override string onMakeSK()
|
||||
// {
|
||||
// return $"{getCombinationKeyForSK()}";
|
||||
//
|
||||
// }
|
||||
|
||||
protected override ServerErrorCode onCheckAndSetPK(string partitionKey)
|
||||
{
|
||||
getPrimaryKey().fillUpPK(partitionKey);
|
||||
return ServerErrorCode.Success;
|
||||
}
|
||||
|
||||
protected override ServerErrorCode onCheckAndSetSK(string sortKey)
|
||||
{
|
||||
getPrimaryKey().fillUpSK(sortKey);
|
||||
return ServerErrorCode.Success;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattlePlayer : EntityBase
|
||||
{
|
||||
private Player m_player;
|
||||
public BattlePlayer(Player player) : base(EntityType.BattlePlayer)
|
||||
{
|
||||
m_player = player;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class SystemBattleEvent
|
||||
{
|
||||
public Int32 m_event_id { get; set; } = 0;
|
||||
public Int32 m_instance_id { get; set; } = 0;
|
||||
|
||||
public DateTime m_ready_time { get; set; } = DateTimeHelper.Current;
|
||||
public bool m_is_send_noti { get; set; } = false;
|
||||
|
||||
public DateTime m_start_time { get; set; } = DateTimeHelper.Current;
|
||||
public Int32 m_ffa_config_data_id { get; set; } = 4;
|
||||
public Int32 m_ffa_reward_group_id { get; set; } = 7;
|
||||
public Int32 m_ffa_hot_time { get; set; } = 1;
|
||||
public Int32 m_round_count { get; set; } = 4;
|
||||
|
||||
public SystemBattleEvent()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace GameServer;
|
||||
|
||||
public static class BattleConstant
|
||||
{
|
||||
public static readonly string PREFIX_BATTLE_INSTANCE_ROOM_ID = "battle_instance";
|
||||
public static readonly string RESPAWN_POS_ANCHOR_NAME = "AT_RespawnPos";
|
||||
public static readonly string BATTLE_OBJECT_ANCHOR_NAME = "AT_BattleObject";
|
||||
public static readonly string BATTLE_OBJECT_GROUP_ANCHOR_NAME = "AT_BattleObjectGroup";
|
||||
public static readonly string BATTLE_ROOM_TRANSACTION_ID_NAME = "BattleRoom";
|
||||
public static readonly string BATTLE_POD_STORAGE_NAME = "Pod_CombatStand";
|
||||
public static readonly string PREFIX_BATTLE_TRANSACTION_GUID = "battle_tran:";
|
||||
public static readonly string BATTLE_INSTANCE_TRANSACTION_NAME = "BattleInstanceUpdate";
|
||||
|
||||
|
||||
public static readonly int BATTLE_EVENT_CHECK_INTERVAL = 240_000;//4분
|
||||
public static readonly int BATTLE_ROOM_CHECK_INTERVAL = 200;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
using MetaAssets;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public static class BattleInstancePlayModeHelper
|
||||
{
|
||||
|
||||
public static BattleInstancesObject? getBattleObject(string anchorGuid, BattleInstanceSnapshotAttribute attribute, EBattleObjectType type)
|
||||
{
|
||||
BattleInstancesObject? battle_instance_object = null;
|
||||
if (type.Equals(EBattleObjectType.Weapon))
|
||||
{
|
||||
battle_instance_object = getBattleObjectWeapon(anchorGuid, attribute);
|
||||
}
|
||||
else if (type.Equals(EBattleObjectType.Buff))
|
||||
{
|
||||
battle_instance_object = getBattleObjectBuff(anchorGuid, attribute);
|
||||
}
|
||||
else if (type.Equals(EBattleObjectType.Pod_Combat))
|
||||
{
|
||||
battle_instance_object = getBattleObjectPodCombat(anchorGuid, attribute);
|
||||
}
|
||||
else if (type.Equals(EBattleObjectType.Pod_Box))
|
||||
{
|
||||
battle_instance_object = getBattleObjectPickupPod(anchorGuid, attribute);
|
||||
}
|
||||
|
||||
return battle_instance_object;
|
||||
}
|
||||
|
||||
private static BattleInstancesObject getBattleObjectWeapon(string anchorGuid, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
if (false == attribute.m_combat_pod_mode.m_weapons.TryGetValue(anchorGuid, out var battle_instance_object_weapon))
|
||||
{
|
||||
battle_instance_object_weapon = new BattleObjectWeapon(anchorGuid);
|
||||
attribute.m_combat_pod_mode.m_weapons.TryAdd(anchorGuid, battle_instance_object_weapon);
|
||||
}
|
||||
return battle_instance_object_weapon;
|
||||
}
|
||||
|
||||
private static BattleInstancesObject getBattleObjectBuff(string anchorGuid, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
if (false == attribute.m_combat_pod_mode.m_buffs.TryGetValue(anchorGuid, out var battle_instance_object_buff))
|
||||
{
|
||||
battle_instance_object_buff = new BattleObjectBuff(anchorGuid);
|
||||
attribute.m_combat_pod_mode.m_buffs.TryAdd(anchorGuid, battle_instance_object_buff);
|
||||
}
|
||||
return battle_instance_object_buff;
|
||||
}
|
||||
|
||||
private static BattleInstancesObject getBattleObjectPodCombat(string anchorGuid, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
if (false == attribute.m_combat_pod_mode.m_pod_storages.TryGetValue(anchorGuid, out var storages))
|
||||
{
|
||||
storages = new BattleObjectPodStorage(anchorGuid);
|
||||
attribute.m_combat_pod_mode.m_pod_storages.TryAdd(anchorGuid, storages);
|
||||
}
|
||||
|
||||
return storages;
|
||||
}
|
||||
|
||||
private static BattleInstancesObject getBattleObjectPickupPod(string anchorGuid, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
if (false == attribute.m_combat_pod_mode.m_pickup_pods.TryGetValue(anchorGuid, out var pickupPod))
|
||||
{
|
||||
Log.getLogger().warn($"not exist pickup pod so..create anchorguid : {anchorGuid}");
|
||||
pickupPod = new BattleObjectPickupPod(anchorGuid);
|
||||
pickupPod.m_is_active = false;
|
||||
attribute.m_combat_pod_mode.m_pickup_pods.TryAdd(anchorGuid, pickupPod);
|
||||
}
|
||||
|
||||
return pickupPod;
|
||||
}
|
||||
|
||||
public static bool isPodCombat(BattleInstanceSnapshotAttribute attribute, string anchorGuid)
|
||||
{
|
||||
return attribute.m_combat_pod_mode.m_pod_combat.m_anchor_guid.Equals(anchorGuid);
|
||||
}
|
||||
|
||||
|
||||
public static (Result, BattleObjectMetaData) getBattleObjectMeta(string anchorGuid, BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
var map = battleInstanceRoom.m_instance_room.getMap();
|
||||
string err_msg = string.Empty;
|
||||
var result = new Result();
|
||||
if(false == map.m_anchors.TryGetValue(anchorGuid, out var anchorInfo))
|
||||
{
|
||||
err_msg = $"Anchor Info Not Exist.... room_id : {map.m_room_id} anchor guid : {anchorGuid}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceNotExistAnchors, err_msg);
|
||||
return (result, new(new BattleObjectMetaDataMutable()));
|
||||
}
|
||||
|
||||
if (false == MapDataTable.Instance.getAnchor(anchorGuid, out var anchor))
|
||||
{
|
||||
err_msg = $"Not found Anchor in MapFileType !!! : anchourGuid:{anchorGuid}";
|
||||
//Log.getLogger(err_msg);
|
||||
result.setFail(ServerErrorCode.BattleInstanceNotExistAnchors, err_msg);
|
||||
return (result, new(new BattleObjectMetaDataMutable()));
|
||||
}
|
||||
|
||||
var table_id = anchorInfo.AnchorProp.TableId;
|
||||
|
||||
if (anchor.Type.Equals(BattleConstant.BATTLE_OBJECT_GROUP_ANCHOR_NAME))
|
||||
{
|
||||
if (false == MetaData.Instance._BattleObjectSpawnGroupMetaTable.TryGetValue(table_id, out var battle_object_spawn_group_meta))
|
||||
{
|
||||
err_msg = $"_BattleObjectSpawnGroupMetaTable data Not Exist.... room_id : {map.m_room_id} anchor guid : {anchorGuid}, tableId : {table_id}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceObjectMetaNotExist, err_msg);
|
||||
return (result, new(new BattleObjectMetaDataMutable()));
|
||||
}
|
||||
|
||||
table_id = battle_object_spawn_group_meta.BattleObjectID;
|
||||
}
|
||||
|
||||
if (false == MetaData.Instance._BattleObjectMetaTable.TryGetValue(table_id, out var battle_object_meta))
|
||||
{
|
||||
err_msg = $"_BattleObjectMetaTable data Not Exist.... room_id : {map.m_room_id} anchor guid : {anchorGuid}, tableId : {table_id}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceObjectMetaNotExist, err_msg);
|
||||
return (result, new(new BattleObjectMetaDataMutable()));
|
||||
}
|
||||
|
||||
return (result, battle_object_meta);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
//인터렉션 로직에 대한 정보를 저장후 처리
|
||||
public class BattleObjectInteractionLogicHandler
|
||||
{
|
||||
public BattleObjectInteractionLogicHandler(string userGuid, string userNickname, string interactionAnchorGuid, string roomId)
|
||||
{
|
||||
m_user_guid = userGuid;
|
||||
m_interaction_anchor_guid = interactionAnchorGuid;
|
||||
|
||||
m_interaction_log_info.m_interaction_anchor_guid = interactionAnchorGuid;
|
||||
m_interaction_log_info.m_interaction_user_guid = userGuid;
|
||||
m_interaction_log_info.m_interaction_user_nickname = userNickname;
|
||||
m_interaction_log_info.m_room_id = roomId;
|
||||
}
|
||||
public string m_user_guid { get; } = string.Empty;
|
||||
public string m_interaction_anchor_guid { get; } = string.Empty;
|
||||
public BattleObjectMetaData m_battle_object_meta { get; set; } = new(new BattleObjectMetaDataMutable());
|
||||
public BattleInstancesObject m_battle_object { get; set; } = new BattleObjectEmpty();
|
||||
|
||||
public bool m_is_combat_pod { get; set; } = false; //true : 전달 받은 anchor_guid 가 combat pod을 의미한다.
|
||||
|
||||
public BattleObjectPodCombat? m_pod_combat { get; set; } = null;
|
||||
|
||||
public bool m_is_need_combat_pod_noti { get; set; } = false;
|
||||
|
||||
public List<BattleInstancesObject> m_need_noti_objects { get; set; } = new(); //인터렉션시 종속적으로상태가 같이 바뀌는 object들은 여기에 넣어서 나중에 noti 보낼때 사용
|
||||
|
||||
public DateTime m_object_active_time { get; set; } = DateTimeHelper.Current;
|
||||
|
||||
|
||||
public BattleObjectInteractionLogInfo m_interaction_log_info { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
using Newtonsoft.Json;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
using Contents.GameMode.Helper;
|
||||
|
||||
public class BattleRoomHelper
|
||||
{
|
||||
public static Result checkBattleActive(EPlaceType type)
|
||||
{
|
||||
var result = new Result();
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var server_config = server_logic.getServerConfig();
|
||||
bool is_battle_system_active = server_config.BattleSystemEnable;
|
||||
|
||||
if (type == EPlaceType.BattleRoom && is_battle_system_active) return result;
|
||||
|
||||
string err_msg = $"BattleSystem Not Active!!!! type : {type}, is_battle_system_active : {is_battle_system_active}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceInActive, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool checkBattleActive()
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var server_config = server_logic.getServerConfig();
|
||||
bool is_battle_system_active = server_config.BattleSystemEnable;
|
||||
|
||||
if (is_battle_system_active) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static (Result, string) getRandomCombatPodAnchorGuid(BattleInstanceSnapshotAttribute attribute, BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
string err_msg = string.Empty;
|
||||
var keys = new List<int>(battleInstanceRoom.m_battle_pod_storage_guid_group.Keys);
|
||||
if (keys.Count == 0)
|
||||
{
|
||||
err_msg = $"battle_instance_room.m_battle_pod_stand_group_pos_meta Keys Count is zero battle_instance_room : {battleInstanceRoom.m_instance_room.getMap().m_room_id}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceNotExistAnchors, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return (result, string.Empty);
|
||||
}
|
||||
|
||||
Random random = new Random();
|
||||
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
// 첫 번째 랜덤: battle_group_id 선택
|
||||
int random_group_idx = random.Next(keys.Count);
|
||||
int selected_battle_group_id = keys[random_group_idx];
|
||||
|
||||
// 선택된 battle_group_id의 List<BattlePosMeta> 가져오기
|
||||
if (false == battleInstanceRoom.m_battle_pod_storage_guid_group.TryGetValue(selected_battle_group_id, out var battle_pos_metas))
|
||||
{
|
||||
err_msg = $"battle_instance_room.m_battle_pod_stand_group_pos_meta value not exist battle_instance_room : {battleInstanceRoom.m_instance_room.getMap().m_room_id}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceNotExistAnchors, err_msg);
|
||||
return (result, string.Empty);
|
||||
}
|
||||
|
||||
// 두 번째 랜덤: List<BattlePosMeta>에서 BattlePosMeta 선택
|
||||
List<string> pos_metas = battle_pos_metas.ToList();
|
||||
if (pos_metas.Count == 0) continue;
|
||||
|
||||
int random_idx = random.Next(pos_metas.Count);
|
||||
var anchor_guid = pos_metas[random_idx];
|
||||
return (result, anchor_guid);
|
||||
}
|
||||
|
||||
err_msg = $"not exist anchorGuid {battleInstanceRoom.m_instance_room.getMap().m_room_id}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceNotExistAnchors, err_msg);
|
||||
return (result, string.Empty);
|
||||
}
|
||||
|
||||
public static (Result, string) getRandomRespawnPos(BattleInstanceSnapshotAttribute attribute, BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
List<string> active_respawns = new();
|
||||
var now = DateTimeHelper.Current;
|
||||
foreach (var respawn_info in attribute.m_combat_pod_mode.m_respawns)
|
||||
{
|
||||
var key = respawn_info.Key;
|
||||
var next_respawn_time = respawn_info.Value;
|
||||
|
||||
if(next_respawn_time <= now ) active_respawns.Add(key);
|
||||
}
|
||||
|
||||
var result = new Result();
|
||||
|
||||
if (active_respawns.Count == 0)
|
||||
{
|
||||
var err_msg = $"respawn pos not exist now : {now}, respawnInfo : {JsonConvert.SerializeObject(attribute.m_combat_pod_mode.m_respawns)} ";
|
||||
result.setFail(ServerErrorCode.BattleInstanceUsableSpawnPointNotExist, err_msg);
|
||||
return (result, string.Empty);
|
||||
}
|
||||
|
||||
Random random = new Random();
|
||||
int random_idx = random.Next(active_respawns.Count);
|
||||
var guid = active_respawns[random_idx];
|
||||
|
||||
|
||||
return (result, guid);
|
||||
}
|
||||
|
||||
|
||||
public static (Result, string) getRandomPickupPod(int groupId, int idx, BattleInstanceRoom battleInstanceRoom, BattleInstanceSnapshotAttribute attribute)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
string err_msg = string.Empty;
|
||||
Random random = new Random();
|
||||
|
||||
//선택된 battle_group_id의 List<BattlePosMeta> 가져오기
|
||||
if (false == battleInstanceRoom.m_battle_pickup_pod_guid_group.TryGetValue(groupId, out var pickup_pod_guid_group))
|
||||
{
|
||||
err_msg = $"battle_instance_room.m_battle_pickup_pod_group_pos_meta value not exist battle_instance_room : {battleInstanceRoom.m_instance_room.getMap().m_room_id}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceNotExistAnchors, err_msg);
|
||||
return (result, string.Empty);
|
||||
}
|
||||
|
||||
// 두 번째 랜덤: List<BattlePosMeta>에서 BattlePosMeta 선택
|
||||
//bool is_duplicate = false;
|
||||
HashSet<string> old_allocated_guids = new();
|
||||
foreach (var infos in attribute.m_combat_pod_mode.m_pickup_pod_generated_info)
|
||||
{
|
||||
var generated_info = infos.Value;
|
||||
var group_id = infos.Key.Item1;
|
||||
var generated_idx = infos.Key.Item2;
|
||||
if (false == generated_info.m_anchor_guid.Equals(string.Empty))
|
||||
{
|
||||
old_allocated_guids.Add(generated_info.m_anchor_guid);
|
||||
}
|
||||
if (false == generated_info.m_before_anchor_guid.Equals(string.Empty) && generated_idx == idx)
|
||||
{
|
||||
old_allocated_guids.Add(generated_info.m_before_anchor_guid);
|
||||
}
|
||||
}
|
||||
|
||||
List<string> guids = pickup_pod_guid_group.ToList();
|
||||
foreach (var old_guid in old_allocated_guids)
|
||||
{
|
||||
guids.Remove(old_guid);
|
||||
}
|
||||
|
||||
|
||||
if (guids.Count == 0)
|
||||
{
|
||||
err_msg = $"guids count is zero..so can't assing pickup pod reward... old_allocated_guids : {JsonConvert.SerializeObject(old_allocated_guids)}, " +
|
||||
$"pickup pod info : {JsonConvert.SerializeObject(attribute.m_combat_pod_mode.m_pickup_pod_generated_info)}";
|
||||
result.setFail(ServerErrorCode.BattleInstancePickupPodRewardAllocateError, err_msg);
|
||||
return (result, string.Empty);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int random_idx = random.Next(guids.Count);
|
||||
var anchor_guid = guids[random_idx];
|
||||
|
||||
return (result, anchor_guid);
|
||||
}
|
||||
|
||||
|
||||
public static SystemBattleEvent? getBattleRoomStartTimeByEventId(string roomId)
|
||||
{
|
||||
|
||||
//instanceroom:battle_instance:0:1017006:timestamp:5978:info//룸ID의 형태
|
||||
|
||||
var event_id = getBattleEventIdFromRoomId(roomId);
|
||||
|
||||
if (event_id == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (false == BattleInstanceManager.It.getSystemBattleEvent(event_id, out var battleEvent))
|
||||
{
|
||||
Log.getLogger().error($"system battle event not exist eventId : {event_id}, total events : {JsonConvert.SerializeObject(BattleInstanceManager.It.getSystemBattleEvents())}");
|
||||
return null;
|
||||
}
|
||||
return battleEvent;
|
||||
}
|
||||
|
||||
public static int getBattleEventIdFromRoomId(string roomId)
|
||||
{
|
||||
var arr_room_tokens = roomId.Split(":");
|
||||
var event_tokens = arr_room_tokens[1].Split("_");
|
||||
if (false == int.TryParse(event_tokens[0], out var eventId))
|
||||
{
|
||||
Log.getLogger().error($"arr_room_tokens parse error !!!! roomId : {arr_room_tokens}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return eventId;
|
||||
}
|
||||
|
||||
public static DateTime calculateDestroyedTime(DateTime startTime, Int32 configId, Int32 roundCount)
|
||||
{
|
||||
if (false == MetaData.Instance._BattleFFAConfigMetaTable.TryGetValue(configId, out var meta))
|
||||
{
|
||||
Log.getLogger().error($"Not Exist _BattleFFAConfigMetaTable configId : {configId}");
|
||||
return DateTimeHelper.Current.AddSeconds(-10);
|
||||
}
|
||||
|
||||
if (roundCount < 1)
|
||||
{
|
||||
Log.getLogger().error($"roundCount less than 1 roundCount : {roundCount}");
|
||||
return DateTimeHelper.Current.AddSeconds(-10);
|
||||
}
|
||||
|
||||
var round_time = meta.RoundTime;
|
||||
var wait_time = meta.NextRoundWaitTime;
|
||||
var result_time = meta.ResultUIWaitTime;
|
||||
|
||||
var process_time_sec = (round_time * roundCount) + (wait_time * (roundCount - 1)) + result_time;
|
||||
|
||||
return startTime.AddSeconds(process_time_sec);
|
||||
}
|
||||
|
||||
|
||||
public static DateTime calculateRoomJoinableTime(DateTime startTime, Int32 configId, Int32 roundCount)
|
||||
{
|
||||
if (false == MetaData.Instance._BattleFFAConfigMetaTable.TryGetValue(configId, out var meta))
|
||||
{
|
||||
Log.getLogger().error($"Not Exist _BattleFFAConfigMetaTable configId : {configId}");
|
||||
return DateTimeHelper.Current.AddSeconds(-10);
|
||||
}
|
||||
|
||||
if (roundCount < 1)
|
||||
{
|
||||
Log.getLogger().error($"roundCount less than 1 roundCount : {roundCount}");
|
||||
return DateTimeHelper.Current.AddSeconds(-10);
|
||||
}
|
||||
|
||||
|
||||
var round_time = meta.RoundTime;
|
||||
var wait_time = meta.NextRoundWaitTime;
|
||||
|
||||
var process_time_sec = (round_time * roundCount) + (wait_time * (roundCount - 1)) - meta.EntranceClosingTime;
|
||||
|
||||
return startTime.AddSeconds(process_time_sec);
|
||||
}
|
||||
|
||||
public static IHostMigrator createHostMigrator(BattlePlayMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case BattlePlayMode.PodCombat:
|
||||
return HostMigrationFactory.createCommonHostMigrator((int) BattlePlayMode.PodCombat, GameServerApp.getServerLogic());
|
||||
//return new BattleFFAModeHostMigrator();
|
||||
default:
|
||||
Log.getLogger($"createHostMigrator Not implements mode : {mode}");
|
||||
throw new NotImplementedException();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Newtonsoft.Json;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public static class BattleRoomNotifyHelper
|
||||
{
|
||||
|
||||
public static void send_GS2C_NTF_POD_COMBAT_STATE(BattleInstanceRoom battleInstanceRoom, Player player)
|
||||
{
|
||||
var ntf = makePodCombatStateNotify(battleInstanceRoom);
|
||||
GameServerApp.getServerLogic().onSendPacket(player, ntf);
|
||||
}
|
||||
|
||||
public static void broadcast_GS2C_NTF_POD_COMBAT_STATE(BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
var ntf = makePodCombatStateNotify(battleInstanceRoom);
|
||||
|
||||
Log.getLogger().debug($"broadcast_GS2C_NTF_POD_COMBAT_STATE ntf battleInstanceRoom Id : {battleInstanceRoom.m_instance_room.getMap().m_room_id} data : {JsonConvert.SerializeObject(ntf.Message.NtfPodCombatState)}");
|
||||
|
||||
battleInstanceRoom.m_instance_room.Broadcast(ntf);
|
||||
}
|
||||
|
||||
private static ClientToGame makePodCombatStateNotify(BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfPodCombatState = new ClientToGameMessage.Types.GS2C_NTF_POD_COMBAT_STATE();
|
||||
|
||||
var attribute = battleInstanceRoom.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"location attribute is null !!");
|
||||
|
||||
var pod_combat = attribute.m_combat_pod_mode.m_pod_combat;
|
||||
|
||||
BattlePodCombatState state = new();
|
||||
state.PodCombatGuid = pod_combat.m_anchor_guid;
|
||||
state.OwnerPodCombatStandGuid = pod_combat.m_source_storage_anchor_guid;
|
||||
state.PodCombatStateType = pod_combat.m_state;
|
||||
state.StatechangeTime = Timestamp.FromDateTime(pod_combat.m_state_change_time);
|
||||
state.CurrentPos = pod_combat.m_currenct_Pos;
|
||||
state.CurrentOwnerGuid = pod_combat.m_current_occupier_guid;
|
||||
state.CurrentTime = Timestamp.FromDateTime(DateTimeHelper.Current);
|
||||
|
||||
ntf.Message.NtfPodCombatState.PodCombatState.Add(state);
|
||||
|
||||
|
||||
return ntf;
|
||||
}
|
||||
|
||||
|
||||
public static void send_GS2C_NTF_BATTLE_INSTANCE_STATE(BattleInstanceRoom battleInstanceRoom, Player player)
|
||||
{
|
||||
var ntf = makeBattleInstanceStateNotify(battleInstanceRoom);
|
||||
Log.getLogger().debug($"send_GS2C_NTF_BATTLE_INSTANCE_STATE ntf battleInstanceRoom Id : {battleInstanceRoom.m_instance_room.getMap().m_room_id} data : {JsonConvert.SerializeObject(ntf.Message.NtfBattleInstanceState)}");
|
||||
|
||||
GameServerApp.getServerLogic().onSendPacket(player, ntf);
|
||||
}
|
||||
|
||||
public static void broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
var ntf = makeBattleInstanceStateNotify(battleInstanceRoom);
|
||||
Log.getLogger().debug($"broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE ntf battleInstanceRoom Id : {battleInstanceRoom.m_instance_room.getMap().m_room_id} data : {JsonConvert.SerializeObject(ntf.Message.NtfBattleInstanceState)}");
|
||||
battleInstanceRoom.m_instance_room.Broadcast(ntf);
|
||||
}
|
||||
|
||||
private static ClientToGame makeBattleInstanceStateNotify(BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfBattleInstanceState = new ClientToGameMessage.Types.GS2C_NTF_BATTLE_INSTANCE_STATE();
|
||||
ntf.Message.NtfBattleInstanceState.CreateTime = Timestamp.FromDateTime(battleInstanceRoom.m_battle_instance_event_start_time);
|
||||
|
||||
var attribute = battleInstanceRoom.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
ntf.Message.NtfBattleInstanceState.CurrentRound = attribute.m_combat_pod_mode.m_current_round;
|
||||
ntf.Message.NtfBattleInstanceState.RoundStateStartTime = Timestamp.FromDateTime(attribute.m_combat_pod_mode.m_current_state_start_time);
|
||||
ntf.Message.NtfBattleInstanceState.RoundStateType = attribute.m_combat_pod_mode.m_round_state_type;
|
||||
ntf.Message.NtfBattleInstanceState.RewardedStep = attribute.m_combat_pod_mode.m_rewarded_step;
|
||||
ntf.Message.NtfBattleInstanceState.ChargedStep = attribute.m_combat_pod_mode.m_charged_step;
|
||||
|
||||
return ntf;
|
||||
}
|
||||
|
||||
public static void send_GS2C_NTF_PLAYER_DEATH(BattleInstanceRoom battleInstanceRoom, string killerGuid, string deadUserGuid, Player player)
|
||||
{
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfBattlePlayerDeath = new ClientToGameMessage.Types.GS2C_NTF_BATTLE_PLAYER_DEATH();
|
||||
ntf.Message.NtfBattlePlayerDeath.DeadUserGuid = deadUserGuid;
|
||||
ntf.Message.NtfBattlePlayerDeath.KillerUserGuid = killerGuid;
|
||||
|
||||
Log.getLogger().debug($"send_GS2C_NTF_PLAYER_DEATH ntf battleInstanceRoom Id : {battleInstanceRoom.m_instance_room.getMap().m_room_id} data : {JsonConvert.SerializeObject(ntf.Message.NtfBattlePlayerDeath)}");
|
||||
|
||||
battleInstanceRoom.m_instance_room.Broadcast(ntf);
|
||||
|
||||
}
|
||||
|
||||
public static void send_GS2C_NTF_PLAYER_RESPAWN(BattleInstanceRoom battleInstanceRoom, Pos pos, Player player)
|
||||
{
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfBattlePlayerRespawn = new ClientToGameMessage.Types.GS2C_NTF_BATTLE_PLAYER_RESPAWN();
|
||||
ntf.Message.NtfBattlePlayerRespawn.RespawnUserGuid = player.getUserGuid();
|
||||
ntf.Message.NtfBattlePlayerRespawn.Pos = pos;
|
||||
|
||||
Log.getLogger().debug($"send_GS2C_NTF_PLAYER_RESPAWN ntf battleInstanceRoom Id : {battleInstanceRoom.m_instance_room.getMap().m_room_id} data : {JsonConvert.SerializeObject(ntf.Message.NtfBattlePlayerRespawn)}");
|
||||
|
||||
battleInstanceRoom.m_instance_room.Broadcast(ntf);
|
||||
}
|
||||
|
||||
public static void broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(BattleInstanceRoom battleInstanceRoom, BattleObjectInteractionLogicHandler handler)
|
||||
{
|
||||
BattleObjectInfo info = new();
|
||||
info.AnchorGuid = handler.m_battle_object.m_anchor_guid;
|
||||
var now = DateTimeHelper.Current;
|
||||
info.IsActive = handler.m_battle_object.m_is_active ? BoolType.True : BoolType.False;
|
||||
List<BattleObjectInfo> infos = new();
|
||||
infos.Add(info);
|
||||
|
||||
|
||||
|
||||
broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(battleInstanceRoom, infos);
|
||||
}
|
||||
|
||||
public static void broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(BattleInstanceRoom battleInstanceRoom, List<BattleObjectInfo> infos)
|
||||
{
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfBattleObjectStateInfo = new ClientToGameMessage.Types.GS2C_NTF_BATTLE_OBJECT_STATE_INFO();
|
||||
ntf.Message.NtfBattleObjectStateInfo.BattleObjectInfos.AddRange(infos);
|
||||
|
||||
Log.getLogger().debug($"broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO ntf battleInstanceRoom Id : {battleInstanceRoom.m_instance_room.getMap().m_room_id} data :{JsonConvert.SerializeObject(infos)}");
|
||||
|
||||
battleInstanceRoom.m_instance_room.Broadcast(ntf);
|
||||
}
|
||||
|
||||
public static void send_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(List<BattleObjectInfo> infos, Player player)
|
||||
{
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfBattleObjectStateInfo = new ClientToGameMessage.Types.GS2C_NTF_BATTLE_OBJECT_STATE_INFO();
|
||||
ntf.Message.NtfBattleObjectStateInfo.BattleObjectInfos.AddRange(infos);
|
||||
|
||||
Log.getLogger().debug($"send_GS2C_NTF_BATTLE_OBJECT_STATE_INFO ntf : {JsonConvert.SerializeObject(infos)}");
|
||||
|
||||
GameServerApp.getServerLogic().onSendPacket(player, ntf);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void broadcast_GS2C_NTF_BATTLE_OBJECT_INTERACTION(BattleInstanceRoom battleInstanceRoom, string userGuid, string anchorGuid)
|
||||
{
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfBattleObjectInteraction = new ClientToGameMessage.Types.GS2C_NTF_BATTLE_OBJECT_INTERACTION();
|
||||
ntf.Message.NtfBattleObjectInteraction.AnchorGuid = anchorGuid;
|
||||
ntf.Message.NtfBattleObjectInteraction.UserGuid = userGuid;
|
||||
|
||||
Log.getLogger().debug($"broadcast_GS2C_NTF_BATTLE_OBJECT_INTERACTION ntf battleInstanceRoom Id : {battleInstanceRoom.m_instance_room.getMap().m_room_id} data : {JsonConvert.SerializeObject(ntf.Message.NtfBattleObjectInteraction)}");
|
||||
|
||||
battleInstanceRoom.m_instance_room.Broadcast(ntf);
|
||||
}
|
||||
|
||||
public static void broadcast_GS2C_NTF_BATTLE_REWARD(BattleInstanceRoom battleInstanceRoom, string acquireUserGuid, CommonResult commonResult)
|
||||
{
|
||||
if (commonResult.EntityCommonResults.Count == 0) return;
|
||||
if (acquireUserGuid.Equals(string.Empty)) return;
|
||||
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfBattleInstanceReward = new ClientToGameMessage.Types.GS2C_NTF_BATTLE_INSTANCE_REWARD();
|
||||
ntf.Message.NtfBattleInstanceReward.AcquireRewards = commonResult;
|
||||
ntf.Message.NtfBattleInstanceReward.AcquireUserGuid = acquireUserGuid;
|
||||
|
||||
Log.getLogger().debug($"send battle reward ntf acquireUserGuid : {acquireUserGuid}, commonResult : {JsonConvert.SerializeObject(commonResult)}");
|
||||
battleInstanceRoom.m_instance_room.Broadcast(ntf);
|
||||
}
|
||||
|
||||
|
||||
public static void broadcast_GS2C_NTF_BATTLE_INSTANCE_DESTROYED(BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfBattleInstanceDestroyed = new ClientToGameMessage.Types.GS2C_NTF_BATTLE_INSTANCE_DESTROYED();
|
||||
battleInstanceRoom.m_instance_room.Broadcast(ntf);
|
||||
}
|
||||
|
||||
|
||||
public static void send_GS2C_NTF_BATTLE_EVENT(Player player)
|
||||
{
|
||||
if (false == BattleRoomHelper.checkBattleActive()) return;
|
||||
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfBattleEvent = new ClientToGameMessage.Types.GS2C_NTF_BATTLE_EVENT();
|
||||
ntf.Message.NtfBattleEvent.BattleEvent.AddRange(BattleInstanceManager.It.getAllProtoBattleEvents());
|
||||
Log.getLogger().debug($"send battle event ntf guid : {player.getUserGuid()}, ntf : {JsonConvert.SerializeObject(ntf.Message.NtfBattleEvent)}");
|
||||
GameServerApp.getServerLogic().onSendPacket(player, ntf);
|
||||
}
|
||||
|
||||
public static void broadcast_GS2C_NTF_BATTLE_EVENT(List<BattleEventInfo> infos)
|
||||
{
|
||||
if (false == BattleRoomHelper.checkBattleActive()) return;
|
||||
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfBattleEvent = new ClientToGameMessage.Types.GS2C_NTF_BATTLE_EVENT();
|
||||
ntf.Message.NtfBattleEvent.BattleEvent.AddRange(infos);
|
||||
|
||||
foreach (var each in GameServerApp.getServerLogic().getPlayerManager().getUsers())
|
||||
{
|
||||
var player = each.Value;
|
||||
GameServerApp.getServerLogic().onSendPacket(player, ntf);
|
||||
}
|
||||
}
|
||||
|
||||
public static void broadcast_GS2C_NTF_PREPARATION_FOR_LEAVING_BATTLE_INSTANCE(BattleInstanceRoom battleInstanceRoom, string leavingUserGuid)
|
||||
{
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfPreparationForLeavingBattleInstance = new ClientToGameMessage.Types.GS2C_NTF_PREPARATION_FOR_LEAVING_BATTLE_INSTANCE();
|
||||
ntf.Message.NtfPreparationForLeavingBattleInstance.LeavingUserGuid = leavingUserGuid;
|
||||
|
||||
Log.getLogger().debug($"broadcast_GS2C_NTF_PREPARATION_FOR_LEAVING_BATTLE_INSTANCE ntf battleInstanceRoom Id : {battleInstanceRoom.m_instance_room.getMap().m_room_id} data : {JsonConvert.SerializeObject(ntf.Message.NtfPreparationForLeavingBattleInstance)}");
|
||||
|
||||
battleInstanceRoom.m_instance_room.Broadcast(ntf);
|
||||
}
|
||||
|
||||
public static void broadcast_GS2C_NTF_P2P_HOST_UPDATE(InstanceRoom instanceRoom, string hostUserGuid)
|
||||
{
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfP2PHostUpdate = new ClientToGameMessage.Types.GS2C_NTF_P2P_HOST_UPDATE();
|
||||
ntf.Message.NtfP2PHostUpdate.HostUserGuid = hostUserGuid;
|
||||
|
||||
Log.getLogger().debug($"broadcast_GS2C_NTF_P2P_HOST_UPDATE ntf battleInstanceRoom Id : {instanceRoom.getMap().m_room_id} data : {JsonConvert.SerializeObject(ntf.Message.NtfP2PHostUpdate)}");
|
||||
instanceRoom.Broadcast(ntf);
|
||||
}
|
||||
|
||||
public static void send_GS2C_NTF_P2P_HOST_UPDATE(Player player, string hostUserGuid)
|
||||
{
|
||||
ClientToGame ntf = new ClientToGame();
|
||||
ntf.Message = new ClientToGameMessage();
|
||||
ntf.Message.NtfP2PHostUpdate = new ClientToGameMessage.Types.GS2C_NTF_P2P_HOST_UPDATE();
|
||||
ntf.Message.NtfP2PHostUpdate.HostUserGuid = hostUserGuid;
|
||||
GameServerApp.getServerLogic().onSendPacket(player, ntf);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
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 BattleEventLog : ILogActor
|
||||
{
|
||||
[JsonProperty]
|
||||
public Int32 m_event_id { get; private set; } = 0;
|
||||
|
||||
//반복 어떻게 하는지 언제까지 반복하는지
|
||||
|
||||
public BattleEventLog(Int32 eventId)
|
||||
{
|
||||
m_event_id = eventId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
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 BattleInstanceActorLog : ILogActor
|
||||
{
|
||||
[JsonProperty]
|
||||
public string m_region_id { get; private set; } = string.Empty;
|
||||
|
||||
[JsonProperty]
|
||||
public string m_server_name { get; private set; } = string.Empty;
|
||||
|
||||
[JsonProperty]
|
||||
public string m_room_id { get; private set; } = string.Empty;
|
||||
[JsonProperty]
|
||||
public int m_instance_id { get; private set; } = 0;
|
||||
|
||||
|
||||
|
||||
public BattleInstanceActorLog(string regionId, string serverName, string roomId, int instanceId)
|
||||
{
|
||||
m_region_id = regionId;
|
||||
m_server_name = serverName;
|
||||
m_room_id = roomId;
|
||||
m_instance_id = instanceId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleObjectInteractionBusinessLog : ILogInvokerEx
|
||||
{
|
||||
private BattleObjectInteractionLogInfo m_info;
|
||||
|
||||
public BattleObjectInteractionBusinessLog(BattleObjectInteractionLogInfo info) : base(LogDomainType.BattleObjectInteraction)
|
||||
{
|
||||
m_info = info;
|
||||
}
|
||||
|
||||
public override bool hasLog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
protected override void fillup(ref BusinessLog.LogBody body)
|
||||
{
|
||||
body.append(new BattleObjectInteractionLogInfo(this, m_info));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleObjectStateUpdateBusinessLog : ILogInvokerEx
|
||||
{
|
||||
private BattleObjectStateUpdateLogInfo m_info;
|
||||
public BattleObjectStateUpdateBusinessLog(string roomId, List<BattleObjectLogInfo> infos) : base(LogDomainType.BattleObjectStateUpdate)
|
||||
{
|
||||
m_info = new();
|
||||
|
||||
m_info.m_room_id = roomId;
|
||||
m_info.m_infos.AddRange(infos);
|
||||
}
|
||||
|
||||
public override bool hasLog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
protected override void fillup(ref BusinessLog.LogBody body)
|
||||
{
|
||||
body.append(new BattleObjectStateUpdateLogInfo(this, m_info));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattlePodCombatRewardBusinessLog : ILogInvokerEx
|
||||
{
|
||||
private BattlePodCombatRewardLogInfo m_info;
|
||||
|
||||
public BattlePodCombatRewardBusinessLog(string roomId, int round, BattleRoundStateType roundSate
|
||||
, string rewardUserGuid, string rewardUserNickname
|
||||
, int chargedStep, int rewardedStep, List<MetaAssets.Reward> rewards) : base(LogDomainType.BattleReward)
|
||||
{
|
||||
m_info = new BattlePodCombatRewardLogInfo(this, roomId, round, roundSate, rewardUserGuid, rewardUserNickname, chargedStep, rewardedStep, rewards);
|
||||
}
|
||||
public override bool hasLog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
protected override void fillup(ref BusinessLog.LogBody body)
|
||||
{
|
||||
body.append(m_info);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleRespawnBusinessLog : ILogInvokerEx
|
||||
{
|
||||
private BattleRespawnLogInfo m_info;
|
||||
|
||||
|
||||
public BattleRespawnBusinessLog(string roomId, int round, BattleRoundStateType roundState, string userGuid, string userNickname, string respawnAnchorGuid, DateTime nextAvailableRespawnTimeAtThisAnchor)
|
||||
: base(LogDomainType.BattleRespawn)
|
||||
{
|
||||
m_info = new(this, roomId, round, roundState, userGuid, userNickname, respawnAnchorGuid, nextAvailableRespawnTimeAtThisAnchor);
|
||||
}
|
||||
|
||||
public override bool hasLog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
protected override void fillup(ref BusinessLog.LogBody body)
|
||||
{
|
||||
body.append(m_info);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleRoomJoinBusinessLog : ILogInvokerEx
|
||||
{
|
||||
private BattleRoomJoinSuccessLogInfo m_info;
|
||||
public BattleRoomJoinBusinessLog(string joinUserGuid, string joinUserNickname, string roomId, int joinRound) : base(LogDomainType.BattleRoomJoin)
|
||||
{
|
||||
m_info = new BattleRoomJoinSuccessLogInfo(this, joinUserGuid, joinUserNickname, roomId, joinRound);
|
||||
}
|
||||
|
||||
|
||||
public override bool hasLog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
protected override void fillup(ref BusinessLog.LogBody body)
|
||||
{
|
||||
body.append(m_info);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleRoomPlayerDeadBusinessLog : ILogInvokerEx
|
||||
{
|
||||
private BattleRoomPlayerDeadLogInfo m_info;
|
||||
|
||||
public BattleRoomPlayerDeadBusinessLog(string deadUserGuid, string deadUserNickname
|
||||
, string killerGuid, string killerNickname
|
||||
, string roomId, int round, bool hasPodCombat): base(LogDomainType.BattleDead)
|
||||
{
|
||||
m_info = new BattleRoomPlayerDeadLogInfo(this, deadUserGuid, deadUserNickname, killerGuid, killerNickname,
|
||||
roomId, round, hasPodCombat);
|
||||
}
|
||||
|
||||
public override bool hasLog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
protected override void fillup(ref BusinessLog.LogBody body)
|
||||
{
|
||||
body.append(m_info);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleRoundUpdateBusinessLog : ILogInvokerEx
|
||||
{
|
||||
private BattleRoundingUpdateLogInfo m_info;
|
||||
|
||||
public BattleRoundUpdateBusinessLog(string roomId, int endedRound, BattleRoundStateType roundSate, List<BattleRoundingExistUsers> users): base(LogDomainType.BattleRound)
|
||||
{
|
||||
m_info = new BattleRoundingUpdateLogInfo(this, roomId, endedRound, roundSate, users);
|
||||
}
|
||||
|
||||
|
||||
public override bool hasLog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
protected override void fillup(ref BusinessLog.LogBody body)
|
||||
{
|
||||
body.append(m_info);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleSnapShotBusinessLog : ILogInvokerEx
|
||||
{
|
||||
private BattleSnapshotLogInfo m_info;
|
||||
|
||||
public BattleSnapShotBusinessLog(BattleInstanceRoom battleInstanceRoom, string loadType): base(LogDomainType.BattleSnapshot)
|
||||
{
|
||||
m_info = createBattleSnapshotLogInfo(this, battleInstanceRoom, loadType);
|
||||
}
|
||||
|
||||
public override bool hasLog()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
protected override void fillup(ref BusinessLog.LogBody body)
|
||||
{
|
||||
body.append(m_info);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public BattleSnapshotLogInfo createBattleSnapshotLogInfo(ILogInvokerEx parent, BattleInstanceRoom battleInstanceRoom, string loadType)
|
||||
{
|
||||
var room_id = battleInstanceRoom.m_instance_room.getMap().m_room_id;
|
||||
BattleSnapshotLogInfo info = new(parent, room_id, loadType);
|
||||
|
||||
var attribute = battleInstanceRoom.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
if (attribute is null)
|
||||
{
|
||||
ServerCore.Log.getLogger().warn($"attribute is null so return empty battleInstanceRoom.roomId() : {room_id}");
|
||||
return info;
|
||||
}
|
||||
|
||||
info.m_play_mode = battleInstanceRoom.m_play_mode;
|
||||
info.m_battle_instance_event_start_time = battleInstanceRoom.m_battle_instance_event_start_time;
|
||||
info.m_pod_combat_reward_group_id = battleInstanceRoom.m_pod_combat_reward_group_id;
|
||||
info.m_pod_combat_ffa_id = battleInstanceRoom.m_pod_combat_ffa_id;
|
||||
info.m_hot_time_reward = battleInstanceRoom.m_hot_time_reward;
|
||||
info.m_round_count = battleInstanceRoom.m_round_count;
|
||||
|
||||
|
||||
info.m_respawns = attribute.m_combat_pod_mode.m_respawns;
|
||||
info.m_pod_storages = attribute.m_combat_pod_mode.m_pod_storages;
|
||||
info.m_pod_combat = attribute.m_combat_pod_mode.m_pod_combat;
|
||||
info.m_pickup_pods = attribute.m_combat_pod_mode.m_pickup_pods;
|
||||
info.m_pickup_pod_generated_info.AddRange(attribute.m_combat_pod_mode.m_pickup_pod_generated_info.Values);
|
||||
info.m_weapons = attribute.m_combat_pod_mode.m_weapons;
|
||||
info.m_buffs = attribute.m_combat_pod_mode.m_buffs;
|
||||
info.m_round_state_type = attribute.m_combat_pod_mode.m_round_state_type;
|
||||
info.m_current_round = attribute.m_combat_pod_mode.m_current_round;
|
||||
info.m_current_state_start_time = attribute.m_combat_pod_mode.m_current_state_start_time;
|
||||
info.m_charged_step = attribute.m_combat_pod_mode.m_charged_step;
|
||||
info.m_rewarded_step = attribute.m_combat_pod_mode.m_rewarded_step;
|
||||
info.m_tactical_board = attribute.m_combat_pod_mode.m_tactical_board;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleEvent : EntityBase, IWithLogActor
|
||||
{
|
||||
public BattleEvent(EntityType entityType) : base(EntityType.BattleEvent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public ILogActor toLogActor()
|
||||
{
|
||||
//var server_logic = ServerLogicApp.getServerLogicApp();
|
||||
var log_info = new BattleEventLog(0);
|
||||
|
||||
return log_info;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using Nettention.Proud;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
public class BattleFFAModeHostMigrator : IHostMigrator
|
||||
{
|
||||
private string m_host_user_guid = string.Empty;
|
||||
|
||||
public Result defineHost(HostID p2pGroupId, SuperPeerSelectionPolicy policy, HostID[] excludes)
|
||||
{
|
||||
var pround_net_listener = GameServerApp.getServerLogic().getProudNetListener();
|
||||
var net_server = pround_net_listener.getNetServer();
|
||||
|
||||
var host_id = net_server.GetMostSuitableSuperPeerInGroup(p2pGroupId, policy, excludes);
|
||||
//net_server.GetClientInfo(host_id);
|
||||
|
||||
string err_msg = string.Empty;
|
||||
var result = new Result();
|
||||
|
||||
if (host_id == 0)
|
||||
{
|
||||
err_msg = $"there is not suitable super peer !!!! host_id : {host_id}";
|
||||
result.setFail(ServerErrorCode.NotFoundUser, err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
var session = pround_net_listener.onLookupEntityWithSession((SESSION_ID)host_id);
|
||||
if (session is null)
|
||||
{
|
||||
err_msg = $"session is null!!!! host_id : {host_id}";
|
||||
result.setFail(ServerErrorCode.NotFoundUser, err_msg);
|
||||
return result;
|
||||
}
|
||||
var player = session as Player;
|
||||
if (player is null)
|
||||
{
|
||||
err_msg = $"player is null!!!! host_id : {host_id}";
|
||||
result.setFail(ServerErrorCode.NotFoundUser, err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
m_host_user_guid = player.getUserGuid();
|
||||
return result;
|
||||
}
|
||||
|
||||
public Result modifyHost(string userGuid)
|
||||
{
|
||||
m_host_user_guid = userGuid;
|
||||
return new Result();
|
||||
}
|
||||
|
||||
public Result removeHost()
|
||||
{
|
||||
m_host_user_guid = string.Empty;
|
||||
return new Result();
|
||||
}
|
||||
|
||||
public string getHostUserGuid()
|
||||
{
|
||||
return m_host_user_guid;
|
||||
}
|
||||
|
||||
public (Result, bool) migrateCheck(bool ignoreInterval)
|
||||
{
|
||||
return (new Result(), false);
|
||||
}
|
||||
|
||||
public void setGroupHostId(HostID groupId)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
public class BattleInstanceInitHandler : GameModeInitHandlerBase
|
||||
{
|
||||
public BattleInstanceInitHandler(InstanceRoom instanceRoom) : base(instanceRoom, EPlaceType.BattleRoom)
|
||||
{
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceInitValidate()
|
||||
{
|
||||
var result = BattleRoomHelper.checkBattleActive(m_place_type);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceInit()
|
||||
{
|
||||
var result = BattleInstanceManager.It.battleInstanceInit(m_instance_room, m_instance_room.getMap().m_room_id).Result; //kihoon todo :이거 리팩토링 대상
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
public class BattleInstanceJoinHandler : GameModeJoinHandlerBase
|
||||
{
|
||||
public BattleInstanceJoinHandler(InstanceRoom instanceRoom) : base(instanceRoom, EPlaceType.BattleRoom)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceJoinValidate(EPlaceType placeType)
|
||||
{
|
||||
var result = BattleRoomHelper.checkBattleActive(m_place_type);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceJoin(Player player)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg = string.Empty;
|
||||
|
||||
//instanceroom 정보는 남아있는데 battleinstance만 없어지는 케이스가 있어서 예외 처리를 위해 넣어놓음
|
||||
var room_id = m_instance_room.getMap().m_room_id;
|
||||
|
||||
var battle_instance_room = BattleInstanceManager.It.getBattleInstanceRoom(room_id); //리팩토링 대상
|
||||
if (battle_instance_room is null)
|
||||
{
|
||||
Log.getLogger().error($"Battle Room Instance is null.. so init start roomId : {room_id}");
|
||||
|
||||
result = Task.Run(() => BattleInstanceManager.It.battleInstanceInit(m_instance_room, room_id)).GetAwaiter().GetResult();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"BattleIntanceJoin init error, _roomId : {room_id}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleInstanceJoinSuccessHandler : GameModeJoinSuccessHandlerBase
|
||||
{
|
||||
private readonly BattleInstanceRoom m_battle_instance_room;
|
||||
public BattleInstanceJoinSuccessHandler(Player player, InstanceRoom instanceRoom)
|
||||
: base(player, EPlaceType.BattleRoom)
|
||||
{
|
||||
var room_id = instanceRoom.getMap().m_room_id;
|
||||
var battle_instance_room = BattleInstanceManager.It.getBattleInstanceRoom(room_id);
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room, () => $"m_battle_instance_room is null !!!");
|
||||
|
||||
m_battle_instance_room = battle_instance_room;
|
||||
}
|
||||
|
||||
public override Result joinSuccessValidate()
|
||||
{
|
||||
var result = BattleRoomHelper.checkBattleActive(m_place_type);
|
||||
if (result.isFail()) return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
public override async Task<Result> joinSuccessConfirmation()
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg = string.Empty;
|
||||
|
||||
var room_id = m_battle_instance_room.m_instance_room.getMap().m_room_id;
|
||||
var battle_instance_attribute = m_battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_attribute, () => $"battle_instance_attribute is null !!!");
|
||||
|
||||
(result, var pos_meta_guid) = BattleRoomHelper.getRandomRespawnPos(battle_instance_attribute, m_battle_instance_room);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (false == m_battle_instance_room.m_respawn_pos_anchors_meta.Contains(pos_meta_guid))
|
||||
{
|
||||
err_msg = $"respawn pos meta not exist idx : {pos_meta_guid}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceUsableSpawnPointNotExist, err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
using (var releaser = await m_battle_instance_room.getAsyncLock())
|
||||
{
|
||||
var now = DateTimeHelper.Current;
|
||||
var next_respawn_time = now.AddSeconds(m_battle_instance_room.m_ffa_config_meta.PlayerRespawnTime);
|
||||
|
||||
battle_instance_attribute.m_combat_pod_mode.m_respawns.AddOrUpdate(pos_meta_guid, next_respawn_time, (key, old) => next_respawn_time);
|
||||
|
||||
var location_action = m_player.getEntityAction<LocationAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(location_action, () => $"location_action is null !!! - {m_player.toBasicString()}");
|
||||
|
||||
|
||||
var currenct_pos = location_action.getCurrentPos();
|
||||
if (false == m_battle_instance_room.m_instance_room.getMap().getAnchors().TryGetValue(pos_meta_guid, out var anchorInfo))
|
||||
{
|
||||
err_msg = $"anchorInfo not exist idx : {pos_meta_guid}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceNotExistAnchors, err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
currenct_pos = anchorInfo.AnchorPos.Clone();
|
||||
currenct_pos.Z += 100;
|
||||
location_action.tryUpdateCurrentPos(currenct_pos);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override async Task<Result> joinSuccessNotify()
|
||||
{
|
||||
var result = new Result();
|
||||
m_player.send_S2C_NTF_SET_LOCATION();
|
||||
result = await BattleInstanceManager.It.sendNtfAboutBattleInstance(m_battle_instance_room, m_player);
|
||||
if (result.isFail()) return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public override void joinSuccessWriteLog()
|
||||
{
|
||||
var room_id = m_battle_instance_room.m_instance_room.getMap().m_room_id;
|
||||
var user_guid = m_player.getUserGuid();
|
||||
var user_nickname = m_player.getUserNickname();
|
||||
|
||||
var battle_instance_attribute = m_battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_attribute, () => $"battle_instance_attribute is null !!!");
|
||||
|
||||
var currenct_round = battle_instance_attribute.m_combat_pod_mode.m_current_round;
|
||||
|
||||
var log_action = new LogActionEx(LogActionType.BattleInstanceJoin);
|
||||
var invoker = new BattleRoomJoinBusinessLog(user_guid, user_nickname, room_id, currenct_round);
|
||||
BusinessLogger.collectLogs(log_action, m_player, new List<ILogInvoker>(){invoker});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,501 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
|
||||
using NeoSmart.AsyncLock;
|
||||
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 BattleInstanceManager : Singleton<BattleInstanceManager>
|
||||
{
|
||||
private AsyncLock m_lock_init = new();
|
||||
public AsyncLock m_lock_data_load = 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 bool hasBattleInstance(string roomId)
|
||||
{
|
||||
return m_battle_instances.ContainsKey(roomId);
|
||||
}
|
||||
|
||||
public BattleInstanceRoom? getBattleInstanceRoom(string roomId)
|
||||
{
|
||||
if (false == m_battle_instances.TryGetValue(roomId, out var room))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return room;
|
||||
|
||||
}
|
||||
|
||||
public ConcurrentDictionary<string, BattleInstanceRoom> getBattleInstanceRooms()
|
||||
{
|
||||
return m_battle_instances;
|
||||
}
|
||||
|
||||
//
|
||||
// public bool isLoadComplete(string roomId)
|
||||
// {
|
||||
// if (false == m_battle_instances.TryGetValue(roomId, out var battleInstanceRoom))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// return battleInstanceRoom.m_is_load_complete;
|
||||
// }
|
||||
|
||||
public async Task<Result> battleInstanceInit(InstanceRoom instanceRoom, string roomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
using (await m_lock_init.LockAsync())
|
||||
{
|
||||
//1. 배틀 인스턴스에 대한 정보 생성
|
||||
Log.getLogger().info($"Battle Instance Create And Init : {roomId}");
|
||||
if (hasBattleInstance(roomId)) return result;
|
||||
|
||||
// instance 정보 추가 등록
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var instance_room_storage = new InstanceRoomStorage();
|
||||
instance_room_storage.Init(server_logic.getRedisDb(), "");
|
||||
|
||||
DateTime start_time = DateTimeHelper.Current;
|
||||
Int32 config_id = 1;
|
||||
Int32 reward_id = 1;
|
||||
Int32 hot_time = 1;
|
||||
Int32 round_count = 8;
|
||||
var system_battle_event = BattleRoomHelper.getBattleRoomStartTimeByEventId(roomId);
|
||||
if (system_battle_event is null)
|
||||
{
|
||||
Log.getLogger().error($"system_battle_event is null!!! : {result.toBasicString()} - instanceRoomId:{roomId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
start_time = system_battle_event.m_start_time;
|
||||
config_id = system_battle_event.m_ffa_config_data_id;
|
||||
reward_id = system_battle_event.m_ffa_reward_group_id;
|
||||
hot_time = system_battle_event.m_ffa_hot_time;
|
||||
round_count = system_battle_event.m_round_count;
|
||||
}
|
||||
|
||||
|
||||
result = await instance_room_storage.setInstanceRoomExtraInfo(roomId, EPlaceType.BattleRoom, start_time);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error($"Failed to BattleRoom setInstanceRoomExtraInfo() !!! : {result.toBasicString()} - instanceRoomId:{roomId}");
|
||||
return result;
|
||||
}
|
||||
|
||||
BattleInstanceRoom battle_instance_room = new BattleInstanceRoom(instanceRoom, start_time, config_id, reward_id, hot_time, round_count);
|
||||
|
||||
if (false == m_battle_instances.TryAdd(roomId, battle_instance_room))
|
||||
{
|
||||
//이미 존재하는 경우는 onInit 절차를 거쳤다고 생각하고, init 처리 안해주고 리턴
|
||||
err_msg = $"Battle Instance Room Already exist room_id : {roomId}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceInfoAlreadyExist, err_msg);
|
||||
Log.getLogger().warn(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//2. 초기화
|
||||
result = await battle_instance_room.init();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().warn(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Log.getLogger().info($"battleInstanceInit done roomId : {roomId}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Result addOrUpatePlayer(string roomId, Player player)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg = string.Empty;
|
||||
|
||||
if (false == m_battle_instances.TryGetValue(roomId, out var battle_instance_room))
|
||||
{
|
||||
err_msg = $"m_battle_instances not exist battleRoomInstance, roomId : {roomId}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceInfoNotExist, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return result;
|
||||
}
|
||||
|
||||
//유저 정보 추가 해줘야 한다.
|
||||
result = battle_instance_room.AddOrUpdatePlayer(player);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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(ServerCommon.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;
|
||||
}
|
||||
|
||||
public async Task tryLeaveBattelInstance(Player player, string instanceRoomId)
|
||||
{
|
||||
if (false == BattleRoomHelper.checkBattleActive()) return;
|
||||
|
||||
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");
|
||||
removeBattlePlayer(player.getUserGuid());
|
||||
return;
|
||||
}
|
||||
if (false == m_battle_instances.TryGetValue(instanceRoomId, out var battleInstanceRoom))
|
||||
{
|
||||
removeBattlePlayer(player.getUserGuid());
|
||||
return;
|
||||
}
|
||||
|
||||
await battleInstanceRoom.removePodCombat(player);
|
||||
|
||||
var host_user_guid = battleInstanceRoom.m_host_migrator.getHostUserGuid();
|
||||
if (player.getUserGuid().Equals(host_user_guid))
|
||||
{
|
||||
using (var releaser = await battleInstanceRoom.getAsyncLock())
|
||||
{
|
||||
battleInstanceRoom.m_host_migrator.removeHost();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//여기서 instanceroom 이 is Destroy 면 DestroyBattleRoom 호출 해줄것
|
||||
if (battleInstanceRoom.m_instance_room.isDestroy)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (false == BattleRoomHelper.checkBattleActive()) return;
|
||||
|
||||
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 _);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void removeBattlePlayer(string userGuid)
|
||||
{
|
||||
foreach (var battle_instance_room in m_battle_instances.Values)
|
||||
{
|
||||
battle_instance_room.removeBattlePlayerIfExist(userGuid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<bool> LeaveBattleRoom(Player player, string instanceRoomId, bool disconnected = false)
|
||||
{
|
||||
|
||||
if (false == m_battle_instances.TryGetValue(instanceRoomId, out var battleRoom))
|
||||
{
|
||||
Log.getLogger().info($"LeaveBattleRoom m_battle_instances.TryGetValue false instanceRoomId : {instanceRoomId}");
|
||||
return false;
|
||||
}
|
||||
|
||||
await battleRoom.LeaveBattleRoom(player, instanceRoomId, disconnected);
|
||||
|
||||
// if (battleRoom.m_instance_room.isDestroy)
|
||||
// {
|
||||
// InstanceRoomManager.Instance.DestroyRoom(instanceRoomId);
|
||||
// }
|
||||
Log.getLogger().debug($"leave battle room player : {player.toBasicString()}, instanceRoomId : {instanceRoomId}");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<Result> sendNtfAboutBattleInstance(BattleInstanceRoom 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(BattleInstanceRoom 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;
|
||||
}
|
||||
|
||||
public BattleInstanceManager Self => this;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleInstanceRespawn
|
||||
{
|
||||
public int m_spawn_idx { get; set; } = 0;
|
||||
public DateTime m_next_usable_time = DateTimeHelper.Current;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public partial class InstanceRoom
|
||||
{
|
||||
public async Task<bool> battleInstanceInit()
|
||||
{
|
||||
var result = await BattleInstanceManager.It.battleInstanceInit(this, _roomId);
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<Result> sendGameModeInstanceJoinSuccess(Player player)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
//var game_mod_handler = GameModeManager.It.getGameModeJoinHandler(_placeType);
|
||||
return new();
|
||||
}
|
||||
|
||||
|
||||
public bool tryGetInstanceMember(string userGuid, [MaybeNullWhen(false)] out Player out_player)
|
||||
{
|
||||
out_player = null;
|
||||
if (false == m_players.TryGetValue(userGuid, out var player))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
out_player = player;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public List<BattleRoundingExistUsers> tryGetInstanceExistUserForLog()
|
||||
{
|
||||
List<BattleRoundingExistUsers> users = new();
|
||||
foreach (var player in m_players.Values)
|
||||
{
|
||||
BattleRoundingExistUsers user = new(player.getUserGuid(), player.getUserNickname());
|
||||
users.Add(user);
|
||||
}
|
||||
|
||||
return users;
|
||||
}
|
||||
|
||||
public async Task LeaveBattleInstanceRoom(Player player, bool disconnected)
|
||||
{
|
||||
var user_guid = player.getUserGuid();
|
||||
|
||||
Log.getLogger().info($"BattleInstanceRoom.Leave() Start !!! - userGuid:{user_guid}, instanceRoomId:{_roomId}, sessionCount:{SessionCount}, addConnectedUser:{getMap().getCurrCountAsAddConnectedUser()}");
|
||||
|
||||
if (m_players.TryRemove(player.getUserGuid(), out _))
|
||||
{
|
||||
await BattleInstanceRoomHandler.leaveBattleInstanceRoom(user_guid, _roomId);
|
||||
}
|
||||
|
||||
var location_attribute = player.getEntityAttribute<LocationAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(location_attribute, () => $"LocationAttribute is null !!! - player:{player.toBasicString()}");
|
||||
location_attribute.CurrentIndunLocation.clear();
|
||||
|
||||
var game_zone_action = player.getEntityAction<GameZoneAction>();
|
||||
await game_zone_action.tryLeaveGameZone();
|
||||
|
||||
if (SessionCount + getMap().getCurrCountAsAddConnectedUser() == 0)
|
||||
{
|
||||
if (!_isPartyInstance || _concertEnd)
|
||||
{
|
||||
await destroyRoom();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
ClientToGame clientToGame = new ClientToGame();
|
||||
clientToGame.Message = new ClientToGameMessage();
|
||||
clientToGame.Message.LeaveInstanceRoomMember = new ClientToGameMessage.Types.LeaveInstanceRoomMember();
|
||||
clientToGame.Message.LeaveInstanceRoomMember.MemberGuid = player.getUserGuid();
|
||||
|
||||
Broadcast(clientToGame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Log.getLogger().info($"InstanceRoom.Leave() Finish !!! - userGuid:{user_guid}, instanceRoomId:{_roomId}, sessionCount:{SessionCount}, addConnectedUser:{getMap().getCurrCountAsAddConnectedUser()}");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
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<Int32> 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<Int32> 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<Result> 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<Result> 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public partial class MapManager
|
||||
{
|
||||
public Pos GetBattleInstnaceRespawnPos(string mapFileName, string roomId)
|
||||
{
|
||||
Pos startPos = new();
|
||||
|
||||
|
||||
var startPosAnchorGuid = MapDataTable.Instance.GetRoomStartPosAnchorGuid(mapFileName);
|
||||
|
||||
if (!AnchorTrees.TryGetValue(startPosAnchorGuid, out var startPosAnchor))
|
||||
{
|
||||
return startPos;
|
||||
}
|
||||
|
||||
startPos.X = startPosAnchor.AnchorPos.X;
|
||||
startPos.Y = startPosAnchor.AnchorPos.Y;
|
||||
startPos.Z = startPosAnchor.AnchorPos.Z + 100;
|
||||
|
||||
return startPos;
|
||||
}
|
||||
|
||||
public List<Anchor> getAllRespawnPos(string mapFileName)
|
||||
{
|
||||
List<Anchor> anchors = new();
|
||||
|
||||
//바꿔야 된다. 배틀인스턴스 스폰 포인트로 바꿔야 한다. 아직 안바꿨음
|
||||
if (false == MapDataTable.Instance.getMapData(mapFileName, out var mapData))
|
||||
{
|
||||
//여기는 error 다. 로그만 찍고 startPos는 그대로 보낸다.
|
||||
Log.getLogger().error($"not exist map data namd : {mapFileName}");
|
||||
return anchors;
|
||||
}
|
||||
|
||||
foreach (var anchor in mapData.Anchors)
|
||||
{
|
||||
if (anchor.Type == "AT_RespawnPos")
|
||||
{
|
||||
anchors.Add(anchor);
|
||||
}
|
||||
}
|
||||
return anchors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
using Google.Protobuf;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer.PacketHandler;
|
||||
|
||||
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_BATTLE_OBJECT_INTERACTION), typeof(BattleObjectInteractionPacketHandler), typeof(GameLoginListener))]
|
||||
|
||||
public class BattleObjectInteractionPacketHandler : PacketRecvHandler
|
||||
{
|
||||
public override async Task<Result> onProcessPacket(ISession session, IMessage recvMessage)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var player = session as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var server_config = server_logic.getServerConfig();
|
||||
bool is_battle_system_active = server_config.BattleSystemEnable;
|
||||
|
||||
if (false == is_battle_system_active)
|
||||
{
|
||||
err_msg = $"is_battle_system_active is false!!!";
|
||||
result.setFail(ServerErrorCode.BattleInstanceInActive, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
send_S2C_ACK_BATTLE_OBJECT_INTERACTION(player, result, "");
|
||||
return result;
|
||||
}
|
||||
|
||||
var req_msg = recvMessage as ClientToGame;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(req_msg, () => $"req_msg is null !!! - {player.toBasicString()}");
|
||||
|
||||
var request = req_msg.Request.ReqBattleObjectInteraction;
|
||||
if (null == request)
|
||||
{
|
||||
err_msg = $"failed to get request message : Invalid Request message - {req_msg.Request.MsgCase}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
|
||||
send_S2C_ACK_BATTLE_OBJECT_INTERACTION(player, result, "");
|
||||
return result;
|
||||
}
|
||||
|
||||
var anchor_guid = request.AnchorGuid;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(anchor_guid, () => $"anchor_guid is null !!! - {player.toBasicString()}");
|
||||
var packet_create_time = request.PacketCreateTime;
|
||||
|
||||
var room_id = player.getCurrentInstanceRoomId();
|
||||
var battle_instance_room = BattleInstanceManager.It.getBattleInstanceRoom(room_id);
|
||||
if (battle_instance_room == null)
|
||||
{
|
||||
err_msg = $"battle_instance_room is null : room_id - {room_id}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.BattleInstanceInfoNotExist, err_msg);
|
||||
send_S2C_ACK_BATTLE_OBJECT_INTERACTION(player, result, anchor_guid);
|
||||
return result;
|
||||
}
|
||||
|
||||
var attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
if (packet_create_time is not null)
|
||||
{
|
||||
Log.getLogger().info($"Battle Object interaction packet received anchor_guid : {anchor_guid}, packetCreateTime : {packet_create_time}, player : {player.toBasicString()}");
|
||||
}
|
||||
|
||||
|
||||
BattleObjectInteractionLogicHandler handler = new(player.getUserGuid(), player.getUserNickname(), anchor_guid, attribute.m_room_id);
|
||||
CommonResult common_result = new();
|
||||
var fn_interact_battle_object = async delegate()
|
||||
{
|
||||
using (var releaser = await battle_instance_room.getAsyncLock())
|
||||
{
|
||||
result = await interactObject(handler, battle_instance_room, anchor_guid, player);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
//batch 처리
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.BattleObjectInteraction, server_logic.getDynamoDbClient());
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
}
|
||||
|
||||
BattleObjectInteractionBusinessLog business_log = new(handler.m_interaction_log_info);
|
||||
batch.appendBusinessLog(business_log);
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
|
||||
if (result.isFail()) return result;
|
||||
|
||||
//보상 내용 가져올것
|
||||
var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents);
|
||||
NullReferenceCheckHelper.throwIfNull(found_transaction_runner, () => $"found_transaction_runner is null !!! - {player.toBasicString()}");
|
||||
common_result = found_transaction_runner.getCommonResult();
|
||||
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid(), TransactionIdType.PrivateContents, "InteractBattleObject", fn_interact_battle_object);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()}, {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
send_S2C_ACK_BATTLE_OBJECT_INTERACTION(player, result, anchor_guid);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//순서 바꾸지 말것(클라 요청사항)
|
||||
send_S2C_ACK_BATTLE_OBJECT_INTERACTION(player, result, anchor_guid);
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_OBJECT_INTERACTION(battle_instance_room, player.getUserGuid(), anchor_guid);
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(battle_instance_room, handler);
|
||||
|
||||
sendOtherNotifies(handler, battle_instance_room, common_result);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void sendOtherNotifies(BattleObjectInteractionLogicHandler handler, BattleInstanceRoom battleInstanceRoom, CommonResult commonResult)
|
||||
{
|
||||
//pod combat이 활성화 되서 stand는 전부 비활성화
|
||||
if (handler.m_need_noti_objects.Count > 0)
|
||||
{
|
||||
System.Collections.Generic.List<BattleObjectInfo> infos = new();
|
||||
foreach (var battle_object in handler.m_need_noti_objects)
|
||||
{
|
||||
BattleObjectInfo info = new();
|
||||
info.AnchorGuid = battle_object.m_anchor_guid;
|
||||
info.IsActive = battle_object.m_is_active ? BoolType.True : BoolType.False;
|
||||
infos.Add(info);
|
||||
}
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(battleInstanceRoom, infos);
|
||||
}
|
||||
|
||||
//pod combat 활성화 Noti
|
||||
if (handler.m_is_need_combat_pod_noti)
|
||||
{
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battleInstanceRoom);
|
||||
}
|
||||
|
||||
if (handler.m_is_need_combat_pod_noti)
|
||||
{
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battleInstanceRoom);
|
||||
}
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_REWARD(battleInstanceRoom, handler.m_user_guid, commonResult);
|
||||
}
|
||||
|
||||
public async Task<Result> interactObject(BattleObjectInteractionLogicHandler handler, BattleInstanceRoom battleInstanceRoom, string anchorGuid, Player player)
|
||||
{
|
||||
var attribute = battleInstanceRoom.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
var result = new Result();
|
||||
string err_msg = string.Empty;
|
||||
|
||||
|
||||
handler.m_is_combat_pod = BattleInstancePlayModeHelper.isPodCombat(attribute, anchorGuid);
|
||||
if (handler.m_is_combat_pod)
|
||||
{
|
||||
Log.getLogger().debug($"m is pod combat is true anchor_guid : {anchorGuid}, player : {player.toBasicString()}");
|
||||
result = await interactPodCombat(handler, battleInstanceRoom, anchorGuid, player);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.getLogger().debug($"m is pod combat is false anchor_guid : {anchorGuid}, player : {player.toBasicString()}");
|
||||
result = await interactBattleObject(handler, battleInstanceRoom, anchorGuid, player);
|
||||
}
|
||||
if (result.isFail()) return result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> interactBattleObject(BattleObjectInteractionLogicHandler handler, BattleInstanceRoom battleInstanceRoom, string anchorGuid, Player player)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg = string.Empty;
|
||||
|
||||
(result, handler.m_battle_object_meta) = BattleInstancePlayModeHelper.getBattleObjectMeta(handler.m_interaction_anchor_guid, battleInstanceRoom);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
|
||||
var attribute = battleInstanceRoom.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
var interact_action = battleInstanceRoom.getEntityAction<BattleObjectInteractAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(interact_action, () => $"interact_action is null !!!");
|
||||
|
||||
|
||||
var battle_instance_object = BattleInstancePlayModeHelper.getBattleObject(handler.m_interaction_anchor_guid, attribute, handler.m_battle_object_meta.ObjectType);
|
||||
if (battle_instance_object is null)
|
||||
{
|
||||
err_msg = $"battle_object activate time not yet " +
|
||||
$"anchorGuid : {handler.m_interaction_anchor_guid}, " +
|
||||
$"objectType : {handler.m_battle_object_meta.ObjectType}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceObjectNotExist, err_msg);
|
||||
return result;
|
||||
}
|
||||
handler.m_battle_object = battle_instance_object;
|
||||
|
||||
if (handler.m_battle_object.m_is_active == false)
|
||||
{
|
||||
err_msg = $"battle_object activ is false " +
|
||||
$"anchorGuid : {handler.m_interaction_anchor_guid}, " +
|
||||
$"objectType : {handler.m_battle_object_meta.ObjectType}," +
|
||||
$" nextActivateTime : {handler.m_battle_object.m_active_time}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceObjectInteractionNotActive, err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
handler.m_interaction_log_info.m_battle_object_type = handler.m_battle_object_meta.ObjectType;
|
||||
switch (handler.m_battle_object_meta.ObjectType)
|
||||
{
|
||||
case EBattleObjectType.Buff:
|
||||
case EBattleObjectType.Weapon:
|
||||
result = await interact_action.interactCommonBattleObject(handler, player);
|
||||
break;
|
||||
case EBattleObjectType.Pod_Box:
|
||||
result = await interact_action.interactPickupPod(handler, player);
|
||||
break;
|
||||
case EBattleObjectType.Pod_Combat:
|
||||
result = await interact_action.interactPodStorage(handler, player);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public async Task<Result> interactPodCombat(BattleObjectInteractionLogicHandler handler, BattleInstanceRoom battleInstanceRoom, string anchorGuid, Player player)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var interact_action = battleInstanceRoom.getEntityAction<BattleObjectInteractAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(interact_action, () => $"interact_action is null !!!");
|
||||
|
||||
var result = await interact_action.interactPodCombat(handler, player);
|
||||
if (result.isFail())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public bool send_S2C_ACK_BATTLE_OBJECT_INTERACTION(Player player, Result result, string anchorGuid)
|
||||
{
|
||||
var ack_packet = new ClientToGame();
|
||||
ack_packet.Response = new ClientToGameRes();
|
||||
|
||||
ack_packet.Response.ErrorCode = result.ErrorCode;
|
||||
ack_packet.Response.AckBattleObjectInteraction = new ClientToGameRes.Types.GS2C_ACK_BATTLE_OBJECT_INTERACTION();
|
||||
ack_packet.Response.AckBattleObjectInteraction.AnchorGuid = anchorGuid;
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using static ClientToGameReq.Types;
|
||||
using static ClientToGameRes.Types;
|
||||
|
||||
|
||||
namespace GameServer.PacketHandler;
|
||||
|
||||
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_BATTLE_PLAYER_DEATH), typeof(BattlePlayerDeadPacketHandler), typeof(GameLoginListener))]
|
||||
public class BattlePlayerDeadPacketHandler : PacketRecvHandler
|
||||
{
|
||||
public override async Task<Result> onProcessPacket(ISession entityWithSession, Google.Protobuf.IMessage recvMessage)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var player = entityWithSession as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var server_config = server_logic.getServerConfig();
|
||||
bool is_battle_system_active = server_config.BattleSystemEnable;
|
||||
|
||||
if (false == is_battle_system_active)
|
||||
{
|
||||
err_msg = $"is_battle_system_active is false!!!";
|
||||
result.setFail(ServerErrorCode.BattleInstanceInActive, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
send_S2C_ACK_BATTLE_PLAYER_DEATH(player, result);
|
||||
return result;
|
||||
}
|
||||
var room_id = player.getCurrentInstanceRoomId();
|
||||
var battle_instance_room = BattleInstanceManager.It.getBattleInstanceRoom(room_id);
|
||||
if (battle_instance_room == null)
|
||||
{
|
||||
err_msg = $"battle_instance_room is null : room_id - {room_id}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.BattleInstanceInfoNotExist, err_msg);
|
||||
send_S2C_ACK_BATTLE_PLAYER_DEATH(player, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
var req_msg = recvMessage as ClientToGame;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(req_msg, () => $"req_msg is null !!! - {player.toBasicString()}");
|
||||
|
||||
var request = req_msg.Request.ReqBattlePlayerDeath;
|
||||
if (null == request)
|
||||
{
|
||||
err_msg = $"failed to get request message : Invalid Request message - {req_msg.Request.MsgCase}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
|
||||
send_S2C_ACK_BATTLE_PLAYER_DEATH(player, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
var killer_guid = request.KillerGuid;
|
||||
var packet_create_time = request.PacketCreateTime;
|
||||
|
||||
if (packet_create_time is not null)
|
||||
{
|
||||
Log.getLogger().info($"Player Deat packet received room_id : {room_id}, anchor_guid : {killer_guid}, packetCreateTime : {packet_create_time}, player : {player.toBasicString()}");
|
||||
}
|
||||
|
||||
result = await playerDeadProcess(player, killer_guid, battle_instance_room);
|
||||
if (result.isFail()) return result;
|
||||
|
||||
await killUserQuestCheck(killer_guid, battle_instance_room);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task killUserQuestCheck(string killerGuid, BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
battleInstanceRoom.m_instance_room.tryGetInstanceMember(killerGuid, out var killer);
|
||||
|
||||
if (killer is null)
|
||||
{
|
||||
Log.getLogger().warn($"killer User not exist instance killerGuid : {killerGuid}, roomId :{battleInstanceRoom.m_instance_room.getMap().m_room_id} ");
|
||||
return;
|
||||
}
|
||||
|
||||
var attribute = battleInstanceRoom.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
if (false == attribute.m_combat_pod_mode.m_tactical_board.TryGetValue(killerGuid, out var boradInfo))
|
||||
{
|
||||
Log.getLogger().warn($"killer User not exist m_tactical_board killerGuid : {killerGuid}, roomId :{battleInstanceRoom.m_instance_room.getMap().m_room_id} ");
|
||||
return;
|
||||
}
|
||||
|
||||
var kill_count = boradInfo.m_kill_count;
|
||||
await QuestManager.It.QuestCheck(killer, new QuestTpsPlayerKill(EQuestEventTargetType.TPS, EQuestEventNameType.PLAYERKILL, kill_count));
|
||||
}
|
||||
|
||||
public async Task<Result> playerDeadProcess(Player player, string kilerUserGuid, BattleInstanceRoom battleInstanceRoom)
|
||||
{
|
||||
var dead_user_guid = player.getUserGuid();
|
||||
var dead_user_nickname = player.getUserNickname();
|
||||
|
||||
var attribute = battleInstanceRoom.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
|
||||
var fn_player_dead = async delegate()
|
||||
{
|
||||
|
||||
bool need_pod_combat_drop_noti = false;
|
||||
using (var releaser = await battleInstanceRoom.getAsyncLock())
|
||||
{
|
||||
increaseKillDeadCount(attribute, kilerUserGuid, dead_user_guid);
|
||||
|
||||
var current_owner_guid = attribute.m_combat_pod_mode.m_pod_combat.m_current_occupier_guid;
|
||||
need_pod_combat_drop_noti = dead_user_guid.Equals(current_owner_guid);
|
||||
|
||||
if (need_pod_combat_drop_noti)
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_pod_combat.changeDropState(player.getCurrentPositionInfo().Pos);
|
||||
attribute.modifiedEntityAttribute(true);
|
||||
}
|
||||
}
|
||||
|
||||
Result fn_result = new();
|
||||
send_S2C_ACK_BATTLE_PLAYER_DEATH(player, fn_result);
|
||||
BattleRoomNotifyHelper.send_GS2C_NTF_PLAYER_DEATH(battleInstanceRoom, kilerUserGuid, dead_user_guid, player);
|
||||
if (need_pod_combat_drop_noti)
|
||||
{
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battleInstanceRoom);
|
||||
}
|
||||
|
||||
battleInstanceRoom.m_instance_room.tryGetInstanceMember(kilerUserGuid, out var killer_player);
|
||||
string killer_nickname = string.Empty;
|
||||
if (killer_player is not null)
|
||||
{
|
||||
killer_nickname = killer_player.getUserNickname();
|
||||
}
|
||||
|
||||
var log_action = new LogActionEx(LogActionType.BattleUserDead);
|
||||
var invoker = new BattleRoomPlayerDeadBusinessLog(dead_user_guid, dead_user_nickname, kilerUserGuid, killer_nickname
|
||||
, battleInstanceRoom.m_instance_room.getMap().m_room_id, attribute.m_combat_pod_mode.m_current_round, need_pod_combat_drop_noti);
|
||||
BusinessLogger.collectLogs(log_action, player, new List<ILogInvoker>(){invoker});
|
||||
|
||||
return fn_result;
|
||||
|
||||
|
||||
};
|
||||
|
||||
var result = await player.runTransactionRunnerSafely(TransactionIdType.BattleRoom, "BattlePlayerDead", fn_player_dead);
|
||||
if (result.isFail())
|
||||
{
|
||||
var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()}, {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
send_S2C_ACK_BATTLE_PLAYER_DEATH(player, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void increaseKillDeadCount(BattleInstanceSnapshotAttribute attribute, string kilerUserGuid, string deadUserGuid)
|
||||
{
|
||||
if (false == attribute.m_combat_pod_mode.m_tactical_board.TryGetValue(kilerUserGuid, out var killerTacticalBoardInfo))
|
||||
{
|
||||
killerTacticalBoardInfo = new(kilerUserGuid);
|
||||
attribute.m_combat_pod_mode.m_tactical_board.TryAdd(kilerUserGuid, killerTacticalBoardInfo);
|
||||
}
|
||||
killerTacticalBoardInfo.m_kill_count++;
|
||||
|
||||
if (false == attribute.m_combat_pod_mode.m_tactical_board.TryGetValue(deadUserGuid, out var deadTacticalBoardInfo))
|
||||
{
|
||||
deadTacticalBoardInfo = new(deadUserGuid);
|
||||
attribute.m_combat_pod_mode.m_tactical_board.TryAdd(deadUserGuid, deadTacticalBoardInfo);
|
||||
}
|
||||
deadTacticalBoardInfo.m_Death_count++;
|
||||
}
|
||||
|
||||
public bool send_S2C_ACK_BATTLE_PLAYER_DEATH(Player player, Result result)
|
||||
{
|
||||
var ack_packet = new ClientToGame();
|
||||
ack_packet.Response = new ClientToGameRes();
|
||||
|
||||
ack_packet.Response.ErrorCode = result.ErrorCode;
|
||||
ack_packet.Response.AckBattlePlayerDeath = new ClientToGameRes.Types.GS2C_ACK_BATTLE_PLAYER_DEATH();
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using static ClientToGameReq.Types;
|
||||
using static ClientToGameRes.Types;
|
||||
|
||||
|
||||
namespace GameServer.PacketHandler;
|
||||
|
||||
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_BATTLE_PLAYER_RESPAWN), typeof(BattlePlayerRespawnPacketHandler), typeof(GameLoginListener))]
|
||||
public class BattlePlayerRespawnPacketHandler : PacketRecvHandler
|
||||
{
|
||||
public override async Task<Result> onProcessPacket(ISession entityWithSession, Google.Protobuf.IMessage recvMessage)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var player = entityWithSession as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var server_config = server_logic.getServerConfig();
|
||||
bool is_battle_system_active = server_config.BattleSystemEnable;
|
||||
|
||||
if (false == is_battle_system_active)
|
||||
{
|
||||
err_msg = $"is_battle_system_active is false!!!";
|
||||
result.setFail(ServerErrorCode.BattleInstanceInActive, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
send_S2C_ACK_BATTLE_PLAYER_RESPAWN(player, null, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
var room_id = player.getCurrentInstanceRoomId();
|
||||
var battle_instance_room = BattleInstanceManager.It.getBattleInstanceRoom(room_id);
|
||||
if (battle_instance_room == null)
|
||||
{
|
||||
err_msg = $"battle_instance_room is null : room_id - {room_id}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.BattleInstanceInfoNotExist, err_msg);
|
||||
send_S2C_ACK_BATTLE_PLAYER_RESPAWN(player, null, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
var req_msg = recvMessage as ClientToGame;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(req_msg, () => $"req_msg is null !!! - {player.toBasicString()}");
|
||||
|
||||
var request = req_msg.Request.ReqBattlePlayerRespawn;
|
||||
if (null == request)
|
||||
{
|
||||
err_msg = $"failed to get request message : Invalid Request message - {req_msg.Request.MsgCase}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
|
||||
send_S2C_ACK_BATTLE_PLAYER_RESPAWN(player, null, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
var packet_create_time = request.PacketCreateTime;
|
||||
if (packet_create_time is not null)
|
||||
{
|
||||
Log.getLogger().info($"Battle Player respawn packet received packetCreateTime : {packet_create_time}, player : {player.toBasicString()}");
|
||||
}
|
||||
|
||||
|
||||
AnchorInfo? anchor_info = null;
|
||||
var attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
var next_respawn_time = DateTimeHelper.Current;
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
using (var releaser = await battle_instance_room.getAsyncLock())
|
||||
{
|
||||
|
||||
|
||||
(result, var pos_meta_guid) = BattleRoomHelper.getRandomRespawnPos(attribute, battle_instance_room);
|
||||
if (result.isFail())
|
||||
{
|
||||
send_S2C_ACK_BATTLE_PLAYER_RESPAWN(player, null, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (false == battle_instance_room.m_respawn_pos_anchors_meta.Contains(pos_meta_guid))
|
||||
{
|
||||
err_msg = $"respawn pos meta not exist pos_meta_guid : {pos_meta_guid}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceUsableSpawnPointNotExist, err_msg);
|
||||
send_S2C_ACK_BATTLE_PLAYER_RESPAWN(player, null, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
next_respawn_time = now.AddSeconds(battle_instance_room.m_ffa_config_meta.PlayerRespawnTime);
|
||||
|
||||
attribute.m_combat_pod_mode.m_respawns.AddOrUpdate(pos_meta_guid, next_respawn_time, (key, old) => next_respawn_time);
|
||||
attribute.modifiedEntityAttribute(true);
|
||||
|
||||
if (false == battle_instance_room.m_instance_room.getMap().m_anchors.TryGetValue(pos_meta_guid, out var anchorInfo))
|
||||
{
|
||||
err_msg = $"anchorInfo not exist pos_meta_guid : {pos_meta_guid}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceNotExistAnchors, err_msg);
|
||||
send_S2C_ACK_BATTLE_PLAYER_RESPAWN(player, null, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
anchor_info = anchorInfo;
|
||||
|
||||
}
|
||||
var cloned_anchor_pos = anchor_info.AnchorPos.Clone();
|
||||
cloned_anchor_pos.Z += 100;
|
||||
|
||||
send_S2C_ACK_BATTLE_PLAYER_RESPAWN(player, cloned_anchor_pos, result);
|
||||
BattleRoomNotifyHelper.send_GS2C_NTF_PLAYER_RESPAWN(battle_instance_room, cloned_anchor_pos, player);
|
||||
|
||||
//로그 남긴다.
|
||||
var invokers = new List<ILogInvoker>();
|
||||
var log_action = new LogActionEx(LogActionType.BattleUserRespawn);
|
||||
|
||||
var round = attribute.m_combat_pod_mode.m_current_round;
|
||||
var round_state = attribute.m_combat_pod_mode.m_round_state_type;
|
||||
var users = battle_instance_room.m_instance_room.tryGetInstanceExistUserForLog();
|
||||
BattleRespawnBusinessLog business_log = new(room_id, round, round_state, player.getUserGuid(), player.getUserNickname(), anchor_info.AnchorGuid, next_respawn_time);
|
||||
invokers.Add(business_log);
|
||||
BusinessLogger.collectLogs(log_action, player, invokers);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool send_S2C_ACK_BATTLE_PLAYER_RESPAWN(Player player, Pos? pos, Result result)
|
||||
{
|
||||
var ack_packet = new ClientToGame();
|
||||
ack_packet.Response = new ClientToGameRes();
|
||||
|
||||
ack_packet.Response.ErrorCode = result.ErrorCode;
|
||||
ack_packet.Response.AckBattlePlayerRespawn = new ClientToGameRes.Types.GS2C_ACK_BATTLE_PLAYER_RESPAWN();
|
||||
|
||||
if (result.isSuccess() && pos is not null)
|
||||
{
|
||||
ack_packet.Response.AckBattlePlayerRespawn.Pos = pos;
|
||||
}
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using static ClientToGameReq.Types;
|
||||
using static ClientToGameRes.Types;
|
||||
|
||||
|
||||
namespace GameServer.PacketHandler;
|
||||
|
||||
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_JOIN_BATTLE_INSTANCE), typeof(JoinBattleInstancePacketHandler), typeof(GameLoginListener))]
|
||||
public class JoinBattleInstancePacketHandler : PacketRecvHandler
|
||||
{
|
||||
public override async Task<Result> onProcessPacket(ISession entityWithSession, Google.Protobuf.IMessage recvMessage)
|
||||
{
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var player = entityWithSession as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
|
||||
|
||||
var req_msg = recvMessage as ClientToGame;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(req_msg, () => $"req_msg is null !!! - {player.toBasicString()}");
|
||||
|
||||
var request = req_msg.Request.ReqJoinBattleInstance;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {player.toBasicString()}");
|
||||
|
||||
var result = parameterValidationCheck(player, request);
|
||||
if (result.isFail())
|
||||
{
|
||||
send_S2C_ACK_JOIN_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
Int32 event_id = request.EventId;
|
||||
var packet_create_time = request.PacketCreateTime;
|
||||
if (packet_create_time is not null)
|
||||
{
|
||||
Log.getLogger().info($"Join Battle Instance packet received event_id : {event_id}, packetCreateTime : {packet_create_time}, player : {player.toBasicString()}");
|
||||
}
|
||||
|
||||
//Battle Instance는 결과적으로 eventId의해 처리될 확률이 높다. 이거 코드 수정 필요
|
||||
if (event_id == 0)
|
||||
{
|
||||
var server_config = ServerConfigHelper.getServerConfig();
|
||||
NullReferenceCheckHelper.throwIfNull(server_config, () => $"server_config is null !!!");
|
||||
|
||||
// ServiceType.Dev 타입일 경우 무조건 치트 사용이 가능 하다. !!!
|
||||
if (server_config.ServiceType.Equals(ServiceType.Dev.ToString()))
|
||||
{
|
||||
return await processPacketByLandId(player, request);
|
||||
}
|
||||
else
|
||||
{
|
||||
err_msg = $"event_id must have over zero !!! : event_id:{event_id} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.InstanceMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
send_S2C_ACK_JOIN_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return await processPacketByEventId(player, event_id);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Result> processJoinBattleInstance(Player player, Int32 eventId, Int32 instanceId, Timestamp eventStartTS)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg = string.Empty;
|
||||
|
||||
Log.getLogger().info($"player : {player.getUserGuid()} join battle instance eventId : {eventId}, intanceId : {instanceId}, evenstStartTS : {eventStartTS}");
|
||||
|
||||
if (!MetaData.Instance._IndunTable.TryGetValue(instanceId, out var indun_meta_data))
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TryGetValue() !!! : instanceMetaId:{instanceId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.InstanceMetaDataNotFound, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
send_S2C_ACK_JOIN_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
//3. indun content type이 battleRoom이 아니면 리턴
|
||||
var server_connect_info = new ServerConnectInfo();
|
||||
var business_logs = new List<ILogInvoker>();
|
||||
if (indun_meta_data.ContentsType != ContentsType.BattleRoom)
|
||||
{
|
||||
err_msg = $"Failed to MetaData.TryGetValue() !!! : instanceMetaId:{instanceId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.BattleRoomContentsTypeOnly, err_msg);
|
||||
send_S2C_ACK_JOIN_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
var game_zone_move_action = player.getEntityAction<GameZoneMoveAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(game_zone_move_action, () => $"game_zone_move_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var fn_transaction_runner = async delegate ()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
(result, server_connect_info, business_logs) = await game_zone_move_action.tryJoinBattleInstance(player.getUserGuid(), eventId, eventStartTS, indun_meta_data);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryJoinInstance() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
send_S2C_ACK_JOIN_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.JoinInstance, server_logic.getDynamoDbClient(), true);
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
batch.addQuery(new QueryFinal());
|
||||
}
|
||||
|
||||
//if(address_business_log != null) batch.appendBusinessLog(address_business_log);
|
||||
if(business_logs.Count > 0) batch.appendBusinessLogs(business_logs);
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
|
||||
|
||||
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to sendQueryAndBusinessLog() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
send_S2C_ACK_JOIN_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
//이거 쓸지 안쓸지 모르겠군...일단 주석 처리
|
||||
//await QuestManager.It.QuestCheckWithoutTransaction(player, new QuestInstance(EQuestEventTargetType.INSTANCE, EQuestEventNameType.ENTERED, request.LandId, request.Floor));
|
||||
//QuestNotifyHelper.send_GS2C_NTF_QUEST_REWARD(player, common_result);
|
||||
//var common_result = found_transaction_runner.getCommonResult();
|
||||
//var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents);
|
||||
//NullReferenceCheckHelper.throwIfNull(found_transaction_runner, () => $"found_transaction_runner is null !!! - {player.toBasicString()}");
|
||||
|
||||
send_S2C_ACK_JOIN_BATTLE_INSTANCE(player, result, server_connect_info);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "JoinBattleInstance", fn_transaction_runner);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<Result> processPacketByEventId(Player player, Int32 eventId)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg = string.Empty;
|
||||
|
||||
if (false == BattleInstanceManager.It.getSystemBattleEvent(eventId, out var systemBattleEvent))
|
||||
{
|
||||
err_msg = $"not exist system battle evetn : eventId:{eventId} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceNotExistEventInfo, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
send_S2C_ACK_JOIN_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
//이벤트 인스턴스 시작시간, 종료 시간 계산해서 들어가게
|
||||
var now = DateTimeHelper.Current;
|
||||
var joinable_time = BattleRoomHelper.calculateRoomJoinableTime(systemBattleEvent.m_start_time, systemBattleEvent.m_ffa_config_data_id, systemBattleEvent.m_round_count);
|
||||
if (joinable_time < now)
|
||||
{
|
||||
err_msg = $"already joinable_time passed : eventId:{eventId} joinable_time : {joinable_time} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceClosingTime, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
send_S2C_ACK_JOIN_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
var instance_meta_id = systemBattleEvent.m_instance_id;
|
||||
return await processJoinBattleInstance(player, eventId, instance_meta_id, Timestamp.FromDateTime(systemBattleEvent.m_start_time));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private async Task<Result> processPacketByLandId(Player player, ClientToGameReq.Types.C2GS_REQ_JOIN_BATTLE_INSTANCE request)
|
||||
{
|
||||
Int32 land_id = request.LandId;
|
||||
Int32 floor_id = request.Floor;
|
||||
Int32 building_id = request.BuildingId;
|
||||
|
||||
var result = new Result();
|
||||
string err_msg = string.Empty;
|
||||
|
||||
var game_zone_move_action = player.getEntityAction<GameZoneMoveAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(game_zone_move_action, () => $"game_zone_move_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
//RoomMapTree 정로를 이용해서 Instance 정보 호출
|
||||
(result, var room_map_tree, var address_business_log) = MapHelper.tryGetRoomMapTree(land_id, floor_id, building_id);
|
||||
if (result.isFail() || null == room_map_tree)
|
||||
{
|
||||
err_msg = $"Failed to tryGetRoomMapTree() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
send_S2C_ACK_JOIN_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
//instance meta id를 이용해 IndunMetadata 정보 호출
|
||||
var instance_meta_id = room_map_tree.InstanceMetaId;
|
||||
return await processJoinBattleInstance(player, 0, instance_meta_id, Timestamp.FromDateTime(DateTimeHelper.MinTime.Date));
|
||||
|
||||
}
|
||||
|
||||
private Result parameterValidationCheck(Player player, ClientToGameReq.Types.C2GS_REQ_JOIN_BATTLE_INSTANCE request)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var server_config = server_logic.getServerConfig();
|
||||
bool is_battle_system_active = server_config.BattleSystemEnable;
|
||||
|
||||
string err_msg = string.Empty;
|
||||
var result = new Result();
|
||||
|
||||
if (false == is_battle_system_active)
|
||||
{
|
||||
err_msg = $"is_battle_system_active is false!!!";
|
||||
result.setFail(ServerErrorCode.BattleInstanceInActive, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool send_S2C_ACK_JOIN_BATTLE_INSTANCE(Player owner, Result result, ServerConnectInfo? serverConnectInfo)
|
||||
{
|
||||
var ack_packet = new ClientToGame();
|
||||
ack_packet.Response = new ClientToGameRes();
|
||||
|
||||
ack_packet.Response.ErrorCode = result.ErrorCode;
|
||||
ack_packet.Response.AckJoinBattleInstance = new();
|
||||
|
||||
if (result.isSuccess() && serverConnectInfo != null)
|
||||
{
|
||||
ack_packet.Response.AckJoinBattleInstance.InstanceServerConnectInfo = serverConnectInfo;
|
||||
}
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(owner, ack_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,286 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using static ClientToGameReq.Types;
|
||||
using static ClientToGameRes.Types;
|
||||
|
||||
|
||||
namespace GameServer.PacketHandler;
|
||||
|
||||
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_LEAVE_BATTLE_INSTANCE), typeof(LeaveBattleInstancePacketHandler), typeof(GameLoginListener))]
|
||||
public class LeaveBattleInstancePacketHandler : PacketRecvHandler
|
||||
{
|
||||
public override async Task<Result> onProcessPacket(ISession entityWithSession, Google.Protobuf.IMessage recvMessage)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var server_config = server_logic.getServerConfig();
|
||||
bool is_battle_system_active = server_config.BattleSystemEnable;
|
||||
|
||||
var player = entityWithSession as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"entity_player is null !!!");
|
||||
|
||||
//앞단에 넣으면 좋겠지만... 일단 여기에..
|
||||
if (false == is_battle_system_active)
|
||||
{
|
||||
err_msg = $"is_battle_system_active is false!!!";
|
||||
result.setFail(ServerErrorCode.BattleInstanceInActive, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
var req_msg = recvMessage as ClientToGame;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(req_msg, () => $"req_msg is null !!! - {player.toBasicString()}");
|
||||
|
||||
var request = req_msg.Request.ReqLeaveBattleInstance;
|
||||
if (null == request)
|
||||
{
|
||||
err_msg = $"failed to get request message : Invalid Request message - {req_msg.Request.MsgCase}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
var packet_create_time = request.PacketCreateTime;
|
||||
if (packet_create_time is not null)
|
||||
{
|
||||
Log.getLogger().info($"Leave Battle Instance packet received, packetCreateTime : {packet_create_time}, player : {player.toBasicString()}");
|
||||
}
|
||||
|
||||
|
||||
var attribute = player.getEntityAttribute<LocationAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"LocationAttribute is null !!! - player:{player.toBasicString()}");
|
||||
|
||||
if (false == MetaData.Instance._IndunTable.TryGetValue(attribute.CurrentIndunLocation.InstanceMetaId, out var prev_indun_data) || null == prev_indun_data)
|
||||
{
|
||||
err_msg = $"failed to get indun data !!! - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.NotFoundIndunData, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
List<ILogInvoker> invokers = new();
|
||||
var departure_position_info = player.getCurrentPositionInfo();
|
||||
var departure_position_log_info = PositionBusinessLogHelper.toPositionLogInfo(PositionMoveType.Departure, departure_position_info);
|
||||
var departure_position_business_log = new PositionBusinessLog(departure_position_log_info);
|
||||
invokers.Add(departure_position_business_log);
|
||||
|
||||
|
||||
// 1. 이동할 서버 조회
|
||||
var channel_server_name = attribute.LastestChannelServerLocation.ServerName;
|
||||
var world_meta_id = attribute.LastestChannelServerLocation.WorldMetaId;
|
||||
|
||||
var move_server_info = await server_logic.getReturnToServerInfo(channel_server_name, ServerType.Channel, player, (ushort)world_meta_id);
|
||||
if (null == move_server_info)
|
||||
{
|
||||
err_msg = $"Failed to get balanced GameServer !!! - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.NoServerConnectable, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 2. 이동 예약 요청
|
||||
var message = new ServerMessage.Types.GS2GS_REQ_RESERVATION_ENTER_TO_SERVER();
|
||||
message.MoveType = ServerMoveType.Force;
|
||||
message.RequestUserGuid = player.getUserGuid();
|
||||
message.RequestServerName = GameServerApp.getServerLogic().getServerName();
|
||||
|
||||
var reserved = await server_logic.getReservationManager().registerReservationEnterToServer(message, move_server_info.Name);
|
||||
|
||||
// 예약 실패 체크
|
||||
if (null == reserved)
|
||||
{
|
||||
err_msg = $"Failed to reservation enter to game server!!! - {nameof(LeaveInstancePacketHandler)}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.FailedToReservationEnter, err_msg);
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 4. instance room 떠나기
|
||||
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "LeaveBattleInstance", leaveBattleInstanceDelegate);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to runTransactionRunner() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
// if (prev_is_in_concert && prev_indun_data is not null)
|
||||
// {
|
||||
// await QuestManager.It.QuestCheck(entity_player, new QuestConcert(EQuestEventTargetType.CONCERT, EQuestEventNameType.ENDED, prev_indun_data.MapId));
|
||||
// }
|
||||
|
||||
|
||||
return result;
|
||||
|
||||
async Task<Result> leaveBattleInstanceDelegate() => await leaveBattleInstanceAsync(player, move_server_info, prev_indun_data, invokers);
|
||||
}
|
||||
|
||||
|
||||
public async Task<Result> leaveBattleInstanceAsync(Player player, ServerInfo server_info, InstanceMetaData prevIndunData, List<ILogInvoker> invokers)
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
|
||||
var battle_zone_move_action = player.getEntityAction<GameZoneMoveAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_zone_move_action, () => $"game_zone_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var result = new Result();
|
||||
string err_msg;
|
||||
|
||||
// 1. leave battle room
|
||||
(result, _) = await battle_zone_move_action.tryLeaveBattleInstanceRoom();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to tryLeaveInstance() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
var location_action = player.getEntityAction<LocationAction>();
|
||||
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)
|
||||
{
|
||||
err_msg = $"tryLeaveBattelInstance instance_room_Id is Empty player : {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceInfoNotExist, err_msg);
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
var battle_instance_room = BattleInstanceManager.It.getBattleInstanceRoom(instance_room_Id);
|
||||
if (battle_instance_room is null)
|
||||
{
|
||||
err_msg = $"battle_instance_room not esist instance_room_Id : {instance_room_Id}, player : {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.BattleInstanceInfoNotExist, err_msg);
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
var battle_instance_room_attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(battle_instance_room_attribute, () => $"battle_instance_room_attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
// 2. move to channel
|
||||
result = await location_action.tryMoveToChannel();
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Fail to tryMoveToIndun";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
var buff_action = player.getEntityAction<BuffAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(buff_action, () => $"buff_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
result = await buff_action.MoveServer(EPlaceType.World);
|
||||
if (result.isFail())
|
||||
{
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 3. otp 생성
|
||||
(result, var reserved_to_switch_server) = await ServerConnectionSwitchHelper.startServerSwitch(player, server_logic.getRedisConnector(), server_info.Name);
|
||||
if (result.isFail() || null == reserved_to_switch_server)
|
||||
{
|
||||
err_msg = $"Fail to startServerSwitch() !!! : {result.toBasicString()}";
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
var game_login_action = player.getEntityAction<GameLoginAction>();
|
||||
NullReferenceCheckHelper.throwIfNull(game_login_action, () => $"game_login_action is null !!! - {player.toBasicString()}");
|
||||
|
||||
var login_cache = game_login_action.getLoginCacheRequest()?.getLoginCache();
|
||||
NullReferenceCheckHelper.throwIfNull(login_cache, () => $"LoginCache is null !!! - player:{player.toBasicString()}");
|
||||
|
||||
login_cache.ReservedToSwitchServer = reserved_to_switch_server;
|
||||
|
||||
var gameServer_connection_info = new ServerConnectInfo
|
||||
{
|
||||
ServerAddr = server_info.Address,
|
||||
ServerPort = server_info.Port,
|
||||
Otp = reserved_to_switch_server.OneTimeKey,
|
||||
};
|
||||
|
||||
var location_attribute = player.getEntityAttribute<LocationAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(location_attribute, () => $"location attribute is null !!! - {player.toBasicString()}");
|
||||
|
||||
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.LeaveInstance, server_logic.getDynamoDbClient());
|
||||
{
|
||||
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
|
||||
batch.addQuery(new QueryFinal());
|
||||
}
|
||||
|
||||
var server_name = ServerType.Indun.toServerName(gameServer_connection_info.ServerAddr, (ushort)gameServer_connection_info.ServerPort);
|
||||
|
||||
var arrival_position_log_info = PositionBusinessLogHelper.toPositionLogInfo(PositionMoveType.Arrival, server_name, ""
|
||||
, MapFileType.World, 0, new());
|
||||
var arrival_position_business_log = new PositionBusinessLog(arrival_position_log_info);
|
||||
invokers.Add(arrival_position_business_log);
|
||||
|
||||
//로그 추가
|
||||
batch.appendBusinessLogs(invokers);
|
||||
|
||||
result = await QueryHelper.sendQueryAndBusinessLog(batch);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
send_S2C_ACK_LEAVE_BATTLE_INSTANCE(player, result, gameServer_connection_info);
|
||||
|
||||
Log.getLogger().debug($"LeaveBattleInstance gameServer_connection_info : {JsonConvert.SerializeObject(gameServer_connection_info)}, player : {player.toBasicString()}");
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool send_S2C_ACK_LEAVE_BATTLE_INSTANCE(Player owner, Result result, ServerConnectInfo? server_info)
|
||||
{
|
||||
var ack_packet = new ClientToGame();
|
||||
ack_packet.Response = new ClientToGameRes();
|
||||
|
||||
ack_packet.Response.ErrorCode = result.ErrorCode;
|
||||
ack_packet.Response.AckLeaveBattleInstance = new ClientToGameRes.Types.GS2C_ACK_LEAVE_BATTLE_INSTANCE();
|
||||
|
||||
if (result.isSuccess() && null != server_info)
|
||||
{
|
||||
ack_packet.Response.AckLeaveBattleInstance.GameServerAddr = server_info.ServerAddr;
|
||||
ack_packet.Response.AckLeaveBattleInstance.GameServerPort = server_info.ServerPort;
|
||||
ack_packet.Response.AckLeaveBattleInstance.Otp = server_info.Otp;
|
||||
}
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(owner, ack_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
using Nettention.Proud;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
|
||||
namespace GameServer.PacketHandler;
|
||||
|
||||
|
||||
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.C2GS_REQ_PREPARATION_FOR_LEAVING_BATTLE_INSTANCE), typeof(PreparationForLeavingBattleInstancePacketHandler), typeof(GameLoginListener))]
|
||||
public class PreparationForLeavingBattleInstancePacketHandler : PacketRecvHandler
|
||||
{
|
||||
|
||||
public override async Task<Result> onProcessPacket(ISession entityWithSession, Google.Protobuf.IMessage recvMessage)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var server_config = server_logic.getServerConfig();
|
||||
bool is_battle_system_active = server_config.BattleSystemEnable;
|
||||
|
||||
var player = entityWithSession as Player;
|
||||
NullReferenceCheckHelper.throwIfNull(player, () => $"entity_player is null !!!");
|
||||
|
||||
//앞단에 넣으면 좋겠지만... 일단 여기에..
|
||||
if (false == is_battle_system_active)
|
||||
{
|
||||
err_msg = $"is_battle_system_active is false!!!";
|
||||
result.setFail(ServerErrorCode.BattleInstanceInActive, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
send_S2C_ACK_PREPARE_FOR_LEAVING_BATTLE_INSTANCE(player, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
var req_msg = recvMessage as ClientToGame;
|
||||
ArgumentNullReferenceCheckHelper.throwIfNull(req_msg, () => $"req_msg is null !!! - {player.toBasicString()}");
|
||||
var request = req_msg.Request.ReqPreparationForLeavingInstance;
|
||||
if (null == request)
|
||||
{
|
||||
err_msg = $"failed to get request message : Invalid Request message - {req_msg.Request.MsgCase}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
|
||||
send_S2C_ACK_PREPARE_FOR_LEAVING_BATTLE_INSTANCE(player, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
var packet_create_time = request.PacketCreateTime;
|
||||
if (packet_create_time is not null)
|
||||
{
|
||||
Log.getLogger().info($"Preparation For leaving Battle Instance Packet Received, packetCreateTime : {packet_create_time}, player : {player.toBasicString()}");
|
||||
}
|
||||
|
||||
|
||||
var room_id = player.getCurrentInstanceRoomId();
|
||||
var battle_instance_room = BattleInstanceManager.It.getBattleInstanceRoom(room_id);
|
||||
if (battle_instance_room == null)
|
||||
{
|
||||
err_msg = $"battle_instance_room is null : room_id - {room_id}";
|
||||
Log.getLogger().error(err_msg);
|
||||
result.setFail(ServerErrorCode.BattleInstanceInfoNotExist, err_msg);
|
||||
send_S2C_ACK_PREPARE_FOR_LEAVING_BATTLE_INSTANCE(player, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
var user_guid = player.getUserGuid();
|
||||
|
||||
var fn_preparation_for_leaving = async delegate()
|
||||
{
|
||||
bool need_pod_combat_drop_noti = false;
|
||||
using (var releaser = await battle_instance_room.getAsyncLock())
|
||||
{
|
||||
|
||||
var attribute = battle_instance_room.getEntityAttribute<BattleInstanceSnapshotAttribute>();
|
||||
NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!!");
|
||||
var current_owner_guid = attribute.m_combat_pod_mode.m_pod_combat.m_current_occupier_guid;
|
||||
need_pod_combat_drop_noti = user_guid.Equals(current_owner_guid);
|
||||
|
||||
if (need_pod_combat_drop_noti)
|
||||
{
|
||||
attribute.m_combat_pod_mode.m_pod_combat.changeDropState(player.getCurrentPositionInfo().Pos);
|
||||
attribute.modifiedEntityAttribute();
|
||||
}
|
||||
}
|
||||
|
||||
send_S2C_ACK_PREPARE_FOR_LEAVING_BATTLE_INSTANCE(player, result);
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_PREPARATION_FOR_LEAVING_BATTLE_INSTANCE(battle_instance_room, user_guid);
|
||||
if (need_pod_combat_drop_noti)
|
||||
{
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battle_instance_room);
|
||||
}
|
||||
|
||||
var host_guid = battle_instance_room.m_host_migrator.getHostUserGuid();
|
||||
|
||||
if (user_guid.Equals(host_guid))
|
||||
{
|
||||
var hosts = new List<HostID>();
|
||||
hosts.Add(player.getHostId());
|
||||
var p2p_group_id = battle_instance_room.m_instance_room.getMap().getP2PGroupId();
|
||||
var define_result = battle_instance_room.m_host_migrator.defineHost(p2p_group_id, new SuperPeerSelectionPolicy(), hosts.ToArray());
|
||||
if (define_result.isFail())
|
||||
{
|
||||
Log.getLogger().warn(define_result.toBasicString());
|
||||
//이걸 define_result로 넘겨야 되나 말아야 되나....리팩토링 후에 고민좀 해보자... 만약 두명이 동시에 나간다고 하면??
|
||||
return result;
|
||||
}
|
||||
|
||||
var new_host_user_guid = battle_instance_room.m_host_migrator.getHostUserGuid();
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_P2P_HOST_UPDATE(battle_instance_room.m_instance_room, new_host_user_guid);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "PreparationForLeavingBattleInstance", fn_preparation_for_leaving);
|
||||
if (result.isFail())
|
||||
{
|
||||
err_msg = $"Failed to runTransactionRunner() !!! : {result.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().error(err_msg);
|
||||
send_S2C_ACK_PREPARE_FOR_LEAVING_BATTLE_INSTANCE(player, result);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool send_S2C_ACK_PREPARE_FOR_LEAVING_BATTLE_INSTANCE(Player player, Result result)
|
||||
{
|
||||
var ack_packet = new ClientToGame();
|
||||
ack_packet.Response = new ClientToGameRes();
|
||||
|
||||
ack_packet.Response.ErrorCode = result.ErrorCode;
|
||||
ack_packet.Response.AckPreparationForLeavingInstance = new ClientToGameRes.Types.GS2C_ACK_PREPARATION_FOR_LEAVING_BATTLE_INSTANCE();
|
||||
|
||||
if (false == GameServerApp.getServerLogic().onSendPacket(player, ack_packet))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,684 @@
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using MetaAssets;
|
||||
using Newtonsoft.Json;
|
||||
using ServerControlCenter;
|
||||
using ServerCore; using ServerBase;
|
||||
using StackExchange.Redis;
|
||||
using System.Numerics;
|
||||
|
||||
namespace ServerCommon;
|
||||
|
||||
// public class InstanceRoomInfo
|
||||
// {
|
||||
// public string roomId { get; set; } = string.Empty;
|
||||
// public string InstanceAddress { get; set; } = string.Empty;
|
||||
// public int InstancePort { get; set; } = 0;
|
||||
// public int InstanceId { get; set; } = 0;
|
||||
// public int UgcNpcCount { get; set; } = 0;
|
||||
// public string MyhomeGuid { get; set; } = string.Empty;
|
||||
// public EPlaceType InstancePlaceType { get; set; } = EPlaceType.NONE;
|
||||
// public Timestamp InstanceStartTime { get; set; } = DateTimeHelper.MinTime.ToTimestamp();
|
||||
// }
|
||||
|
||||
|
||||
public class BattleInstanceRoomStorage
|
||||
{
|
||||
|
||||
//readonly int KEEP_INSTANCE_ROOM_TIME = (60 * 1000);
|
||||
|
||||
//ConnectionMultiplexer _connection = default!;
|
||||
IDatabase _database = default!;
|
||||
|
||||
string _roomKeyPrefix = String.Empty;
|
||||
string _instanceKeyPrefix = String.Empty;
|
||||
|
||||
public void Init(IDatabase redisDB, string keyPrefix)
|
||||
{
|
||||
_database = redisDB;
|
||||
_roomKeyPrefix = keyPrefix;
|
||||
if (_roomKeyPrefix != string.Empty && !_roomKeyPrefix.EndsWith(":"))
|
||||
{
|
||||
_roomKeyPrefix += ":";
|
||||
}
|
||||
|
||||
_roomKeyPrefix += "instanceroom";
|
||||
|
||||
_instanceKeyPrefix = keyPrefix;
|
||||
if (_instanceKeyPrefix != string.Empty && !_instanceKeyPrefix.EndsWith(":"))
|
||||
{
|
||||
_instanceKeyPrefix += ":";
|
||||
}
|
||||
|
||||
_instanceKeyPrefix += "instanceroom";
|
||||
}
|
||||
|
||||
|
||||
public async Task<Result> addBattleInstanceRoomList(string instanceRoomIdBase, string instanceRoomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_list_key = GetInstanceRoomListKey(instanceRoomIdBase);
|
||||
|
||||
await _database.SortedSetAddAsync(instance_room_list_key, instanceRoomId, 0);
|
||||
await _database.KeyExpireAsync(instance_room_list_key, TimeSpan.FromMilliseconds(300000));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
err_msg = $"Failed to addInstanceRoomList from Redis !!! : message:{e}";
|
||||
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
||||
Log.getLogger().fatal(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//이코드는 만약에 GetInstanceRoomListKey 에 키값이 변경된다면 battleInstance는 문제가 생길수 있음
|
||||
public string GetInstanceRoomListKey(string instanceRoomIdBase)
|
||||
{
|
||||
return $"{_instanceKeyPrefix}:{instanceRoomIdBase}:roomlist";
|
||||
}
|
||||
|
||||
public async Task<List<string>> getBattleInstanceRoomList(string instanceRoomIdBase, int limitCount)
|
||||
{
|
||||
var err_msg = string.Empty;
|
||||
|
||||
List<string> result_room_list = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_list_key = GetInstanceRoomListKey(instanceRoomIdBase);
|
||||
|
||||
var room_list = await _database.SortedSetRangeByScoreAsync(instance_room_list_key, 0, limitCount, Exclude.Stop, Order.Descending);
|
||||
foreach (var roomId in room_list)
|
||||
{
|
||||
result_room_list.Add(roomId.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
err_msg = $"Failed to get InstanceRoomList from Redis !!! : : errorCode{error_code}, errMsg:{e.Message}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return result_room_list;
|
||||
}
|
||||
|
||||
|
||||
public async Task<(Result, SortedSetEntry[]?)> getBattleInstanceTotalRoomListWithScore(string instanceRoomIdBase, int limitCount)
|
||||
{
|
||||
|
||||
var result = new Result();
|
||||
string instance_room_list_key = string.Empty;
|
||||
try
|
||||
{
|
||||
instance_room_list_key = GetInstanceRoomListKey(instanceRoomIdBase);
|
||||
|
||||
var room_list = await _database.SortedSetRangeByRankWithScoresAsync(instance_room_list_key, 0, limitCount, Order.Descending);
|
||||
|
||||
// foreach (var room in room_list)
|
||||
// {
|
||||
// var room_id = room.Element.ToString();
|
||||
// var score = room.Score;
|
||||
// }
|
||||
|
||||
return (result, room_list);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
var err_msg = $"Exception !!!, Failed to process in getBattleInstanceTotalRoomListWithScore() !!! : errorCode{error_code}, instanceRoomIdBase:{instanceRoomIdBase}, instance_room_list_key : {instance_room_list_key}, exception:{e}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
}
|
||||
|
||||
return (result, null);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
string GetRoomIdSeqKey()
|
||||
{
|
||||
return $"{_roomKeyPrefix}:roomidseq";
|
||||
}
|
||||
|
||||
public string GetRoomInfoKey(string instanceRoomId)
|
||||
{
|
||||
return $"{_roomKeyPrefix}:{instanceRoomId}:info";
|
||||
}
|
||||
|
||||
public string GetRoomMemberListKey(string instanceRoomId)
|
||||
{
|
||||
return $"{_roomKeyPrefix}:{instanceRoomId}:memberlist";
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<long> getRoomIdSeq()
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
long room_id_seq = 0;
|
||||
|
||||
try
|
||||
{
|
||||
string room_id_seq_key = GetRoomIdSeqKey();
|
||||
room_id_seq = await _database.StringIncrementAsync(room_id_seq_key);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
err_msg = $"Failed to getRoomIdSeq from Redis !!! : message:{e}";
|
||||
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
||||
Log.getLogger().fatal(result.toBasicString());
|
||||
}
|
||||
|
||||
return room_id_seq;
|
||||
}
|
||||
|
||||
public async Task<(Result, bool)> createInstanceRoom(string instanceRoomId, string instanceAddress, int instancePort, int instanceMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
var is_created = false;
|
||||
|
||||
try
|
||||
{
|
||||
string room_info_key = GetRoomInfoKey(instanceRoomId);
|
||||
|
||||
var instance_room_info = new InstanceRoomInfo();
|
||||
instance_room_info.roomId = instanceRoomId;
|
||||
instance_room_info.InstanceAddress = instanceAddress;
|
||||
instance_room_info.InstancePort = instancePort;
|
||||
instance_room_info.InstanceId = instanceMetaId;
|
||||
instance_room_info.UgcNpcCount = 0;
|
||||
|
||||
// 중복 확인
|
||||
var exist_instance_room_state = await isExistInstanceRoom(instanceRoomId, instanceMetaId);
|
||||
switch (exist_instance_room_state)
|
||||
{
|
||||
case ExistInstanceRoomState.None:
|
||||
{
|
||||
var hash_entries = TypeConvertHelper.toHashEntries(instance_room_info);
|
||||
await _database.HashSetAsync(room_info_key, hash_entries);
|
||||
await _database.KeyExpireAsync(room_info_key, TimeSpan.FromMilliseconds(KEEP_INSTANCE_ROOM_TIME));
|
||||
|
||||
is_created = true;
|
||||
}
|
||||
break;
|
||||
case ExistInstanceRoomState.Different:
|
||||
{
|
||||
err_msg = $"InstanceRoomId is Duplicated !!! : instanceRoomId:{instanceRoomId}, instanceMetaId:{instanceMetaId}";
|
||||
result.setFail(ServerErrorCode.InstanceRoomIdDuplicated, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return (result, is_created);
|
||||
}
|
||||
case ExistInstanceRoomState.Exist:
|
||||
{
|
||||
// 존재하는 방이 만드려는 방과 동일하다.
|
||||
// 해당 방으로 입장한다.
|
||||
}
|
||||
break;
|
||||
case ExistInstanceRoomState.Exception:
|
||||
{
|
||||
err_msg = $"Failed to isExistInstanceRoom() !!!";
|
||||
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, is_created);
|
||||
}
|
||||
default:
|
||||
{
|
||||
err_msg = $"ExistInstanceRoomState Invalid !!! : state:{exist_instance_room_state}";
|
||||
result.setFail(ServerErrorCode.NotImplemented, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return (result, is_created);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
err_msg = $"Failed to createInstanceRoom from Redis !!! : message:{e}";
|
||||
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
||||
Log.getLogger().fatal(err_msg);
|
||||
}
|
||||
|
||||
return (result, is_created);
|
||||
}
|
||||
|
||||
async Task<ExistInstanceRoomState> isExistInstanceRoom(string instanceRoomId, int instanceMetaId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_info_key = GetRoomInfoKey(instanceRoomId);
|
||||
|
||||
// 기존 방 정보 얻기
|
||||
var value = await _database.HashGetAllAsync(instance_room_info_key, CommandFlags.PreferReplica);
|
||||
if (value.Length <= 0)
|
||||
return ExistInstanceRoomState.None;
|
||||
|
||||
// 내가 원하는 방인지 확인
|
||||
var instance_room_info = TypeConvertHelper.toClassFromHashEntries<InstanceRoomInfo>(value);
|
||||
if (instance_room_info.roomId != instanceRoomId || instance_room_info.InstanceId != instanceMetaId)
|
||||
return ExistInstanceRoomState.Different;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
err_msg = $"Failed to isExistInstanceRoom from Redis !!! : message:{e}";
|
||||
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
||||
Log.getLogger().fatal(result.toBasicString());
|
||||
|
||||
return ExistInstanceRoomState.Exception;
|
||||
}
|
||||
|
||||
return ExistInstanceRoomState.Exist;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public async Task<Result> joinInstanceRoom(string userGuid, string instanceRoomId, int limitCount)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_member_list_key = GetRoomMemberListKey(instanceRoomId);
|
||||
|
||||
var push_after_length = await _database.ListRightPushAsync(instance_room_member_list_key, userGuid);
|
||||
if (push_after_length > limitCount)
|
||||
{
|
||||
await _database.ListTrimAsync(instance_room_member_list_key, 0, limitCount - 1);
|
||||
var trim_after_position = await _database.ListPositionAsync(instance_room_member_list_key, userGuid);
|
||||
if (trim_after_position == -1)
|
||||
{
|
||||
err_msg = $"roomId:{instanceRoomId} is full !!! : pushAfterLength:{push_after_length}, limitCount:{limitCount}, trimAfterPosition:{trim_after_position} - userGuid:{userGuid}";
|
||||
result.setFail(ServerErrorCode.InstanceRoomIsFull, err_msg);
|
||||
Log.getLogger().debug(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
await _database.KeyExpireAsync(instance_room_member_list_key, TimeSpan.FromMilliseconds(KEEP_INSTANCE_ROOM_TIME));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
err_msg = $"Failed to joinInstanceRoom from Redis !!! : message:{e} - userGuid:{userGuid}";
|
||||
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
||||
Log.getLogger().fatal(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> increaseInstanceRoomScore(string instanceRoomIdBase, string instanceRoomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_list_key = GetInstanceRoomListKey(instanceRoomIdBase);
|
||||
|
||||
await _database.SortedSetIncrementAsync(instance_room_list_key, instanceRoomId, 1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
err_msg = $"Failed to increaseInstanceRoomScore from Redis !!! : message:{e}";
|
||||
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
||||
Log.getLogger().fatal(result.toBasicString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> increaseInstanceRoomUgcNpcScore(string instanceRoomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_info_key = GetRoomInfoKey(instanceRoomId);
|
||||
await _database.HashIncrementAsync(instance_room_info_key, nameof(InstanceRoomInfo.UgcNpcCount), 1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
err_msg = $"Failed to decreaseInstanceRoomUgcNpcScore from Redis !!! : : errorCode{error_code}, errMsg:{e.Message}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<List<string>> GetInstanceRoomMemberList(string roomId)
|
||||
{
|
||||
List<string> returnList = new();
|
||||
string roomKey = GetRoomMemberListKey(roomId);
|
||||
var roomMemberList = await _database.ListRangeAsync(roomKey);
|
||||
|
||||
if (roomMemberList == null) return returnList;
|
||||
|
||||
returnList.AddRange(roomMemberList.Select(x => x.ToString()));
|
||||
return returnList;
|
||||
}
|
||||
|
||||
public async Task<Result> leaveInstanceRoom(string userGuid, string instanceRoomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_list_key = GetRoomMemberListKey(instanceRoomId);
|
||||
|
||||
await _database.ListRemoveAsync(instance_room_list_key, userGuid);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
err_msg = $"Failed to leaveInstanceRoom from Redis !!! : message:{e} - userGuid:{userGuid}";
|
||||
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
||||
Log.getLogger().fatal(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> decreaseInstanceRoomScore(string instanceRoomIdBase, string instanceRoomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_list_key = GetInstanceRoomListKey(instanceRoomIdBase);
|
||||
|
||||
await _database.SortedSetDecrementAsync(instance_room_list_key, instanceRoomId, 1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
err_msg = $"Failed to decreaseInstanceRoomScore from Redis !!! : : errorCode{error_code}, errMsg:{e.Message}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> decreaseInstanceRoomUgcNpcScore(string instanceRoomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_info_key = GetRoomInfoKey(instanceRoomId);
|
||||
await _database.HashDecrementAsync(instance_room_info_key, nameof(InstanceRoomInfo.UgcNpcCount), 1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
err_msg = $"Failed to decreaseInstanceRoomUgcNpcScore from Redis !!! : : errorCode{error_code}, errMsg:{e.Message}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> deleteInstanceRoom(string instanceRoomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string roomInfoKey = GetRoomInfoKey(instanceRoomId);
|
||||
string roomMemberListKey = GetRoomMemberListKey(instanceRoomId);
|
||||
|
||||
await _database.KeyDeleteAsync(roomInfoKey);
|
||||
await _database.KeyDeleteAsync(roomMemberListKey);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
err_msg = $"Failed to deleteInstanceRoom from Redis !!! : errorCode{error_code}, errMsg:{e.Message}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> removeInstanceRoomList(string instanceRoomIdBase, string instanceRoomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_list_key = GetInstanceRoomListKey(instanceRoomIdBase);
|
||||
|
||||
await _database.SortedSetRemoveAsync(instance_room_list_key, instanceRoomId);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
err_msg = $"Failed to removeInstanceRoomList from Redis !!! : : errorCode{error_code}, errMsg:{e.Message}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<InstanceRoomInfo?> GetInstanceRoomInfo(string instanceRoomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
var instance_room_info_key = GetRoomInfoKey(instanceRoomId);
|
||||
var value = await _database.HashGetAllAsync(instance_room_info_key, CommandFlags.PreferReplica);
|
||||
if (value.Length <= 0) return null;
|
||||
|
||||
return TypeConvertHelper.toClassFromHashEntries<InstanceRoomInfo>(value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
err_msg = $"Failed to GetInstanceRoomInfo() from Redis !!! : message:{e}";
|
||||
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result> setInstanceRoomExtraInfo(string roomId, EPlaceType placeType, DateTime startTime)
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
try
|
||||
{
|
||||
var instance_info = await GetInstanceRoomInfo(roomId);
|
||||
if (null == instance_info)
|
||||
{
|
||||
result.setFail(ServerErrorCode.NotExistInstanceRoom);
|
||||
return result;
|
||||
}
|
||||
|
||||
instance_info.InstancePlaceType = placeType;
|
||||
instance_info.InstanceStartTime = startTime.ToTimestamp();
|
||||
|
||||
var room_info_key = GetRoomInfoKey(roomId);
|
||||
var hash_entries = TypeConvertHelper.toHashEntries(instance_info);
|
||||
await _database.HashSetAsync(room_info_key, hash_entries);
|
||||
await _database.KeyExpireAsync(room_info_key, TimeSpan.FromMilliseconds(KEEP_INSTANCE_ROOM_TIME));
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.setFail(ServerErrorCode.InstanceRoomException, $"{ex}");
|
||||
Log.getLogger().error($"{ex.ToString()}");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Result> setInstanceRoomMyhomeGuid(string roomId, string myhomeGuid)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
var instance_info = await GetInstanceRoomInfo(roomId);
|
||||
if (null == instance_info)
|
||||
{
|
||||
err_msg = $"Failed to GetInstanceRoomInfo() !!! : instanceRoomId:{roomId}";
|
||||
result.setFail(ServerErrorCode.InstanceRoomNotExistAtRedis, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
instance_info.MyhomeGuid = myhomeGuid;
|
||||
|
||||
var room_info_key = GetRoomInfoKey(roomId);
|
||||
var hash_entries = TypeConvertHelper.toHashEntries(instance_info);
|
||||
await _database.HashSetAsync(room_info_key, hash_entries);
|
||||
await _database.KeyExpireAsync(room_info_key, TimeSpan.FromMilliseconds(KEEP_INSTANCE_ROOM_TIME));
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
err_msg = $"Failed to setInstanceRoomMyhomeGuid from Redis !!! : message:{e}";
|
||||
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
||||
Log.getLogger().fatal(err_msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public async Task<int> getInstanceRoomListTotalUserCount(string instanceRoomIdBase)
|
||||
{
|
||||
var err_msg = string.Empty;
|
||||
|
||||
int total_user_count = 0;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_list_key = GetInstanceRoomListKey(instanceRoomIdBase);
|
||||
|
||||
var sorted_set_entities = await _database.SortedSetRangeByRankWithScoresAsync(instance_room_list_key);
|
||||
foreach (var entity in sorted_set_entities)
|
||||
{
|
||||
if (entity.Score < 0)
|
||||
continue;
|
||||
|
||||
total_user_count += (int)entity.Score;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
err_msg = $"Failed to get InstanceRoomListTotalUserCount from Redis !!! : : errorCode{error_code}, errMsg:{e.Message}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return total_user_count;
|
||||
}
|
||||
|
||||
public async Task<int> getInstanceRoomUserCount(string instanceRoomId)
|
||||
{
|
||||
var err_msg = string.Empty;
|
||||
|
||||
int user_count = 0;
|
||||
|
||||
try
|
||||
{
|
||||
var room_member_list_key = GetRoomMemberListKey(instanceRoomId);
|
||||
|
||||
user_count = (int)await _database.ListLengthAsync(room_member_list_key, CommandFlags.PreferReplica);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
err_msg = $"Failed to get InstanceRoomUserCount from Redis !!! : : errorCode{error_code}, errMsg:{e.Message}";
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return user_count;
|
||||
}
|
||||
|
||||
public async Task<Result> keepInstanceRoom(string instanceRoomId)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_info_key = GetRoomInfoKey(instanceRoomId);
|
||||
string intstance_room_member_list_key = GetRoomMemberListKey(instanceRoomId);
|
||||
|
||||
await _database.KeyExpireAsync(instance_room_info_key, TimeSpan.FromMilliseconds(KEEP_INSTANCE_ROOM_TIME));
|
||||
await _database.KeyExpireAsync(intstance_room_member_list_key, TimeSpan.FromMilliseconds(KEEP_INSTANCE_ROOM_TIME));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
err_msg = $"Failed to KeepInstanceRoom from Redis !!! : : errorCode{error_code}, errMsg:{e.Message}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> keepInstanceRoomList(string instanceRoomIdBase)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
string instance_room_list_key = GetInstanceRoomListKey(instanceRoomIdBase);
|
||||
|
||||
await _database.KeyExpireAsync(instance_room_list_key, TimeSpan.FromMilliseconds(KEEP_INSTANCE_ROOM_TIME), ExpireWhen.Always, CommandFlags.FireAndForget);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var error_code = ServerErrorCode.TryCatchException;
|
||||
err_msg = $"Failed to KeepInstanceRoomList from Redis !!! : : errorCode{error_code}, errMsg:{e.Message}";
|
||||
result.setFail(error_code, err_msg);
|
||||
Log.getLogger().error(err_msg);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace GameServer.Contents.Battle.Reward;
|
||||
|
||||
public class RewardPickupPod : RewardBase
|
||||
{
|
||||
public RewardPickupPod(Player player, string userGuid, List<MetaAssets.Reward> rewards) : base(player, userGuid, rewards)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override Task<Result> prepareReward()
|
||||
{
|
||||
return Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// 보상처리 후 필요한 로직들 처리
|
||||
//=====================================================================================
|
||||
public override Task<Result> finalizeReward()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class RewardPodCombat : RewardBase
|
||||
{
|
||||
public RewardPodCombat(Player player, string userGuid, List<MetaAssets.Reward> rewards) : base(player, userGuid, rewards)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override Task<Result> prepareReward()
|
||||
{
|
||||
return Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// 보상처리 후 필요한 로직들 처리
|
||||
//=====================================================================================
|
||||
public override Task<Result> finalizeReward()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace GameServer.Contents.Battle.Reward;
|
||||
|
||||
public class RewardPodStorage : RewardBase
|
||||
{
|
||||
|
||||
public RewardPodStorage(Player player, string userGuid, List<MetaAssets.Reward> rewards) : base(player, userGuid, rewards)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override Task<Result> prepareReward()
|
||||
{
|
||||
return Task.FromResult(new Result());
|
||||
}
|
||||
|
||||
//=====================================================================================
|
||||
// 보상처리 후 필요한 로직들 처리
|
||||
//=====================================================================================
|
||||
public override Task<Result> finalizeReward()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
using GameServer.Contents.Battle.Doc;
|
||||
using MetaAssets;
|
||||
using Newtonsoft.Json;
|
||||
using ServerCommon;
|
||||
using ServerCore; using ServerBase;
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleEventCheckTicker : EntityTicker
|
||||
{
|
||||
public BattleEventCheckTicker(double onTickIntervalMilliseconds, CancellationTokenSource? cts)
|
||||
: base(EntityType.BattleEventCheckTicker, onTickIntervalMilliseconds, cts)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public override async Task onTaskTick()
|
||||
{
|
||||
if (false == BattleRoomHelper.checkBattleActive()) return;
|
||||
|
||||
var result = await refreshEvent();
|
||||
if (result.isFail())
|
||||
{
|
||||
Log.getLogger().error($"BattleEventCheckTicker onTaskTick error :{result.toBasicString()}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override async Task<Result> onInit()
|
||||
{
|
||||
await refreshEvent();
|
||||
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<Result> refreshEvent()
|
||||
{
|
||||
var result = new Result();
|
||||
(result, var docs) = await loadFromDB();
|
||||
if (result.isFail()) return result;
|
||||
|
||||
if (docs.Count == 0)
|
||||
{
|
||||
Log.getLogger().info("Not exist Battle Evnet From DB");
|
||||
return result;
|
||||
}
|
||||
|
||||
//실제로 작동하는 battle event로 만들기
|
||||
await updateBattleEvent(docs);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<(Result, List<BattleEventDoc>)> loadFromDB()
|
||||
{
|
||||
var server_logic = GameServerApp.getServerLogic();
|
||||
var dynamo_db_client = server_logic.getDynamoDbClient();
|
||||
|
||||
var doc = new BattleEventDoc();
|
||||
var query_config = dynamo_db_client.makeQueryConfigForReadByPKOnly(doc.getPK());
|
||||
(var result, var read_doc_list) = await dynamo_db_client.simpleQueryDocTypesWithQueryOperationConfig<BattleEventDoc>(query_config);
|
||||
if (result.isFail())
|
||||
{
|
||||
return (result, new());
|
||||
}
|
||||
|
||||
Log.getLogger().info($"load battle event from db eventdoc count : {read_doc_list.Count}");
|
||||
|
||||
return (result, read_doc_list);
|
||||
}
|
||||
|
||||
|
||||
public List<BattleEventAttrib> loadTempEvent()
|
||||
{
|
||||
List<BattleEventAttrib> battle_event_attribs = new();
|
||||
|
||||
for(int i = 1; i < 15; i++)
|
||||
{
|
||||
var battle_event_attrib = new BattleEventAttrib();
|
||||
battle_event_attrib.m_event_id = i;
|
||||
battle_event_attrib.m_is_active = i == 11 ? false : true;
|
||||
|
||||
battle_event_attrib.m_start_day = DateTimeHelper.Current.Date;
|
||||
battle_event_attrib.m_start_hour = i-1; //9시 부터 셋팅
|
||||
battle_event_attrib.m_start_min = 00;
|
||||
|
||||
|
||||
battle_event_attrib.m_instance_id = 1017006 + ((i % 3) % 2);
|
||||
battle_event_attrib.m_period = OncePeriodRangeType.Daily;
|
||||
battle_event_attrib.m_day_of_week_type = new();
|
||||
battle_event_attrib.m_ffa_config_data_id = 1;
|
||||
battle_event_attrib.m_ffa_reward_group_id = 1;
|
||||
battle_event_attrib.m_ffa_hot_time = 1 + (i % 3) ;
|
||||
|
||||
battle_event_attrib.m_round_count = 1 + (i % 5);
|
||||
battle_event_attrib.m_end_date = DateTimeHelper.Current.Date.AddDays(7);
|
||||
|
||||
battle_event_attribs.Add(battle_event_attrib);
|
||||
|
||||
}
|
||||
|
||||
return battle_event_attribs;
|
||||
}
|
||||
|
||||
public async Task updateBattleEvent(List<BattleEventDoc> docs)
|
||||
{
|
||||
|
||||
await Task.CompletedTask;
|
||||
DateTime now = DateTimeHelper.Current;
|
||||
DateTime today = now.Date;
|
||||
|
||||
deleteOldEvents(now);
|
||||
|
||||
foreach (var read_doc in docs)
|
||||
{
|
||||
addNewEvent(read_doc, today, now);
|
||||
}
|
||||
|
||||
foreach (var read_doc in docs)
|
||||
{
|
||||
checkModifiedEvent(now, read_doc);
|
||||
}
|
||||
|
||||
BattleInstanceManager.It.logSystemBattleEvents();
|
||||
}
|
||||
|
||||
private void addNewEvent(BattleEventDoc doc, DateTime today, DateTime now)
|
||||
{
|
||||
var attrib = doc.getAttrib<BattleEventAttrib>();
|
||||
if (attrib is null)
|
||||
{
|
||||
Log.getLogger().error("BattleEventDoc BattleEventAttrib is null !!!!");
|
||||
return;
|
||||
}
|
||||
|
||||
//메모리에 존재하는 이벤트면 리턴
|
||||
if (BattleInstanceManager.It.existSystemBattleEvent(attrib.m_event_id)) return;
|
||||
|
||||
//아직 시작 안한 이벤트면 리턴
|
||||
var start_day = DateTime.SpecifyKind(attrib.m_start_day, DateTimeKind.Utc);
|
||||
|
||||
var recently_events = CreateSystemBattleEvents(attrib, start_day, now);
|
||||
foreach (var new_ev in recently_events)
|
||||
{
|
||||
BattleInstanceManager.It.addNewSystemBattleEvent(new_ev, true);
|
||||
}
|
||||
|
||||
var new_events = CreateSystemBattleEvents(attrib, today, now);
|
||||
foreach (var new_ev in new_events)
|
||||
{
|
||||
BattleInstanceManager.It.addNewSystemBattleEvent(new_ev, true);
|
||||
}
|
||||
|
||||
//다음날 events 도 추가능한것은 추가한다.
|
||||
var tomorrow_new_events = CreateSystemBattleEvents(attrib, today.AddDays(1), now);
|
||||
foreach (var new_ev in tomorrow_new_events)
|
||||
{
|
||||
BattleInstanceManager.It.addNewSystemBattleEvent(new_ev, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void checkModifiedEvent(DateTime now, BattleEventDoc doc)
|
||||
{
|
||||
var events = BattleInstanceManager.It.getSystemBattleEvents();
|
||||
|
||||
var attrib = doc.getAttrib<BattleEventAttrib>();
|
||||
if (attrib is null)
|
||||
{
|
||||
Log.getLogger().error("BattleEventDoc BattleEventAttrib is null !!!!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (false == events.TryGetValue(attrib.m_event_id, out var event_data)) return;
|
||||
if (event_data.m_start_time <= now) return;
|
||||
|
||||
var delete_event_ids = new List<int>();
|
||||
if (attrib.m_is_active == false)
|
||||
{
|
||||
delete_event_ids.Add(attrib.m_event_id);
|
||||
}
|
||||
|
||||
if (delete_event_ids.Count > 0)
|
||||
{
|
||||
Log.getLogger().info($"deleted event ids : {JsonConvert.SerializeObject(delete_event_ids)}");
|
||||
BattleInstanceManager.It.removeSystemBattleEvents(delete_event_ids);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void deleteOldEvents(DateTime now)
|
||||
{
|
||||
var events = BattleInstanceManager.It.getSystemBattleEvents();
|
||||
|
||||
//오래된 이벤트 id 취합 및 삭제
|
||||
List<Int32> deleted_event_ids = new();
|
||||
foreach (var battle_events in events.Values.ToList())
|
||||
{
|
||||
var event_id = battle_events.m_event_id;
|
||||
var start_time = battle_events.m_start_time;
|
||||
|
||||
var destroyed_time = BattleRoomHelper.calculateDestroyedTime(start_time, battle_events.m_ffa_config_data_id, battle_events.m_round_count);
|
||||
if (destroyed_time < now)
|
||||
{
|
||||
deleted_event_ids.Add(event_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (deleted_event_ids.Count > 0)
|
||||
{
|
||||
Log.getLogger().info($"deleted event ids : {JsonConvert.SerializeObject(deleted_event_ids)}");
|
||||
BattleInstanceManager.It.removeSystemBattleEvents(deleted_event_ids);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private List<SystemBattleEvent> CreateSystemBattleEvents(BattleEventAttrib attrib, DateTime startDay, DateTime now)
|
||||
{
|
||||
List<SystemBattleEvent> new_events = new();
|
||||
if (BattleInstanceManager.It.existSystemBattleEvent(attrib.m_event_id)) return new_events;
|
||||
|
||||
var start_time = makeSystemBattleEventStartTime(attrib, startDay);
|
||||
|
||||
//파괴되는 시간을 계산했는데 이벤트 종료시간보다 크면 안넣는다.
|
||||
var joinableTime_time = BattleRoomHelper.calculateRoomJoinableTime(start_time, attrib.m_ffa_config_data_id, attrib.m_round_count);
|
||||
if (joinableTime_time < now) return new_events;
|
||||
if (attrib.m_end_date < joinableTime_time) return new_events;
|
||||
|
||||
//이벤트 비활성 상태면 안넣는다.
|
||||
if (attrib.m_is_active == false) return new_events;
|
||||
|
||||
switch (attrib.m_period)
|
||||
{
|
||||
case OncePeriodRangeType.NONE:
|
||||
case OncePeriodRangeType.Daily:
|
||||
new_events.AddRange(makeDailySystemBattleEvent(start_time, now, attrib));
|
||||
break;
|
||||
case OncePeriodRangeType.Weekly:
|
||||
new_events.AddRange(makeWeekliySystemBattleEvent(startDay, now, attrib));
|
||||
break;
|
||||
case OncePeriodRangeType.Monthly:
|
||||
new_events.AddRange(makeMonthiySystemBattleEvent(startDay, now, attrib));
|
||||
break;
|
||||
case OncePeriodRangeType.Nolimit:
|
||||
Log.getLogger($"There is not used Type in Battle System Event !!!! eventId : {attrib.m_event_id}");
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_events.Count > 0)
|
||||
{
|
||||
string new_events_str = JsonConvert.SerializeObject(new_events);
|
||||
Log.getLogger().info($"new battele events set {new_events_str}");
|
||||
}
|
||||
|
||||
return new_events;
|
||||
}
|
||||
|
||||
private DateTime makeSystemBattleEventStartTime(BattleEventAttrib attrib, DateTime today)
|
||||
{
|
||||
switch (attrib.m_period)
|
||||
{
|
||||
case OncePeriodRangeType.NONE:
|
||||
var start_day = DateTime.SpecifyKind(attrib.m_start_day, DateTimeKind.Utc);
|
||||
return start_day.AddHours(attrib.m_start_hour).AddMinutes(attrib.m_start_min);
|
||||
case OncePeriodRangeType.Daily:
|
||||
case OncePeriodRangeType.Weekly:
|
||||
case OncePeriodRangeType.Monthly:
|
||||
return today.AddHours(attrib.m_start_hour).AddMinutes(attrib.m_start_min);
|
||||
case OncePeriodRangeType.Nolimit:
|
||||
Log.getLogger($"There is not used Type in Battle System Event !!!! eventId : {JsonConvert.SerializeObject(attrib)}");
|
||||
return DateTimeHelper.MinTime;
|
||||
}
|
||||
return DateTimeHelper.MinTime;
|
||||
}
|
||||
// private List<SystemBattleEvent> makeNoneTypeSystemBattleEvent(DateTime startTime, DateTime now, BattleEventAttrib attrib)
|
||||
// {
|
||||
// List<SystemBattleEvent> events = new();
|
||||
//
|
||||
// if (startTime >= now) // && startTime < now.AddDays(1))
|
||||
// {
|
||||
// if (attrib.m_end_date <= now) return events;
|
||||
//
|
||||
// SystemBattleEvent new_event = new SystemBattleEvent
|
||||
// {
|
||||
// m_event_id = attrib.m_event_id,
|
||||
// m_instance_id = attrib.m_instance_id,
|
||||
// m_start_time = startTime,
|
||||
// m_ffa_config_data_id = attrib.m_ffa_config_data_id,
|
||||
// m_ffa_reward_group_id = attrib.m_ffa_reward_group_id,
|
||||
// m_ready_time = startTime.AddMinutes(-5),
|
||||
// m_is_send_noti = false,
|
||||
// m_ffa_hot_time = attrib.m_ffa_hot_time,
|
||||
// m_round_count = attrib.m_round_count
|
||||
// };
|
||||
// events.Add(new_event);
|
||||
// }
|
||||
// return events;
|
||||
// }
|
||||
|
||||
private List<SystemBattleEvent> makeDailySystemBattleEvent(DateTime startTime, DateTime now, BattleEventAttrib attrib)
|
||||
{
|
||||
List<SystemBattleEvent> events = new();
|
||||
|
||||
if (attrib.m_end_date <= now) return events;
|
||||
SystemBattleEvent new_event = new SystemBattleEvent
|
||||
{
|
||||
m_event_id = attrib.m_event_id,
|
||||
m_instance_id = attrib.m_instance_id,
|
||||
m_start_time = startTime,
|
||||
m_ffa_config_data_id = attrib.m_ffa_config_data_id,
|
||||
m_ffa_reward_group_id = attrib.m_ffa_reward_group_id,
|
||||
m_ready_time = startTime.AddMinutes(-5),
|
||||
m_is_send_noti = false,
|
||||
m_ffa_hot_time = attrib.m_ffa_hot_time,
|
||||
m_round_count = attrib.m_round_count
|
||||
};
|
||||
events.Add(new_event);
|
||||
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
private List<SystemBattleEvent> makeWeekliySystemBattleEvent(DateTime today, DateTime now, BattleEventAttrib attrib)
|
||||
{
|
||||
List<SystemBattleEvent> events = new();
|
||||
foreach (var dayOfWeek in attrib.m_day_of_week_type)
|
||||
{
|
||||
int daysUntilNext = ((int)dayOfWeek - (int)today.DayOfWeek + 7) % 7;
|
||||
DateTime eventTime = today.AddDays(daysUntilNext).Date
|
||||
.AddHours(attrib.m_start_hour)
|
||||
.AddMinutes(attrib.m_start_min);
|
||||
|
||||
if (eventTime >= now)// && eventTime < now.AddDays(1))
|
||||
{
|
||||
if (attrib.m_end_date <= now) return events;
|
||||
|
||||
events.Add(new SystemBattleEvent
|
||||
{
|
||||
m_event_id = attrib.m_event_id,
|
||||
m_instance_id = attrib.m_instance_id,
|
||||
m_start_time = eventTime,
|
||||
m_ffa_config_data_id = attrib.m_ffa_config_data_id,
|
||||
m_ffa_reward_group_id = attrib.m_ffa_reward_group_id,
|
||||
m_ready_time = eventTime.AddMinutes(-5),
|
||||
m_is_send_noti = false,
|
||||
m_ffa_hot_time = attrib.m_ffa_hot_time,
|
||||
m_round_count = attrib.m_round_count
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
private List<SystemBattleEvent> makeMonthiySystemBattleEvent(DateTime today, DateTime now, BattleEventAttrib attrib)
|
||||
{
|
||||
List<SystemBattleEvent> events = new();
|
||||
DateTime monthlyTime = new DateTime(
|
||||
today.Year, today.Month, attrib.m_start_day.Day,
|
||||
attrib.m_start_hour, attrib.m_start_min, 0
|
||||
);
|
||||
|
||||
if (monthlyTime >= now)// && monthlyTime < now.AddDays(1))
|
||||
{
|
||||
if (attrib.m_end_date <= now) return events;
|
||||
events.Add(new SystemBattleEvent
|
||||
{
|
||||
|
||||
m_event_id = attrib.m_event_id,
|
||||
m_instance_id = attrib.m_instance_id,
|
||||
m_start_time = monthlyTime,
|
||||
m_ffa_config_data_id = attrib.m_ffa_config_data_id,
|
||||
m_ffa_reward_group_id = attrib.m_ffa_reward_group_id,
|
||||
m_ready_time = monthlyTime.AddMinutes(-5),
|
||||
m_is_send_noti = false,
|
||||
m_ffa_hot_time = attrib.m_ffa_hot_time,
|
||||
m_round_count = attrib.m_round_count
|
||||
});
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class BattleEventNotifyTicker : EntityTicker
|
||||
{
|
||||
public BattleEventNotifyTicker(double onTickIntervalMilliseconds, CancellationTokenSource? cts)
|
||||
: base(EntityType.BattleInstanceStateCheckTicker, onTickIntervalMilliseconds, cts)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override async Task onTaskTick()
|
||||
{
|
||||
if (false == BattleRoomHelper.checkBattleActive()) return;
|
||||
|
||||
//필요한 Noti가 있다면 broadCast
|
||||
await notifyBattleEvent();
|
||||
|
||||
}
|
||||
|
||||
private async Task notifyBattleEvent()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
var battle_events = BattleInstanceManager.It.getSystemBattleEvents().Values;
|
||||
|
||||
var now = DateTimeHelper.Current;
|
||||
List<Int32> event_ids = new();
|
||||
foreach (var ev in battle_events)
|
||||
{
|
||||
if (ev.m_ready_time < now && now <= ev.m_start_time && ev.m_is_send_noti == false)
|
||||
{
|
||||
event_ids.Add(ev.m_event_id);
|
||||
ev.m_is_send_noti = true;
|
||||
}
|
||||
}
|
||||
|
||||
List<BattleEventInfo> infos = new();
|
||||
foreach (var event_id in event_ids)
|
||||
{
|
||||
if (false == BattleInstanceManager.It.getSystemBattleEvent(event_id, out var battleEvent))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
infos.Add(BattleInstanceManager.It.makeProtoBattleEvent(battleEvent));
|
||||
}
|
||||
|
||||
if (infos.Count > 0)
|
||||
{
|
||||
BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_EVENT(infos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class ArcadeRunningInstanceInitHandler : GameModeInitHandlerBase
|
||||
{
|
||||
public ArcadeRunningInstanceInitHandler(InstanceRoom instanceRoom) : base(instanceRoom, EPlaceType.ArcadeRunning)
|
||||
{
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceInitValidate()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
//kihoon todo : running 추가
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceInit()
|
||||
{
|
||||
var result = new Result();
|
||||
//kihoon todo : running 추가
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
|
||||
public class ArcadeRunningInstanceJoinHandler : GameModeJoinHandlerBase
|
||||
{
|
||||
public ArcadeRunningInstanceJoinHandler(InstanceRoom instanceRoom) : base(instanceRoom, EPlaceType.ArcadeRunning)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceJoinValidate(EPlaceType placeType)
|
||||
{
|
||||
var result = new Result();
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Result gamedModeInstanceJoin(Player player)
|
||||
{
|
||||
var result = new Result();
|
||||
string err_msg = string.Empty;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
public class ArcadeRunningInstanceJoinSuccessHandler : GameModeJoinSuccessHandlerBase
|
||||
{
|
||||
public ArcadeRunningInstanceJoinSuccessHandler(Player player, InstanceRoom instanceRoom) : base(player, EPlaceType.ArcadeRunning)
|
||||
{
|
||||
}
|
||||
|
||||
public override Result joinSuccessValidate()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Task<Result> joinSuccessConfirmation()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override Task<Result> joinSuccessNotify()
|
||||
{
|
||||
var result = new Result();
|
||||
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
public override void joinSuccessWriteLog()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user