Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Camels v1.0.0
plugins/CamelMod.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace CamelMod; internal static class CamelAsset { internal class BoneDef { public string Name; public int Parent; public Vector3 Pos; public Quaternion Rot; public string Path; } internal static BoneDef[] Bones; internal static Mesh Mesh; internal static Texture2D Texture; internal static readonly List<AnimationClip> Clips = new List<AnimationClip>(); internal static bool Loaded; private static readonly string[] Props = new string[7] { "localPosition.x", "localPosition.y", "localPosition.z", "localRotation.x", "localRotation.y", "localRotation.z", "localRotation.w" }; internal static void Load(string dir) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Expected O, but got Unknown //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Expected O, but got Unknown try { using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(Path.Combine(dir, "camel.bytes")))) { if (Encoding.ASCII.GetString(binaryReader.ReadBytes(4)) != "CAML") { throw new Exception("camel.bytes: bad header"); } binaryReader.ReadInt32(); int num = binaryReader.ReadInt32(); Bones = new BoneDef[num]; for (int i = 0; i < num; i++) { BoneDef boneDef = new BoneDef { Name = ReadStr(binaryReader), Parent = binaryReader.ReadInt32(), Pos = ReadV3(binaryReader), Rot = ReadQ(binaryReader) }; boneDef.Path = ((boneDef.Parent < 0) ? boneDef.Name : (Bones[boneDef.Parent].Path + "/" + boneDef.Name)); Bones[i] = boneDef; } int num2 = binaryReader.ReadInt32(); Vector3[] array = (Vector3[])(object)new Vector3[num2]; Vector3[] array2 = (Vector3[])(object)new Vector3[num2]; Vector2[] array3 = (Vector2[])(object)new Vector2[num2]; BoneWeight[] array4 = (BoneWeight[])(object)new BoneWeight[num2]; for (int j = 0; j < num2; j++) { array[j] = ReadV3(binaryReader); array2[j] = ReadV3(binaryReader); array3[j] = new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle()); BoneWeight val = default(BoneWeight); ((BoneWeight)(ref val)).boneIndex0 = binaryReader.ReadInt32(); ((BoneWeight)(ref val)).weight0 = binaryReader.ReadSingle(); ((BoneWeight)(ref val)).boneIndex1 = binaryReader.ReadInt32(); ((BoneWeight)(ref val)).weight1 = binaryReader.ReadSingle(); ((BoneWeight)(ref val)).boneIndex2 = binaryReader.ReadInt32(); ((BoneWeight)(ref val)).weight2 = binaryReader.ReadSingle(); ((BoneWeight)(ref val)).boneIndex3 = binaryReader.ReadInt32(); ((BoneWeight)(ref val)).weight3 = binaryReader.ReadSingle(); array4[j] = val; } int num3 = binaryReader.ReadInt32(); int[] array5 = new int[num3]; for (int k = 0; k < num3; k++) { array5[k] = binaryReader.ReadInt32(); } Mesh = new Mesh { name = "CamelMesh" }; Mesh.vertices = array; Mesh.normals = array2; Mesh.uv = array3; Mesh.boneWeights = array4; Mesh.triangles = array5; Matrix4x4[] array6 = (Matrix4x4[])(object)new Matrix4x4[num]; Matrix4x4[] array7 = (Matrix4x4[])(object)new Matrix4x4[num]; for (int l = 0; l < num; l++) { Matrix4x4 val2 = Matrix4x4.TRS(Bones[l].Pos, Bones[l].Rot, Vector3.one); array6[l] = ((Bones[l].Parent < 0) ? val2 : (array6[Bones[l].Parent] * val2)); array7[l] = ((Matrix4x4)(ref array6[l])).inverse; } Mesh.bindposes = array7; Mesh.RecalculateBounds(); int num4 = binaryReader.ReadInt32(); for (int m = 0; m < num4; m++) { string name = ReadStr(binaryReader); float fps = binaryReader.ReadSingle(); bool loop = binaryReader.ReadInt32() != 0; int num5 = binaryReader.ReadInt32(); float[,,] array8 = new float[num5, num, 7]; for (int n = 0; n < num5; n++) { for (int num6 = 0; num6 < num; num6++) { for (int num7 = 0; num7 < 7; num7++) { array8[n, num6, num7] = binaryReader.ReadSingle(); } } } Clips.Add(MakeClip(name, fps, loop, num5, num, array8)); } } Texture = new Texture2D(2, 2, (TextureFormat)4, true) { name = "camel" }; ImageConversion.LoadImage(Texture, File.ReadAllBytes(Path.Combine(dir, "camel.png"))); ((Texture)Texture).anisoLevel = 4; Loaded = true; CamelPlugin.Log.LogInfo((object)$"Camel asset: {Bones.Length} bones, {Mesh.vertexCount} verts, {Mesh.triangles.Length / 3} tris, {Clips.Count} clips, texture {((Texture)Texture).width}x{((Texture)Texture).height}"); } catch (Exception ex) { CamelPlugin.Log.LogError((object)("Camel asset load failed: " + ex)); } } private static AnimationClip MakeClip(string name, float fps, bool loop, int frames, int nb, float[,,] data) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) AnimationClip val = new AnimationClip { name = name, legacy = true, frameRate = fps }; val.wrapMode = (WrapMode)(loop ? 2 : 8); for (int i = 0; i < nb; i++) { for (int j = 0; j < 7; j++) { Keyframe[] array = (Keyframe[])(object)new Keyframe[frames]; for (int k = 0; k < frames; k++) { int num = k - 1; int num2 = k + 1; if (loop) { if (num < 0) { num = frames - 2; } if (num2 > frames - 1) { num2 = 1; } } else { if (num < 0) { num = 0; } if (num2 > frames - 1) { num2 = frames - 1; } } int num3 = num2 - num; if (num3 <= 0) { num3 += frames - 1; } float num4 = (data[num2, i, j] - data[num, i, j]) * fps / (float)num3; array[k] = new Keyframe((float)k / fps, data[k, i, j], num4, num4); } val.SetCurve(Bones[i].Path, typeof(Transform), Props[j], new AnimationCurve(array)); } } val.EnsureQuaternionContinuity(); return val; } internal static GameObject Build(Material mat, Transform parent, out SkinnedMeshRenderer smr, out Animation anim) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("CamelModel"); val.transform.SetParent(parent, false); Transform[] array = (Transform[])(object)new Transform[Bones.Length]; for (int i = 0; i < Bones.Length; i++) { BoneDef boneDef = Bones[i]; Transform transform = new GameObject(boneDef.Name).transform; transform.SetParent((boneDef.Parent < 0) ? val.transform : array[boneDef.Parent], false); transform.localPosition = boneDef.Pos; transform.localRotation = boneDef.Rot; array[i] = transform; } GameObject val2 = new GameObject("CamelMesh"); val2.transform.SetParent(val.transform, false); smr = val2.AddComponent<SkinnedMeshRenderer>(); smr.sharedMesh = Mesh; smr.bones = array; smr.rootBone = val.transform; ((Renderer)smr).sharedMaterial = mat; smr.quality = (SkinQuality)4; smr.updateWhenOffscreen = false; ((Renderer)smr).localBounds = new Bounds(new Vector3(0f, 1.4f, 0f), new Vector3(6f, 3.6f, 6f)); anim = val.AddComponent<Animation>(); anim.playAutomatically = false; anim.cullingType = (AnimationCullingType)1; foreach (AnimationClip clip in Clips) { anim.AddClip(clip, ((Object)clip).name); } anim.clip = ((Clips.Count > 0) ? Clips[0] : null); return val; } internal static Transform FindDeep(Transform t, string name) { if (((Object)t).name == name) { return t; } for (int i = 0; i < t.childCount; i++) { Transform val = FindDeep(t.GetChild(i), name); if ((Object)(object)val != (Object)null) { return val; } } return null; } private static string ReadStr(BinaryReader br) { return Encoding.UTF8.GetString(br.ReadBytes(br.ReadInt32())); } private static Vector3 ReadV3(BinaryReader br) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); } private static Quaternion ReadQ(BinaryReader br) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) return new Quaternion(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle()); } } public class CamelBrain : MonoBehaviour { private const float WalkClipSpeed = 1.21f; private const float RunClipSpeed = 5.55f; private static readonly int s_eatingHash = StringExtensionMethods.GetStableHashCode("camel_eating"); private Character m_character; private BaseAI m_ai; private ZNetView m_nview; private Animation m_anim; private string m_current = ""; private Vector3 m_lastPos; private float m_speed; private bool m_moving; private bool m_eating; private float m_stillTime; private float m_nextDecision; private float m_eatUntil; public bool WantsToStayPut { get { if (m_eating && (Object)(object)m_ai != (Object)null) { return !m_ai.IsAlerted(); } return false; } } private void Awake() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) m_character = ((Component)this).GetComponent<Character>(); m_ai = ((Component)this).GetComponent<BaseAI>(); m_nview = ((Component)this).GetComponent<ZNetView>(); m_anim = ((Component)this).GetComponentInChildren<Animation>(); m_lastPos = ((Component)this).transform.position; m_nextDecision = Time.time + Random.Range(2f, 5f); } private void Start() { if (!((Object)(object)m_anim == (Object)null)) { m_anim.Play("idle"); AnimationState val = m_anim["idle"]; if ((TrackedReference)(object)val != (TrackedReference)null) { val.time = Random.Range(0f, val.length); } m_current = "idle"; } } private void Update() { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0060: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_anim == (Object)null || (Object)(object)m_character == (Object)null || m_character.IsDead()) { return; } float deltaTime = Time.deltaTime; if (deltaTime <= 0f) { return; } Vector3 position = ((Component)this).transform.position; Vector3 val = position - m_lastPos; val.y = 0f; m_lastPos = position; float num = ((Vector3)(ref val)).magnitude / deltaTime; if (num > 30f) { num = 0f; } m_speed = Mathf.Lerp(m_speed, num, 1f - Mathf.Exp((0f - deltaTime) * 8f)); if (m_moving) { if (m_speed < 0.15f) { m_moving = false; } } else if (m_speed > 0.3f) { m_moving = true; } bool flag = (Object)(object)m_nview != (Object)null && m_nview.IsValid(); if (flag && m_nview.IsOwner()) { bool flag2 = (Object)(object)m_ai != (Object)null && m_ai.IsAlerted(); if (m_moving || flag2) { m_stillTime = 0f; if (m_eating) { m_eating = false; m_nextDecision = Time.time + Random.Range(4f, 8f); } } else { m_stillTime += deltaTime; } if (!m_eating && m_stillTime > 1f && Time.time > m_nextDecision) { m_nextDecision = Time.time + Random.Range(3f, 6f); if (Random.value < 0.65f) { m_eating = true; m_eatUntil = Time.time + Random.Range(7f, 16f); } } if (m_eating && Time.time > m_eatUntil) { m_eating = false; m_nextDecision = Time.time + Random.Range(4f, 9f); } ZDO zDO = m_nview.GetZDO(); if (zDO.GetBool(s_eatingHash, false) != m_eating) { zDO.Set(s_eatingHash, m_eating); } } else if (flag) { m_eating = m_nview.GetZDO().GetBool(s_eatingHash, false); } float speed = 1f; string text; if (m_moving && m_speed > 3f) { text = "run"; speed = Mathf.Clamp(m_speed / 5.55f, 0.7f, 1.6f); } else if (m_moving) { text = "walk"; speed = Mathf.Clamp(m_speed / 1.21f, 0.6f, 2.2f); } else { text = (m_eating ? "eat" : "idle"); } if (text != m_current) { float num2 = ((text == "eat" || m_current == "eat") ? 0.9f : ((text == "run" || m_current == "run") ? 0.25f : 0.35f)); m_anim.CrossFade(text, num2); m_current = text; } AnimationState val2 = m_anim[text]; if ((TrackedReference)(object)val2 != (TrackedReference)null) { val2.speed = speed; } } } public class CamelDeath : MonoBehaviour { private void Start() { Animation componentInChildren = ((Component)this).GetComponentInChildren<Animation>(); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.Play("die"); } } } internal static class CamelDebug { internal static void Dump(GameObject go) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)go == (Object)null) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("=== PREFAB " + ((Object)go).name); Walk(go.transform, 0, stringBuilder); Character component = go.GetComponent<Character>(); if ((Object)(object)component != (Object)null) { stringBuilder.AppendFormat("Character: hp={0} speed={1} walk={2} run={3} turn={4} runTurn={5} tilt={6} faction={7} group={8} eye={9}\n", component.m_health, component.m_speed, component.m_walkSpeed, component.m_runSpeed, component.m_turnSpeed, component.m_runTurnSpeed, component.m_groundTilt, component.m_faction, component.m_group, ((Object)(object)component.m_eye != (Object)null) ? ((Object)component.m_eye).name : "null"); } if ((Object)(object)component != (Object)null && component.m_deathEffects != null) { EffectData[] effectPrefabs = component.m_deathEffects.m_effectPrefabs; foreach (EffectData val in effectPrefabs) { stringBuilder.AppendLine(" deathEffect " + (((Object)(object)val.m_prefab != (Object)null) ? ((Object)val.m_prefab).name : "null")); } } BaseAI component2 = go.GetComponent<BaseAI>(); if ((Object)(object)component2 != (Object)null) { stringBuilder.AppendFormat("AI {0}: view={1} hear={2} agent={3} moveInterval={4} moveRange={5} fleeRange={6} idleSoundInterval={7}\n", ((object)component2).GetType().Name, component2.m_viewRange, component2.m_hearRange, component2.m_pathAgentType, component2.m_randomMoveInterval, component2.m_randomMoveRange, component2.m_fleeRange, component2.m_idleSoundInterval); } CapsuleCollider component3 = go.GetComponent<CapsuleCollider>(); if ((Object)(object)component3 != (Object)null) { stringBuilder.AppendFormat("Capsule r={0} h={1} c={2} dir={3}\n", component3.radius, component3.height, component3.center, component3.direction); } Rigidbody component4 = go.GetComponent<Rigidbody>(); if ((Object)(object)component4 != (Object)null) { stringBuilder.AppendFormat("Rigidbody mass={0} kinematic={1}\n", component4.mass, component4.isKinematic); } Ragdoll component5 = go.GetComponent<Ragdoll>(); if ((Object)(object)component5 != (Object)null) { stringBuilder.AppendFormat("Ragdoll ttl={0} drop={1} float={2} mainModel={3} lootJoint={4}\n", component5.m_ttl, component5.m_dropItems, component5.m_float, ((Object)(object)component5.m_mainModel != (Object)null) ? ((Object)component5.m_mainModel).name : "null", ((Object)(object)component5.m_lootSpawnJoint != (Object)null) ? ((Object)component5.m_lootSpawnJoint).name : "null"); } Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>(true); foreach (Renderer val2 in componentsInChildren) { Material sharedMaterial = val2.sharedMaterial; stringBuilder.Append("Renderer ").Append(((Object)val2).name).Append(" shader=") .Append(((Object)(object)sharedMaterial != (Object)null) ? ((Object)sharedMaterial.shader).name : "null"); if ((Object)(object)sharedMaterial != (Object)null) { stringBuilder.Append(" props:"); int propertyCount = sharedMaterial.shader.GetPropertyCount(); for (int j = 0; j < propertyCount; j++) { stringBuilder.Append(' ').Append(sharedMaterial.shader.GetPropertyName(j)); } } stringBuilder.AppendLine(); } CamelPlugin.Log.LogInfo((object)stringBuilder.ToString()); } private static void Walk(Transform t, int depth, StringBuilder sb) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) sb.Append(' ', depth * 2).Append(((Object)t).name).Append(" ["); Component[] components = ((Component)t).GetComponents<Component>(); foreach (Component val in components) { if ((Object)(object)val != (Object)null && !(val is Transform)) { sb.Append(((object)val).GetType().Name).Append(' '); } } sb.Append("] pos=").Append(t.localPosition).Append(" rot=") .Append(t.localEulerAngles) .Append(" scale=") .Append(t.localScale) .AppendLine(); if (depth < 3) { for (int j = 0; j < t.childCount; j++) { Walk(t.GetChild(j), depth + 1, sb); } } } } [BepInPlugin("rombi.camelmod", "Camel", "1.0.0")] public class CamelPlugin : BaseUnityPlugin { public const string Guid = "rombi.camelmod"; public const string Version = "1.0.0"; internal static ManualLogSource Log; internal static string Dir; internal static ConfigEntry<float> Health; internal static ConfigEntry<bool> SpawnEnabled; internal static ConfigEntry<bool> DebugDump; internal static ConfigEntry<bool> EnableConsole; private void Awake() { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Dir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); Health = ((BaseUnityPlugin)this).Config.Bind<float>("Camel", "Health", 300f, "Max health of a camel (deer 10, lox 1000)."); SpawnEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "Enabled", true, "Camels spawn on their own in the Plains, like lox."); DebugDump = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DumpPrefabs", false, "Write details of the deer / lox prefabs to the BepInEx log once per game start."); EnableConsole = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableConsole", false, "Turn on the F5 console (same as the -console launch option), e.g. for 'spawn Camel'."); CamelAsset.Load(Dir); CamelSounds.Load(Dir); new Harmony("rombi.camelmod").PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)("Camel mod 1.0.0 loaded from " + Dir)); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class Patch_ZNetScene_Awake { private static void Postfix(ZNetScene __instance) { CamelPrefabs.Register(__instance); } } [HarmonyPatch(typeof(SpawnSystem), "Awake")] internal static class Patch_SpawnSystem_Awake { private static void Postfix(SpawnSystem __instance) { CamelPrefabs.AddSpawns(__instance); } } [HarmonyPatch(typeof(Localization), "SetupLanguage")] internal static class Patch_Localization_SetupLanguage { private static void Postfix(Localization __instance, string language) { CamelPrefabs.AddWords(__instance, language); } } [HarmonyPatch(typeof(Console), "Awake")] internal static class Patch_Console_Awake { private static void Postfix() { if (CamelPlugin.EnableConsole.Value) { Console.SetConsoleEnabled(true); } } } [HarmonyPatch(typeof(BaseAI), "IdleMovement")] internal static class Patch_BaseAI_IdleMovement { private static bool Prefix(BaseAI __instance) { CamelBrain component = ((Component)__instance).GetComponent<CamelBrain>(); if ((Object)(object)component != (Object)null && component.WantsToStayPut) { __instance.StopMoving(); return false; } return true; } } internal static class CamelPrefabs { internal static GameObject Camel; internal static GameObject CamelRagdoll; private const float ModelOffsetZ = 0.45f; private static GameObject s_holder; private static SpawnSystemList s_spawnList; private static bool s_spawnLogged; private static readonly MethodInfo s_addWord = AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null); private static readonly MethodInfo s_memberwiseClone = AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null); internal static void Register(ZNetScene zs) { if (!CamelAsset.Loaded) { return; } try { if ((Object)(object)Camel == (Object)null) { Create(zs); } if ((Object)(object)Camel == (Object)null) { return; } if ((Object)(object)CamelRagdoll != (Object)null) { AddPrefab(zs, CamelRagdoll); } foreach (GameObject prefab in CamelSounds.Prefabs) { if ((Object)(object)prefab.GetComponent<ZNetView>() != (Object)null) { AddPrefab(zs, prefab); } } AddPrefab(zs, Camel); if (Localization.instance != null) { AddWords(Localization.instance, Localization.instance.GetSelectedLanguage()); } CamelPlugin.Log.LogInfo((object)"Camel prefab registered (spawn with: spawn Camel)"); } catch (Exception ex) { CamelPlugin.Log.LogError((object)("Camel registration failed: " + ex)); } } private static void AddPrefab(ZNetScene zs, GameObject go) { if (!zs.m_prefabs.Contains(go)) { zs.m_prefabs.Add(go); } Traverse.Create((object)zs).Field("m_namedPrefabs").GetValue<Dictionary<int, GameObject>>()[StringExtensionMethods.GetStableHashCode(((Object)go).name)] = go; } private static void Create(ZNetScene zs) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Expected O, but got Unknown //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = zs.GetPrefab("Deer"); GameObject prefab2 = zs.GetPrefab("Lox"); if ((Object)(object)prefab == (Object)null) { CamelPlugin.Log.LogError((object)"Deer prefab not found, camel not created"); return; } Character component = prefab.GetComponent<Character>(); GameObject val = null; EffectData[] effectPrefabs = component.m_deathEffects.m_effectPrefabs; foreach (EffectData val2 in effectPrefabs) { if ((Object)(object)val2.m_prefab != (Object)null && (Object)(object)val2.m_prefab.GetComponent<Ragdoll>() != (Object)null) { val = val2.m_prefab; } } if (CamelPlugin.DebugDump.Value) { CamelDebug.Dump(prefab); CamelDebug.Dump(val); CamelDebug.Dump(prefab2); CamelDebug.Dump(zs.GetPrefab("Goblin")); } s_holder = new GameObject("CamelMod_Prefabs"); s_holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)s_holder); Material val3 = new Material(((Renderer)prefab.GetComponentInChildren<SkinnedMeshRenderer>(true)).sharedMaterial) { name = "CamelMat" }; if (val3.HasProperty("_MainTex")) { val3.SetTexture("_MainTex", (Texture)(object)CamelAsset.Texture); } if (val3.HasProperty("_BumpMap")) { val3.SetTexture("_BumpMap", (Texture)null); } val3.DisableKeyword("_NORMALMAP"); if (val3.HasProperty("_Color")) { val3.SetColor("_Color", Color.white); } CamelPlugin.Log.LogInfo((object)("Camel material based on shader " + ((Object)val3.shader).name)); if ((Object)(object)val != (Object)null) { CamelRagdoll = MakeRagdoll(val, val3); } else { CamelPlugin.Log.LogWarning((object)"Deer ragdoll not found: camel will vanish on death without animation"); } Camel = MakeCamel(prefab, prefab2, val3, zs); } private static GameObject MakeCamel(GameObject deer, GameObject lox, Material mat, ZNetScene zs) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Expected O, but got Unknown //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_037e: Expected O, but got Unknown GameObject val = Object.Instantiate<GameObject>(deer, s_holder.transform, false); ((Object)val).name = "Camel"; Character component = val.GetComponent<Character>(); component.m_name = "$enemy_camel"; component.m_group = "camel"; component.m_health = CamelPlugin.Health.Value; component.m_walkSpeed = 1.2f; component.m_speed = 1.5f; component.m_runSpeed = 6.5f; component.m_turnSpeed = Mathf.Min(component.m_turnSpeed, 120f); component.m_runTurnSpeed = Mathf.Min(component.m_runTurnSpeed, 240f); Character val2 = (((Object)(object)lox != (Object)null) ? lox.GetComponent<Character>() : null); component.m_faction = (Faction)((!((Object)(object)val2 != (Object)null)) ? 7 : ((int)val2.m_faction)); Transform val3 = val.transform.Find("Visual"); if ((Object)(object)val3 == (Object)null) { val3 = val.transform; } Renderer[] componentsInChildren = ((Component)val3).GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } LevelEffects[] componentsInChildren2 = val.GetComponentsInChildren<LevelEffects>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } Animator[] componentsInChildren3 = val.GetComponentsInChildren<Animator>(true); for (int i = 0; i < componentsInChildren3.Length; i++) { componentsInChildren3[i].cullingMode = (AnimatorCullingMode)2; } SkinnedMeshRenderer smr; Animation anim; GameObject val4 = CamelAsset.Build(mat, val3, out smr, out anim); PlaceModel(val4.transform, val.transform); LODGroup component2 = ((Component)val3).GetComponent<LODGroup>(); if ((Object)(object)component2 != (Object)null) { component2.SetLODs((LOD[])(object)new LOD[1] { new LOD(0.02f, (Renderer[])(object)new Renderer[1] { (Renderer)smr }) }); component2.RecalculateBounds(); } Transform val5 = CamelAsset.FindDeep(val4.transform, "Head"); if ((Object)(object)val5 != (Object)null) { component.m_eye = val5; } CapsuleCollider component3 = val.GetComponent<CapsuleCollider>(); if ((Object)(object)component3 != (Object)null) { component3.direction = 1; component3.radius = 0.8f; component3.height = 2.5f; component3.center = new Vector3(0f, 1.25f, 0f); } Rigidbody component4 = val.GetComponent<Rigidbody>(); Rigidbody val6 = (((Object)(object)lox != (Object)null) ? lox.GetComponent<Rigidbody>() : null); if ((Object)(object)component4 != (Object)null && (Object)(object)val6 != (Object)null) { component4.mass = val6.mass * 0.6f; } BaseAI component5 = val.GetComponent<BaseAI>(); BaseAI val7 = (((Object)(object)lox != (Object)null) ? lox.GetComponent<BaseAI>() : null); if ((Object)(object)component5 != (Object)null) { if ((Object)(object)val7 != (Object)null) { component5.m_pathAgentType = val7.m_pathAgentType; } component5.m_randomMoveInterval = Mathf.Max(component5.m_randomMoveInterval, 8f); component5.m_randomMoveRange = Mathf.Max(component5.m_randomMoveRange, 14f); } CharacterDrop component6 = val.GetComponent<CharacterDrop>(); if ((Object)(object)component6 != (Object)null) { component6.m_drops = new List<Drop>(); AddDrop(component6, zs, "LoxMeat", 1, 2); AddDrop(component6, zs, "LoxPelt", 1, 1); } if ((Object)(object)CamelRagdoll != (Object)null) { List<EffectData> list = new List<EffectData>(); EffectData[] effectPrefabs = component.m_deathEffects.m_effectPrefabs; foreach (EffectData val8 in effectPrefabs) { if ((Object)(object)val8.m_prefab != (Object)null && (Object)(object)val8.m_prefab.GetComponent<Ragdoll>() != (Object)null) { EffectData val9 = (EffectData)s_memberwiseClone.Invoke(val8, null); val9.m_prefab = CamelRagdoll; list.Add(val9); } else { list.Add(val8); } } component.m_deathEffects = new EffectList { m_effectPrefabs = list.ToArray() }; } CamelSounds.Apply(val, s_holder.transform); val.AddComponent<CamelBrain>(); return val; } private static GameObject MakeRagdoll(GameObject src, Material mat) { //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(src, s_holder.transform, false); ((Object)val).name = "Camel_ragdoll"; for (int num = val.transform.childCount - 1; num >= 0; num--) { Object.DestroyImmediate((Object)(object)((Component)val.transform.GetChild(num)).gameObject); } Joint[] components = val.GetComponents<Joint>(); for (int i = 0; i < components.Length; i++) { Object.DestroyImmediate((Object)(object)components[i]); } Collider[] components2 = val.GetComponents<Collider>(); for (int i = 0; i < components2.Length; i++) { Object.DestroyImmediate((Object)(object)components2[i]); } Rigidbody component = val.GetComponent<Rigidbody>(); if ((Object)(object)component != (Object)null) { component.isKinematic = true; component.useGravity = false; } Ragdoll component2 = val.GetComponent<Ragdoll>(); component2.m_mainModel = null; component2.m_float = false; component2.m_ttl = Mathf.Max(component2.m_ttl, 8f); SkinnedMeshRenderer smr; Animation anim; GameObject val2 = CamelAsset.Build(mat, val.transform, out smr, out anim); PlaceModel(val2.transform, val.transform); LODGroup component3 = val.GetComponent<LODGroup>(); if ((Object)(object)component3 != (Object)null) { component3.SetLODs((LOD[])(object)new LOD[1] { new LOD(0.02f, (Renderer[])(object)new Renderer[1] { (Renderer)smr }) }); component3.RecalculateBounds(); } Transform val3 = CamelAsset.FindDeep(val2.transform, "Spine"); if ((Object)(object)val3 != (Object)null) { component2.m_lootSpawnJoint = ((Component)val3).gameObject; } val.AddComponent<CamelDeath>(); return val; } private static void PlaceModel(Transform model, Transform owner) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) Vector3 lossyScale = model.parent.lossyScale; model.localScale = new Vector3(1f / lossyScale.x, 1f / lossyScale.y, 1f / lossyScale.z); model.SetPositionAndRotation(owner.TransformPoint(0f, 0f, 0.45f / Mathf.Max(0.0001f, owner.lossyScale.z)), owner.rotation); } private static void AddDrop(CharacterDrop cd, ZNetScene zs, string item, int min, int max) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown GameObject prefab = zs.GetPrefab(item); if ((Object)(object)prefab == (Object)null) { CamelPlugin.Log.LogWarning((object)("Drop item not found: " + item)); return; } cd.m_drops.Add(new Drop { m_prefab = prefab, m_amountMin = min, m_amountMax = max, m_chance = 1f, m_onePerPlayer = false, m_levelMultiplier = true }); } internal static void AddSpawns(SpawnSystem ss) { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Expected O, but got Unknown //IL_014c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Camel == (Object)null || !CamelPlugin.SpawnEnabled.Value) { return; } try { if ((Object)(object)s_spawnList == (Object)null) { SpawnData val = null; foreach (SpawnSystemList spawnList in ss.m_spawnLists) { foreach (SpawnData spawner in spawnList.m_spawners) { if (val == null && spawner.m_enabled && (Object)(object)spawner.m_prefab != (Object)null && ((Object)spawner.m_prefab).name == "Lox") { val = spawner; } } } if (val == null) { if (!s_spawnLogged) { CamelPlugin.Log.LogWarning((object)"No Lox spawn entry found yet"); } s_spawnLogged = true; return; } SpawnData val2 = val.Clone(); val2.m_name = "Camel"; val2.m_prefab = Camel; val2.m_enabled = true; GameObject val3 = new GameObject("CamelMod_SpawnList"); Object.DontDestroyOnLoad((Object)val3); s_spawnList = val3.AddComponent<SpawnSystemList>(); s_spawnList.m_spawners = new List<SpawnData> { val2 }; CamelPlugin.Log.LogInfo((object)$"Camel spawns copied from Lox: biome={val2.m_biome} max={val2.m_maxSpawned} interval={val2.m_spawnInterval} chance={val2.m_spawnChance} group={val2.m_groupSizeMin}-{val2.m_groupSizeMax} day={val2.m_spawnAtDay} night={val2.m_spawnAtNight} levels={val2.m_minLevel}-{val2.m_maxLevel}"); } if (!ss.m_spawnLists.Contains(s_spawnList)) { ss.m_spawnLists.Add(s_spawnList); } } catch (Exception ex) { CamelPlugin.Log.LogError((object)("Camel spawn setup failed: " + ex)); } } internal static void AddWords(Localization loc, string language) { if (loc != null && !(s_addWord == null)) { bool flag = language == "Russian"; Word(loc, "enemy_camel", flag ? "Верблюд" : "Camel"); Word(loc, "caption_camel_idle", flag ? "Верблюд ворчит" : "Camel grumbles"); Word(loc, "caption_camel_alert", flag ? "Верблюд тревожно стонет" : "Camel groans in alarm"); Word(loc, "caption_camel_hit", flag ? "Верблюд вскрикивает" : "Camel cries out"); Word(loc, "caption_camel_death", flag ? "Верблюд ревёт" : "Camel roars"); } } private static void Word(Localization loc, string key, string text) { s_addWord.Invoke(loc, new object[2] { key, text }); } } internal static class CamelSounds { private static readonly Dictionary<string, List<AudioClip>> s_clips = new Dictionary<string, List<AudioClip>>(); internal static readonly List<GameObject> Prefabs = new List<GameObject>(); private static readonly MethodInfo s_memberwiseClone = AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null); internal static void Load(string dir) { string path = Path.Combine(dir, "sounds"); if (!Directory.Exists(path)) { CamelPlugin.Log.LogWarning((object)"No sounds folder, camels keep deer sounds"); return; } string[] files = Directory.GetFiles(path, "*.wav"); foreach (string text in files) { try { AudioClip clip = LoadWav(text); string? fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); Add(fileNameWithoutExtension.Split('_')[0], clip); if (fileNameWithoutExtension.StartsWith("idle_grunt")) { Add("hit", clip); } } catch (Exception ex) { CamelPlugin.Log.LogWarning((object)("Sound " + text + " skipped: " + ex.Message)); } } StringBuilder stringBuilder = new StringBuilder("Camel sounds:"); foreach (KeyValuePair<string, List<AudioClip>> s_clip in s_clips) { stringBuilder.Append(' ').Append(s_clip.Key).Append('=') .Append(s_clip.Value.Count); } CamelPlugin.Log.LogInfo((object)stringBuilder.ToString()); } private static void Add(string role, AudioClip clip) { if (!s_clips.TryGetValue(role, out var value)) { value = (s_clips[role] = new List<AudioClip>()); } value.Add(clip); } private static AudioClip LoadWav(string path) { byte[] array = File.ReadAllBytes(path); if (Encoding.ASCII.GetString(array, 0, 4) != "RIFF" || Encoding.ASCII.GetString(array, 8, 4) != "WAVE") { throw new Exception("not a WAV file"); } int i = 12; int num = 1; int num2 = 44100; int num3 = 16; int num4 = -1; int num5 = 0; int num6; for (; i + 8 <= array.Length; i += 8 + num6 + (num6 & 1)) { string text = Encoding.ASCII.GetString(array, i, 4); num6 = BitConverter.ToInt32(array, i + 4); if (text == "fmt ") { num = BitConverter.ToInt16(array, i + 10); num2 = BitConverter.ToInt32(array, i + 12); num3 = BitConverter.ToInt16(array, i + 22); } else if (text == "data") { num4 = i + 8; num5 = Math.Min(num6, array.Length - num4); break; } } if (num3 != 16 || num4 < 0) { throw new Exception("only 16-bit PCM WAV is supported"); } int num7 = num5 / 2; float[] array2 = new float[num7]; for (int j = 0; j < num7; j++) { array2[j] = (float)BitConverter.ToInt16(array, num4 + j * 2) / 32768f; } AudioClip obj = AudioClip.Create(Path.GetFileNameWithoutExtension(path), num7 / num, num, num2, false); obj.SetData(array2, 0); return obj; } internal static void Apply(GameObject camel, Transform holder) { if (s_clips.Count == 0) { return; } Character component = camel.GetComponent<Character>(); BaseAI component2 = camel.GetComponent<BaseAI>(); GameObject val = null; EffectList[] array = (EffectList[])(object)new EffectList[4] { ((Object)(object)component2 != (Object)null) ? component2.m_idleSound : null, ((Object)(object)component2 != (Object)null) ? component2.m_alertedEffects : null, ((Object)(object)component != (Object)null) ? component.m_hitEffects : null, ((Object)(object)component != (Object)null) ? component.m_deathEffects : null }; foreach (EffectList list in array) { if ((Object)(object)val == (Object)null) { val = FindSfx(list); } } if ((Object)(object)val == (Object)null) { CamelPlugin.Log.LogWarning((object)"No deer sound prefab found to copy, camels keep deer sounds"); return; } if ((Object)(object)component2 != (Object)null) { component2.m_idleSound = Swap(component2.m_idleSound, "idle", val, holder, 0.9f, 1.08f); component2.m_alertedEffects = Swap(component2.m_alertedEffects, "alert", val, holder, 0.95f, 1.05f); } if ((Object)(object)component != (Object)null) { component.m_hitEffects = Swap(component.m_hitEffects, "hit", val, holder, 1.08f, 1.22f); component.m_critHitEffects = Swap(component.m_critHitEffects, "hit", val, holder, 1.08f, 1.22f); component.m_deathEffects = Swap(component.m_deathEffects, "death", val, holder, 0.96f, 1f); } } private static GameObject FindSfx(EffectList list) { if (list == null || list.m_effectPrefabs == null) { return null; } EffectData[] effectPrefabs = list.m_effectPrefabs; foreach (EffectData val in effectPrefabs) { if (val != null && (Object)(object)val.m_prefab != (Object)null && (Object)(object)val.m_prefab.GetComponent<ZSFX>() != (Object)null) { return val.m_prefab; } } return null; } private static EffectList Swap(EffectList list, string role, GameObject fallback, Transform holder, float minPitch, float maxPitch) { //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Expected O, but got Unknown if (!s_clips.TryGetValue(role, out var value) || value.Count == 0) { return list; } Array obj = ((list != null && list.m_effectPrefabs != null) ? ((Array)list.m_effectPrefabs) : ((Array)new EffectData[0])); GameObject val = FindSfx(list); GameObject prefab = MakeSfx(((Object)(object)val != (Object)null) ? val : fallback, "sfx_camel_" + role, value.ToArray(), minPitch, maxPitch, holder); List<EffectData> list2 = new List<EffectData>(); bool flag = false; EffectData[] array = (EffectData[])obj; foreach (EffectData val2 in array) { if (val2 != null && (Object)(object)val2.m_prefab != (Object)null && (Object)(object)val2.m_prefab.GetComponent<ZSFX>() != (Object)null) { if (!flag) { EffectData val3 = (EffectData)s_memberwiseClone.Invoke(val2, null); val3.m_prefab = prefab; list2.Add(val3); flag = true; } } else { list2.Add(val2); } } if (!flag) { list2.Add(new EffectData { m_prefab = prefab, m_enabled = true }); } CamelPlugin.Log.LogInfo((object)string.Format("Camel sound {0}: {1} clips (copied from {2})", role, value.Count, ((Object)(object)val != (Object)null) ? ((Object)val).name : (((Object)fallback).name + " [fallback]"))); return new EffectList { m_effectPrefabs = list2.ToArray() }; } private static GameObject MakeSfx(GameObject template, string name, AudioClip[] clips, float minPitch, float maxPitch, Transform holder) { foreach (GameObject prefab in Prefabs) { if (((Object)prefab).name == name) { return prefab; } } GameObject val = Object.Instantiate<GameObject>(template, holder, false); ((Object)val).name = name; ZSFX component = val.GetComponent<ZSFX>(); component.m_audioClips = clips; component.m_minPitch = minPitch; component.m_maxPitch = maxPitch; component.m_closedCaptionToken = "$caption_" + name.Substring(4); component.m_secondaryCaptionToken = ""; component.m_hash = StringExtensionMethods.GetStableHashCode(name); AudioSource component2 = val.GetComponent<AudioSource>(); if ((Object)(object)component2 != (Object)null && component2.maxDistance < 35f) { component2.maxDistance = 35f; } Prefabs.Add(val); return val; } }