diff --git a/PioneerSize/PioneerSize.csproj b/PioneerSize/PioneerSize.csproj
new file mode 100644
index 0000000..ef3a82e
--- /dev/null
+++ b/PioneerSize/PioneerSize.csproj
@@ -0,0 +1,60 @@
+
+
+ net6.0
+ latest
+ disable
+ disable
+ true
+ PioneerSize
+ PioneerSize
+ true
+ D:\SteamLibrary\steamapps\common\Skopje83
+
+
+
+
+ $(GameDir)\BepInEx\core\0Harmony.dll
+ false
+
+
+ $(GameDir)\BepInEx\core\BepInEx.Core.dll
+ false
+
+
+ $(GameDir)\BepInEx\core\BepInEx.Unity.IL2CPP.dll
+ false
+
+
+ $(GameDir)\BepInEx\core\Il2CppInterop.Runtime.dll
+ false
+
+
+ $(GameDir)\BepInEx\interop\Il2Cppmscorlib.dll
+ false
+
+
+ $(GameDir)\BepInEx\interop\SkopjeAssembly.dll
+ false
+
+
+ $(GameDir)\BepInEx\interop\FishNet.Runtime.dll
+ false
+
+
+ $(GameDir)\BepInEx\interop\KCC.dll
+ false
+
+
+ $(GameDir)\BepInEx\interop\Archon.SwissArmyLib.dll
+ false
+
+
+ $(GameDir)\BepInEx\interop\UnityEngine.CoreModule.dll
+ false
+
+
+ $(GameDir)\BepInEx\interop\UnityEngine.PhysicsModule.dll
+ false
+
+
+
diff --git a/PioneerSize/PioneerSizePlugin.cs b/PioneerSize/PioneerSizePlugin.cs
new file mode 100644
index 0000000..583c256
--- /dev/null
+++ b/PioneerSize/PioneerSizePlugin.cs
@@ -0,0 +1,579 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using BepInEx;
+using BepInEx.Configuration;
+using BepInEx.Logging;
+using BepInEx.Unity.IL2CPP;
+using HarmonyLib;
+using Il2CppInterop.Runtime;
+using Il2CppInterop.Runtime.Injection;
+using Il2CppInterop.Runtime.InteropTypes;
+using KinematicCharacterController;
+using Skopje.Modding;
+using UnityEngine;
+
+namespace PioneerSize
+{
+ [BepInPlugin(PluginGuid, PluginName, PluginVersion)]
+ public class PioneerSizePlugin : BasePlugin
+ {
+ public const string PluginGuid = "com.skopje.pioneersize";
+ public const string PluginName = "PioneerSize";
+ public const string PluginVersion = "1.0.2";
+
+ internal static ManualLogSource LogSource;
+ internal static ConfigEntry Height;
+ internal static ConfigEntry SpeedMultiplier;
+
+ static Harmony _harmony;
+ static GameObject _host;
+ static Il2CppSystem.Action _onPlayerStartedClient;
+ static Il2CppSystem.Action _onPlayerStoppedClient;
+
+ public override void Load()
+ {
+ LogSource = Log;
+ Height = Config.Bind("Size", "Height", 1.8f, new ConfigDescription(
+ "Standing height in meters. Crouch keeps the game's own crouch fraction of this height.",
+ new AcceptableValueRange(0.5f, 3f)));
+ SpeedMultiplier = Config.Bind("Size", "SpeedMultiplier", 1f, new ConfigDescription(
+ "Multiplies walk, sprint, crouch, air, jump, and dash speed. 1 is normal.",
+ new AcceptableValueRange(0.05f, 10f)));
+
+ ClassInjector.RegisterTypeInIl2Cpp();
+
+ _onPlayerStartedClient = DelegateSupport.ConvertDelegate>(new Action(PioneerSizeApply.OnPlayerStartedClient));
+ _onPlayerStoppedClient = DelegateSupport.ConvertDelegate>(new Action(PioneerSizeApply.OnPlayerStoppedClient));
+ ModAPI.add_OnPlayerStartedClient(_onPlayerStartedClient);
+ ModAPI.add_OnPlayerStoppedClient(_onPlayerStoppedClient);
+
+ _harmony = new Harmony(PluginGuid);
+ Patch(AccessTools.Method(typeof(SkopjePlayer), "OnStartClient"), nameof(PioneerSizeApply.AfterPlayer));
+ Patch(AccessTools.Method(typeof(SkopjeCharacterController), "Start"), nameof(PioneerSizeApply.AfterController));
+ Patch(AccessTools.Method(typeof(SkopjeCharacterController), "ResetController"), nameof(PioneerSizeApply.AfterReset));
+ Patch(AccessTools.Method(typeof(SkopjePlayer), "RefreshActiveModels"), nameof(PioneerSizeApply.AfterPlayer));
+ Patch(AccessTools.Method(typeof(SkopjePlayer), "RefreshPlayerCollider"), nameof(PioneerSizeApply.AfterPlayer));
+
+ _host = new GameObject("PioneerSize");
+ UnityEngine.Object.DontDestroyOnLoad(_host);
+ _host.hideFlags = HideFlags.HideAndDontSave;
+ _host.AddComponent();
+
+ LogSource.LogInfo($"{PluginName} {PluginVersion} loaded. Height {Height.Value} m, speed {SpeedMultiplier.Value}. Config: {Config.ConfigFilePath}");
+ }
+
+ public override bool Unload()
+ {
+ PioneerSizeApply.RestoreAll();
+ if (_harmony != null)
+ _harmony.UnpatchSelf();
+ if (_onPlayerStartedClient != null)
+ ModAPI.remove_OnPlayerStartedClient(_onPlayerStartedClient);
+ if (_onPlayerStoppedClient != null)
+ ModAPI.remove_OnPlayerStoppedClient(_onPlayerStoppedClient);
+ if (_host != null)
+ {
+ UnityEngine.Object.Destroy(_host);
+ _host = null;
+ }
+
+ return true;
+ }
+
+ static void Patch(MethodInfo method, string postfix)
+ {
+ if (method == null)
+ {
+ LogSource.LogWarning("PioneerSize hook was not found: " + postfix);
+ return;
+ }
+
+ _harmony.Patch(method, postfix: new HarmonyMethod(typeof(PioneerSizeApply), postfix));
+ }
+ }
+
+ public class PioneerSizeDriver : MonoBehaviour
+ {
+ void Update()
+ {
+ PioneerSizeApply.Pump();
+ }
+ }
+
+ static class PioneerSizeApply
+ {
+ const float MinHeight = 0.5f;
+ const float MaxHeight = 3f;
+ const float MinSpeed = 0.05f;
+ const float MaxSpeed = 10f;
+
+ sealed class Body
+ {
+ public float Walk;
+ public float Air;
+ public float AirAccel;
+ public float Crouch;
+ public float Sprint;
+ public float Jump;
+ public float Dash;
+ public float Height;
+ public float Radius;
+ public float Step;
+ public float YOffset;
+ public Vector3 Head;
+ public Vector3 Chest;
+ public Vector3 Center;
+ public bool HeadLocal;
+ public bool ChestLocal;
+ public bool CenterLocal;
+ public float AppliedScale = -1f;
+ public float AppliedHeight = -1f;
+ public float AppliedSpeed = -1f;
+ public bool Logged;
+ }
+
+ sealed class Avatar
+ {
+ public Vector3 Mesh = Vector3.one;
+ public bool HasMesh;
+ public Vector3 First = Vector3.one;
+ public bool HasFirst;
+ public Vector3 Third = Vector3.one;
+ public bool HasThird;
+ public float FirstPersonPlayerScale = 1f;
+ public Vector3 CameraLocal;
+ public bool HasCamera;
+ public bool CameraUnderVisual;
+ public float OwnerHeight;
+ public float OwnerRadius;
+ public Vector3 OwnerCenter;
+ public bool HasOwner;
+ public bool OwnerIsMotor;
+ public float AppliedScale = -1f;
+ }
+
+ static readonly Dictionary Bodies = new Dictionary();
+ static readonly Dictionary Avatars = new Dictionary();
+ static readonly List Watching = new List();
+ static bool _restoring;
+ static int _errors;
+
+ public static void OnPlayerStartedClient(SkopjePlayer player)
+ {
+ if (!Alive(player))
+ return;
+
+ Watch(player);
+ bool applied = Apply(player, false);
+ if (PioneerSizePlugin.LogSource != null)
+ {
+ PioneerSizePlugin.LogSource.LogInfo(applied
+ ? $"OnPlayerStartedClient applied size to player {player.PlayerIdx}."
+ : $"OnPlayerStartedClient queued player {player.PlayerIdx}. The body is not ready yet.");
+ }
+ }
+
+ public static void OnPlayerStoppedClient(SkopjePlayer player)
+ {
+ IntPtr key = Key(player);
+ if (key == IntPtr.Zero)
+ return;
+
+ for (int i = Watching.Count - 1; i >= 0; i--)
+ {
+ if (Key(Watching[i]) == key)
+ Watching.RemoveAt(i);
+ }
+
+ Avatars.Remove(key);
+ SkopjeCharacterController controller = player.SkopjeCharacterController;
+ IntPtr bodyKey = Key(controller);
+ if (bodyKey != IntPtr.Zero)
+ Bodies.Remove(bodyKey);
+ }
+
+ public static void AfterPlayer(SkopjePlayer __instance)
+ {
+ if (!Alive(__instance))
+ return;
+
+ Watch(__instance);
+ Apply(__instance, false);
+ }
+
+ public static void AfterController(SkopjeCharacterController __instance)
+ {
+ if (!Alive(__instance))
+ return;
+
+ SkopjePlayer player = __instance.Player;
+ if (!Alive(player))
+ return;
+
+ Watch(player);
+ Apply(player, false);
+ }
+
+ public static void AfterReset(SkopjeCharacterController __instance)
+ {
+ if (!Alive(__instance))
+ return;
+
+ SkopjePlayer player = __instance.Player;
+ if (!Alive(player))
+ return;
+
+ Watch(player);
+ Apply(player, true);
+ }
+
+ public static void Pump()
+ {
+ for (int i = Watching.Count - 1; i >= 0; i--)
+ {
+ SkopjePlayer player = Watching[i];
+ if (!Alive(player))
+ {
+ Watching.RemoveAt(i);
+ continue;
+ }
+
+ Apply(player, false);
+ }
+ }
+
+ public static void RestoreAll()
+ {
+ _restoring = true;
+ try
+ {
+ for (int i = 0; i < Watching.Count; i++)
+ {
+ if (Alive(Watching[i]))
+ Apply(Watching[i], true);
+ }
+ }
+ finally
+ {
+ _restoring = false;
+ Watching.Clear();
+ Bodies.Clear();
+ Avatars.Clear();
+ }
+ }
+
+ static bool Apply(SkopjePlayer player, bool reset)
+ {
+ if (!Alive(player))
+ return false;
+
+ try
+ {
+ SkopjeCharacterController controller = player.SkopjeCharacterController;
+ if (!Alive(controller))
+ return false;
+
+ IntPtr id = Key(controller);
+ if (!Bodies.TryGetValue(id, out Body body))
+ {
+ if (!Ready(controller))
+ return false;
+
+ body = Capture(controller);
+ Bodies[id] = body;
+ }
+
+ float height = _restoring ? body.Height : ReadHeight();
+ float speed = ReadSpeed();
+ float scale = body.Height > 0.01f ? height / body.Height : 1f;
+ bool sizeDirty = reset || body.AppliedScale < 0f || Mathf.Abs(body.AppliedHeight - height) > 0.0001f;
+ bool speedDirty = reset || body.AppliedSpeed < 0f || Mathf.Abs(body.AppliedSpeed - speed) > 0.0001f;
+ if (!sizeDirty && !speedDirty)
+ return true;
+
+ if (speedDirty)
+ WriteSpeeds(controller, body, speed);
+ if (sizeDirty)
+ WriteSize(controller, player, body, scale, reset || body.AppliedScale < 0f);
+
+ body.AppliedScale = scale;
+ body.AppliedHeight = height;
+ body.AppliedSpeed = speed;
+
+ if (!body.Logged && PioneerSizePlugin.LogSource != null)
+ {
+ body.Logged = true;
+ PioneerSizePlugin.LogSource.LogInfo($"Pioneer height {height:0.##} m, stock {body.Height:0.##} m, speed x{speed:0.##} on player {player.PlayerIdx}.");
+ }
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ LogOnce(ex);
+ return false;
+ }
+ }
+
+ static void WriteSpeeds(SkopjeCharacterController controller, Body body, float speed)
+ {
+ controller.MaxStableMoveSpeed = body.Walk * speed;
+ controller.MaxAirMoveSpeed = body.Air * speed;
+ controller.AirAccelerationSpeed = body.AirAccel * speed;
+ controller.CrouchMoveSpeed = body.Crouch * speed;
+ controller.SprintSpeed = body.Sprint * speed;
+ controller.JumpSpeed = body.Jump * speed;
+ controller.DashSpeed = body.Dash * speed;
+ }
+
+ // Standing height is the crouch system's full-height reference. The live capsule is scaled
+ // from wherever the stance currently is, so a crouch in progress is not popped back up.
+ static void WriteSize(SkopjeCharacterController controller, SkopjePlayer player, Body body, float scale, bool fromVanilla)
+ {
+ float ratio = fromVanilla || body.AppliedScale <= 0.0001f ? scale : scale / body.AppliedScale;
+ controller.standingHeight = body.Height * scale;
+ controller.playerRadius = body.Radius * scale;
+
+ KinematicCharacterMotor motor = controller.Motor;
+ if (Alive(motor))
+ {
+ motor.MaxStepHeight = body.Step * scale;
+ float radius = fromVanilla ? body.Radius * scale : motor.CapsuleRadius * ratio;
+ float height = fromVanilla ? body.Height * scale : motor.CapsuleHeight * ratio;
+ float yOffset = fromVanilla
+ ? (body.YOffset > 0.001f ? body.YOffset * scale : height * 0.5f)
+ : motor.CapsuleYOffset * ratio;
+ motor.SetCapsuleDimensions(radius, height, yOffset);
+ }
+
+ if (body.HeadLocal)
+ controller.originalHeadPosition = (fromVanilla ? body.Head : controller.originalHeadPosition) * (fromVanilla ? scale : ratio);
+ if (body.ChestLocal)
+ controller.originalChestPosition = (fromVanilla ? body.Chest : controller.originalChestPosition) * (fromVanilla ? scale : ratio);
+ if (body.CenterLocal)
+ controller.originalCenterPosition = (fromVanilla ? body.Center : controller.originalCenterPosition) * (fromVanilla ? scale : ratio);
+
+ ScaleVisuals(player, controller, scale, ratio, fromVanilla);
+ }
+
+ static void ScaleVisuals(SkopjePlayer player, SkopjeCharacterController controller, float scale, float ratio, bool fromVanilla)
+ {
+ IntPtr id = Key(player);
+ if (id == IntPtr.Zero || Mathf.Abs(ratio - 1f) < 0.0001f)
+ return;
+
+ if (!Avatars.TryGetValue(id, out Avatar avatar))
+ {
+ avatar = new Avatar();
+ Avatars[id] = avatar;
+ }
+
+ CaptureAvatar(player, avatar);
+
+ Transform mesh = controller.MeshRoot;
+ if (avatar.HasMesh && mesh != null)
+ mesh.localScale = fromVanilla ? avatar.Mesh * scale : mesh.localScale * ratio;
+
+ if (avatar.HasFirst && player.FirstPerson != null && player.FirstPerson.transform.localScale.sqrMagnitude > 0.0001f)
+ player.FirstPerson.transform.localScale = fromVanilla ? avatar.First * scale : player.FirstPerson.transform.localScale * ratio;
+
+ if (avatar.HasThird && player.ThirdPerson != null && player.ThirdPerson.transform.localScale.sqrMagnitude > 0.0001f)
+ player.ThirdPerson.transform.localScale = fromVanilla ? avatar.Third * scale : player.ThirdPerson.transform.localScale * ratio;
+
+ player.FirstPersonPlayerScale = fromVanilla ? avatar.FirstPersonPlayerScale * scale : player.FirstPersonPlayerScale * ratio;
+
+ if (avatar.HasCamera && !avatar.CameraUnderVisual && player.SkopjeFPSCamera != null)
+ {
+ Transform cam = player.SkopjeFPSCamera.transform;
+ cam.localPosition = fromVanilla ? avatar.CameraLocal * scale : cam.localPosition * ratio;
+ }
+
+ CapsuleCollider owner = OwnerCapsule(player);
+ if (avatar.HasOwner && owner != null && !avatar.OwnerIsMotor)
+ {
+ owner.height = fromVanilla ? avatar.OwnerHeight * scale : owner.height * ratio;
+ owner.radius = fromVanilla ? avatar.OwnerRadius * scale : owner.radius * ratio;
+ owner.center = fromVanilla ? avatar.OwnerCenter * scale : owner.center * ratio;
+ }
+ }
+
+ static void CaptureAvatar(SkopjePlayer player, Avatar avatar)
+ {
+ Transform mesh = Alive(player.SkopjeCharacterController) ? player.SkopjeCharacterController.MeshRoot : null;
+ if (!avatar.HasMesh && mesh != null && mesh.localScale.sqrMagnitude > 0.0001f)
+ {
+ avatar.Mesh = mesh.localScale;
+ avatar.HasMesh = true;
+ }
+
+ if (!avatar.HasFirst && player.FirstPerson != null && player.FirstPerson.transform.localScale.sqrMagnitude > 0.0001f)
+ {
+ avatar.First = player.FirstPerson.transform.localScale;
+ avatar.HasFirst = true;
+ }
+
+ if (!avatar.HasThird && player.ThirdPerson != null && player.ThirdPerson.transform.localScale.sqrMagnitude > 0.0001f)
+ {
+ avatar.Third = player.ThirdPerson.transform.localScale;
+ avatar.HasThird = true;
+ }
+
+ if (avatar.AppliedScale < 0f)
+ {
+ avatar.FirstPersonPlayerScale = player.FirstPersonPlayerScale;
+ avatar.AppliedScale = 1f;
+ }
+
+ if (!avatar.HasCamera && player.SkopjeFPSCamera != null)
+ {
+ avatar.CameraLocal = player.SkopjeFPSCamera.transform.localPosition;
+ avatar.HasCamera = true;
+ avatar.CameraUnderVisual = IsUnder(player.SkopjeFPSCamera.transform, mesh)
+ || (player.FirstPerson != null && IsUnder(player.SkopjeFPSCamera.transform, player.FirstPerson.transform))
+ || (player.ThirdPerson != null && IsUnder(player.SkopjeFPSCamera.transform, player.ThirdPerson.transform));
+ }
+
+ if (!avatar.HasOwner)
+ {
+ CapsuleCollider owner = OwnerCapsule(player);
+ KinematicCharacterMotor motor = Alive(player.SkopjeCharacterController) ? player.SkopjeCharacterController.Motor : null;
+ if (owner != null)
+ {
+ avatar.OwnerHeight = owner.height;
+ avatar.OwnerRadius = owner.radius;
+ avatar.OwnerCenter = owner.center;
+ avatar.HasOwner = true;
+ avatar.OwnerIsMotor = Alive(motor) && Same(motor.Capsule, owner);
+ }
+ }
+ }
+
+ static Body Capture(SkopjeCharacterController controller)
+ {
+ KinematicCharacterMotor motor = controller.Motor;
+ float height = controller.standingHeight;
+ float radius = controller.playerRadius;
+ float yOffset = 0f;
+ float step = 0.3f;
+ if (Alive(motor))
+ {
+ if (height <= 0.01f)
+ height = motor.CapsuleHeight;
+ if (radius <= 0.01f)
+ radius = motor.CapsuleRadius;
+ yOffset = motor.CapsuleYOffset;
+ step = motor.MaxStepHeight;
+ }
+
+ return new Body
+ {
+ Walk = controller.MaxStableMoveSpeed,
+ Air = controller.MaxAirMoveSpeed,
+ AirAccel = controller.AirAccelerationSpeed,
+ Crouch = controller.CrouchMoveSpeed,
+ Sprint = controller.SprintSpeed,
+ Jump = controller.JumpSpeed,
+ Dash = controller.DashSpeed,
+ Height = height,
+ Radius = radius,
+ Step = step,
+ YOffset = yOffset,
+ Head = controller.originalHeadPosition,
+ Chest = controller.originalChestPosition,
+ Center = controller.originalCenterPosition,
+ HeadLocal = IsLocalOffset(controller.originalHeadPosition),
+ ChestLocal = IsLocalOffset(controller.originalChestPosition),
+ CenterLocal = IsLocalOffset(controller.originalCenterPosition),
+ };
+ }
+
+ static bool Ready(SkopjeCharacterController controller)
+ {
+ if (!Alive(controller.Motor))
+ return false;
+ if (controller.MaxStableMoveSpeed <= 0.01f)
+ return false;
+ return controller.standingHeight > 0.01f || controller.Motor.CapsuleHeight > 0.01f;
+ }
+
+ static void Watch(SkopjePlayer player)
+ {
+ IntPtr key = Key(player);
+ if (key == IntPtr.Zero)
+ return;
+
+ for (int i = 0; i < Watching.Count; i++)
+ {
+ if (Key(Watching[i]) == key)
+ return;
+ }
+
+ Watching.Add(player);
+ }
+
+ static bool Alive(Il2CppObjectBase obj)
+ {
+ return obj != null && obj.Pointer != IntPtr.Zero;
+ }
+
+ static IntPtr Key(Il2CppObjectBase obj)
+ {
+ return obj == null ? IntPtr.Zero : obj.Pointer;
+ }
+
+ static bool Same(UnityEngine.Object left, UnityEngine.Object right)
+ {
+ IntPtr a = Key(left as Il2CppObjectBase);
+ IntPtr b = Key(right as Il2CppObjectBase);
+ return a != IntPtr.Zero && a == b;
+ }
+
+ static bool IsLocalOffset(Vector3 value)
+ {
+ return value.sqrMagnitude > 0.0001f && value.sqrMagnitude < 25f && value.y > 0f && value.y < 3f;
+ }
+
+ static bool IsUnder(Transform child, Transform parent)
+ {
+ if (child == null || parent == null)
+ return false;
+
+ for (Transform cursor = child; cursor != null; cursor = cursor.parent)
+ {
+ if (cursor == parent)
+ return true;
+ }
+
+ return false;
+ }
+
+ static CapsuleCollider OwnerCapsule(SkopjePlayer player)
+ {
+ if (player.OwnerCollider == null)
+ return null;
+ return player.OwnerCollider.TryCast();
+ }
+
+ static float ReadHeight()
+ {
+ float value = PioneerSizePlugin.Height != null ? PioneerSizePlugin.Height.Value : 1.8f;
+ return Mathf.Clamp(value, MinHeight, MaxHeight);
+ }
+
+ static float ReadSpeed()
+ {
+ if (_restoring)
+ return 1f;
+ float value = PioneerSizePlugin.SpeedMultiplier != null ? PioneerSizePlugin.SpeedMultiplier.Value : 1f;
+ return Mathf.Clamp(value, MinSpeed, MaxSpeed);
+ }
+
+ static void LogOnce(Exception ex)
+ {
+ if (_errors++ > 4 || PioneerSizePlugin.LogSource == null)
+ return;
+ PioneerSizePlugin.LogSource.LogError("PioneerSize failed to resize the player:\n" + ex);
+ }
+ }
+}
diff --git a/PioneerSize/bin/Release/net6.0/PioneerSize.deps.json b/PioneerSize/bin/Release/net6.0/PioneerSize.deps.json
new file mode 100644
index 0000000..a19486f
--- /dev/null
+++ b/PioneerSize/bin/Release/net6.0/PioneerSize.deps.json
@@ -0,0 +1,23 @@
+{
+ "runtimeTarget": {
+ "name": ".NETCoreApp,Version=v6.0",
+ "signature": ""
+ },
+ "compilationOptions": {},
+ "targets": {
+ ".NETCoreApp,Version=v6.0": {
+ "PioneerSize/1.0.0": {
+ "runtime": {
+ "PioneerSize.dll": {}
+ }
+ }
+ }
+ },
+ "libraries": {
+ "PioneerSize/1.0.0": {
+ "type": "project",
+ "serviceable": false,
+ "sha512": ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/PioneerSize/bin/Release/net6.0/PioneerSize.dll b/PioneerSize/bin/Release/net6.0/PioneerSize.dll
new file mode 100644
index 0000000..79687d7
Binary files /dev/null and b/PioneerSize/bin/Release/net6.0/PioneerSize.dll differ
diff --git a/PioneerSize/bin/Release/net6.0/PioneerSize.pdb b/PioneerSize/bin/Release/net6.0/PioneerSize.pdb
new file mode 100644
index 0000000..eb8bb30
Binary files /dev/null and b/PioneerSize/bin/Release/net6.0/PioneerSize.pdb differ
diff --git a/PioneerSize/obj/PioneerSize.csproj.nuget.dgspec.json b/PioneerSize/obj/PioneerSize.csproj.nuget.dgspec.json
new file mode 100644
index 0000000..206649f
--- /dev/null
+++ b/PioneerSize/obj/PioneerSize.csproj.nuget.dgspec.json
@@ -0,0 +1,85 @@
+{
+ "format": 1,
+ "restore": {
+ "c:\\Users\\andre\\Desktop\\SkopjeMods\\PioneerSize\\PioneerSize.csproj": {}
+ },
+ "projects": {
+ "c:\\Users\\andre\\Desktop\\SkopjeMods\\PioneerSize\\PioneerSize.csproj": {
+ "version": "1.0.0",
+ "restore": {
+ "projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\PioneerSize\\PioneerSize.csproj",
+ "projectName": "PioneerSize",
+ "projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\PioneerSize\\PioneerSize.csproj",
+ "packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\afd7538f5b7936e372e0688765bff098\\nuget",
+ "outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\PioneerSize\\obj\\",
+ "projectStyle": "PackageReference",
+ "configFilePaths": [
+ "C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config",
+ "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
+ ],
+ "originalTargetFrameworks": [
+ "net6.0"
+ ],
+ "sources": {
+ "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
+ "https://api.nuget.org/v3/index.json": {}
+ },
+ "frameworks": {
+ "net6.0": {
+ "framework": "net6.0",
+ "targetAlias": "net6.0",
+ "projectReferences": {}
+ }
+ },
+ "warningProperties": {
+ "warnAsError": [
+ "NU1605"
+ ]
+ },
+ "restoreAuditProperties": {
+ "enableAudit": "true",
+ "auditLevel": "low",
+ "auditMode": "direct"
+ },
+ "SdkAnalysisLevel": "10.0.300"
+ },
+ "frameworks": {
+ "net6.0": {
+ "framework": "net6.0",
+ "targetAlias": "net6.0",
+ "imports": [
+ "net461",
+ "net462",
+ "net47",
+ "net471",
+ "net472",
+ "net48",
+ "net481"
+ ],
+ "assetTargetFallback": true,
+ "warn": true,
+ "downloadDependencies": [
+ {
+ "name": "Microsoft.AspNetCore.App.Ref",
+ "version": "[6.0.36, 6.0.36]"
+ },
+ {
+ "name": "Microsoft.NETCore.App.Ref",
+ "version": "[6.0.36, 6.0.36]"
+ },
+ {
+ "name": "Microsoft.WindowsDesktop.App.Ref",
+ "version": "[6.0.36, 6.0.36]"
+ }
+ ],
+ "frameworkReferences": {
+ "Microsoft.NETCore.App": {
+ "privateAssets": "all"
+ }
+ },
+ "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/PioneerSize/obj/PioneerSize.csproj.nuget.g.props b/PioneerSize/obj/PioneerSize.csproj.nuget.g.props
new file mode 100644
index 0000000..9e62854
--- /dev/null
+++ b/PioneerSize/obj/PioneerSize.csproj.nuget.g.props
@@ -0,0 +1,15 @@
+
+
+
+ True
+ NuGet
+ $(MSBuildThisFileDirectory)project.assets.json
+ $(UserProfile)\AppData\Local\Temp\cursor-sandbox-cache\afd7538f5b7936e372e0688765bff098\nuget
+ C:\Users\andre\AppData\Local\Temp\cursor-sandbox-cache\afd7538f5b7936e372e0688765bff098\nuget
+ PackageReference
+ 7.0.0
+
+
+
+
+
\ No newline at end of file
diff --git a/PioneerSize/obj/PioneerSize.csproj.nuget.g.targets b/PioneerSize/obj/PioneerSize.csproj.nuget.g.targets
new file mode 100644
index 0000000..3dc06ef
--- /dev/null
+++ b/PioneerSize/obj/PioneerSize.csproj.nuget.g.targets
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/PioneerSize/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/PioneerSize/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs
new file mode 100644
index 0000000..ed92695
--- /dev/null
+++ b/PioneerSize/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs
@@ -0,0 +1,4 @@
+//
+using System;
+using System.Reflection;
+[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
diff --git a/PioneerSize/obj/Release/net6.0/PioneerSize.AssemblyInfo.cs b/PioneerSize/obj/Release/net6.0/PioneerSize.AssemblyInfo.cs
new file mode 100644
index 0000000..2b53547
--- /dev/null
+++ b/PioneerSize/obj/Release/net6.0/PioneerSize.AssemblyInfo.cs
@@ -0,0 +1,22 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Reflection;
+
+[assembly: System.Reflection.AssemblyCompanyAttribute("PioneerSize")]
+[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
+[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+fb002cbf0c265ef67a8927e2c87fd31339991a48")]
+[assembly: System.Reflection.AssemblyProductAttribute("PioneerSize")]
+[assembly: System.Reflection.AssemblyTitleAttribute("PioneerSize")]
+[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
+
+// Generated by the MSBuild WriteCodeFragment class.
+
diff --git a/PioneerSize/obj/Release/net6.0/PioneerSize.AssemblyInfoInputs.cache b/PioneerSize/obj/Release/net6.0/PioneerSize.AssemblyInfoInputs.cache
new file mode 100644
index 0000000..5d967ea
--- /dev/null
+++ b/PioneerSize/obj/Release/net6.0/PioneerSize.AssemblyInfoInputs.cache
@@ -0,0 +1 @@
+2db90a6245934e2b7d1dea631b762cbbf6cbe0e50a8b0ef6b9893e59e0a8dfb9
diff --git a/PioneerSize/obj/Release/net6.0/PioneerSize.GeneratedMSBuildEditorConfig.editorconfig b/PioneerSize/obj/Release/net6.0/PioneerSize.GeneratedMSBuildEditorConfig.editorconfig
new file mode 100644
index 0000000..4c3662e
--- /dev/null
+++ b/PioneerSize/obj/Release/net6.0/PioneerSize.GeneratedMSBuildEditorConfig.editorconfig
@@ -0,0 +1,18 @@
+is_global = true
+build_property.TargetFramework = net6.0
+build_property.TargetFrameworkIdentifier = .NETCoreApp
+build_property.TargetFrameworkVersion = v6.0
+build_property.TargetPlatformMinVersion =
+build_property.UsingMicrosoftNETSdkWeb =
+build_property.ProjectTypeGuids =
+build_property.InvariantGlobalization =
+build_property.PlatformNeutralAssembly =
+build_property.EnforceExtendedAnalyzerRules =
+build_property.EntryPointFilePath =
+build_property._SupportedPlatformList = Linux,macOS,Windows
+build_property.RootNamespace = PioneerSize
+build_property.ProjectDir = c:\Users\andre\Desktop\SkopjeMods\PioneerSize\
+build_property.EnableComHosting =
+build_property.EnableGeneratedComInterfaceComImportInterop =
+build_property.EffectiveAnalysisLevelStyle = 6.0
+build_property.EnableCodeStyleSeverity =
diff --git a/PioneerSize/obj/Release/net6.0/PioneerSize.assets.cache b/PioneerSize/obj/Release/net6.0/PioneerSize.assets.cache
new file mode 100644
index 0000000..9873952
Binary files /dev/null and b/PioneerSize/obj/Release/net6.0/PioneerSize.assets.cache differ
diff --git a/PioneerSize/obj/Release/net6.0/PioneerSize.csproj.AssemblyReference.cache b/PioneerSize/obj/Release/net6.0/PioneerSize.csproj.AssemblyReference.cache
new file mode 100644
index 0000000..3c911fc
Binary files /dev/null and b/PioneerSize/obj/Release/net6.0/PioneerSize.csproj.AssemblyReference.cache differ
diff --git a/PioneerSize/obj/Release/net6.0/PioneerSize.csproj.CoreCompileInputs.cache b/PioneerSize/obj/Release/net6.0/PioneerSize.csproj.CoreCompileInputs.cache
new file mode 100644
index 0000000..becfb7c
--- /dev/null
+++ b/PioneerSize/obj/Release/net6.0/PioneerSize.csproj.CoreCompileInputs.cache
@@ -0,0 +1 @@
+1e5a7db68b3b701762c9c3d00a51b7c600869e818220c462f478e3ba6c28c76f
diff --git a/PioneerSize/obj/Release/net6.0/PioneerSize.csproj.FileListAbsolute.txt b/PioneerSize/obj/Release/net6.0/PioneerSize.csproj.FileListAbsolute.txt
new file mode 100644
index 0000000..7c7c04d
--- /dev/null
+++ b/PioneerSize/obj/Release/net6.0/PioneerSize.csproj.FileListAbsolute.txt
@@ -0,0 +1,12 @@
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\bin\Release\net6.0\PioneerSize.deps.json
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\bin\Release\net6.0\PioneerSize.dll
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\bin\Release\net6.0\PioneerSize.pdb
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\obj\Release\net6.0\PioneerSize.csproj.AssemblyReference.cache
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\obj\Release\net6.0\PioneerSize.GeneratedMSBuildEditorConfig.editorconfig
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\obj\Release\net6.0\PioneerSize.AssemblyInfoInputs.cache
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\obj\Release\net6.0\PioneerSize.AssemblyInfo.cs
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\obj\Release\net6.0\PioneerSize.csproj.CoreCompileInputs.cache
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\obj\Release\net6.0\PioneerSize.dll
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\obj\Release\net6.0\refint\PioneerSize.dll
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\obj\Release\net6.0\PioneerSize.pdb
+c:\Users\andre\Desktop\SkopjeMods\PioneerSize\obj\Release\net6.0\ref\PioneerSize.dll
diff --git a/PioneerSize/obj/Release/net6.0/PioneerSize.dll b/PioneerSize/obj/Release/net6.0/PioneerSize.dll
new file mode 100644
index 0000000..79687d7
Binary files /dev/null and b/PioneerSize/obj/Release/net6.0/PioneerSize.dll differ
diff --git a/PioneerSize/obj/Release/net6.0/PioneerSize.pdb b/PioneerSize/obj/Release/net6.0/PioneerSize.pdb
new file mode 100644
index 0000000..eb8bb30
Binary files /dev/null and b/PioneerSize/obj/Release/net6.0/PioneerSize.pdb differ
diff --git a/PioneerSize/obj/Release/net6.0/ref/PioneerSize.dll b/PioneerSize/obj/Release/net6.0/ref/PioneerSize.dll
new file mode 100644
index 0000000..dedb38c
Binary files /dev/null and b/PioneerSize/obj/Release/net6.0/ref/PioneerSize.dll differ
diff --git a/PioneerSize/obj/Release/net6.0/refint/PioneerSize.dll b/PioneerSize/obj/Release/net6.0/refint/PioneerSize.dll
new file mode 100644
index 0000000..dedb38c
Binary files /dev/null and b/PioneerSize/obj/Release/net6.0/refint/PioneerSize.dll differ
diff --git a/PioneerSize/obj/project.assets.json b/PioneerSize/obj/project.assets.json
new file mode 100644
index 0000000..7fbd01c
--- /dev/null
+++ b/PioneerSize/obj/project.assets.json
@@ -0,0 +1,90 @@
+{
+ "version": 4,
+ "targets": {
+ "net6.0": {}
+ },
+ "libraries": {},
+ "projectFileDependencyGroups": {
+ "net6.0": []
+ },
+ "packageFolders": {
+ "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\afd7538f5b7936e372e0688765bff098\\nuget": {}
+ },
+ "project": {
+ "version": "1.0.0",
+ "restore": {
+ "projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\PioneerSize\\PioneerSize.csproj",
+ "projectName": "PioneerSize",
+ "projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\PioneerSize\\PioneerSize.csproj",
+ "packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\afd7538f5b7936e372e0688765bff098\\nuget",
+ "outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\PioneerSize\\obj\\",
+ "projectStyle": "PackageReference",
+ "configFilePaths": [
+ "C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config",
+ "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
+ ],
+ "originalTargetFrameworks": [
+ "net6.0"
+ ],
+ "sources": {
+ "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
+ "https://api.nuget.org/v3/index.json": {}
+ },
+ "frameworks": {
+ "net6.0": {
+ "framework": "net6.0",
+ "targetAlias": "net6.0",
+ "projectReferences": {}
+ }
+ },
+ "warningProperties": {
+ "warnAsError": [
+ "NU1605"
+ ]
+ },
+ "restoreAuditProperties": {
+ "enableAudit": "true",
+ "auditLevel": "low",
+ "auditMode": "direct"
+ },
+ "SdkAnalysisLevel": "10.0.300"
+ },
+ "frameworks": {
+ "net6.0": {
+ "framework": "net6.0",
+ "targetAlias": "net6.0",
+ "imports": [
+ "net461",
+ "net462",
+ "net47",
+ "net471",
+ "net472",
+ "net48",
+ "net481"
+ ],
+ "assetTargetFallback": true,
+ "warn": true,
+ "downloadDependencies": [
+ {
+ "name": "Microsoft.AspNetCore.App.Ref",
+ "version": "[6.0.36, 6.0.36]"
+ },
+ {
+ "name": "Microsoft.NETCore.App.Ref",
+ "version": "[6.0.36, 6.0.36]"
+ },
+ {
+ "name": "Microsoft.WindowsDesktop.App.Ref",
+ "version": "[6.0.36, 6.0.36]"
+ }
+ ],
+ "frameworkReferences": {
+ "Microsoft.NETCore.App": {
+ "privateAssets": "all"
+ }
+ },
+ "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/PioneerSize/obj/project.nuget.cache b/PioneerSize/obj/project.nuget.cache
new file mode 100644
index 0000000..a3dcf68
--- /dev/null
+++ b/PioneerSize/obj/project.nuget.cache
@@ -0,0 +1,12 @@
+{
+ "version": 2,
+ "dgSpecHash": "ephFWYTgh8M=",
+ "success": true,
+ "projectFilePath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\PioneerSize\\PioneerSize.csproj",
+ "expectedPackageFiles": [
+ "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\afd7538f5b7936e372e0688765bff098\\nuget\\microsoft.netcore.app.ref\\6.0.36\\microsoft.netcore.app.ref.6.0.36.nupkg.sha512",
+ "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\afd7538f5b7936e372e0688765bff098\\nuget\\microsoft.windowsdesktop.app.ref\\6.0.36\\microsoft.windowsdesktop.app.ref.6.0.36.nupkg.sha512",
+ "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\afd7538f5b7936e372e0688765bff098\\nuget\\microsoft.aspnetcore.app.ref\\6.0.36\\microsoft.aspnetcore.app.ref.6.0.36.nupkg.sha512"
+ ],
+ "logs": []
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 8edfac3..b3ff606 100644
--- a/README.md
+++ b/README.md
@@ -28,3 +28,4 @@ File: BepInEx-Unity.IL2CPP-win-x64-6.0.0-be.789+6cea286.zip
| Minimap | Small map under the clock, using the in-game map. | 1.0.0 |  |
| DOM Radio | Plays your mp3 and wav files inside the Dom, and mutes its music while the radio is on. | 1.0.0 |  |
| PeePeeMod | Hold a key to piss. The stream is sent with a server RPC so every player can see it. | 1.0.0 |  |
+| PioneerSize | Sets the player standing height in meters and multiplies move speed. Crouch keeps the game's crouch fraction. | 1.0.2 |  |