feat: refactor equipment payload methods to unify handling and remove gift box specific logic

This commit is contained in:
Alexa
2026-06-07 10:39:08 +03:00
parent f27d16c4fe
commit feccd439d4
3 changed files with 55 additions and 38 deletions
+52 -1
View File
@@ -355,6 +355,11 @@ public class Mod : MelonMod
$"(raisePhotonRate={Cfg.DesktopScreenShareRaisePhotonRate})"); $"(raisePhotonRate={Cfg.DesktopScreenShareRaisePhotonRate})");
} }
TryPatchByName("RecRoom.Tools.MakerPenVisuals",
"set_LaserPointerEnabled",
args: new[] { typeof(bool) },
prefix: nameof(MakerPenGiftPreviewPatches.LaserPointerEnabled_Prefix));
RegisterDiagnostics(); RegisterDiagnostics();
Log.Msg("=== Client patches registered ==="); Log.Msg("=== Client patches registered ===");
} }
@@ -769,7 +774,7 @@ public class Mod : MelonMod
{ {
// Look in all three patch holder classes — small enough that a // Look in all three patch holder classes — small enough that a
// linear scan is cheaper than per-class lookups. // linear scan is cheaper than per-class lookups.
foreach (var holder in new[] { typeof(UriPatches), typeof(PhotonPatches), typeof(TlsPatches), typeof(DiagnosticPatches), typeof(SavePatches), typeof(ChatPatches), typeof(JoinPatches), typeof(RegistrationPatches), typeof(DebugConsolePatches), typeof(ScreenSharePatches) }) foreach (var holder in new[] { typeof(UriPatches), typeof(PhotonPatches), typeof(TlsPatches), typeof(DiagnosticPatches), typeof(SavePatches), typeof(ChatPatches), typeof(JoinPatches), typeof(RegistrationPatches), typeof(DebugConsolePatches), typeof(ScreenSharePatches), typeof(MakerPenGiftPreviewPatches) })
{ {
var m = holder.GetMethod(name, BindingFlags.Public | BindingFlags.Static); var m = holder.GetMethod(name, BindingFlags.Public | BindingFlags.Static);
if (m is not null) return m; if (m is not null) return m;
@@ -1540,6 +1545,52 @@ internal static class ScreenSharePatches
} }
} }
internal static class MakerPenGiftPreviewPatches
{
private static bool _loggedMissingPointer;
private static bool _loggedMissingRestrictionFlag;
public static bool LaserPointerEnabled_Prefix(object __instance, bool ONGBFDACHHG)
{
try
{
if (__instance is null) return true;
var t = __instance.GetType();
if (ReadField(__instance, t, "pointerLineRenderer") is null)
{
if (!_loggedMissingPointer)
{
_loggedMissingPointer = true;
Mod.Log.Msg("[makerpen-preview] skipped LaserPointerEnabled on MakerPenVisuals with no pointerLineRenderer");
}
return false;
}
if (ONGBFDACHHG && ReadField(__instance, t, "EANJBIDHAMN") is null)
{
if (!_loggedMissingRestrictionFlag)
{
_loggedMissingRestrictionFlag = true;
Mod.Log.Msg("[makerpen-preview] skipped LaserPointerEnabled=true on MakerPenVisuals with no laser restriction flag");
}
return false;
}
}
catch (Exception ex)
{
Mod.Log.Warning($"[makerpen-preview] guard failed, letting original run: {ex.Message}");
}
return true;
}
private static object? ReadField(object instance, Type type, string name)
{
var field = AccessTools.Field(type, name) ?? AccessTools.Field(type.BaseType, name);
return field?.GetValue(instance);
}
}
internal static class UriPatches internal static class UriPatches
{ {
public static void HttpManagerSendRequestString_Prefix(ref string url) public static void HttpManagerSendRequestString_Prefix(ref string url)
@@ -103,7 +103,7 @@ public class StorefrontsBuyController(
StoreService.TryGetAvatarItemPayload(item.Slug, out var avatarItemType, out avatarItemDesc); StoreService.TryGetAvatarItemPayload(item.Slug, out var avatarItemType, out avatarItemDesc);
var inventoryAvatarDesc = StoreService.InventoryAvatarItemDesc(avatarItemDesc); var inventoryAvatarDesc = StoreService.InventoryAvatarItemDesc(avatarItemDesc);
StoreService.TryGetConsumableItemDesc(item.Slug, out var consumableItemDesc); StoreService.TryGetConsumableItemDesc(item.Slug, out var consumableItemDesc);
StoreService.TryGetGiftBoxEquipmentPayload(item.Slug, out var equipmentPrefabName, out var equipmentModificationGuid); StoreService.TryGetEquipmentPayload(item.Slug, out var equipmentPrefabName, out var equipmentModificationGuid);
if (StoreService.TryGetHairDyePayload(item.Slug, out var hairDyeConsumableDesc, out var hairDyeColorGuid)) if (StoreService.TryGetHairDyePayload(item.Slug, out var hairDyeConsumableDesc, out var hairDyeColorGuid))
{ {
avatarItemType = 1; avatarItemType = 1;
@@ -352,7 +352,7 @@ public class StorefrontsBuyController(
{ {
StoreService.TryGetAvatarItemPayload(grantedSlug, out avatarItemType, out avatarItemDesc); StoreService.TryGetAvatarItemPayload(grantedSlug, out avatarItemType, out avatarItemDesc);
StoreService.TryGetConsumableItemDesc(grantedSlug, out consumableItemDesc); StoreService.TryGetConsumableItemDesc(grantedSlug, out consumableItemDesc);
StoreService.TryGetGiftBoxEquipmentPayload(grantedSlug, out equipmentPrefabName, out equipmentModificationGuid); StoreService.TryGetEquipmentPayload(grantedSlug, out equipmentPrefabName, out equipmentModificationGuid);
if (StoreService.TryGetHairDyePayload(grantedSlug, out var hairDyeConsumableDesc, out var hairDyeColorGuid)) if (StoreService.TryGetHairDyePayload(grantedSlug, out var hairDyeConsumableDesc, out var hairDyeColorGuid))
{ {
avatarItemType = 1; avatarItemType = 1;
+1 -35
View File
@@ -383,40 +383,6 @@ public class StoreService(DorkNetDbContext db, LevelService level, IConfiguratio
out string modificationGuid) => out string modificationGuid) =>
TryGetEquipmentPayload(slug, out prefabName, out modificationGuid, out _); TryGetEquipmentPayload(slug, out prefabName, out modificationGuid, out _);
public static bool TryGetGiftBoxEquipmentPayload(
string? slug,
out string prefabName,
out string modificationGuid,
out EquipmentSkinEntry? entry)
{
if (!TryGetEquipmentPayload(slug, out prefabName, out modificationGuid, out entry))
return false;
// The 2020 client previews GiftPackage equipment by spawning the
// prefab. Spawning [MakerPen] outside the real tool equip flow wakes
// MakerPen tool scripts without their visuals wired up, causing a
// repeating MakerPenVisuals null-ref/spin. Still grant the skin as
// inventory; just don't ask the gift-box/store-preview path to spawn it.
if (IsMakerPenPrefab(prefabName))
{
prefabName = string.Empty;
modificationGuid = string.Empty;
entry = null;
return false;
}
return true;
}
public static bool TryGetGiftBoxEquipmentPayload(
string? slug,
out string prefabName,
out string modificationGuid) =>
TryGetGiftBoxEquipmentPayload(slug, out prefabName, out modificationGuid, out _);
private static bool IsMakerPenPrefab(string? prefabName) =>
string.Equals(prefabName, "[MakerPen]", StringComparison.OrdinalIgnoreCase);
private async Task SeedEquipmentSkinsAsync(HashSet<string> existingSlugs) private async Task SeedEquipmentSkinsAsync(HashSet<string> existingSlugs)
{ {
var catalog = _equipmentSkinCatalog.Value; var catalog = _equipmentSkinCatalog.Value;
@@ -983,7 +949,7 @@ public class StoreService(DorkNetDbContext db, LevelService level, IConfiguratio
// here too. // here too.
TryGetAvatarItemPayload(i.Slug, out var avatarItemType, out var avatarItemDesc); TryGetAvatarItemPayload(i.Slug, out var avatarItemType, out var avatarItemDesc);
TryGetConsumableItemDesc(i.Slug, out var consumableItemDesc); TryGetConsumableItemDesc(i.Slug, out var consumableItemDesc);
TryGetGiftBoxEquipmentPayload(i.Slug, out var equipmentPrefabName, out var equipmentModificationGuid, out var equipmentEntry); TryGetEquipmentPayload(i.Slug, out var equipmentPrefabName, out var equipmentModificationGuid, out var equipmentEntry);
var isHairDye = TryGetHairDyePayload(i.Slug, out var consumableHairDyeDesc, out var hairDyeColorGuid); var isHairDye = TryGetHairDyePayload(i.Slug, out var consumableHairDyeDesc, out var hairDyeColorGuid);
if (isHairDye) if (isHairDye)
{ {