From 6b0c5e746dd6f47801df43a985456a1babe13da7 Mon Sep 17 00:00:00 2001 From: Justin Oros Date: Sun, 27 Sep 2026 13:23:59 -0700 Subject: [PATCH] Add scope on and off command --- README.md | 162 +++++++++++++++++++++++++++++++++++++++++--------- RifleScope.cs | 60 ++++++++++++++++++- 2 files changed, 192 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 35d2aea..8d7405d 100644 --- a/README.md +++ b/README.md @@ -1,100 +1,206 @@ -# Rifle Scope +\# Rifle Scope + + A stronger rifle scope for Sons of the Forest. Aiming down the rifle scope zooms + 5x further than the vanilla scope and shows a full screen scope view with a + crosshair reticle, mil dots and a rangefinder instead of the red dot. -## Multiplayer + + +\## Multiplayer + + Client side only. Nothing gets installed on a dedicated server, and other players + do not need the mod. -## Installation -### Easy install + +\## Installation + + + +\### Easy install + + Close the game, open PowerShell and paste: + + ```powershell + irm https://raw.githubusercontent.com/JustinOros/sotf-riflescope/main/Install.ps1 | iex + ``` + + It finds your game, installs RedLoader if needed, and installs the latest + RifleScope. Run it again any time to update. -### Manual install -#### Step 1: Install RedLoader -[RedLoader](https://github.com/ToniMacaroni/RedLoader/releases/latest) is the mod +\### Manual install + + + +\#### Step 1: Install RedLoader + + + +\[RedLoader](https://github.com/ToniMacaroni/RedLoader/releases/latest) is the mod + loader for Sons of the Forest. The game cannot load any mod without it, so + install it first. You only have to do this once. -1. Download `RedLoader.zip` from the - [latest RedLoader release](https://github.com/ToniMacaroni/RedLoader/releases/latest) -2. Extract it into your Sons of the Forest folder, the one containing - `SonsOfTheForest.exe`, usually - `C:\Program Files (x86)\Steam\steamapps\common\Sons Of The Forest` -3. Launch the game once and wait until you reach the main menu. The first launch - takes a few minutes while RedLoader processes the game files -4. Check that `MODS` appears on the main menu, then quit -#### Step 2: Install RifleScope -1. Download `RifleScope.zip` from the - [latest release](https://github.com/JustinOros/sotf-riflescope/releases/latest) -2. Extract it into the `Mods` folder inside your game folder -3. You should end up with: +1\. Download `RedLoader.zip` from the + + \[latest RedLoader release](https://github.com/ToniMacaroni/RedLoader/releases/latest) + +2\. Extract it into your Sons of the Forest folder, the one containing + + `SonsOfTheForest.exe`, usually + + `C:\\Program Files (x86)\\Steam\\steamapps\\common\\Sons Of The Forest` + +3\. Launch the game once and wait until you reach the main menu. The first launch + + takes a few minutes while RedLoader processes the game files + +4\. Check that `MODS` appears on the main menu, then quit + + + +\#### Step 2: Install RifleScope + + + +1\. Download `RifleScope.zip` from the + + \[latest release](https://github.com/JustinOros/sotf-riflescope/releases/latest) + +2\. Extract it into the `Mods` folder inside your game folder + +3\. You should end up with: + + ``` -Mods\RifleScope.dll -Mods\RifleScope\manifest.json + +Mods\\RifleScope.dll + +Mods\\RifleScope\\manifest.json + ``` -## Usage + + +\## Usage + + Equip the rifle and aim. Once zoomed in, the rifle model is hidden and the scope + view is shown. Your shot goes where the crosshair is. + + The red number at the bottom left of the scope is the range in meters to whatever + is under the crosshair. + + The reticle has 10 mil dots in each direction. At 5x each dot is 2 mils, which + covers 20 cm at 100 m. At 10x and higher each dot is 1 mil. Use them to hold over + or to the side at long range. + + Press F1 to open the console, then use these commands: + + | Command | Action | + | --- | --- | + +| `scope` | Show whether the mod is on or off | + +| `scope off` | Turn the mod off and go back to the vanilla scope | + +| `scope on` | Turn the mod back on | + | `scopezoom` | Show the current zoom | + | `scopezoom 5` | Set the zoom as a multiple of the vanilla scope, 1 to 50. The default is 5 | + | `scopetrim` | Show the current vertical trim | + | `scopetrim 50` | Set the vertical trim, -200 to 200. Positive moves hits down, negative moves hits up. The default is 50 | + | `scopewind` | Show the current windage | + | `scopewind 20` | Set the windage, -200 to 200. Positive moves hits right, negative moves hits left. The default is 0 | + | `scopedebug` | Toggle a debug readout above the range | + + Trim and windage are angle adjustments, so a setting that is right at one range + stays right at every range. -The zoom, trim and windage are saved to `UserData\RifleScope.txt` in your game + + +The on or off setting, zoom, trim and windage are saved to `UserData\\RifleScope.txt` in your game + folder. Setting the zoom to 1 keeps vanilla zoom and the normal scope view, + without the red dot. -## Building from source + + +\## Building from source + + Requires the .NET 8 SDK and RedLoader installed with its game assemblies + generated. + + ```powershell -.\build.ps1 -Install + +.\\build.ps1 -Install + ``` + + Use `-Package` to build `RifleScope.zip` for a release. Pass `-GameDir "path"` if + the game is not found automatically. -## Troubleshooting -Check `_RedLoader\Latest.log` in your game folder. RifleScope logs a line when it + +\## Troubleshooting + + + +Check `\_RedLoader\\Latest.log` in your game folder. RifleScope logs a line when it + loads. + diff --git a/RifleScope.cs b/RifleScope.cs index aa27a58..92a9afe 100644 --- a/RifleScope.cs +++ b/RifleScope.cs @@ -43,6 +43,8 @@ public class RifleScope : SonsMod private static float _trimCm = DefaultTrimCm; private static float _windCm; private static bool _debug; + private static bool _enabled = true; + private static readonly List<(Renderer Renderer, int Slot, Material Original)> RedDotSlots = new(); private static string _configPath; private static RifleAnimatorController _rifle; @@ -99,6 +101,9 @@ public class RifleScope : SonsMod private static void Tick() { + if (!_enabled) + return; + if (!_rifle || !_rifle.gameObject.activeInHierarchy) { _rifle = null; @@ -269,6 +274,7 @@ public class RifleScope : SonsMod var mat = mats[i]; if (!mat || HiddenIds.Contains(mat.GetInstanceID()) || !mat.shader || mat.shader.name != RedDotShader) continue; + RedDotSlots.Add((renderer, i, mat)); mats[i] = HiddenFor(mat); changed = true; } @@ -277,6 +283,34 @@ public class RifleScope : SonsMod } } + private static void RestoreRedDot() + { + foreach (var (renderer, slot, original) in RedDotSlots) + { + if (!renderer || !original) + continue; + var mats = renderer.sharedMaterials; + if (slot >= mats.Length || !mats[slot] || !HiddenIds.Contains(mats[slot].GetInstanceID())) + continue; + mats[slot] = original; + renderer.sharedMaterials = mats; + } + RedDotSlots.Clear(); + } + + private static void Disable() + { + SetZoomed(false, null); + if (_rifle) + { + var settings = _rifle._fovChangeSettings; + if (settings != null && OriginalOffsets.TryGetValue(settings.Pointer, out var original)) + settings._FieldOfViewTargetOffset_k__BackingField = original; + } + RestoreRedDot(); + _rifle = null; + } + private static Material HiddenFor(Material original) { var id = original.GetInstanceID(); @@ -634,6 +668,26 @@ public class RifleScope : SonsMod return tex; } + [DebugCommand("scope")] + private static void ScopeCommand(string args) + { + args = (args ?? string.Empty).Trim().ToLowerInvariant(); + + if (args == "on" || args == "off") + { + _enabled = args == "on"; + Save(); + if (_enabled) + _rifle = null; + else + Disable(); + Say($"RifleScope {(_enabled ? "on" : "off")}"); + return; + } + + Say($"RifleScope is {(_enabled ? "on" : "off")}. Usage: scope on or scope off"); + } + [DebugCommand("scopezoom")] private static void ScopeZoomCommand(string args) { @@ -734,6 +788,8 @@ public class RifleScope : SonsMod _trimCm = trim; if (parts.Length > 2 && float.TryParse(parts[2], NumberStyles.Float, Inv, out var wind) && wind >= -MaxWindCm && wind <= MaxWindCm) _windCm = wind; + if (parts.Length > 3) + _enabled = parts[3] != "0"; } catch (Exception e) { @@ -745,11 +801,11 @@ public class RifleScope : SonsMod { try { - File.WriteAllText(_configPath, $"{_zoom.ToString(Inv)} {_trimCm.ToString(Inv)} {_windCm.ToString(Inv)}"); + File.WriteAllText(_configPath, $"{_zoom.ToString(Inv)} {_trimCm.ToString(Inv)} {_windCm.ToString(Inv)} {(_enabled ? "1" : "0")}"); } catch (Exception e) { RLog.Error($"RifleScope could not write config: {e.Message}"); } } -} +} \ No newline at end of file