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
{
///
/// Map에서 Cell의 X 좌표
///
public int CellX { get; private set; }
///
/// Map에서 Cell의 Y 좌표
///
public int CellY { get; private set; }
///
/// Map에서 Grid의 X 좌표
///
public int GridX { get; private set; }
///
/// Map에서 Grid의 Y 좌표
///
public int GridY { get; private set; }
///
/// Grid에서 Cell의 X 좌표
///
public int CellinGridX { get; private set; }
///
/// Grid에서 Cell의 Y 좌표
///
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));
}
///
/// CellX 가 -MAX_CELLS_IN_GRID, ,,, -4, -3, -2, -1 인 경우
/// MAX_CELLS_IN_GRID 로 나누면 -MAX_CELLS_IN_GRID 는 -1 이 나오고 나머지 값들은 0이 나온다.
/// 해당 값은 모두 -1이 되어야 한다. (0은 CellX 가 0, 1, 2, 3 ,,, MAX_CELLS_IN_GRID 인 경우에 쓰인다.)
/// CellX에서 1 빼고 MAX_CELLS_IN_GRID 로 나눌 경우
/// 모든 값이 0이 나오고 여기서 -1을 하면 모두 -1이 된다.
///
/// 좌표가 소속된 CellX or CellY
/// 좌표가 소속된 GridX or GridY
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);
}
}
///
/// CellX 가 -MAX_CELLS_IN_GRID, ,,, -4, -3, -2, -1 인 경우
/// MAX_CELLS_IN_GRID 로 나눈 나머지가 0, -MAX_CELLS_IN_GRID+1, ,,, -3, -2, -1 로 나온다
/// 0, 1, 2, ,,, MAX_CELLS_IN_GRID-1 로 나오도록 나머지가 음수일 경우 MAX_CELLS_IN_GRID 를 더해준다.
///
/// 좌표가 소속된 CellX or CellY
/// 좌표가 소속된 CellinGridX or CellinGridY
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;
///
/// Map의 X 좌표 최소값, 최대값
///
(int min, int max) MapRangeX;
///
/// Map의 Y 좌표 최소값, 최대값
///
(int min, int max) MapRangeY;
///
/// Map의 CellX 좌표 최소값, 최대값
///
(int min, int max) MapRangeCellX;
///
/// Map의 CellY 좌표 최소값, 최대값
///
(int min, int max) MapRangeCellY;
///
/// Map의 GridX 좌표 최소값, 최대값
///
(int min, int max) MapRangeGridX;
///
/// Map의 GridY 좌표 최소값, 최대값
///
(int min, int max) MapRangeGridY;
///
/// (GridX, GridY)가 키 값임
///
Dictionary<(int, int), Grid> Grids = new Dictionary<(int, int), Grid>();
PropGroupManager m_prop_group_manager = new();
public ConcurrentDictionary m_anchors = new();
public List WorldAccountStartPos = new();
//ENTITY_INSTANCE_GUID는 UGC_NPC_META_GUID와 동일하다 !!!
private ConcurrentDictionary m_ugc_npc_entities = new();
// 진행중인 파밍 목록
private ConcurrentDictionary 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 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 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();
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();
var current_pos = location_action.getCurrentPos();
if (isLogin)
{
SetNewPosOverlapLoctionPlayer(current_pos);
}
CellPos cellPos = GetCellPos(current_pos.X, current_pos.Y);
List sightCells = GetSightCells(cellPos, District.ALL_DISTRICT);
List inSightActors = new List(ServerCommon.Constant.SEND_MAX_GRID_USER);
List inSightPlayers = new List(ServerCommon.Constant.SEND_MAX_GRID_USER);
List inSightProps = new();
List inSightUgcNpcs = new List(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();
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();
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();
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 sightCells = GetSightCells(cellPos, District.ALL_DISTRICT);
List removeSightActors = new List(ServerCommon.Constant.SEND_MAX_GRID_USER);
List removeSightPlayers = new List(ServerCommon.Constant.SEND_MAX_GRID_USER);
List removeSightProps = new();
List removeSightUgcNpcGuids = new List(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;
}
///
/// 종복위치의 Player를 겹치지 않는 위치로 재조성해줌.
///
///
///
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();
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();
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 removeSight, List newSight) = GetSight(oldCellPos, newCellPos);
List removeSightActors = new List(ServerCommon.Constant.SEND_MAX_GRID_USER);
List removeSightPlayers = new List(ServerCommon.Constant.SEND_MAX_GRID_USER);
List removeSightProps = new();
List removeSightUgcNpcGuids = new List(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 newSightActors = new List(ServerCommon.Constant.SEND_MAX_GRID_USER);
List newSightPlayers = new List(ServerCommon.Constant.SEND_MAX_GRID_USER);
List inSightProps = new();
List inSightUgcNpcs = new List(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();
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();
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 inSightPlayers = new List();
List sightCells = GetSightCells(newCellPos, District.ALL_DISTRICT);
foreach (CellPos cellPos in sightCells)
{
GetCell(cellPos)?.CallFunc((Player actor) =>
{
inSightPlayers.Add(actor);
});
}
var account_attribute = player.getOriginEntityAttribute();
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 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 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();
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(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();
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(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 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();
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 tryRemoveFarming(FarmingEffect toLocatedFarmingEffect)
{
NullReferenceCheckHelper.throwIfNull(toLocatedFarmingEffect, () => $"toLocatedFarmingEffect is null !!!");
var result = new Result();
var err_msg = string.Empty;
var farming_effect_attribute = toLocatedFarmingEffect.getEntityAttribute();
NullReferenceCheckHelper.throwIfNull(farming_effect_attribute, () => $"farming_effect_attribute is null !!! - {toLocatedFarmingEffect.toBasicString()}");
var farming_effect_action = toLocatedFarmingEffect.getEntityAction();
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 getAnchors()
{
return m_anchors;
}
public ConcurrentDictionary getFarmingEffects()
{
return m_farming_effects;
}
List 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 sightCells = new List(9);
foreach ((int x, int y) in cells)
{
if (IsCellPosOutOfMapRange(x, y) == false)
continue;
sightCells.Add(new CellPos(x, y));
}
return sightCells;
}
(List removeSight, List 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 remoeSight = GetSightCells(oldCellPos, (District)removeDistrict);
List newSight = GetSightCells(newCellPos, (District)newDistrict);
return (remoeSight, newSight);
}
public void Broadcast(Player player, ClientToGame message, bool dontSendblockUser = false)
{
var location_action = player.getEntityAction();
var current_pos = location_action.getCurrentPos();
CellPos cellPos = GetCellPos(current_pos.X, current_pos.Y);
List sightCells = GetSightCells(cellPos, District.ALL_DISTRICT);
List hostIDs = new List();
foreach (CellPos cell in sightCells)
{
GetCell(cell)?.CallFunc((Player actor) =>
{
var user_block_action = actor.getEntityAction();
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 sightCells = GetSightCells(cellPos, District.ALL_DISTRICT);
List hostIDs = new List();
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 action)
{
var location_action = player.getEntityAction();
var current_pos = location_action.getCurrentPos();
CellPos cellPos = GetCellPos(current_pos.X, current_pos.Y);
List 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);
}
///
/// X or Y 좌표 값을 좌표가 소속된 CellX or CellY 로 바꾼다.
/// CELL_SIZE 가 100 일때 -50과 50은 0으로 같은 값이 나온다.
/// 구분하기 위하여 음수 일 경우 -1 한다. -50은 -1, 50은 0으로 구분할수 있도록
/// 원 그리드 일 경우 0 리턴
///
/// 좌표값 X or Y
/// 좌표가 소속된 CellX or CellY
int GetCellCoord(float coord)
{
if (IsOneGrid)
return 0;
var cellCoord = (int)((float)coord / CELL_SIZE);
if (coord < 0) cellCoord--;
return cellCoord;
}
///
/// X or Y 좌표 값을 좌표가 소속된 GridX or GridY 로 바꾼다.
/// GRID_SIZE 가 100 일때 -50과 50은 0으로 같은 값이 나온다.
/// 구분하기 위하여 음수 일 경우 -1 한다. -50은 -1, 50은 0으로 구분할수 있도록
/// 원 그리드 일 경우 0 리턴
///
/// 좌표값 X or Y
/// 좌표가 소속된 GridX or GridY
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();
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();
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 sampleCells = new List| ();
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;
}
}
| |