Files
2026-07-13 12:49:17 +08:00

262 lines
9.4 KiB
C#

using System;
using System.Reflection;
using UnityEngine;
namespace MCPForUnity.Runtime.Helpers
{
// Part of MCP for Unity's compat-shim family. See UnityCompatShims.cs in this
// folder for the full list of shims, the audit policy, and the reflection pattern.
/// <summary>
/// Version-compatible wrappers for Physics / Physics2D properties whose surface
/// changes across Unity versions.
///
/// Currently covered:
/// - Physics.autoSyncTransforms (deprecated in Unity 6.x; replacement is Physics.SyncTransforms())
/// - Physics2D.autoSyncTransforms (deprecated in Unity 6.x; replacement is Physics2D.SyncTransforms())
/// - Physics.autoSimulation (deprecated in 2022.2; replacement is Physics.simulationMode)
///
/// We use reflection rather than direct property access so calls stay clean of
/// CS0618 warnings AND survive eventual removal of the obsolete property without
/// a recompile of this package.
/// </summary>
public static class UnityPhysicsCompat
{
/// <summary>
/// Cross-version description of the 3D physics simulation mode.
/// On 2022.2+ this maps onto <c>UnityEngine.SimulationMode</c>; on older
/// versions it represents the on/off semantics of <c>autoSimulation</c>.
/// </summary>
public enum SimulationMode
{
FixedUpdate,
Update,
Script,
Unknown,
}
// ---------- Physics2D ----------
private static PropertyInfo _physics2DAutoSync;
private static bool _physics2DProbed;
private static PropertyInfo Physics2DAutoSyncProp
{
get
{
if (!_physics2DProbed)
{
_physics2DProbed = true;
_physics2DAutoSync = typeof(Physics2D).GetProperty(
"autoSyncTransforms",
BindingFlags.Public | BindingFlags.Static);
}
return _physics2DAutoSync;
}
}
/// <summary>
/// Reads <c>Physics2D.autoSyncTransforms</c> if the property exists in this
/// Unity version. Returns <c>null</c> if the property has been removed.
/// </summary>
public static bool? GetPhysics2DAutoSyncTransforms()
{
var prop = Physics2DAutoSyncProp;
if (prop == null || !prop.CanRead) return null;
try { return (bool)prop.GetValue(null); }
catch { return null; }
}
/// <summary>
/// Writes <c>Physics2D.autoSyncTransforms</c> if the property exists and is
/// writable. Returns <c>true</c> if the write happened, <c>false</c> if the
/// property is unavailable in this Unity version.
/// </summary>
public static bool TrySetPhysics2DAutoSyncTransforms(bool value)
{
var prop = Physics2DAutoSyncProp;
if (prop == null || !prop.CanWrite) return false;
try
{
prop.SetValue(null, value);
return true;
}
catch
{
return false;
}
}
// ---------- Physics (3D) ----------
private static PropertyInfo _physicsAutoSync;
private static bool _physicsProbed;
private static PropertyInfo PhysicsAutoSyncProp
{
get
{
if (!_physicsProbed)
{
_physicsProbed = true;
_physicsAutoSync = typeof(Physics).GetProperty(
"autoSyncTransforms",
BindingFlags.Public | BindingFlags.Static);
}
return _physicsAutoSync;
}
}
/// <summary>
/// Reads <c>Physics.autoSyncTransforms</c> if the property exists in this
/// Unity version. Returns <c>null</c> if the property has been removed.
/// </summary>
public static bool? GetPhysicsAutoSyncTransforms()
{
var prop = PhysicsAutoSyncProp;
if (prop == null || !prop.CanRead) return null;
try { return (bool)prop.GetValue(null); }
catch { return null; }
}
/// <summary>
/// Writes <c>Physics.autoSyncTransforms</c> if the property exists and is
/// writable. Returns <c>true</c> if the write happened, <c>false</c> if the
/// property is unavailable in this Unity version.
/// </summary>
public static bool TrySetPhysicsAutoSyncTransforms(bool value)
{
var prop = PhysicsAutoSyncProp;
if (prop == null || !prop.CanWrite) return false;
try
{
prop.SetValue(null, value);
return true;
}
catch
{
return false;
}
}
// ---------- Physics simulation mode (3D) ----------
// 2022.2+ : UnityEngine.Physics.simulationMode (UnityEngine.SimulationMode enum)
// <2022.2 : UnityEngine.Physics.autoSimulation (bool — true ⇔ FixedUpdate, false ⇔ Script)
private static PropertyInfo _physicsSimulationMode;
private static bool _physicsSimulationModeProbed;
private static PropertyInfo _physicsAutoSimulation;
private static bool _physicsAutoSimulationProbed;
private static PropertyInfo PhysicsSimulationModeProp
{
get
{
if (!_physicsSimulationModeProbed)
{
_physicsSimulationModeProbed = true;
_physicsSimulationMode = typeof(Physics).GetProperty(
"simulationMode",
BindingFlags.Public | BindingFlags.Static);
}
return _physicsSimulationMode;
}
}
private static PropertyInfo PhysicsAutoSimulationProp
{
get
{
if (!_physicsAutoSimulationProbed)
{
_physicsAutoSimulationProbed = true;
_physicsAutoSimulation = typeof(Physics).GetProperty(
"autoSimulation",
BindingFlags.Public | BindingFlags.Static);
}
return _physicsAutoSimulation;
}
}
/// <summary>
/// Reads the current 3D physics simulation mode in a Unity-version-agnostic way.
/// Returns <see cref="SimulationMode.Unknown"/> if neither API is available.
/// </summary>
public static SimulationMode GetPhysicsSimulationMode()
{
var modeProp = PhysicsSimulationModeProp;
if (modeProp != null && modeProp.CanRead)
{
try { return ParseSimulationMode(modeProp.GetValue(null)?.ToString()); }
catch { /* fall through */ }
}
var autoProp = PhysicsAutoSimulationProp;
if (autoProp != null && autoProp.CanRead)
{
try
{
var auto = (bool)autoProp.GetValue(null);
return auto ? SimulationMode.FixedUpdate : SimulationMode.Script;
}
catch { /* fall through */ }
}
return SimulationMode.Unknown;
}
/// <summary>
/// Sets the 3D physics simulation mode in a Unity-version-agnostic way.
/// Returns false if the requested mode isn't expressible on this Unity version
/// (e.g. Update mode on pre-2022.2).
/// </summary>
public static bool TrySetPhysicsSimulationMode(SimulationMode mode)
{
var modeProp = PhysicsSimulationModeProp;
if (modeProp != null && modeProp.CanWrite)
{
try
{
var enumType = modeProp.PropertyType;
var enumValue = Enum.Parse(enumType, mode.ToString(), ignoreCase: true);
modeProp.SetValue(null, enumValue);
return true;
}
catch { /* fall through to legacy bool path */ }
}
var autoProp = PhysicsAutoSimulationProp;
if (autoProp != null && autoProp.CanWrite)
{
try
{
switch (mode)
{
case SimulationMode.FixedUpdate:
autoProp.SetValue(null, true);
return true;
case SimulationMode.Script:
autoProp.SetValue(null, false);
return true;
// Update mode does not exist pre-2022.2 — caller must handle false.
}
}
catch { /* fall through */ }
}
return false;
}
private static SimulationMode ParseSimulationMode(string s)
{
if (string.IsNullOrEmpty(s)) return SimulationMode.Unknown;
switch (s.ToLowerInvariant())
{
case "fixedupdate": return SimulationMode.FixedUpdate;
case "update": return SimulationMode.Update;
case "script": return SimulationMode.Script;
default: return SimulationMode.Unknown;
}
}
}
}