Compare commits
No commits in common. "master" and "1.2.0" have entirely different histories.
11
.gitignore
vendored
11
.gitignore
vendored
@ -1,10 +1,3 @@
|
||||
# Custom ignores
|
||||
project/References/EFT_Managed/*
|
||||
|
||||
# Allow these files, despite the rules above
|
||||
!project/References/EFT_Managed/.keep
|
||||
!project/References/SPT/.keep
|
||||
|
||||
# ---> VisualStudio
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
@ -248,10 +241,6 @@ ClientBin/
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
.idea
|
||||
Freecam.sln.DotSettings.user
|
||||
Project/.idea/
|
||||
Project/Shared/*
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
|
11
README.md
11
README.md
@ -1,6 +1,6 @@
|
||||
# Freecam
|
||||
|
||||
A BepInEx plugin for SPT-AKI that allows you to detach the camera and fly around freely in Escape From Tarkov.
|
||||
An SPT-AKI module mod that allows you to detach the camera and fly around freely in Escape From Tarkov.
|
||||
|
||||
### Controls
|
||||
|
||||
@ -21,13 +21,14 @@ Alternatively, you can find the `com.terkoiz.freecam.cfg` file in your `BepInEx/
|
||||
|
||||
### Known issues
|
||||
|
||||
1. 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. When flying to distant parts of the map in freecam mode, LODs are not triggered (these seem to follow the player)
|
||||
1. Your weapon doesn't turn invisible when you enter freecam mode
|
||||
2. When teleporting to camera position, the camera rotation gets copied exactly, potentially causing the player model to tilt
|
||||
3. Game version UI element is not hidden when toggling UI
|
||||
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
|
||||
|
||||
1. Download/clone this repository
|
||||
2. Open your current SPT directory and copy all files from `\EscapeFromTarkov_Data\Managed` into this solution's `\References\EFT_Managed` folder.
|
||||
2. Re-import dependencies. I recommend you do this from the SPT-AKI/Modules project's `Shared/Managed` folder, if you have the Modules project fully setup.
|
||||
3. Rebuild the project in the Release configuration.
|
||||
4. Grab the `Terkoiz.Freecam.dll` file from the `bin/Release` folder and use it wherever. Refer to the "How to install" section if you need help here.
|
@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageRestore>
|
||||
<add key="enabled" value="True" />
|
||||
<add key="automatic" value="True" />
|
||||
</packageRestore>
|
||||
<activePackageSource>
|
||||
<add key="All" value="(Aggregate source)" />
|
||||
</activePackageSource>
|
||||
<packageSources>
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
<add key="BepInEx" value="https://nuget.bepinex.dev/v3/index.json" protocolVersion="3" />
|
||||
</packageSources>
|
||||
</configuration>
|
@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32616.157
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Terkoiz.Freecam", "Terkoiz.Freecam\Terkoiz.Freecam.csproj", "{9C38A2B1-5F09-49FE-AC57-9FBEF7717582}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{9C38A2B1-5F09-49FE-AC57-9FBEF7717582}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9C38A2B1-5F09-49FE-AC57-9FBEF7717582}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9C38A2B1-5F09-49FE-AC57-9FBEF7717582}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9C38A2B1-5F09-49FE-AC57-9FBEF7717582}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {26F91A8D-3767-457A-821C-F66AFD620885}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -1,44 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
using JetBrains.Annotations;
|
||||
using JetBrains.Annotations;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Terkoiz.Freecam
|
||||
@ -6,14 +6,14 @@ namespace Terkoiz.Freecam
|
||||
/// <summary>
|
||||
/// A simple free camera to be added to a Unity game object.
|
||||
///
|
||||
/// Full credit to Ashley Davis on GitHub for the initial code:
|
||||
/// Full credit to Ashley Davis on GitHub for the inital code:
|
||||
/// https://gist.github.com/ashleydavis/f025c03a9221bc840a2b
|
||||
///
|
||||
/// </summary>
|
||||
public class Freecam : MonoBehaviour
|
||||
{
|
||||
public bool IsActive = false;
|
||||
|
||||
|
||||
[UsedImplicitly]
|
||||
public void Update()
|
||||
{
|
||||
@ -27,44 +27,44 @@ namespace Terkoiz.Freecam
|
||||
|
||||
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
|
||||
{
|
||||
transform.position += (-transform.right * (movementSpeed * Time.deltaTime));
|
||||
transform.position += (-transform.right * movementSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
|
||||
{
|
||||
transform.position += (transform.right * (movementSpeed * Time.deltaTime));
|
||||
transform.position += (transform.right * movementSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
|
||||
{
|
||||
transform.position += (transform.forward * (movementSpeed * Time.deltaTime));
|
||||
transform.position += (transform.forward * movementSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
|
||||
{
|
||||
transform.position += (-transform.forward * (movementSpeed * Time.deltaTime));
|
||||
transform.position += (-transform.forward * movementSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
if (FreecamPlugin.CameraHeightMovement.Value)
|
||||
{
|
||||
if (Input.GetKey(KeyCode.Q))
|
||||
{
|
||||
transform.position += (transform.up * (movementSpeed * Time.deltaTime));
|
||||
transform.position += (transform.up * movementSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
if (Input.GetKey(KeyCode.E))
|
||||
{
|
||||
transform.position += (-transform.up * (movementSpeed * Time.deltaTime));
|
||||
transform.position += (-transform.up * movementSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
if (Input.GetKey(KeyCode.R) || Input.GetKey(KeyCode.PageUp))
|
||||
{
|
||||
transform.position += (Vector3.up * (movementSpeed * Time.deltaTime));
|
||||
transform.position += (Vector3.up * movementSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
if (Input.GetKey(KeyCode.F) || Input.GetKey(KeyCode.PageDown))
|
||||
{
|
||||
transform.position += (-Vector3.up * (movementSpeed * Time.deltaTime));
|
||||
transform.position += (-Vector3.up * movementSpeed * Time.deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,15 +78,9 @@ namespace Terkoiz.Freecam
|
||||
if (axis != 0)
|
||||
{
|
||||
var zoomSensitivity = fastMode ? FreecamPlugin.CameraFastZoomSpeed.Value : FreecamPlugin.CameraZoomSpeed.Value;
|
||||
transform.position += transform.forward * (axis * zoomSensitivity);
|
||||
transform.position += transform.forward * axis * zoomSensitivity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
private void OnDestroy()
|
||||
{
|
||||
Destroy(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
using System.Reflection;
|
||||
using Comfort.Common;
|
||||
using EFT;
|
||||
using EFT.CameraControl;
|
||||
using EFT.UI;
|
||||
using HarmonyLib;
|
||||
using JetBrains.Annotations;
|
||||
using MonoMod.RuntimeDetour;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Terkoiz.Freecam
|
||||
@ -13,48 +15,40 @@ namespace Terkoiz.Freecam
|
||||
private GameObject _mainCamera;
|
||||
private Freecam _freeCamScript;
|
||||
|
||||
private EftBattleUIScreen _playerUi;
|
||||
private BattleUIScreen _playerUi;
|
||||
private bool _uiHidden;
|
||||
|
||||
private GamePlayerOwner _gamePlayerOwner;
|
||||
private MethodInfo _playerMoveMethod;
|
||||
private MethodInfo _playerRotateMethod;
|
||||
private Detour _moveDetour;
|
||||
private Detour _rotateDetour;
|
||||
|
||||
private Vector3? _lastPosition;
|
||||
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]
|
||||
public void Start()
|
||||
{
|
||||
// Get Main Camera
|
||||
_mainCamera = GetLocalPlayerFromWorld().GetComponent<PlayerCameraController>().Camera.gameObject;
|
||||
if (_mainCamera == null)
|
||||
// We locate and get the MethodInfo for the Move method that we will later detour to prevent the player from moving during Freecam
|
||||
_playerMoveMethod = typeof(Player).GetMethod("Move");
|
||||
if (_playerMoveMethod == null)
|
||||
{
|
||||
FreecamPlugin.Logger.LogError("Failed to locate main camera");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get Player UI
|
||||
_playerUi = Singleton<CommonUI>.Instance.EftBattleUIScreen;
|
||||
if (_playerUi == null)
|
||||
FreecamPlugin.Logger.LogError("Failed to locate the Player.Move method!");
|
||||
}
|
||||
|
||||
// Same deal here, but for player rotation
|
||||
_playerRotateMethod = typeof(Player).GetMethod("Rotate");
|
||||
if (_playerRotateMethod == null)
|
||||
{
|
||||
FreecamPlugin.Logger.LogError("Failed to locate player UI");
|
||||
return;
|
||||
}
|
||||
|
||||
// Add Freecam script to main camera in scene
|
||||
_freeCamScript = _mainCamera.AddComponent<Freecam>();
|
||||
if (_freeCamScript == null)
|
||||
{
|
||||
FreecamPlugin.Logger.LogError("Failed to add Freecam script to Camera");
|
||||
}
|
||||
|
||||
// Get GamePlayerOwner component
|
||||
_gamePlayerOwner = GetLocalPlayerFromWorld().GetComponentInChildren<GamePlayerOwner>();
|
||||
if (_gamePlayerOwner == null)
|
||||
{
|
||||
FreecamPlugin.Logger.LogError("Failed to locate GamePlayerOwner");
|
||||
FreecamPlugin.Logger.LogError("Failed to locate the Player.Rotate method!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[UsedImplicitly]
|
||||
public void Update()
|
||||
{
|
||||
@ -68,11 +62,6 @@ namespace Terkoiz.Freecam
|
||||
ToggleCamera();
|
||||
}
|
||||
|
||||
if (FreecamPlugin.ToggleFreecamControls.Value.IsDown())
|
||||
{
|
||||
ToggleCameraControls();
|
||||
}
|
||||
|
||||
if (FreecamPlugin.TeleportToCamera.Value.IsDown())
|
||||
{
|
||||
MovePlayerToCamera();
|
||||
@ -87,7 +76,29 @@ namespace Terkoiz.Freecam
|
||||
// Get our own Player instance. Null means we're not in a raid
|
||||
var localPlayer = GetLocalPlayerFromWorld();
|
||||
if (localPlayer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If we don't have the main camera object cached, go look for it in the scene
|
||||
if (_mainCamera == null)
|
||||
{
|
||||
// Finding a GameObject by name directly is apparently better than searching for objects of a type.
|
||||
// 'FPS Camera' is our main camera instance - so we just grab that
|
||||
_mainCamera = GameObject.Find("FPS Camera");
|
||||
if (_mainCamera == null)
|
||||
{
|
||||
FreecamPlugin.Logger.LogError("Failed to locate main camera");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the Freecam script and attach it to the main camera
|
||||
if (_freeCamScript == null)
|
||||
{
|
||||
ClearDetours();
|
||||
_freeCamScript = _mainCamera.AddComponent<Freecam>();
|
||||
}
|
||||
|
||||
if (!_freeCamScript.IsActive)
|
||||
{
|
||||
@ -106,18 +117,22 @@ namespace Terkoiz.Freecam
|
||||
{
|
||||
var localPlayer = GetLocalPlayerFromWorld();
|
||||
if (localPlayer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If we don't have the main camera cached, it means we have yet to enter Freecam mode and there is nowhere to teleport to
|
||||
if (_mainCamera == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Move the player to the camera's current position and switch to First Person mode
|
||||
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
|
||||
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, _mainCamera.transform.rotation);
|
||||
SetPlayerToFirstPersonMode(localPlayer);
|
||||
}
|
||||
@ -130,7 +145,21 @@ namespace Terkoiz.Freecam
|
||||
{
|
||||
// Check if we're currently in a raid
|
||||
if (GetLocalPlayerFromWorld() == null)
|
||||
{
|
||||
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);
|
||||
_uiHidden = !_uiHidden;
|
||||
@ -165,8 +194,17 @@ namespace Terkoiz.Freecam
|
||||
FreecamPlugin.Logger.LogError("Failed to get the PlayerBody field");
|
||||
}
|
||||
|
||||
// Instead of Detouring, just turn off _gamePlayerOwner which takes the input
|
||||
_gamePlayerOwner.enabled = false;
|
||||
// Detour the Player.Move method into an empty one, preventing the character from moving during Freecam mode
|
||||
if (_playerMoveMethod != null)
|
||||
{
|
||||
_moveDetour = new Detour(_playerMoveMethod, typeof(FreecamController).GetMethod(nameof(DisabledMove)));
|
||||
}
|
||||
|
||||
// Same deal here, but for player rotation
|
||||
if (_playerRotateMethod != null)
|
||||
{
|
||||
_rotateDetour = new Detour(_playerRotateMethod, typeof(FreecamController).GetMethod(nameof(DisabledRotate)));
|
||||
}
|
||||
|
||||
if (FreecamPlugin.CameraRememberLastPosition.Value && _lastPosition != null && _lastRotation != null)
|
||||
{
|
||||
@ -190,32 +228,12 @@ namespace Terkoiz.Freecam
|
||||
_lastPosition = _mainCamera.transform.position;
|
||||
_lastRotation = _mainCamera.transform.rotation;
|
||||
}
|
||||
|
||||
// re-enable _gamePlayerOwner
|
||||
_gamePlayerOwner.enabled = true;
|
||||
|
||||
ClearDetours();
|
||||
|
||||
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>
|
||||
/// Gets the current <see cref="Player"/> instance if it's available
|
||||
/// </summary>
|
||||
@ -224,18 +242,56 @@ namespace Terkoiz.Freecam
|
||||
{
|
||||
// If the GameWorld instance is null or has no RegisteredPlayers, it most likely means we're not in a raid
|
||||
var gameWorld = Singleton<GameWorld>.Instance;
|
||||
if (gameWorld == null || gameWorld.MainPlayer == null)
|
||||
if (gameWorld == null || gameWorld.RegisteredPlayers == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// One of the RegisteredPlayers will have the IsYourPlayer flag set, which will be our own Player instance
|
||||
return gameWorld.MainPlayer;
|
||||
return gameWorld.RegisteredPlayers.Find(p => p.IsYourPlayer);
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
public void OnDestroy()
|
||||
{
|
||||
// Destroy FreeCamScript before FreeCamController if exists
|
||||
Destroy(_freeCamScript);
|
||||
_freeCamScript.IsActive = false;
|
||||
|
||||
// Making sure no stray Detours are left
|
||||
ClearDetours();
|
||||
|
||||
_lastPosition = null;
|
||||
_lastRotation = null;
|
||||
}
|
||||
|
||||
public void ClearDetours()
|
||||
{
|
||||
if (_moveDetour != null)
|
||||
{
|
||||
_moveDetour.Dispose();
|
||||
_moveDetour = null;
|
||||
}
|
||||
|
||||
if (_rotateDetour != null)
|
||||
{
|
||||
_rotateDetour.Dispose();
|
||||
_rotateDetour = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An empty method that's used to detour the player Move method, preventing movement during Freecam mode
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public static void DisabledMove(Player self, Vector2 direction)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An empty method that's used to detour the player Rotate method, preventing rotation during Freecam mode
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public static void DisabledRotate(Player self, Vector2 deltaRotation, bool ignoreClamp = false)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
using System.Reflection;
|
||||
using SPT.Reflection.Patching;
|
||||
using Comfort.Common;
|
||||
using EFT;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace Terkoiz.Freecam
|
||||
{
|
||||
public class FreecamPatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return AccessTools.Method(typeof(GameWorld), nameof(GameWorld.OnGameStarted));
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
public static void PatchPostFix()
|
||||
{
|
||||
var gameWorld = Singleton<GameWorld>.Instance;
|
||||
|
||||
if (gameWorld == null)
|
||||
return;
|
||||
|
||||
// Add FreecamController to GameWorld GameObject
|
||||
gameWorld.gameObject.AddComponent<FreecamController>();
|
||||
}
|
||||
}
|
||||
}
|
@ -3,92 +3,72 @@ using BepInEx.Configuration;
|
||||
using BepInEx.Logging;
|
||||
using JetBrains.Annotations;
|
||||
using UnityEngine;
|
||||
using KeyboardShortcut = BepInEx.Configuration.KeyboardShortcut;
|
||||
|
||||
namespace Terkoiz.Freecam
|
||||
{
|
||||
[BepInPlugin("com.terkoiz.freecam", "Terkoiz.Freecam", "1.4.4")]
|
||||
[BepInPlugin("com.terkoiz.freecam", "Terkoiz.Freecam", "1.2.0")]
|
||||
public class FreecamPlugin : BaseUnityPlugin
|
||||
{
|
||||
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;
|
||||
private static GameObject HookObject;
|
||||
|
||||
// Keyboard shortcut config entries
|
||||
private const string KeybindSectionName = "Keybinds";
|
||||
internal static ConfigEntry<KeyboardShortcut> ToggleFreecamMode;
|
||||
internal static ConfigEntry<KeyboardShortcut> ToggleFreecamControls;
|
||||
internal static ConfigEntry<KeyboardShortcut> TeleportToCamera;
|
||||
internal static ConfigEntry<KeyboardShortcut> ToggleUi;
|
||||
|
||||
// Camera settings config entries
|
||||
private const string CameraSettingsSectionName = "Camera Settings";
|
||||
private const string CameraSettingsSectionName = "CameraSettings";
|
||||
internal static ConfigEntry<float> CameraMoveSpeed;
|
||||
internal static ConfigEntry<float> CameraFastMoveSpeed;
|
||||
internal static ConfigEntry<float> CameraLookSensitivity;
|
||||
internal static ConfigEntry<float> CameraZoomSpeed;
|
||||
internal static ConfigEntry<float> CameraFastZoomSpeed;
|
||||
|
||||
// General toggles
|
||||
private const string TogglesSectionName = "Toggles";
|
||||
internal static ConfigEntry<bool> CameraHeightMovement;
|
||||
internal static ConfigEntry<bool> CameraMousewheelZoom;
|
||||
internal static ConfigEntry<bool> CameraRememberLastPosition;
|
||||
|
||||
// TODO: Hook into camera OnDestroy to run the OnDestroy from FreecamController
|
||||
|
||||
[UsedImplicitly]
|
||||
internal void Start()
|
||||
{
|
||||
Logger = base.Logger;
|
||||
|
||||
InitConfiguration();
|
||||
|
||||
new FreecamPatch().Enable();
|
||||
new FallDamagePatch().Enable();
|
||||
HookObject = new GameObject();
|
||||
HookObject.AddComponent<FreecamController>();
|
||||
DontDestroyOnLoad(HookObject);
|
||||
}
|
||||
|
||||
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(
|
||||
KeybindSectionName,
|
||||
"Toggle Freecam",
|
||||
"ToggleCamera",
|
||||
new KeyboardShortcut(KeyCode.KeypadPlus),
|
||||
"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(
|
||||
KeybindSectionName,
|
||||
"Teleport To Camera",
|
||||
"TeleportToCamera",
|
||||
new KeyboardShortcut(KeyCode.KeypadEnter),
|
||||
"The keyboard shortcut that teleports the player to camera position");
|
||||
|
||||
ToggleUi = Config.Bind(
|
||||
KeybindSectionName,
|
||||
"Toggle UI",
|
||||
"ToggleUi",
|
||||
new KeyboardShortcut(KeyCode.KeypadMultiply),
|
||||
"The keyboard shortcut that toggles the game UI");
|
||||
|
||||
CameraMoveSpeed = Config.Bind(
|
||||
CameraSettingsSectionName,
|
||||
"Camera Speed",
|
||||
"CameraMoveSpeed",
|
||||
10f,
|
||||
new ConfigDescription(
|
||||
"The speed at which the camera will move normally",
|
||||
@ -96,7 +76,7 @@ namespace Terkoiz.Freecam
|
||||
|
||||
CameraFastMoveSpeed = Config.Bind(
|
||||
CameraSettingsSectionName,
|
||||
"Camera Sprint Speed",
|
||||
"CameraFastMoveSpeed",
|
||||
100f,
|
||||
new ConfigDescription(
|
||||
"The speed at which the camera will move when the Shift key is held down",
|
||||
@ -104,7 +84,7 @@ namespace Terkoiz.Freecam
|
||||
|
||||
CameraLookSensitivity = Config.Bind(
|
||||
CameraSettingsSectionName,
|
||||
"Camera Mouse Sensitivity",
|
||||
"CameraLookSensitivity",
|
||||
3f,
|
||||
new ConfigDescription(
|
||||
"Camera free look mouse sensitivity",
|
||||
@ -112,7 +92,7 @@ namespace Terkoiz.Freecam
|
||||
|
||||
CameraZoomSpeed = Config.Bind(
|
||||
CameraSettingsSectionName,
|
||||
"Camera Zoom Speed",
|
||||
"CameraMousewheelZoomSpeed",
|
||||
10f,
|
||||
new ConfigDescription(
|
||||
"Amount to zoom the camera when using the mouse wheel",
|
||||
@ -120,30 +100,30 @@ namespace Terkoiz.Freecam
|
||||
|
||||
CameraFastZoomSpeed = Config.Bind(
|
||||
CameraSettingsSectionName,
|
||||
"Camera Zoom Sprint Speed",
|
||||
"CameraMousewheelFastZoomSpeed",
|
||||
50f,
|
||||
new ConfigDescription(
|
||||
"Amount to zoom the camera when using the mouse wheel while holding Shift",
|
||||
new AcceptableValueRange<float>(0.01f, 1000f)));
|
||||
|
||||
|
||||
CameraHeightMovement = Config.Bind(
|
||||
TogglesSectionName,
|
||||
"Camera Height Movement Keys",
|
||||
"CameraHeightMovementKeys",
|
||||
true,
|
||||
"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");
|
||||
|
||||
CameraMousewheelZoom = Config.Bind(
|
||||
TogglesSectionName,
|
||||
"Camera Mousewheel Zoom",
|
||||
"CameraMousewheelZoom",
|
||||
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.");
|
||||
|
||||
CameraRememberLastPosition = Config.Bind(
|
||||
TogglesSectionName,
|
||||
"Remember Last Camera Position",
|
||||
"CameraRememberLastPosition",
|
||||
false,
|
||||
"If enabled, returning to Freecam mode will put the camera to it's last position which is saved when exiting Freecam mode.");
|
||||
"If enabled, returning to Freecam mode will put the camera to it's last position which was saved when exiting Freecam mode.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
36
project/Terkoiz.Freecam/Properties/AssemblyInfo.cs
Normal file
36
project/Terkoiz.Freecam/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Terkoiz.Freecam")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Terkoiz.Freecam")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("be2de623-48ff-4807-9696-167a17787718")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
@ -1,48 +1,109 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net471</TargetFramework>
|
||||
<Version>1.4.4</Version>
|
||||
<Authors>Terkoiz, Kobrakon, CWX</Authors>
|
||||
<RepositoryUrl>https://dev.sp-tarkov.com/Terkoiz/Freecam</RepositoryUrl>
|
||||
<PackageLicenseExpression>NCSA</PackageLicenseExpression>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{BE2DE623-48FF-4807-9696-167A17787718}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Terkoiz.Freecam</RootNamespace>
|
||||
<AssemblyName>Terkoiz.Freecam</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>
|
||||
</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Core" Version="5.4.21">
|
||||
<ExcludeAssets>runtime</ExcludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Aki.Reflection">
|
||||
<HintPath>..\References\SPT\spt-reflection.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
<Reference Include="0Harmony, Version=2.7.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\HarmonyX.2.7.0\lib\net45\0Harmony.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>..\References\EFT_Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
<HintPath>..\Shared\Hollowed\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BepInEx, Version=5.4.19.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BepInEx.BaseLib.5.4.19\lib\net35\BepInEx.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Comfort">
|
||||
<HintPath>..\References\EFT_Managed\Comfort.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
<HintPath>..\Shared\Managed\Comfort.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Comfort.Unity">
|
||||
<HintPath>..\References\EFT_Managed\Comfort.Unity.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
<Reference Include="ItemComponent.Types">
|
||||
<HintPath>..\Shared\Managed\ItemComponent.Types.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Cecil, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Cecil.Mdb, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Mdb.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Cecil.Pdb, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Pdb.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Cecil.Rocks, Version=0.11.4.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Mono.Cecil.0.11.4\lib\net40\Mono.Cecil.Rocks.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MonoMod.RuntimeDetour, Version=21.12.13.1, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MonoMod.RuntimeDetour.21.12.13.1\lib\net452\MonoMod.RuntimeDetour.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MonoMod.Utils, Version=21.12.13.1, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MonoMod.Utils.21.12.13.1\lib\net452\MonoMod.Utils.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>..\References\EFT_Managed\UnityEngine.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
<HintPath>..\Shared\Managed\UnityEngine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>..\References\EFT_Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
<HintPath>..\Shared\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.InputLegacyModule">
|
||||
<HintPath>..\References\EFT_Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
<HintPath>..\Shared\Managed\UnityEngine.InputLegacyModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UIModule">
|
||||
<HintPath>..\Shared\Managed\UnityEngine.UIModule.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
<ItemGroup>
|
||||
<Compile Include="Freecam.cs" />
|
||||
<Compile Include="FreecamController.cs" />
|
||||
<Compile Include="FreecamPlugin.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\BepInEx.Core.5.4.19\build\BepInEx.Core.targets" Condition="Exists('..\packages\BepInEx.Core.5.4.19\build\BepInEx.Core.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\BepInEx.Core.5.4.19\build\BepInEx.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\BepInEx.Core.5.4.19\build\BepInEx.Core.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
11
project/Terkoiz.Freecam/app.config
Normal file
11
project/Terkoiz.Freecam/app.config
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Mono.Cecil" publicKeyToken="50cebf1cceb9d05e" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-0.11.4.0" newVersion="0.11.4.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
9
project/Terkoiz.Freecam/packages.config
Normal file
9
project/Terkoiz.Freecam/packages.config
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="BepInEx.BaseLib" version="5.4.19" targetFramework="net472" />
|
||||
<package id="BepInEx.Core" version="5.4.19" targetFramework="net472" />
|
||||
<package id="HarmonyX" version="2.7.0" targetFramework="net472" />
|
||||
<package id="Mono.Cecil" version="0.11.4" targetFramework="net472" />
|
||||
<package id="MonoMod.RuntimeDetour" version="21.12.13.1" targetFramework="net472" />
|
||||
<package id="MonoMod.Utils" version="21.12.13.1" targetFramework="net472" />
|
||||
</packages>
|
Reference in New Issue
Block a user