초기커밋

This commit is contained in:
2025-05-01 07:20:41 +09:00
commit 98bb2e3c5c
2747 changed files with 646947 additions and 0 deletions

View File

@@ -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);
// }
// }
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View 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}");
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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()
{
}
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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();
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View 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 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;
}
}

View File

@@ -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;
}
}

View File

@@ -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)
{
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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});
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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()}");
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}
*/

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}