using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BetterJump;
using BetterJump.Config;
using BetterJump.Runtime;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using Mimic.Actors;
using MimicAPI.GameAPI;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "BetterJump", "1.5.2", "DooDesch", null)]
[assembly: MelonGame("ReLUGames", "MIMESIS")]
[assembly: MelonOptionalDependencies(new string[] { "MimicAPI" })]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BetterJump")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.5.2.0")]
[assembly: AssemblyInformationalVersion("1.5.2+5c186acfd9fdcafb060b5e0dfa07a98c71075fbc")]
[assembly: AssemblyProduct("BetterJump")]
[assembly: AssemblyTitle("BetterJump")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace BetterJump
{
public sealed class Core : MelonMod
{
public override void OnInitializeMelon()
{
BetterJumpPreferences.Initialize();
((MelonBase)this).HarmonyInstance.PatchAll();
MelonLogger.Msg("BetterJump initialized. JumpVelocity={0:F2}, ForceUngroundTime={1:F2}, AirGravityScale={2:F2}", new object[3]
{
BetterJumpPreferences.JumpVelocity,
BetterJumpPreferences.ForceUngroundTime,
BetterJumpPreferences.AirGravityScale
});
}
}
}
namespace BetterJump.Patches
{
[HarmonyPatch(typeof(FakeJumper), "StartJump")]
internal static class FakeJumperPatches
{
private static void Postfix(FakeJumper __instance)
{
JumpRuntimeState.OnJumpStarted(__instance);
}
}
[HarmonyPatch(typeof(ProtoActor), "CheckGrounded")]
internal static class ProtoActorGroundedPatch
{
private static void Postfix(ProtoActor __instance)
{
JumpRuntimeState.OnGroundCheck(__instance);
}
}
[HarmonyPatch(typeof(ProtoActor), "OnDestroy")]
internal static class ProtoActorDestroyPatch
{
private static void Postfix(ProtoActor __instance)
{
JumpRuntimeState.OnActorDestroyed(__instance);
}
}
}
namespace BetterJump.Runtime
{
internal static class JumpRuntimeState
{
private sealed class ActorState
{
public float ForceUngroundUntil;
public float AirGravityUntil;
public float GroundedSince;
public float LastGravityTime;
}
private const float MaxAirGravitySeconds = 8f;
private const float LandSettleSeconds = 0.15f;
private const float ApexBlendSpeed = 2.5f;
private static readonly Dictionary<ProtoActor, ActorState> States = new Dictionary<ProtoActor, ActorState>();
internal static void OnJumpStarted(FakeJumper fakeJumper)
{
if (!BetterJumpPreferences.Enabled || fakeJumper == null)
{
return;
}
ProtoActor fieldValue = ReflectionHelper.GetFieldValue<ProtoActor>((object)fakeJumper, "owner");
if ((Object)(object)fieldValue == (Object)null)
{
return;
}
bool flag = fieldValue.AmIAvatar();
bool grounded = GetGrounded(fieldValue);
bool flag2 = States.ContainsKey(fieldValue);
if (BetterJumpPreferences.DebugLogs)
{
MelonLogger.Msg("[DBG] StartJump trigger: avatar={0} grounded={1} inProgress={2} y={3:F2} falling={4:F2}", new object[5]
{
flag,
grounded,
flag2,
GetHeight(fieldValue),
GetFalling(fieldValue)
});
}
if (flag && grounded && !flag2)
{
if (BetterJumpPreferences.DebugLogs)
{
MelonLogger.Msg("[DBG] -> BOOST falling={0:F2}", new object[1] { BetterJumpPreferences.JumpVelocity });
}
SetFalling(fieldValue, BetterJumpPreferences.JumpVelocity);
SetGrounded(fieldValue, value: false);
SetWasGrounded(fieldValue, value: false);
ActorState value = new ActorState
{
ForceUngroundUntil = Time.time + Mathf.Max(0.02f, BetterJumpPreferences.ForceUngroundTime),
AirGravityUntil = Time.time + 8f,
GroundedSince = -1f,
LastGravityTime = -1f
};
States[fieldValue] = value;
}
}
internal static void OnGroundCheck(ProtoActor actor)
{
if (!BetterJumpPreferences.Enabled || !States.TryGetValue(actor, out var value))
{
return;
}
if (BetterJumpPreferences.DebugLogs)
{
string text = ((Time.time < value.ForceUngroundUntil) ? "FORCE" : (GetGrounded(actor) ? "GROUND" : "AIR"));
MelonLogger.Msg("[DBG] tick {0}: y={1:F2} falling={2:F2} grounded={3} wasGrounded={4} ground={5} t={6:F2}", new object[7]
{
text,
GetHeight(actor),
GetFalling(actor),
GetGrounded(actor),
GetWasGrounded(actor),
GroundProbe(actor),
Time.time
});
}
if (Time.time < value.ForceUngroundUntil)
{
SetGrounded(actor, value: false);
SetWasGrounded(actor, value: false);
value.GroundedSince = -1f;
ApplyAirGravity(actor, value);
}
else if (GetGrounded(actor))
{
if (value.GroundedSince < 0f)
{
value.GroundedSince = Time.time;
}
if (Time.time - value.GroundedSince >= 0.15f)
{
States.Remove(actor);
}
}
else
{
value.GroundedSince = -1f;
if (Time.time >= value.AirGravityUntil)
{
States.Remove(actor);
}
else
{
ApplyAirGravity(actor, value);
}
}
}
internal static void OnActorDestroyed(ProtoActor actor)
{
States.Remove(actor);
}
private static bool GetGrounded(ProtoActor actor)
{
object propertyValue = ReflectionHelper.GetPropertyValue((object)actor, "grounded");
if (propertyValue != null && propertyValue is bool)
{
return (bool)propertyValue;
}
propertyValue = ReflectionHelper.GetFieldValue((object)actor, "<grounded>k__BackingField");
if (propertyValue != null && propertyValue is bool)
{
return (bool)propertyValue;
}
return false;
}
private static void SetGrounded(ProtoActor actor, bool value)
{
ReflectionHelper.SetFieldValue((object)actor, "<grounded>k__BackingField", (object)value);
}
private static void SetFalling(ProtoActor actor, float value)
{
ReflectionHelper.SetFieldValue((object)actor, "falling", (object)value);
}
private static void SetWasGrounded(ProtoActor actor, bool value)
{
ReflectionHelper.SetFieldValue((object)actor, "wasGrounded", (object)value);
}
private static float GetFalling(ProtoActor actor)
{
return ReflectionHelper.GetFieldValue<float>((object)actor, "falling");
}
private static bool GetWasGrounded(ProtoActor actor)
{
return ReflectionHelper.GetFieldValue<bool>((object)actor, "wasGrounded");
}
private static float GetHeight(ProtoActor actor)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)actor != (Object)null))
{
return 0f;
}
return ((Component)actor).transform.position.y;
}
private static string GroundProbe(ProtoActor actor)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)actor == (Object)null)
{
return "n/a";
}
RaycastHit val = default(RaycastHit);
if (Physics.Raycast(((Component)actor).transform.position + Vector3.up * 0.1f, Vector3.down, ref val, 20f, -1, (QueryTriggerInteraction)1))
{
string arg = LayerMask.LayerToName(((Component)((RaycastHit)(ref val)).collider).gameObject.layer);
return $"{((RaycastHit)(ref val)).distance - 0.1f:F2}m@{((Object)((RaycastHit)(ref val)).collider).name}[{arg}]";
}
return "none";
}
private static void ApplyAirGravity(ProtoActor actor, ActorState state)
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
float airGravityScale = BetterJumpPreferences.AirGravityScale;
if (!(airGravityScale >= 1f))
{
float falling = GetFalling(actor);
if (!(falling <= 0f) && state.LastGravityTime != Time.time)
{
state.LastGravityTime = Time.time;
float num = Mathf.Clamp01(falling / 2.5f);
float num2 = Mathf.Lerp(1f, airGravityScale, num);
float num3 = Physics.gravity.y * Time.deltaTime * (num2 - 1f);
SetFalling(actor, falling + num3);
}
}
}
}
}
namespace BetterJump.Config
{
internal static class BetterJumpPreferences
{
private const string CategoryId = "BetterJump";
private static MelonPreferences_Category _category;
private static MelonPreferences_Entry<bool> _enabled;
private static MelonPreferences_Entry<float> _jumpVelocity;
private static MelonPreferences_Entry<float> _forceUngroundTime;
private static MelonPreferences_Entry<float> _airGravityScale;
private static MelonPreferences_Entry<bool> _debugLogs;
internal static bool Enabled => _enabled.Value;
internal static float JumpVelocity => Mathf.Max(0f, _jumpVelocity.Value);
internal static float ForceUngroundTime => Mathf.Max(0.01f, _forceUngroundTime.Value);
internal static float AirGravityScale => Mathf.Clamp(_airGravityScale.Value, 0.1f, 1f);
internal static bool DebugLogs => _debugLogs.Value;
internal static void Initialize()
{
if (_category == null)
{
_category = MelonPreferences.CreateCategory("BetterJump", "BetterJump");
_enabled = CreateEntry("Enabled", defaultValue: true, "Enabled", "Enable BetterJump functionality. When disabled, the mod will not modify jump behavior.");
_jumpVelocity = CreateEntry("JumpVelocity", 4.8f, "Jump Velocity", "Upward speed applied when a jump starts (units/second). Higher values result in stronger jumps. Default: 4.8");
_forceUngroundTime = CreateEntry("ForceUngroundTime", 0.08f, "Force Unground Time", "Seconds to keep avatar airborne before the next ground check can succeed. This prevents the game from immediately detecting the ground after a jump, allowing for better jump responsiveness. Default: 0.08");
_airGravityScale = CreateEntry("AirGravityScale", 0.7f, "Air Gravity Scale", "Gravity multiplier applied during the fast part of the RISE (lower = floatier, higher arc). Near the apex it blends back to normal gravity so there is no hovering 'platform' at the top, and the descent always uses normal gravity for crisp landings. 1.0 disables the effect. Default: 0.7");
_debugLogs = CreateEntry("DebugLogs", defaultValue: false, "Debug Logs", "Enable detailed debug logging for troubleshooting jump behavior.");
}
}
private static MelonPreferences_Entry<T> CreateEntry<T>(string identifier, T defaultValue, string displayName, string description = null)
{
if (_category == null)
{
throw new InvalidOperationException("Preference category not initialized.");
}
return _category.CreateEntry<T>(identifier, defaultValue, displayName, description, false, false, (ValueValidator)null, (string)null);
}
}
}