Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/raftcreative rotation fixes #86

Merged
merged 8 commits into from
May 23, 2024
46 changes: 46 additions & 0 deletions src/ValheimRAFT/ValheimRAFT.Patches/Character_Patch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,50 @@ private static void UpdateGroundContact(Character __instance)

if (!mbr && !bvc && __instance.transform.parent != null) __instance.transform.SetParent(null);
}

/// <summary>
/// Fixes issue where player is running on a moving boat and then enters flying mode or hover mode if moving near edge and ship is moving forward but player is moving backwards
/// </summary>
/// <param name="__instance"></param>
/// <param name="collision"></param>
/// <returns></returns>
[HarmonyPatch(typeof(Character), "OnCollisionStay")]
[HarmonyPrefix]
private static bool OnCollisionStay(Character __instance, Collision collision)
{
if (!__instance.m_nview.IsValid() || !__instance.m_nview.IsOwner() ||
__instance.m_jumpTimer < 0.1f) return false;
var contacts = collision.contacts;
for (var i = 0; i < contacts.Length; i++)
{
var contactPoint = contacts[i];
var hitnormal = contactPoint.normal;
var hitpoint = contactPoint.point;
var hitDistance = Mathf.Abs(hitpoint.y - __instance.transform.position.y);
if (!__instance.m_groundContact && hitnormal.y < 0f && hitDistance < 0.1f)
{
hitnormal *= -1f;
hitpoint = __instance.transform.position;
}

if (!(hitnormal.y > 0.1f) || !(hitDistance < __instance.m_collider.radius)) continue;
if (hitnormal.y > __instance.m_groundContactNormal.y || !__instance.m_groundContact)
{
__instance.m_groundContact = true;
__instance.m_groundContactNormal = hitnormal;
__instance.m_groundContactPoint = hitpoint;
__instance.m_lowestContactCollider = collision.collider;
continue;
}

var groundContactNormal = Vector3.Normalize(__instance.m_groundContactNormal + hitnormal);
if (groundContactNormal.y > __instance.m_groundContactNormal.y)
{
__instance.m_groundContactNormal = groundContactNormal;
__instance.m_groundContactPoint = (__instance.m_groundContactPoint + hitpoint) * 0.5f;
}
}

return false;
}
}
4 changes: 2 additions & 2 deletions src/ValheimRAFT/ValheimRAFT.Patches/GamePause_Patch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ private static void PreventTimeFreezeOnShip()
// not on ship, do nothing
if (!baseVehicleShip) return;

var hasPeerConnections = ZNet.instance?.GetPeerConnections() > 0;

var hasPeerConnections = ZNet.instance?.GetPeerConnections() > 0 ||
ValheimRaftPlugin.Instance.ShipPausePatchSinglePlayer.Value;
// Previously onPause the time was set to 0 regarless if using multiplayer, which borks ZDOs and Physics updates that are reliant on the controlling player.
// Also causes issues with Players that are on a ship controlled by another player and the ship moves out of range. The player is forced through the wall or smashed up into the air.
if (Game.IsPaused())
Expand Down
55 changes: 36 additions & 19 deletions src/ValheimRAFT/ValheimRAFT/CreativeModeConsoleCommand.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections;
using Jotunn.Entities;
using UnityEngine;
using ValheimVehicles.Vehicles;
Expand All @@ -16,6 +17,14 @@ public override void Run(string[] args)
RunCreativeModeCommand(Name);
}

private static IEnumerator SetPlayerBackOnBoat(Character character)
{
yield return new WaitForFixedUpdate();
character.m_body.velocity = Vector3.zero;
character.m_body.angularVelocity = Vector3.zero;
character.m_body.isKinematic = false;
}

public static void RunCreativeModeCommand(string comandName)
{
var player = Player.m_localPlayer;
Expand Down Expand Up @@ -52,7 +61,14 @@ public static void RunCreativeModeCommand(string comandName)
}
}

private static bool ToggleMode(Character player,
/// <summary>
/// This moves the ship in the air for ship creation
/// </summary>
/// todo move all rigidbodies near or on the ship into a non-collision state and then move them back to the ship with the offset. This way this prevents all rigidbodies from being smashed into air
/// <param name="character"></param>
/// <param name="ship"></param>
/// <returns></returns>
private static bool ToggleMode(Character character,
VehicleShip ship)
{
if (!(bool)ship)
Expand All @@ -66,32 +82,33 @@ public static void RunCreativeModeCommand(string comandName)

if (toggledKinematicValue)
{
if (player.transform.parent == ship.VehicleController.Instance.transform)
var shipYPosition =
ship.m_body.position.y + ValheimRaftPlugin.Instance.RaftCreativeHeight.Value;
var playerInBoat = character.transform.parent == ship.VehicleController.Instance.transform;
if (playerInBoat)
{
player.m_body.position = new Vector3(
player.m_body.transform.position.x,
player.m_body.transform.position.y + 2f +
character.m_body.isKinematic = true;
character.m_body.position = new Vector3(
character.m_body.transform.position.x,
character.m_body.transform.position.y + 0.2f +
ValheimRaftPlugin.Instance.RaftCreativeHeight.Value,
player.m_body.transform.position.z);
character.m_body.transform.position.z);

// prevents player from being launched into the sky if the ship hits them when it is moved upwards
player.m_body.isKinematic = true;
}

var directionRaftUpwards = new Vector3(ship.transform.position.x,
ship.m_body.position.y + ValheimRaftPlugin.Instance.RaftCreativeHeight.Value,
shipYPosition,
ship.transform.position.z);
var rotationWithoutTilt = Quaternion.Euler(0f, ship.m_body.rotation.eulerAngles.y, 0f);
var rotationWithoutTilt = Quaternion.Euler(0, ship.m_body.rotation.eulerAngles.y, 0);
ship.SetCreativeMode(true);

ship.m_body.position = directionRaftUpwards;
ship.m_body.transform.rotation = rotationWithoutTilt;
ship.Instance.transform.rotation = rotationWithoutTilt;
ship.VehicleController.Instance.transform.rotation = rotationWithoutTilt;
ship.transform.rotation = rotationWithoutTilt;

// set player back to being controllable
player.m_body.isKinematic = false;
character.StartCoroutine(SetPlayerBackOnBoat(character));
}
else
{
Expand All @@ -102,7 +119,7 @@ public static void RunCreativeModeCommand(string comandName)
return true;
}

private static bool ToggleMode(Player player, Ship ship)
private static bool ToggleMode(Player character, Ship ship)
{
var mb = ship.GetComponent<MoveableBaseShipComponent>();
if ((bool)mb)
Expand All @@ -112,21 +129,21 @@ private static bool ToggleMode(Player player, Ship ship)
zsync.m_isKinematicBody = mb.m_rigidbody.isKinematic;
if (mb.m_rigidbody.isKinematic)
{
if (player.transform.parent == mb.m_baseRoot.transform)
if (character.transform.parent == mb.m_baseRoot.transform)
{
player.m_body.position = new Vector3(
player.m_body.transform.position.x,
player.m_body.transform.position.y +
character.m_body.position = new Vector3(
character.m_body.transform.position.x,
character.m_body.transform.position.y +
ValheimRaftPlugin.Instance.RaftCreativeHeight.Value,
player.m_body.transform.position.z);
character.m_body.transform.position.z);
}

mb.m_rigidbody.position =
new Vector3(mb.transform.position.x,
mb.m_rigidbody.position.y + ValheimRaftPlugin.Instance.RaftCreativeHeight.Value,
mb.transform.position.z);
mb.m_rigidbody.transform.rotation =
Quaternion.Euler(0f, mb.m_rigidbody.rotation.eulerAngles.y, 0f);
Quaternion.Euler(0, mb.m_rigidbody.rotation.eulerAngles.y, 0);
mb.isCreative = true;
}
else
Expand Down
6 changes: 6 additions & 0 deletions src/ValheimRAFT/ValheimRAFT/ValheimRaftPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class ValheimRaftPlugin : BaseUnityPlugin
public ConfigEntry<bool> PlanBuildPatches { get; set; }

public ConfigEntry<bool> ShipPausePatch { get; set; }
public ConfigEntry<bool> ShipPausePatchSinglePlayer { get; set; }


public ConfigEntry<float> ServerRaftUpdateZoneInterval { get; set; }
Expand Down Expand Up @@ -391,6 +392,11 @@ private void CreateBaseConfig()
CreateConfigDescription(
"Prevents pausing on a boat, pausing causes a TON of desync problems and can make your boat crash or other players crash",
true, true));
ShipPausePatchSinglePlayer = Config.Bind<bool>("Patches",
"Vehicles Prevent Pausing SinglePlayer", true,
CreateConfigDescription(
"Prevents pausing on a boat during singleplayer. Must have the Vehicle Prevent Pausing patch as well",
true, true));
PlanBuildPatches = Config.Bind<bool>("Patches",
"Enable PlanBuild Patches (required to be on if you installed PlanBuild)", false,
new ConfigDescription(
Expand Down
103 changes: 93 additions & 10 deletions src/ValheimVehicles/ValheimVehicles.ConsoleCommands/VehicleCommands.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BepInEx.Logging;
using Components;
using Jotunn.Entities;
using Jotunn.Managers;
using UnityEngine;
using UnityEngine.Assertions.Must;
using ValheimRAFT;
using ValheimVehicles.Prefabs;
using ValheimVehicles.Vehicles;
using Logger = Jotunn.Logger;
using Object = UnityEngine.Object;

namespace ValheimVehicles.ConsoleCommands;

Expand All @@ -24,25 +27,24 @@ private static class VehicleCommandArgs
public const string creative = "creative";
public const string help = "help";
public const string recover = "recover";
public const string rotate = "rotate";
public const string move = "move";
public const string toggleOceanSway = "toggleOceanSway";
public const string upgradeToV2 = "upgradeShipToV2";
public const string downgradeToV1 = "downgradeShipToV1";
}

public override string Help => OnHelp();

public string OnHelp()
public static string OnHelp()
{
return
"Runs vehicle commands, each command will require parameters to run use help to see the input values." +
"\n<debug> will show a menu with options like rotating or debugging vehicle colliders" +
"\n<recover>: will recover any vehicles within range of 1000 and turn them into V2 Vehicles";
}

private class RotateArgs
{
public const string rotateX = "x";
public const string rotateY = "y";
public const string rotateZ = "z";
$"\n<{VehicleCommandArgs.debug}>: will show a menu with options like rotating or debugging vehicle colliders" +
$"\n<{VehicleCommandArgs.recover}>: will recover any vehicles within range of 1000 and turn them into V2 Vehicles" +
$"\n<{VehicleCommandArgs.rotate}>: defaults to zeroing x and z tilt. Can also provide 3 args: x y z" +
$"\n<{VehicleCommandArgs.move}>: Must provide 3 args: x y z, the movement is relative to those points" +
$"\n<{VehicleCommandArgs.toggleOceanSway}>: stops the vehicle from swaying in the water. It will stay at 0 degrees (x and z) tilt and only allow rotating on y axis";
}

public override void Run(string[] args)
Expand All @@ -54,13 +56,25 @@ private void ParseFirstArg(string[] args)
{
var firstArg = args.First();
if (firstArg == null)
{
Logger.LogMessage("Must provide a argument for `vehicle` command");
return;
}

switch (firstArg)
{
// case VehicleCommandArgs.locate:
// LocateVehicle.LocateAllVehicles();
// break;
case VehicleCommandArgs.move:
VehicleMove(args);
break;
case VehicleCommandArgs.toggleOceanSway:
VehicleStopOceanSway();
break;
case VehicleCommandArgs.rotate:
VehicleRotate(args);
break;
case VehicleCommandArgs.recover:
RecoverRaftConsoleCommand.RecoverRaftWithoutDryRun($"{Name} {VehicleCommandArgs.recover}");
break;
Expand All @@ -79,6 +93,73 @@ private void ParseFirstArg(string[] args)
}
}

public void VehicleMove(string[] args)
{
var vehicleController = VehicleDebugHelpers.GetVehicleController();
if (vehicleController == null)
{
Logger.LogMessage("No VehicleController Detected");
return;
}

if (args.Length == 4)
{
float.TryParse(args[1], out var x);
float.TryParse(args[2], out var y);
float.TryParse(args[3], out var z);
var offsetVector = new Vector3(x, y, z);
vehicleController.VehicleInstance.Instance.transform.position += offsetVector;
}
else
{
Logger.LogMessage("Must provide x y z parameters, IE: vehicle rotate 0.5 0 10");
}
}

/// <summary>
/// Freezes the Vehicle rotation permenantly until the boat is unloaded similar to raftcreative
/// </summary>
private static void VehicleStopOceanSway()
{
var vehicleController = VehicleDebugHelpers.GetVehicleController();
if (!vehicleController)
{
Logger.LogMessage("No VehicleController Detected");
return;
}

vehicleController?.VehicleInstance.Instance.MovementController.SendToggleOceanSway();
}

private static void VehicleRotate(string[] args)
{
var vehicleController = VehicleDebugHelpers.GetVehicleController();
if (!vehicleController)
{
Logger.LogMessage("No VehicleController Detected");
return;
}

if (args.Length == 1)
{
vehicleController.VehicleInstance.Instance.FixShipRotation();
}

if (args.Length == 4)
{
float.TryParse(args[1], out var x);
float.TryParse(args[2], out var y);
float.TryParse(args[3], out var z);
vehicleController.VehicleInstance.Instance.transform.rotation = Quaternion.Euler(
Mathf.Approximately(0f, x) ? 0 : x, Mathf.Approximately(0f, y) ? 0 : y,
Mathf.Approximately(0f, z) ? 0 : z);
}
else
{
Logger.LogMessage("Must provide x y z parameters, IE: vehicle rotate 0.5 0 10");
}
}

private static void RunDowngradeToV1()
{
var vehicleController = VehicleDebugHelpers.GetVehicleController();
Expand Down Expand Up @@ -150,6 +231,8 @@ private static void ToggleVehicleDebugComponent()
[
// VehicleCommandArgs.locate,
// VehicleCommandArgs.destroy,
VehicleCommandArgs.rotate,
VehicleCommandArgs.toggleOceanSway,
VehicleCommandArgs.creative,
VehicleCommandArgs.debug,
VehicleCommandArgs.help,
Expand Down
Loading
Loading