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