v1.1.0 rifle suppressor with suppressed shot sound
This commit is contained in:
@@ -1,206 +1,114 @@
|
||||
\# 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. You can
|
||||
also put the pistol suppressor on the rifle for quiet, suppressed shots.
|
||||
|
||||
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
|
||||
|
||||
|
||||
\## Installation
|
||||
|
||||
|
||||
|
||||
\### Easy install
|
||||
|
||||
|
||||
### 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
|
||||
|
||||
\### Manual install
|
||||
|
||||
|
||||
|
||||
\#### Step 1: Install RedLoader
|
||||
|
||||
|
||||
|
||||
\[RedLoader](https://github.com/ToniMacaroni/RedLoader/releases/latest) is the mod
|
||||
|
||||
[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 `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 `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 |
|
||||
|
||||
| `scope` | Show whether the scope is on or off |
|
||||
| `scope off` | Go back to the vanilla scope. The suppressor is not affected |
|
||||
| `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 |
|
||||
|
||||
| `suppressor` | Show whether the rifle suppressor is on or off |
|
||||
| `suppressor on` | Put the suppressor on the rifle |
|
||||
| `suppressor off` | Take the suppressor off the rifle |
|
||||
| `scopedebug` | Toggle a debug readout above the range |
|
||||
|
||||
### Suppressor
|
||||
|
||||
Run `suppressor on` to put the pistol suppressor on the end of the rifle barrel.
|
||||
Rifle shots then use the suppressed pistol shot sound. It stays on until you run
|
||||
`suppressor off`, even after restarting the game. You do not need a suppressor in
|
||||
your inventory.
|
||||
|
||||
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
|
||||
|
||||
The on or off setting, suppressor, 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
|
||||
|
||||
|
||||
\## Troubleshooting
|
||||
|
||||
|
||||
|
||||
Check `\_RedLoader\\Latest.log` in your game folder. RifleScope logs a line when it
|
||||
|
||||
loads.
|
||||
|
||||
Check `_RedLoader\Latest.log` in your game folder. RifleScope logs a line when it
|
||||
loads.
|
||||
+306
-9
@@ -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,10 +26,16 @@ 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 string SuppressorModName = "CompactPistolSuppressorMod";
|
||||
private const string SuppressedFireEvent = "event:/SotF Events/player sounds/Weapons/PistolTactical/PistolTacticalFire";
|
||||
private const string MuzzleName = "RifleScopeMuzzle";
|
||||
private const string RifleFireEvent = "event:/SotF Events/player sounds/Weapons/Rifle/rifle_fire";
|
||||
private const string UpgradeParameter = "upgrade";
|
||||
private const float SuppressedUpgradeValue = 0.2f;
|
||||
private const int MilDotCount = 10;
|
||||
private const float MilDotSize = 0.4f;
|
||||
private const float MinDotPx = 7f;
|
||||
@@ -44,6 +56,12 @@ public class RifleScope : SonsMod
|
||||
private static float _windCm;
|
||||
private static bool _debug;
|
||||
private static bool _enabled = true;
|
||||
private static bool _suppressor;
|
||||
private static string _originalFireEvent;
|
||||
private static HarmonyLib.Harmony _audioHarmony;
|
||||
private static bool _loggedParamError;
|
||||
private static bool _loggedPistolParams;
|
||||
private static bool _reissuing;
|
||||
private static readonly List<(Renderer Renderer, int Slot, Material Original)> RedDotSlots = new();
|
||||
private static string _configPath;
|
||||
|
||||
@@ -101,9 +119,6 @@ public class RifleScope : SonsMod
|
||||
|
||||
private static void Tick()
|
||||
{
|
||||
if (!_enabled)
|
||||
return;
|
||||
|
||||
if (!_rifle || !_rifle.gameObject.activeInHierarchy)
|
||||
{
|
||||
_rifle = null;
|
||||
@@ -115,6 +130,9 @@ public class RifleScope : SonsMod
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_enabled)
|
||||
return;
|
||||
|
||||
var manager = _rifle._cameraFovManager;
|
||||
if (!manager)
|
||||
{
|
||||
@@ -137,14 +155,274 @@ public class RifleScope : SonsMod
|
||||
continue;
|
||||
_rifle = rifle;
|
||||
_projectile = FindProjectileTransform(rifle);
|
||||
if (!_overlay)
|
||||
CreateOverlay();
|
||||
HideRedDot(rifle);
|
||||
_originalFireEvent ??= rifle._gunShotAudioEvent;
|
||||
if (_enabled)
|
||||
{
|
||||
if (!_overlay)
|
||||
CreateOverlay();
|
||||
HideRedDot(rifle);
|
||||
}
|
||||
if (_suppressor)
|
||||
SetSuppressor(rifle, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static WeaponMod FindSuppressorMod()
|
||||
{
|
||||
foreach (var mod in Resources.FindObjectsOfTypeAll<WeaponMod>())
|
||||
{
|
||||
if (mod && mod.name == SuppressorModName)
|
||||
return mod;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Transform FindChild(Transform root, string name)
|
||||
{
|
||||
foreach (var t in root.GetComponentsInChildren<Transform>(true))
|
||||
{
|
||||
if (t.name == name)
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool EnsureMuzzleSlot(RangedWeaponController rifle, WeaponMods mods)
|
||||
{
|
||||
var links = mods._modLocations;
|
||||
for (var i = 0; i < links.Count; i++)
|
||||
{
|
||||
if (links[i].Slot == WeaponMod.Slot.Muzzle)
|
||||
return true;
|
||||
}
|
||||
|
||||
var anchor = FindChild(rifle.transform, "ProjectileVisualTransform");
|
||||
if (!anchor)
|
||||
return false;
|
||||
|
||||
var muzzle = FindChild(anchor.parent, MuzzleName);
|
||||
if (!muzzle)
|
||||
{
|
||||
var go = new GameObject(MuzzleName);
|
||||
go.layer = anchor.gameObject.layer;
|
||||
muzzle = go.transform;
|
||||
muzzle.SetParent(anchor.parent, false);
|
||||
muzzle.localPosition = anchor.localPosition;
|
||||
muzzle.localRotation = Quaternion.identity;
|
||||
muzzle.localScale = Vector3.one;
|
||||
}
|
||||
|
||||
var link = new WeaponMods.ModLink();
|
||||
link.Slot = WeaponMod.Slot.Muzzle;
|
||||
link.Location = muzzle;
|
||||
links.Add(link);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Type FindGameType(string name)
|
||||
{
|
||||
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
Type[] types;
|
||||
try
|
||||
{
|
||||
types = asm.GetTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException e)
|
||||
{
|
||||
types = e.Types.Where(t => t != null).ToArray();
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var t in types)
|
||||
{
|
||||
if (t != null && t.Name == name)
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void InstallAudioPatches()
|
||||
{
|
||||
if (_audioHarmony != null)
|
||||
return;
|
||||
_audioHarmony = new HarmonyLib.Harmony("RifleScope.SuppressorAudio");
|
||||
|
||||
var handler = FindGameType("FMOD_AnimationEventHandler");
|
||||
var animPrefix = new HarmonyMethod(typeof(RifleScope).GetMethod(nameof(AnimEventPrefix), BindingFlags.NonPublic | BindingFlags.Static));
|
||||
var count = 0;
|
||||
if (handler != null)
|
||||
{
|
||||
foreach (var m in handler.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
|
||||
{
|
||||
var ps = m.GetParameters();
|
||||
if (m.Name != "playFMODEvent" || ps.Length == 0 || ps[0].ParameterType != typeof(string))
|
||||
continue;
|
||||
_audioHarmony.Patch(m, prefix: animPrefix);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
var common = FindGameType("FMODCommon");
|
||||
var oneshotPrefix = new HarmonyMethod(typeof(RifleScope).GetMethod(nameof(OneshotPrefix), BindingFlags.NonPublic | BindingFlags.Static));
|
||||
if (common != null)
|
||||
{
|
||||
foreach (var m in common.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly))
|
||||
{
|
||||
var ps = m.GetParameters();
|
||||
if (m.Name != "PlayOneshotInternal" || ps.Length < 4 || ps[0].ParameterType != typeof(string))
|
||||
continue;
|
||||
_audioHarmony.Patch(m, prefix: oneshotPrefix);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
RLog.Msg($"Suppressor audio: patched {count} methods (handler={(handler != null)}, common={(common != null)})");
|
||||
}
|
||||
|
||||
private static bool RifleSuppressedNow() =>
|
||||
_suppressor && _rifle && _rifle.gameObject.activeInHierarchy;
|
||||
|
||||
private static bool AnimEventPrefix(Component __instance, object[] __args)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!RifleSuppressedNow() || __args == null || __args.Length == 0 || __args[0] as string != RifleFireEvent)
|
||||
return true;
|
||||
if (!__instance || __instance.transform.root != _rifle.transform.root)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool OneshotPrefix(MethodBase __originalMethod, object[] __args)
|
||||
{
|
||||
if (_reissuing)
|
||||
return true;
|
||||
|
||||
try
|
||||
{
|
||||
if (__args == null || __args.Length < 4 || __args[0] as string != SuppressedFireEvent)
|
||||
return true;
|
||||
|
||||
var existing = __args[3] as Il2CppReferenceArray<Il2CppSystem.Object>;
|
||||
|
||||
if (!RifleSuppressedNow())
|
||||
{
|
||||
if (!_loggedPistolParams && existing != null && existing.Length > 0)
|
||||
{
|
||||
_loggedPistolParams = true;
|
||||
RLog.Msg($"Suppressor audio: pistol params [{string.Join(", ", existing.Select(Describe))}]");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
var oldCount = existing?.Length ?? 0;
|
||||
for (var i = 0; i < oldCount; i++)
|
||||
{
|
||||
if (existing[i] != null && existing[i].ToString() == UpgradeParameter)
|
||||
return true;
|
||||
}
|
||||
|
||||
var array = new Il2CppReferenceArray<Il2CppSystem.Object>(oldCount + 2);
|
||||
for (var i = 0; i < oldCount; i++)
|
||||
array[i] = existing[i];
|
||||
array[oldCount] = new Il2CppSystem.Object(IL2CPP.ManagedStringToIl2Cpp(UpgradeParameter));
|
||||
array[oldCount + 1] = BoxFloat(SuppressedUpgradeValue);
|
||||
|
||||
var args = (object[])__args.Clone();
|
||||
args[3] = array;
|
||||
_reissuing = true;
|
||||
try
|
||||
{
|
||||
__originalMethod.Invoke(null, args);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_reissuing = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!_loggedParamError)
|
||||
{
|
||||
_loggedParamError = true;
|
||||
RLog.Error($"Suppressor audio: could not play suppressed shot: {(e.InnerException ?? e).Message}");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static Il2CppSystem.Object BoxFloat(float value)
|
||||
{
|
||||
object single = new Il2CppSystem.Single();
|
||||
typeof(Il2CppSystem.Single).GetField("m_value", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)?.SetValue(single, value);
|
||||
return ((Il2CppSystem.Single)single).BoxIl2CppObject();
|
||||
}
|
||||
|
||||
private static string Describe(Il2CppSystem.Object o)
|
||||
{
|
||||
if (o == null)
|
||||
return "null";
|
||||
try
|
||||
{
|
||||
return $"{o.GetIl2CppType().Name}:{o.ToString()}";
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetSuppressor(RangedWeaponController rifle, bool on)
|
||||
{
|
||||
var weapon = rifle._rangedWeapon;
|
||||
var mods = weapon ? weapon._weaponMods : null;
|
||||
if (!mods)
|
||||
{
|
||||
Say("Suppressor: rifle has no WeaponMods");
|
||||
return;
|
||||
}
|
||||
|
||||
var mod = FindSuppressorMod();
|
||||
if (!mod)
|
||||
{
|
||||
Say("Suppressor: pistol suppressor mod is not loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
if (on)
|
||||
{
|
||||
InstallAudioPatches();
|
||||
if (!EnsureMuzzleSlot(rifle, mods))
|
||||
{
|
||||
Say("Suppressor: could not find the rifle muzzle");
|
||||
return;
|
||||
}
|
||||
|
||||
var applied = mods.HasMod(mod.ModItemId) || mods.ApplyMod(mod);
|
||||
rifle._gunShotAudioEvent = SuppressedFireEvent;
|
||||
RLog.Msg($"Suppressor on: applied={applied} slot={mod.AttachesToSlot} required={mod.RequiredSlot} item={mod.ModItemId}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mods.HasMod(mod.ModItemId))
|
||||
mods.RemoveMod(mod);
|
||||
if (_originalFireEvent != null)
|
||||
rifle._gunShotAudioEvent = _originalFireEvent;
|
||||
}
|
||||
|
||||
private static Transform FindProjectileTransform(RangedWeaponController rifle)
|
||||
{
|
||||
var constraint = rifle._projectileTransformConstraint;
|
||||
@@ -308,7 +586,6 @@ public class RifleScope : SonsMod
|
||||
settings._FieldOfViewTargetOffset_k__BackingField = original;
|
||||
}
|
||||
RestoreRedDot();
|
||||
_rifle = null;
|
||||
}
|
||||
|
||||
private static Material HiddenFor(Material original)
|
||||
@@ -688,6 +965,24 @@ public class RifleScope : SonsMod
|
||||
Say($"RifleScope is {(_enabled ? "on" : "off")}. Usage: scope on or scope off");
|
||||
}
|
||||
|
||||
[DebugCommand("suppressor")]
|
||||
private static void SuppressorCommand(string args)
|
||||
{
|
||||
args = (args ?? string.Empty).Trim().ToLowerInvariant();
|
||||
|
||||
if (args != "on" && args != "off")
|
||||
{
|
||||
Say($"Rifle suppressor is {(_suppressor ? "on" : "off")}. Usage: suppressor on or suppressor off");
|
||||
return;
|
||||
}
|
||||
|
||||
_suppressor = args == "on";
|
||||
Save();
|
||||
if (_rifle)
|
||||
SetSuppressor(_rifle, _suppressor);
|
||||
Say($"Rifle suppressor {(_suppressor ? "on" : "off")}");
|
||||
}
|
||||
|
||||
[DebugCommand("scopezoom")]
|
||||
private static void ScopeZoomCommand(string args)
|
||||
{
|
||||
@@ -790,6 +1085,8 @@ public class RifleScope : SonsMod
|
||||
_windCm = wind;
|
||||
if (parts.Length > 3)
|
||||
_enabled = parts[3] != "0";
|
||||
if (parts.Length > 4)
|
||||
_suppressor = parts[4] == "1";
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -801,7 +1098,7 @@ public class RifleScope : SonsMod
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText(_configPath, $"{_zoom.ToString(Inv)} {_trimCm.ToString(Inv)} {_windCm.ToString(Inv)} {(_enabled ? "1" : "0")}");
|
||||
File.WriteAllText(_configPath, $"{_zoom.ToString(Inv)} {_trimCm.ToString(Inv)} {_windCm.ToString(Inv)} {(_enabled ? "1" : "0")} {(_suppressor ? "1" : "0")}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AssemblyName>RifleScope</AssemblyName>
|
||||
<RootNamespace>RifleScope</RootNamespace>
|
||||
<Version>1.0.1</Version>
|
||||
<Version>1.1.0</Version>
|
||||
<NoWarn>CS0436;CS1701;CS1702;MSB3277;MSB3106</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -34,4 +34,4 @@
|
||||
<EmbeddedResource Include="manifest.json" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
+2
-2
@@ -3,9 +3,9 @@
|
||||
"id": "RifleScope",
|
||||
"name": "RifleScope",
|
||||
"author": "JustinOros",
|
||||
"version": "1.0.1",
|
||||
"version": "1.1.0",
|
||||
"description": "Stronger rifle scope magnification and a crosshair reticle",
|
||||
"gameVersion": "1.0.0",
|
||||
"platform": "Client",
|
||||
"type": "Mod"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user