Skip to content

Commit 598e470

Browse files
committed
Merge branch 'master' of https://github.com/knah/VRCMods
2 parents 41bd243 + 6c5badb commit 598e470

27 files changed

+509
-429
lines changed

AdvancedSafety/AdvancedSafety.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<VrcReferences>true</VrcReferences>
66
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
77
<LangVersion>latest</LangVersion>
8-
<Version>1.6.0.0</Version>
8+
<Version>1.6.1.0</Version>
99
<UsesNativePatches>true</UsesNativePatches>
1010
</PropertyGroup>
1111

AdvancedSafety/AdvancedSafetyMod.cs

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
using Object = UnityEngine.Object;
2020

2121
[assembly:MelonGame("VRChat", "VRChat")]
22-
[assembly:MelonInfo(typeof(AdvancedSafetyMod), "Advanced Safety", "1.6.0", "knah, Requi, Ben", "https://github.com/xAstroBoy/VRCMods-Unchained")]
22+
[assembly:MelonInfo(typeof(AdvancedSafetyMod), "Advanced Safety", "1.6.1", "knah, Requi, Ben", "https://github.com/knah/VRCMods")]
2323
[assembly:MelonOptionalDependencies("UIExpansionKit")]
2424

2525
namespace AdvancedSafety
@@ -32,32 +32,9 @@ internal partial class AdvancedSafetyMod : MelonMod
3232
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
3333
private delegate void VoidDelegate(IntPtr thisPtr, IntPtr nativeMethodInfo);
3434

35-
private static readonly Func<VRCUiManager> ourGetUiManager;
36-
37-
static AdvancedSafetyMod()
38-
{
39-
ourGetUiManager = (Func<VRCUiManager>)Delegate.CreateDelegate(typeof(Func<VRCUiManager>), typeof(VRCUiManager)
40-
.GetProperties(BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly)
41-
.First(it => it.PropertyType == typeof(VRCUiManager)).GetMethod);
42-
}
43-
44-
internal static VRCUiManager GetUiManager() => ourGetUiManager();
45-
46-
private static void DoAfterUiManagerInit(Action code)
47-
{
48-
MelonCoroutines.Start(OnUiManagerInitCoro(code));
49-
}
50-
51-
private static IEnumerator OnUiManagerInitCoro(Action code)
52-
{
53-
while (GetUiManager() == null)
54-
yield return null;
55-
code();
56-
}
57-
58-
5935
public override void OnApplicationStart()
6036
{
37+
if (!CheckWasSuccessful || !MustStayTrue || MustStayFalse) return;
6138

6239
AdvancedSafetySettings.RegisterSettings();
6340
ClassInjector.RegisterTypeInIl2Cpp<SortingOrderHammerer>();
@@ -144,6 +121,7 @@ void TaskMoveNextPatch(IntPtr taskPtr, IntPtr nativeMethodInfo)
144121

145122
PortalHiding.OnApplicationStart();
146123
AvatarHiding.OnApplicationStart(HarmonyInstance);
124+
FinalIkPatches.ApplyPatches(HarmonyInstance);
147125

148126
if(MelonHandler.Mods.Any(it => it.Info.Name == "UI Expansion Kit"))
149127
{

AdvancedSafety/BundleVerifier/BundleDlContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ internal void CompleteDownload()
100100
if (exitCode != 0)
101101
{
102102
var cleanedUrl = BundleVerifierMod.SanitizeUrl(Url);
103-
MelonLogger.Msg($"Verifier process failed with exit code {exitCode} for bundle uid={cleanedUrl.Item1}+{cleanedUrl.Item2}");
103+
MelonLogger.Msg($"Verifier process failed with exit code {exitCode} ({VerifierExitCodes.GetExitCodeDescription(exitCode)}) for bundle uid={cleanedUrl.Item1}+{cleanedUrl.Item2}");
104104
BundleVerifierMod.BadBundleCache.Add(Url);
105105
MelonDebug.Msg("Reporting completion without data");
106106
// feed some garbage into it, otherwise it dies
450 Bytes
Binary file not shown.

AdvancedSafety/BundleVerifier/BundleVerifierMod.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ private static IEnumerator CheckInstanceType()
9393
MelonDebug.Msg($"Got instance, intercept state: {BundleDlInterceptor.ShouldIntercept}");
9494
}
9595

96-
private const string VerifierVersion = "1.1-2019.4.31";
96+
private const string VerifierVersion = "1.2-2019.4.31";
9797
internal const string SettingsCategory = "ASBundleVerifier";
9898

9999
private static void PrepareVerifierDir()
@@ -108,6 +108,8 @@ private static void PrepareVerifierDir()
108108
if (existingVersion == VerifierVersion) return;
109109
}
110110

111+
BadBundleCache.Clear();
112+
111113
File.Copy(Path.Combine(MelonUtils.GameDirectory, "UnityPlayer.dll"), Path.Combine(baseDir, "UnityPlayer.dll"), true);
112114
using var zipFile = new ZipArchive(Assembly.GetExecutingAssembly().GetManifestResourceStream("AdvancedSafety.BundleVerifier.BundleVerifier.zip")!, ZipArchiveMode.Read, false);
113115
foreach (var zipArchiveEntry in zipFile.Entries)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Collections.Generic;
2+
3+
namespace AdvancedSafety.BundleVerifier
4+
{
5+
public static class VerifierExitCodes
6+
{
7+
private static readonly Dictionary<int, string> ourCodeDescriptions = new()
8+
{
9+
{ 179, "Generic exception (report a bug!)" },
10+
{ 180, "CLI argument parse error (report a bug!)" },
11+
{ 181, "VRChat process suddenly died" },
12+
{ 182, "Loaded bundle was null" },
13+
{ 183, "Loaded bundle did not contain a prefab" },
14+
{ 184, "Prefab instantiation failed" },
15+
{ 185, "Minimum framerate not achieved" },
16+
{ 186, "Over component limit" },
17+
{ -1073741819, "Generic crash (corrupted bundle)" }, // 0xc0000005
18+
{ -2147483645, "Breakpoint crash (corrupted bundle)" }, // 0x80000003
19+
};
20+
21+
internal static string GetExitCodeDescription(int? exitCode)
22+
{
23+
if (!exitCode.HasValue) return "Timed out";
24+
25+
return ourCodeDescriptions.TryGetValue(exitCode.Value, out var result) ? result : "Unknown";
26+
}
27+
}
28+
}

AdvancedSafety/FinalIkPatches.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System.Linq;
2+
using HarmonyLib;
3+
using RootMotion.FinalIK;
4+
using UnityEngine;
5+
6+
namespace AdvancedSafety
7+
{
8+
/**
9+
* Source: FinalIkSanity (https://github.com/FenrixTheFox/FinalIKSanity, GPLv3) and Requi (contributed personally by him)
10+
*/
11+
public static class FinalIkPatches
12+
{
13+
public static void ApplyPatches(HarmonyLib.Harmony harmony)
14+
{
15+
harmony.Patch(typeof(IKSolverHeuristic).GetMethods().First(m => m.Name.Equals("IsValid") && m.GetParameters().Length == 1),
16+
new HarmonyMethod(typeof(FinalIkPatches), nameof(IkSolverIsValid)));
17+
18+
harmony.Patch(typeof(IKSolverAim).GetMethod(nameof(IKSolverAim.GetClampedIKPosition)),
19+
new HarmonyMethod(typeof(FinalIkPatches), nameof(IkSolverAimGetClampedIKPosition)));
20+
21+
harmony.Patch(typeof(IKSolverFullBody).GetMethod(nameof(IKSolverFullBody.Solve)),
22+
new HarmonyMethod(typeof(FinalIkPatches), nameof(IKSolverFullBodySolve)));
23+
24+
harmony.Patch(typeof(IKSolverFABRIKRoot).GetMethod(nameof(IKSolverFABRIKRoot.OnUpdate)),
25+
new HarmonyMethod(typeof(FinalIkPatches), nameof(IKSolverFABRIKRootOnUpdate)));
26+
}
27+
28+
private static void IkSolverAimGetClampedIKPosition(ref IKSolverAim __instance)
29+
{
30+
if (__instance == null) return;
31+
__instance.clampSmoothing = Mathf.Clamp(__instance.clampSmoothing, 0, 2);
32+
}
33+
34+
private static bool IkSolverIsValid(ref IKSolverHeuristic __instance, ref bool __result, ref string message)
35+
{
36+
if (__instance == null) return true;
37+
if (__instance.maxIterations <= 64) return true;
38+
39+
__result = false;
40+
message = "The solver requested too many iterations.";
41+
42+
return false;
43+
}
44+
45+
private static void IKSolverFullBodySolve(ref IKSolverFullBody __instance)
46+
{
47+
if (__instance == null) return;
48+
__instance.iterations = Mathf.Clamp(__instance.iterations, 0, 10);
49+
}
50+
51+
private static bool IKSolverFABRIKRootOnUpdate(ref IKSolverFABRIKRoot __instance)
52+
{
53+
if (__instance == null)
54+
return true;
55+
return __instance.iterations <= 10;
56+
}
57+
}
58+
}

AdvancedSafety/NativeStructs.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace AdvancedSafety
5+
{
6+
// These are copypasted from Unhollower. TODO: use actual structs from unhollower once/if they become public
7+
[StructLayout(LayoutKind.Sequential)]
8+
internal struct Il2CppFieldInfo_24_1
9+
{
10+
public IntPtr name; // const char*
11+
public IntPtr typePtr; // const
12+
public IntPtr parentClassPtr; // non-const?
13+
public int offset; // If offset is -1, then it's thread static
14+
public uint token;
15+
}
16+
}

AdvancedSafety/ReaderPatches.cs

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Security.Cryptography;
77
using System.Threading;
88
using MelonLoader;
9+
using UnhollowerBaseLib;
910

1011
namespace AdvancedSafety
1112
{
@@ -27,12 +28,13 @@ public class ReaderPatches
2728

2829
private static readonly string[] ourAllowedFields = { "m_BreakForce", "m_BreakTorque", "collisionSphereDistance", "maxDistance", "inSlope", "outSlope" };
2930

30-
private static readonly Dictionary<string, (int ProduceMixer, int TransferFloat, int CountNodes, int DebugAssert, int ReaderOOB, int ReallocateString)> ourOffsets = new() {
31-
{ "aCEmIwSIcjYriBQDFjQlpTNNW1/kA8Wlbkqelmt1USOMB09cnKwK7QWyOulz9d7DEYJh4+vO0Ldv8gdH+dZCrg==", (0x4997C0, 0xD7320, 0, 0, 0, 0) }, // U2018.4.20 non-dev
32-
{ "5dkhl/dWeTREXhHCIkZK17mzZkbjhTKlxb+IUSk+YaWzZrrV+G+M0ekTOEGjZ4dJuB4O3nU/oE3dycXWeJq9uA==", (0xA80660, 0xC7B40, 0, 0, 0, 0) }, // U2019.4.28 non-dev
33-
{ "MV6xP7theydao4ENbGi6BbiBxdZsgGOBo/WrPSeIqh6A/E00NImjUNZn+gL+ZxzpVbJms7nUb6zluLL3+aIcfg==", (0xA82350, 0xC7E50, 0, 0, 0, 0) }, // U2019.4.29 non-dev
34-
{ "ccZ4F7iE7a78kWdXdMekJzP7/ktzS5jOOS8IOITxa1C5Jg2TKxC0/ywY8F0o9I1vZHsxAO4eh7G2sOGzsR/+uQ==", (0xA83410, 0xC7E80, 0, 0, 0, 0) }, // U2019.4.30 non-dev
35-
{ "sgZUlX3+LSHKnTiTC+nXNcdtLOTrAB1fNjBLOwDdKzCyndlFLAdL0udR4S1szTC/q5pnFhG3Kdspsj5jvwLY1A==", (0xA86270, 0xC8230, 0xDF29F0, 0xDDBDC0, 0x7B9EB0, 0xC69F0) }, // U2019.4.31 non-dev
31+
private static readonly Dictionary<string, (int ProduceMixer, int TransferFloat, int CountNodes, int DebugAssert,
32+
int ReaderOOB, int ReallocateString, int TransferMonoObject, int TransferUEObjectSBR)> ourOffsets = new()
33+
{
34+
{
35+
"sgZUlX3+LSHKnTiTC+nXNcdtLOTrAB1fNjBLOwDdKzCyndlFLAdL0udR4S1szTC/q5pnFhG3Kdspsj5jvwLY1A==",
36+
(0xA86270, 0xC8230, 0xDF29F0, 0xDDBDC0, 0x7B9EB0, 0xC69F0, 0x8D1160, 0x8E5CD0)
37+
}, // U2019.4.31 non-dev
3638
};
3739

3840
internal static void ApplyPatches()
@@ -73,6 +75,12 @@ internal static void ApplyPatches()
7375

7476
// core::StringStorageDefault<char>::reallocate, identified to be an issue by Requi&Ben
7577
DoPatch(module, offsets.ReallocateString, ReallocateStringPatch, out ourOriginalRealloc);
78+
79+
// TransferPPtrToMonoObject
80+
DoPatch(module, offsets.TransferMonoObject, TransferMonoObjectPatch, out ourOriginalTransferMonoObject);
81+
82+
// TransferField_NonArray<SafeBinaryRead,Converter_UnityEngineObject>
83+
DoPatch(module, offsets.TransferUEObjectSBR, TransferUeObjectSbrPatch, out ourOriginalTransferUeObjectSbr);
7684
}
7785

7886
break;
@@ -149,6 +157,63 @@ private static void ReaderOobPatch(IntPtr thisPtr, long a, long b)
149157
}
150158
}
151159

160+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
161+
private delegate void TransferObjectSbrDelegate(IntPtr staticInfo, IntPtr runtimeInfo, IntPtr converter);
162+
163+
[ThreadStatic] private static Stack<IntPtr> ourCurrentSafeTransferStack;
164+
private static TransferObjectSbrDelegate ourOriginalTransferUeObjectSbr;
165+
166+
private static void TransferUeObjectSbrPatch(IntPtr staticInfo, IntPtr runtimeInfo, IntPtr converter)
167+
{
168+
ourCurrentSafeTransferStack ??= new Stack<IntPtr>();
169+
ourCurrentSafeTransferStack.Push(staticInfo);
170+
try
171+
{
172+
ourOriginalTransferUeObjectSbr(staticInfo, runtimeInfo, converter);
173+
}
174+
finally
175+
{
176+
ourCurrentSafeTransferStack.Pop();
177+
}
178+
}
179+
180+
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
181+
private delegate IntPtr TransferMonoObjectDelegate(ref IntPtr hiddenThisReturn, IntPtr instanceId,
182+
IntPtr il2cppClass, IntPtr dataToCreateNull, IntPtr transferFlags);
183+
184+
private static TransferMonoObjectDelegate ourOriginalTransferMonoObject;
185+
186+
private static unsafe IntPtr TransferMonoObjectPatch(ref IntPtr hiddenThisReturn, IntPtr instanceId,
187+
IntPtr il2cppClass, IntPtr dataToCreateNull, IntPtr transferFlags)
188+
{
189+
var result = ourOriginalTransferMonoObject(ref hiddenThisReturn, instanceId, il2cppClass, dataToCreateNull, transferFlags);
190+
191+
if (hiddenThisReturn == IntPtr.Zero || ourCurrentSafeTransferStack == null || ourCurrentSafeTransferStack.Count == 0) return result;
192+
193+
var objectType = *(IntPtr*)hiddenThisReturn;
194+
195+
var topStaticInfo = (StaticTransferInfoPrefix*)ourCurrentSafeTransferStack.Peek();
196+
var staticFieldInfoPtr = topStaticInfo->field;
197+
198+
var fieldType = IL2CPP.il2cpp_class_from_type(staticFieldInfoPtr->typePtr);
199+
if (IL2CPP.il2cpp_class_is_assignable_from(fieldType, objectType)) return result;
200+
201+
var fieldName = Marshal.PtrToStringAnsi(staticFieldInfoPtr->name);
202+
203+
MelonDebug.Msg($"While deserializing field of type {RenderTypeName(fieldType)} named {fieldName} we got an object of type {RenderTypeName(objectType)}");
204+
hiddenThisReturn = IntPtr.Zero;
205+
206+
return result;
207+
}
208+
209+
private static string RenderTypeName(IntPtr classPtr) => Il2CppSystem.Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(classPtr)).ToString();
210+
211+
[StructLayout(LayoutKind.Sequential)]
212+
private unsafe struct StaticTransferInfoPrefix
213+
{
214+
public Il2CppFieldInfo_24_1* field;
215+
}
216+
152217

153218
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
154219
private delegate void DebugAssertDelegate(IntPtr data);

FavCat/Database/DatabaseImageHandler.cs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Threading.Tasks;
15
using FavCat.Database.Stored;
26
using LiteDB;
37
using MelonLoader;
48
using SixLabors.ImageSharp;
59
using SixLabors.ImageSharp.PixelFormats;
610
using SixLabors.ImageSharp.Processing;
7-
using System;
8-
using System.Collections.Generic;
9-
using System.IO;
10-
using System.Threading.Tasks;
1111
using UIExpansionKit.API;
1212
using UnhollowerBaseLib;
1313
using UnityEngine;
@@ -40,10 +40,10 @@ public Task TrimCache(long maxSize)
4040
foreach (var liteFileInfo in myFileDatabase.FileStorage.FindAll())
4141
{
4242
if (string.IsNullOrEmpty(liteFileInfo.Id)) continue;
43-
43+
4444
allFileInfos.Add((liteFileInfo,
4545
myImageInfos.FindById(liteFileInfo.Id) ?? new StoredImageInfo
46-
{ LastAccessed = DateTime.MinValue, Id = liteFileInfo.Id }));
46+
{LastAccessed = DateTime.MinValue, Id = liteFileInfo.Id}));
4747
}
4848

4949
allFileInfos.Sort((a, b) => a.Item2.LastAccessed.CompareTo(b.Item2.LastAccessed));
@@ -71,12 +71,12 @@ public Task TrimCache(long maxSize)
7171
}
7272

7373
await TaskUtilities.YieldToMainThread();
74-
74+
7575
MelonLogger.Msg($"Removed {cutoffPoint} images from cache");
7676
}).ContinueWith(task =>
7777
{
7878
if (!task.IsFaulted) return;
79-
79+
8080
MelonLogger.Warning("Image cache trim failed; assuming cache corrupted, clearing collections. Exception: " + task.Exception);
8181
myFileDatabase.GetCollection<LiteFileInfo<string>>("_files").DeleteAll();
8282
myFileDatabase.GetCollection("_chunks").DeleteAll();
@@ -98,7 +98,7 @@ public async Task LoadImageAsync(string url, Action<Texture2D?> onDone)
9898
using var imageStream = myFileDatabase.FileStorage.OpenRead(url);
9999
using var image = await Image.LoadAsync<Rgba32>(imageStream).ConfigureAwait(false);
100100

101-
var newImageInfo = new StoredImageInfo { Id = url, LastAccessed = DateTime.UtcNow };
101+
var newImageInfo = new StoredImageInfo {Id = url, LastAccessed = DateTime.UtcNow};
102102
myImageInfos.Upsert(newImageInfo);
103103

104104
await TaskUtilities.YieldToMainThread();
@@ -129,7 +129,7 @@ private static unsafe Texture2D CreateTextureFromImage(Image<Rgba32> image)
129129

130130
var texture = new Texture2D(image.Width, image.Height, TextureFormat.RGBA32, false, false);
131131
fixed (void* pixelsPtr = pixels)
132-
texture.LoadRawTextureData((IntPtr)pixelsPtr, pixels.Length * 4);
132+
texture.LoadRawTextureData((IntPtr) pixelsPtr, pixels.Length * 4);
133133

134134
texture.Apply(false, true);
135135

@@ -140,16 +140,19 @@ public Task StoreImageAsync(string url, Il2CppStructArray<byte> data)
140140
{
141141
if (string.IsNullOrEmpty(url)) return Task.CompletedTask;
142142

143+
// copy the byte[] on calling thread to avoid issues
144+
var stream = new MemoryStream(data);
145+
143146
return Task.Run(() =>
144147
{
145148
try
146149
{
147150
if (myFileDatabase.FileStorage.Exists(url))
148151
return;
149152

150-
myFileDatabase.FileStorage.Upload(url, url, new MemoryStream(data));
153+
myFileDatabase.FileStorage.Upload(url, url, stream);
151154

152-
var newImageInfo = new StoredImageInfo { Id = url, LastAccessed = DateTime.MinValue };
155+
var newImageInfo = new StoredImageInfo {Id = url, LastAccessed = DateTime.MinValue};
153156
myImageInfos.Upsert(newImageInfo);
154157
}
155158
catch (LiteException ex)

0 commit comments

Comments
 (0)