using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Logging;
using FishNet;
using FishNet.Managing;
using FishNet.Managing.Object;
using FishNet.Object;
using HarmonyLib;
using HowToFish.ItemSDK;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("HTFMoreItemAPI")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Runtime custom item registration API for How to Fish")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0+4cf7ec4204765620bc4bfcfabac8a7b944cfe3f3")]
[assembly: AssemblyProduct("HTFMoreItemAPI")]
[assembly: AssemblyTitle("HTFMoreItemAPI")]
[assembly: AssemblyVersion("2.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace HowToFish.ItemAPI
{
public sealed class GeneratedItemRegistration
{
public string ModGuid { get; set; }
public string InternalName { get; set; }
public GameObject ContentPrefab { get; set; }
public InventoryIcon InventoryIcon { get; set; }
public HTFItemHoldPoseAsset HoldPose { get; set; }
public string DisplayName { get; set; }
public float PickupRadius { get; set; } = 0.6f;
public float Buoyancy { get; set; }
public ushort NetworkCollectionId { get; set; }
public static GeneratedItemRegistration FromDefinition(HTFItemDefinitionAsset definition, string modGuid)
{
if (!Object.op_Implicit((Object)(object)definition))
{
throw new ArgumentNullException("definition");
}
string message = default(string);
if (!definition.Validate(ref message))
{
throw new ArgumentException(message, "definition");
}
return new GeneratedItemRegistration
{
ModGuid = modGuid,
InternalName = definition.InternalName,
ContentPrefab = definition.ContentPrefab,
InventoryIcon = InventoryIcon.FromTexture((Texture)(object)definition.InventoryIcon),
HoldPose = definition.HoldPose,
DisplayName = definition.DisplayName,
PickupRadius = definition.PickupRadius,
Buoyancy = definition.Buoyancy
};
}
}
internal static class GeneratedPrefabFactory
{
private const byte GenericTemplateItemId = 55;
private static readonly Guid SupportedGameMvid = new Guid("48815c0b-02c6-4024-a20a-1cb6cbfee2ec");
private static readonly FieldInfo ItemIdField = AccessTools.Field(typeof(Item), "_id");
private static readonly FieldInfo WorldCollidersField = AccessTools.Field(typeof(Item), "_worldColliders");
private static readonly FieldInfo PickupColliderField = AccessTools.Field(typeof(Item), "_pickUpCollider");
private static readonly FieldInfo RenderersField = AccessTools.Field(typeof(Item), "_renderers");
private static readonly FieldInfo SkinRenderersField = AccessTools.Field(typeof(Item), "_skinRenderers");
private static readonly FieldInfo MeshField = AccessTools.Field(typeof(Item), "_mesh");
private static readonly FieldInfo WeightField = AccessTools.Field(typeof(Item), "_weight");
private static readonly FieldInfo BuoyancyField = AccessTools.Field(typeof(Item), "_buoyancy");
private static readonly FieldInfo HeldPositionField = AccessTools.Field(typeof(Item), "_heldPos");
private static readonly FieldInfo HeldRotationField = AccessTools.Field(typeof(Item), "_heldRot");
private static readonly FieldInfo DrawStartPositionField = AccessTools.Field(typeof(Item), "_drawAnimStartPos");
private static readonly FieldInfo DrawStartRotationField = AccessTools.Field(typeof(Item), "_drawAnimStartRot");
private static readonly FieldInfo RightHandTransformsField = AccessTools.Field(typeof(Item), "_handTransformsRight");
private static readonly FieldInfo LeftHandTransformsField = AccessTools.Field(typeof(Item), "_handTransformsLeft");
private static readonly FieldInfo HoldBobMultiplierField = AccessTools.Field(typeof(Item), "_holdBobMulti");
private static readonly FieldInfo OverridePlayerVelocityField = AccessTools.Field(typeof(Item), "_overridePlayerVelAmount");
private static readonly FieldInfo PlayerVelocityAmountField = AccessTools.Field(typeof(Item), "_playerVelAmount");
private static GameObject _runtimeRoot;
internal static bool ValidateSource(GeneratedItemRegistration registration, out string error)
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
error = null;
if (!Object.op_Implicit((Object)(object)registration.ContentPrefab))
{
error = "ContentPrefab cannot be null.";
return false;
}
Scene scene = registration.ContentPrefab.scene;
if (((Scene)(ref scene)).IsValid())
{
error = "ContentPrefab must be a prefab asset returned by AssetBundle.LoadAsset<GameObject>().";
return false;
}
if (registration.InventoryIcon == null || !Object.op_Implicit((Object)(object)registration.InventoryIcon.Texture))
{
error = "A generated item must provide a valid icon from its AssetBundle.";
return false;
}
if (registration.PickupRadius <= 0f || float.IsNaN(registration.PickupRadius) || float.IsInfinity(registration.PickupRadius))
{
error = "PickupRadius must be a finite value greater than zero.";
return false;
}
if (float.IsNaN(registration.Buoyancy) || float.IsInfinity(registration.Buoyancy))
{
error = "Buoyancy must be a finite value.";
return false;
}
if (Object.op_Implicit((Object)(object)registration.HoldPose) && !registration.HoldPose.Validate(ref error))
{
error = "HoldPose is invalid: " + error;
return false;
}
if (Object.op_Implicit((Object)(object)registration.ContentPrefab.GetComponentInChildren<Item>(true)))
{
error = "ContentPrefab must not contain Item; the API provides it through the game skeleton.";
return false;
}
if (Object.op_Implicit((Object)(object)registration.ContentPrefab.GetComponentInChildren<RigidbodySync>(true)))
{
error = "ContentPrefab must not contain RigidbodySync; the API provides it.";
return false;
}
if (Object.op_Implicit((Object)(object)registration.ContentPrefab.GetComponentInChildren<NetworkObject>(true)))
{
error = "ContentPrefab must not contain NetworkObject; the API provides it.";
return false;
}
Rigidbody[] componentsInChildren = registration.ContentPrefab.GetComponentsInChildren<Rigidbody>(true);
Rigidbody component = registration.ContentPrefab.GetComponent<Rigidbody>();
if (componentsInChildren.Length != 1 || !Object.op_Implicit((Object)(object)component) || (Object)(object)componentsInChildren[0] != (Object)(object)component)
{
error = $"The ContentPrefab root must contain exactly one Rigidbody; the hierarchy currently contains {componentsInChildren.Length}.";
return false;
}
if (registration.ContentPrefab.GetComponentsInChildren<Collider>(true).Length == 0)
{
error = "ContentPrefab must contain at least one Collider.";
return false;
}
return true;
}
internal static bool TryCreate(string key, byte itemId, GeneratedItemRegistration registration, out Item item, out NetworkObject networkObject, out string error)
{
//IL_014c: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_01de: Unknown result type (might be due to invalid IL or missing references)
item = null;
networkObject = null;
error = null;
Guid moduleVersionId = typeof(Item).Assembly.ManifestModule.ModuleVersionId;
if (moduleVersionId != SupportedGameMvid)
{
error = "The current Assembly-CSharp is not supported by the generation pipeline; " + $"MVID={moduleVersionId}, Supported={SupportedGameMvid}.";
return false;
}
if (!ValidateSource(registration, out error))
{
return false;
}
if (!ValidateReflection(out error))
{
return false;
}
Item spawnable = GameInfo.GetSpawnable((byte)55);
if (!ValidateTemplate(spawnable, out error))
{
return false;
}
EnsureRuntimeRoot();
GameObject val = null;
try
{
val = Object.Instantiate<GameObject>(((Component)spawnable).gameObject, _runtimeRoot.transform, false);
((Object)val).name = "HTFMoreItemAPI_" + SanitizeObjectName(key);
if (val.activeInHierarchy)
{
throw new InvalidOperationException("The generation container is unexpectedly active.");
}
Item component = val.GetComponent<Item>();
NetworkObject component2 = val.GetComponent<NetworkObject>();
Rigidbody component3 = val.GetComponent<Rigidbody>();
SphereCollider val2 = FindRootPickupCollider(val);
if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2) || !Object.op_Implicit((Object)(object)component3) || !Object.op_Implicit((Object)(object)val2))
{
throw new InvalidOperationException("The cloned base-item skeleton is missing required components.");
}
RemoveTemplateChildren(val.transform);
GameObject val3 = Object.Instantiate<GameObject>(registration.ContentPrefab, val.transform, false);
((Object)val3).name = "Content";
val3.transform.localPosition = Vector3.zero;
val3.transform.localRotation = Quaternion.identity;
Rigidbody[] componentsInChildren = val3.GetComponentsInChildren<Rigidbody>(true);
if (componentsInChildren.Length != 1)
{
throw new InvalidOperationException("The number of Rigidbodies changed after cloning the content prefab.");
}
CopyRigidbodySettings(componentsInChildren[0], component3);
Object.DestroyImmediate((Object)(object)componentsInChildren[0]);
Collider[] componentsInChildren2 = val3.GetComponentsInChildren<Collider>(true);
if (componentsInChildren2.Length == 0)
{
throw new InvalidOperationException("The cloned content prefab has no Collider.");
}
Collider[] array = componentsInChildren2;
foreach (Collider obj in array)
{
obj.isTrigger = false;
obj.enabled = true;
}
((Collider)val2).isTrigger = true;
val2.center = Vector3.zero;
val2.radius = registration.PickupRadius;
((Collider)val2).enabled = true;
List<Renderer> list = new List<Renderer>(val3.GetComponentsInChildren<Renderer>(true));
List<Renderer> list2 = new List<Renderer>();
foreach (Renderer item2 in list)
{
if (item2 is SkinnedMeshRenderer)
{
list2.Add(item2);
}
}
Mesh value = FindFirstMesh(val3);
ItemIdField.SetValue(component, itemId);
WorldCollidersField.SetValue(component, componentsInChildren2);
PickupColliderField.SetValue(component, val2);
RenderersField.SetValue(component, list);
SkinRenderersField.SetValue(component, list2);
MeshField.SetValue(component, value);
WeightField.SetValue(component, component3.mass);
BuoyancyField.SetValue(component, registration.Buoyancy);
if (Object.op_Implicit((Object)(object)registration.HoldPose))
{
ApplyHoldPose(component, val.transform, registration.HoldPose);
}
component2.SetIsSpawnable(true);
item = component;
networkObject = component2;
return true;
}
catch (Exception ex)
{
if (Object.op_Implicit((Object)(object)val))
{
Object.DestroyImmediate((Object)(object)val);
}
error = "Failed to generate the item skeleton: " + ex.GetType().Name + ": " + ex.Message;
return false;
}
}
internal static void Shutdown()
{
if (Object.op_Implicit((Object)(object)_runtimeRoot))
{
Object.Destroy((Object)(object)_runtimeRoot);
}
_runtimeRoot = null;
}
private static bool ValidateReflection(out string error)
{
error = null;
if (ItemIdField != null && WorldCollidersField != null && PickupColliderField != null && RenderersField != null && SkinRenderersField != null && MeshField != null && WeightField != null && BuoyancyField != null && HeldPositionField != null && HeldRotationField != null && DrawStartPositionField != null && DrawStartRotationField != null && RightHandTransformsField != null && LeftHandTransformsField != null && HoldBobMultiplierField != null && OverridePlayerVelocityField != null && PlayerVelocityAmountField != null)
{
return true;
}
error = "The current game version is missing Item serialization fields required by the generation pipeline.";
return false;
}
private static bool ValidateTemplate(Item template, out string error)
{
error = null;
if (!Object.op_Implicit((Object)(object)template))
{
error = $"The original generic item template ItemId={(byte)55} was not found.";
return false;
}
if (((object)template).GetType() != typeof(Item))
{
error = "The generic template must be exactly Item, but was " + ((object)template).GetType().FullName + ".";
return false;
}
if (!Object.op_Implicit((Object)(object)((Component)template).GetComponent<NetworkObject>()) || !Object.op_Implicit((Object)(object)((Component)template).GetComponent<RigidbodySync>()) || !Object.op_Implicit((Object)(object)((Component)template).GetComponent<Rigidbody>()))
{
error = "The original generic item template is missing NetworkObject, RigidbodySync, or Rigidbody.";
return false;
}
NetworkBehaviour[] components = ((Component)template).GetComponents<NetworkBehaviour>();
if (components.Length != 2)
{
error = $"The original generic template must contain 2 NetworkBehaviours, but contains {components.Length}.";
return false;
}
if ((Object)(object)FindRootPickupCollider(((Component)template).gameObject) == (Object)null)
{
error = "The original generic item template is missing its root pickup SphereCollider.";
return false;
}
return true;
}
private static void EnsureRuntimeRoot()
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
if (!Object.op_Implicit((Object)(object)_runtimeRoot))
{
_runtimeRoot = new GameObject("HTFMoreItemAPI.RuntimePrefabs");
((Object)_runtimeRoot).hideFlags = (HideFlags)61;
Object.DontDestroyOnLoad((Object)(object)_runtimeRoot);
_runtimeRoot.SetActive(false);
}
}
private static SphereCollider FindRootPickupCollider(GameObject root)
{
SphereCollider[] components = root.GetComponents<SphereCollider>();
foreach (SphereCollider val in components)
{
if (((Collider)val).isTrigger)
{
return val;
}
}
return null;
}
private static void RemoveTemplateChildren(Transform root)
{
for (int num = root.childCount - 1; num >= 0; num--)
{
Object.DestroyImmediate((Object)(object)((Component)root.GetChild(num)).gameObject);
}
}
private static void CopyRigidbodySettings(Rigidbody source, Rigidbody target)
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
target.mass = source.mass;
target.linearDamping = source.linearDamping;
target.angularDamping = source.angularDamping;
target.useGravity = source.useGravity;
target.isKinematic = source.isKinematic;
target.interpolation = source.interpolation;
target.collisionDetectionMode = source.collisionDetectionMode;
target.constraints = source.constraints;
target.detectCollisions = source.detectCollisions;
target.maxAngularVelocity = source.maxAngularVelocity;
target.maxLinearVelocity = source.maxLinearVelocity;
target.automaticCenterOfMass = source.automaticCenterOfMass;
if (!source.automaticCenterOfMass)
{
target.centerOfMass = source.centerOfMass;
}
target.automaticInertiaTensor = source.automaticInertiaTensor;
if (!source.automaticInertiaTensor)
{
target.inertiaTensor = source.inertiaTensor;
target.inertiaTensorRotation = source.inertiaTensorRotation;
}
}
private static void ApplyHoldPose(Item item, Transform itemRoot, HTFItemHoldPoseAsset pose)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
HeldPositionField.SetValue(item, pose.HeldPosition);
HeldRotationField.SetValue(item, pose.HeldRotation);
DrawStartPositionField.SetValue(item, pose.DrawStartPosition);
DrawStartRotationField.SetValue(item, pose.DrawStartRotation);
RightHandTransformsField.SetValue(item, CreateGameHandPose(pose.RightHand, itemRoot));
LeftHandTransformsField.SetValue(item, CreateGameHandPose(pose.LeftHand, itemRoot));
HoldBobMultiplierField.SetValue(item, pose.HoldBobMultiplier);
OverridePlayerVelocityField.SetValue(item, pose.OverridePlayerVelocityAmount);
PlayerVelocityAmountField.SetValue(item, pose.PlayerVelocityAmount);
}
private static HandTransforms CreateGameHandPose(HTFHandPoseData source, Transform itemRoot)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Expected O, but got Unknown
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Expected O, but got Unknown
if (source != null && source.Enabled)
{
Quaternion[] fingerLocalRotations = source.FingerLocalRotations;
if (fingerLocalRotations == null || fingerLocalRotations.Length != 15)
{
throw new InvalidOperationException($"An enabled hand pose must contain {15} finger-joint rotations.");
}
Quaternion[] array = (Quaternion[])(object)new Quaternion[fingerLocalRotations.Length];
Array.Copy(fingerLocalRotations, array, array.Length);
return new HandTransforms(true, source.HandPosition, source.HandRotation, array, itemRoot);
}
return new HandTransforms(false);
}
private static Mesh FindFirstMesh(GameObject content)
{
MeshFilter[] componentsInChildren = content.GetComponentsInChildren<MeshFilter>(true);
foreach (MeshFilter val in componentsInChildren)
{
if (Object.op_Implicit((Object)(object)val.sharedMesh))
{
return val.sharedMesh;
}
}
SkinnedMeshRenderer[] componentsInChildren2 = content.GetComponentsInChildren<SkinnedMeshRenderer>(true);
foreach (SkinnedMeshRenderer val2 in componentsInChildren2)
{
if (Object.op_Implicit((Object)(object)val2.sharedMesh))
{
return val2.sharedMesh;
}
}
return null;
}
private static string SanitizeObjectName(string value)
{
return value.Replace(':', '_').Replace('/', '_').Replace('\\', '_');
}
}
public sealed class InventoryIcon
{
public Texture Texture { get; }
public Rect UvRect { get; }
public Color Tint { get; }
public InventoryIcon(Texture texture)
: this(texture, new Rect(0f, 0f, 1f, 1f), Color.white)
{
}//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
public InventoryIcon(Texture texture, Rect uvRect, Color tint)
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)texture))
{
throw new ArgumentNullException("texture");
}
Texture = texture;
UvRect = uvRect;
Tint = tint;
}
public static InventoryIcon FromTexture(Texture texture)
{
return new InventoryIcon(texture);
}
public static InventoryIcon FromSprite(Sprite sprite)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)sprite))
{
throw new ArgumentNullException("sprite");
}
Texture2D texture = sprite.texture;
Rect textureRect = sprite.textureRect;
Rect uvRect = default(Rect);
((Rect)(ref uvRect))..ctor(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height);
return new InventoryIcon((Texture)(object)texture, uvRect, Color.white);
}
}
public static class ItemApiMetadata
{
public const string PluginGuid = "xiaohai.HTF.MoreItemAPI";
public const string PluginName = "HTF MoreItemAPI";
public const string PluginVersion = "2.0.0";
}
[HarmonyPatch(typeof(GameInfo), "Awake")]
internal static class GameInfoAwakePatch
{
[HarmonyPostfix]
private static void Postfix()
{
RegistryRuntime.OnGameInfoAwakeCompleted();
}
}
[HarmonyPatch(typeof(Item), "GetName")]
internal static class CustomItemNamePatch
{
[HarmonyPostfix]
private static void Postfix(Item __instance, ref string __result)
{
if (Object.op_Implicit((Object)(object)__instance) && RegistryRuntime.TryGetDisplayName(__instance.ID, out var displayName))
{
__result = displayName;
}
}
}
[HarmonyPatch(typeof(InventorySlot), "SetItem")]
internal static class InventorySlotIconPatch
{
private sealed class NativeImageState
{
internal Texture Texture;
internal Rect UvRect;
internal Color Color;
internal bool Enabled;
}
private static readonly FieldInfo FilterField = AccessTools.Field(typeof(InventorySlot), "_filter");
private static readonly FieldInfo ImageField = AccessTools.Field(typeof(InventorySlot), "_itemImage");
private static readonly Dictionary<RawImage, NativeImageState> NativeStates = new Dictionary<RawImage, NativeImageState>();
[HarmonyPostfix]
private static void Postfix(InventorySlot __instance, Item item)
{
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)__instance == (Object)null || ImageField == null)
{
return;
}
object? value = ImageField.GetValue(__instance);
RawImage val = (RawImage)((value is RawImage) ? value : null);
if (!Object.op_Implicit((Object)(object)val))
{
return;
}
if (!NativeStates.TryGetValue(val, out var value2))
{
value2 = new NativeImageState
{
Texture = val.texture,
UvRect = val.uvRect,
Color = ((Graphic)val).color,
Enabled = ((Behaviour)val).enabled
};
NativeStates.Add(val, value2);
}
if (!Object.op_Implicit((Object)(object)item) || !RegistryRuntime.TryGetIcon(item.ID, out var icon))
{
val.texture = (Texture)(Object.op_Implicit((Object)(object)value2.Texture) ? ((object)value2.Texture) : ((object)GameInfo.InventoryTexture));
val.uvRect = value2.UvRect;
((Graphic)val).color = value2.Color;
((Behaviour)val).enabled = value2.Enabled;
return;
}
object? obj = FilterField?.GetValue(__instance);
MeshFilter val2 = (MeshFilter)((obj is MeshFilter) ? obj : null);
if (Object.op_Implicit((Object)(object)val2))
{
val2.mesh = null;
}
val.texture = icon.Texture;
val.uvRect = icon.UvRect;
((Graphic)val).color = icon.Tint;
((Behaviour)val).enabled = true;
((Component)val).transform.localScale = Vector3.one;
}
}
[BepInPlugin("xiaohai.HTF.MoreItemAPI", "HTF MoreItemAPI", "2.0.0")]
public sealed class ItemApiPlugin : BaseUnityPlugin
{
private Harmony _harmony;
private void Awake()
{
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
RegistryRuntime.Initialize(((BaseUnityPlugin)this).Logger);
_harmony = new Harmony("xiaohai.HTF.MoreItemAPI");
_harmony.PatchAll(typeof(ItemApiPlugin).Assembly);
((BaseUnityPlugin)this).Logger.LogInfo((object)"HTF MoreItemAPI v2.0.0 loaded.");
}
private void Update()
{
RegistryRuntime.Tick();
}
private void OnDestroy()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
GeneratedPrefabFactory.Shutdown();
RegistryRuntime.Shutdown();
}
}
internal static class ItemIdAllocator
{
internal const int SlotCount = 256;
internal static Dictionary<string, byte> Allocate(IEnumerable<string> keys, IEnumerable<byte> occupiedIds)
{
if (keys == null)
{
throw new ArgumentNullException("keys");
}
HashSet<byte> hashSet = ((occupiedIds == null) ? new HashSet<byte>() : new HashSet<byte>(occupiedIds));
hashSet.Add(byte.MaxValue);
List<string> list = new List<string>();
foreach (string key in keys)
{
if (string.IsNullOrWhiteSpace(key))
{
throw new ArgumentException("Allocation keys cannot be null or empty.", "keys");
}
list.Add(key);
}
list.Sort(StringComparer.Ordinal);
if (list.Count > 256 - hashSet.Count)
{
throw new InvalidOperationException($"No free Item ID slots remain: requested={list.Count}, free={256 - hashSet.Count}.");
}
Dictionary<string, byte> dictionary = new Dictionary<string, byte>(StringComparer.OrdinalIgnoreCase);
foreach (string item in list)
{
if (dictionary.ContainsKey(item))
{
throw new InvalidOperationException("Duplicate item registration key '" + item + "'.");
}
byte b = DerivePreferredId(item);
bool flag = false;
for (int i = 0; i < 256; i++)
{
byte b2 = (byte)(b + i);
if (hashSet.Add(b2))
{
dictionary.Add(item, b2);
flag = true;
break;
}
}
if (!flag)
{
throw new InvalidOperationException("No free Item ID slots remain.");
}
}
return dictionary;
}
internal static byte DerivePreferredId(string key)
{
uint num = 2166136261u;
byte[] bytes = Encoding.UTF8.GetBytes(key);
foreach (byte b in bytes)
{
num ^= b;
num *= 16777619;
}
return (byte)num;
}
}
public sealed class ItemRegistration
{
public string ModGuid { get; set; }
public string InternalName { get; set; }
public GameObject Prefab { get; set; }
public string DisplayName { get; set; }
public InventoryIcon InventoryIcon { get; set; }
public ushort NetworkCollectionId { get; set; }
}
public enum ItemRegistrationState
{
Rejected,
PendingGameRegistry,
PendingNetworkManager,
Registered,
Failed
}
public sealed class ItemRegistrationHandle
{
public string Key { get; }
public byte? ItemId { get; internal set; }
public bool HasAssignedItemId => ItemId.HasValue;
public ushort NetworkCollectionId { get; }
public Item ItemPrefab { get; internal set; }
public ItemRegistrationState State { get; internal set; }
public string Message { get; internal set; }
public bool IsRegistered => State == ItemRegistrationState.Registered;
internal ItemRegistrationHandle(string key, ushort networkCollectionId, Item itemPrefab, ItemRegistrationState state, string message)
{
Key = key;
NetworkCollectionId = networkCollectionId;
ItemPrefab = itemPrefab;
State = state;
Message = message;
}
public override string ToString()
{
string text = (ItemId.HasValue ? ItemId.Value.ToString() : "<auto-pending>");
return $"{Key} (ItemId={text}, CollectionId={NetworkCollectionId}, State={State})";
}
}
public static class ItemRegistry
{
public static event Action<ItemRegistrationHandle> RegistrationChanged;
public static ItemRegistrationHandle Register(ItemRegistration registration)
{
return RegistryRuntime.Register(registration);
}
public static ItemRegistrationHandle RegisterGenerated(GeneratedItemRegistration registration)
{
return RegistryRuntime.RegisterGenerated(registration);
}
public static bool TryGet(byte itemId, out ItemRegistrationHandle handle)
{
return RegistryRuntime.TryGet(itemId, out handle);
}
public static bool TryGet(string modGuid, string internalName, out ItemRegistrationHandle handle)
{
return RegistryRuntime.TryGet(RegistryRuntime.BuildKey(modGuid, internalName), out handle);
}
public static IReadOnlyList<ItemRegistrationHandle> GetAll()
{
return RegistryRuntime.GetAllHandles();
}
internal static void RaiseRegistrationChanged(ItemRegistrationHandle handle)
{
Action<ItemRegistrationHandle> registrationChanged = ItemRegistry.RegistrationChanged;
if (registrationChanged == null)
{
return;
}
try
{
registrationChanged(handle);
}
catch (Exception exception)
{
RegistryRuntime.LogSubscriberException(exception);
}
}
}
internal static class RegistryRuntime
{
private sealed class RegistrationRecord
{
internal string Key;
internal string NormalizedName;
internal string DisplayName;
internal Item ItemPrefab;
internal NetworkObject NetworkPrefab;
internal InventoryIcon Icon;
internal GeneratedItemRegistration GeneratedRegistration;
internal ItemRegistrationHandle Handle;
internal bool GameRegistryApplied;
internal readonly HashSet<NetworkManager> RegisteredNetworkManagers = new HashSet<NetworkManager>();
}
private static readonly object Sync = new object();
private static readonly Dictionary<string, RegistrationRecord> ByKey = new Dictionary<string, RegistrationRecord>(StringComparer.OrdinalIgnoreCase);
private static readonly Dictionary<byte, RegistrationRecord> ById = new Dictionary<byte, RegistrationRecord>();
private static readonly Dictionary<ushort, RegistrationRecord> ByCollectionId = new Dictionary<ushort, RegistrationRecord>();
private static readonly FieldInfo ItemIdField = AccessTools.Field(typeof(Item), "_id");
private static readonly FieldInfo GameInfoInstanceField = AccessTools.Field(typeof(GameInfo), "_instance");
private static readonly FieldInfo AllItemsField = AccessTools.Field(typeof(GameInfo), "_allItems");
private static readonly FieldInfo NameToSpawnableField = AccessTools.Field(typeof(GameInfo), "_nameToSpawnable");
private static readonly FieldInfo IdToSpawnableField = AccessTools.Field(typeof(GameInfo), "_idToSpawnable");
private static ManualLogSource _logger;
private static int _mainThreadId;
private static bool _initialized;
private static bool _gameInfoAwakeCompleted;
private static float _nextRetryAt;
internal static void Initialize(ManualLogSource logger)
{
_logger = logger;
_mainThreadId = Thread.CurrentThread.ManagedThreadId;
_initialized = true;
_gameInfoAwakeCompleted = GameInfoInstanceField?.GetValue(null) != null;
if (ItemIdField == null || GameInfoInstanceField == null || AllItemsField == null || NameToSpawnableField == null || IdToSpawnableField == null)
{
_logger.LogError((object)"[ItemAPI] The current game version is missing expected Item/GameInfo fields; registration will fail safely.");
}
}
internal static void Shutdown()
{
_initialized = false;
_logger = null;
}
internal static ItemRegistrationHandle Register(ItemRegistration registration)
{
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
if (!_initialized)
{
return Rejected("<unknown>", 0, null, "The Item API plugin is not initialized. Declare a hard BepInEx dependency.");
}
if (Thread.CurrentThread.ManagedThreadId != _mainThreadId)
{
return Rejected("<unknown>", 0, null, "Register must be called from Unity's main thread.");
}
if (registration == null)
{
return Rejected("<unknown>", 0, null, "registration cannot be null.");
}
string key;
try
{
key = BuildKey(registration.ModGuid, registration.InternalName);
}
catch (ArgumentException ex)
{
return Rejected("<invalid>", 0, null, ex.Message);
}
if (!Object.op_Implicit((Object)(object)registration.Prefab))
{
return Rejected(key, 0, null, "Prefab cannot be null.");
}
Scene scene = registration.Prefab.scene;
if (((Scene)(ref scene)).IsValid())
{
return Rejected(key, 0, null, "Prefab is a scene instance. Pass the prefab asset returned by AssetBundle.LoadAsset<GameObject>() directly.");
}
Item component = registration.Prefab.GetComponent<Item>();
if (!Object.op_Implicit((Object)(object)component))
{
return Rejected(key, 0, null, "The prefab root is missing an Item component.");
}
NetworkObject component2 = registration.Prefab.GetComponent<NetworkObject>();
if (!Object.op_Implicit((Object)(object)component2))
{
return Rejected(key, 0, component, "The prefab root is missing a FishNet NetworkObject component.");
}
if (ItemIdField == null)
{
return Rejected(key, 0, component, "Item._id could not be located in the current game version.");
}
ushort num = ((registration.NetworkCollectionId != 0) ? registration.NetworkCollectionId : DeriveCollectionId(key));
string text = NormalizeName(registration.InternalName);
if (text.Length == 0)
{
return Rejected(key, num, component, "InternalName cannot be empty after normalization.");
}
lock (Sync)
{
if (ByKey.TryGetValue(key, out var value))
{
if ((Object)(object)value.ItemPrefab == (Object)(object)component)
{
return value.Handle;
}
return Rejected(key, num, component, "The registration key is already used by another prefab.");
}
if (ByCollectionId.TryGetValue(num, out var value2))
{
return Rejected(key, num, component, "FishNet collection ID is already used by " + value2.Key + "; explicitly specify another NetworkCollectionId.");
}
component2.SetIsSpawnable(true);
ItemRegistrationHandle itemRegistrationHandle = new ItemRegistrationHandle(key, num, component, ItemRegistrationState.PendingGameRegistry, "Waiting for GameInfo to complete original item registration.");
RegistrationRecord value3 = new RegistrationRecord
{
Key = key,
NormalizedName = text,
DisplayName = registration.DisplayName,
ItemPrefab = component,
NetworkPrefab = component2,
Icon = registration.InventoryIcon,
Handle = itemRegistrationHandle
};
ByKey.Add(key, value3);
ByCollectionId.Add(num, value3);
_logger.LogInfo((object)$"[ItemAPI] Accepted {itemRegistrationHandle}.");
}
ProcessRegistrations();
return GetHandleByKey(key);
}
internal static ItemRegistrationHandle RegisterGenerated(GeneratedItemRegistration registration)
{
if (!_initialized)
{
return Rejected("<unknown>", 0, null, "The Item API plugin is not initialized. Declare a hard BepInEx dependency.");
}
if (Thread.CurrentThread.ManagedThreadId != _mainThreadId)
{
return Rejected("<unknown>", 0, null, "RegisterGenerated must be called from Unity's main thread.");
}
if (registration == null)
{
return Rejected("<unknown>", 0, null, "registration cannot be null.");
}
string key;
try
{
key = BuildKey(registration.ModGuid, registration.InternalName);
}
catch (ArgumentException ex)
{
return Rejected("<invalid>", 0, null, ex.Message);
}
ushort num = ((registration.NetworkCollectionId != 0) ? registration.NetworkCollectionId : DeriveCollectionId(key));
string text = NormalizeName(registration.InternalName);
if (text.Length == 0)
{
return Rejected(key, num, null, "InternalName cannot be empty after normalization.");
}
if (!GeneratedPrefabFactory.ValidateSource(registration, out var error))
{
return Rejected(key, num, null, error);
}
lock (Sync)
{
if (ByKey.TryGetValue(key, out var value))
{
if (value.GeneratedRegistration != null && (Object)(object)value.GeneratedRegistration.ContentPrefab == (Object)(object)registration.ContentPrefab)
{
return value.Handle;
}
return Rejected(key, num, null, "The registration key is already used by another generated-item definition.");
}
if (ByCollectionId.TryGetValue(num, out var value2))
{
return Rejected(key, num, null, "FishNet collection ID is already used by " + value2.Key + "; explicitly specify another NetworkCollectionId.");
}
GeneratedItemRegistration generatedItemRegistration = new GeneratedItemRegistration
{
ModGuid = registration.ModGuid,
InternalName = registration.InternalName,
ContentPrefab = registration.ContentPrefab,
InventoryIcon = registration.InventoryIcon,
HoldPose = registration.HoldPose,
DisplayName = registration.DisplayName,
PickupRadius = registration.PickupRadius,
Buoyancy = registration.Buoyancy,
NetworkCollectionId = num
};
ItemRegistrationHandle itemRegistrationHandle = new ItemRegistrationHandle(key, num, null, ItemRegistrationState.PendingGameRegistry, "Waiting for GameInfo before generating the original item skeleton.");
RegistrationRecord value3 = new RegistrationRecord
{
Key = key,
NormalizedName = text,
DisplayName = generatedItemRegistration.DisplayName,
GeneratedRegistration = generatedItemRegistration,
Icon = generatedItemRegistration.InventoryIcon,
Handle = itemRegistrationHandle
};
ByKey.Add(key, value3);
ByCollectionId.Add(num, value3);
_logger.LogInfo((object)$"[ItemAPI] Accepted generated item {itemRegistrationHandle}.");
}
ProcessRegistrations();
return GetHandleByKey(key);
}
internal static void Tick()
{
if (_initialized && !(Time.unscaledTime < _nextRetryAt))
{
_nextRetryAt = Time.unscaledTime + 0.25f;
ProcessRegistrations();
}
}
internal static void OnGameInfoAwakeCompleted()
{
_gameInfoAwakeCompleted = true;
ProcessRegistrations();
}
private static void ProcessRegistrations()
{
if (!_initialized || Thread.CurrentThread.ManagedThreadId != _mainThreadId)
{
return;
}
RegistrationRecord[] array;
lock (Sync)
{
array = new RegistrationRecord[ByKey.Count];
ByKey.Values.CopyTo(array, 0);
}
if (_gameInfoAwakeCompleted)
{
AssignPendingItemIds(array);
}
RegistrationRecord[] array2 = array;
foreach (RegistrationRecord registrationRecord in array2)
{
if (registrationRecord.Handle.State == ItemRegistrationState.Failed || registrationRecord.Handle.State == ItemRegistrationState.Rejected)
{
continue;
}
if (!_gameInfoAwakeCompleted)
{
SetState(registrationRecord, ItemRegistrationState.PendingGameRegistry, "Waiting for GameInfo before HTF MoreItemAPI assigns a game-local Item ID.");
continue;
}
if (!registrationRecord.Handle.ItemId.HasValue)
{
SetState(registrationRecord, ItemRegistrationState.PendingGameRegistry, "Waiting for HTF MoreItemAPI to assign a free game-local Item ID.");
continue;
}
if (!Object.op_Implicit((Object)(object)registrationRecord.ItemPrefab))
{
if (registrationRecord.GeneratedRegistration == null)
{
Fail(registrationRecord, "The registration record does not contain a valid Item prefab.");
continue;
}
if (!GeneratedPrefabFactory.TryCreate(registrationRecord.Key, registrationRecord.Handle.ItemId.Value, registrationRecord.GeneratedRegistration, out var item, out var networkObject, out var error))
{
Fail(registrationRecord, error);
continue;
}
registrationRecord.ItemPrefab = item;
registrationRecord.NetworkPrefab = networkObject;
registrationRecord.Handle.ItemPrefab = item;
_logger.LogInfo((object)("[ItemAPI] Generated the item skeleton for " + registrationRecord.Key + " through the fixed pipeline; " + $"WorldColliders={((Component)item).GetComponentsInChildren<Collider>(true).Length - 1}."));
}
if (!registrationRecord.GameRegistryApplied && !TryApplyGameRegistry(registrationRecord, out var error2))
{
Fail(registrationRecord, error2);
continue;
}
NetworkManager networkManager = InstanceFinder.NetworkManager;
if (!Object.op_Implicit((Object)(object)networkManager))
{
SetState(registrationRecord, ItemRegistrationState.PendingNetworkManager, "The game registry is ready; waiting for FishNet NetworkManager.");
continue;
}
if (!registrationRecord.RegisteredNetworkManagers.Contains(networkManager))
{
if (!TryApplyNetworkRegistry(registrationRecord, networkManager, out var error3))
{
Fail(registrationRecord, error3);
continue;
}
registrationRecord.RegisteredNetworkManagers.Add(networkManager);
}
SetState(registrationRecord, ItemRegistrationState.Registered, "Registered with GameInfo and the FishNet runtime spawnable collection.");
}
}
private static void AssignPendingItemIds(RegistrationRecord[] records)
{
if (AllItemsField == null || IdToSpawnableField == null || ItemIdField == null)
{
return;
}
Dictionary<byte, Item> dictionary = AllItemsField.GetValue(null) as Dictionary<byte, Item>;
Dictionary<byte, Item> dictionary2 = IdToSpawnableField.GetValue(null) as Dictionary<byte, Item>;
if (dictionary == null || dictionary2 == null)
{
return;
}
List<RegistrationRecord> list = new List<RegistrationRecord>();
HashSet<byte> hashSet = new HashSet<byte>(dictionary.Keys);
hashSet.UnionWith(dictionary2.Keys);
lock (Sync)
{
hashSet.UnionWith(ById.Keys);
foreach (RegistrationRecord registrationRecord in records)
{
if (!registrationRecord.Handle.ItemId.HasValue && registrationRecord.Handle.State != ItemRegistrationState.Failed && registrationRecord.Handle.State != ItemRegistrationState.Rejected)
{
list.Add(registrationRecord);
}
}
}
if (list.Count == 0)
{
return;
}
List<string> list2 = new List<string>(list.Count);
foreach (RegistrationRecord item in list)
{
list2.Add(item.Key);
}
Dictionary<string, byte> dictionary3;
try
{
dictionary3 = ItemIdAllocator.Allocate(list2, hashSet);
}
catch (InvalidOperationException ex)
{
foreach (RegistrationRecord item2 in list)
{
Fail(item2, "Automatic Item ID allocation failed: " + ex.Message);
}
return;
}
lock (Sync)
{
foreach (RegistrationRecord item3 in list)
{
if (!item3.Handle.ItemId.HasValue)
{
byte b = dictionary3[item3.Key];
item3.Handle.ItemId = b;
ById.Add(b, item3);
if (Object.op_Implicit((Object)(object)item3.ItemPrefab))
{
ItemIdField.SetValue(item3.ItemPrefab, b);
}
_logger.LogInfo((object)($"[ItemAPI] Automatically assigned ItemId={b} to {item3.Key}; " + $"Preferred={ItemIdAllocator.DerivePreferredId(item3.Key)}."));
}
}
}
}
private static bool TryApplyGameRegistry(RegistrationRecord record, out string error)
{
error = null;
if (AllItemsField == null || NameToSpawnableField == null || IdToSpawnableField == null)
{
error = "GameInfo registry fields could not be located in the current game version.";
return false;
}
Dictionary<byte, Item> dictionary = AllItemsField.GetValue(null) as Dictionary<byte, Item>;
Dictionary<string, Item> dictionary2 = NameToSpawnableField.GetValue(null) as Dictionary<string, Item>;
Dictionary<byte, Item> dictionary3 = IdToSpawnableField.GetValue(null) as Dictionary<byte, Item>;
if (dictionary == null || dictionary2 == null || dictionary3 == null)
{
error = "The GameInfo registry is not available yet.";
return false;
}
byte value = record.Handle.ItemId.Value;
if (dictionary.TryGetValue(value, out var value2) && (Object)(object)value2 != (Object)(object)record.ItemPrefab)
{
error = $"Automatically assigned Item ID {value} is already used by {Describe(value2)} from the game or another mod.";
return false;
}
if (dictionary3.TryGetValue(value, out var value3) && (Object)(object)value3 != (Object)(object)record.ItemPrefab)
{
error = $"Automatically assigned Spawnable ID {value} is already used by {Describe(value3)}.";
return false;
}
if (dictionary2.TryGetValue(record.NormalizedName, out var value4) && (Object)(object)value4 != (Object)(object)record.ItemPrefab)
{
error = "Normalized name '" + record.NormalizedName + "' is already used by " + Describe(value4) + ".";
return false;
}
dictionary[value] = record.ItemPrefab;
dictionary3[value] = record.ItemPrefab;
dictionary2[record.NormalizedName] = record.ItemPrefab;
record.GameRegistryApplied = true;
_logger.LogInfo((object)$"[ItemAPI] Added {record.Key} to GameInfo, ItemId={value}.");
return true;
}
private static bool TryApplyNetworkRegistry(RegistrationRecord record, NetworkManager manager, out string error)
{
error = null;
ushort networkCollectionId = record.Handle.NetworkCollectionId;
PrefabObjects prefabObjects = manager.GetPrefabObjects<DefaultPrefabObjects>(networkCollectionId, false);
if ((Object)(object)prefabObjects != (Object)null && prefabObjects.GetObjectCount() > 0)
{
if ((Object)(object)prefabObjects.GetObject(true, 0) == (Object)(object)record.NetworkPrefab)
{
return true;
}
error = $"FishNet runtime collection {networkCollectionId} is already used by an external mod.";
return false;
}
if (InstanceFinder.IsClientStarted || InstanceFinder.IsServerStarted)
{
error = "The network session has already started, so network items cannot be appended safely. Call Register before connecting or hosting.";
return false;
}
PrefabObjects val = prefabObjects ?? manager.GetPrefabObjects<DefaultPrefabObjects>(networkCollectionId, true);
if ((Object)(object)val == (Object)null)
{
error = $"FishNet could not create runtime collection {networkCollectionId}.";
return false;
}
val.AddObject(record.NetworkPrefab, true, true);
if (val.GetObjectCount() != 1 || (Object)(object)val.GetObject(true, 0) != (Object)(object)record.NetworkPrefab)
{
error = $"FishNet runtime collection {networkCollectionId} is inconsistent after initialization.";
return false;
}
_logger.LogInfo((object)$"[ItemAPI] Added {record.Key} to FishNet collection={networkCollectionId}, PrefabId=0.");
return true;
}
internal static bool TryGet(byte itemId, out ItemRegistrationHandle handle)
{
lock (Sync)
{
if (ById.TryGetValue(itemId, out var value))
{
handle = value.Handle;
return true;
}
}
handle = null;
return false;
}
internal static bool TryGet(string key, out ItemRegistrationHandle handle)
{
lock (Sync)
{
if (key != null && ByKey.TryGetValue(key, out var value))
{
handle = value.Handle;
return true;
}
}
handle = null;
return false;
}
internal static bool TryGetIcon(byte itemId, out InventoryIcon icon)
{
lock (Sync)
{
if (ById.TryGetValue(itemId, out var value) && value.Icon != null && Object.op_Implicit((Object)(object)value.Icon.Texture))
{
icon = value.Icon;
return true;
}
}
icon = null;
return false;
}
internal static bool TryGetDisplayName(byte itemId, out string displayName)
{
lock (Sync)
{
if (ById.TryGetValue(itemId, out var value) && !string.IsNullOrWhiteSpace(value.DisplayName))
{
displayName = value.DisplayName;
return true;
}
}
displayName = null;
return false;
}
internal static IReadOnlyList<ItemRegistrationHandle> GetAllHandles()
{
lock (Sync)
{
List<ItemRegistrationHandle> list = new List<ItemRegistrationHandle>(ByKey.Count);
foreach (RegistrationRecord value in ByKey.Values)
{
list.Add(value.Handle);
}
list.Sort(delegate(ItemRegistrationHandle left, ItemRegistrationHandle right)
{
if (left.ItemId.HasValue && right.ItemId.HasValue)
{
return left.ItemId.Value.CompareTo(right.ItemId.Value);
}
if (left.ItemId.HasValue)
{
return -1;
}
return right.ItemId.HasValue ? 1 : string.Compare(left.Key, right.Key, StringComparison.Ordinal);
});
return list;
}
}
internal static string BuildKey(string modGuid, string internalName)
{
if (string.IsNullOrWhiteSpace(modGuid))
{
throw new ArgumentException("ModGuid cannot be empty.", "modGuid");
}
if (string.IsNullOrWhiteSpace(internalName))
{
throw new ArgumentException("InternalName cannot be empty.", "internalName");
}
return modGuid.Trim().ToLowerInvariant() + ":" + internalName.Trim().ToLowerInvariant();
}
private static string NormalizeName(string value)
{
return value.Replace(" ", string.Empty).Trim().ToLowerInvariant();
}
private static ushort DeriveCollectionId(string key)
{
uint num = 2166136261u;
byte[] bytes = Encoding.UTF8.GetBytes(key);
foreach (byte b in bytes)
{
num ^= b;
num *= 16777619;
}
return (ushort)(32768 + num % 32767);
}
private static ItemRegistrationHandle Rejected(string key, ushort collectionId, Item item, string message)
{
ManualLogSource logger = _logger;
if (logger != null)
{
logger.LogError((object)("[ItemAPI] Rejected registration " + key + ": " + message));
}
return new ItemRegistrationHandle(key, collectionId, item, ItemRegistrationState.Rejected, message);
}
private static ItemRegistrationHandle GetHandleByKey(string key)
{
lock (Sync)
{
return ByKey[key].Handle;
}
}
private static void Fail(RegistrationRecord record, string message)
{
SetState(record, ItemRegistrationState.Failed, message);
_logger.LogError((object)("[ItemAPI] Registration failed for " + record.Key + ": " + message));
}
private static void SetState(RegistrationRecord record, ItemRegistrationState state, string message)
{
if (record.Handle.State != state || !string.Equals(record.Handle.Message, message, StringComparison.Ordinal))
{
record.Handle.State = state;
record.Handle.Message = message;
ItemRegistry.RaiseRegistrationChanged(record.Handle);
}
}
private static string Describe(Item item)
{
if (!Object.op_Implicit((Object)(object)item))
{
return "<null>";
}
return "'" + ((Object)item).name + "'";
}
internal static void LogSubscriberException(Exception exception)
{
ManualLogSource logger = _logger;
if (logger != null)
{
logger.LogError((object)$"[ItemAPI] A RegistrationChanged subscriber threw an exception: {exception}");
}
}
}
}