1865 lines
72 KiB
C#
1865 lines
72 KiB
C#
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Data;
|
|
|
|
|
|
using Amazon.DynamoDBv2.DocumentModel;
|
|
using Google.Protobuf.WellKnownTypes;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Nettention.Proud;
|
|
|
|
|
|
using ServerCore;
|
|
using ServerBase;
|
|
using ServerCommon;
|
|
|
|
|
|
using ENTITY_INSTANCE_GUID = System.String;
|
|
using ANCHOR_META_GUID = System.String;
|
|
using UGC_NPC_META_GUID = System.String;
|
|
using LOCATION_UNIQUE_ID = System.String;
|
|
using META_ID = System.UInt32;
|
|
|
|
|
|
namespace GameServer;
|
|
|
|
public class CellPos
|
|
{
|
|
/// <summary>
|
|
/// Map에서 Cell의 X 좌표
|
|
/// </summary>
|
|
public int CellX { get; private set; }
|
|
/// <summary>
|
|
/// Map에서 Cell의 Y 좌표
|
|
/// </summary>
|
|
public int CellY { get; private set; }
|
|
/// <summary>
|
|
/// Map에서 Grid의 X 좌표
|
|
/// </summary>
|
|
public int GridX { get; private set; }
|
|
/// <summary>
|
|
/// Map에서 Grid의 Y 좌표
|
|
/// </summary>
|
|
public int GridY { get; private set; }
|
|
/// <summary>
|
|
/// Grid에서 Cell의 X 좌표
|
|
/// </summary>
|
|
public int CellinGridX { get; private set; }
|
|
/// <summary>
|
|
/// Grid에서 Cell의 Y 좌표
|
|
/// </summary>
|
|
public int CellinGridY { get; private set; }
|
|
|
|
public CellPos(int cellX, int cellY)
|
|
{
|
|
CellX = cellX;
|
|
CellY = cellY;
|
|
|
|
GridX = GetGridCoordFromCellCoord(cellX);
|
|
GridY = GetGridCoordFromCellCoord(cellY);
|
|
|
|
CellinGridX = GetCellinGridCoordFromCellCoord(cellX);
|
|
CellinGridY = GetCellinGridCoordFromCellCoord(cellY);
|
|
}
|
|
|
|
public override bool Equals(object? obj)
|
|
{
|
|
if (obj == null)
|
|
return false;
|
|
|
|
return obj is CellPos pos2 ?
|
|
(CellX == pos2.CellX && CellY == pos2.CellY) : false;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return (CellX, CellY).GetHashCode();
|
|
}
|
|
|
|
public static bool operator ==(CellPos pos1, CellPos pos2)
|
|
{
|
|
return pos1.Equals(pos2);
|
|
}
|
|
|
|
public static bool operator !=(CellPos pos1, CellPos pos2)
|
|
{
|
|
return !(pos1.Equals(pos2));
|
|
}
|
|
|
|
/// <summary>
|
|
/// CellX 가 -MAX_CELLS_IN_GRID, ,,, -4, -3, -2, -1 인 경우<br/>
|
|
/// MAX_CELLS_IN_GRID 로 나누면 -MAX_CELLS_IN_GRID 는 -1 이 나오고 나머지 값들은 0이 나온다.<br/>
|
|
/// 해당 값은 모두 -1이 되어야 한다. (0은 CellX 가 0, 1, 2, 3 ,,, MAX_CELLS_IN_GRID 인 경우에 쓰인다.)<br/>
|
|
/// CellX에서 1 빼고 MAX_CELLS_IN_GRID 로 나눌 경우<br/>
|
|
/// 모든 값이 0이 나오고 여기서 -1을 하면 모두 -1이 된다.<br/>
|
|
/// </summary>
|
|
/// <param name="cellCoord">좌표가 소속된 CellX or CellY</param>
|
|
/// <returns>좌표가 소속된 GridX or GridY</returns>
|
|
public static int GetGridCoordFromCellCoord(int cellCoord)
|
|
{
|
|
if (cellCoord < 0)
|
|
{
|
|
return ((int)((cellCoord + 1) / Map.MAX_CELLS_IN_GRID)) - 1;
|
|
}
|
|
else
|
|
{
|
|
return (int)(cellCoord / Map.MAX_CELLS_IN_GRID);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// CellX 가 -MAX_CELLS_IN_GRID, ,,, -4, -3, -2, -1 인 경우<br/>
|
|
/// MAX_CELLS_IN_GRID 로 나눈 나머지가 0, -MAX_CELLS_IN_GRID+1, ,,, -3, -2, -1 로 나온다<br/>
|
|
/// 0, 1, 2, ,,, MAX_CELLS_IN_GRID-1 로 나오도록 나머지가 음수일 경우 MAX_CELLS_IN_GRID 를 더해준다.<br/>
|
|
/// </summary>
|
|
/// <param name="cellCoord">좌표가 소속된 CellX or CellY</param>
|
|
/// <returns>좌표가 소속된 CellinGridX or CellinGridY</returns>
|
|
public static int GetCellinGridCoordFromCellCoord(int cellCoord)
|
|
{
|
|
if (cellCoord < 0)
|
|
{
|
|
var cellinGridCoord = cellCoord % Map.MAX_CELLS_IN_GRID;
|
|
if (cellinGridCoord < 0)
|
|
cellinGridCoord += Map.MAX_CELLS_IN_GRID;
|
|
|
|
return cellinGridCoord;
|
|
}
|
|
else
|
|
{
|
|
return cellCoord % Map.MAX_CELLS_IN_GRID;
|
|
}
|
|
}
|
|
|
|
public string toBasicString()
|
|
{
|
|
return $"CellPos[CellX:{CellX},CellY:{CellY}], GridX:{GridX},GridY:{GridY}, CellInGridX:{CellinGridX},CellInGridX:{CellinGridY}]";
|
|
}
|
|
}
|
|
|
|
enum District
|
|
{
|
|
UPPER_DISTRICT = 1,
|
|
LOWER_DISTRICT = 1 << 1,
|
|
LEFT_DISTRICT = 1 << 2,
|
|
RIGHT_DISTRICT = 1 << 3,
|
|
CENTER_DISTRICT = 1 << 4,
|
|
UPPER_LEFT_DISTRICT = (UPPER_DISTRICT | LEFT_DISTRICT),
|
|
UPPER_RIGHT_DISTRICT = (UPPER_DISTRICT | RIGHT_DISTRICT),
|
|
LOWER_LEFT_DISTRICT = (LOWER_DISTRICT | LEFT_DISTRICT),
|
|
LOWER_RIGHT_DISTRICT = (LOWER_DISTRICT | RIGHT_DISTRICT),
|
|
ALL_DISTRICT = (UPPER_DISTRICT | LOWER_DISTRICT | LEFT_DISTRICT | RIGHT_DISTRICT | CENTER_DISTRICT)
|
|
};
|
|
|
|
public class Map
|
|
{
|
|
public static readonly float CELL_SIZE = 6400f;
|
|
public static readonly int MAX_CELLS_IN_GRID = 8;
|
|
|
|
public static readonly float GRID_SIZE = CELL_SIZE * MAX_CELLS_IN_GRID;
|
|
|
|
/// <summary>
|
|
/// Map의 X 좌표 최소값, 최대값
|
|
/// </summary>
|
|
(int min, int max) MapRangeX;
|
|
/// <summary>
|
|
/// Map의 Y 좌표 최소값, 최대값
|
|
/// </summary>
|
|
(int min, int max) MapRangeY;
|
|
/// <summary>
|
|
/// Map의 CellX 좌표 최소값, 최대값
|
|
/// </summary>
|
|
(int min, int max) MapRangeCellX;
|
|
/// <summary>
|
|
/// Map의 CellY 좌표 최소값, 최대값
|
|
/// </summary>
|
|
(int min, int max) MapRangeCellY;
|
|
/// <summary>
|
|
/// Map의 GridX 좌표 최소값, 최대값
|
|
/// </summary>
|
|
(int min, int max) MapRangeGridX;
|
|
/// <summary>
|
|
/// Map의 GridY 좌표 최소값, 최대값
|
|
/// </summary>
|
|
(int min, int max) MapRangeGridY;
|
|
/// <summary>
|
|
/// (GridX, GridY)가 키 값임
|
|
/// </summary>
|
|
Dictionary<(int, int), Grid> Grids = new Dictionary<(int, int), Grid>();
|
|
|
|
PropGroupManager m_prop_group_manager = new();
|
|
public ConcurrentDictionary<string, AnchorInfo> m_anchors = new();
|
|
public List<Pos> WorldAccountStartPos = new();
|
|
|
|
//ENTITY_INSTANCE_GUID는 UGC_NPC_META_GUID와 동일하다 !!!
|
|
private ConcurrentDictionary<ENTITY_INSTANCE_GUID, UgcNpc> m_ugc_npc_entities = new();
|
|
|
|
// 진행중인 파밍 목록
|
|
private ConcurrentDictionary<ANCHOR_META_GUID, FarmingEffect> m_farming_effects = new();
|
|
|
|
// 현재 접속자 추가 카운트
|
|
private Counter m_curr_count_as_add_connected_user = new();
|
|
|
|
private LOCATION_UNIQUE_ID m_location_unique_id = string.Empty;
|
|
|
|
Counter m_current_player_count = new();
|
|
|
|
int AccountStartPosIndex = 0;
|
|
|
|
bool IsOneGrid = false;
|
|
public string MapFileName { get; private set; } = string.Empty;
|
|
public MapFileType MapFileType { get; private set; }
|
|
public int MapMId { get; private set; }
|
|
public string m_room_id { get; private set; } = string.Empty;
|
|
|
|
CancellationTokenSource _cts = new();
|
|
|
|
public Map() { }
|
|
|
|
public async Task<bool> onInit(string mapFileName, string instanceNumber, bool isOneGrid = false)
|
|
{
|
|
var err_msg = string.Empty;
|
|
|
|
MapFileName = mapFileName;
|
|
IsOneGrid = isOneGrid;
|
|
m_room_id = instanceNumber;
|
|
|
|
if (!MapDataTable.Instance.getMapData(MapFileName, out var mapData))
|
|
{
|
|
Log.getLogger().error($"Not Exist MapData {MapFileName}");
|
|
return false;
|
|
}
|
|
|
|
MapFileType = mapData.MapFileType;
|
|
MapMId = mapData.MapMetaId;
|
|
|
|
var location_unique_id = makeLOCATION_UNIQUE_IDByInstanceNumber(instanceNumber);
|
|
setLocationUniqueId(location_unique_id);
|
|
|
|
MapRangeX.min = (int)mapData.Min.X;
|
|
MapRangeX.max = (int)mapData.Max.X;
|
|
|
|
MapRangeY.min = (int)mapData.Min.Y;
|
|
MapRangeY.max = (int)mapData.Max.Y;
|
|
|
|
initGrid(isOneGrid);
|
|
|
|
MapManager.Instance.GetMapAnchorListForMapCreate(MapFileName, out var anchorList);
|
|
foreach (var anchor in anchorList)
|
|
{
|
|
var anchorInfo = new AnchorInfo(anchor.AnchorGuid, anchor.AnchorPos, anchor.AnchorProp);
|
|
|
|
if (false == MapHelper.isUsableAnchorInMapFileType(anchorInfo.AnchorGuid, MapFileType))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (MapHelper.isRewardProp(anchorInfo.AnchorGuid))
|
|
anchorInfo.PropState = PropState.Activation;
|
|
|
|
CellPos propCellPos = GetCellPos(anchorInfo.AnchorPos.X, anchorInfo.AnchorPos.Y);
|
|
GetGrid(propCellPos.GridX, propCellPos.GridY)?.AddAnchor(propCellPos, anchorInfo);
|
|
|
|
getAnchors().TryAdd(anchorInfo.AnchorGuid, anchorInfo);
|
|
|
|
if (MapHelper.isStartPoint(anchorInfo.AnchorGuid, StartPointType.WorldAccountStartPoint))
|
|
WorldAccountStartPos.Add(anchorInfo.AnchorPos);
|
|
|
|
if (MapHelper.isGroupProp(anchorInfo.AnchorGuid))
|
|
m_prop_group_manager.addAnchor(anchorInfo);
|
|
}
|
|
|
|
m_prop_group_manager.init(this);
|
|
|
|
foreach (var anchor in getAnchors().Values)
|
|
{
|
|
CellPos propCellPos = GetCellPos(anchor.AnchorPos.X, anchor.AnchorPos.Y);
|
|
GetGrid(propCellPos.GridX, propCellPos.GridY)?.AddAnchor(propCellPos, anchor);
|
|
}
|
|
|
|
ByteArray byArray = new ByteArray();
|
|
P2PGroupType p2PGroupType = new P2PGroupType();
|
|
p2PGroupType.Type = 2;
|
|
HostID[] array = new HostID[0];
|
|
ServerBase.ProudNetHelper.convertP2PGroupToByteArray(byArray, p2PGroupType);
|
|
|
|
_ = CheckRewardPropRespawn();
|
|
|
|
return await Task.FromResult(true);
|
|
}
|
|
|
|
public async Task<bool> onInitFromMyhomeUgc(string myhomeGuid, MyhomeUgcInfo myhomeUgcInfo, string roomId)
|
|
{
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
result = MyhomeHelper.getMyhomeInstanceId(myhomeUgcInfo.RoomType, out var instance_meta_id);
|
|
if (result.isFail())
|
|
{
|
|
err_msg = $"Fail to getMyhomeInstanceId() !!! : {result.toBasicString()}";
|
|
Log.getLogger().error(err_msg);
|
|
|
|
return false;
|
|
}
|
|
|
|
MapFileType = MapFileType.Instance;
|
|
MapMId = instance_meta_id;
|
|
m_room_id = roomId;
|
|
|
|
IsOneGrid = true;
|
|
initGrid(IsOneGrid);
|
|
|
|
var myhome_warp_pos = MapHelper.getWarpPos(ContentsType.MyHome);
|
|
|
|
foreach (var anchorinfo in myhomeUgcInfo.AnchorInfos)
|
|
{
|
|
var newAnchorPos = new Pos();
|
|
newAnchorPos.X = myhome_warp_pos.X + anchorinfo.Coordinate.X;
|
|
newAnchorPos.Y = myhome_warp_pos.Y + anchorinfo.Coordinate.Y;
|
|
newAnchorPos.Z = myhome_warp_pos.Z + anchorinfo.Coordinate.Z;
|
|
|
|
var anchor_prop = new AnchorProp();
|
|
anchor_prop.TableId = anchorinfo.TableId;
|
|
anchor_prop.GuidByType = anchorinfo.EntityGuid;
|
|
|
|
var anchor_info = new AnchorInfo(anchorinfo.AnchorGuid, newAnchorPos, anchor_prop);
|
|
|
|
if (anchorinfo.isRewardProp())
|
|
anchor_info.PropState = PropState.Activation;
|
|
|
|
CellPos propCellPos = GetCellPos(anchor_info.AnchorPos.X, anchor_info.AnchorPos.Y);
|
|
GetGrid(propCellPos.GridX, propCellPos.GridY)?.AddAnchor(propCellPos, anchor_info);
|
|
|
|
getAnchors().TryAdd(anchor_info.AnchorGuid, anchor_info);
|
|
|
|
if (anchorinfo.isGroupProp())
|
|
m_prop_group_manager.addAnchor(anchor_info);
|
|
}
|
|
|
|
m_prop_group_manager.init(this);
|
|
|
|
foreach (var anchor in getAnchors().Values)
|
|
{
|
|
CellPos propCellPos = GetCellPos(anchor.AnchorPos.X, anchor.AnchorPos.Y);
|
|
GetGrid(propCellPos.GridX, propCellPos.GridY)?.AddAnchor(propCellPos, anchor);
|
|
}
|
|
|
|
(result, var ugc_npcs) = await UgcNpcHelper.loadUgcNpcFromMyhome(this, myhomeGuid);
|
|
if (result.isFail() || null == ugc_npcs)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
foreach (var ugc_npc in ugc_npcs)
|
|
{
|
|
var ugc_npc_action = ugc_npc.getEntityAction<UgcNpcAction>();
|
|
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {ugc_npc.toBasicString()}");
|
|
|
|
ugc_npc_action.setCountingAsConnectedUser(false);
|
|
result = await ugc_npc_action.tryLocateInGameZone(this, myhomeGuid);
|
|
if (result.isFail())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ByteArray byArray = new ByteArray();
|
|
P2PGroupType p2PGroupType = new P2PGroupType();
|
|
p2PGroupType.Type = 2;
|
|
HostID[] array = new HostID[0];
|
|
ServerBase.ProudNetHelper.convertP2PGroupToByteArray(byArray, p2PGroupType);
|
|
|
|
_ = CheckRewardPropRespawn();
|
|
|
|
return true;
|
|
}
|
|
|
|
public FarmingEffect? findFarmingEffect(ANCHOR_META_GUID anchorMetaGuid)
|
|
{
|
|
FarmingEffect? found_farming_effect = null;
|
|
|
|
if (true == m_farming_effects.TryGetValue(anchorMetaGuid, out found_farming_effect))
|
|
{
|
|
return found_farming_effect;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
void initGrid(bool isOneGrid)
|
|
{
|
|
MapRangeCellX.min = isOneGrid ? 0 : GetCellCoord(MapRangeX.min);
|
|
MapRangeCellX.max = isOneGrid ? 0 : GetCellCoord(MapRangeX.max);
|
|
|
|
MapRangeCellY.min = isOneGrid ? 0 : GetCellCoord(MapRangeY.min);
|
|
MapRangeCellY.max = isOneGrid ? 0 : GetCellCoord(MapRangeY.max);
|
|
|
|
MapRangeGridX.min = isOneGrid ? 0 : GetGridCoord(MapRangeX.min);
|
|
MapRangeGridX.max = isOneGrid ? 0 : GetGridCoord(MapRangeX.max);
|
|
|
|
MapRangeGridY.min = isOneGrid ? 0 : GetGridCoord(MapRangeY.min);
|
|
MapRangeGridY.max = isOneGrid ? 0 : GetGridCoord(MapRangeY.max);
|
|
|
|
Log.getLogger().debug($"map:{MapFileName} CellX min:{MapRangeCellX.min} CellX max:{MapRangeCellX.max} MapRangeCellY.min:{MapRangeCellY.min} MapRangeCellY.max:{MapRangeCellY.max}");
|
|
Log.getLogger().debug($"MapRangeGridX.min:{MapRangeGridX.min} MapRangeGridX.max:{MapRangeGridX.min} MapRangeGridY.min:{MapRangeGridY.min} MapRangeGridY.max:{MapRangeGridY.max}");
|
|
|
|
for (int gridX = MapRangeGridX.min; gridX <= MapRangeGridX.max; gridX++)
|
|
{
|
|
for (int gridY = MapRangeGridY.min; gridY <= MapRangeGridY.max; gridY++)
|
|
{
|
|
Grids[(gridX, gridY)] = new Grid(gridX, gridY, IsOneGrid, StartPointType.WorldContinuedStartPoint);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Result tryAddPlayer(Player player, bool isLogin = false)
|
|
{
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
var location_action = player.getEntityAction<LocationAction>();
|
|
|
|
var current_pos = location_action.getCurrentPos();
|
|
|
|
if (isLogin)
|
|
{
|
|
SetNewPosOverlapLoctionPlayer(current_pos);
|
|
}
|
|
|
|
CellPos cellPos = GetCellPos(current_pos.X, current_pos.Y);
|
|
List<CellPos> sightCells = GetSightCells(cellPos, District.ALL_DISTRICT);
|
|
|
|
List<global::GameActor> inSightActors = new List<global::GameActor>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
List<Player> inSightPlayers = new List<Player>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
List<PropInfo> inSightProps = new();
|
|
|
|
List<UgcNpcEntity> inSightUgcNpcs = new List<UgcNpcEntity>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
foreach (CellPos cellPos1 in sightCells)
|
|
{
|
|
GetCell(cellPos1)?.CallFunc((AnchorInfo anchor) =>
|
|
{
|
|
if ( false == string.IsNullOrEmpty(anchor.AnchorProp.GuidByType)
|
|
|| anchor.AnchorProp.IsMannequinsChanged
|
|
|| MapHelper.isRewardProp(anchor.AnchorGuid)
|
|
|| MapHelper.isGroupProp(anchor.AnchorGuid)
|
|
|| MapHelper.isFarmingProp(anchor.AnchorGuid) )
|
|
{
|
|
var propInfo = new PropInfo();
|
|
propInfo.AnchorGuid = anchor.AnchorGuid;
|
|
propInfo.OccupiedActorGuid = anchor.OccupyingUserGuid;
|
|
propInfo.TableId = anchor.AnchorProp.TableId;
|
|
propInfo.ItemGuid = anchor.AnchorProp.GuidByType;
|
|
|
|
if(true == getFarmingEffects().TryGetValue(anchor.AnchorGuid, out var found_farming_effect))
|
|
{
|
|
var farming_effect_attribute = found_farming_effect.getEntityAttribute<FarmingEffectAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(farming_effect_attribute, () => $"farming_effect_attribute is null !!! - AnchorGuid:{anchor.AnchorGuid}, {player.toBasicString()}");
|
|
|
|
propInfo.StartTime = farming_effect_attribute.FarmingStartTime.ToTimestamp();
|
|
propInfo.EndTime = farming_effect_attribute.FarmingEndTime.ToTimestamp();
|
|
propInfo.RespawnTime = anchor.respawnTime;
|
|
}
|
|
|
|
if (anchor.AnchorProp.Mannequins != null && anchor.AnchorProp.IsMannequinsChanged)
|
|
{
|
|
propInfo.Mannequins.AddRange(anchor.AnchorProp.Mannequins);
|
|
}
|
|
propInfo.IsUsable = anchor.PropState == PropState.Activation ? 1 : 0;
|
|
|
|
inSightProps.Add(propInfo);
|
|
}
|
|
});
|
|
|
|
GetCell(cellPos1)?.CallFunc((Player actor) =>
|
|
{
|
|
GameActor gameActor = actor.toGameActor();
|
|
|
|
if (inSightActors.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
inSightActors.Add(gameActor);
|
|
if (inSightPlayers.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
inSightPlayers.Add(actor);
|
|
});
|
|
|
|
GetCell(cellPos1)?.CallFunc((UgcNpc ugcNpc) =>
|
|
{
|
|
var ugc_npc_action = ugcNpc.getEntityAction<UgcNpcAction>();
|
|
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {ugcNpc.toBasicString()}");
|
|
|
|
var ugc_npc_entity = ugc_npc_action.toUgcNpcEntity();
|
|
if (inSightUgcNpcs.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
inSightUgcNpcs.Add(ugc_npc_entity);
|
|
});
|
|
|
|
HostID hostId = GetCell(cellPos1)?._P2PGroup ?? HostID.HostID_None;
|
|
GameServerApp.getServerLogic().getProudNetListener().getNetServer()?.JoinP2PGroup(player.getHostId(), hostId);
|
|
}
|
|
|
|
// PropInSight 를 ActorInSight 보다 먼저 보낸다
|
|
if (inSightProps.Count > 0)
|
|
{
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.PropInSight = new ClientToGameMessage.Types.PropInSight();
|
|
clientToGame.Message.PropInSight.PropList.AddRange(inSightProps);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
if (inSightActors.Count > 0)
|
|
{
|
|
// 내 주변 actor 정보를 나에게 보냄
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.NtfPlayerInSight = new ClientToGameMessage.Types.GS2C_NTF_PLAYER_IN_SIGHT();
|
|
clientToGame.Message.NtfPlayerInSight.ToAddPlayerEntities.AddRange(inSightActors);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
if (inSightUgcNpcs.Count > 0)
|
|
{
|
|
// 내 주변 ugcNpc 정보를 나에게 보냄
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.NtfNpcInSight = new ClientToGameMessage.Types.GS2C_NTF_NPC_IN_SIGHT();
|
|
clientToGame.Message.NtfNpcInSight.ToAddUgcNpcEntities.AddRange(inSightUgcNpcs);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
if (inSightPlayers.Count > 0)
|
|
{
|
|
// 나의 정보를 주변 player들에게 보냄
|
|
global::GameActor gameActor = player.toGameActor();
|
|
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
HostID[] allClients = inSightPlayers.Select(x => x.getHostId()).ToArray();
|
|
|
|
clientToGame.Message.NtfPlayerInSight = new ClientToGameMessage.Types.GS2C_NTF_PLAYER_IN_SIGHT();
|
|
clientToGame.Message.NtfPlayerInSight.ToAddPlayerEntities.Add(gameActor);
|
|
GameServerApp.getServerLogic().onSendPacketToHosts(allClients, ServerCore.ProudNetHelper.compressRmi(), clientToGame);
|
|
}
|
|
|
|
var found_grid = GetGrid(cellPos.GridX, cellPos.GridY);
|
|
if(null == found_grid)
|
|
{
|
|
err_msg = $"Not found Cell !!! : {cellPos.toBasicString()}, {toBasicString()} - {player.toBasicString()}";
|
|
result.setFail(ServerErrorCode.MapGridNotFoundGrid, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
|
|
return result;
|
|
}
|
|
|
|
result = found_grid.tryAddPlayer(cellPos, player);
|
|
if(result.isFail())
|
|
{
|
|
err_msg = $"Failed to tryAddPlayer() : {result.toBasicString()}, {toBasicString()} - {player.toBasicString()}";
|
|
Log.getLogger().error(result.toBasicString());
|
|
|
|
return result;
|
|
}
|
|
|
|
// 카운트 증가
|
|
m_current_player_count.incCount();
|
|
|
|
return result;
|
|
}
|
|
|
|
public Result tryRemovePlayer(Player player)
|
|
{
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
var location_action = player.getEntityAction<LocationAction>();
|
|
NullReferenceCheckHelper.throwIfNull(location_action, () => $"location_action is null !!! - {player.toBasicString()}");
|
|
|
|
var current_pos = location_action.getCurrentPos();
|
|
|
|
CellPos cellPos = GetCellPos(current_pos.X, current_pos.Y);
|
|
var found_grid = GetGrid(cellPos.GridX, cellPos.GridY);
|
|
if (null == found_grid)
|
|
{
|
|
err_msg = $"Not found Cell !!! : {cellPos.toBasicString()}, {toBasicString()} - {player.toBasicString()}";
|
|
result.setFail(ServerErrorCode.MapGridNotFoundGrid, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
|
|
return result;
|
|
}
|
|
|
|
result = found_grid.tryRemovePlayer(cellPos, player);
|
|
if(result.isFail())
|
|
{
|
|
err_msg = $"Failed to tryRemovePlayer() : {result.toBasicString()}, {toBasicString()} - {player.toBasicString()}";
|
|
Log.getLogger().error(result.toBasicString());
|
|
|
|
return result;
|
|
}
|
|
|
|
// 카운트 감소
|
|
m_current_player_count.decCount();
|
|
|
|
List<CellPos> sightCells = GetSightCells(cellPos, District.ALL_DISTRICT);
|
|
|
|
List<string> removeSightActors = new List<string>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
List<Player> removeSightPlayers = new List<Player>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
List<string> removeSightProps = new();
|
|
|
|
List<string> removeSightUgcNpcGuids = new List<string>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
foreach (CellPos cellPos1 in sightCells)
|
|
{
|
|
GetCell(cellPos1)?.CallFunc((Player actor) =>
|
|
{
|
|
if (removeSightActors.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
removeSightActors.Add(actor.getUserGuid());
|
|
if (removeSightPlayers.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
removeSightPlayers.Add(actor);
|
|
});
|
|
|
|
GetCell(cellPos1)?.CallFunc((AnchorInfo anchor) =>
|
|
{
|
|
removeSightProps.Add(anchor.AnchorGuid);
|
|
});
|
|
|
|
GetCell(cellPos1)?.CallFunc((UgcNpc ugcNpc) =>
|
|
{
|
|
if (removeSightUgcNpcGuids.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
removeSightUgcNpcGuids.Add(ugcNpc.getUgcNpcMetaGuid());
|
|
});
|
|
|
|
HostID hostId = GetCell(cellPos1)?._P2PGroup ?? HostID.HostID_None;
|
|
GameServerApp.getServerLogic().getProudNetListener().getNetServer()?.LeaveP2PGroup(player.getHostId(), hostId);
|
|
}
|
|
|
|
if (removeSightActors.Count > 0)
|
|
{
|
|
var clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.NtfPlayerOutOfSight = new ClientToGameMessage.Types.GS2C_NTF_PLAYER_OUT_OF_SIGHT();
|
|
clientToGame.Message.NtfPlayerOutOfSight.ToOutOfPlayerGuids.AddRange(removeSightActors);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
if (removeSightPlayers.Count > 0)
|
|
{
|
|
var clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
HostID[] allClients = removeSightPlayers.Select(x => x.getHostId()).ToArray();
|
|
|
|
clientToGame.Message.NtfPlayerOutOfSight = new ClientToGameMessage.Types.GS2C_NTF_PLAYER_OUT_OF_SIGHT();
|
|
clientToGame.Message.NtfPlayerOutOfSight.ToOutOfPlayerGuids.Add(player.getUserGuid());
|
|
GameServerApp.getServerLogic().onSendPacketToHosts(allClients, ServerCore.ProudNetHelper.compressRmi(), clientToGame);
|
|
}
|
|
|
|
if (removeSightProps.Count > 0)
|
|
{
|
|
var clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.PropOutOfSight = new ClientToGameMessage.Types.PropOutOfSight();
|
|
clientToGame.Message.PropOutOfSight.AnchorGuid.AddRange(removeSightProps);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
if (removeSightUgcNpcGuids.Count > 0)
|
|
{
|
|
var clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.NtfNpcOutOfSight = new ClientToGameMessage.Types.GS2C_NTF_NPC_OUT_OF_SIGHT();
|
|
clientToGame.Message.NtfNpcOutOfSight.ToOutOfEntityInstantGuids.AddRange(removeSightUgcNpcGuids);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 종복위치의 Player를 겹치지 않는 위치로 재조성해줌.
|
|
/// </summary>
|
|
/// <param name="newPos"></param>
|
|
/// <returns></returns>
|
|
public void SetNewPosOverlapLoctionPlayer(Pos newPos)
|
|
{
|
|
int limitCount = 30;
|
|
while (true)
|
|
{
|
|
CellPos newCellPos = GetCellPos(newPos.X, newPos.Y);
|
|
Cell? cell = GetCell(newCellPos);
|
|
if (cell != null)
|
|
{
|
|
bool isOverlep = false;
|
|
cell.CallFunc((Player FuncPlayer) =>
|
|
{
|
|
var location_action = FuncPlayer.getEntityAction<LocationAction>();
|
|
|
|
var current_pos = location_action.getCurrentPos();
|
|
|
|
//if (Math.Sqrt(Math.Pow(FuncPlayer.PositionX - newPos.X, 2) + Math.Pow(FuncPlayer.PositionY - newPos.Y, 2))
|
|
if ( (Math.Abs(current_pos.X - newPos.X) + Math.Abs(current_pos.Y - newPos.Y))
|
|
< ServerCommon.Constant.CHARACTER_RADIUS * 2 )
|
|
{
|
|
isOverlep = true;
|
|
}
|
|
});
|
|
|
|
if (isOverlep == false || limitCount <= 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
newPos.X += (RandomHelper.next(-5, 6) * ServerCommon.Constant.CHARACTER_RADIUS * 2);
|
|
newPos.Y += (RandomHelper.next(-5, 6) * ServerCommon.Constant.CHARACTER_RADIUS * 2);
|
|
--limitCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
public Result tryRelocate(Player player, Pos newPos)
|
|
{
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
var location_action = player.getEntityAction<LocationAction>();
|
|
|
|
var oldPos = location_action.getCurrentPos();
|
|
|
|
CellPos oldCellPos = GetCellPos(oldPos.X, oldPos.Y);
|
|
CellPos newCellPos = GetCellPos(newPos.X, newPos.Y);
|
|
|
|
if (false == IsCellPosOutOfMapRange(newCellPos.CellX, newCellPos.CellY))
|
|
{
|
|
err_msg = $"Invalid CellPos of MapRange !!! : {newCellPos.toBasicString()} - {player.toBasicString()}";
|
|
result.setFail(ServerErrorCode.MapRangeOutOfCellPos, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
|
|
return result;
|
|
}
|
|
|
|
//Log.getLogger().info($"old: {oldCellPos.X}, {oldCellPos.Y}, new: {newCellPos.X}, {newCellPos.Y}");
|
|
|
|
if (oldCellPos != newCellPos)
|
|
{
|
|
var found_curr_grid = GetGrid(oldCellPos.GridX, oldCellPos.GridY);
|
|
if (null == found_curr_grid)
|
|
{
|
|
err_msg = $"Not found current Cell !!! : {oldCellPos.toBasicString()} - {player.toBasicString()}";
|
|
result.setFail(ServerErrorCode.MapGridNotFoundGrid, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
|
|
return result;
|
|
}
|
|
result = found_curr_grid.tryRemovePlayer(oldCellPos, player);
|
|
if(result.isFail())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
var found_to_locate_grid = GetGrid(newCellPos.GridX, newCellPos.GridY);
|
|
if (null == found_to_locate_grid)
|
|
{
|
|
err_msg = $"Not found to locate Cell !!! : {newCellPos.toBasicString()} - {player.toBasicString()}";
|
|
result.setFail(ServerErrorCode.MapGridNotFoundGrid, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
|
|
return result;
|
|
}
|
|
result = found_to_locate_grid.tryAddPlayer(newCellPos, player);
|
|
if (result.isFail())
|
|
{
|
|
return result;
|
|
}
|
|
|
|
(List<CellPos> removeSight, List<CellPos> newSight) = GetSight(oldCellPos, newCellPos);
|
|
|
|
List<string> removeSightActors = new List<string>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
List<Player> removeSightPlayers = new List<Player>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
List<string> removeSightProps = new();
|
|
|
|
List<string> removeSightUgcNpcGuids = new List<string>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
foreach (CellPos cellPos in removeSight)
|
|
{
|
|
GetCell(cellPos)?.CallFunc((Player actor) =>
|
|
{
|
|
if (removeSightActors.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
removeSightActors.Add(actor.getUserGuid());
|
|
if (removeSightPlayers.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
removeSightPlayers.Add(actor);
|
|
});
|
|
|
|
GetCell(cellPos)?.CallFunc((AnchorInfo anchor) =>
|
|
{
|
|
removeSightProps.Add(anchor.AnchorGuid);
|
|
});
|
|
|
|
GetCell(cellPos)?.CallFunc((UgcNpc ugcNpc) =>
|
|
{
|
|
if (removeSightUgcNpcGuids.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
removeSightUgcNpcGuids.Add(ugcNpc.getUgcNpcMetaGuid());
|
|
});
|
|
|
|
HostID hostId = GetCell(cellPos)?._P2PGroup ?? HostID.HostID_None;
|
|
GameServerApp.getServerLogic().getProudNetListener().getNetServer()?.LeaveP2PGroup(player.getHostId(), hostId);
|
|
}
|
|
|
|
if (removeSightActors.Count > 0)
|
|
{
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.NtfPlayerOutOfSight = new ClientToGameMessage.Types.GS2C_NTF_PLAYER_OUT_OF_SIGHT();
|
|
clientToGame.Message.NtfPlayerOutOfSight.ToOutOfPlayerGuids.AddRange(removeSightActors);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
if (removeSightPlayers.Count > 0)
|
|
{
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
HostID[] allClients = removeSightPlayers.Select(x => x.getHostId()).ToArray();
|
|
|
|
clientToGame.Message.NtfPlayerOutOfSight = new ClientToGameMessage.Types.GS2C_NTF_PLAYER_OUT_OF_SIGHT();
|
|
clientToGame.Message.NtfPlayerOutOfSight.ToOutOfPlayerGuids.Add(player.getUserGuid());
|
|
GameServerApp.getServerLogic().onSendPacketToHosts(allClients, ServerCore.ProudNetHelper.compressRmi(), clientToGame);
|
|
}
|
|
|
|
if (removeSightProps.Count > 0)
|
|
{
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.PropOutOfSight = new ClientToGameMessage.Types.PropOutOfSight();
|
|
clientToGame.Message.PropOutOfSight.AnchorGuid.AddRange(removeSightProps);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
if (removeSightUgcNpcGuids.Count > 0)
|
|
{
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.NtfNpcOutOfSight = new ClientToGameMessage.Types.GS2C_NTF_NPC_OUT_OF_SIGHT();
|
|
clientToGame.Message.NtfNpcOutOfSight.ToOutOfEntityInstantGuids.AddRange(removeSightUgcNpcGuids);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
List<global::GameActor> newSightActors = new List<global::GameActor>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
List<Player> newSightPlayers = new List<Player>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
List<PropInfo> inSightProps = new();
|
|
|
|
List<UgcNpcEntity> inSightUgcNpcs = new List<UgcNpcEntity>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
foreach (CellPos cellPos in newSight)
|
|
{
|
|
GetCell(cellPos)?.CallFunc((AnchorInfo anchor) =>
|
|
{
|
|
if ( !string.IsNullOrEmpty(anchor.AnchorProp.GuidByType)
|
|
|| anchor.AnchorProp.IsMannequinsChanged
|
|
|| MapHelper.isRewardProp(anchor.AnchorGuid)
|
|
|| MapHelper.isGroupProp(anchor.AnchorGuid)
|
|
|| MapHelper.isFarmingProp(anchor.AnchorGuid) )
|
|
{
|
|
var propInfo = new PropInfo();
|
|
propInfo.AnchorGuid = anchor.AnchorGuid;
|
|
propInfo.OccupiedActorGuid = anchor.OccupyingUserGuid;
|
|
propInfo.TableId = anchor.AnchorProp.TableId;
|
|
propInfo.ItemGuid = anchor.AnchorProp.GuidByType;
|
|
|
|
if (true == getFarmingEffects().TryGetValue(anchor.AnchorGuid, out var found_farming_effect))
|
|
{
|
|
var farming_effect_attribute = found_farming_effect.getEntityAttribute<FarmingEffectAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(farming_effect_attribute, () => $"farming_effect_attribute is null !!! - AnchorGuid:{anchor.AnchorGuid}, {player.toBasicString()}");
|
|
|
|
propInfo.StartTime = farming_effect_attribute.FarmingStartTime.ToTimestamp();
|
|
propInfo.EndTime = farming_effect_attribute.FarmingEndTime.ToTimestamp();
|
|
propInfo.RespawnTime = anchor.respawnTime;
|
|
}
|
|
|
|
if (anchor.AnchorProp.Mannequins != null && anchor.AnchorProp.IsMannequinsChanged)
|
|
propInfo.Mannequins.AddRange(anchor.AnchorProp.Mannequins);
|
|
|
|
propInfo.IsUsable = anchor.PropState == PropState.Activation ? 1 : 0;
|
|
|
|
inSightProps.Add(propInfo);
|
|
}
|
|
});
|
|
|
|
GetCell(cellPos)?.CallFunc((Player actor) =>
|
|
{
|
|
global::GameActor gameActor = actor.toGameActor();
|
|
if (newSightActors.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
newSightActors.Add(gameActor);
|
|
if (newSightPlayers.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
newSightPlayers.Add(actor);
|
|
});
|
|
|
|
GetCell(cellPos)?.CallFunc((UgcNpc ugcNpc) =>
|
|
{
|
|
var ugc_npc_action = ugcNpc.getEntityAction<UgcNpcAction>();
|
|
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {ugcNpc.toBasicString()}");
|
|
|
|
var ugc_npc_entity = ugc_npc_action.toUgcNpcEntity();
|
|
if (inSightUgcNpcs.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
inSightUgcNpcs.Add(ugc_npc_entity);
|
|
});
|
|
|
|
HostID hostId = GetCell(cellPos)?._P2PGroup ?? HostID.HostID_None;
|
|
GameServerApp.getServerLogic().getProudNetListener().getNetServer()?.JoinP2PGroup(player.getHostId(), hostId);
|
|
}
|
|
|
|
// PropInSight 를 ActorInSight 보다 먼저 보낸다
|
|
if (inSightProps.Count > 0)
|
|
{
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.PropInSight = new ClientToGameMessage.Types.PropInSight();
|
|
clientToGame.Message.PropInSight.PropList.AddRange(inSightProps);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
if (newSightActors.Count > 0)
|
|
{
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.NtfPlayerInSight = new ClientToGameMessage.Types.GS2C_NTF_PLAYER_IN_SIGHT();
|
|
clientToGame.Message.NtfPlayerInSight.ToAddPlayerEntities.AddRange(newSightActors);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
if (inSightUgcNpcs.Count > 0)
|
|
{
|
|
// 내 주변 ugcNpc 정보를 나에게 보냄
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.NtfNpcInSight = new ClientToGameMessage.Types.GS2C_NTF_NPC_IN_SIGHT();
|
|
clientToGame.Message.NtfNpcInSight.ToAddUgcNpcEntities.AddRange(inSightUgcNpcs);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
}
|
|
|
|
if (newSightPlayers.Count > 0)
|
|
{
|
|
global::GameActor gameActor = player.toGameActor();
|
|
gameActor.Pos = newPos;
|
|
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.NtfPlayerInSight = new ClientToGameMessage.Types.GS2C_NTF_PLAYER_IN_SIGHT();
|
|
clientToGame.Message.NtfPlayerInSight.ToAddPlayerEntities.Add(gameActor);
|
|
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
|
|
|
HostID[] allClients = newSightPlayers.Select(x => x.getHostId()).ToArray();
|
|
GameServerApp.getServerLogic().onSendPacketToHosts(allClients, ServerCore.ProudNetHelper.compressRmi(), clientToGame);
|
|
}
|
|
|
|
Log.getLogger().debug($"move cell");
|
|
}
|
|
|
|
// 내 주변 player들에게 내 좌표 변경을 알림
|
|
List<Player> inSightPlayers = new List<Player>();
|
|
List<CellPos> sightCells = GetSightCells(newCellPos, District.ALL_DISTRICT);
|
|
foreach (CellPos cellPos in sightCells)
|
|
{
|
|
GetCell(cellPos)?.CallFunc((Player actor) =>
|
|
{
|
|
inSightPlayers.Add(actor);
|
|
});
|
|
}
|
|
|
|
var account_attribute = player.getOriginEntityAttribute<AccountAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(account_attribute, () => $"AccountAttribute is null !! - player:{player.toBasicString()}");
|
|
|
|
if (inSightPlayers.Count > 0 && account_attribute.AuthAdminLevelType == AuthAdminLevelType.GmSuper) // 봇 일때로 빠꾸어야함
|
|
{
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
clientToGame.Message.MoveActor = new ClientToGameMessage.Types.MoveActor(); // 클라이언트에서 MoveActor는 본인, 봇을 제외한 다른 유저 정보는 무시한다.
|
|
clientToGame.Message.MoveActor.ActorGuid = player.getUserGuid();
|
|
clientToGame.Message.MoveActor.Pos = newPos;
|
|
|
|
HostID[] allClients = inSightPlayers.Select(x => x.getHostId()).ToArray();
|
|
GameServerApp.getServerLogic().onSendPacketToHosts(allClients, ServerCore.ProudNetHelper.compressRmi(), clientToGame);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<Result> tryLocateUgcNpc(UgcNpc toLocateUgcNpc)
|
|
{
|
|
await Task.CompletedTask;
|
|
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
//ENTITY_INSTANCE_GUID를 UGC_NPC_META_GUID 로 사용 한다. - kangms
|
|
var ugc_npc_meta_guid = toLocateUgcNpc.getUgcNpcMetaGuid();
|
|
if (false == m_ugc_npc_entities.TryAdd(ugc_npc_meta_guid, toLocateUgcNpc))
|
|
{
|
|
err_msg = $"Failed to TryAdd() !!!, Already regiestered UgcNpc in GameZone !!! : ugcNpcMetaGuid:{ugc_npc_meta_guid} - {toLocateUgcNpc.toBasicString()}, MapId:{MapMId}";
|
|
result.setFail(ServerErrorCode.UgcNpcAlreadyRegisteredInGameZone, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
|
|
return result;
|
|
}
|
|
|
|
Log.getLogger().debug($"Call tryLocateUgcNpc() : {toLocateUgcNpc.toStateString()} - {toLocateUgcNpc.toBasicString()}, MapId:{MapMId}");
|
|
|
|
await addUgcNpc(toLocateUgcNpc);
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<Result> tryRemoveUgcNpc(UgcNpc toRemoveUgcNpc)
|
|
{
|
|
await Task.CompletedTask;
|
|
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
var ugc_npc_meta_guid = toRemoveUgcNpc.getUgcNpcMetaGuid();
|
|
if (false == m_ugc_npc_entities.Remove(ugc_npc_meta_guid, out _))
|
|
{
|
|
err_msg = $"Failed to Remove() !!!, Not registered UgcNpc in GameZone !!! : ugcNpcMetaGuid:{ugc_npc_meta_guid} - {toRemoveUgcNpc.toBasicString()}, MapId:{MapMId}";
|
|
result.setFail(ServerErrorCode.UgcNpcNotRegisteredInGameZone, err_msg);
|
|
Log.getLogger().error(err_msg);
|
|
|
|
return result;
|
|
}
|
|
|
|
Log.getLogger().debug($"Call tryRemoveUgcNpc() : {toRemoveUgcNpc.toStateString()} - {toRemoveUgcNpc.toBasicString()}, MapId:{MapMId}");
|
|
|
|
await removeUgcNpc(toRemoveUgcNpc);
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task addUgcNpc(UgcNpc ugcNpc)
|
|
{
|
|
var ugc_npc_action = ugcNpc.getEntityAction<UgcNpcAction>();
|
|
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {ugcNpc.toBasicString()}");
|
|
|
|
var current_pos = ugc_npc_action.getCurrentPos();
|
|
|
|
var cell_pos = GetCellPos(current_pos.X, current_pos.Y);
|
|
var sight_cells = GetSightCells(cell_pos, District.ALL_DISTRICT);
|
|
|
|
// Npc를 볼 수 있는 plyaer 목록을 구성 한다.
|
|
var insight_players = new List<Player>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
|
|
foreach (var sight_cell_pos in sight_cells)
|
|
{
|
|
GetCell(sight_cell_pos)?.CallFunc((Player watchable_player) =>
|
|
{
|
|
if (insight_players.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
{
|
|
insight_players.Add(watchable_player);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (insight_players.Count > 0)
|
|
{
|
|
// npc를 볼 수 있는 player 들에게 통지 한다.
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
HostID[] allClients = insight_players.Select(x => x.getHostId()).ToArray();
|
|
|
|
clientToGame.Message.NtfNpcInSight = new ClientToGameMessage.Types.GS2C_NTF_NPC_IN_SIGHT();
|
|
clientToGame.Message.NtfNpcInSight.ToAddUgcNpcEntities.Add(ugc_npc_action.toUgcNpcEntity());
|
|
GameServerApp.getServerLogic().onSendPacketToHosts(allClients, ServerCore.ProudNetHelper.compressRmi(), clientToGame);
|
|
}
|
|
|
|
GetGrid(cell_pos.GridX, cell_pos.GridY)?.addUgcNpc(cell_pos, ugcNpc);
|
|
if(true == ugc_npc_action.isCountingAsAddConnectedUser())
|
|
{
|
|
m_curr_count_as_add_connected_user.incCount();
|
|
if (GameServerApp.getServerLogic().getServerType().toServerType() != ServerType.Channel)
|
|
{
|
|
await InstanceRoomHandler.increaseInstanceRoomScoreForUgcNpc(InstanceRoomHandler.getInstanceRoomIdBaseFromInstanceRoomId(m_room_id), m_room_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
public async Task removeUgcNpc(UgcNpc ugcNpc)
|
|
{
|
|
var ugc_npc_action = ugcNpc.getEntityAction<UgcNpcAction>();
|
|
NullReferenceCheckHelper.throwIfNull(ugc_npc_action, () => $"ugc_npc_action is null !!! - {ugcNpc.toBasicString()}");
|
|
|
|
var current_pos = ugc_npc_action.getCurrentPos();
|
|
|
|
var cell_pos = GetCellPos(current_pos.X, current_pos.Y);
|
|
GetGrid(cell_pos.GridX, cell_pos.GridY)?.removeUgcNpc(cell_pos, ugcNpc);
|
|
if (true == ugc_npc_action.isCountingAsAddConnectedUser())
|
|
{
|
|
m_curr_count_as_add_connected_user.decCount();
|
|
if (GameServerApp.getServerLogic().getServerType().toServerType() != ServerType.Channel)
|
|
{
|
|
await InstanceRoomHandler.decreaseInstanceRoomScoreForUgcNpc(InstanceRoomHandler.getInstanceRoomIdBaseFromInstanceRoomId(m_room_id), m_room_id);
|
|
|
|
if (m_curr_count_as_add_connected_user.getCount() == 0)
|
|
{
|
|
var room = InstanceRoomManager.Instance.getInstanceRoomByRoomId(m_room_id);
|
|
if (null == room) return;
|
|
|
|
if (room.SessionCount == 0)
|
|
{
|
|
await room.destroyRoom();
|
|
InstanceRoomManager.Instance.DestroyRoom(m_room_id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var sight_cells = GetSightCells(cell_pos, District.ALL_DISTRICT);
|
|
var insight_players = new List<Player>(ServerCommon.Constant.SEND_MAX_GRID_USER);
|
|
|
|
foreach (var sight_cell_pos in sight_cells)
|
|
{
|
|
GetCell(sight_cell_pos)?.CallFunc((Player watchable_player) =>
|
|
{
|
|
if (insight_players.Count <= ServerCommon.Constant.SEND_MAX_GRID_USER)
|
|
{
|
|
insight_players.Add(watchable_player);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (insight_players.Count > 0)
|
|
{
|
|
ClientToGame clientToGame = new ClientToGame();
|
|
clientToGame.Message = new ClientToGameMessage();
|
|
|
|
HostID[] allClients = insight_players.Select(x => x.getHostId()).ToArray();
|
|
|
|
clientToGame.Message.NtfNpcOutOfSight = new ClientToGameMessage.Types.GS2C_NTF_NPC_OUT_OF_SIGHT();
|
|
clientToGame.Message.NtfNpcOutOfSight.ToOutOfEntityInstantGuids.Add(ugcNpc.getUgcNpcMetaGuid());
|
|
GameServerApp.getServerLogic().onSendPacketToHosts(allClients, ServerCore.ProudNetHelper.compressRmi(), clientToGame);
|
|
}
|
|
}
|
|
|
|
public UgcNpc? findUgcNpc(UGC_NPC_META_GUID ugcNpcMetaGuid)
|
|
{
|
|
m_ugc_npc_entities.TryGetValue(ugcNpcMetaGuid, out var found_ugc_npc);
|
|
return found_ugc_npc;
|
|
}
|
|
|
|
public async Task<Result> tryLocateFarming(FarmingEffect toLocateFarmingEffect)
|
|
{
|
|
ArgumentNullReferenceCheckHelper.throwIfNull(toLocateFarmingEffect, () => $"toLocateFarmingEffect is null !!!");
|
|
|
|
await Task.CompletedTask;
|
|
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
var anchor_meta_guid = toLocateFarmingEffect.getAnchorMetaGuid();
|
|
if (false == m_farming_effects.TryAdd(anchor_meta_guid, toLocateFarmingEffect))
|
|
{
|
|
err_msg = $"Failed to TryAdd() !!!, Already regiestered FarmingEffect in GameZone !!! : anchorMetaGuid:{anchor_meta_guid} - {toLocateFarmingEffect.toBasicString()}, MapId:{MapMId}";
|
|
result.setFail(ServerErrorCode.FarmingEffectAlreadyRegisteredInGameZone, err_msg);
|
|
Log.getLogger().error(err_msg);
|
|
|
|
return result;
|
|
}
|
|
|
|
var farming_effect_action = toLocateFarmingEffect.getEntityAction<FarmingEffectAction>();
|
|
NullReferenceCheckHelper.throwIfNull(farming_effect_action, () => $"farming_effect_action is null !!!");
|
|
var anchor_info = farming_effect_action.getAnchorInfo();
|
|
NullReferenceCheckHelper.throwIfNull(anchor_info, () => $"anchor_info is null !!!");
|
|
|
|
anchor_info.PropState = PropState.Progress;
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<Result> tryRemoveFarming(FarmingEffect toLocatedFarmingEffect)
|
|
{
|
|
NullReferenceCheckHelper.throwIfNull(toLocatedFarmingEffect, () => $"toLocatedFarmingEffect is null !!!");
|
|
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
var farming_effect_attribute = toLocatedFarmingEffect.getEntityAttribute<FarmingEffectAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(farming_effect_attribute, () => $"farming_effect_attribute is null !!! - {toLocatedFarmingEffect.toBasicString()}");
|
|
|
|
var farming_effect_action = toLocatedFarmingEffect.getEntityAction<FarmingEffectAction>();
|
|
NullReferenceCheckHelper.throwIfNull(farming_effect_action, () => $"farming_effect_action is null !!! - {toLocatedFarmingEffect.toBasicString()}");
|
|
|
|
var curr_anchor_info = farming_effect_action.getAnchorInfo();
|
|
NullReferenceCheckHelper.throwIfNull(curr_anchor_info, () => $"curr_anchor_info is null !!! - {toLocatedFarmingEffect.toBasicString()}");
|
|
NullReferenceCheckHelper.throwIfNull(curr_anchor_info.AnchorProp, () => $"AnchorProp is null !!! - {toLocatedFarmingEffect.toBasicString()}");
|
|
|
|
curr_anchor_info.PropState = farming_effect_attribute.FarmingState.toPropState();
|
|
curr_anchor_info.respawnTime = farming_effect_attribute.FarmingRespawnTime.ToTimestamp();
|
|
|
|
var anchor_meta_guid = toLocatedFarmingEffect.getAnchorMetaGuid();
|
|
err_msg = $"Called tryRemoveFarming() !!! : AnchorState:{curr_anchor_info.PropState}, AnchorRespawnTime:{curr_anchor_info.respawnTime} - FarmingAnchorGuid:{anchor_meta_guid}";
|
|
Log.getLogger().debug(err_msg);
|
|
|
|
if (false == m_farming_effects.TryRemove(anchor_meta_guid, out _))
|
|
{
|
|
err_msg = $"Failed to TryRemove() !!!, Not exist FarmingEffect in GameZone !!! : anchorMetaGuid:{anchor_meta_guid} - {toLocatedFarmingEffect.toBasicString()}, MapId:{MapMId}";
|
|
result.setFail(ServerErrorCode.FarmingEffectNotExistInGameZone, err_msg);
|
|
Log.getLogger().error(err_msg);
|
|
|
|
return result;
|
|
}
|
|
|
|
return await Task.FromResult(result);
|
|
}
|
|
|
|
public AnchorInfo? findAnchorInfo(ANCHOR_META_GUID anchorMetaGuid)
|
|
{
|
|
getAnchors().TryGetValue(anchorMetaGuid, out var found_anchor);
|
|
return found_anchor;
|
|
}
|
|
|
|
public AnchorInfo? getFirstAnchorInfoOfFarming()
|
|
{
|
|
var anchor_infos = getAnchors();
|
|
foreach (var anchor_info in anchor_infos.Values)
|
|
{
|
|
if (MapHelper.isFarmingProp(anchor_info.AnchorGuid))
|
|
return anchor_info;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public LOCATION_UNIQUE_ID getLocationUniqueId()
|
|
{
|
|
return m_location_unique_id;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// LOCATION_UNIQUE_ID : "LocationTargetType#MapMetaId#InstanceNumber"
|
|
//=====================================================================================
|
|
public LOCATION_UNIQUE_ID makeLOCATION_UNIQUE_IDByInstanceNumber(string instanceNumber)
|
|
{
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
var location_target_type = server_logic.getServerType().toLocationTargetType();
|
|
|
|
return $"{location_target_type}#{MapMId}#{instanceNumber}";
|
|
}
|
|
|
|
public LOCATION_UNIQUE_ID makeLOCATION_UNIQUE_IDByMetaId(string metaId)
|
|
{
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
var location_target_type = server_logic.getServerType().toLocationTargetType();
|
|
|
|
return $"{location_target_type}#{metaId}#{0}";
|
|
}
|
|
|
|
public LOCATION_UNIQUE_ID makeLOCATION_UNIQUE_IDByMetaIdWithLocationTargetType(LocationTargetType locationTargetType, string metaId)
|
|
{
|
|
return $"{locationTargetType}#{metaId}#{0}";
|
|
}
|
|
|
|
public void setLocationUniqueId(LOCATION_UNIQUE_ID locationUniqueId)
|
|
{
|
|
m_location_unique_id = locationUniqueId;
|
|
}
|
|
|
|
public static (Result, string[]?) parseLOCATION_UNIQUE_ID(LOCATION_UNIQUE_ID locationUniqueId)
|
|
{
|
|
var result = new Result();
|
|
var err_msg = string.Empty;
|
|
|
|
var location_unique_id_parts = locationUniqueId.Split('#');
|
|
if (location_unique_id_parts.Length != 3)
|
|
{
|
|
err_msg = $"Invalid length of LOCATION_UNIQUE_ID !!! : 3 == length:{location_unique_id_parts.Length}";
|
|
result.setFail(ServerErrorCode.LocationUniqueIdInvalid, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
|
|
return (result, null);
|
|
}
|
|
|
|
return (result, location_unique_id_parts);
|
|
}
|
|
|
|
public static (bool, META_ID) parseMapMetaId(LOCATION_UNIQUE_ID locationUniqueId)
|
|
{
|
|
var location_unique_id_parts = locationUniqueId.Split('#');
|
|
if (location_unique_id_parts.Length == 3)
|
|
{
|
|
location_unique_id_parts[1].toInt32(out var map_meta_id);
|
|
return (true, (META_ID)map_meta_id);
|
|
}
|
|
|
|
return (false, 0);
|
|
}
|
|
|
|
public ConcurrentDictionary<string, AnchorInfo> getAnchors()
|
|
{
|
|
return m_anchors;
|
|
}
|
|
|
|
public ConcurrentDictionary<ANCHOR_META_GUID, FarmingEffect> getFarmingEffects()
|
|
{
|
|
return m_farming_effects;
|
|
}
|
|
|
|
|
|
List<CellPos> GetSightCells(CellPos cellPos, District district)
|
|
{
|
|
var cells = new List<(int, int)>(9);
|
|
|
|
switch (district)
|
|
{
|
|
case District.UPPER_DISTRICT:
|
|
cells.Add((cellPos.CellX - 1, cellPos.CellY - 1));
|
|
cells.Add((cellPos.CellX, cellPos.CellY - 1));
|
|
cells.Add((cellPos.CellX + 1, cellPos.CellY - 1));
|
|
break;
|
|
case District.LOWER_DISTRICT:
|
|
cells.Add((cellPos.CellX - 1, cellPos.CellY + 1));
|
|
cells.Add((cellPos.CellX, cellPos.CellY + 1));
|
|
cells.Add((cellPos.CellX + 1, cellPos.CellY + 1));
|
|
break;
|
|
case District.LEFT_DISTRICT:
|
|
cells.Add((cellPos.CellX - 1, cellPos.CellY - 1));
|
|
cells.Add((cellPos.CellX - 1, cellPos.CellY));
|
|
cells.Add((cellPos.CellX - 1, cellPos.CellY + 1));
|
|
break;
|
|
case District.RIGHT_DISTRICT:
|
|
cells.Add((cellPos.CellX + 1, cellPos.CellY - 1));
|
|
cells.Add((cellPos.CellX + 1, cellPos.CellY));
|
|
cells.Add((cellPos.CellX + 1, cellPos.CellY + 1));
|
|
break;
|
|
case District.CENTER_DISTRICT:
|
|
cells.Add((cellPos.CellX, cellPos.CellY));
|
|
break;
|
|
case District.UPPER_LEFT_DISTRICT:
|
|
cells.Add((cellPos.CellX - 1, cellPos.CellY - 1));
|
|
cells.Add((cellPos.CellX, cellPos.CellY - 1));
|
|
cells.Add((cellPos.CellX - 1, cellPos.CellY));
|
|
break;
|
|
case District.UPPER_RIGHT_DISTRICT:
|
|
cells.Add((cellPos.CellX + 1, cellPos.CellY - 1));
|
|
cells.Add((cellPos.CellX, cellPos.CellY - 1));
|
|
cells.Add((cellPos.CellX + 1, cellPos.CellY));
|
|
break;
|
|
case District.LOWER_LEFT_DISTRICT:
|
|
cells.Add((cellPos.CellX - 1, cellPos.CellY + 1));
|
|
cells.Add((cellPos.CellX, cellPos.CellY + 1));
|
|
cells.Add((cellPos.CellX - 1, cellPos.CellY));
|
|
break;
|
|
case District.LOWER_RIGHT_DISTRICT:
|
|
cells.Add((cellPos.CellX + 1, cellPos.CellY + 1));
|
|
cells.Add((cellPos.CellX, cellPos.CellY + 1));
|
|
cells.Add((cellPos.CellX + 1, cellPos.CellY));
|
|
break;
|
|
case District.ALL_DISTRICT:
|
|
for (int x = cellPos.CellX - 1; x <= cellPos.CellX + 1; x++)
|
|
{
|
|
for (int y = cellPos.CellY - 1; y <= cellPos.CellY + 1; y++)
|
|
{
|
|
cells.Add((x, y));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
List<CellPos> sightCells = new List<CellPos>(9);
|
|
foreach ((int x, int y) in cells)
|
|
{
|
|
if (IsCellPosOutOfMapRange(x, y) == false)
|
|
continue;
|
|
|
|
sightCells.Add(new CellPos(x, y));
|
|
}
|
|
|
|
return sightCells;
|
|
}
|
|
|
|
(List<CellPos> removeSight, List<CellPos> newSight) GetSight(CellPos oldCellPos, CellPos newCellPos)
|
|
{
|
|
int removeDistrict = 0;
|
|
int newDistrict = 0;
|
|
|
|
if (Math.Abs(newCellPos.CellX - oldCellPos.CellX) > 1 || Math.Abs(newCellPos.CellY - oldCellPos.CellY) > 1)
|
|
{
|
|
removeDistrict = (int)District.ALL_DISTRICT;
|
|
newDistrict = (int)District.ALL_DISTRICT;
|
|
}
|
|
else
|
|
{
|
|
if (newCellPos.CellX < oldCellPos.CellX)
|
|
{
|
|
newDistrict |= (int)District.LEFT_DISTRICT;
|
|
removeDistrict |= (int)District.RIGHT_DISTRICT;
|
|
}
|
|
else if (newCellPos.CellX > oldCellPos.CellX)
|
|
{
|
|
newDistrict |= (int)District.RIGHT_DISTRICT;
|
|
removeDistrict |= (int)District.LEFT_DISTRICT;
|
|
}
|
|
|
|
if (newCellPos.CellY < oldCellPos.CellY)
|
|
{
|
|
newDistrict |= (int)District.UPPER_DISTRICT;
|
|
removeDistrict |= (int)District.LOWER_DISTRICT;
|
|
}
|
|
else if (newCellPos.CellY > oldCellPos.CellY)
|
|
{
|
|
newDistrict |= (int)District.LOWER_DISTRICT;
|
|
removeDistrict |= (int)District.UPPER_DISTRICT;
|
|
}
|
|
}
|
|
|
|
List<CellPos> remoeSight = GetSightCells(oldCellPos, (District)removeDistrict);
|
|
List<CellPos> newSight = GetSightCells(newCellPos, (District)newDistrict);
|
|
|
|
return (remoeSight, newSight);
|
|
}
|
|
|
|
public void Broadcast(Player player, ClientToGame message, bool dontSendblockUser = false)
|
|
{
|
|
var location_action = player.getEntityAction<LocationAction>();
|
|
|
|
|
|
var current_pos = location_action.getCurrentPos();
|
|
|
|
CellPos cellPos = GetCellPos(current_pos.X, current_pos.Y);
|
|
List<CellPos> sightCells = GetSightCells(cellPos, District.ALL_DISTRICT);
|
|
List<HostID> hostIDs = new List<HostID>();
|
|
foreach (CellPos cell in sightCells)
|
|
{
|
|
GetCell(cell)?.CallFunc((Player actor) =>
|
|
{
|
|
var user_block_action = actor.getEntityAction<BlockUserAgentAction>();
|
|
NullReferenceCheckHelper.throwIfNull(user_block_action, () => $"user_block_action is null !!!");
|
|
|
|
if (dontSendblockUser == true && user_block_action.isBlockUser(player.getUserGuid())) return;
|
|
hostIDs.Add(actor.getHostId());
|
|
|
|
});
|
|
}
|
|
|
|
HostID[] allClients = hostIDs.ToArray();
|
|
GameServerApp.getServerLogic().onSendPacketToHosts(allClients, ServerCore.ProudNetHelper.compressRmi(), message);
|
|
}
|
|
|
|
public void Broadcast( Pos pos, ClientToGame message, HostID excludeId = 0)
|
|
{
|
|
CellPos cellPos = GetCellPos(pos.X, pos.Y);
|
|
List<CellPos> sightCells = GetSightCells(cellPos, District.ALL_DISTRICT);
|
|
List<HostID> hostIDs = new List<HostID>();
|
|
foreach (CellPos cell in sightCells)
|
|
{
|
|
GetCell(cell)?.CallFunc((Player actor) =>
|
|
{
|
|
if( excludeId != actor.getHostId() )
|
|
{
|
|
hostIDs.Add(actor.getHostId());
|
|
}
|
|
});
|
|
}
|
|
|
|
HostID[] allClients = hostIDs.ToArray();
|
|
GameServerApp.getServerLogic().onSendPacketToHosts(allClients, ServerCore.ProudNetHelper.compressRmi(), message);
|
|
}
|
|
|
|
public void CallSightCells(Player player, Action<Player> action)
|
|
{
|
|
var location_action = player.getEntityAction<LocationAction>();
|
|
|
|
|
|
var current_pos = location_action.getCurrentPos();
|
|
|
|
CellPos cellPos = GetCellPos(current_pos.X, current_pos.Y);
|
|
List<CellPos> sightCells = GetSightCells(cellPos, District.ALL_DISTRICT);
|
|
|
|
foreach (CellPos cell in sightCells)
|
|
{
|
|
GetCell(cell)?.CallFunc(action);
|
|
}
|
|
}
|
|
|
|
Grid? GetGrid(int gridX, int gridY)
|
|
{
|
|
if (gridX < MapRangeGridX.min || gridX > MapRangeGridX.max
|
|
|| gridY < MapRangeGridY.min || gridY > MapRangeGridY.max)
|
|
return null;
|
|
|
|
try
|
|
{
|
|
return Grids[(gridX, gridY)];
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log.getLogger().error($"Execption !!!, Map.GetGrid() : message:{e}, GridX:{gridX}, GridY:{gridY}");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
Cell? GetCell(CellPos cellPos)
|
|
{
|
|
return GetGrid(cellPos.GridX, cellPos.GridY)?.GetCell(cellPos.CellinGridX, cellPos.CellinGridY);
|
|
}
|
|
|
|
public CellPos GetCellPos(float x, float y)
|
|
{
|
|
int cellX = GetCellCoord(x);
|
|
int cellY = GetCellCoord(y);
|
|
|
|
return new CellPos(cellX, cellY);
|
|
}
|
|
|
|
/// <summary>
|
|
/// X or Y 좌표 값을 좌표가 소속된 CellX or CellY 로 바꾼다. <br/>
|
|
/// CELL_SIZE 가 100 일때 -50과 50은 0으로 같은 값이 나온다. <br/>
|
|
/// 구분하기 위하여 음수 일 경우 -1 한다. -50은 -1, 50은 0으로 구분할수 있도록 <br/>
|
|
/// 원 그리드 일 경우 0 리턴
|
|
/// </summary>
|
|
/// <param name="coord">좌표값 X or Y</param>
|
|
/// <returns>좌표가 소속된 CellX or CellY</returns>
|
|
int GetCellCoord(float coord)
|
|
{
|
|
if (IsOneGrid)
|
|
return 0;
|
|
|
|
var cellCoord = (int)((float)coord / CELL_SIZE);
|
|
if (coord < 0) cellCoord--;
|
|
|
|
return cellCoord;
|
|
}
|
|
|
|
/// <summary>
|
|
/// X or Y 좌표 값을 좌표가 소속된 GridX or GridY 로 바꾼다. <br/>
|
|
/// GRID_SIZE 가 100 일때 -50과 50은 0으로 같은 값이 나온다. <br/>
|
|
/// 구분하기 위하여 음수 일 경우 -1 한다. -50은 -1, 50은 0으로 구분할수 있도록 <br/>
|
|
/// 원 그리드 일 경우 0 리턴
|
|
/// </summary>
|
|
/// <param name="coord">좌표값 X or Y</param>
|
|
/// <returns>좌표가 소속된 GridX or GridY</returns>
|
|
int GetGridCoord(float coord)
|
|
{
|
|
if (IsOneGrid)
|
|
return 0;
|
|
|
|
var gridCoord = (int)((float)coord / GRID_SIZE);
|
|
if (coord < 0) gridCoord--;
|
|
|
|
return gridCoord;
|
|
}
|
|
|
|
bool IsCellPosOutOfMapRange(int cellX, int cellY)
|
|
{
|
|
if (cellX < MapRangeCellX.min || MapRangeCellX.max < cellX)
|
|
return false;
|
|
|
|
if (cellY < MapRangeCellY.min || MapRangeCellY.max < cellY)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public void PropModifyNoti(string anchorGuid)
|
|
{
|
|
if (false == getAnchors().TryGetValue(anchorGuid, out var anchorInfo))
|
|
return;
|
|
|
|
ClientToGame clientToGame = new();
|
|
clientToGame.Message = new();
|
|
clientToGame.Message.PropModify = new();
|
|
|
|
var propInfo = new PropInfo();
|
|
propInfo.AnchorGuid = anchorInfo.AnchorGuid;
|
|
propInfo.OccupiedActorGuid = anchorInfo.OccupyingUserGuid;
|
|
propInfo.TableId = anchorInfo.AnchorProp.TableId;
|
|
propInfo.ItemGuid = anchorInfo.AnchorProp.GuidByType;
|
|
|
|
if (true == getFarmingEffects().TryGetValue(anchorGuid, out var found_farming_effect))
|
|
{
|
|
var farming_effect_attribute = found_farming_effect.getEntityAttribute<FarmingEffectAttribute>();
|
|
NullReferenceCheckHelper.throwIfNull(farming_effect_attribute, () => $"farming_effect_attribute is null !!! - AnchorGuid:{anchorInfo.AnchorGuid}");
|
|
|
|
propInfo.StartTime = farming_effect_attribute.FarmingStartTime.ToTimestamp();
|
|
propInfo.EndTime = farming_effect_attribute.FarmingEndTime.ToTimestamp();
|
|
propInfo.RespawnTime = anchorInfo.respawnTime;
|
|
}
|
|
|
|
if (anchorInfo.AnchorProp.Mannequins != null)
|
|
propInfo.Mannequins.AddRange(anchorInfo.AnchorProp.Mannequins);
|
|
|
|
clientToGame.Message.PropModify.PropList.Add(propInfo);
|
|
|
|
Broadcast(anchorInfo.AnchorPos, clientToGame);
|
|
}
|
|
|
|
public void DestroyP2PGroup()
|
|
{
|
|
foreach (var grid in Grids.Values)
|
|
{
|
|
grid.DestroyP2PGroup();
|
|
}
|
|
}
|
|
|
|
public async Task CheckRewardPropRespawn()
|
|
{
|
|
var result = new Result();
|
|
|
|
var server_logic = GameServerApp.getServerLogic();
|
|
|
|
var cancel_token = _cts;
|
|
|
|
while (_cts.IsCancellationRequested == false)
|
|
{
|
|
try
|
|
{
|
|
await Task.Delay(ServerCommon.Constant.FARMING_CHECK_INTERVAL_MSEC, cancel_token.Token);
|
|
|
|
foreach (var anchorInfo in getAnchors().Values)
|
|
{
|
|
await updateAnchorInfo(anchorInfo);
|
|
}
|
|
|
|
m_prop_group_manager.checkRespawnPropGroup(this);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
break;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
var err_msg = $"Exception !!!, CheckRewardPropRespawn() : message:{e}";
|
|
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
}
|
|
}
|
|
}
|
|
|
|
protected async Task updateAnchorInfo(AnchorInfo anchorInfo)
|
|
{
|
|
var result = new Result();
|
|
|
|
try
|
|
{
|
|
using (anchorInfo.getAsyncLock().Lock())
|
|
{
|
|
if (anchorInfo.PropState == PropState.Progress)
|
|
{
|
|
var anchor_guid = anchorInfo.AnchorGuid;
|
|
if (true == getFarmingEffects().TryGetValue(anchor_guid, out var found_farming_effect))
|
|
{
|
|
var farming_effect_action = found_farming_effect.getEntityAction<FarmingEffectAction>();
|
|
NullReferenceCheckHelper.throwIfNull(farming_effect_action, () => $"farming_effect_action is null !!!");
|
|
|
|
result = await farming_effect_action.onUpdateFarming();
|
|
if (result.isFail())
|
|
{
|
|
Log.getLogger().error($"Failed to onUpdateFarming() !!! : {result.toBasicString()}");
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( anchorInfo.PropState == PropState.Respawning
|
|
&& anchorInfo.respawnTime < Timestamp.FromDateTime(DateTime.UtcNow) )
|
|
{
|
|
anchorInfo.PropState = PropState.Activation;
|
|
|
|
ClientToGame clientToGame = new();
|
|
clientToGame.Message = new();
|
|
clientToGame.Message.RewardPropStateNoti = new();
|
|
|
|
clientToGame.Message.RewardPropStateNoti.AnchorGuid = anchorInfo.AnchorGuid;
|
|
clientToGame.Message.RewardPropStateNoti.TableId = anchorInfo.AnchorProp.TableId;
|
|
clientToGame.Message.RewardPropStateNoti.IsUsable = 1;
|
|
|
|
Broadcast(anchorInfo.AnchorPos, clientToGame);
|
|
|
|
getFarmingEffects().TryRemove(anchorInfo.AnchorGuid, out var found_farming_effect);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
var err_msg = $"Exception !!!, CheckRewardPropRespawn() : message:{e}";
|
|
result.setFail(ServerErrorCode.TryCatchException, err_msg);
|
|
Log.getLogger().error(result.toBasicString());
|
|
}
|
|
}
|
|
|
|
public bool getAccountStartPoint([MaybeNullWhen(false)] out Pos accountStartPos)
|
|
{
|
|
accountStartPos = default;
|
|
|
|
if (WorldAccountStartPos.Count < 1)
|
|
return false;
|
|
|
|
int index = AccountStartPosIndex % WorldAccountStartPos.Count;
|
|
Interlocked.Add(ref AccountStartPosIndex, AccountStartPosIndex < WorldAccountStartPos.Count ? 1 : 1 - WorldAccountStartPos.Count);
|
|
accountStartPos = WorldAccountStartPos[index].Clone();
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool GetNearestStartPoint(Pos checkPos, [MaybeNullWhen(false)] out Pos nearestStartPoint)
|
|
{
|
|
int base_cell_x = GetCellCoord(checkPos.X);
|
|
int base_cell_y = GetCellCoord(checkPos.Y);
|
|
|
|
List<Cell> sampleCells = new List<Cell>();
|
|
|
|
var base_cell = GetCell(new CellPos(base_cell_x, base_cell_y));
|
|
if (base_cell != null)
|
|
{
|
|
sampleCells.Add(base_cell);
|
|
}
|
|
|
|
int sample_cell_x_start = base_cell_x;
|
|
int sample_cell_x_end = base_cell_x;
|
|
int sample_cell_y_start = base_cell_y;
|
|
int sample_cell_y_end = base_cell_y;
|
|
|
|
bool is_not_find = true;
|
|
|
|
while(is_not_find)
|
|
{
|
|
sample_cell_x_start--;
|
|
sample_cell_x_end++;
|
|
sample_cell_y_start--;
|
|
sample_cell_y_end++;
|
|
|
|
if (sample_cell_x_start < MapRangeCellX.min)
|
|
sample_cell_x_start = MapRangeCellX.min;
|
|
|
|
if (sample_cell_x_end > MapRangeCellX.max)
|
|
sample_cell_x_end = MapRangeCellX.max;
|
|
|
|
if (sample_cell_y_start < MapRangeCellY.min)
|
|
sample_cell_y_start = MapRangeCellY.min;
|
|
|
|
if (sample_cell_y_end > MapRangeCellY.max)
|
|
sample_cell_y_end = MapRangeCellY.max;
|
|
|
|
if (sample_cell_x_start <= MapRangeCellX.min && sample_cell_x_end >= MapRangeCellX.max && sample_cell_y_start <= MapRangeCellY.min && sample_cell_y_end >= MapRangeCellY.max)
|
|
break;
|
|
|
|
|
|
// ■■■□
|
|
// □ □
|
|
// □ □
|
|
// □□□□
|
|
for (int i = sample_cell_x_start; i < sample_cell_x_end; i++)
|
|
{
|
|
var cell = GetCell(new CellPos(i, sample_cell_y_start));
|
|
if (cell == null)
|
|
continue;
|
|
|
|
sampleCells.Add(cell);
|
|
}
|
|
|
|
// □□□■
|
|
// □ ■
|
|
// □ ■
|
|
// □□□□
|
|
for (int i = sample_cell_y_start; i < sample_cell_y_end; i++)
|
|
{
|
|
var cell = GetCell(new CellPos(sample_cell_x_end, i));
|
|
if (cell == null)
|
|
continue;
|
|
|
|
sampleCells.Add(cell);
|
|
}
|
|
|
|
// □□□□
|
|
// □ □
|
|
// □ □
|
|
// □■■■
|
|
for (int i = sample_cell_x_end; i > sample_cell_x_start; i--)
|
|
{
|
|
var cell = GetCell(new CellPos(i, sample_cell_y_end));
|
|
if (cell == null)
|
|
continue;
|
|
|
|
sampleCells.Add(cell);
|
|
}
|
|
|
|
// □□□□
|
|
// ■ □
|
|
// ■ □
|
|
// ■□□□
|
|
for (int i = sample_cell_y_end; i > sample_cell_y_start; i--)
|
|
{
|
|
var cell = GetCell(new CellPos(sample_cell_x_start, i));
|
|
if (cell == null)
|
|
continue;
|
|
|
|
sampleCells.Add(cell);
|
|
}
|
|
|
|
Pos? nearest_start_point = null;
|
|
double nearest_start_point_distance = -1;
|
|
|
|
foreach(var sampleCell in sampleCells)
|
|
{
|
|
if (!sampleCell.GetNearestStartPoint(checkPos, out var cellNearestPoinstDistance, out var cellNearestStartPoint))
|
|
continue;
|
|
|
|
if (nearest_start_point == null || cellNearestPoinstDistance < nearest_start_point_distance)
|
|
{
|
|
nearest_start_point_distance = cellNearestPoinstDistance;
|
|
nearest_start_point = cellNearestStartPoint;
|
|
}
|
|
}
|
|
|
|
if (nearest_start_point != null)
|
|
{
|
|
nearestStartPoint = nearest_start_point;
|
|
nearestStartPoint.Z += 100;
|
|
return true;
|
|
}
|
|
|
|
sampleCells.Clear();
|
|
}
|
|
|
|
nearestStartPoint = null;
|
|
return false;
|
|
}
|
|
|
|
public CancellationTokenSource getCancellationToken() => _cts;
|
|
|
|
public Int32 getCurrCountAsAddConnectedUser()
|
|
{
|
|
return (Int32)m_curr_count_as_add_connected_user.getCount();
|
|
}
|
|
|
|
public int getCurrentPlayerCount()
|
|
{
|
|
return (int)m_current_player_count.getCount();
|
|
}
|
|
|
|
public string? toBasicString()
|
|
{
|
|
return $"LocationUniqueId:{getLocationUniqueId()}, MapMetaId:{MapMId}, MapFile:{MapFileName}";
|
|
}
|
|
|
|
public HostID getP2PGroupId()
|
|
{
|
|
foreach (var grid in Grids.Values)
|
|
{
|
|
var host_id = grid.getP2PGroupId();
|
|
if (host_id != 0) return host_id;
|
|
}
|
|
|
|
Log.getLogger().error("grid.getP2PGroupId() is zero!!!!");
|
|
return 0;
|
|
}
|
|
}
|