Skip to content

Commit ab4b3ec

Browse files
committed
chore(release): merge dev into main for v0.2.32
2 parents 8fbbab7 + 8ffacfb commit ab4b3ec

26 files changed

Lines changed: 947 additions & 97 deletions

Audio/Patches/NAudioManagerGuidMappedStudioEventsPatches.cs

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,34 @@ namespace STS2RitsuLib.Audio.Patches
1616
/// </summary>
1717
public static class NAudioManagerGuidMappedStudioEventsPatches
1818
{
19+
private static readonly Lock MissingStudioPathWarningGate = new();
20+
private static readonly HashSet<string> MissingStudioPathWarningLoggedKeys = new(StringComparer.Ordinal);
21+
22+
private static void LogMissingStudioPathOnce(string operation, string path)
23+
{
24+
if (!path.StartsWith("event:/", StringComparison.Ordinal))
25+
return;
26+
27+
var pathExistsInRuntime = FmodStudioServer.TryCheckEventPath(path);
28+
if (pathExistsInRuntime != false)
29+
return;
30+
31+
var key = operation + "\0" + path;
32+
lock (MissingStudioPathWarningGate)
33+
{
34+
if (!MissingStudioPathWarningLoggedKeys.Add(key))
35+
return;
36+
}
37+
38+
RitsuLibFramework.Logger.Warn(
39+
$"[Audio] FMOD event was not found in GUID mappings or loaded Studio events. " +
40+
$"operation={operation}; " +
41+
$"path={path}; guidMapEventCount={FmodStudioGuidPathTable.EventMappingCount}; " +
42+
$"loadedBankCount={FmodStudioServer.TryGetLoadedBankCount()}; " +
43+
$"loadedEventDescriptionCount={FmodStudioServer.TryGetLoadedEventDescriptionCount()}; " +
44+
$"banksStillLoading={FmodStudioServer.TryBanksStillLoading()?.ToString() ?? "?"}");
45+
}
46+
1947
/// <summary>
2048
/// Intercepts mapped <see cref="NAudioManager.PlayOneShot(string, Dictionary{string, float}, float)" /> calls.
2149
/// 拦截已映射的 <see cref="NAudioManager.PlayOneShot(string, Dictionary{string, float}, float)" /> 调用。
@@ -55,9 +83,14 @@ public static bool Prefix(NAudioManager __instance, string path, Dictionary<stri
5583
if (TestMode.IsOn)
5684
return true;
5785

58-
if (string.IsNullOrEmpty(path) ||
59-
!FmodStudioGuidPathTable.TryGetStudioGuidForEventPath(path, out var mappedGuid))
86+
if (string.IsNullOrEmpty(path))
87+
return true;
88+
89+
if (!FmodStudioGuidPathTable.TryGetStudioGuidForEventPath(path, out var mappedGuid))
90+
{
91+
LogMissingStudioPathOnce("PlayOneShot", path);
6092
return true;
93+
}
6194

6295
if (FmodStudioDirectOneShots.TryFireOneShotForMappedEventPath(path, volume, parameters))
6396
return false;
@@ -104,9 +137,15 @@ public static bool Prefix(NAudioManager __instance, string path, bool usesLoopPa
104137
if (TestMode.IsOn)
105138
return true;
106139

107-
if (string.IsNullOrEmpty(path) || !GuidMappedNaudioStudioProxy.IsMappedPath(path))
140+
if (string.IsNullOrEmpty(path))
108141
return true;
109142

143+
if (!GuidMappedNaudioStudioProxy.IsMappedPath(path))
144+
{
145+
LogMissingStudioPathOnce("PlayLoop", path);
146+
return true;
147+
}
148+
110149
if (GuidMappedNaudioStudioProxy.TryEnqueueMappedLoop(path, usesLoopParam))
111150
return false;
112151

@@ -275,8 +314,14 @@ public static bool Prefix(NAudioManager __instance, string music)
275314
if (TestMode.IsOn)
276315
return true;
277316

278-
if (string.IsNullOrEmpty(music) || !GuidMappedNaudioStudioProxy.IsMappedPath(music))
317+
if (string.IsNullOrEmpty(music))
318+
return true;
319+
320+
if (!GuidMappedNaudioStudioProxy.IsMappedPath(music))
321+
{
322+
LogMissingStudioPathOnce("PlayMusic", music);
279323
return true;
324+
}
280325

281326
__instance.StopMusic();
282327

Combat/HandSize/BaseLibMaxHandSizeBridge.cs

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using MegaCrit.Sts2.Core.DevConsole.ConsoleCommands;
66
using MegaCrit.Sts2.Core.Entities.Players;
77
using MegaCrit.Sts2.Core.GameActions.Multiplayer;
8+
using MegaCrit.Sts2.Core.Models;
89
using STS2RitsuLib.Compat;
910
using STS2RitsuLib.Patching.Core;
1011
using STS2RitsuLib.Patching.Models;
@@ -28,6 +29,8 @@ internal static class BaseLibMaxHandSizeBridge
2829
[ThreadStatic] private static int _suppressPostfixDepth;
2930

3031
private static MethodInfo? _baseLibGetMaxHandSizeMethod;
32+
private static MethodInfo? _baseLibGetMaxHandSizeWithBaseMethod;
33+
private static MethodInfo? _baseLibGetMaxHandSizeFromCardMethod;
3134
private static Func<Player, int>? _baseLibGetMaxHandSize;
3235
private static bool _postfixPatched;
3336
private static bool _loggedResolveFailure;
@@ -50,6 +53,13 @@ internal static bool IsBaseLibHandSizePatchActive()
5053
[typeof(Player), typeof(string[])]));
5154
}
5255

56+
internal static bool IsBaseLibBaseAmountConsumer(CodeInstruction instruction)
57+
{
58+
return instruction.operand is MethodInfo method
59+
&& (IsSameMethod(method, TryResolveBaseLibGetMaxHandSizeWithBaseMethod())
60+
|| IsSameMethod(method, TryResolveBaseLibGetMaxHandSizeFromCardMethod()));
61+
}
62+
5363
internal static bool TryGetMaxHandSizeFromBaseLib(Player player, out int amount)
5464
{
5565
amount = 0;
@@ -98,7 +108,8 @@ private static void EnsureBaseLibPostfixPatched()
98108
{
99109
if (_postfixPatched)
100110
return;
101-
if (!TryResolveBaseLibGetMaxHandSizeMethod(out var getMaxMethod))
111+
var getMaxMethod = TryResolveBaseLibGetMaxHandSizeWithBaseMethod();
112+
if (getMaxMethod == null)
102113
return;
103114

104115
var postfix = AccessTools.Method(typeof(BaseLibMaxHandSizeBridge),
@@ -178,6 +189,53 @@ private static bool TryResolveBaseLibGetMaxHandSizeMethod(out MethodInfo method)
178189
}
179190
}
180191

192+
private static MethodInfo? TryResolveBaseLibGetMaxHandSizeWithBaseMethod()
193+
{
194+
lock (Gate)
195+
{
196+
if (_baseLibGetMaxHandSizeWithBaseMethod != null)
197+
return _baseLibGetMaxHandSizeWithBaseMethod;
198+
199+
var type = ResolveBaseLibMaxHandSizePatchType();
200+
var resolved = type?.GetMethod(
201+
"GetMaxHandSize",
202+
BindingFlags.Public | BindingFlags.Static,
203+
null,
204+
[typeof(Player), typeof(int)],
205+
null);
206+
207+
_baseLibGetMaxHandSizeWithBaseMethod = resolved;
208+
return resolved;
209+
}
210+
}
211+
212+
private static MethodInfo? TryResolveBaseLibGetMaxHandSizeFromCardMethod()
213+
{
214+
lock (Gate)
215+
{
216+
if (_baseLibGetMaxHandSizeFromCardMethod != null)
217+
return _baseLibGetMaxHandSizeFromCardMethod;
218+
219+
var type = ResolveBaseLibMaxHandSizePatchType();
220+
var resolved = type?.GetMethod(
221+
"GetMaxHandSizeFromCard",
222+
BindingFlags.NonPublic | BindingFlags.Static,
223+
null,
224+
[typeof(CardModel), typeof(int)],
225+
null);
226+
227+
_baseLibGetMaxHandSizeFromCardMethod = resolved;
228+
return resolved;
229+
}
230+
}
231+
232+
private static bool IsSameMethod(MethodInfo method, MethodInfo? candidate)
233+
{
234+
return candidate != null
235+
&& method.Module == candidate.Module
236+
&& method.MetadataToken == candidate.MetadataToken;
237+
}
238+
181239
private static Type? ResolveBaseLibMaxHandSizePatchType()
182240
{
183241
var byQualifiedName = ExternalFrameworkRegistry.ResolveType("BaseLib.Patches.Hooks.MaxHandSizePatch");

Combat/HandSize/MaxHandSizePatchInstaller.cs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ internal static void EnsurePatched()
5454

5555
var builder = new DynamicPatchBuilder("max_hand_size");
5656
var transpilerPlayerArg0 =
57-
DynamicPatchBuilder.FromMethod(typeof(MaxHandSizePatchInstaller), nameof(PlayerArg0Transpiler));
57+
FromMethodAfterBaseLib(nameof(PlayerArg0Transpiler));
5858
var transpilerPlayerArg1 =
59-
DynamicPatchBuilder.FromMethod(typeof(MaxHandSizePatchInstaller), nameof(PlayerArg1Transpiler));
59+
FromMethodAfterBaseLib(nameof(PlayerArg1Transpiler));
6060
var transpilerStateMachine =
61-
DynamicPatchBuilder.FromMethod(typeof(MaxHandSizePatchInstaller), nameof(StateMachineTranspiler));
61+
FromMethodAfterBaseLib(nameof(StateMachineTranspiler));
6262
var cardOnPlayTranspiler =
63-
DynamicPatchBuilder.FromMethod(typeof(MaxHandSizePatchInstaller), nameof(CardOnPlayTranspiler));
63+
FromMethodAfterBaseLib(nameof(CardOnPlayTranspiler));
6464

6565
TryAddMethodPatch(builder, typeof(CardPileCmd),
6666
nameof(CardPileCmd.CheckIfDrawIsPossibleAndShowThoughtBubbleIfNot),
@@ -130,6 +130,13 @@ internal static void EnsurePatched()
130130
}
131131
}
132132

133+
private static HarmonyMethod FromMethodAfterBaseLib(string methodName)
134+
{
135+
var method = DynamicPatchBuilder.FromMethod(typeof(MaxHandSizePatchInstaller), methodName);
136+
method.after = [Const.BaseLibHarmonyId];
137+
return method;
138+
}
139+
133140
private static void TryAddMethodPatch(
134141
DynamicPatchBuilder builder,
135142
Type targetType,
@@ -213,33 +220,54 @@ private static bool IsMaxHandSizeToken(CodeInstruction ins)
213220
#endif
214221
}
215222

223+
private static bool IsBaseLibBaseAmountToken(IReadOnlyList<CodeInstruction> code, int index)
224+
{
225+
return index + 1 < code.Count
226+
&& IsMaxHandSizeToken(code[index])
227+
&& BaseLibMaxHandSizeBridge.IsBaseLibBaseAmountConsumer(code[index + 1]);
228+
}
229+
216230
private static IEnumerable<CodeInstruction> PlayerArg0Transpiler(IEnumerable<CodeInstruction> instructions)
217231
{
218-
foreach (var ins in instructions)
232+
var code = instructions.ToList();
233+
for (var i = 0; i < code.Count; i++)
219234
{
220-
if (IsMaxHandSizeToken(ins))
235+
if (IsBaseLibBaseAmountToken(code, i))
236+
{
237+
yield return code[i];
238+
continue;
239+
}
240+
241+
if (IsMaxHandSizeToken(code[i]))
221242
{
222243
yield return new(OpCodes.Ldarg_0);
223244
yield return new(OpCodes.Call, GetMaxHandSizeMethod);
224245
continue;
225246
}
226247

227-
yield return ins;
248+
yield return code[i];
228249
}
229250
}
230251

231252
private static IEnumerable<CodeInstruction> PlayerArg1Transpiler(IEnumerable<CodeInstruction> instructions)
232253
{
233-
foreach (var ins in instructions)
254+
var code = instructions.ToList();
255+
for (var i = 0; i < code.Count; i++)
234256
{
235-
if (IsMaxHandSizeToken(ins))
257+
if (IsBaseLibBaseAmountToken(code, i))
258+
{
259+
yield return code[i];
260+
continue;
261+
}
262+
263+
if (IsMaxHandSizeToken(code[i]))
236264
{
237265
yield return new(OpCodes.Ldarg_1);
238266
yield return new(OpCodes.Call, GetMaxHandSizeMethod);
239267
continue;
240268
}
241269

242-
yield return ins;
270+
yield return code[i];
243271
}
244272
}
245273

@@ -258,6 +286,8 @@ private static IEnumerable<CodeInstruction> StateMachineTranspiler(IEnumerable<C
258286
{
259287
if (!IsMaxHandSizeToken(code[i]))
260288
continue;
289+
if (IsBaseLibBaseAmountToken(code, i))
290+
continue;
261291

262292
code[i] = new(OpCodes.Call, GetMaxHandSizeMethod);
263293
code.InsertRange(i, loadPlayer.Select(ci => ci.Clone()));
@@ -282,6 +312,8 @@ private static IEnumerable<CodeInstruction> CardOnPlayTranspiler(IEnumerable<Cod
282312
{
283313
if (!IsMaxHandSizeToken(code[i]))
284314
continue;
315+
if (IsBaseLibBaseAmountToken(code, i))
316+
continue;
285317

286318
code[i] = new(OpCodes.Call, GetMaxHandSizeFromCardMethod);
287319
code.InsertRange(i, loadCard.Select(ci => ci.Clone()));
@@ -392,7 +424,7 @@ private static bool GetPositionPrefix(int handSize, int cardIndex, ref Vector2 _
392424

393425
var halfSpread = GetInferredHalfSpread(handSize);
394426
var edgeLift = Math.Max(72f, 88f - (handSize - 10) * 1.5f);
395-
var u = handSize <= 1 ? 0f : 2f * cardIndex / (handSize - 1f) - 1f;
427+
var u = 2f * cardIndex / (handSize - 1f) - 1f;
396428
var x = halfSpread * u;
397429
var y = Math.Min(18f, -64f + edgeLift * u * u);
398430
__result = new(x, y);
@@ -413,7 +445,7 @@ private static bool GetAnglePrefix(int handSize, int cardIndex, ref float __resu
413445

414446
var halfSpread = GetInferredHalfSpread(handSize);
415447
var edgeLift = Math.Max(72f, 88f - (handSize - 10) * 1.5f);
416-
var u = handSize <= 1 ? 0f : 2f * cardIndex / (handSize - 1f) - 1f;
448+
var u = 2f * cardIndex / (handSize - 1f) - 1f;
417449
var dyDu = 2f * edgeLift * u;
418450
var dxDu = Math.Max(1f, halfSpread);
419451
var angle = Mathf.RadToDeg(Mathf.Atan2(dyDu, dxDu));

Const.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static class Const
2222
/// Assembly / manifest version string.
2323
/// 程序集/清单版本字符串。
2424
/// </summary>
25-
public const string Version = "0.2.31";
25+
public const string Version = "0.2.32";
2626

2727
/// <summary>
2828
/// Root key for RitsuLib JSON settings under the mod’s user folder.

0 commit comments

Comments
 (0)