Compare commits
1 commit
main
...
mb-physics
Author | SHA1 | Date | |
---|---|---|---|
2c52668d3f |
3 changed files with 337 additions and 6 deletions
8
Config.cs
Normal file
8
Config.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Sandbox
|
||||
{
|
||||
internal class Config
|
||||
{
|
||||
public static bool uncapVelocity = false;
|
||||
public static bool diagonalMovement = false;
|
||||
}
|
||||
}
|
|
@ -1,16 +1,53 @@
|
|||
using MIU;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Sandbox
|
||||
{
|
||||
internal class ConsoleCommands
|
||||
{
|
||||
[ConsoleCommand(description = "Simple hello world testing command")]
|
||||
public static string hello(params string[] args)
|
||||
[ConsoleCommand(description = "Enable/disable velocity cap")]
|
||||
public static string mbuncapvelocity(params string[] args)
|
||||
{
|
||||
return "Hello, World!";
|
||||
if (args.Length != 1)
|
||||
return "Expected 1 argument: 0, 1, or show";
|
||||
|
||||
switch (args[0])
|
||||
{
|
||||
case "show":
|
||||
return Config.uncapVelocity ? "Velocity is currently uncapped" : "Velocity is currently capped";
|
||||
case "0":
|
||||
case "false":
|
||||
Config.uncapVelocity = false;
|
||||
return "Velocity has been capped";
|
||||
case "1":
|
||||
case "true":
|
||||
Config.uncapVelocity = true;
|
||||
return "Velocity has been uncapped";
|
||||
default:
|
||||
return "Unknown value. Expected 0, 1, or show";
|
||||
}
|
||||
}
|
||||
|
||||
[ConsoleCommand(description = "Enable/disable diagonal movement")]
|
||||
public static string mbdiagonal(params string[] args)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
return "Expected 1 argument: 0, 1, or show";
|
||||
|
||||
switch (args[0])
|
||||
{
|
||||
case "show":
|
||||
return Config.diagonalMovement ? "Diagonal movement is currently disabled" : "Diagonal movement is currently enabled";
|
||||
case "0":
|
||||
case "false":
|
||||
Config.diagonalMovement = false;
|
||||
return "Diagonal movement has been disabled";
|
||||
case "1":
|
||||
case "true":
|
||||
Config.diagonalMovement = true;
|
||||
return "Diagonal movement has been enabled";
|
||||
default:
|
||||
return "Unknown value. Expected 0, 1, or show";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
286
Patches/MarbleBlastPhysicsPatches.cs
Normal file
286
Patches/MarbleBlastPhysicsPatches.cs
Normal file
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
* Ever wanted to play with diagonal movement and no speedcap?
|
||||
*/
|
||||
|
||||
using HarmonyLib;
|
||||
using MIU;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Sandbox.Patches
|
||||
{
|
||||
|
||||
/*
|
||||
* Turn on the rewind flag if you're using these, so you don't submit any scores
|
||||
*/
|
||||
[HarmonyPatch(typeof(MarbleManager), "FixedUpdate")]
|
||||
internal class MarbleManagerFixedUpdatePatch
|
||||
{
|
||||
static bool Prefix()
|
||||
{
|
||||
if (Config.diagonalMovement || Config.uncapVelocity)
|
||||
MarbleManager.usedRewind = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reimplement MoveNormal except don't normalize the input.
|
||||
* Wish I didn't have to do this to remove one function call...
|
||||
*/
|
||||
[HarmonyPatch(typeof(MarbleController), "MoveNormal")]
|
||||
internal class MarbleControllerMoveNormalPatch
|
||||
{
|
||||
static bool Prefix(MarbleController __instance, float dT, GameMove move)
|
||||
{
|
||||
if (!Config.diagonalMovement)
|
||||
return true; // Run original method
|
||||
|
||||
if (move == null)
|
||||
{
|
||||
move = new GameMove();
|
||||
}
|
||||
|
||||
Assembly miuuAsm = typeof(MarbleController).Assembly;
|
||||
Type marbleControllerType = miuuAsm.GetType("MarbleController");
|
||||
FieldInfo marbleControllerRespawnCounterField = marbleControllerType.GetField("respawnCounter", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
|
||||
int respawnCounter = (int)marbleControllerRespawnCounterField.GetValue(__instance);
|
||||
if (respawnCounter > 0)
|
||||
{
|
||||
respawnCounter--;
|
||||
marbleControllerRespawnCounterField.SetValue(__instance, respawnCounter);
|
||||
if (respawnCounter <= 0)
|
||||
{
|
||||
marbleControllerType.GetField("respawnCounter", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(__instance, true);
|
||||
return false; // Skip original method
|
||||
}
|
||||
}
|
||||
if (__instance.InMode(256))
|
||||
{
|
||||
if (__instance.GrinderEffects != null)
|
||||
{
|
||||
__instance.GrinderEffects.AdvanceCrush(__instance, dT);
|
||||
}
|
||||
return false; // Skip original method
|
||||
}
|
||||
if (__instance.GrinderEffects != null)
|
||||
{
|
||||
__instance.GrinderEffects.Reset();
|
||||
}
|
||||
FieldInfo marbleControllerContactsField = marbleControllerType.GetField("Contacts", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
List<Contact> contacts = (List<Contact>)marbleControllerContactsField.GetValue(__instance);
|
||||
if (__instance.InMode(8))
|
||||
{
|
||||
marbleControllerType.GetMethod("MoveStarting", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, new object[] { dT });
|
||||
__instance.SetVelocity(Vector3.zero);
|
||||
contacts.Clear();
|
||||
if (!NetworkManager.IsMultiplayer && __instance.IsServerObject())
|
||||
{
|
||||
Powerup[] array = ((GameProcess)marbleControllerType.GetField("LocalProcess", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance)).FindObjectsOfType<Powerup>();
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
array[i].Restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
bool flag = !MarbleManager.Rewinding && GamePlayManager.Get().PlayType != PlayType.Replay && !ConsoleGUI.IsActive;
|
||||
if (__instance.InMode(32))
|
||||
{
|
||||
if (__instance.TrackingTarget != null)
|
||||
{
|
||||
Vector3 position = __instance.TrackingTarget.position;
|
||||
if (position != Vector3.zero && contacts.Count > 0)
|
||||
{
|
||||
FieldInfo marbleControllerTrackingErrorSumField = marbleControllerType.GetField("TrackingErrorSum", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
Vector3 trackingErrorSum = (Vector3)marbleControllerTrackingErrorSumField.GetValue(__instance);
|
||||
Vector3 vector = position - __instance.transform.position;
|
||||
Vector3 vector2 = vector * __instance.TrackingPID.x + trackingErrorSum * __instance.TrackingPID.y - __instance.GetVelocity() * __instance.TrackingPID.z;
|
||||
move.d.x = vector2.x;
|
||||
move.d.y = vector2.z;
|
||||
trackingErrorSum += vector;
|
||||
marbleControllerTrackingErrorSumField.SetValue(__instance, trackingErrorSum);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (flag && __instance.InMode(8))
|
||||
{
|
||||
move.trigger0 = false;
|
||||
move.trigger1 = false;
|
||||
move.trigger2 = false;
|
||||
}
|
||||
// PATCH STARTS HERE - don't normalize the input!
|
||||
/*if (move.d.magnitude > 1f)
|
||||
{
|
||||
move.d.Normalize();
|
||||
}*/
|
||||
// PATCH ENDS HERE
|
||||
Type marbleInputManagerType = miuuAsm.GetType("MarbleInputManager");
|
||||
marbleInputManagerType.GetField("DebugMoveClamped", BindingFlags.Public | BindingFlags.Static).SetValue(null, move.d);
|
||||
((HashSet<GameObject>)marbleControllerType.GetField("_ContactsThisTickList", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance)).Clear();
|
||||
marbleControllerType.GetMethod("AdvancePhysics", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, new object[] { move, dT });
|
||||
if (NetworkManager.IsDedicated && !MarbleManager.Replaying)
|
||||
{
|
||||
__instance.transform.position = __instance.GetPosition();
|
||||
__instance.transform.rotation = (Quaternion)marbleControllerType.GetField("qW", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance);
|
||||
}
|
||||
|
||||
return false; // Skip original method
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reimplement this one without normalization as well
|
||||
* aaaaaaaaaaaaaaa
|
||||
*/
|
||||
[HarmonyPatch(typeof(MarbleController), "ComputeMoveForces")]
|
||||
internal class MarbleControllerComputeMoveForcesPatch
|
||||
{
|
||||
static bool Prefix(MarbleController __instance, ref bool __result, ref Vector3 aControl, ref Vector3 desiredOmega, GameMove move)
|
||||
{
|
||||
if (!Config.diagonalMovement)
|
||||
return true; // Run original method
|
||||
|
||||
Assembly miuuAsm = typeof(MarbleController).Assembly;
|
||||
Type marbleControllerType = miuuAsm.GetType("MarbleController");
|
||||
|
||||
aControl = Vector3.zero;
|
||||
desiredOmega = Vector3.zero;
|
||||
Vector3 vector = -__instance.GetGravityDir() * __instance.Radius;
|
||||
Vector3 lhs = Vector3.Cross(__instance.GetAngularVelocity(), vector);
|
||||
Vector3 sideDir = Vector3.zero;
|
||||
Vector3 motionDir = Vector3.zero;
|
||||
Vector3 upDir = Vector3.zero;
|
||||
object[] inputParams = new object[] { sideDir, motionDir, upDir, move };
|
||||
marbleControllerType.GetMethod("GetMarbleAxis", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, inputParams);
|
||||
// Just in case?
|
||||
sideDir = (Vector3)inputParams[0];
|
||||
motionDir = (Vector3)inputParams[1];
|
||||
upDir = (Vector3)inputParams[2];
|
||||
float num = Vector3.Dot(lhs, motionDir);
|
||||
float num2 = Vector3.Dot(lhs, sideDir);
|
||||
// PATCH 1 STARTS HERE - don't do anything here. Note that this might reduce the input range on an analog stick
|
||||
Vector2 vector2 = move.d;
|
||||
/*Vector2 vector2 = move.d * 1f / 0.65f;
|
||||
if (vector2.magnitude > 1f)
|
||||
{
|
||||
vector2.Normalize();
|
||||
}*/
|
||||
// PATCH 1 ENDS HERE
|
||||
float maxRollVelocity = (float)marbleControllerType.GetField("MaxRollVelocity", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance);
|
||||
float num3 = maxRollVelocity * vector2.y;
|
||||
float num4 = maxRollVelocity * vector2.x;
|
||||
float num5 = Math.Max(__instance.physMod.RollForceMult.x, __instance.physMod.RollForceMult.y);
|
||||
if (vector2.magnitude > 0.01f)
|
||||
{
|
||||
TimeGraph.GraphLog("moveMag", vector2.magnitude);
|
||||
if (num > num3 && num3 > 0.9f)
|
||||
{
|
||||
num3 = num;
|
||||
}
|
||||
else if (num < num3 && num3 < -0.9f)
|
||||
{
|
||||
num3 = num;
|
||||
}
|
||||
if (num2 > num4 && num4 > 0.9f)
|
||||
{
|
||||
num4 = num2;
|
||||
}
|
||||
else if (num2 < num4 && num4 < -0.9f)
|
||||
{
|
||||
num4 = num2;
|
||||
}
|
||||
Vector2 to = new Vector2(num2, num);
|
||||
// PATCH 2 STARTS HERE - don't normalize
|
||||
//Vector2 vector3 = new Vector2(num4, num3).normalized * Mathf.Max(maxRollVelocity * num5, to.magnitude);
|
||||
Vector2 vector3 = new Vector2(num4, num3) * Mathf.Max(maxRollVelocity * num5, to.magnitude);
|
||||
// PATCH 2 ENDS HERE
|
||||
float num6 = Vector2.Angle(vector3, to);
|
||||
float num7 = num6;
|
||||
if (num7 >= 180f)
|
||||
{
|
||||
num7 = 179.99f;
|
||||
}
|
||||
if (num7 <= 0f)
|
||||
{
|
||||
num7 = 0f;
|
||||
}
|
||||
if (float.IsNaN(num7))
|
||||
{
|
||||
num7 = 0f;
|
||||
}
|
||||
float a = __instance.TurningCompensationFactor.Evaluate(0f);
|
||||
float b = __instance.TurningCompensationFactor.Evaluate(num6);
|
||||
float turningVelStartVelocity = (float)marbleControllerType.GetField("TurningVelStartVelocity", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance);
|
||||
float num8 = Mathf.Lerp(a, b, (to.magnitude - turningVelStartVelocity * num5) / (maxRollVelocity - turningVelStartVelocity) * num5);
|
||||
if (to.magnitude < turningVelStartVelocity * num5)
|
||||
{
|
||||
num8 = __instance.TurningCompensationFactor.Evaluate(0f);
|
||||
}
|
||||
// PATCH 3 STARTS HERE - don't normalize
|
||||
//Vector2 vector4 = vector3.normalized * num8;
|
||||
Vector2 vector4 = vector3 * num8;
|
||||
// PATCH 3 ENDS HERE
|
||||
vector4 = new Vector2(vector4.x * __instance.physMod.RollForceMult.y, vector4.y * __instance.physMod.RollForceMult.x);
|
||||
vector3 = (vector3 + vector4) * vector2.magnitude;
|
||||
num4 = vector3.x;
|
||||
num3 = vector3.y;
|
||||
desiredOmega = Vector3.Cross(vector, num3 * motionDir + num4 * sideDir) / Vector3.Dot(vector, vector);
|
||||
aControl = desiredOmega - __instance.GetAngularVelocity();
|
||||
float magnitude = aControl.magnitude;
|
||||
float angularAcceleration = (float)marbleControllerType.GetField("AngularAcceleration", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance);
|
||||
if (magnitude > angularAcceleration)
|
||||
{
|
||||
aControl *= angularAcceleration / magnitude;
|
||||
}
|
||||
__result = false;
|
||||
return false; // Skip original method
|
||||
}
|
||||
|
||||
__result = true;
|
||||
return false; // Skip original method
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Another one, awesome!!! A lot easier at least since we can do a Postfix and grab the correct value
|
||||
*/
|
||||
[HarmonyPatch(typeof(MarbleController), nameof(MarbleController.GetNextMove))]
|
||||
internal class MarbleControllerGetNextMovePatch
|
||||
{
|
||||
static bool printed = false;
|
||||
static void Postfix(MarbleController __instance, ref bool __result, ref GameMove move)
|
||||
{
|
||||
if (!Config.diagonalMovement)
|
||||
return; // Don't do anything here
|
||||
|
||||
if (!__result)
|
||||
return;
|
||||
|
||||
Assembly miuuAsm = typeof(MarbleController).Assembly;
|
||||
//Type marbleControllerType = miuuAsm.GetType("MarbleController");
|
||||
Type marbleInputManagerType = miuuAsm.GetType("MarbleInputManager");
|
||||
|
||||
move.d = (Vector2)marbleInputManagerType.GetField("DebugMoveScaled", BindingFlags.Public | BindingFlags.Static).GetValue(null);
|
||||
marbleInputManagerType.GetField("DebugMoveEased", BindingFlags.Public | BindingFlags.Static).SetValue(null, move.d);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove speed cap. Very easy, just don't do it
|
||||
*/
|
||||
[HarmonyPatch(typeof(MarbleController), "EnforceVelocityCap")]
|
||||
internal class MarbleControllerEnforceVelocityCapPatch
|
||||
{
|
||||
static bool Prefix()
|
||||
{
|
||||
if (!Config.uncapVelocity)
|
||||
return true; // Run original method
|
||||
|
||||
return false; // Skip original method
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue