using System.Collections.Generic; using NitroxClient.Communication.Abstract; using NitroxClient.Communication.Packets.Processors; using NitroxClient.MonoBehaviours; using NitroxModel.DataStructures; using NitroxModel.Packets; using NitroxModel_Subnautica.DataStructures.GameLogic; using NitroxModel_Subnautica.Packets; using UnityEngine; namespace NitroxClient.GameLogic { /// /// Handles all of the s in the game. Currently, the only known Fire spawning is in . The /// fires in the Aurora come loaded with the map and do not grow in size. If we want to create a Fire spawning mechanic outside of Cyclops fires, it should be /// added to . Fire dousing goes by Id and does not need to be /// modified /// public class Fires { private readonly IPacketSender packetSender; /// /// Used to reduce the packet spam as fires are being doused. A packet is only sent after /// the douse amount surpasses /// private readonly Dictionary fireDouseAmount = new Dictionary(); /// /// Each extinguisher hit is from 0.15 to 0.25. 5 is a bit less than half a second of full extinguishing /// private const float FIRE_DOUSE_AMOUNT_TRIGGER = 5f; public Fires(IPacketSender packetSender) { this.packetSender = packetSender; } /// /// Triggered when is executed. To create a new fire manually, /// call /// public void OnCreate(Fire fire, SubFire.RoomFire room, int nodeIndex) { if (!fire.TryGetIdOrWarn(out NitroxId fireId)) { return; } if (!fire.fireSubRoot.TryGetIdOrWarn(out NitroxId subRootId)) { return; } CyclopsFireCreated packet = new CyclopsFireCreated(fireId, subRootId, room.roomLinks.room, nodeIndex); packetSender.Send(packet); } /// /// Triggered when is executed. To Douse a fire manually, retrieve the call the Douse method /// public void OnDouse(Fire fire, float douseAmount) { if (!fire.TryGetIdOrWarn(out NitroxId fireId)) { return; } // Temporary packet limiter if (!fireDouseAmount.ContainsKey(fireId)) { fireDouseAmount.Add(fireId, douseAmount); } else { float summedDouseAmount = fireDouseAmount[fireId] + douseAmount; if (summedDouseAmount > FIRE_DOUSE_AMOUNT_TRIGGER) { // It is significantly faster to keep the key as a 0 value than to remove it and re-add it later. fireDouseAmount[fireId] = 0; FireDoused packet = new FireDoused(fireId, douseAmount); packetSender.Send(packet); } } } /// /// Create a new . Majority of code copied from . Currently does not support Fires created outside of a Cyclops /// public void Create(CyclopsFireData fireData) { SubFire subFire = NitroxEntity.RequireObjectFrom(fireData.CyclopsId).GetComponent().damageManager.subFire; Dictionary roomFiresDict = subFire.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 Id with the new one if (transform2.childCount > 0) { Fire existingFire = transform2.GetComponentInChildren(); if (existingFire.TryGetNitroxId(out NitroxId existingFireId) && existingFireId != fireData.CyclopsId) { Log.Error($"[Fires.Create Fire already exists at node index {fireData.NodeIndex}! Replacing existing Fire Id {existingFireId} with Id {fireData.CyclopsId}]"); NitroxEntity.SetNewId(existingFire.gameObject, fireData.CyclopsId); } return; } List availableNodes = subFire.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(); if (!component) { return; } else { Log.Error( $"[{nameof(CyclopsFireCreatedProcessor)} Cannot create new Cyclops fire! PrefabSpawn component could not be found in fire node! Fire Id: {fireData.FireId} SubRoot Id: {fireData.CyclopsId} Room: {fireData.Room} NodeIndex: {fireData.NodeIndex}]"); } component.SpawnManual(delegate(GameObject fireGO) { Fire componentInChildren = fireGO.GetComponentInChildren(); if (componentInChildren) { componentInChildren.fireSubRoot = subFire.subRoot; NitroxEntity.SetNewId(componentInChildren.gameObject, fireData.FireId); } }); subFire.roomFires = roomFiresDict; subFire.availableNodes = availableNodes; } } }