Compare commits

...

8 Commits

Author SHA1 Message Date
Terkoiz
f49dfbdb01 Updated for SPT 3.9.0 2024-07-09 00:06:17 +03:00
ac56754db2 I am destroying any instances of GameObject.Find() to save the world (#5)
lgtm
Co-authored-by: Nympfonic <arys.steam@gmail.com>
Co-committed-by: Nympfonic <arys.steam@gmail.com>
2024-04-08 07:09:43 +00:00
Terkoiz
4839e050f8 Version bump for recompiled DLL targetting SPT 3.8.0 2024-03-18 18:29:14 +02:00
Terkoiz
183c640ea3 Version bump 2024-03-03 20:27:57 +02:00
Terkoiz
34e6c8fc06 Updated README 2024-03-03 17:43:39 +02:00
027893c1d6 Freecam Controls Toggle (#4)
Added option to toggle Freecam Controls using a new keybind (default: keypad period).

This allows users to easily switch to Freecam mode, move their camera to position, toggle camera controls, and move the player character. Great addition for efficient testing of weight painting and animations.

Reviewed-on: #4
Co-authored-by: GrooveypenguinX <grooveypenguinx@noreply.dev.sp-tarkov.com>
Co-committed-by: GrooveypenguinX <grooveypenguinx@noreply.dev.sp-tarkov.com>
2024-03-03 13:40:33 +00:00
Terkoiz
28fd27d21d Proper fall damage prevention feature & settings refactor
* Added a proper, way more reliable fall damage removal feature
* Added an experimental 'smarter' fall damage prevention feature
* Refactored all setting labels for better readability
2024-03-02 18:40:51 +02:00
Terkoiz
796e7a6005 Fixed .gitignore 2024-02-19 14:47:38 +02:00
11 changed files with 141 additions and 54 deletions

3
.gitignore vendored
View File

@ -2,7 +2,8 @@
project/References/EFT_Managed/* project/References/EFT_Managed/*
# Allow these files, despite the rules above # Allow these files, despite the rules above
project/References/EFT_Managed/.keep !project/References/EFT_Managed/.keep
!project/References/SPT/.keep
# ---> VisualStudio # ---> VisualStudio
## Ignore Visual Studio temporary files, build results, and ## Ignore Visual Studio temporary files, build results, and

View File

@ -1,6 +1,6 @@
# Freecam # Freecam
An SPT-AKI module mod that allows you to detach the camera and fly around freely in Escape From Tarkov. A BepInEx plugin for SPT-AKI that allows you to detach the camera and fly around freely in Escape From Tarkov.
### Controls ### Controls
@ -21,10 +21,9 @@ Alternatively, you can find the `com.terkoiz.freecam.cfg` file in your `BepInEx/
### Known issues ### Known issues
1. Your weapon doesn't turn invisible when you enter freecam mode 1. When teleporting to camera position, the camera rotation gets copied exactly, potentially causing the player model to tilt
2. When teleporting to camera position, the camera rotation gets copied exactly, potentially causing the player model to tilt 2. Game version UI element is not hidden when toggling UI
3. Game version UI element is not hidden when toggling UI 3. When flying to distant parts of the map in freecam mode, LODs are not triggered (these seem to follow the player)
4. When flying to distant parts of the map in freecam mode, LODs are not triggered (these seem to follow the player)
### How to build from source ### How to build from source

View File

View File

View File

@ -0,0 +1,44 @@
using System.Reflection;
using SPT.Reflection.Patching;
using EFT.HealthSystem;
using HarmonyLib;
namespace Terkoiz.Freecam
{
public class FallDamagePatch : ModulePatch
{
internal static bool HasTeleported;
protected override MethodBase GetTargetMethod()
{
return AccessTools.Method(typeof(ActiveHealthController), nameof(ActiveHealthController.HandleFall));
}
[PatchPrefix]
public static bool PatchPrefix(ActiveHealthController __instance, float height)
{
// WARNING: The 'HandleFall' method gets called every frame for every player and AI in a raid. Be very careful with logging or expensive operations in this prefix patch!
// Check if it's our own player, or if a Player property even exists
if (__instance.Player?.IsAI ?? true)
{
return true; // Run original method
}
// Global fall damage flag overrides everything
if (FreecamPlugin.GlobalDisableFallDamage.Value)
{
return false; // Prevent original method from running
}
// If smart fall damage flag is enabled, check if we've recently teleported and if the fall height value was positive
if (FreecamPlugin.SmartDisableFallDamage.Value && HasTeleported && height > 0)
{
HasTeleported = false;
return false; // Prevent original method from running
}
return true; // Run original method
}
}
}

View File

@ -6,7 +6,7 @@ namespace Terkoiz.Freecam
/// <summary> /// <summary>
/// A simple free camera to be added to a Unity game object. /// A simple free camera to be added to a Unity game object.
/// ///
/// Full credit to Ashley Davis on GitHub for the inital code: /// Full credit to Ashley Davis on GitHub for the initial code:
/// https://gist.github.com/ashleydavis/f025c03a9221bc840a2b /// https://gist.github.com/ashleydavis/f025c03a9221bc840a2b
/// ///
/// </summary> /// </summary>

View File

@ -13,7 +13,7 @@ namespace Terkoiz.Freecam
private GameObject _mainCamera; private GameObject _mainCamera;
private Freecam _freeCamScript; private Freecam _freeCamScript;
private BattleUIScreen _playerUi; private EftBattleUIScreen _playerUi;
private bool _uiHidden; private bool _uiHidden;
private GamePlayerOwner _gamePlayerOwner; private GamePlayerOwner _gamePlayerOwner;
@ -21,22 +21,25 @@ namespace Terkoiz.Freecam
private Vector3? _lastPosition; private Vector3? _lastPosition;
private Quaternion? _lastRotation; private Quaternion? _lastRotation;
// TODO:
// Hide version number UI element
// Button to toggle between camera and player movement
// Independent FoV setting for Freecam mode (_mainCamera.GetComponent<Camera>().fieldOfView = ...)
[UsedImplicitly] [UsedImplicitly]
public void Start() public void Start()
{ {
// Find Main Camera // Get Main Camera
_mainCamera = GameObject.Find("FPS Camera"); _mainCamera = GetLocalPlayerFromWorld().GetComponent<PlayerCameraController>().Camera.gameObject;
if (_mainCamera == null) if (_mainCamera == null)
{ {
FreecamPlugin.Logger.LogError("Failed to locate main camera"); FreecamPlugin.Logger.LogError("Failed to locate main camera");
return; return;
} }
// Get Player UI
_playerUi = Singleton<CommonUI>.Instance.EftBattleUIScreen;
if (_playerUi == null)
{
FreecamPlugin.Logger.LogError("Failed to locate player UI");
return;
}
// Add Freecam script to main camera in scene // Add Freecam script to main camera in scene
_freeCamScript = _mainCamera.AddComponent<Freecam>(); _freeCamScript = _mainCamera.AddComponent<Freecam>();
if (_freeCamScript == null) if (_freeCamScript == null)
@ -65,6 +68,11 @@ namespace Terkoiz.Freecam
ToggleCamera(); ToggleCamera();
} }
if (FreecamPlugin.ToggleFreecamControls.Value.IsDown())
{
ToggleCameraControls();
}
if (FreecamPlugin.TeleportToCamera.Value.IsDown()) if (FreecamPlugin.TeleportToCamera.Value.IsDown())
{ {
MovePlayerToCamera(); MovePlayerToCamera();
@ -103,6 +111,9 @@ namespace Terkoiz.Freecam
// Move the player to the camera's current position and switch to First Person mode // Move the player to the camera's current position and switch to First Person mode
if (_freeCamScript.IsActive) if (_freeCamScript.IsActive)
{ {
// Tell the fall damage patch that we just teleported. Used for the "smart" fall damage prevention feature
FallDamagePatch.HasTeleported = true;
// We grab the camera's position, but we subtract a bit off the Y axis, because the players coordinate origin is at the feet // We grab the camera's position, but we subtract a bit off the Y axis, because the players coordinate origin is at the feet
var position = new Vector3(_mainCamera.transform.position.x, _mainCamera.transform.position.y - 1.8f, _mainCamera.transform.position.z); var position = new Vector3(_mainCamera.transform.position.x, _mainCamera.transform.position.y - 1.8f, _mainCamera.transform.position.z);
localPlayer.gameObject.transform.SetPositionAndRotation(position, Quaternion.Euler(0, _mainCamera.transform.rotation.y, 0)); localPlayer.gameObject.transform.SetPositionAndRotation(position, Quaternion.Euler(0, _mainCamera.transform.rotation.y, 0));
@ -121,18 +132,6 @@ namespace Terkoiz.Freecam
if (GetLocalPlayerFromWorld() == null) if (GetLocalPlayerFromWorld() == null)
return; return;
// If we don't have the UI Component cached, go look for it in the scene
if (_playerUi == null)
{
_playerUi = GameObject.Find("BattleUIScreen").GetComponent<BattleUIScreen>();
if (_playerUi == null)
{
FreecamPlugin.Logger.LogError("Failed to locate player UI");
return;
}
}
_playerUi.gameObject.SetActive(_uiHidden); _playerUi.gameObject.SetActive(_uiHidden);
_uiHidden = !_uiHidden; _uiHidden = !_uiHidden;
} }
@ -198,6 +197,25 @@ namespace Terkoiz.Freecam
localPlayer.PointOfView = EPointOfView.FirstPerson; localPlayer.PointOfView = EPointOfView.FirstPerson;
} }
/// <summary>
/// A helper method to toggle the Freecam Camera Controls
/// </summary>
private void ToggleCameraControls()
{
if (_freeCamScript.IsActive)
{
_freeCamScript.IsActive = false;
_gamePlayerOwner.enabled = true;
}
else
{
_freeCamScript.IsActive = true;
_gamePlayerOwner.enabled = false;
}
}
/// <summary> /// <summary>
/// Gets the current <see cref="Player"/> instance if it's available /// Gets the current <see cref="Player"/> instance if it's available
/// </summary> /// </summary>
@ -218,7 +236,6 @@ namespace Terkoiz.Freecam
{ {
// Destroy FreeCamScript before FreeCamController if exists // Destroy FreeCamScript before FreeCamController if exists
Destroy(_freeCamScript); Destroy(_freeCamScript);
Destroy(this);
} }
} }
} }

View File

@ -1,7 +1,8 @@
using System.Reflection; using System.Reflection;
using Aki.Reflection.Patching; using SPT.Reflection.Patching;
using Comfort.Common; using Comfort.Common;
using EFT; using EFT;
using HarmonyLib;
namespace Terkoiz.Freecam namespace Terkoiz.Freecam
{ {
@ -9,19 +10,19 @@ namespace Terkoiz.Freecam
{ {
protected override MethodBase GetTargetMethod() protected override MethodBase GetTargetMethod()
{ {
return typeof(GameWorld).GetMethod("OnGameStarted", BindingFlags.Public | BindingFlags.Instance); return AccessTools.Method(typeof(GameWorld), nameof(GameWorld.OnGameStarted));
} }
[PatchPostfix] [PatchPostfix]
public static void PatchPostFix() public static void PatchPostFix()
{ {
var gameworld = Singleton<GameWorld>.Instance; var gameWorld = Singleton<GameWorld>.Instance;
if (gameworld == null) if (gameWorld == null)
return; return;
// Add FreeCamController to GameWorld GameObject // Add FreecamController to GameWorld GameObject
gameworld.gameObject.AddComponent<FreecamController>(); gameWorld.gameObject.AddComponent<FreecamController>();
} }
} }
} }

View File

@ -7,19 +7,25 @@ using KeyboardShortcut = BepInEx.Configuration.KeyboardShortcut;
namespace Terkoiz.Freecam namespace Terkoiz.Freecam
{ {
[BepInPlugin("com.terkoiz.freecam", "Terkoiz.Freecam", "1.3.2")] [BepInPlugin("com.terkoiz.freecam", "Terkoiz.Freecam", "1.4.4")]
public class FreecamPlugin : BaseUnityPlugin public class FreecamPlugin : BaseUnityPlugin
{ {
internal new static ManualLogSource Logger { get; private set; } internal new static ManualLogSource Logger { get; private set; }
// Fall damage config entries
private const string FallDamageSectionName = "Fall Damage";
internal static ConfigEntry<bool> GlobalDisableFallDamage;
internal static ConfigEntry<bool> SmartDisableFallDamage;
// Keyboard shortcut config entries // Keyboard shortcut config entries
private const string KeybindSectionName = "Keybinds"; private const string KeybindSectionName = "Keybinds";
internal static ConfigEntry<KeyboardShortcut> ToggleFreecamMode; internal static ConfigEntry<KeyboardShortcut> ToggleFreecamMode;
internal static ConfigEntry<KeyboardShortcut> ToggleFreecamControls;
internal static ConfigEntry<KeyboardShortcut> TeleportToCamera; internal static ConfigEntry<KeyboardShortcut> TeleportToCamera;
internal static ConfigEntry<KeyboardShortcut> ToggleUi; internal static ConfigEntry<KeyboardShortcut> ToggleUi;
// Camera settings config entries // Camera settings config entries
private const string CameraSettingsSectionName = "CameraSettings"; private const string CameraSettingsSectionName = "Camera Settings";
internal static ConfigEntry<float> CameraMoveSpeed; internal static ConfigEntry<float> CameraMoveSpeed;
internal static ConfigEntry<float> CameraFastMoveSpeed; internal static ConfigEntry<float> CameraFastMoveSpeed;
internal static ConfigEntry<float> CameraLookSensitivity; internal static ConfigEntry<float> CameraLookSensitivity;
@ -39,31 +45,50 @@ namespace Terkoiz.Freecam
InitConfiguration(); InitConfiguration();
new FreecamPatch().Enable(); new FreecamPatch().Enable();
new FallDamagePatch().Enable();
} }
private void InitConfiguration() private void InitConfiguration()
{ {
GlobalDisableFallDamage = Config.Bind(
FallDamageSectionName,
"Globally Disable Fall Damage",
false,
"Completely disables fall damage. This is the safest option for using freecam. Will fully override the 'Smart Fall Damage Prevention' setting.");
SmartDisableFallDamage = Config.Bind(
FallDamageSectionName,
"Smart Fall Damage Prevention",
true,
"Fall damage will only be disabled after using teleport, until your player lands. Less cheat-y way to save yourself from fall damage, but might sometimes be unreliable.");
ToggleFreecamMode = Config.Bind( ToggleFreecamMode = Config.Bind(
KeybindSectionName, KeybindSectionName,
"ToggleCamera", "Toggle Freecam",
new KeyboardShortcut(KeyCode.KeypadPlus), new KeyboardShortcut(KeyCode.KeypadPlus),
"The keyboard shortcut that toggles Freecam"); "The keyboard shortcut that toggles Freecam");
ToggleFreecamControls = Config.Bind(
KeybindSectionName,
"Toggle Freecam Controls",
new KeyboardShortcut(KeyCode.KeypadPeriod),
"The keyboard shortcut that toggles Freecam Controls");
TeleportToCamera = Config.Bind( TeleportToCamera = Config.Bind(
KeybindSectionName, KeybindSectionName,
"TeleportToCamera", "Teleport To Camera",
new KeyboardShortcut(KeyCode.KeypadEnter), new KeyboardShortcut(KeyCode.KeypadEnter),
"The keyboard shortcut that teleports the player to camera position"); "The keyboard shortcut that teleports the player to camera position");
ToggleUi = Config.Bind( ToggleUi = Config.Bind(
KeybindSectionName, KeybindSectionName,
"ToggleUi", "Toggle UI",
new KeyboardShortcut(KeyCode.KeypadMultiply), new KeyboardShortcut(KeyCode.KeypadMultiply),
"The keyboard shortcut that toggles the game UI"); "The keyboard shortcut that toggles the game UI");
CameraMoveSpeed = Config.Bind( CameraMoveSpeed = Config.Bind(
CameraSettingsSectionName, CameraSettingsSectionName,
"CameraMoveSpeed", "Camera Speed",
10f, 10f,
new ConfigDescription( new ConfigDescription(
"The speed at which the camera will move normally", "The speed at which the camera will move normally",
@ -71,7 +96,7 @@ namespace Terkoiz.Freecam
CameraFastMoveSpeed = Config.Bind( CameraFastMoveSpeed = Config.Bind(
CameraSettingsSectionName, CameraSettingsSectionName,
"CameraFastMoveSpeed", "Camera Sprint Speed",
100f, 100f,
new ConfigDescription( new ConfigDescription(
"The speed at which the camera will move when the Shift key is held down", "The speed at which the camera will move when the Shift key is held down",
@ -79,7 +104,7 @@ namespace Terkoiz.Freecam
CameraLookSensitivity = Config.Bind( CameraLookSensitivity = Config.Bind(
CameraSettingsSectionName, CameraSettingsSectionName,
"CameraLookSensitivity", "Camera Mouse Sensitivity",
3f, 3f,
new ConfigDescription( new ConfigDescription(
"Camera free look mouse sensitivity", "Camera free look mouse sensitivity",
@ -87,7 +112,7 @@ namespace Terkoiz.Freecam
CameraZoomSpeed = Config.Bind( CameraZoomSpeed = Config.Bind(
CameraSettingsSectionName, CameraSettingsSectionName,
"CameraMousewheelZoomSpeed", "Camera Zoom Speed",
10f, 10f,
new ConfigDescription( new ConfigDescription(
"Amount to zoom the camera when using the mouse wheel", "Amount to zoom the camera when using the mouse wheel",
@ -95,30 +120,30 @@ namespace Terkoiz.Freecam
CameraFastZoomSpeed = Config.Bind( CameraFastZoomSpeed = Config.Bind(
CameraSettingsSectionName, CameraSettingsSectionName,
"CameraMousewheelFastZoomSpeed", "Camera Zoom Sprint Speed",
50f, 50f,
new ConfigDescription( new ConfigDescription(
"Amount to zoom the camera when using the mouse wheel while holding Shift", "Amount to zoom the camera when using the mouse wheel while holding Shift",
new AcceptableValueRange<float>(0.01f, 1000f))); new AcceptableValueRange<float>(0.01f, 1000f)));
CameraHeightMovement = Config.Bind( CameraHeightMovement = Config.Bind(
TogglesSectionName, TogglesSectionName,
"CameraHeightMovementKeys", "Camera Height Movement Keys",
true, true,
"Enables or disables the camera height movement keys, which default to Q, E, R, F." + "Enables or disables the camera height movement keys, which default to Q, E, R, F." +
" \nUseful to disable if you want to let your character lean in Freecam mode"); " \nUseful to disable if you want to let your character lean in Freecam mode");
CameraMousewheelZoom = Config.Bind( CameraMousewheelZoom = Config.Bind(
TogglesSectionName, TogglesSectionName,
"CameraMousewheelZoom", "Camera Mousewheel Zoom",
true, true,
"Enables or disables camera movement on mousewheel scroll. Just in case you find it annoying and want that disabled."); "Enables or disables camera movement on mousewheel scroll. Just in case you find it annoying and want that disabled.");
CameraRememberLastPosition = Config.Bind( CameraRememberLastPosition = Config.Bind(
TogglesSectionName, TogglesSectionName,
"CameraRememberLastPosition", "Remember Last Camera Position",
false, false,
"If enabled, returning to Freecam mode will put the camera to it's last position which was saved when exiting Freecam mode."); "If enabled, returning to Freecam mode will put the camera to it's last position which is saved when exiting Freecam mode.");
} }
} }
} }

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net472</TargetFramework> <TargetFramework>net471</TargetFramework>
<Version>1.3.2</Version> <Version>1.4.4</Version>
<Authors>Terkoiz, Kobrakon, CWX</Authors> <Authors>Terkoiz, Kobrakon, CWX</Authors>
<RepositoryUrl>https://dev.sp-tarkov.com/Terkoiz/Freecam</RepositoryUrl> <RepositoryUrl>https://dev.sp-tarkov.com/Terkoiz/Freecam</RepositoryUrl>
<PackageLicenseExpression>NCSA</PackageLicenseExpression> <PackageLicenseExpression>NCSA</PackageLicenseExpression>
@ -16,11 +16,11 @@
<ItemGroup> <ItemGroup>
<Reference Include="Aki.Reflection"> <Reference Include="Aki.Reflection">
<HintPath>..\References\EFT_Managed\Aki.Reflection.dll</HintPath> <HintPath>..\References\SPT\spt-reflection.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="Assembly-CSharp"> <Reference Include="Assembly-CSharp">
<HintPath>..\References\Hollowed\Assembly-CSharp.dll</HintPath> <HintPath>..\References\EFT_Managed\Assembly-CSharp.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="Comfort"> <Reference Include="Comfort">