Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07b8ebb2e7 | ||
|
|
ad9987cac0 | ||
|
|
af00ddb866 | ||
|
|
796e898deb | ||
|
|
a5f241c1b3 | ||
|
|
b3aecc2bd5 | ||
|
|
7ac7c41645 | ||
|
|
f618337421 | ||
|
|
6b0c5e746d | ||
|
|
a785fd5c1a |
@@ -117,7 +117,6 @@ try {
|
||||
Write-Host 'Start Sons of the Forest, then:'
|
||||
Write-Host ' 1. Check that MODS appears on the main menu and lists RifleScope'
|
||||
Write-Host ' 2. Load into a game, equip the rifle and aim down the scope'
|
||||
Write-Host ' 3. Press F1 and type scopezoom to see or change the zoom'
|
||||
Write-Host ''
|
||||
}
|
||||
catch {
|
||||
@@ -129,4 +128,3 @@ catch {
|
||||
Write-Host ''
|
||||
}
|
||||
|
||||
Read-Host 'Press Enter to close' | Out-Null
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
# Rifle Scope
|
||||
|
||||
[](https://github.com/JustinOros/sotf-riflescope/releases) [](https://github.com/JustinOros/sotf-riflescope/releases/latest)
|
||||
|
||||
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.
|
||||
|
||||
Want a suppressed rifle too? Install
|
||||
[RifleSuppressor](https://github.com/JustinOros/sotf-riflesuppressor). It used to
|
||||
be part of this mod and is now its own mod, so you can use either one or both.
|
||||
|
||||
## Multiplayer
|
||||
|
||||
Client side only. Nothing gets installed on a dedicated server, and other players
|
||||
@@ -67,15 +73,21 @@ Press F1 to open the console, then use these commands:
|
||||
|
||||
| Command | Action |
|
||||
| --- | --- |
|
||||
| `scope` | Show whether the scope is on or off |
|
||||
| `scope off` | Go back to the vanilla scope |
|
||||
| `scope on` | Turn the scope 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 |
|
||||
| `scopetrim 60` | Set the vertical trim, -200 to 200. Positive moves hits down, negative moves hits up. The default is 60 |
|
||||
| `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 |
|
||||
|
||||
The zoom, trim and windage are saved to `UserData\RifleScope.txt` in your game
|
||||
Trim and windage are angle adjustments, so a setting that is right at one range
|
||||
stays right at every range.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
+104
-16
@@ -2,9 +2,15 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using RedLoader;
|
||||
using RedLoader.Utils;
|
||||
using Sons.FieldOfView;
|
||||
using Sons.Items.Core;
|
||||
using Sons.Weapon;
|
||||
using SonsSdk;
|
||||
using SonsSdk.Attributes;
|
||||
@@ -20,9 +26,10 @@ public class RifleScope : SonsMod
|
||||
private const float DefaultZoom = 5f;
|
||||
private const float MinZoom = 1f;
|
||||
private const float MaxZoom = 50f;
|
||||
private const float DefaultTrimCm = 50f;
|
||||
private const float DefaultTrimCm = 60f;
|
||||
private const float MaxTrimCm = 200f;
|
||||
private const float MaxWindCm = 200f;
|
||||
private const float TrimReferenceRange = 50f;
|
||||
private const int MilDotCount = 10;
|
||||
private const float MilDotSize = 0.4f;
|
||||
private const float MinDotPx = 7f;
|
||||
@@ -42,10 +49,12 @@ 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;
|
||||
private static float _nextSearch;
|
||||
private static RifleAnimatorController _pendingRifle;
|
||||
private static float _hipFov;
|
||||
private static float _vanillaAimFov = 35f;
|
||||
private static float _targetAimFov;
|
||||
@@ -73,6 +82,7 @@ public class RifleScope : SonsMod
|
||||
public RifleScope()
|
||||
{
|
||||
OnUpdateCallback = OnUpdate;
|
||||
HarmonyPatchAll = true;
|
||||
}
|
||||
|
||||
protected override void OnSdkInitialized()
|
||||
@@ -99,16 +109,23 @@ public class RifleScope : SonsMod
|
||||
private static void Tick()
|
||||
{
|
||||
if (!_rifle || !_rifle.gameObject.activeInHierarchy)
|
||||
{
|
||||
if (_rifle || _hiddenCam)
|
||||
{
|
||||
_rifle = null;
|
||||
SetZoomed(false, null);
|
||||
if (Time.unscaledTime < _nextSearch)
|
||||
return;
|
||||
_nextSearch = Time.unscaledTime + 0.5f;
|
||||
if (!FindRifle())
|
||||
return;
|
||||
}
|
||||
|
||||
var pending = _pendingRifle;
|
||||
_pendingRifle = null;
|
||||
if (!pending || !pending.gameObject.activeInHierarchy)
|
||||
return;
|
||||
AdoptRifle(pending);
|
||||
}
|
||||
|
||||
if (!_enabled)
|
||||
return;
|
||||
|
||||
var manager = _rifle._cameraFovManager;
|
||||
if (!manager)
|
||||
{
|
||||
@@ -123,20 +140,25 @@ public class RifleScope : SonsMod
|
||||
SetZoomed(zoomed, cam);
|
||||
}
|
||||
|
||||
private static bool FindRifle()
|
||||
internal static void OnWeaponTick(RangedWeaponController controller)
|
||||
{
|
||||
foreach (var rifle in UnityEngine.Object.FindObjectsOfType<RifleAnimatorController>())
|
||||
if (!controller || (_rifle && _rifle.Pointer == controller.Pointer))
|
||||
return;
|
||||
var rifle = controller.TryCast<RifleAnimatorController>();
|
||||
if (rifle && rifle.IsLocalPlayer())
|
||||
_pendingRifle = rifle;
|
||||
}
|
||||
|
||||
private static void AdoptRifle(RifleAnimatorController rifle)
|
||||
{
|
||||
if (!rifle || !rifle.gameObject.activeInHierarchy || !rifle.IsLocalPlayer())
|
||||
continue;
|
||||
_rifle = rifle;
|
||||
_projectile = FindProjectileTransform(rifle);
|
||||
if (_enabled)
|
||||
{
|
||||
if (!_overlay)
|
||||
CreateOverlay();
|
||||
HideRedDot(rifle);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Transform FindProjectileTransform(RangedWeaponController rifle)
|
||||
@@ -196,8 +218,9 @@ public class RifleScope : SonsMod
|
||||
}
|
||||
|
||||
CenterPoint(cam, out var point);
|
||||
point -= cam.transform.up * (_trimCm * 0.01f);
|
||||
point += cam.transform.right * (_windCm * 0.01f);
|
||||
var scale = Vector3.Distance(cam.transform.position, point) / TrimReferenceRange;
|
||||
point -= cam.transform.up * (_trimCm * 0.01f * scale);
|
||||
point += cam.transform.right * (_windCm * 0.01f * scale);
|
||||
var dir = point - _projectile.position;
|
||||
if (dir.sqrMagnitude < 0.0001f)
|
||||
return;
|
||||
@@ -267,6 +290,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;
|
||||
}
|
||||
@@ -275,6 +299,33 @@ 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();
|
||||
}
|
||||
|
||||
private static Material HiddenFor(Material original)
|
||||
{
|
||||
var id = original.GetInstanceID();
|
||||
@@ -632,6 +683,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)
|
||||
{
|
||||
@@ -732,6 +803,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)
|
||||
{
|
||||
@@ -743,7 +816,7 @@ 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)
|
||||
{
|
||||
@@ -751,3 +824,18 @@ public class RifleScope : SonsMod
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(RangedWeaponController), nameof(RangedWeaponController.CheckFireInput))]
|
||||
internal static class CheckFireInputPatch
|
||||
{
|
||||
private static void Postfix(RangedWeaponController __instance)
|
||||
{
|
||||
try
|
||||
{
|
||||
global::RifleScope.RifleScope.OnWeaponTick(__instance);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AssemblyName>RifleScope</AssemblyName>
|
||||
<RootNamespace>RifleScope</RootNamespace>
|
||||
<Version>1.0.0</Version>
|
||||
<Version>1.2.0</Version>
|
||||
<NoWarn>CS0436;CS1701;CS1702;MSB3277;MSB3106</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
"id": "RifleScope",
|
||||
"name": "RifleScope",
|
||||
"author": "JustinOros",
|
||||
"version": "1.0.0",
|
||||
"version": "1.2.0",
|
||||
"description": "Stronger rifle scope magnification and a crosshair reticle",
|
||||
"gameVersion": "1.0.0",
|
||||
"platform": "Client",
|
||||
|
||||
Reference in New Issue
Block a user