Files
caliverse_server/GameServer/Map/Helper/MapHelper.cs
2025-05-01 07:20:41 +09:00

664 lines
22 KiB
C#

using System.Numerics;
using System.Diagnostics.CodeAnalysis;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
namespace GameServer;
public static class MapHelper
{
public static bool isStartPoint(string anchorGuid, StartPointType startPointType)
{
if (!MapManager.Instance.getParentMapFileName(anchorGuid, out var parentMapFileName))
return false;
if (!MapDataTable.Instance.getMapData(parentMapFileName, out var mapData))
return false;
if (!MapDataTable.Instance.getAnchor(anchorGuid, out var anchor))
return false;
if (anchor.Type != "AT_StartPos")
return false;
switch (startPointType)
{
case StartPointType.WorldAccountStartPoint:
{
if (mapData.MapFileType != MapFileType.World)
return false;
if (!anchor.EditorName.Contains("AccountStartPos"))
return false;
}
break;
case StartPointType.WorldContinuedStartPoint:
{
if (mapData.MapFileType != MapFileType.World)
return false;
if (!anchor.EditorName.Contains("ContinuedStartPos"))
return false;
}
break;
case StartPointType.LandStartPoint:
{
if (mapData.MapFileType != MapFileType.Land)
return false;
}
break;
case StartPointType.BuildingStartPoint:
{
if (mapData.MapFileType != MapFileType.Building)
return false;
}
break;
default:
return false;
}
return true;
}
public static MapFileType getMapFileType(string mapFileName)
{
MapFileType return_value = MapFileType.None;
switch (Path.GetExtension(mapFileName))
{
case ".zone":
return_value = MapFileType.World;
break;
case ".land":
return_value = MapFileType.Land;
break;
case ".build":
return_value = MapFileType.Building;
break;
case ".room":
return_value = MapFileType.Instance;
break;
}
return return_value;
}
public static bool isUsableAnchorInMapFileType(string anchorGuid, MapFileType mapFileType)
{
if (false == MapDataTable.Instance.getAnchor(anchorGuid, out var anchor))
{
var err_msg = $"Not found Anchor in MapFileType !!! : anchourGuid:{anchorGuid} - MapFileType:{mapFileType}";
Log.getLogger(err_msg);
return false;
}
return anchor.isUsableAnchorInMapFileType(mapFileType);
}
public static bool isUsableAnchorInMapFileType(this Anchor anchor, MapFileType mapFileType)
{
if (true == anchor.isFarmingProp())
{
if (MapFileType.Instance == mapFileType || MapFileType.World == mapFileType)
{
return true;
}
var err_msg = $"Not usable in MapFileType !!! : anchorType:{anchor.Type}, anchourGuid:{anchor.GUID} - MapFileType:{mapFileType}";
Log.getLogger(err_msg);
return false;
}
return true;
}
public static bool isRewardProp(string anchorGuid)
{
if (!MapDataTable.Instance.getAnchor(anchorGuid, out var anchor))
return false;
return anchor.isRewardProp();
}
public static bool isRewardProp(this Anchor anchor)
{
return isAnchorTypeRewardPorp(anchor.Type);
}
public static bool isRewardProp(this UgcAnchorInfo anchor)
{
return isAnchorTypeRewardPorp(anchor.AnchorType);
}
static bool isAnchorTypeRewardPorp(string anchorType)
{
return (anchorType == "AT_TreasureBox");
}
public static bool isFarmingProp(string anchorGuid)
{
if (!MapDataTable.Instance.getAnchor(anchorGuid, out var anchor))
return false;
return anchor.isFarmingProp();
}
public static bool isFarmingProp(this Anchor anchor)
{
return isAnchorTypeFarming(anchor.Type);
}
static bool isAnchorTypeFarming(string anchorType)
{
return (anchorType == "AT_Farming");
}
public static bool isGroupProp(string anchorGuid)
{
if (!MapDataTable.Instance.getAnchor(anchorGuid, out var anchor))
return false;
return anchor.isGroupProp();
}
public static bool isGroupProp(this Anchor anchor)
{
return isAnchorTypeGroupProp(anchor.Type);
}
public static bool isGroupProp(this UgcAnchorInfo anchor)
{
return isAnchorTypeGroupProp(anchor.AnchorType);
}
static bool isAnchorTypeGroupProp(string anchorType)
{
return (anchorType == "AT_TreasureGroupBox");
}
public static bool isNpcProp(string anchorGuid)
{
if (!MapDataTable.Instance.getAnchor(anchorGuid, out var anchor))
return false;
return anchor.isNpcProp();
}
public static bool isNpcProp(this Anchor anchor)
{
return isAnchorTypeNpcProp(anchor.Type);
}
public static bool isNpcProp(this UgcAnchorInfo anchor)
{
return isAnchorTypeNpcProp(anchor.AnchorType);
}
static bool isAnchorTypeNpcProp(string anchorType)
{
return (anchorType == "AT_Npc");
}
public static bool isProp(this UgcAnchorInfo anchor)
{
return isAnchorTypeProp(anchor.AnchorType);
}
static bool isAnchorTypeProp(string anchorType)
{
return (anchorType == "AT_Prop");
}
public static bool isCrafterProp(this UgcAnchorInfo anchor)
{
var err_msg = string.Empty;
if (!isAnchorTypeProp(anchor.AnchorType))
return false;
if (!MetaData.Instance._InteriorMetaTable.TryGetValue(anchor.TableId, out var interior_meta_data))
{
err_msg = $"Failed to TryGetValue() !!! : interiorMetaId:{anchor.TableId}";
Log.getLogger().error(err_msg);
return false;
}
if (!MetaData.Instance._ItemTable.TryGetValue(anchor.TableId, out var item_meta_data))
{
err_msg = $"Failed to TryGetValue() !!! : itemMetaId:{anchor.TableId}";
Log.getLogger().error(err_msg);
return false;
}
return item_meta_data.isCrafterItem();
}
public static (Result, RoomMapTree?, AddressBusinessLog?) tryGetRoomMapTree(int landMetaId, int floor, int buildingMetaId = 0)
{
var result = new Result();
var err_msg = string.Empty;
if (!MapManager.Instance.GetLandMapTree(landMetaId, out var landMapTree))
{
err_msg = $"Failed to GetLandMapTree() !!! : LandMetaId:{landMetaId}";
result.setFail(ServerErrorCode.LandMapTreeDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null);
}
var buildingMapTree = landMapTree.ChildBuildingMapTree;
if (buildingMapTree == null)
{
err_msg = $"Not Exist LandMapTree ChildBuilding !!! : LandMap:{landMapTree.LandMapFileName}";
result.setFail(ServerErrorCode.LandMapTreeChildBuildingNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null);
}
if (buildingMetaId != 0 && buildingMetaId != buildingMapTree.BuildingMetaId)
{
err_msg = $"Not Match LandMap ChildBuilding !!! : ChildBuildingMetaId:{buildingMapTree.BuildingMetaId}, inputBuildingMetaId:{buildingMetaId}";
result.setFail(ServerErrorCode.LandMapTreeChildBuildingNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null);
}
if (!buildingMapTree.ChildRoomMapTrees.TryGetValue(floor, out var roomMapTree))
{
err_msg = $"Failed to BuildingMapTree.ChildRoomMaps.TryGetValue() !!! : BuildingMap:{buildingMapTree.BuildingMapFileName}, floor:{floor}";
result.setFail(ServerErrorCode.WorldMapTreeChildLandNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null, null);
}
var world_meta_id = landMapTree.ParentWorldMapTree.WorldMetaId;
var building_meta_id = buildingMetaId == 0 ? buildingMapTree.BuildingMetaId : buildingMetaId;
var instance_meta_id = roomMapTree.InstanceMetaId;
var myhome_guid = roomMapTree.MyhomeGuid;
var owner_guid = roomMapTree.OwnerGuid;
var address_log_info = AddressBusinessLogHelper.toAddressLogInfo(world_meta_id, landMetaId, building_meta_id, floor, instance_meta_id, myhome_guid, owner_guid);
var address_business_log = new AddressBusinessLog(address_log_info);
return (result, roomMapTree, address_business_log);
}
public static Pos getWarpPos(ContentsType contentsType)
{
return getWarpPos(contentsType.toPlaceType());
}
public static Pos getWarpPos(EPlaceType placeType)
{
var warp_pos = new Pos();
switch (placeType)
{
case EPlaceType.MyHome:
warp_pos = getWarpPos(WarpType.MYHOME);
break;
case EPlaceType.DressRoom:
warp_pos = getWarpPos(WarpType.FITTINGROOM);
break;
case EPlaceType.EditRoom:
warp_pos = getWarpPos(WarpType.EDITROOM);
break;
default:
break;
}
return warp_pos;
}
public static Pos getWarpPos(WarpType warpType)
{
var warp_pos = new Pos();
switch (warpType)
{
case WarpType.MYHOME:
{
if (MetaData.Instance._WarpTable.TryGetValue(ServerCommon.Constant.MYHOME_WARP_ID, out var warpData))
{
warp_pos.X = warpData.PositionX;
warp_pos.Y = warpData.PositionY;
warp_pos.Z = warpData.PositionZ;
}
}
break;
case WarpType.FITTINGROOM:
{
if (MetaData.Instance._WarpTable.TryGetValue(ServerCommon.Constant.DRESSROOM_WARP_ID, out var warpData))
{
warp_pos.X = warpData.PositionX;
warp_pos.Y = warpData.PositionY;
warp_pos.Z = warpData.PositionZ;
}
}
break;
case WarpType.EDITROOM:
{
if (MetaData.Instance._WarpTable.TryGetValue(ServerCommon.Constant.EDITROOM_WARP_ID, out var warpData))
{
warp_pos.X = warpData.PositionX;
warp_pos.Y = warpData.PositionY;
warp_pos.Z = warpData.PositionZ;
}
}
break;
default:
break;
}
return warp_pos;
}
public static Pos getMyhomeStartPos(Position myhomeStartPosAnchorPosition)
{
var myhome_start_pos_anchor_pos = myhomeStartPosAnchorPosition.toPos();
var myhome_warp_pos = getWarpPos(ContentsType.MyHome);
var myhome_start_pos = new Pos();
myhome_start_pos.X = myhome_warp_pos.X + myhome_start_pos_anchor_pos.X;
myhome_start_pos.Y = myhome_warp_pos.Y + myhome_start_pos_anchor_pos.Y;
myhome_start_pos.Z = myhome_warp_pos.Z + myhome_start_pos_anchor_pos.Z;
return myhome_start_pos;
}
public static Pos getWorldPosFromMyhomeRelativePos(Pos myhomeRelativePos)
{
var myhome_warp_pos = getWarpPos(ContentsType.MyHome);
var world_pos = new Pos();
world_pos.X = myhome_warp_pos.X + myhomeRelativePos.X;
world_pos.Y = myhome_warp_pos.Y + myhomeRelativePos.Y;
world_pos.Z = myhome_warp_pos.Z + myhomeRelativePos.Z;
return world_pos;
}
public static Pos getWorldPosFromMyhomeRelativePos(Coordinate myhomeRelativePos)
{
var myhome_relative_pos = new Pos
{
X = myhomeRelativePos.X,
Y = myhomeRelativePos.Y,
Z = myhomeRelativePos.Z,
};
return getWorldPosFromMyhomeRelativePos(myhome_relative_pos);
}
public static (Result, Pos) getWorldPosFromRoomRelativePos(RoomMapTree roomMapTree, Pos roomRelativePos)
{
var result = new Result();
var err_msg = string.Empty;
var world_pos = new Pos();
var building_map_tree = roomMapTree.ParentBuildingMapTree;
var land_map_tree = building_map_tree.ParentLandMapTree;
var room_map_file_name = roomMapTree.RoomMapFileName;
var building_map_file_name = building_map_tree.BuildingMapFileName;
var land_map_file_name = land_map_tree.LandMapFileName;
if (!MapDataTable.Instance.getMapData(land_map_file_name, out var land_map_data))
{
err_msg = $"Not Exist MapData !!! : fileName:{land_map_file_name}";
result.setFail(ServerErrorCode.LandMapDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, world_pos);
}
Position? building_position = null;
foreach (var building_data in land_map_data.BuildingDatas)
{
var building_file_name = Path.GetFileName(building_data.BuildingName);
if (building_file_name == building_map_file_name)
{
building_position = building_data.Position;
break;
}
}
if (building_position == null)
{
err_msg = $"Not Found Building Position !!! : landFileName:{land_map_file_name}, buildingFileName:{building_map_file_name}";
result.setFail(ServerErrorCode.BuildingMapDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, world_pos);
}
if (!MapDataTable.Instance.getMapData(building_map_file_name, out var building_map_data))
{
err_msg = $"Not Exist MapData !!! : fileName:{building_map_file_name} or CHECK BuildingData.xlsx";
result.setFail(ServerErrorCode.BuildingMapDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, world_pos);
}
Position? room_position = null;
foreach (var room_data in building_map_data.RoomDatas)
{
var room_file_name = Path.GetFileName(room_data.RoomName);
if (room_file_name == room_map_file_name)
{
room_position = room_data.Position;
break;
}
}
if (room_position == null)
{
err_msg = $"Not Found Building Position !!! : buildingFileName:{building_map_file_name}, roomFileName:{room_map_file_name}";
result.setFail(ServerErrorCode.RoomMapDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, world_pos);
}
if (!MapDataTable.Instance.getMapData(room_map_file_name, out var room_map_data))
{
err_msg = $"Not Exist MapData !!! : fileName:{room_map_file_name} or CHECK InstanceData.xlsx";
result.setFail(ServerErrorCode.RoomMapDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, world_pos);
}
var world_position = roomRelativePos.toPosition();
world_position = TransformHelper.rotate(world_position, room_map_data.Rotation);
world_position.X += room_position.X;
world_position.Y += room_position.Y;
world_position.Z += room_position.Z;
world_position = TransformHelper.rotate(world_position, building_map_data.Rotation);
world_position.X += building_position.X;
world_position.Y += building_position.Y;
world_position.Z += building_position.Z;
world_position = TransformHelper.rotate(world_position, land_map_data.Rotation);
world_position.X += land_map_data.Position.X;
world_position.Y += land_map_data.Position.Y;
world_position.Z += land_map_data.Position.Z;
world_pos = world_position.toPos();
return (result, world_pos);
}
public static Position toPosition(this Pos pos)
{
var position = new Position
{
X = pos.X,
Y = pos.Y,
Z = pos.Z
};
return position;
}
public static Pos toPos(this Position position)
{
Pos pos = new()
{
X = (float)position.X,
Y = (float)position.Y,
Z = (float)position.Z
};
return pos;
}
public static (Result, Map?) getCurrMapOfMaster(this EntityBase owner)
{
var result = new Result();
var err_msg = string.Empty;
var master = owner.onGetMasterEntity();
if (null == master)
{
err_msg = $"Not found Master !!! - {owner.toBasicString()}";
result.setFail(ServerErrorCode.MasterNotFound, err_msg);
return (result, null);
}
var master_game_zone_action = master.getEntityAction<GameZoneAction>();
NullReferenceCheckHelper.throwIfNull(master_game_zone_action, () => $"master_game_zone_action is null !!! - {owner.toBasicString()}");
var curr_map = master_game_zone_action.getLinkedToMap();
if (null == curr_map)
{
err_msg = $"Not found Map !!! - {owner.toBasicString()}";
result.setFail(ServerErrorCode.MapIsNull, err_msg);
return (result, null);
}
return (result, curr_map);
}
public static bool getAnchor(string anchorGuid, [MaybeNullWhen(false)] out Anchor anchor)
{
anchor = null;
if (false == MapDataTable.Instance.getAnchor(anchorGuid, out var found_anchor))
{
return false;
}
anchor = found_anchor;
return true;
}
public static ModifyFloorLinkedInfo makeModifyFloorLinkedInfo(ModifyType modifyType, int landMetaId, int buildingMetaId, int floor, List<string> ugcNpcGuids)
{
var modify_floor_linked_info = new ModifyFloorLinkedInfo();
modify_floor_linked_info.ModifyType = modifyType;
modify_floor_linked_info.LandId = landMetaId;
modify_floor_linked_info.BuildingId = buildingMetaId;
modify_floor_linked_info.Floor = floor;
modify_floor_linked_info.FloorLinkedInfo = new FloorLinkedInfo();
modify_floor_linked_info.FloorLinkedInfo.UgcNpcGuids.AddRange(ugcNpcGuids);
return modify_floor_linked_info;
}
public static RoomMapTree makeRoomMapTree(BuildingMapTree buildingMapTree, int instanceMetaId, RentFloorRequestInfo rentFloorRequestInfo, List<string> ugcNpcGuids)
{
var room_map_tree = new RoomMapTree(instanceMetaId, rentFloorRequestInfo.MyhomeGuid, buildingMapTree);
room_map_tree.OwnerGuid = rentFloorRequestInfo.OwnerGuid;
room_map_tree.MyhomeGuid = rentFloorRequestInfo.MyhomeGuid;
room_map_tree.InstanceName = rentFloorRequestInfo.InstanceName;
room_map_tree.ThumbnailImageId = rentFloorRequestInfo.ThumbnailImageId;
room_map_tree.ListImageId = rentFloorRequestInfo.ListImageId;
room_map_tree.EnterPlayerCount = rentFloorRequestInfo.EnterPlayerCount;
room_map_tree.UgcNpcs.AddRange(ugcNpcGuids);
return room_map_tree;
}
//=========================================================================================
// X축,Y축,Z축에 대한 회전을 순차적으로 적용하는 함수 - kangms
//=========================================================================================
public static Vector3 applyRotation(System.Numerics.Vector3 vector, System.Numerics.Vector3 rotation)
{
// X축 회전
Quaternion rotationX = Quaternion.CreateFromAxisAngle(Vector3.UnitX, MathF.PI / 180 * rotation.X);
vector = Vector3.Transform(vector, rotationX);
// Y축 회전
Quaternion rotationY = Quaternion.CreateFromAxisAngle(Vector3.UnitY, MathF.PI / 180 * rotation.Y);
vector = Vector3.Transform(vector, rotationY);
// Z축 회전
Quaternion rotationZ = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, MathF.PI / 180 * rotation.Z);
vector = Vector3.Transform(vector, rotationZ);
return vector;
}
//=========================================================================================
// X축,Y축,Z축에 대한 회전을 순차적으로 적용하는 함수 - kangms
//=========================================================================================
public static Vector3 applyRotationFromYawPitchRoll(System.Numerics.Vector3 vector, float yaw, float pitch, float roll)
{
float yaw_rad = yaw * MathHelper.Deg2Rad;
float pitch_rad = pitch * MathHelper.Deg2Rad;
float roll_rad = roll * MathHelper.Deg2Rad;
Quaternion rotation = Quaternion.CreateFromYawPitchRoll(yaw_rad, pitch_rad, roll_rad);
vector = Vector3.Transform(vector, rotation);
return vector;
}
//=========================================================================================
// Z축 회전된 벡터를 각도로 반환 해주는 함수 - kangms
//=========================================================================================
public static float getZRotationAngle(Vector3 vector)
{
// atan2 함수 사용하여 Z축 회전 각도 계산 (라디안 -> 도)
float angleInRadians = MathF.Atan2(vector.Y, vector.X);
float angleInDegrees = angleInRadians * (180 / MathF.PI);
return angleInDegrees;
}
public static Vector3 toUnrealCoordinateVector(System.Numerics.Vector3 vector)
{
var unreal_vector = new Vector3();
unreal_vector.Y = vector.X;
unreal_vector.Z = vector.Y;
unreal_vector.X = vector.Z;
return unreal_vector;
}
}