public static void Postfix(SubFire __instance, SubFire.RoomFire startInRoom, bool __state) { // Spent way too much time trying to get around a bug in dnspy that doesn't allow me to propery edit this method, so I'm going with the hacky solution. // Every time a Fire is created, the whole list of SubFire.availableNodes is cleared, then populated with any transforms that have 0 childCount. // Next, it chooses a random index, then spawns a fire in that node. // We can easily find where it is because it'll be the only Transform in SubFire.availableNodes with a childCount > 0 if (__state) { List <Transform> availableNodes = (List <Transform>)__instance.ReflectionGet("availableNodes"); Dictionary <CyclopsRooms, SubFire.RoomFire> roomFiresDict = (Dictionary <CyclopsRooms, SubFire.RoomFire>)__instance.ReflectionGet("roomFires"); foreach (Transform transform in availableNodes) { if (transform.childCount > 0) { int nodeIndex = Array.IndexOf(roomFiresDict[startInRoom.roomLinks.room].spawnNodes, transform); Fire fire = transform.GetComponentInChildren <Fire>(); NitroxServiceLocator.LocateService <Fires>().OnCreate(transform.GetComponentInChildren <Fire>(), startInRoom, nodeIndex); return; } } } }
/// <summary> /// Create a new <see cref="Fire"/>. Majority of code copied from <see cref="SubFire.CreateFire(SubFire.RoomFire)"/>. Currently does not support Fires created outside of a Cyclops /// </summary> /// <param name="fireGuid">Guid of the Fire. Used for identification when dousing the fire</param> /// <param name="subRootGuid">Guid of the Cyclops <see cref="SubRoot"/></param> /// <param name="room">The room the Fire will be spawned in</param> /// <param name="spawnNodeIndex">Each <see cref="CyclopsRooms"/> has multiple static Fire spawn points called spawnNodes. If the wrong index is provided, /// the clients will see fires in different places from the owner</param> public void Create(CyclopsFireData fireData) { SubFire subFire = GuidHelper.RequireObjectFrom(fireData.CyclopsGuid).GetComponent <SubRoot>().damageManager.subFire; Dictionary <CyclopsRooms, SubFire.RoomFire> roomFiresDict = (Dictionary <CyclopsRooms, SubFire.RoomFire>)subFire.ReflectionGet("roomFires"); // Copied from SubFire_CreateFire_Patch, which copies from SubFire.CreateFire() Transform transform2 = roomFiresDict[fireData.Room].spawnNodes[fireData.NodeIndex]; // If a fire already exists at the node, replace the old Guid with the new one if (transform2.childCount > 0) { Fire existingFire = transform2.GetComponentInChildren <Fire>(); if (GuidHelper.GetGuid(existingFire.gameObject) != fireData.CyclopsGuid) { Log.Error("[Fires.Create Fire already exists at node index " + fireData.NodeIndex + "! Replacing existing Fire Guid " + GuidHelper.GetGuid(existingFire.gameObject) + " with Guid " + fireData.CyclopsGuid + "]"); GuidHelper.SetNewGuid(existingFire.gameObject, fireData.CyclopsGuid); } return; } List <Transform> availableNodes = (List <Transform>)subFire.ReflectionGet("availableNodes"); availableNodes.Clear(); foreach (Transform transform in roomFiresDict[fireData.Room].spawnNodes) { if (transform.childCount == 0) { availableNodes.Add(transform); } } roomFiresDict[fireData.Room].fireValue++; PrefabSpawn component = transform2.GetComponent <PrefabSpawn>(); if (component == null) { return; } else { Log.Error("[FireCreatedProcessor Cannot create new Cyclops fire! PrefabSpawn component could not be found in fire node!" + " Fire Guid: " + fireData.FireGuid + " SubRoot Guid: " + fireData.CyclopsGuid + " Room: " + fireData.Room + " NodeIndex: " + fireData.NodeIndex + "]"); } GameObject gameObject = component.SpawnManual(); Fire componentInChildren = gameObject.GetComponentInChildren <Fire>(); if (componentInChildren) { componentInChildren.fireSubRoot = subFire.subRoot; GuidHelper.SetNewGuid(componentInChildren.gameObject, fireData.FireGuid); } subFire.ReflectionSet("roomFires", roomFiresDict); subFire.ReflectionSet("availableNodes", availableNodes); }
/// <summary> /// Get all of the index locations of all the fires on the <see cref="SubRoot"/>. <see cref="SubFire.RoomFire.spawnNodes"/> contains /// a static list of all possible fire nodes. /// </summary> private IEnumerable <CyclopsFireData> GetActiveRoomFires(SubFire subFire) { string subRootGuid = GuidHelper.GetGuid(subFire.subRoot.gameObject); Dictionary <CyclopsRooms, SubFire.RoomFire> roomFires = (Dictionary <CyclopsRooms, SubFire.RoomFire>)subFire.ReflectionGet("roomFires"); foreach (KeyValuePair <CyclopsRooms, SubFire.RoomFire> roomFire in roomFires) { for (int i = 0; i < roomFire.Value.spawnNodes.Length; i++) { if (roomFire.Value.spawnNodes[i].childCount > 0) { yield return(new CyclopsFireData(GuidHelper.GetGuid(roomFire.Value.spawnNodes[i].GetComponentInChildren <Fire>().gameObject), subRootGuid, roomFire.Key, i)); } } } }
/// <summary> /// Add/remove fires until it matches the <paramref name="roomFires"/> array. Can trigger <see cref="FireDoused"/> packets /// </summary> private void SetActiveRoomFires(SubRoot subRoot, CyclopsFireData[] roomFires) { SubFire subFire = subRoot.gameObject.RequireComponent <SubFire>(); Dictionary <CyclopsRooms, SubFire.RoomFire> roomFiresDict = (Dictionary <CyclopsRooms, SubFire.RoomFire>)subFire.ReflectionGet("roomFires"); string subRootGuid = GuidHelper.GetGuid(subRoot.gameObject); CyclopsFireData fireNode = null; if (roomFires != null && roomFires.Length > 0) { // Removing and adding fires will happen in the same loop foreach (KeyValuePair <CyclopsRooms, SubFire.RoomFire> keyValuePair in roomFiresDict) { for (int nodeIndex = 0; nodeIndex < keyValuePair.Value.spawnNodes.Length; nodeIndex++) { fireNode = roomFires.SingleOrDefault(x => x.Room == keyValuePair.Key && x.NodeIndex == nodeIndex); // If there's a matching node index, add a fire if there isn't one already. Otherwise remove a fire if there is one if (fireNode == null) { if (keyValuePair.Value.spawnNodes[nodeIndex].childCount > 0) { keyValuePair.Value.spawnNodes[nodeIndex].GetComponentInChildren <Fire>().Douse(10000); } } else { if (keyValuePair.Value.spawnNodes[nodeIndex].childCount < 1) { fires.Create(new CyclopsFireData(fireNode.FireGuid, subRootGuid, fireNode.Room, fireNode.NodeIndex)); } } } } } // Clear out the fires, there should be none active else { foreach (KeyValuePair <CyclopsRooms, SubFire.RoomFire> keyValuePair in roomFiresDict) { for (int nodeIndex = 0; nodeIndex < keyValuePair.Value.spawnNodes.Length; nodeIndex++) { if (keyValuePair.Value.spawnNodes[nodeIndex].childCount > 0) { keyValuePair.Value.spawnNodes[nodeIndex].GetComponentInChildren <Fire>().Douse(10000); } } } } }