using System;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace TeleportationMap;
[BepInPlugin("chadi7bark.howtofish.teleportationmap", "Teleportation Map", "0.1.14")]
public sealed class TeleportationMapPlugin : BaseUnityPlugin
{
private const float WorldToMapXScale = 0.0006040856f;
private const float WorldToMapXOffset = 0.5680561f;
private const float WorldToMapZScale = -0.0005951446f;
private const float WorldToMapZOffset = 0.4647192f;
private const float LighthouseMapCenterU = 0.459947f;
private const float LighthouseMapCenterV = 0.094246f;
private const float LighthouseWorldCenterX = -202.596f;
private const float LighthouseWorldCenterZ = 601.437f;
private const float IslandTeleportY = 1.5f;
private const float AnywhereFallbackY = 3f;
private const float GroundProbeStartY = 250f;
private const float GroundProbeDistance = 500f;
private const float GroundSpawnOffsetY = 1.75f;
private const int IslandScenePhysicsSettleFrames = 12;
private const double IslandSceneLoadTimeoutSeconds = 8.0;
private static readonly string[] IslandNames = new string[5] { "Lighthouse Island", "Shed Island", "Tropical Island", "Casino Island", "Volcano Island" };
private static readonly float[] IslandWorldX = new float[5] { -200f, 500f, 310f, -150f, -700f };
private static readonly float[] IslandWorldZ = new float[5] { 600f, -100f, -570f, -770f, -560f };
private static readonly string[] IslandSceneNames = new string[5] { "Island1", "Island2", "Island3", "Island4", "Island5" };
private static readonly float[] IslandMapMinU = new float[5] { 0.420707f, 0.836483f, 0.69433f, 0.435497f, 0.064092f };
private static readonly float[] IslandMapMaxU = new float[5] { 0.486442f, 0.913722f, 0.795399f, 0.527527f, 0.221857f };
private static readonly float[] IslandMapMinV = new float[5] { 0.08662f, 0.506574f, 0.764114f, 0.887858f, 0.740139f };
private static readonly float[] IslandMapMaxV = new float[5] { 0.137664f, 0.569219f, 0.846868f, 0.949729f, 0.864656f };
private static readonly float[] LockedIslandMinX = new float[5] { -219.67f, 479.53f, 276f, -177.33f, -780.6f };
private static readonly float[] LockedIslandMaxX = new float[5] { -180.26f, 527.49f, 345.83f, -127.74f, -623.63f };
private static readonly float[] LockedIslandMinZ = new float[5] { 580.5f, -128.28f, -605.58f, -791.01f, -633.57f };
private static readonly float[] LockedIslandMaxZ = new float[5] { 616.84f, -83.55f, -537.14f, -743.53f, -485.97f };
private static readonly float[] LighthouseMapPolyU = new float[8] { 0.484f, 0.4785f, 0.4635f, 0.4475f, 0.4408f, 0.446f, 0.46f, 0.476f };
private static readonly float[] LighthouseMapPolyV = new float[8] { 0.1015f, 0.09f, 0.0868f, 0.0888f, 0.1005f, 0.1105f, 0.119f, 0.112f };
private static readonly float[] LighthouseWorldPolyX = new float[8] { -180.8f, -187f, -197f, -211.5f, -219f, -212.5f, -199.5f, -186f };
private static readonly float[] LighthouseWorldPolyZ = new float[8] { 598.5f, 608f, 612f, 608f, 597f, 586f, 581f, 586f };
private static readonly float[] IslandBoundsScanRadius = new float[5] { 120f, 130f, 150f, 140f, 190f };
private static readonly float[] GroundProbeOffsetX = new float[21]
{
0f, 2f, -2f, 0f, 0f, 2f, 2f, -2f, -2f, 4f,
-4f, 0f, 0f, 4f, 4f, -4f, -4f, 6f, -6f, 0f,
0f
};
private static readonly float[] GroundProbeOffsetZ = new float[21]
{
0f, 0f, 0f, 2f, -2f, 2f, -2f, 2f, -2f, 0f,
0f, 4f, -4f, 4f, -4f, 4f, -4f, 0f, 0f, 6f,
-6f
};
private object _mapTexture;
private int _mapWidth = 1217;
private int _mapHeight = 1293;
private object _camera;
private bool _fullMapOpen;
private float _frozenMapYaw;
private bool _frozenMapYawValid;
private bool _oldCursorVisible;
private object _oldCursorLock;
private int _frameCounter;
private Type _inputType;
private Type _keyCodeType;
private Type _guiType;
private Type _rectType;
private Type _colorType;
private Type _textureType;
private Type _texture2DType;
private Type _textureFormatType;
private Type _textureWrapModeType;
private Type _filterModeType;
private Type _scaleModeType;
private Type _screenType;
private Type _cameraType;
private Type _cursorType;
private Type _cursorLockModeType;
private Type _imageConversionType;
private Type _playerCameraType;
private Type _playerType;
private Type _guiStyleType;
private Type _textAnchorType;
private Type _guiUtilityType;
private Type _vector2Type;
private Type _vector3Type;
private Type _serverType;
private Type _physicsType;
private Type _colliderType;
private Type _raycastHitType;
private Type _queryTriggerInteractionType;
private Type _sceneManagerType;
private Type _sceneType;
private Type _loadSceneModeType;
private object _localPlayer;
private object _server;
private object _localPlayerTransform;
private FieldInfo _playerTransformField;
private FieldInfo _playerCameraField;
private FieldInfo _playerCameraRotField;
private FieldInfo _playerCamObjectField;
private MethodInfo _serverTeleportPlayer;
private MethodInfo _playerLocalTeleport;
private MethodInfo _physicsRaycastAll;
private MethodInfo _sceneGetByName;
private MethodInfo _sceneLoadSceneAsync;
private MethodInfo _sceneLoadScene;
private string _lastYawSource = "none";
private object _playerCamera;
private MethodInfo _toggleMouse;
private PropertyInfo _playerCameraEnabled;
private bool _oldPlayerCameraEnabled = true;
private bool _playerCameraDisabledByMap;
private MethodInfo _getKeyDown;
private MethodInfo _getMouseButtonDown;
private MethodInfo _drawTextureUv;
private MethodInfo _drawTexture4;
private MethodInfo _drawTexture2;
private MethodInfo _label2;
private MethodInfo _label3;
private PropertyInfo _guiColor;
private PropertyInfo _screenWidth;
private PropertyInfo _screenHeight;
private PropertyInfo _cameraMain;
private PropertyInfo _mousePosition;
private PropertyInfo _cursorVisible;
private PropertyInfo _cursorLockState;
private PropertyInfo _guiMatrix;
private MethodInfo _rotateAroundPivot;
private object _keyM;
private object _keyEscape;
private object _scaleStretch;
private object _cursorNone;
private object _whiteTexture;
private object _whiteColor;
private object _yellowColor;
private object _blackColor;
private object _black78;
private object _haloColor;
private object _softGoldColor;
private object _centerColor;
private object _indicatorStyle;
private object _indicatorShadowStyle;
private object _haloStyle;
private object _ringStyle;
private object _centerStyle;
private int _hoveredIsland = -1;
private readonly bool[] _islandBoundsValid = new bool[5];
private readonly float[] _islandMinX = new float[5];
private readonly float[] _islandMaxX = new float[5];
private readonly float[] _islandMinZ = new float[5];
private readonly float[] _islandMaxZ = new float[5];
private readonly int[] _islandBoundsColliderCount = new int[5];
private int _pendingTeleportIsland = -1;
private float _pendingTeleportYaw;
private float _pendingTeleportWorldX;
private float _pendingTeleportWorldZ;
private float _pendingTeleportMapU;
private float _pendingTeleportMapV;
private bool _pendingTeleportUseIslandMapping;
private bool _pendingTeleportPreferIslandLand;
private bool _pendingSceneLoadRequested;
private int _pendingSceneReadyFrame = -1;
private DateTime _pendingTeleportStartedUtc;
private void LogInfo(string message)
{
Console.WriteLine("[Teleportation Map] " + message);
}
private void LogWarning(string message)
{
Console.WriteLine("[Teleportation Map] [WARNING] " + message);
}
private void LogError(string message)
{
Console.WriteLine("[Teleportation Map] [ERROR] " + message);
}
private void Awake()
{
LogInfo("============================================================");
LogInfo(" TELEPORTATION MAP v0.1.14 BEPINEX / LIGHTHOUSE POLYGON");
LogInfo(" Author: chadi7bark");
LogInfo("============================================================");
LogInfo("M = open/close full map");
LogInfo("BepInEx 5 port of v0.1.14: locked coordinates + Lighthouse shoreline polygon + triangulated map/world mapping.");
if (!InitializeUnityApi())
{
LogError("Teleportation Map could not initialize the Unity runtime API.");
return;
}
LoadMapTexture();
RefreshCamera();
InitializeLockedIslandBounds();
LogInfo("LIGHTHOUSE POLYGON -> 8 shoreline vertices; raft excluded; anchor map=(0.459947,0.094246) world=(-202.596,601.437).");
}
private void Update()
{
_frameCounter++;
ProcessPendingIslandTeleport();
if (_inputType == null && !InitializeUnityApi())
{
return;
}
if (GetKeyDown(_keyM))
{
if (_fullMapOpen)
{
CloseFullMap();
}
else
{
OpenFullMap();
}
}
if (_fullMapOpen && GetKeyDown(_keyEscape))
{
CloseFullMap();
}
if (_fullMapOpen && GetMouseButtonDown(0) && TryHandleMapClick())
{
return;
}
if (_fullMapOpen)
{
ForceCursorUnlocked();
if (_frameCounter % 15 == 0)
{
RefreshPlayerCamera();
if (_playerCamera != null && _playerCameraEnabled != null)
{
try
{
_playerCameraEnabled.SetValue(_playerCamera, false, null);
}
catch
{
}
}
}
}
if (_camera == null || _frameCounter % 30 == 0)
{
RefreshCamera();
}
else if (_localPlayerTransform == null || _frameCounter % 30 == 0)
{
RefreshLocalPlayer();
}
}
private void OnGUI()
{
if (_mapTexture != null && !(_guiType == null) && _fullMapOpen)
{
DrawFullMap();
}
}
private bool InitializeUnityApi()
{
try
{
_inputType = ResolveType("UnityEngine.Input", "UnityEngine.InputLegacyModule", "UnityEngine.CoreModule");
_keyCodeType = ResolveType("UnityEngine.KeyCode", "UnityEngine.InputLegacyModule", "UnityEngine.CoreModule");
_guiType = ResolveType("UnityEngine.GUI", "UnityEngine.IMGUIModule");
_rectType = ResolveType("UnityEngine.Rect", "UnityEngine.CoreModule");
_colorType = ResolveType("UnityEngine.Color", "UnityEngine.CoreModule");
_textureType = ResolveType("UnityEngine.Texture", "UnityEngine.CoreModule");
_texture2DType = ResolveType("UnityEngine.Texture2D", "UnityEngine.CoreModule");
_textureFormatType = ResolveType("UnityEngine.TextureFormat", "UnityEngine.CoreModule");
_textureWrapModeType = ResolveType("UnityEngine.TextureWrapMode", "UnityEngine.CoreModule");
_filterModeType = ResolveType("UnityEngine.FilterMode", "UnityEngine.CoreModule");
_scaleModeType = ResolveType("UnityEngine.ScaleMode", "UnityEngine.IMGUIModule", "UnityEngine.CoreModule");
_screenType = ResolveType("UnityEngine.Screen", "UnityEngine.CoreModule");
_cameraType = ResolveType("UnityEngine.Camera", "UnityEngine.CoreModule");
_cursorType = ResolveType("UnityEngine.Cursor", "UnityEngine.CoreModule");
_cursorLockModeType = ResolveType("UnityEngine.CursorLockMode", "UnityEngine.CoreModule");
_imageConversionType = ResolveType("UnityEngine.ImageConversion", "UnityEngine.ImageConversionModule");
_playerCameraType = ResolveType("PlayerCamera", "Assembly-CSharp");
_playerType = ResolveType("Player", "Assembly-CSharp");
_guiStyleType = ResolveType("UnityEngine.GUIStyle", "UnityEngine.IMGUIModule");
_textAnchorType = ResolveType("UnityEngine.TextAnchor", "UnityEngine.TextRenderingModule", "UnityEngine.CoreModule");
_guiUtilityType = ResolveType("UnityEngine.GUIUtility", "UnityEngine.IMGUIModule");
_vector2Type = ResolveType("UnityEngine.Vector2", "UnityEngine.CoreModule");
_vector3Type = ResolveType("UnityEngine.Vector3", "UnityEngine.CoreModule");
_serverType = ResolveType("Server", "Assembly-CSharp");
_physicsType = ResolveType("UnityEngine.Physics", "UnityEngine.PhysicsModule");
_colliderType = ResolveType("UnityEngine.Collider", "UnityEngine.PhysicsModule");
_raycastHitType = ResolveType("UnityEngine.RaycastHit", "UnityEngine.PhysicsModule");
_queryTriggerInteractionType = ResolveType("UnityEngine.QueryTriggerInteraction", "UnityEngine.PhysicsModule");
_sceneManagerType = ResolveType("UnityEngine.SceneManagement.SceneManager", "UnityEngine.CoreModule");
_sceneType = ResolveType("UnityEngine.SceneManagement.Scene", "UnityEngine.CoreModule");
_loadSceneModeType = ResolveType("UnityEngine.SceneManagement.LoadSceneMode", "UnityEngine.CoreModule");
if (_inputType == null || _keyCodeType == null || _guiType == null || _rectType == null || _colorType == null || _textureType == null || _texture2DType == null || _screenType == null || _cameraType == null)
{
return false;
}
_getKeyDown = FindStaticMethod(_inputType, "GetKeyDown", new Type[1] { _keyCodeType });
_getMouseButtonDown = FindStaticMethod(_inputType, "GetMouseButtonDown", new Type[1] { typeof(int) });
_mousePosition = _inputType.GetProperty("mousePosition", BindingFlags.Static | BindingFlags.Public);
_drawTextureUv = FindStaticMethod(_guiType, "DrawTextureWithTexCoords", new Type[4]
{
_rectType,
_textureType,
_rectType,
typeof(bool)
});
_drawTexture4 = ((_scaleModeType == null) ? null : FindStaticMethod(_guiType, "DrawTexture", new Type[4]
{
_rectType,
_textureType,
_scaleModeType,
typeof(bool)
}));
_drawTexture2 = FindStaticMethod(_guiType, "DrawTexture", new Type[2] { _rectType, _textureType });
_label2 = FindStaticMethod(_guiType, "Label", new Type[2]
{
_rectType,
typeof(string)
});
_label3 = ((_guiStyleType == null) ? null : FindStaticMethod(_guiType, "Label", new Type[3]
{
_rectType,
typeof(string),
_guiStyleType
}));
_guiColor = _guiType.GetProperty("color", BindingFlags.Static | BindingFlags.Public);
_guiMatrix = _guiType.GetProperty("matrix", BindingFlags.Static | BindingFlags.Public);
if (_guiUtilityType != null && _vector2Type != null)
{
_rotateAroundPivot = FindStaticMethod(_guiUtilityType, "RotateAroundPivot", new Type[2]
{
typeof(float),
_vector2Type
});
}
_screenWidth = _screenType.GetProperty("width", BindingFlags.Static | BindingFlags.Public);
_screenHeight = _screenType.GetProperty("height", BindingFlags.Static | BindingFlags.Public);
_cameraMain = _cameraType.GetProperty("main", BindingFlags.Static | BindingFlags.Public);
if (_cursorType != null)
{
_cursorVisible = _cursorType.GetProperty("visible", BindingFlags.Static | BindingFlags.Public);
_cursorLockState = _cursorType.GetProperty("lockState", BindingFlags.Static | BindingFlags.Public);
}
_keyM = Enum.Parse(_keyCodeType, "M");
_keyEscape = Enum.Parse(_keyCodeType, "Escape");
if (_scaleModeType != null)
{
_scaleStretch = Enum.Parse(_scaleModeType, "StretchToFill");
}
if (_cursorLockModeType != null)
{
_cursorNone = Enum.Parse(_cursorLockModeType, "None");
}
_whiteColor = NewColor(1f, 1f, 1f, 1f);
_yellowColor = NewColor(0.97f, 0.83f, 0.18f, 1f);
_blackColor = NewColor(0f, 0f, 0f, 1f);
_black78 = NewColor(0f, 0f, 0f, 0.78f);
_haloColor = NewColor(0f, 0f, 0f, 0.58f);
_softGoldColor = NewColor(1f, 0.72f, 0.1f, 0.95f);
_centerColor = NewColor(1f, 0.96f, 0.72f, 1f);
PropertyInfo property = _texture2DType.GetProperty("whiteTexture", BindingFlags.Static | BindingFlags.Public);
if (property != null)
{
_whiteTexture = property.GetValue(null, null);
}
BuildIndicatorStyles(32);
ResolveTeleportApi();
ResolvePhysicsApi();
ResolveSceneApi();
return _getKeyDown != null && _screenWidth != null && _screenHeight != null && _label2 != null;
}
catch (Exception ex)
{
LogError("Unity reflection setup failed: " + ex);
return false;
}
}
private void LoadMapTexture()
{
string text = Path.Combine(Environment.CurrentDirectory, "UserData", "TeleportationMap", "TeleportationMap.png");
if (!File.Exists(text))
{
LogError("Map image was not found: " + text);
return;
}
try
{
object obj = CreateTexture2D();
if (obj == null)
{
LogError("Could not construct Unity Texture2D.");
return;
}
SetPropertyIfPresent(obj, "name", "TeleportationMapTexture");
if (_textureWrapModeType != null)
{
SetPropertyIfPresent(obj, "wrapMode", Enum.Parse(_textureWrapModeType, "Clamp"));
}
if (_filterModeType != null)
{
SetPropertyIfPresent(obj, "filterMode", Enum.Parse(_filterModeType, "Bilinear"));
}
byte[] data = File.ReadAllBytes(text);
if (!LoadPngIntoTexture(obj, data))
{
LogError("Unity could not decode TeleportationMap.png.");
return;
}
_mapTexture = obj;
_mapWidth = ReadIntProperty(obj, "width", _mapWidth);
_mapHeight = ReadIntProperty(obj, "height", _mapHeight);
LogInfo("Loaded custom map texture: " + _mapWidth + "x" + _mapHeight);
}
catch (Exception ex)
{
LogError("Failed to load map texture: " + ex);
}
}
private object CreateTexture2D()
{
try
{
if (_textureFormatType != null)
{
object obj = Enum.Parse(_textureFormatType, "RGBA32");
ConstructorInfo constructor = _texture2DType.GetConstructor(new Type[4]
{
typeof(int),
typeof(int),
_textureFormatType,
typeof(bool)
});
if (constructor != null)
{
return constructor.Invoke(new object[4] { 2, 2, obj, false });
}
}
ConstructorInfo constructor2 = _texture2DType.GetConstructor(new Type[2]
{
typeof(int),
typeof(int)
});
if (constructor2 != null)
{
return constructor2.Invoke(new object[2] { 2, 2 });
}
}
catch (Exception ex)
{
LogError("Texture2D constructor failed: " + ex);
}
return null;
}
private bool LoadPngIntoTexture(object texture, byte[] data)
{
if (_imageConversionType == null)
{
_imageConversionType = ResolveType("UnityEngine.ImageConversion", "UnityEngine.ImageConversionModule");
}
_playerCameraType = ResolveType("PlayerCamera", "Assembly-CSharp");
_playerType = ResolveType("Player", "Assembly-CSharp");
_guiStyleType = ResolveType("UnityEngine.GUIStyle", "UnityEngine.IMGUIModule");
_textAnchorType = ResolveType("UnityEngine.TextAnchor", "UnityEngine.TextRenderingModule", "UnityEngine.CoreModule");
_guiUtilityType = ResolveType("UnityEngine.GUIUtility", "UnityEngine.IMGUIModule");
_vector2Type = ResolveType("UnityEngine.Vector2", "UnityEngine.CoreModule");
if (_imageConversionType == null)
{
return false;
}
MethodInfo[] methods = _imageConversionType.GetMethods(BindingFlags.Static | BindingFlags.Public);
foreach (MethodInfo methodInfo in methods)
{
if (methodInfo.Name != "LoadImage")
{
continue;
}
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length == 3 && !(parameters[0].ParameterType.FullName != "UnityEngine.Texture2D") && !(parameters[1].ParameterType != typeof(byte[])) && !(parameters[2].ParameterType != typeof(bool)))
{
object obj = methodInfo.Invoke(null, new object[3] { texture, data, false });
if (obj is bool)
{
return (bool)obj;
}
return false;
}
}
return false;
}
private void RefreshCamera()
{
try
{
if (_cameraMain != null)
{
_camera = _cameraMain.GetValue(null, null);
}
RefreshPlayerCamera();
RefreshLocalPlayer();
}
catch
{
_camera = null;
}
}
private void DrawFullMap()
{
int screenWidth = GetScreenWidth();
int screenHeight = GetScreenHeight();
DrawSolidRect(0f, 0f, screenWidth, screenHeight, _black78);
GetMapRect(screenWidth, screenHeight, out var mapX, out var mapY, out var mapW, out var mapH);
object rect = NewRect(mapX, mapY, mapW, mapH);
SetGuiColor(_whiteColor);
DrawTexture(rect, _mapTexture);
GetNavigationState(out var x, out var z, out var yawDegrees);
if (_frozenMapYawValid)
{
yawDegrees = _frozenMapYaw;
}
WorldToMapNormalizedAuto(x, z, out var u, out var screenV, out var _);
float centerX = mapX + u * mapW;
float centerY = mapY + screenV * mapH;
DrawPlayerIndicator(centerX, centerY, yawDegrees, Clamp(mapW * 0.035f, 26f, 46f));
_hoveredIsland = FindIslandUnderMouse(mapX, mapY, mapW, mapH);
SetGuiColor(_whiteColor);
DrawLabel(NewRect(12f, 10f, (float)screenWidth - 24f, 28f), "TELEPORTATION MAP");
string text;
if (TryGetMapMouseWorld(mapX, mapY, mapW, mapH, out var worldX, out var worldZ))
{
int num = FindNearestIsland(worldX, worldZ);
text = "LEFT CLICK TO TELEPORT | X=" + worldX.ToString("0") + " Z=" + worldZ.ToString("0");
if (_hoveredIsland >= 0)
{
text = text + " | " + IslandNames[_hoveredIsland];
text = ((!_islandBoundsValid[_hoveredIsland]) ? (text + " locked mapping") : (text + " LOCKED-MAPPED"));
}
else if (num >= 0)
{
text = text + " | nearest: " + IslandNames[num];
}
}
else
{
text = "LEFT CLICK ANYWHERE ON THE MAP TO TELEPORT | M or ESC = close";
}
DrawLabel(NewRect(12f, (float)screenHeight - 30f, (float)screenWidth - 24f, 24f), text);
}
private bool TryHandleMapClick()
{
int screenWidth = GetScreenWidth();
int screenHeight = GetScreenHeight();
GetMapRect(screenWidth, screenHeight, out var mapX, out var mapY, out var mapW, out var mapH);
if (!TryGetMapMouseNormalized(mapX, mapY, mapW, mapH, out var u, out var v))
{
return false;
}
int num = FindIslandAtNormalized(u, v);
bool preferIslandLand = num >= 0;
MapNormalizedToWorldAuto(u, v, out var worldX, out var worldZ, out var mappedIsland);
int num2 = num;
if (num2 < 0)
{
num2 = mappedIsland;
}
if (num2 < 0)
{
num2 = FindNearestIsland(worldX, worldZ);
}
if (num2 < 0)
{
return false;
}
float yaw = (_frozenMapYawValid ? _frozenMapYaw : 0f);
if (!BeginMapTeleport(worldX, worldZ, num2, yaw, preferIslandLand, u, v, num >= 0))
{
return false;
}
LogInfo("ANYWHERE CLICK -> map=(" + u.ToString("0.0000") + "," + v.ToString("0.0000") + ") world=(" + worldX.ToString("0.00") + ", " + worldZ.ToString("0.00") + ") scene=" + IslandSceneNames[num2] + ((num >= 0) ? "; ISLAND-LOCAL LOCKED BOUNDS requested." : "; global ocean mapping requested."));
CloseFullMap();
return true;
}
private bool TryGetMapMouseNormalized(float mapX, float mapY, float mapW, float mapH, out float u, out float v)
{
u = 0f;
v = 0f;
if (!TryGetGuiMousePosition(out var x, out var y))
{
return false;
}
if (mapW <= 0.01f || mapH <= 0.01f)
{
return false;
}
if (x < mapX || x > mapX + mapW || y < mapY || y > mapY + mapH)
{
return false;
}
u = Clamp((x - mapX) / mapW, 0.045f, 0.955f);
v = Clamp((y - mapY) / mapH, 0.04f, 0.955f);
return true;
}
private bool TryGetMapMouseWorld(float mapX, float mapY, float mapW, float mapH, out float worldX, out float worldZ)
{
worldX = 0f;
worldZ = 0f;
if (!TryGetMapMouseNormalized(mapX, mapY, mapW, mapH, out var u, out var v))
{
return false;
}
MapNormalizedToWorldAuto(u, v, out worldX, out worldZ, out var _);
return true;
}
private int FindNearestIsland(float worldX, float worldZ)
{
int result = -1;
float num = float.MaxValue;
for (int i = 0; i < IslandWorldX.Length && i < IslandWorldZ.Length; i++)
{
float num2 = worldX - IslandWorldX[i];
float num3 = worldZ - IslandWorldZ[i];
float num4 = num2 * num2 + num3 * num3;
if (num4 < num)
{
num = num4;
result = i;
}
}
return result;
}
private int FindIslandUnderMouse(float mapX, float mapY, float mapW, float mapH)
{
if (!TryGetMapMouseNormalized(mapX, mapY, mapW, mapH, out var u, out var v))
{
return -1;
}
return FindIslandAtNormalized(u, v);
}
private int FindIslandAtNormalized(float u, float v)
{
if (IsPointInLighthouseMapPolygon(u, v))
{
return 0;
}
for (int i = 1; i < IslandNames.Length; i++)
{
float num = IslandMapMinU[i];
float num2 = IslandMapMaxU[i];
float num3 = IslandMapMinV[i];
float num4 = IslandMapMaxV[i];
float num5 = (num + num2) * 0.5f;
float num6 = (num3 + num4) * 0.5f;
float num7 = Math.Max((num2 - num) * 0.54f, 0.001f);
float num8 = Math.Max((num4 - num3) * 0.54f, 0.001f);
float num9 = (u - num5) / num7;
float num10 = (v - num6) / num8;
if (num9 * num9 + num10 * num10 <= 1f)
{
return i;
}
}
return -1;
}
private bool IsPointInLighthouseMapPolygon(float u, float v)
{
bool flag = false;
int num = LighthouseMapPolyU.Length;
int num2 = num - 1;
for (int i = 0; i < num; i++)
{
float num3 = LighthouseMapPolyU[i];
float num4 = LighthouseMapPolyV[i];
float num5 = LighthouseMapPolyU[num2];
float num6 = LighthouseMapPolyV[num2];
if (num4 > v != num6 > v)
{
float num7 = num6 - num4;
if (Math.Abs(num7) < 1E-07f)
{
num7 = ((num7 < 0f) ? (-1E-07f) : 1E-07f);
}
float num8 = (num5 - num3) * (v - num4) / num7 + num3;
if (u < num8)
{
flag = !flag;
}
}
num2 = i;
}
return flag;
}
private bool TryMapLighthouseMapToWorld(float u, float v, out float worldX, out float worldZ)
{
worldX = 0f;
worldZ = 0f;
if (!IsPointInLighthouseMapPolygon(u, v))
{
return false;
}
int num = LighthouseMapPolyU.Length;
for (int i = 0; i < num; i++)
{
int num2 = (i + 1) % num;
if (TryBarycentric2D(u, v, 0.459947f, 0.094246f, LighthouseMapPolyU[i], LighthouseMapPolyV[i], LighthouseMapPolyU[num2], LighthouseMapPolyV[num2], out var wa, out var wb, out var wc))
{
worldX = wa * -202.596f + wb * LighthouseWorldPolyX[i] + wc * LighthouseWorldPolyX[num2];
worldZ = wa * 601.437f + wb * LighthouseWorldPolyZ[i] + wc * LighthouseWorldPolyZ[num2];
return true;
}
}
return false;
}
private bool TryMapLighthouseWorldToMap(float worldX, float worldZ, out float u, out float v)
{
u = 0f;
v = 0f;
int num = LighthouseWorldPolyX.Length;
for (int i = 0; i < num; i++)
{
int num2 = (i + 1) % num;
if (TryBarycentric2D(worldX, worldZ, -202.596f, 601.437f, LighthouseWorldPolyX[i], LighthouseWorldPolyZ[i], LighthouseWorldPolyX[num2], LighthouseWorldPolyZ[num2], out var wa, out var wb, out var wc))
{
u = wa * 0.459947f + wb * LighthouseMapPolyU[i] + wc * LighthouseMapPolyU[num2];
v = wa * 0.094246f + wb * LighthouseMapPolyV[i] + wc * LighthouseMapPolyV[num2];
return true;
}
}
return false;
}
private static bool TryBarycentric2D(float px, float py, float ax, float ay, float bx, float by, float cx, float cy, out float wa, out float wb, out float wc)
{
wa = 0f;
wb = 0f;
wc = 0f;
float num = bx - ax;
float num2 = by - ay;
float num3 = cx - ax;
float num4 = cy - ay;
float num5 = px - ax;
float num6 = py - ay;
float num7 = num * num + num2 * num2;
float num8 = num * num3 + num2 * num4;
float num9 = num3 * num3 + num4 * num4;
float num10 = num5 * num + num6 * num2;
float num11 = num5 * num3 + num6 * num4;
float num12 = num7 * num9 - num8 * num8;
if (Math.Abs(num12) < 1E-08f)
{
return false;
}
wb = (num9 * num10 - num8 * num11) / num12;
wc = (num7 * num11 - num8 * num10) / num12;
wa = 1f - wb - wc;
if (wa >= -0.0006f && wb >= -0.0006f)
{
return wc >= -0.0006f;
}
return false;
}
private bool TryGetGuiMousePosition(out float x, out float y)
{
x = 0f;
y = 0f;
if (_mousePosition == null)
{
return false;
}
try
{
object value = _mousePosition.GetValue(null, null);
if (value == null)
{
return false;
}
FieldInfo field = value.GetType().GetField("x", BindingFlags.Instance | BindingFlags.Public);
FieldInfo field2 = value.GetType().GetField("y", BindingFlags.Instance | BindingFlags.Public);
if (field == null || field2 == null)
{
return false;
}
x = Convert.ToSingle(field.GetValue(value));
y = (float)GetScreenHeight() - Convert.ToSingle(field2.GetValue(value));
return true;
}
catch
{
return false;
}
}
private void GetMapRect(int screenW, int screenH, out float mapX, out float mapY, out float mapW, out float mapH)
{
float num = (float)screenW * 0.63f;
float num2 = (float)screenH * 0.63f;
float num3 = ((_mapHeight <= 0) ? 1f : ((float)_mapWidth / (float)_mapHeight));
mapW = num;
mapH = mapW / num3;
if (mapH > num2)
{
mapH = num2;
mapW = mapH * num3;
}
mapX = ((float)screenW - mapW) * 0.5f;
mapY = ((float)screenH - mapH) * 0.5f + 10f;
}
private void ResolveSceneApi()
{
if (_sceneManagerType == null)
{
_sceneManagerType = ResolveType("UnityEngine.SceneManagement.SceneManager", "UnityEngine.CoreModule");
}
if (_sceneType == null)
{
_sceneType = ResolveType("UnityEngine.SceneManagement.Scene", "UnityEngine.CoreModule");
}
if (_loadSceneModeType == null)
{
_loadSceneModeType = ResolveType("UnityEngine.SceneManagement.LoadSceneMode", "UnityEngine.CoreModule");
}
if (_sceneManagerType == null)
{
return;
}
try
{
_sceneGetByName = _sceneManagerType.GetMethod("GetSceneByName", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
if (_loadSceneModeType != null)
{
_sceneLoadSceneAsync = _sceneManagerType.GetMethod("LoadSceneAsync", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
{
typeof(string),
_loadSceneModeType
}, null);
_sceneLoadScene = _sceneManagerType.GetMethod("LoadScene", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
{
typeof(string),
_loadSceneModeType
}, null);
}
}
catch
{
}
}
private bool BeginMapTeleport(float worldX, float worldZ, int island, float yaw, bool preferIslandLand, float mapU, float mapV, bool useIslandMapping)
{
if (island < 0 || island >= IslandNames.Length)
{
return false;
}
if (_pendingTeleportIsland >= 0)
{
LogWarning("A map teleport is already waiting for an island scene to load.");
return false;
}
_pendingTeleportIsland = island;
_pendingTeleportYaw = yaw;
_pendingTeleportWorldX = worldX;
_pendingTeleportWorldZ = worldZ;
_pendingTeleportMapU = mapU;
_pendingTeleportMapV = mapV;
_pendingTeleportUseIslandMapping = useIslandMapping;
_pendingTeleportPreferIslandLand = preferIslandLand;
_pendingSceneLoadRequested = false;
_pendingSceneReadyFrame = -1;
_pendingTeleportStartedUtc = DateTime.UtcNow;
string text = IslandSceneNames[island];
if (IsSceneLoaded(text))
{
_pendingSceneReadyFrame = _frameCounter + 12;
LogInfo("Nearest island scene already loaded -> " + text + "; waiting briefly for physics before point ground scan.");
}
else
{
RequestIslandSceneLoad(text);
}
return true;
}
private void ProcessPendingIslandTeleport()
{
if (_pendingTeleportIsland < 0)
{
return;
}
if (_pendingTeleportIsland >= IslandNames.Length)
{
ClearPendingIslandTeleport();
return;
}
int pendingTeleportIsland = _pendingTeleportIsland;
string text = IslandSceneNames[pendingTeleportIsland];
if (!IsSceneLoaded(text))
{
if (!_pendingSceneLoadRequested)
{
RequestIslandSceneLoad(text);
}
if (!((DateTime.UtcNow - _pendingTeleportStartedUtc).TotalSeconds < 8.0))
{
LogWarning("Timed out waiting for " + text + "; teleporting with the original fallback if ground is still unavailable.");
float pendingTeleportYaw = _pendingTeleportYaw;
float worldX = _pendingTeleportWorldX;
float worldZ = _pendingTeleportWorldZ;
bool pendingTeleportPreferIslandLand = _pendingTeleportPreferIslandLand;
if (_pendingTeleportUseIslandMapping && ScanIslandWorldBounds(pendingTeleportIsland))
{
MapIslandNormalizedToWorld(pendingTeleportIsland, _pendingTeleportMapU, _pendingTeleportMapV, out worldX, out worldZ);
}
ClearPendingIslandTeleport();
TeleportToMapPoint(worldX, worldZ, pendingTeleportIsland, pendingTeleportYaw, text, pendingTeleportPreferIslandLand);
}
}
else if (_pendingSceneReadyFrame < 0)
{
_pendingSceneReadyFrame = _frameCounter + 12;
LogInfo("ISLAND SCENE READY -> " + text + "; waiting " + 12 + " frames for colliders.");
}
else if (_frameCounter >= _pendingSceneReadyFrame)
{
ScanIslandWorldBounds(pendingTeleportIsland);
float pendingTeleportYaw2 = _pendingTeleportYaw;
float worldX2 = _pendingTeleportWorldX;
float worldZ2 = _pendingTeleportWorldZ;
bool pendingTeleportPreferIslandLand2 = _pendingTeleportPreferIslandLand;
if (_pendingTeleportUseIslandMapping && _islandBoundsValid[pendingTeleportIsland])
{
MapIslandNormalizedToWorld(pendingTeleportIsland, _pendingTeleportMapU, _pendingTeleportMapV, out worldX2, out worldZ2);
LogInfo("LOCKED ISLAND REMAP -> " + IslandNames[pendingTeleportIsland] + " world=(" + worldX2.ToString("0.00") + ", " + worldZ2.ToString("0.00") + ")");
}
ClearPendingIslandTeleport();
TeleportToMapPoint(worldX2, worldZ2, pendingTeleportIsland, pendingTeleportYaw2, text, pendingTeleportPreferIslandLand2);
}
}
private void ClearPendingIslandTeleport()
{
_pendingTeleportIsland = -1;
_pendingTeleportYaw = 0f;
_pendingTeleportWorldX = 0f;
_pendingTeleportWorldZ = 0f;
_pendingTeleportMapU = 0f;
_pendingTeleportMapV = 0f;
_pendingTeleportUseIslandMapping = false;
_pendingTeleportPreferIslandLand = false;
_pendingSceneLoadRequested = false;
_pendingSceneReadyFrame = -1;
}
private bool IsSceneLoaded(string sceneName)
{
if (string.IsNullOrEmpty(sceneName))
{
return false;
}
if (_sceneGetByName == null)
{
ResolveSceneApi();
}
if (_sceneGetByName == null)
{
return false;
}
try
{
object obj = _sceneGetByName.Invoke(null, new object[1] { sceneName });
if (obj == null)
{
return false;
}
PropertyInfo property = obj.GetType().GetProperty("isLoaded", BindingFlags.Instance | BindingFlags.Public);
if (property != null)
{
return Convert.ToBoolean(property.GetValue(obj, null));
}
}
catch
{
}
return false;
}
private bool RequestIslandSceneLoad(string sceneName)
{
if (string.IsNullOrEmpty(sceneName))
{
return false;
}
if (_sceneManagerType == null || (_sceneLoadSceneAsync == null && _sceneLoadScene == null))
{
ResolveSceneApi();
}
if (_sceneManagerType == null || _loadSceneModeType == null)
{
return false;
}
_pendingSceneLoadRequested = true;
try
{
object obj = Enum.Parse(_loadSceneModeType, "Additive");
if (_sceneLoadSceneAsync != null)
{
_sceneLoadSceneAsync.Invoke(null, new object[2] { sceneName, obj });
LogInfo("ADDITIVE ISLAND LOAD -> " + sceneName + " requested; waiting for scene + collision before teleport.");
return true;
}
if (_sceneLoadScene != null)
{
_sceneLoadScene.Invoke(null, new object[2] { sceneName, obj });
LogInfo("ADDITIVE ISLAND LOAD -> " + sceneName + " requested synchronously.");
return true;
}
}
catch (Exception ex)
{
LogWarning("Could not request island scene load for " + sceneName + ": " + ex.Message);
}
return false;
}
private void InitializeLockedIslandBounds()
{
for (int i = 0; i < IslandNames.Length; i++)
{
_islandMinX[i] = LockedIslandMinX[i];
_islandMaxX[i] = LockedIslandMaxX[i];
_islandMinZ[i] = LockedIslandMinZ[i];
_islandMaxZ[i] = LockedIslandMaxZ[i];
_islandBoundsColliderCount[i] = -1;
_islandBoundsValid[i] = true;
LogInfo("LOCKED ISLAND BOUNDS -> " + IslandNames[i] + " X=[" + _islandMinX[i].ToString("0.00") + "," + _islandMaxX[i].ToString("0.00") + "] Z=[" + _islandMinZ[i].ToString("0.00") + "," + _islandMaxZ[i].ToString("0.00") + "]");
}
}
private void RefreshLoadedIslandBounds()
{
}
private bool ScanIslandWorldBounds(int island)
{
if (island >= 0 && island < IslandNames.Length)
{
return _islandBoundsValid[island];
}
return false;
}
private static bool LooksLikeIslandTerrainCollider(string name)
{
if (string.IsNullOrEmpty(name))
{
return false;
}
string text = name.ToLowerInvariant();
string[] array = new string[9] { "island", "terrain", "ground", "rock", "cliff", "sand", "beach", "shore", "land" };
for (int i = 0; i < array.Length; i++)
{
if (text.IndexOf(array[i], StringComparison.Ordinal) >= 0)
{
return true;
}
}
return false;
}
private void WorldToMapNormalizedAuto(float worldX, float worldZ, out float u, out float screenV, out int mappedIsland)
{
if (IsWorldPointNearIslandBounds(0, worldX, worldZ, 8f) && TryMapLighthouseWorldToMap(worldX, worldZ, out u, out screenV))
{
mappedIsland = 0;
return;
}
mappedIsland = FindNearestIsland(worldX, worldZ);
if (mappedIsland >= 0 && mappedIsland < IslandNames.Length && _islandBoundsValid[mappedIsland] && IsWorldPointNearIslandBounds(mappedIsland, worldX, worldZ, 16f))
{
float num = InverseLerp(_islandMinX[mappedIsland], _islandMaxX[mappedIsland], worldX);
float num2 = InverseLerp(_islandMinZ[mappedIsland], _islandMaxZ[mappedIsland], worldZ);
u = IslandMapMinU[mappedIsland] + num * (IslandMapMaxU[mappedIsland] - IslandMapMinU[mappedIsland]);
screenV = IslandMapMaxV[mappedIsland] - num2 * (IslandMapMaxV[mappedIsland] - IslandMapMinV[mappedIsland]);
}
else
{
mappedIsland = -1;
WorldToMapNormalized(worldX, worldZ, out u, out screenV);
}
}
private void MapNormalizedToWorldAuto(float u, float screenV, out float worldX, out float worldZ, out int mappedIsland)
{
if (TryMapLighthouseMapToWorld(u, screenV, out worldX, out worldZ))
{
mappedIsland = 0;
return;
}
mappedIsland = FindIslandAtNormalized(u, screenV);
if (mappedIsland >= 0 && mappedIsland < IslandNames.Length && _islandBoundsValid[mappedIsland])
{
MapIslandNormalizedToWorld(mappedIsland, u, screenV, out worldX, out worldZ);
return;
}
mappedIsland = -1;
MapNormalizedToWorld(u, screenV, out worldX, out worldZ);
}
private void MapIslandNormalizedToWorld(int island, float u, float screenV, out float worldX, out float worldZ)
{
if (island != 0 || !TryMapLighthouseMapToWorld(u, screenV, out worldX, out worldZ))
{
if (island < 0 || island >= IslandNames.Length || !_islandBoundsValid[island])
{
MapNormalizedToWorld(u, screenV, out worldX, out worldZ);
return;
}
float num = InverseLerp(IslandMapMinU[island], IslandMapMaxU[island], u);
float num2 = InverseLerp(IslandMapMaxV[island], IslandMapMinV[island], screenV);
worldX = _islandMinX[island] + num * (_islandMaxX[island] - _islandMinX[island]);
worldZ = _islandMinZ[island] + num2 * (_islandMaxZ[island] - _islandMinZ[island]);
}
}
private bool IsWorldPointNearIslandBounds(int island, float worldX, float worldZ, float padding)
{
if (island < 0 || island >= IslandNames.Length || !_islandBoundsValid[island])
{
return false;
}
if (worldX >= _islandMinX[island] - padding && worldX <= _islandMaxX[island] + padding && worldZ >= _islandMinZ[island] - padding)
{
return worldZ <= _islandMaxZ[island] + padding;
}
return false;
}
private void ResolveTeleportApi()
{
if (_serverType == null)
{
_serverType = ResolveType("Server", "Assembly-CSharp");
}
if (_playerType == null)
{
_playerType = ResolveType("Player", "Assembly-CSharp");
}
if (_vector3Type == null)
{
_vector3Type = ResolveType("UnityEngine.Vector3", "UnityEngine.CoreModule");
}
if (_serverType != null && _playerType != null && _vector3Type != null)
{
_serverTeleportPlayer = _serverType.GetMethod("TeleportPlayer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3]
{
_playerType,
_vector3Type,
typeof(float)
}, null);
}
if (_playerType != null && _vector3Type != null)
{
_playerLocalTeleport = _playerType.GetMethod("LocalTeleport", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3]
{
_vector3Type,
typeof(float),
typeof(bool)
}, null);
}
}
private void RefreshServer()
{
if (_serverType == null)
{
_serverType = ResolveType("Server", "Assembly-CSharp");
}
if (_serverType == null)
{
return;
}
try
{
Array array = FindUnityObjectsOfType(_serverType);
if (array == null || array.Length == 0)
{
return;
}
object obj = null;
for (int i = 0; i < array.Length; i++)
{
object value = array.GetValue(i);
if (value != null)
{
if (obj == null)
{
obj = value;
}
if (ReadStringProperty(value, "name") == "Server(Clone)")
{
_server = value;
return;
}
}
}
_server = obj;
}
catch
{
}
}
private bool TeleportToMapPoint(float requestedX, float requestedZ, int nearestIsland, float yaw, string requiredSceneName, bool preferIslandLand)
{
if (_localPlayer == null)
{
RefreshLocalPlayer();
}
if (_localPlayer == null)
{
LogWarning("Teleport failed: live PlayerHolder(Clone) was not found.");
return false;
}
if (_serverTeleportPlayer == null || _playerLocalTeleport == null)
{
ResolveTeleportApi();
}
if (_server == null)
{
RefreshServer();
}
float safeX = requestedX;
float safeY = 3f;
float safeZ = requestedZ;
string surfaceName;
bool flag = TryFindSolidGroundNearIsland(requestedX, requestedZ, requiredSceneName, preferIslandLand, out safeX, out safeY, out safeZ, out surfaceName);
if (!flag)
{
flag = TryFindSolidGroundNearIsland(requestedX, requestedZ, string.Empty, preferIslandLand, out safeX, out safeY, out safeZ, out surfaceName);
}
if (flag)
{
LogInfo((preferIslandLand ? "ANYWHERE island-land landing -> surface=" : "ANYWHERE ground-safe landing -> surface=") + surfaceName + " pos=(" + safeX.ToString("0.00") + ", " + safeY.ToString("0.00") + ", " + safeZ.ToString("0.00") + ")" + ((nearestIsland >= 0 && nearestIsland < IslandNames.Length) ? (" nearest=" + IslandNames[nearestIsland]) : string.Empty));
}
else
{
safeX = requestedX;
safeY = 3f;
safeZ = requestedZ;
LogWarning("No solid ground at clicked map point; using exact X/Z fallback at Y=" + 3f.ToString("0.00") + ".");
}
object obj = CreateVector3(safeX, safeY, safeZ);
if (obj == null)
{
LogWarning("Teleport failed: Vector3 could not be created.");
return false;
}
if (_server != null && _serverTeleportPlayer != null)
{
try
{
_serverTeleportPlayer.Invoke(_server, new object[3] { _localPlayer, obj, yaw });
LogInfo("Teleport route: Server.TeleportPlayer");
return true;
}
catch (Exception ex)
{
LogWarning("Server.TeleportPlayer failed: " + ex.Message);
}
}
if (_playerLocalTeleport != null)
{
try
{
_playerLocalTeleport.Invoke(_localPlayer, new object[3] { obj, yaw, true });
LogInfo("Teleport route fallback: Player.LocalTeleport");
return true;
}
catch (Exception ex2)
{
LogWarning("Player.LocalTeleport fallback failed: " + ex2.Message);
}
}
LogWarning("Teleport failed: no usable native teleport route was available.");
return false;
}
private void ResolvePhysicsApi()
{
if (_physicsType == null)
{
_physicsType = ResolveType("UnityEngine.Physics", "UnityEngine.PhysicsModule");
}
if (_vector3Type == null)
{
_vector3Type = ResolveType("UnityEngine.Vector3", "UnityEngine.CoreModule");
}
if (_raycastHitType == null)
{
_raycastHitType = ResolveType("UnityEngine.RaycastHit", "UnityEngine.PhysicsModule");
}
if (_queryTriggerInteractionType == null)
{
_queryTriggerInteractionType = ResolveType("UnityEngine.QueryTriggerInteraction", "UnityEngine.PhysicsModule");
}
if (_physicsType == null || _vector3Type == null)
{
return;
}
try
{
MethodInfo[] methods = _physicsType.GetMethods(BindingFlags.Static | BindingFlags.Public);
MethodInfo methodInfo = null;
foreach (MethodInfo methodInfo2 in methods)
{
if (methodInfo2.Name != "RaycastAll")
{
continue;
}
ParameterInfo[] parameters = methodInfo2.GetParameters();
if (parameters.Length >= 3 && parameters.Length <= 5 && !(parameters[0].ParameterType != _vector3Type) && !(parameters[1].ParameterType != _vector3Type) && !(parameters[2].ParameterType != typeof(float)) && methodInfo2.ReturnType.IsArray)
{
if (parameters.Length == 3)
{
_physicsRaycastAll = methodInfo2;
return;
}
if (methodInfo == null)
{
methodInfo = methodInfo2;
}
}
}
_physicsRaycastAll = methodInfo;
}
catch
{
}
}
private bool TryFindSolidGroundNearIsland(float baseX, float baseZ, string requiredSceneName, bool allowLowIslandGround, out float safeX, out float safeY, out float safeZ, out string surfaceName)
{
safeX = baseX;
safeY = 1.5f;
safeZ = baseZ;
surfaceName = "none";
if (_physicsRaycastAll == null)
{
ResolvePhysicsApi();
}
if (_physicsRaycastAll == null)
{
return false;
}
if (TryProbeSolidGround(baseX, baseZ, requiredSceneName, allowLowIslandGround, out var groundY, out var surfaceName2, out var lowSurfaceFound))
{
safeX = baseX;
safeY = groundY + 1.75f;
if (!allowLowIslandGround && safeY < 3f)
{
safeY = 3f;
}
safeZ = baseZ;
surfaceName = surfaceName2;
return true;
}
if (lowSurfaceFound)
{
LogInfo("Clicked point is over low/submerged ground; keeping exact X/Z and using the water-safe fallback height.");
return false;
}
for (int i = 1; i < GroundProbeOffsetX.Length && i < GroundProbeOffsetZ.Length; i++)
{
float num = baseX + GroundProbeOffsetX[i];
float num2 = baseZ + GroundProbeOffsetZ[i];
if (TryProbeSolidGround(num, num2, requiredSceneName, allowLowIslandGround, out var groundY2, out var surfaceName3, out var _))
{
safeX = num;
safeY = groundY2 + 1.75f;
if (!allowLowIslandGround && safeY < 3f)
{
safeY = 3f;
}
safeZ = num2;
surfaceName = surfaceName3;
return true;
}
}
return false;
}
private bool TryProbeSolidGround(float x, float z, string requiredSceneName, bool allowLowIslandGround, out float groundY, out string surfaceName, out bool lowSurfaceFound)
{
groundY = 0f;
surfaceName = "none";
lowSurfaceFound = false;
if (_physicsRaycastAll == null)
{
return false;
}
try
{
object obj = CreateVector3(x, 250f, z);
object obj2 = CreateVector3(0f, -1f, 0f);
if (obj == null || obj2 == null)
{
return false;
}
ParameterInfo[] parameters = _physicsRaycastAll.GetParameters();
object[] parameters2;
if (parameters.Length == 3)
{
parameters2 = new object[3] { obj, obj2, 500f };
}
else if (parameters.Length == 4)
{
parameters2 = new object[4] { obj, obj2, 500f, -1 };
}
else
{
if (parameters.Length != 5)
{
return false;
}
object obj3 = null;
if (_queryTriggerInteractionType != null)
{
try
{
obj3 = Enum.Parse(_queryTriggerInteractionType, "Ignore");
}
catch
{
obj3 = Enum.ToObject(_queryTriggerInteractionType, 1);
}
}
parameters2 = new object[5] { obj, obj2, 500f, -1, obj3 };
}
if (!(_physicsRaycastAll.Invoke(null, parameters2) is Array { Length: not 0 } array))
{
return false;
}
bool flag = false;
float num = float.MinValue;
string text = "unknown";
for (int i = 0; i < array.Length; i++)
{
object value = array.GetValue(i);
if (value == null)
{
continue;
}
object obj5 = ReadPropertyValue(value, "collider");
if (obj5 == null || ReadBoolProperty(obj5, "isTrigger", fallback: false))
{
continue;
}
string text2 = ReadStringProperty(obj5, "name");
string text3 = text2;
object obj6 = ReadPropertyValue(obj5, "transform");
if (obj6 != null)
{
string text4 = ReadStringProperty(obj6, "name");
if (!string.IsNullOrEmpty(text4))
{
text3 = text3 + "/" + text4;
}
object obj7 = ReadPropertyValue(obj6, "gameObject");
if (obj7 != null)
{
string text5 = ReadStringProperty(obj7, "name");
if (!string.IsNullOrEmpty(text5))
{
text3 = text3 + "/" + text5;
}
}
}
if (LooksLikeNonGroundCollider(text3))
{
continue;
}
string colliderSceneName = GetColliderSceneName(obj5);
if (!string.IsNullOrEmpty(requiredSceneName) && !string.Equals(colliderSceneName, requiredSceneName, StringComparison.OrdinalIgnoreCase))
{
continue;
}
object obj8 = ReadPropertyValue(value, "normal");
if (obj8 != null && TryReadVector3Y(obj8, out var y) && y < 0.45f)
{
continue;
}
object obj9 = ReadPropertyValue(value, "point");
if (obj9 != null && TryReadVector3Y(obj9, out var y2))
{
if (!allowLowIslandGround && y2 + 1.75f < 3f)
{
lowSurfaceFound = true;
}
else if (!flag || y2 > num)
{
flag = true;
num = y2;
text = (string.IsNullOrEmpty(text2) ? "solid collider" : text2);
}
}
}
if (flag)
{
groundY = num;
surfaceName = text;
return true;
}
}
catch (Exception ex)
{
LogWarning("Ground probe failed: " + ex.Message);
}
return false;
}
private static string GetColliderSceneName(object collider)
{
if (collider == null)
{
return string.Empty;
}
try
{
object obj = ReadPropertyValue(collider, "gameObject");
if (obj == null)
{
object obj2 = ReadPropertyValue(collider, "transform");
if (obj2 != null)
{
obj = ReadPropertyValue(obj2, "gameObject");
}
}
if (obj == null)
{
return string.Empty;
}
object obj3 = ReadPropertyValue(obj, "scene");
if (obj3 == null)
{
return string.Empty;
}
PropertyInfo property = obj3.GetType().GetProperty("name", BindingFlags.Instance | BindingFlags.Public);
if (property == null)
{
return string.Empty;
}
object value = property.GetValue(obj3, null);
return (value == null) ? string.Empty : value.ToString();
}
catch
{
return string.Empty;
}
}
private static bool LooksLikeNonGroundCollider(string name)
{
if (string.IsNullOrEmpty(name))
{
return false;
}
string text = name.ToLowerInvariant();
string[] array = new string[29]
{
"water", "ocean", "sea", "trigger", "player", "boat", "item", "creature", "fish", "projectile",
"bullet", "dynamicobject", "pickup", "radar", "camera", "volume", "killbox", "death", "hurt", "damage",
"armupper", "armlower", "hand", "ragdoll", "character", "npc", "foot", "head", "hitbox"
};
for (int i = 0; i < array.Length; i++)
{
if (text.IndexOf(array[i], StringComparison.Ordinal) >= 0)
{
return true;
}
}
return false;
}
private static object ReadPropertyValue(object instance, string propertyName)
{
if (instance == null)
{
return null;
}
try
{
PropertyInfo property = instance.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null)
{
return property.GetValue(instance, null);
}
}
catch
{
}
return null;
}
private static bool ReadBoolProperty(object instance, string propertyName, bool fallback)
{
try
{
object obj = ReadPropertyValue(instance, propertyName);
if (obj != null)
{
return Convert.ToBoolean(obj);
}
}
catch
{
}
return fallback;
}
private static bool TryReadVector3XZ(object vector, out float x, out float z)
{
x = 0f;
z = 0f;
if (vector == null)
{
return false;
}
try
{
FieldInfo field = vector.GetType().GetField("x", BindingFlags.Instance | BindingFlags.Public);
FieldInfo field2 = vector.GetType().GetField("z", BindingFlags.Instance | BindingFlags.Public);
if (field != null && field2 != null)
{
x = Convert.ToSingle(field.GetValue(vector));
z = Convert.ToSingle(field2.GetValue(vector));
return true;
}
PropertyInfo property = vector.GetType().GetProperty("x", BindingFlags.Instance | BindingFlags.Public);
PropertyInfo property2 = vector.GetType().GetProperty("z", BindingFlags.Instance | BindingFlags.Public);
if (property != null && property2 != null)
{
x = Convert.ToSingle(property.GetValue(vector, null));
z = Convert.ToSingle(property2.GetValue(vector, null));
return true;
}
}
catch
{
}
return false;
}
private static bool TryReadVector3Y(object vector, out float y)
{
y = 0f;
if (vector == null)
{
return false;
}
try
{
FieldInfo field = vector.GetType().GetField("y", BindingFlags.Instance | BindingFlags.Public);
if (field != null)
{
y = Convert.ToSingle(field.GetValue(vector));
return true;
}
PropertyInfo property = vector.GetType().GetProperty("y", BindingFlags.Instance | BindingFlags.Public);
if (property != null)
{
y = Convert.ToSingle(property.GetValue(vector, null));
return true;
}
}
catch
{
}
return false;
}
private object CreateVector3(float x, float y, float z)
{
if (_vector3Type == null)
{
_vector3Type = ResolveType("UnityEngine.Vector3", "UnityEngine.CoreModule");
}
if (_vector3Type == null)
{
return null;
}
try
{
return Activator.CreateInstance(_vector3Type, x, y, z);
}
catch
{
return null;
}
}
private bool GetMouseButtonDown(int button)
{
if (_getMouseButtonDown == null)
{
return false;
}
try
{
return Convert.ToBoolean(_getMouseButtonDown.Invoke(null, new object[1] { button }));
}
catch
{
return false;
}
}
private void DrawTexture(object rect, object texture)
{
if (_drawTexture4 != null && _scaleStretch != null)
{
_drawTexture4.Invoke(null, new object[4] { rect, texture, _scaleStretch, false });
}
else if (_drawTexture2 != null)
{
_drawTexture2.Invoke(null, new object[2] { rect, texture });
}
}
private void DrawPlayerIndicator(float centerX, float centerY, float yawDegrees, float size)
{
int num = (int)Math.Round(size * 1.18f);
if (num < 25)
{
num = 25;
}
if (num > 54)
{
num = 54;
}
BuildIndicatorStyles(num);
float num2 = size * 1.2f;
float num3 = size * 0.88f;
float num4 = size * 0.34f;
if (_label3 != null && _haloStyle != null && _ringStyle != null)
{
SetGuiColor(_whiteColor);
_label3.Invoke(null, new object[3]
{
NewRect(centerX - num2 * 0.5f, centerY - num2 * 0.53f, num2, num2),
"●",
_haloStyle
});
_label3.Invoke(null, new object[3]
{
NewRect(centerX - num3 * 0.5f, centerY - num3 * 0.53f, num3, num3),
"●",
_ringStyle
});
_label3.Invoke(null, new object[3]
{
NewRect(centerX - num3 * 0.38f, centerY - num3 * 0.405f, num3 * 0.76f, num3 * 0.76f),
"●",
_haloStyle
});
}
DrawRotatingPointer(centerX, centerY, yawDegrees, size);
if (_label3 != null && _centerStyle != null)
{
SetGuiColor(_whiteColor);
_label3.Invoke(null, new object[3]
{
NewRect(centerX - num4 * 0.5f, centerY - num4 * 0.54f, num4, num4),
"●",
_centerStyle
});
}
}
private void DrawRotatingPointer(float centerX, float centerY, float yawDegrees, float size)
{
float num = centerX - size * 0.5f;
float num2 = centerY - size * 0.62f;
float num3 = Math.Max(1f, size * 0.055f);
object obj = null;
bool flag = false;
try
{
if (_guiMatrix != null && _rotateAroundPivot != null && _vector2Type != null)
{
obj = _guiMatrix.GetValue(null, null);
object obj2 = Activator.CreateInstance(_vector2Type, centerX, centerY);
_rotateAroundPivot.Invoke(null, new object[2]
{
NormalizeAngle(yawDegrees),
obj2
});
flag = true;
}
string text = (flag ? "▲" : GetArrowGlyph(yawDegrees));
if (_label3 != null && _indicatorStyle != null && _indicatorShadowStyle != null)
{
SetGuiColor(_whiteColor);
_label3.Invoke(null, new object[3]
{
NewRect(num - num3, num2, size, size),
text,
_indicatorShadowStyle
});
_label3.Invoke(null, new object[3]
{
NewRect(num + num3, num2, size, size),
text,
_indicatorShadowStyle
});
_label3.Invoke(null, new object[3]
{
NewRect(num, num2 - num3, size, size),
text,
_indicatorShadowStyle
});
_label3.Invoke(null, new object[3]
{
NewRect(num, num2 + num3, size, size),
text,
_indicatorShadowStyle
});
_label3.Invoke(null, new object[3]
{
NewRect(num, num2, size, size),
text,
_indicatorStyle
});
}
else
{
SetGuiColor(_blackColor);
DrawLabel(NewRect(num - num3, num2, size, size), text);
DrawLabel(NewRect(num + num3, num2, size, size), text);
SetGuiColor(_yellowColor);
DrawLabel(NewRect(num, num2, size, size), text);
}
}
catch
{
}
finally
{
if (flag && obj != null && _guiMatrix != null)
{
try
{
_guiMatrix.SetValue(null, obj, null);
}
catch
{
}
}
}
}
private void BuildIndicatorStyles(int fontSize)
{
if (_guiStyleType == null)
{
return;
}
try
{
if (_indicatorStyle == null)
{
_indicatorStyle = Activator.CreateInstance(_guiStyleType);
}
if (_indicatorShadowStyle == null)
{
_indicatorShadowStyle = Activator.CreateInstance(_guiStyleType);
}
if (_haloStyle == null)
{
_haloStyle = Activator.CreateInstance(_guiStyleType);
}
if (_ringStyle == null)
{
_ringStyle = Activator.CreateInstance(_guiStyleType);
}
if (_centerStyle == null)
{
_centerStyle = Activator.CreateInstance(_guiStyleType);
}
SetPropertyIfPresent(_indicatorStyle, "fontSize", fontSize);
SetPropertyIfPresent(_indicatorShadowStyle, "fontSize", fontSize);
SetPropertyIfPresent(_haloStyle, "fontSize", (int)Math.Round((float)fontSize * 1.12f));
SetPropertyIfPresent(_ringStyle, "fontSize", (int)Math.Round((float)fontSize * 0.88f));
SetPropertyIfPresent(_centerStyle, "fontSize", Math.Max(10, (int)Math.Round((float)fontSize * 0.34f)));
if (_textAnchorType != null)
{
object value = Enum.Parse(_textAnchorType, "MiddleCenter");
SetPropertyIfPresent(_indicatorStyle, "alignment", value);
SetPropertyIfPresent(_indicatorShadowStyle, "alignment", value);
SetPropertyIfPresent(_haloStyle, "alignment", value);
SetPropertyIfPresent(_ringStyle, "alignment", value);
SetPropertyIfPresent(_centerStyle, "alignment", value);
}
SetGuiStyleTextColor(_indicatorStyle, _yellowColor);
SetGuiStyleTextColor(_indicatorShadowStyle, _blackColor);
SetGuiStyleTextColor(_haloStyle, _haloColor);
SetGuiStyleTextColor(_ringStyle, _softGoldColor);
SetGuiStyleTextColor(_centerStyle, _centerColor);
}
catch
{
}
}
private void SetGuiStyleTextColor(object style, object color)
{
if (style == null || color == null)
{
return;
}
try
{
PropertyInfo property = style.GetType().GetProperty("normal", BindingFlags.Instance | BindingFlags.Public);
if (property == null)
{
return;
}
object value = property.GetValue(style, null);
if (value != null)
{
PropertyInfo property2 = value.GetType().GetProperty("textColor", BindingFlags.Instance | BindingFlags.Public);
if (property2 != null && property2.CanWrite)
{
property2.SetValue(value, color, null);
}
}
}
catch
{
}
}
private string GetArrowGlyph(float yawDegrees)
{
float num = NormalizeAngle(yawDegrees);
return ((int)Math.Round((double)num / 45.0) % 8) switch
{
0 => "▲",
1 => "◥",
2 => "▶",
3 => "◢",
4 => "▼",
5 => "◣",
6 => "◀",
_ => "◤",
};
}
private void DrawLabel(object rect, string text)
{
if (_label2 != null)
{
_label2.Invoke(null, new object[2] { rect, text });
}
}
private void DrawSolidRect(float x, float y, float w, float h, object color)
{
if (_whiteTexture != null && !(_drawTexture2 == null))
{
object guiColor = GetGuiColor();
SetGuiColor(color);
_drawTexture2.Invoke(null, new object[2]
{
NewRect(x, y, w, h),
_whiteTexture
});
SetGuiColor(guiColor);
}
}
private void GetNavigationState(out float x, out float z, out float yawDegrees)
{
x = 0f;
z = 0f;
yawDegrees = 0f;
if (_localPlayerTransform == null || _frameCounter % 30 == 0)
{
RefreshLocalPlayer();
}
object localPlayerTransform = _localPlayerTransform;
if (localPlayerTransform == null)
{
return;
}
try
{
PropertyInfo property = localPlayerTransform.GetType().GetProperty("position", BindingFlags.Instance | BindingFlags.Public);
if (property != null)
{
object value = property.GetValue(localPlayerTransform, null);
if (value != null)
{
FieldInfo field = value.GetType().GetField("x", BindingFlags.Instance | BindingFlags.Public);
FieldInfo field2 = value.GetType().GetField("z", BindingFlags.Instance | BindingFlags.Public);
if (field != null)
{
x = Convert.ToSingle(field.GetValue(value));
}
if (field2 != null)
{
z = Convert.ToSingle(field2.GetValue(value));
}
}
}
if (TryGetLivePlayerLookYaw(out var yawDegrees2))
{
yawDegrees = yawDegrees2;
return;
}
if (TryGetPlayerCamObjectYaw(out yawDegrees2))
{
yawDegrees = yawDegrees2;
return;
}
if (TryGetCameraYaw(out yawDegrees2))
{
yawDegrees = yawDegrees2;
return;
}
yawDegrees = ReadTransformYaw(localPlayerTransform);
_lastYawSource = "LocalPlayer.Transform";
}
catch
{
}
}
private bool TryGetLivePlayerLookYaw(out float yawDegrees)
{
yawDegrees = 0f;
if (_localPlayer == null || _playerType == null)
{
return false;
}
try
{
if (_playerCameraField == null)
{
_playerCameraField = _playerType.GetField("_camera", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
if (_playerCameraField == null)
{
return false;
}
object value = _playerCameraField.GetValue(_localPlayer);
if (value == null)
{
return false;
}
if (_playerCameraRotField == null || _playerCameraRotField.DeclaringType != value.GetType())
{
_playerCameraRotField = value.GetType().GetField("_rot", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
if (_playerCameraRotField == null)
{
return false;
}
object value2 = _playerCameraRotField.GetValue(value);
if (value2 == null)
{
return false;
}
FieldInfo field = value2.GetType().GetField("y", BindingFlags.Instance | BindingFlags.Public);
if (field == null)
{
return false;
}
yawDegrees = NormalizeAngle(Convert.ToSingle(field.GetValue(value2)));
_lastYawSource = "PlayerCamera._rot.y";
return true;
}
catch
{
return false;
}
}
private bool TryGetPlayerCamObjectYaw(out float yawDegrees)
{
yawDegrees = 0f;
if (_localPlayer == null || _playerType == null)
{
return false;
}
try
{
if (_playerCamObjectField == null)
{
_playerCamObjectField = _playerType.GetField("<CamObject>k__BackingField", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
if (_playerCamObjectField == null)
{
return false;
}
object value = _playerCamObjectField.GetValue(_localPlayer);
if (value == null)
{
return false;
}
yawDegrees = NormalizeAngle(ReadTransformYaw(value));
_lastYawSource = "Player.CamObject";
return true;
}
catch
{
return false;
}
}
private bool TryGetCameraYaw(out float yawDegrees)
{
yawDegrees = 0f;
if (_camera == null)
{
return false;
}
try
{
PropertyInfo property = _camera.GetType().GetProperty("transform", BindingFlags.Instance | BindingFlags.Public);
if (property == null)
{
return false;
}
object value = property.GetValue(_camera, null);
if (value == null)
{
return false;
}
yawDegrees = ReadTransformYaw(value);
_lastYawSource = "Camera.main";
return true;
}
catch
{
return false;
}
}
private float ReadTransformYaw(object transform)
{
if (transform == null)
{
return 0f;
}
try
{
PropertyInfo property = transform.GetType().GetProperty("eulerAngles", BindingFlags.Instance | BindingFlags.Public);
if (property == null)
{
return 0f;
}
object value = property.GetValue(transform, null);
if (value == null)
{
return 0f;
}
FieldInfo field = value.GetType().GetField("y", BindingFlags.Instance | BindingFlags.Public);
if (field != null)
{
return Convert.ToSingle(field.GetValue(value));
}
}
catch
{
}
return 0f;
}
private void RefreshLocalPlayer()
{
if (_playerType == null)
{
_playerType = ResolveType("Player", "Assembly-CSharp");
}
if (_playerType == null)
{
return;
}
try
{
Array array = FindUnityObjectsOfType(_playerType);
if (array == null || array.Length == 0)
{
return;
}
object obj = null;
object obj2 = null;
for (int i = 0; i < array.Length; i++)
{
object value = array.GetValue(i);
if (value == null)
{
continue;
}
object playerNavigationTransform = GetPlayerNavigationTransform(value);
if (playerNavigationTransform != null)
{
string text = ReadStringProperty(value, "name");
if (text == "PlayerHolder(Clone)")
{
obj = value;
obj2 = playerNavigationTransform;
break;
}
if (obj == null)
{
obj = value;
obj2 = playerNavigationTransform;
}
}
}
if (obj != null && obj2 != null)
{
bool flag = !object.ReferenceEquals(_localPlayer, obj);
_localPlayer = obj;
_localPlayerTransform = obj2;
if (flag)
{
LogInfo("Player tracker locked to live PlayerHolder(Clone) Transform.");
}
}
}
catch
{
}
}
private object GetPlayerNavigationTransform(object player)
{
if (player == null)
{
return null;
}
try
{
if (_playerTransformField == null)
{
_playerTransformField = _playerType.GetField("<Transform>k__BackingField", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
if (_playerTransformField != null)
{
object value = _playerTransformField.GetValue(player);
if (value != null)
{
return value;
}
}
PropertyInfo property = _playerType.GetProperty("Transform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null)
{
object value2 = property.GetValue(player, null);
if (value2 != null)
{
return value2;
}
}
}
catch
{
}
return null;
}
private Array FindUnityObjectsOfType(Type wantedType)
{
try
{
Type type = ResolveType("UnityEngine.Object", "UnityEngine.CoreModule");
if (type != null)
{
MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
foreach (MethodInfo methodInfo in methods)
{
if (methodInfo.Name != "FindObjectsOfType")
{
continue;
}
ParameterInfo[] parameters = methodInfo.GetParameters();
object obj = null;
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(Type))
{
obj = methodInfo.Invoke(null, new object[1] { wantedType });
}
else
{
if (parameters.Length != 2 || !(parameters[0].ParameterType == typeof(Type)) || !(parameters[1].ParameterType == typeof(bool)))
{
continue;
}
obj = methodInfo.Invoke(null, new object[2] { wantedType, true });
}
if (obj is Array { Length: >0 } array)
{
return array;
}
}
}
}
catch
{
}
try
{
Type type2 = ResolveType("UnityEngine.Resources", "UnityEngine.CoreModule");
if (type2 != null)
{
MethodInfo method = type2.GetMethod("FindObjectsOfTypeAll", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Type) }, null);
if (method != null)
{
return method.Invoke(null, new object[1] { wantedType }) as Array;
}
}
}
catch
{
}
return null;
}
private void OpenFullMap()
{
if (!_fullMapOpen)
{
SaveCursorState();
_fullMapOpen = true;
RefreshPlayerCamera();
RefreshLocalPlayer();
GetNavigationState(out var x, out var z, out var yawDegrees);
_frozenMapYaw = NormalizeAngle(yawDegrees);
_frozenMapYawValid = true;
string lastYawSource = _lastYawSource;
WorldToMapNormalizedAuto(x, z, out var u, out var screenV, out var mappedIsland);
LogInfo("Map tracker world position: X=" + x.ToString("0.00") + " Z=" + z.ToString("0.00") + " frozenYaw=" + _frozenMapYaw.ToString("0.0") + " source=" + lastYawSource + " -> map=(" + u.ToString("0.000") + "," + screenV.ToString("0.000") + ")" + ((mappedIsland >= 0) ? (" lockedBounds=" + IslandNames[mappedIsland]) : " globalFallback"));
TryTogglePlayerMouse(unlock: true);
DisablePlayerCameraForMap();
ForceCursorUnlocked();
}
}
private void CloseFullMap()
{
if (_fullMapOpen)
{
_fullMapOpen = false;
_frozenMapYawValid = false;
RestorePlayerCameraAfterMap();
TryTogglePlayerMouse(unlock: false);
RestoreCursorState();
}
}
private void RefreshPlayerCamera()
{
if (_playerCameraType == null)
{
_playerCameraType = ResolveType("PlayerCamera", "Assembly-CSharp");
}
if (_playerCameraType == null)
{
return;
}
object obj = null;
if (_camera != null)
{
try
{
MethodInfo[] methods = _camera.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
for (int i = 0; i < methods.Length; i++)
{
if (obj != null)
{
break;
}
MethodInfo methodInfo = methods[i];
if (!(methodInfo.Name != "GetComponentInParent"))
{
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(Type))
{
obj = methodInfo.Invoke(_camera, new object[1] { _playerCameraType });
}
else if (parameters.Length == 2 && parameters[0].ParameterType == typeof(Type) && parameters[1].ParameterType == typeof(bool))
{
obj = methodInfo.Invoke(_camera, new object[2] { _playerCameraType, true });
}
}
}
}
catch
{
}
}
if (obj == null)
{
obj = FindUnityObjectOfType(_playerCameraType);
}
if (obj != null)
{
_playerCamera = obj;
_toggleMouse = _playerCameraType.GetMethod("ToggleMouse", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(bool) }, null);
_playerCameraEnabled = _playerCameraType.GetProperty("enabled", BindingFlags.Instance | BindingFlags.Public);
}
}
private object FindUnityObjectOfType(Type wantedType)
{
try
{
Type type = ResolveType("UnityEngine.Object", "UnityEngine.CoreModule");
if (type == null)
{
return null;
}
MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
foreach (MethodInfo methodInfo in methods)
{
if (methodInfo.Name != "FindObjectsOfType")
{
continue;
}
ParameterInfo[] parameters = methodInfo.GetParameters();
object obj = null;
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(Type))
{
obj = methodInfo.Invoke(null, new object[1] { wantedType });
}
else
{
if (parameters.Length != 2 || !(parameters[0].ParameterType == typeof(Type)) || !(parameters[1].ParameterType == typeof(bool)))
{
continue;
}
obj = methodInfo.Invoke(null, new object[2] { wantedType, true });
}
if (!(obj is Array { Length: >0 } array))
{
continue;
}
for (int j = 0; j < array.Length; j++)
{
object value = array.GetValue(j);
if (value != null)
{
return value;
}
}
}
}
catch
{
}
try
{
Type type2 = ResolveType("UnityEngine.Resources", "UnityEngine.CoreModule");
if (type2 != null)
{
MethodInfo method = type2.GetMethod("FindObjectsOfTypeAll", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(Type) }, null);
if (method != null && method.Invoke(null, new object[1] { wantedType }) is Array { Length: >0 } array2)
{
for (int k = 0; k < array2.Length; k++)
{
object value2 = array2.GetValue(k);
if (value2 != null)
{
return value2;
}
}
}
}
}
catch
{
}
return null;
}
private void SaveCursorState()
{
try
{
if (_cursorVisible != null)
{
_oldCursorVisible = Convert.ToBoolean(_cursorVisible.GetValue(null, null));
}
if (_cursorLockState != null)
{
_oldCursorLock = _cursorLockState.GetValue(null, null);
}
}
catch
{
}
}
private void ForceCursorUnlocked()
{
try
{
if (_cursorVisible != null)
{
_cursorVisible.SetValue(null, true, null);
}
if (_cursorLockState != null && _cursorNone != null)
{
_cursorLockState.SetValue(null, _cursorNone, null);
}
}
catch
{
}
}
private void RestoreCursorState()
{
try
{
if (_cursorVisible != null)
{
_cursorVisible.SetValue(null, _oldCursorVisible, null);
}
if (_cursorLockState != null && _oldCursorLock != null)
{
_cursorLockState.SetValue(null, _oldCursorLock, null);
}
}
catch
{
}
}
private void DisablePlayerCameraForMap()
{
try
{
if (_playerCamera == null || _playerCameraEnabled == null)
{
RefreshPlayerCamera();
}
if (_playerCamera == null || _playerCameraEnabled == null)
{
LogWarning("PlayerCamera was not found; cursor unlocked but hard camera lock is unavailable.");
return;
}
_oldPlayerCameraEnabled = Convert.ToBoolean(_playerCameraEnabled.GetValue(_playerCamera, null));
_playerCameraEnabled.SetValue(_playerCamera, false, null);
_playerCameraDisabledByMap = true;
LogInfo("Map camera lock: PlayerCamera disabled.");
}
catch (Exception ex)
{
LogWarning("Could not disable PlayerCamera: " + ex.Message);
}
}
private void RestorePlayerCameraAfterMap()
{
if (!_playerCameraDisabledByMap)
{
return;
}
try
{
if (_playerCamera != null && _playerCameraEnabled != null)
{
_playerCameraEnabled.SetValue(_playerCamera, _oldPlayerCameraEnabled, null);
}
}
catch
{
}
_playerCameraDisabledByMap = false;
}
private bool TryTogglePlayerMouse(bool unlock)
{
try
{
if (_playerCamera == null || _toggleMouse == null)
{
RefreshPlayerCamera();
}
if (_playerCamera == null || _toggleMouse == null)
{
return false;
}
_toggleMouse.Invoke(_playerCamera, new object[1] { unlock });
return true;
}
catch
{
return false;
}
}
private bool GetKeyDown(object key)
{
if (_getKeyDown == null || key == null)
{
return false;
}
try
{
return Convert.ToBoolean(_getKeyDown.Invoke(null, new object[1] { key }));
}
catch
{
return false;
}
}
private int GetScreenWidth()
{
try
{
return Convert.ToInt32(_screenWidth.GetValue(null, null));
}
catch
{
return 1920;
}
}
private int GetScreenHeight()
{
try
{
return Convert.ToInt32(_screenHeight.GetValue(null, null));
}
catch
{
return 1080;
}
}
private object NewRect(float x, float y, float w, float h)
{
return Activator.CreateInstance(_rectType, x, y, w, h);
}
private object NewColor(float r, float g, float b, float a)
{
return Activator.CreateInstance(_colorType, r, g, b, a);
}
private object GetGuiColor()
{
try
{
return (_guiColor == null) ? _whiteColor : _guiColor.GetValue(null, null);
}
catch
{
return _whiteColor;
}
}
private void SetGuiColor(object color)
{
if (_guiColor == null || color == null)
{
return;
}
try
{
_guiColor.SetValue(null, color, null);
}
catch
{
}
}
private static void SetPropertyIfPresent(object instance, string propertyName, object value)
{
if (instance == null)
{
return;
}
try
{
PropertyInfo property = instance.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
if (property != null && property.CanWrite)
{
property.SetValue(instance, value, null);
}
}
catch
{
}
}
private static string ReadStringProperty(object instance, string propertyName)
{
try
{
PropertyInfo property = instance.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
if (property != null)
{
object value = property.GetValue(instance, null);
return (value == null) ? string.Empty : value.ToString();
}
}
catch
{
}
return string.Empty;
}
private static int ReadIntProperty(object instance, string propertyName, int fallback)
{
try
{
PropertyInfo property = instance.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
if (property != null)
{
return Convert.ToInt32(property.GetValue(instance, null));
}
}
catch
{
}
return fallback;
}
private static void WorldToMapNormalized(float worldX, float worldZ, out float u, out float screenV)
{
u = 0.0006040856f * worldX + 0.5680561f;
screenV = -0.0005951446f * worldZ + 0.4647192f;
u = Clamp(u, 0.045f, 0.955f);
screenV = Clamp(screenV, 0.04f, 0.955f);
}
private static void MapNormalizedToWorld(float u, float screenV, out float worldX, out float worldZ)
{
worldX = (u - 0.5680561f) / 0.0006040856f;
worldZ = (screenV - 0.4647192f) / -0.0005951446f;
}
private static float NormalizeAngle(float degrees)
{
while (degrees < 0f)
{
degrees += 360f;
}
while (degrees >= 360f)
{
degrees -= 360f;
}
return degrees;
}
private static float InverseLerp(float a, float b, float value)
{
if (Math.Abs(b - a) < 0.0001f)
{
return 0.5f;
}
return Clamp((value - a) / (b - a), 0f, 1f);
}
private static float Clamp(float value, float min, float max)
{
if (value < min)
{
return min;
}
if (value > max)
{
return max;
}
return value;
}
private static MethodInfo FindStaticMethod(Type type, string name, Type[] parameterTypes)
{
if (type == null)
{
return null;
}
try
{
return type.GetMethod(name, BindingFlags.Static | BindingFlags.Public, null, parameterTypes, null);
}
catch
{
return null;
}
}
private static Type ResolveType(string fullName, params string[] assemblyNames)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int i = 0; i < assemblies.Length; i++)
{
try
{
Type type = assemblies[i].GetType(fullName, throwOnError: false);
if (type != null)
{
return type;
}
}
catch
{
}
}
if (assemblyNames != null)
{
for (int i = 0; i < assemblyNames.Length; i++)
{
try
{
Assembly assembly = Assembly.Load(assemblyNames[i]);
Type type2 = assembly.GetType(fullName, throwOnError: false);
if (type2 != null)
{
return type2;
}
}
catch
{
}
}
}
return null;
}
}