Files
caliverse_server/GameServer/Contents/Party/PacketHandler/JoinPartyInstancePacketHandler.cs
2025-05-01 07:20:41 +09:00

285 lines
12 KiB
C#

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.JoinPartyInstanceReq), typeof(JoinPartyInstancePacketHandler), typeof(GameLoginListener))]
public class JoinPartyInstancePacketHandler : PacketRecvHandler
{
private static void send_S2C_ACK_JOIN_PARTY_INSTANCE(Player owner, Result result, ClientToGameRes.Types.JoinPartyInstanceRes? response)
{
var ack_packet = new ClientToGame
{
Response = new ClientToGameRes
{
ErrorCode = result.ErrorCode,
JoinPartyInstanceRes = new()
}
};
if (result.isSuccess())
{
ack_packet.Response.JoinPartyInstanceRes = response;
}
GameServerApp.getServerLogic().onSendPacket(owner, ack_packet);
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var result = new Result();
string err_msg;
var entity_player = entityWithSession as Player;
NullReferenceCheckHelper.throwIfNull(entity_player, () => "player is null !!!");
// 1. 기본 정보 체크
var request = (recvMessage as ClientToGame)?.Request.JoinPartyInstanceReq;
if (null == request)
{
err_msg = $"Failed to get request type !!! : {nameof(ClientToGame.Request.JoinPartyInstanceReq)}";
result.setFail(ServerErrorCode.InvalidArgument, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_JOIN_PARTY_INSTANCE(entity_player, result, null);
return result;
}
// 2. 소속 파티 Guid 조회
var personal_party_action = entity_player.getEntityAction<PersonalPartyAction>();
NullReferenceCheckHelper.throwIfNull(personal_party_action, () => $"personal_party_action is null !!! - {entity_player.toBasicString()}");
var personal_party = personal_party_action.getPersonalParty();
if (null == personal_party)
{
err_msg = $"Failed to get party info !!! - not party member - {entity_player.getUserGuid()}";
result.setFail(ServerErrorCode.NotParty, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_JOIN_PARTY_INSTANCE(entity_player, result, null);
return result;
}
var global_party = GameServerApp.getServerLogic().findGlobalEntity<GlobalParty>();
NullReferenceCheckHelper.throwIfNull(global_party, () => "global_party is null !!!");
var party = global_party.getParty(personal_party.getPartyGuid());
NullReferenceCheckHelper.throwIfNull(party, () => $"party is null !!! - party guid: {personal_party.getPartyGuid()}");
// 3. Party Instance 정보 조회
var party_instance_attribute = party.getEntityAttribute<PartyInstanceAttribute>();
NullReferenceCheckHelper.throwIfNull(party_instance_attribute, () => $"party_instance_attribute is null !!! - {entity_player.toBasicString()} / {party.toBasicString()}");
if (party_instance_attribute.InstanceId <= 0)
{
err_msg = $"Failed to join party instance !!! - instance id is null - {party_instance_attribute.InstanceId}";
result.setFail(ServerErrorCode.EmptyPartyInstanceId, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_JOIN_PARTY_INSTANCE(entity_player, result, null);
return result;
}
// 4. Party Instance 입장 요청
result = await joinPartyInstance(entity_player, party_instance_attribute.InstanceId, party_instance_attribute.RoomId);
if (result.isFail())
{
send_S2C_ACK_JOIN_PARTY_INSTANCE(entity_player, result, null);
}
return result;
}
private async Task<Result> joinPartyInstance(Player player, int instanceId, string roomId)
{
var result = new Result();
string err_msg;
var server_logic = GameServerApp.getServerLogic();
var res = new ClientToGameRes.Types.JoinPartyInstanceRes();
// 1. instance 입장 티켓 확인
result = player.checkInstanceAccess(instanceId);
if (result.isFail())
{
err_msg = $"Failed to join party instance !!! : no exist entered ticket - instanceMetaId:{instanceId}";
result.setFail(ServerErrorCode.NotExistInstanceTicket, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 2. join instance
var instance_room_id = await InstanceRoomHandler.JoinPartyInstance(player.getUserGuid(), roomId);
if (instance_room_id == string.Empty)
{
err_msg = $"Failed to join party instance !!! - {instanceId}";
result.setFail(ServerErrorCode.JoinInstanceFail, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 3. room 정보 획득
var instance_room_storage = new InstanceRoomStorage();
instance_room_storage.Init(server_logic.getRedisDb(), "");
var instanceRoom = await instance_room_storage.GetInstanceRoomInfo(instance_room_id);
if (instanceRoom == null)
{
err_msg = $"Not found InstanceRoomInfo. roomId:{instance_room_id}";
result.setFail(ServerErrorCode.NotExistRoomInfoForEnter, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
var serverName = ServerType.Indun.toServerName(instanceRoom.InstanceAddress, (ushort)instanceRoom.InstancePort);
// 4. 이동 예약 요청
var message = new ServerMessage.Types.GS2GS_REQ_RESERVATION_ENTER_TO_SERVER();
message.MoveType = ServerMoveType.Force;
message.RequestServerName = server_logic.getServerName();
message.RequestUserGuid = player.getUserGuid();
var reserved = await server_logic.getReservationManager().registerReservationEnterToServer(message, serverName);
// 5. 예약 실패 체크
if (null == reserved)
{
err_msg = $"Failed to reservation enter to game server!!! - {nameof(JoinInstancePacketHandler)}";
Log.getLogger().error(err_msg);
result.setFail(ServerErrorCode.FailedToReservationEnter, err_msg);
send_S2C_ACK_JOIN_PARTY_INSTANCE(player, result, null);
return result;
}
// 6. 이동 처리
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "JoinPartyInstance",
joinPartyInstanceDelegate);
if (result.isFail())
{
err_msg = $"Failed to transactionRunner !! : {result.ResultString}";
Log.getLogger().error(err_msg);
}
return result;
async Task<Result> joinPartyInstanceDelegate() => await joinPartyInstanceAsync(player, serverName, roomId, instanceRoom);
}
public async Task<Result> joinPartyInstanceAsync(Player player, string destServerName, string roomId, InstanceRoomInfo instanceRoom)
{
var server_logic = GameServerApp.getServerLogic();
var result = new Result();
string err_msg;
// 1. 위치 정보 수정
var location_action = player.getEntityAction<LocationAction>();
NullReferenceCheckHelper.throwIfNull(location_action, () => $"location_action is null !!! - {player.toBasicString()}");
result = await location_action.tryMoveToIndun(instanceRoom);
if (result.isFail())
{
err_msg = $"Fail to tryMoveToIndun";
Log.getLogger().error(err_msg);
send_S2C_ACK_JOIN_PARTY_INSTANCE(player, result, null);
return result;
}
if (!MetaData.Instance._IndunTable.TryGetValue(instanceRoom.InstanceId, out var indun_meta_data))
{
err_msg = $"Failed to TryGetValue() !!! : instanceMetaId:{instanceRoom.InstanceId} : {this.getTypeName()}";
result.setFail(ServerErrorCode.InstanceMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_JOIN_PARTY_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(indun_meta_data.placeType());
if (result.isFail())
{
send_S2C_ACK_JOIN_PARTY_INSTANCE(player, result, null);
return result;
}
// 2. otp 획득
(result, var reserved_to_switch_server) = await ServerConnectionSwitchHelper.startServerSwitch(player, server_logic.getRedisConnector() , destServerName);
if (result.isFail() || null == reserved_to_switch_server)
{
err_msg = $"Fail to startServerSwitch() !!! : {result.toBasicString()}";
Log.getLogger().error(err_msg);
send_S2C_ACK_JOIN_PARTY_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, () => $"Login Cache is null !!! - player: {player.toBasicString()}");
login_cache.ReservedToSwitchServer = reserved_to_switch_server;
var res = new ClientToGameRes.Types.JoinPartyInstanceRes();
res.InstanceServerAddr = instanceRoom.InstanceAddress;
res.InstanceServerPort = instanceRoom.InstancePort;
res.Otp = reserved_to_switch_server.OneTimeKey;
res.RoomId = roomId;
// 3. DB 갱신
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.JoinPartyInstance, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
batch.addQuery(new QueryFinal());
}
writeBusinessLog(batch, player.getUserGuid(), roomId);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
err_msg = $"Failed to write for reserve enter GameServer !!! - {player.toBasicString()}";
result.setFail(ServerErrorCode.NoServerConnectable, err_msg);
Log.getLogger().error(err_msg);
return result;
}
send_S2C_ACK_JOIN_PARTY_INSTANCE(player, result, res);
return result;
}
private void writeBusinessLog(QueryBatchBase queryBatchBase, string userGuid, string roomId)
{
var party_guid = PartyHelper.getPartyGuidFromPartyInstanceRoomId(roomId);
if (string.IsNullOrEmpty(party_guid)) return;
// 1. 파티 인스턴스 정보
var party_instance_log_data = PartyBusinessLogHelper.toPartyInstanceLogData(party_guid, false);
var party_instance_business_log = new PartyInstanceBusinessLog(party_instance_log_data);
queryBatchBase.appendBusinessLog(party_instance_business_log);
// 2. 파티 멤버 정보
var party_member_log_data =
PartyBusinessLogHelper.toPartyMemberLogData(party_guid, userGuid, PartyMemberActionType.PartyInstanceJoin);
var party_member_business_log = new PartyMemberBusinessLog(party_member_log_data);
queryBatchBase.appendBusinessLog(party_member_business_log);
}
}