초기커밋
This commit is contained in:
465
GameServer/Map/Grid.cs
Normal file
465
GameServer/Map/Grid.cs
Normal file
@@ -0,0 +1,465 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
|
||||
|
||||
using NeoSmart.AsyncLock;
|
||||
using Nettention.Proud;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
|
||||
|
||||
using ServerCore;
|
||||
using ServerBase;
|
||||
using ServerCommon;
|
||||
using ServerCommon.BusinessLogDomain;
|
||||
using MetaAssets;
|
||||
|
||||
|
||||
using SESSION_ID = System.Int32;
|
||||
using META_ID = System.UInt32;
|
||||
using ENTITY_GUID = System.String;
|
||||
using ANCHOR_GUID = System.String;
|
||||
using USER_GUID = System.String;
|
||||
|
||||
|
||||
|
||||
namespace GameServer;
|
||||
|
||||
/// <summary>
|
||||
/// Map Class 에서 사용
|
||||
/// </summary>
|
||||
public class AnchorInfo
|
||||
{
|
||||
public string AnchorGuid;
|
||||
public Pos AnchorPos;
|
||||
public AnchorProp AnchorProp;
|
||||
public string OccupyingUserGuid = string.Empty;
|
||||
public PropState PropState = PropState.None;
|
||||
public Timestamp respawnTime = new();
|
||||
|
||||
private AsyncLock m_lock = new();
|
||||
|
||||
public AnchorInfo(string anchorGuid, Pos pos, AnchorProp prop)
|
||||
{
|
||||
AnchorGuid = anchorGuid;
|
||||
AnchorPos = pos;
|
||||
AnchorProp = prop;
|
||||
}
|
||||
|
||||
public AsyncLock getAsyncLock() => m_lock;
|
||||
}
|
||||
|
||||
internal class Cell
|
||||
{
|
||||
/// <summary>
|
||||
/// Grid에서 Cell의 X 좌표
|
||||
/// </summary>
|
||||
int _cellinGridX;
|
||||
/// <summary>
|
||||
/// Grid에서 Cell의 Y 좌표
|
||||
/// </summary>
|
||||
int _cellinGridY;
|
||||
|
||||
ConcurrentDictionary<USER_GUID, Player> _players = new ConcurrentDictionary<string, Player>();
|
||||
|
||||
ConcurrentDictionary<ANCHOR_GUID, AnchorInfo> _anchors = new();
|
||||
ConcurrentDictionary<ENTITY_GUID, UgcNpc> _ugc_npcs = new();
|
||||
|
||||
List<AnchorInfo> _startPoints = new();
|
||||
StartPointType m_stat_point_type = StartPointType.None;
|
||||
public HostID _P2PGroup = HostID.HostID_None;
|
||||
|
||||
public Cell(int cellinGridX, int cellinGridY, StartPointType startPointType)
|
||||
{
|
||||
ByteArray byArray = new ByteArray();
|
||||
P2PGroupType p2PGroupType = new P2PGroupType();
|
||||
p2PGroupType.Type = 1;
|
||||
|
||||
ServerBase.ProudNetHelper.convertP2PGroupToByteArray(byArray, p2PGroupType);
|
||||
|
||||
HostID[] arrHostID = new HostID[0];
|
||||
|
||||
_P2PGroup = GameServerApp.getServerLogic().getProudNetListener().getNetServer().CreateP2PGroup(arrHostID, byArray);
|
||||
if (_P2PGroup == HostID.HostID_None)
|
||||
{
|
||||
Log.getLogger().error($"fail CreateP2PGroup");
|
||||
}
|
||||
|
||||
_cellinGridX = cellinGridX;
|
||||
_cellinGridY = cellinGridY;
|
||||
m_stat_point_type = startPointType;
|
||||
}
|
||||
|
||||
public void addPlayer(Player player)
|
||||
{
|
||||
_players.AddOrUpdate(player.getUserGuid(), player, (key, oldValue) => player);
|
||||
SendP2PGroup(player);
|
||||
}
|
||||
|
||||
public bool removePlayer(Player player)
|
||||
{
|
||||
return _players.TryRemove(player.getUserGuid(), out _);
|
||||
}
|
||||
|
||||
public void AddAnchor(AnchorInfo anchor)
|
||||
{
|
||||
_anchors.AddOrUpdate(anchor.AnchorGuid, anchor, (key, oldValue) => anchor);
|
||||
|
||||
if (MapHelper.isStartPoint(anchor.AnchorGuid, m_stat_point_type))
|
||||
{
|
||||
_startPoints.Add(anchor);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveAnchor(AnchorInfo anchor)
|
||||
{
|
||||
_anchors.TryRemove(anchor.AnchorGuid, out _);
|
||||
}
|
||||
|
||||
public void addUgcNpc(UgcNpc ugcNpc)
|
||||
{
|
||||
_ugc_npcs.AddOrUpdate(ugcNpc.getEntityGuid(), ugcNpc, (key, oldValue) => ugcNpc);
|
||||
}
|
||||
|
||||
public bool removeUgcNpc(UgcNpc ugcNpc)
|
||||
{
|
||||
return _ugc_npcs.TryRemove(ugcNpc.getEntityGuid(), out _);
|
||||
}
|
||||
|
||||
public bool GetNearestStartPoint(Pos checkPos, out double nearestPoinstDistance, [MaybeNullWhen(false)] out Pos nearestPoint)
|
||||
{
|
||||
nearestPoinstDistance = -1;
|
||||
Pos? minPos = null;
|
||||
|
||||
foreach (var startPoint in _startPoints)
|
||||
{
|
||||
var distance = Math.Sqrt(Math.Pow(checkPos.X - startPoint.AnchorPos.X, 2) + Math.Pow(checkPos.Y - startPoint.AnchorPos.Y, 2));
|
||||
if (minPos == null || distance < nearestPoinstDistance)
|
||||
{
|
||||
nearestPoinstDistance = distance;
|
||||
minPos = startPoint.AnchorPos.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
if (minPos == null)
|
||||
{
|
||||
nearestPoint = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
nearestPoint = minPos;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Broadcast(ClientToGame message)
|
||||
{
|
||||
HostID[] allClients = _players.Values.Select(x => x.getHostId()).ToArray();
|
||||
|
||||
GameServerApp.getServerLogic().onSendPacketToHosts(allClients, ServerCore.ProudNetHelper.compressRmi(), message);
|
||||
}
|
||||
|
||||
void SendP2PGroup(Player player)
|
||||
{
|
||||
ClientToGame clientToGame = new ClientToGame();
|
||||
clientToGame.Message = new ClientToGameMessage();
|
||||
clientToGame.Message.P2PGroupHostIdNoti = new ClientToGameMessage.Types.P2PGroupHostIdNoti();
|
||||
|
||||
clientToGame.Message.P2PGroupHostIdNoti.P2PGroupHostId = (int)_P2PGroup;
|
||||
|
||||
GameServerApp.getServerLogic().onSendPacket(player, clientToGame);
|
||||
}
|
||||
|
||||
public void CallFunc(Action<Player> action)
|
||||
{
|
||||
foreach (var player in _players.Values)
|
||||
{
|
||||
action(player);
|
||||
}
|
||||
}
|
||||
|
||||
public void CallFunc(Action<UgcNpc> action)
|
||||
{
|
||||
foreach (var ugc_ppc in _ugc_npcs.Values)
|
||||
{
|
||||
action(ugc_ppc);
|
||||
}
|
||||
}
|
||||
|
||||
public void CallFunc(Action<AnchorInfo> action)
|
||||
{
|
||||
foreach (var anchor in _anchors.Values)
|
||||
{
|
||||
action(anchor);
|
||||
}
|
||||
}
|
||||
|
||||
public string toBasicString()
|
||||
{
|
||||
return $"Cell[CellInGridX:{_cellinGridX},CellInGridY:{_cellinGridY}]";
|
||||
}
|
||||
}
|
||||
|
||||
internal class Grid
|
||||
{
|
||||
Cell[,] _cells;
|
||||
/// <summary>
|
||||
/// Map에서 Grid의 X 좌표
|
||||
/// </summary>
|
||||
public int GridX { get; private set; }
|
||||
/// <summary>
|
||||
/// Map에서 Grid의 Y 좌표
|
||||
/// </summary>
|
||||
public int GridY { get; private set; }
|
||||
|
||||
readonly int _maxCellInGrid;
|
||||
|
||||
public Grid(int gridX, int gridY, bool isOneGrid, StartPointType startPointType)
|
||||
{
|
||||
if (isOneGrid)
|
||||
{
|
||||
_cells = new Cell[1, 1];
|
||||
_maxCellInGrid = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cells = new Cell[Map.MAX_CELLS_IN_GRID, Map.MAX_CELLS_IN_GRID];
|
||||
_maxCellInGrid = Map.MAX_CELLS_IN_GRID;
|
||||
}
|
||||
|
||||
GridX = gridX;
|
||||
GridY = gridY;
|
||||
|
||||
for (int cellinGridX = 0; cellinGridX < _cells.GetLength(0); cellinGridX++)
|
||||
{
|
||||
for (int cellinGridY = 0; cellinGridY < _cells.GetLength(1); cellinGridY++)
|
||||
{
|
||||
_cells[cellinGridX, cellinGridY] = new Cell(cellinGridX, cellinGridY, startPointType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Result tryAddPlayer(CellPos cellPos, Player player)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (cellPos.CellinGridX < 0 || cellPos.CellinGridX >= _maxCellInGrid)
|
||||
{
|
||||
err_msg = $"Position Out of Range X Grid Bounds !!! : 0 < {cellPos.CellinGridX} or {cellPos.CellinGridX} < {_maxCellInGrid} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridBoundOutOfRange, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (cellPos.CellinGridY < 0 || cellPos.CellinGridY >= _maxCellInGrid)
|
||||
{
|
||||
err_msg = $"Position Out of Range Y Grid Bounds !!! : 0 < {cellPos.CellinGridY} or {cellPos.CellinGridY} < {_maxCellInGrid} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridBoundOutOfRange, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var found_cell = GetCell(cellPos.CellinGridX, cellPos.CellinGridY);
|
||||
if (null == found_cell)
|
||||
{
|
||||
err_msg = $"Not found Cell !!! : {cellPos.toBasicString()} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridNotFoundCell, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
found_cell.addPlayer(player);
|
||||
|
||||
Log.getLogger().debug($"Player Enter in Cell Grid : {found_cell.toBasicString()}, {cellPos.toBasicString()} - {player.toBasicString()}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Result tryRemovePlayer(CellPos cellPos, Player player)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (cellPos.CellinGridX < 0 || cellPos.CellinGridX >= _maxCellInGrid)
|
||||
{
|
||||
err_msg = $"Position Out of Range X Grid Bounds !!! : 0 < {cellPos.CellinGridX} or {cellPos.CellinGridX} < {_maxCellInGrid} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridBoundOutOfRange, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (cellPos.CellinGridY < 0 || cellPos.CellinGridY >= _maxCellInGrid)
|
||||
{
|
||||
err_msg = $"Position Out of Range Y Grid Bounds !!! : 0 < {cellPos.CellinGridY} or {cellPos.CellinGridY} < {_maxCellInGrid} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridBoundOutOfRange, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var found_cell = GetCell(cellPos.CellinGridX, cellPos.CellinGridY);
|
||||
if(null == found_cell)
|
||||
{
|
||||
err_msg = $"Not found Cell !!! : {cellPos.toBasicString()} - {player.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridNotFoundCell, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if(false == found_cell.removePlayer(player))
|
||||
{
|
||||
err_msg = $"Failed to RemovePlayer in Cell Grid !!! : {cellPos.toBasicString()} - {player.toBasicString()}";
|
||||
Log.getLogger().warn(result.toBasicString());
|
||||
}
|
||||
|
||||
Log.getLogger().debug($"Player Leave in Cell Grid : {found_cell.toBasicString()}, {cellPos.toBasicString()} - {player.toBasicString()}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void AddAnchor(CellPos cellPos, AnchorInfo anchor)
|
||||
{
|
||||
if (cellPos.CellinGridX < 0 || cellPos.CellinGridX >= _maxCellInGrid)
|
||||
return;
|
||||
|
||||
if (cellPos.CellinGridY < 0 || cellPos.CellinGridY >= _maxCellInGrid)
|
||||
return;
|
||||
|
||||
GetCell(cellPos.CellinGridX, cellPos.CellinGridY)?.AddAnchor(anchor);
|
||||
}
|
||||
|
||||
public void RemoveAnchor(CellPos cellPos, AnchorInfo anchor)
|
||||
{
|
||||
if (cellPos.CellinGridX < 0 || cellPos.CellinGridX >= _maxCellInGrid)
|
||||
return;
|
||||
|
||||
if (cellPos.CellinGridY < 0 || cellPos.CellinGridY >= _maxCellInGrid)
|
||||
return;
|
||||
|
||||
GetCell(cellPos.CellinGridX, cellPos.CellinGridY)?.RemoveAnchor(anchor);
|
||||
}
|
||||
|
||||
public Result addUgcNpc(CellPos cellPos, UgcNpc ugcNpc)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (cellPos.CellinGridX < 0 || cellPos.CellinGridX >= _maxCellInGrid)
|
||||
{
|
||||
err_msg = $"Position Out of Range X Grid Bounds !!! : 0 < {cellPos.CellinGridX} or {cellPos.CellinGridX} < {_maxCellInGrid} - {ugcNpc.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridBoundOutOfRange, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (cellPos.CellinGridY < 0 || cellPos.CellinGridY >= _maxCellInGrid)
|
||||
{
|
||||
err_msg = $"Position Out of Range Y Grid Bounds !!! : 0 < {cellPos.CellinGridY} or {cellPos.CellinGridY} < {_maxCellInGrid} - {ugcNpc.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridBoundOutOfRange, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var found_cell = GetCell(cellPos.CellinGridX, cellPos.CellinGridY);
|
||||
if (null == found_cell)
|
||||
{
|
||||
err_msg = $"Not found Cell !!! : {cellPos.toBasicString()} - {ugcNpc.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridNotFoundCell, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
found_cell.addUgcNpc(ugcNpc);
|
||||
|
||||
Log.getLogger().debug($"UgcNpc Enter in Cell Grid : {found_cell.toBasicString()}, {cellPos.toBasicString()} - {ugcNpc.toBasicString()}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Result removeUgcNpc(CellPos cellPos, UgcNpc ugcNpc)
|
||||
{
|
||||
var result = new Result();
|
||||
var err_msg = string.Empty;
|
||||
|
||||
if (cellPos.CellinGridX < 0 || cellPos.CellinGridX >= _maxCellInGrid)
|
||||
{
|
||||
err_msg = $"Position Out of Range X Grid Bounds !!! : 0 < {cellPos.CellinGridX} or {cellPos.CellinGridX} < {_maxCellInGrid} - {ugcNpc.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridBoundOutOfRange, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (cellPos.CellinGridY < 0 || cellPos.CellinGridY >= _maxCellInGrid)
|
||||
{
|
||||
err_msg = $"Position Out of Range Y Grid Bounds !!! : 0 < {cellPos.CellinGridY} or {cellPos.CellinGridY} < {_maxCellInGrid} - {ugcNpc.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridBoundOutOfRange, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var found_cell = GetCell(cellPos.CellinGridX, cellPos.CellinGridY);
|
||||
if (null == found_cell)
|
||||
{
|
||||
err_msg = $"Not found Cell !!! : {cellPos.toBasicString()} - {ugcNpc.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridNotFoundCell, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (false == found_cell.removeUgcNpc(ugcNpc))
|
||||
{
|
||||
err_msg = $"Failed to RemovePlayer in Cell Grid !!! : {cellPos.toBasicString()} - {ugcNpc.toBasicString()}";
|
||||
result.setFail(ServerErrorCode.MapGridCellNotFoundPlayer, err_msg);
|
||||
Log.getLogger().error(result.toBasicString());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Log.getLogger().debug($"UgcNpc Leave in Cell Grid : {found_cell.toBasicString()}, {cellPos.toBasicString()} - {ugcNpc.toBasicString()}");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public Cell? GetCell(int cellinGridX, int cellinGridY)
|
||||
{
|
||||
if (cellinGridX < 0 || cellinGridX >= _maxCellInGrid)
|
||||
return null;
|
||||
|
||||
if (cellinGridY < 0 || cellinGridY >= _maxCellInGrid)
|
||||
return null;
|
||||
|
||||
return _cells[cellinGridX, cellinGridY];
|
||||
}
|
||||
|
||||
public void DestroyP2PGroup()
|
||||
{
|
||||
foreach(var cell in _cells)
|
||||
{
|
||||
GameServerApp.getServerLogic().getProudNetListener().getNetServer()?.DestroyP2PGroup(cell._P2PGroup);
|
||||
}
|
||||
}
|
||||
|
||||
//instance 내 p2p host 설정을 위한 groupId 가져오는 함수
|
||||
public HostID getP2PGroupId()
|
||||
{
|
||||
foreach(var cell in _cells)
|
||||
{
|
||||
return cell._P2PGroup;
|
||||
}
|
||||
|
||||
Log.getLogger().error("cell._P2PGroup is not exist!!!!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user