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

347 lines
15 KiB
C#

using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
using USER_GUID = System.String;
namespace GameServer.PacketHandler;
[PacketHandler(typeof(ClientToGameReq), typeof(ClientToGameReq.Types.SummonPartyMemberReq), typeof(SummonPartyMemberPacketHandler), typeof(GameLoginListener))]
public class SummonPartyMemberPacketHandler : PacketRecvHandler
{
private static void send_S2C_ACK_SUMMON_PARTY_MEMBER(Player owner, Result result, Item? spentItem)
{
var ack_packet = new ClientToGame();
ack_packet.Response = new();
ack_packet.Response.ErrorCode = result.ErrorCode;
ack_packet.Response.SummonPartyMemberRes = new();
if (result.isSuccess())
{
NullReferenceCheckHelper.throwIfNull(spentItem, () => $"spentItem is null !!! - {owner.toBasicString()}");
var delete = spentItem.toItemData4Client();
var item = new ItemGuidCount();
item.ItemGuid = delete.ItemGuid;
item.ItemCount = delete.Count;
ack_packet.Response.SummonPartyMemberRes.Items.Add(item);
}
GameServerApp.getServerLogic().onSendPacket(owner, ack_packet);
}
public override async Task<Result> onProcessPacket(ISession entityWithSession, IMessage recvMessage)
{
var player = entityWithSession as Player;
ArgumentNullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var game_msg = recvMessage as ClientToGame;
ArgumentNullReferenceCheckHelper.throwIfNull(game_msg, () => $"game_msg is null !!! - {player.toBasicString()}");
var request = game_msg.Request.SummonPartyMemberReq;
ArgumentNullReferenceCheckHelper.throwIfNull(request, () => $"request is null !!! - {player.toBasicString()}");
var result = new Result();
string err_msg;
var player_action = player.getEntityAction<PlayerAction>();
NullReferenceCheckHelper.throwIfNull(player_action, () => $"player_action is null !!! - {player.toBasicString()}");
// 1. 캐릭터 선택 상태 체크
var selected_character = player_action.getSelectedCharacter();
if (null == selected_character)
{
err_msg = $"Not selected Character !!! - {player.toBasicString()}";
result.setFail(ServerErrorCode.CharacterNotSelected, err_msg);
Log.getLogger().error(result.toBasicString());
send_S2C_ACK_SUMMON_PARTY_MEMBER(player, result, null);
return result;
}
// 2. 소속 파티 Guid 조회
var personal_party_action = player.getEntityAction<PersonalPartyAction>();
NullReferenceCheckHelper.throwIfNull(personal_party_action, () => $"personal_party_action is null !!! - {player.toBasicString()}");
var personal_party = personal_party_action.getPersonalParty();
if (null == personal_party)
{
err_msg = $"Failed to get party info !!! - not party member - {player.getUserGuid()}";
result.setFail(ServerErrorCode.NotParty, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_SUMMON_PARTY_MEMBER(player, result, null);
return result;
}
var global_party = GameServerApp.getServerLogic().findGlobalEntity<GlobalParty>();
NullReferenceCheckHelper.throwIfNull(global_party, () => $"global_party is null !!! - {player.toBasicString()}");
var party = global_party.getParty(personal_party.getPartyGuid());
NullReferenceCheckHelper.throwIfNull(party, () => $"party is null !!! - {player.toBasicString()}");
// 3. 파티장 체크
var party_action = party.getEntityAction<GlobalPartyDetailAction>();
NullReferenceCheckHelper.throwIfNull(party_action, () => $"party_action is null !!! - {player.toBasicString()}");
var is_leader = party_action.isLeader(player.getUserGuid());
if (false == is_leader)
{
err_msg = $"Failed to summon party member !!! : not party leader - {player.getUserGuid()}";
result.setFail(ServerErrorCode.NotPartyLeader, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_SUMMON_PARTY_MEMBER(player, result, null);
return result;
}
// 4. 파티원 체크
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"party_member_action is null !!! - {player.toBasicString()}");
var is_member = party_member_action.isPartyMember(request.PartyMemberUserGuid);
if (false == is_member)
{
err_msg = $"Failed to summon party member !!! : not party member - {request.PartyMemberUserGuid}";
result.setFail(ServerErrorCode.NotPartyMember, err_msg);
Log.getLogger().error(err_msg);
send_S2C_ACK_SUMMON_PARTY_MEMBER(player, result, null);
return result;
}
// 5. 소환 조건 체크
result = await checkSummonConditionAsync(player, request.PartyMemberUserGuid, party);
if (result.isFail())
{
send_S2C_ACK_SUMMON_PARTY_MEMBER(player, result, null);
return result;
}
// 6. 소환 처리
result = await player.runTransactionRunnerSafely( TransactionIdType.PrivateContents, "SummonPartyMember"
, summonDelegate );
if (result.isFail())
{
_ = await party_member_action.clearSummonMemberAsync(request.PartyMemberUserGuid, false);
send_S2C_ACK_SUMMON_PARTY_MEMBER(player, result, null);
return result;
}
return result;
async Task<Result> summonDelegate() => await summonAsync(player, request.PartyMemberUserGuid, party);
}
private async Task<Result> checkSummonConditionAsync(Player player, USER_GUID summonUserGuid, GlobalPartyDetail party)
{
var result = new Result();
string err_msg;
var server_logic = GameServerApp.getServerLogic();
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"party_member_action is null !!! - {player.toBasicString()}");
var summon_members = party_member_action.getSummonMembers();
var proud_net_listener = server_logic.getProudNetListener();
// 1. base 체크
var curr_user_count = proud_net_listener.getEntityWithSessions().Count +
server_logic.getReservationManager().getReservedUserCount() +
server_logic.getReturnManager().getReturnUserCount() +
UgcNpcCountManager.Instance.calculateNpcCount();
if (proud_net_listener.getMaxConnectionCount() <= curr_user_count)
{
err_msg = $"Failed to summon party member !!! : not channel server - {curr_user_count}";
result.setFail(ServerErrorCode.PartyLeaderServerIsFull, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 2. leader condition 체크
result = await checkLeaderConditions(player, summon_members.Count());
if (result.isFail()) return result;
// 3. summon user condition 체크
result = await checkSummonUserConditions(player, summon_members.ToList(), summonUserGuid);
if (result.isFail()) return result;
return result;
}
private async Task<Result> checkLeaderConditions(Player player, int summonMemberCount)
{
await Task.CompletedTask;
var server_logic = GameServerApp.getServerLogic();
var result = new Result();
string err_msg;
// 1. leader 가 channel 인지 체크
if (server_logic.getServerType().toServerType() != ServerType.Channel)
{
err_msg = $"Failed to summon party member !!! : not channel server - {GameServerApp.getServerLogic().getServerType().toServerType()}";
result.setFail(ServerErrorCode.InvalidSummonServerType, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 2. 소환 불가 위치 체크
// todo (sangyeob.kim) : client 에서 체크 중 -> 서버체크는 필요시 추가 ( 현재는 notifyReply 로 한다. )
// 3. 소환석 아이템 수량 체크
var inventory_action = player.getEntityAction<InventoryActionBase>();
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!! - {player.toBasicString()}");
var summon_item_count = inventory_action.getItemCountAllByMetaId((uint)MetaHelper.GameConfigMeta.SummonStoneItemMetaId);
if (summon_item_count < summonMemberCount + 1)
{
err_msg = $"Failed to summon party member !!! : insufficient summon item - summon_item_count[{summon_item_count}] / summon_count[{summonMemberCount}]";
result.setFail(ServerErrorCode.ItemCountNotEnough, err_msg);
Log.getLogger().error(err_msg);
}
return result;
}
private async Task<Result> checkSummonUserConditions(Player player, IReadOnlyList<USER_GUID> summonUsers, USER_GUID summonUserGuid)
{
var server_logic = GameServerApp.getServerLogic();
var result = new Result();
string err_msg;
// 1. 소환 중인 유저 체크
if (summonUsers.Contains(summonUserGuid))
{
err_msg = $"Failed to summon party member !!! : Already summon member - {summonUserGuid}";
result.setFail(ServerErrorCode.AlreadySummon, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 2. 소환 유저 로그인 체크
var login_cache = await PartyHelper.getOtherUserLoginCache(summonUserGuid);
if (null == login_cache)
{
err_msg = $"Failed to summon party member !!! : summon user logged out - {summonUserGuid}";
result.setFail(ServerErrorCode.LogOffTarget, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 3. 동일 월드 체크
(result, var summon_user_server_info) = await server_logic.getServerInfoByServerName(login_cache.CurrentServer);
NullReferenceCheckHelper.throwIfNull(summon_user_server_info, () => $"summon_user_server_info is null !!! - {player.toBasicString()}");
if (summon_user_server_info.WorldId != server_logic.getWorldId())
{
err_msg = $"Failed to summon party member !!! : invalid world id - leader[{server_logic.getWorldId()}] summon[{summon_user_server_info.WorldId}]";
result.setFail(ServerErrorCode.InvalidSummonWorldServer, err_msg);
Log.getLogger().error(err_msg);
return result;
}
// 4. 소환 파티원 위치 체크
var player_manager = server_logic.getPlayerManager();
if (player_manager.tryGetUserByPrimaryKey(summonUserGuid, out var summon_user))
{
if(null == summon_user)
{
err_msg = $"Failed to summon party member !!! : summon user logged out - {summonUserGuid}";
result.setFail(ServerErrorCode.LogOffTarget, err_msg);
Log.getLogger().error(err_msg);
return result;
}
var leader_location_action = player.getEntityAction<LocationAction>();
NullReferenceCheckHelper.throwIfNull(leader_location_action, () => $"leader_location_action is null !!! - {player.toBasicString()}");
var leader_curr_pos = leader_location_action.getCurrentPos();
var summon_user_location_action = summon_user.getEntityAction<LocationAction>();
NullReferenceCheckHelper.throwIfNull(summon_user_location_action, () => $"summon_user_location_action is null !!! : {summon_user.toBasicString()} - {player.toBasicString()}");
var summon_user_location = summon_user_location_action.getCurrentPos();
var distance = PartyHelper.calculateDistance(leader_curr_pos, summon_user_location);
if (distance <= ServerCommon.Constant.PARTY_SUMMON_LIMIT_DISTANCE)
{
err_msg = $"Failed to summon party member !!! : summon user is short distance - {distance}";
result.setFail(ServerErrorCode.SummonUserLimitDistance, err_msg);
Log.getLogger().error(err_msg);
return result;
}
}
return result;
}
private async Task<Result> summonAsync(Player leader, string summon_user_guid, GlobalPartyDetail party)
{
var leader_location = leader.getEntityAction<LocationAction>()?.getCurrentPos();
NullReferenceCheckHelper.throwIfNull(leader_location, () => $"leader_location is null !!! - {leader.toBasicString()}");
// 0. 소환 데이터 생성
var summon = new SummonInfo();
summon.IsAlreadySummon = true;
summon.SummonServer = GameServerApp.getServerLogic().getServerName();
summon.SummonPos = leader_location;
var party_member_action = party.getEntityAction<GlobalPartyDetailMemberAction>();
NullReferenceCheckHelper.throwIfNull(party_member_action, () => $"party_member_action is null !!! - {leader.toBasicString()}");
// 1. 소환 처리
var summon_result = await party_member_action.summonMemberAsync(summon_user_guid, summon);
if (summon_result.result.isFail())
{
return summon_result.result;
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>( leader, LogActionType.SummonParty
, GameServerApp.getServerLogic().getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
batch.addQuery(new QueryFinal());
}
// 2. Business Log 기록
writeBusinessLog(batch, party.PartyGuid, summon_user_guid);
var result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail()) return result;
send_S2C_ACK_SUMMON_PARTY_MEMBER(leader, result, summon_result.delete_item);
return result;
}
private void writeBusinessLog(QueryBatchBase queryBatch, string partyGuid, string userGuid)
{
// 1. 파티 정보
var party_log_data = PartyBusinessLogHelper.toPartyLogData(partyGuid, false);
var party_business_log = new PartyBusinessLog(party_log_data);
queryBatch.appendBusinessLog(party_business_log);
// 2. 파티 멤버 정보
var party_member_log_data =
PartyBusinessLogHelper.toPartyMemberLogData(partyGuid, userGuid, PartyMemberActionType.Summon);
var party_member_business_log = new PartyMemberBusinessLog(party_member_log_data);
queryBatch.appendBusinessLog(party_member_business_log);
}
}