Upload from upload_mods.ps1
This commit is contained in:
22
Score/Fire/Harmony/ChunkSetBlock.cs
Normal file
22
Score/Fire/Harmony/ChunkSetBlock.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace Features.Fire.Harmony
|
||||
{
|
||||
[HarmonyPatch(typeof(Chunk))]
|
||||
[HarmonyPatch("SetBlock")]
|
||||
|
||||
public class ChunkSetBlock
|
||||
{
|
||||
public static void Postfix(Chunk __instance, int ___m_X, int ___m_Z, int x, int y, int z, bool _fromReset)
|
||||
{
|
||||
if (!_fromReset) return;
|
||||
// If the POI is being reset, clear the fire.
|
||||
var vector3I = new Vector3i((___m_X << 4) + x, y, (___m_Z << 4) + z);
|
||||
var fireMap = FireManager.Instance?.GetFireMap();
|
||||
if (fireMap == null) return;
|
||||
if (fireMap.ContainsKey(vector3I))
|
||||
{
|
||||
FireManager.Instance?.RemoveFire(vector3I);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
43
Score/Fire/Harmony/Explosion.cs
Normal file
43
Score/Fire/Harmony/Explosion.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace Features.Fire.Harmony
|
||||
{
|
||||
// Allows the spread of the particles to catch things on fire.
|
||||
[HarmonyPatch(typeof(Explosion))]
|
||||
[HarmonyPatch("AttackBlocks")]
|
||||
public class SCoreExplosionattackBlocks
|
||||
{
|
||||
public static void Postfix(Explosion __instance, int _entityThatCausedExplosion, ExplosionData ___explosionData)
|
||||
{
|
||||
if (FireManager.Instance == null) return;
|
||||
if (FireManager.Instance.Enabled == false) return;
|
||||
|
||||
// BlockDamage set to 0 does nothing.
|
||||
if (___explosionData.BlockDamage == 0) return;
|
||||
if (___explosionData.ParticleIndex == 0) return;
|
||||
|
||||
var entityAlive = GameManager.Instance.World.GetEntity(_entityThatCausedExplosion) as EntityAlive;
|
||||
if (entityAlive != null)
|
||||
{
|
||||
if (entityAlive.EntityClass.Properties.Contains("SpreadFire"))
|
||||
{
|
||||
if (entityAlive.EntityClass.Properties.GetBool("SpreadFire") == false)
|
||||
return;
|
||||
}
|
||||
|
||||
if (entityAlive.Buffs.HasCustomVar("SpreadFire"))
|
||||
{
|
||||
var spreadFire = entityAlive.Buffs.GetCustomVar("SpreadFire");
|
||||
if (spreadFire == -1f) return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var position in __instance.ChangedBlockPositions)
|
||||
{
|
||||
// Negative block damages extinguishes
|
||||
if (___explosionData.BlockDamage < 0f)
|
||||
FireManager.Instance.Extinguish(position.Key);
|
||||
else
|
||||
FireManager.Instance.Add(position.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Score/Fire/Harmony/FireInit.cs
Normal file
28
Score/Fire/Harmony/FireInit.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Features.Fire.Harmony
|
||||
{
|
||||
// Allows the spread of the particles to catch things on fire.
|
||||
/*[HarmonyPatch(typeof(GameStateManager))]
|
||||
[HarmonyPatch("StartGame")]
|
||||
public class GameStateManagerStartGame
|
||||
{
|
||||
public static void Postfix()
|
||||
{
|
||||
if (GamePrefs.GetString(EnumGamePrefs.GameWorld) == "Empty"
|
||||
|| GamePrefs.GetString(EnumGamePrefs.GameWorld) == "Playtesting"
|
||||
|| GamePrefs.GetString(EnumGamePrefs.GameMode) == "GameModeEditWorld")
|
||||
{
|
||||
Debug.Log("Disabling Fire Manager in Play Testing / Prefab editor");
|
||||
return;
|
||||
}
|
||||
FireManager.Init();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
34
Score/Fire/Harmony/PerformanceTweaks.cs
Normal file
34
Score/Fire/Harmony/PerformanceTweaks.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
namespace Features.Fire.Harmony
|
||||
{
|
||||
|
||||
// Light reduction patch from ocbMaurice
|
||||
[HarmonyPatch(typeof(ParticleEffect))]
|
||||
[HarmonyPatch("SpawnParticleEffect")]
|
||||
public class ParticleEffectspawnParticleEffect
|
||||
{
|
||||
private const int Odds = 4;
|
||||
private static int _count = Odds;
|
||||
|
||||
public static void Postfix(ref Transform __result)
|
||||
{
|
||||
if (__result == null) return;
|
||||
|
||||
bool optionFireManager = CustomGameOptions.GetBool("CustomFireManager");
|
||||
if (!optionFireManager) return;
|
||||
|
||||
if (__result.GetComponentInChildren<Light>() is not Light light) return;
|
||||
if (_count == Odds)
|
||||
{
|
||||
_count = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
light.enabled = false;
|
||||
var go = light.gameObject;
|
||||
//Log.Out($"SpawnParticleEffect - Destroy Light gameObject: {go}, parent: {go.transform.parent}");
|
||||
go.transform.parent = null;
|
||||
UnityEngine.Object.Destroy(go);
|
||||
_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Score/Fire/Harmony/UpdateCurrentBlockposAndValueFire.cs
Normal file
27
Score/Fire/Harmony/UpdateCurrentBlockposAndValueFire.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace Features.Fire.Harmony
|
||||
{
|
||||
[HarmonyPatch(typeof(Block))]
|
||||
[HarmonyPatch("OnEntityWalking")]
|
||||
public class BlockOnEntityWalking
|
||||
{
|
||||
public static void Postfix(int _x, int _y, int _z, Entity entity)
|
||||
{
|
||||
if (FireManager.Instance == null) return;
|
||||
|
||||
var blockPosition = new Vector3i(_x, _y, _z);
|
||||
|
||||
if (!FireManager.IsBurning(blockPosition)) return;
|
||||
|
||||
if (!GameManager.IsDedicatedServer)
|
||||
if (!GameManager.Instance.HasBlockParticleEffect(blockPosition)) return;
|
||||
|
||||
if (entity is not EntityAlive entityAlive) return;
|
||||
|
||||
var buff = "buffBurningMolotov";
|
||||
if (!string.IsNullOrEmpty(buff))
|
||||
{
|
||||
entityAlive.Buffs.AddBuff(buff, -1, entityAlive.isEntityRemote);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
259
Score/Fire/Readme.md
Normal file
259
Score/Fire/Readme.md
Normal file
@@ -0,0 +1,259 @@
|
||||
Fire Manager
|
||||
---
|
||||
The Fire Manager introduces fire mechanics into the game. This includes starting, spreading and extinguishing fires, and
|
||||
allowing blocks to explode.
|
||||
|
||||
# Table of Contents
|
||||
1. [Summary](#summary)
|
||||
2. [Fire Manage Global Configuration](#fire-manager-global-configuration)
|
||||
3. [Block-Specific Configuration](#block-specific-configuration)
|
||||
4. [Examples](#examples)
|
||||
## Summary
|
||||
|
||||
A block may catch on fire through a variety of means, depending on the mod in question. For example, a thrown molotov would certainly catch
|
||||
blocks on fire, potentially triggering a cascading fire that may burn a building down.
|
||||
|
||||
When a block is on fire, it will have damage dealt to it over time, using the CheckInterval time.
|
||||
|
||||
When a block is checked during its CheckInterval time, neighboring blocks may catch on fire if they are flammable. A FireSpread property can disable this.
|
||||
|
||||
When a block has taken more damage than its max damage, the block will downgrade itself to its defined Downgrade block. By default, this is an air block.
|
||||
|
||||
When a block has an Explosion.ParticleIndex defined, the Fire Manage will use that data to trigger an explosion.
|
||||
|
||||
When a block is extinguished, a smoke particle will be placed on it, showing the player that it has been extinguished. An extinguished block will not immediately
|
||||
catch fire again.
|
||||
|
||||
To determine if a block is flammable or not, several checks are performed. The checks here are listed in the order they are checked in code. Once a block is
|
||||
determined to not be flammable, then the other checks are not performed.
|
||||
|
||||
- Does the block have tag of "inflammable"?
|
||||
- Is the position a child of a block? ( think of multi-dim's here)
|
||||
- Not Flammable.
|
||||
- Is the position air?
|
||||
- Not Flammable.
|
||||
- is the position water?
|
||||
- Not Flammable.
|
||||
- Does The block have the tag of "flammable"?
|
||||
- Flammable
|
||||
- Does the Config block have the Property "MaterialID", and does it match our Block?
|
||||
- Flammable
|
||||
- Does the Config block have the Property "MaterialDamage", and does it match our Block?
|
||||
- Flammable
|
||||
- Does the Config block have the Property "MaterialSurface", and does it match our Block?
|
||||
- Flammable
|
||||
|
||||
The block must return a "Flammable" check to be added to the Fire Manager's system, and be lit on fire.
|
||||
|
||||
## Fire Manager Global Configuration
|
||||
|
||||
The blocks.xml contains configurations and settings to adjust the fire behaviour from its defaults.
|
||||
|
||||
Note: Some of these properties may be defined on the block or material entry to over-ride the default.
|
||||
|
||||
#### Logging
|
||||
```xml
|
||||
<!-- Enables or disables verbose logging for troubleshooting -->
|
||||
<property name="Logging" value="false"/>
|
||||
```
|
||||
#### FireEnable
|
||||
```xml
|
||||
<!-- Enables or disables the fire manager completely -->
|
||||
<property name="FireEnable" value="false"/>
|
||||
```
|
||||
#### CheckInterval
|
||||
```xml
|
||||
<!-- Determines how often the fire manager should damage a block, determine fire spreading, etc -->
|
||||
<property name="CheckInterval" value="20"/>
|
||||
```
|
||||
#### FireDamage
|
||||
```xml
|
||||
<!-- Determines how much damage is done to a block per CheckInterval. -->
|
||||
<!-- If this property is defined on a specific block, that value will be used, rather than the default -->
|
||||
<!-- If this property is defined on a materials.xml entry, that value will be used. -->
|
||||
<property name="FireDamage" value="10"/>
|
||||
```
|
||||
#### SmokeTime
|
||||
```xml
|
||||
<!-- Determines the length of time, in seconds, that the smoke particle will appear on an extinguished block -->
|
||||
<!-- If this property is defined on a specific block, that value will be used, rather than the default -->
|
||||
<property name="SmokeTime" value="60"/>
|
||||
```
|
||||
#### FireSound
|
||||
```xml
|
||||
<!-- Determines which SoundDataNode entry will be used to play the sound -->
|
||||
<!-- If this property is defined on a specific block, that value will be used, rather than the default -->
|
||||
<property name="FireSound" value="ScoreMediumLoop"/>
|
||||
```
|
||||
#### BuffOnFire
|
||||
```xml
|
||||
<!-- Defines which buff to apply to a player / zombie / NPC when they touch a block on fire -->
|
||||
<property name="BuffOnFire" value="buffBurningMolotov"/>
|
||||
```
|
||||
#### MaterialID
|
||||
```xml
|
||||
<!-- Defines which materials are considered flammable, by material ID in materials.xml -->
|
||||
<property name="MaterialID" value="Mplants, Mcorn, Mhay"/>
|
||||
```
|
||||
#### MaterialDamage
|
||||
```xml
|
||||
<!-- Defines which materials are considered flammable, by material Damage in materials.xml -->
|
||||
<property name="MaterialDamage" value="wood, cloth, corn, grass, plastic, leaves, cactus, mushroom, hay, paper, trash, backpack, organic"/>
|
||||
```
|
||||
#### MaterialSurface
|
||||
```xml
|
||||
<!-- Defines which materials are considered flammable, by material Surface in materials.xml -->
|
||||
<property name="MaterialDamage" value="wood, cloth, corn, grass, plastic, leaves, cactus, mushroom, hay, paper, trash, backpack, organic"/>
|
||||
```
|
||||
#### SmokeParticle
|
||||
```xml
|
||||
<!-- Defines the Smoke Particle to be used on an extinguished block -->
|
||||
<!-- If this property is defined on a specific block, that value will be used, rather than the default -->
|
||||
<property name="SmokeParticle" value="#@modfolder:Resources/PathSmoke.unity3d?P_PathSmoke_X"/>
|
||||
```
|
||||
#### FireParticle
|
||||
```xml
|
||||
<!-- Defines the Fire Particle to be used on a block that is burning. -->
|
||||
<!-- If this property is defined on a specific block, that value will be used, rather than the default -->
|
||||
<property name="FireParticle" value="#@modfolder:Resources/gupFireParticles.unity3d?gupBeavis05-Heavy"/>
|
||||
|
||||
<!-- Other particles that may be available, but may cause more performance overhead -->
|
||||
<!--
|
||||
<property name="FireParticle" value="#@modfolder:Resources/gupFireParticles.unity3d?gupBeavis02-CampFire" />
|
||||
<property name="FireParticle" value="#@modfolder:Resources/gupFireParticles.unity3d?gupBeavis03-Cartoon" />
|
||||
<property name="FireParticle" value="#@modfolder:Resources/gupFireParticles.unity3d?gupBeavis04-SlowFire" />
|
||||
<property name="FireParticle" value="#@modfolder:Resources/gupFireParticles.unity3d?gupBeavis05-Heavy" />
|
||||
<property name="FireParticle" value="#@modfolder:Resources/gupFireParticles.unity3d?gupBeavis06-HeavyLight" />
|
||||
-->
|
||||
```
|
||||
#### FireSpread
|
||||
```xml
|
||||
<!-- Defines is fire can be spread to neighboring blocks -->
|
||||
<property name="FireSpread" value="true"/>
|
||||
```
|
||||
#### ChanceToExtinguish
|
||||
```xml
|
||||
<!-- The chance, in percentage as defined from 0 to 1 to denote 0% to 100%, for a block to self-extinguish -->
|
||||
<!-- This is re-checked on each CheckInterval -->
|
||||
<!-- If this property is defined on a specific block, that value will be used, rather than the default -->
|
||||
<property name="ChanceToExtinguish" value="0.05"/>
|
||||
```
|
||||
|
||||
|
||||
## Block-specific Configuration
|
||||
|
||||
In addition to the above settings in the Fire Manager's overall blocks.xml, further properties may be optionally added to blocks.xml to further define the behaviour.
|
||||
|
||||
These per-block settings will over-ride the global value for that block in which they are defined on.
|
||||
|
||||
#### FireDowngradeBlock
|
||||
```xml
|
||||
<!-- When a block is destroyed by fire, it will downgrade to this block -->
|
||||
<!-- By default, this is air -->
|
||||
<property name="FireDowngradeBlock" value="burnBlock"/>
|
||||
```
|
||||
#### Explosion.ParticleIndex
|
||||
```xml
|
||||
<!-- If a block has a defined Explosion.ParticleIndex and is destroyed by fire, the fire manager will set an explosion based on those settings. -->
|
||||
<property name="Explosion.ParticleIndex" value="0"/>
|
||||
```
|
||||
#### ChanceToExtinguish
|
||||
```xml
|
||||
<!-- The chance, in percentage as defined from 0 to 1 to denote 0% to 100%, for a block to self-extinguish -->
|
||||
<property name="ChanceToExtinguish" value="0.05"/>
|
||||
```
|
||||
#### FireDamage
|
||||
```xml
|
||||
<!-- Determines how much damage is done to a block per CheckInterval. -->
|
||||
<property name="FireDamage" value="10"/>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## MinEvents
|
||||
|
||||
A few MinEvents have been written to help modders interact with the fire system. These MinEvents may be added to buffs or item actions.
|
||||
|
||||
The trigger may change depending on context and use.
|
||||
|
||||
#### MinEventActionAddFireDamage
|
||||
|
||||
This effect will set a block on fire, using the target's position, and the range. There is an optional delay time, which will delay the fire from starting.
|
||||
```xml
|
||||
<triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamage, SCore" target="positionAOE" range="5" delayTime="10" />
|
||||
```
|
||||
|
||||
#### MinEventActionAddFireDamageCascade
|
||||
|
||||
This effect can allow fire to spread to to surrounding blocks. You can set up a filter based on the type of blocks you wanted affected.
|
||||
|
||||
```xml
|
||||
<!-- The same type of block -->
|
||||
<triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamageCascade, SCore" range="4" filter="Type" />
|
||||
|
||||
<!-- Shares the same material -->
|
||||
<triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamageCascade, SCore" range="4" filter="Material" />
|
||||
|
||||
<!-- Shares the same material damage classification -->
|
||||
<triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamageCascade, SCore" range="4" filter="MaterialDamage" />
|
||||
|
||||
<!-- Shares the same material surface classification -->
|
||||
<triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamageCascade, SCore" range="4" filter="MaterialSurface" />
|
||||
```
|
||||
|
||||
#### MinEventActionCheckFireProximity
|
||||
|
||||
Checks to see if there's any fire blocks within the specified range, using the player's position as center.
|
||||
|
||||
```xml
|
||||
<!-- The cvar specified, by default _closeFires, will contain the number of burning blocks in the range. -->
|
||||
<triggered_effect trigger="onSelfBuffUpdate" action="CheckFireProximity, SCore" range="5" cvar="_closeFires" />
|
||||
```
|
||||
|
||||
#### MinEventActionRemoveFire
|
||||
|
||||
Remove Fire within the specified range, using the specified target.
|
||||
|
||||
```xml
|
||||
<!-- This will remove fire from all blocks with a range of 5 from the position of the target. -->
|
||||
<triggered_effect trigger="onSelfDamagedBlock" action="RemoveFire, SCore" target="positionAOE" range="5"/>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
### XPath
|
||||
|
||||
Here are some examples on how to modify the ConfigFeatureBlock, which holds the Fire Management settings, from another modlet.
|
||||
```xml
|
||||
<!-- Enable fire -->
|
||||
<set xpath="/blocks/block[@name='ConfigFeatureBlock']/property[@class='FireManagement']/property[@name='FireEnable']/@value">true</set>
|
||||
<!-- Turn on verbose logging -->
|
||||
<set xpath="/blocks/block[@name='ConfigFeatureBlock']/property[@class='FireManagement']/property[@name='Logging']/@value">true</set>
|
||||
|
||||
<!-- Adding materials -->
|
||||
<set xpath="/blocks/block[@name='ConfigFeatureBlock']/property[@class='FireManagement']/property[@name='MaterialDamage']/@value">wood, cloth, corn, grass, plastic, leaves, cactus, mushroom, hay, paper, trash, backpack, organic</set>
|
||||
<set xpath="/blocks/block[@name='ConfigFeatureBlock']/property[@class='FireManagement']/property[@name='MaterialSurface']/@value">wood, cloth, corn, grass, plastic, leaves, cactus, mushroom, hay, paper, trash, backpack, organic</set>
|
||||
```
|
||||
|
||||
To adding Fire Damage to the flaming crossbow bolts
|
||||
```xml
|
||||
<append xpath="/items/item[@name='ammoCrossbowBoltFlaming']/effect_group" >
|
||||
<triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamage, SCore" delayTime="5000"/> <!-- Delay Time in ms -->
|
||||
</append>
|
||||
```
|
||||
|
||||
### Triggers
|
||||
|
||||
```xml
|
||||
<!-- Adds fire to the block being hit, if it's flammable. -->
|
||||
<triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamage, SCore" />
|
||||
|
||||
<!-- Remove fire from an area -->
|
||||
<triggered_effect trigger="onSelfPrimaryActionRayHit" action="RemoveFire, SCore" target="positionAOE" range="5"/>
|
||||
|
||||
<!-- Spread fire to all surrounding blocks that have the same material as the target being hit, such as cloth -->
|
||||
<triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamageCascade, SCore" range="4" filter="Material" />
|
||||
```
|
||||
|
||||
786
Score/Fire/Scripts/FireManager.cs
Normal file
786
Score/Fire/Scripts/FireManager.cs
Normal file
@@ -0,0 +1,786 @@
|
||||
using Audio;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
/// <summary>
|
||||
/// SCore's FireManager allows flammable blocks to catch and spread fire.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Fire Manager allows blocks to catch on fire, and allows them to spread to other blocks around it at a timed interval.
|
||||
/// The following parameters are configured through the blocks.xml
|
||||
/// </remarks>
|
||||
|
||||
public class FireManager
|
||||
{
|
||||
private const string AdvFeatureClass = "FireManagement";
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
private static readonly ConcurrentDictionary<Vector3i, BlockValue>
|
||||
FireMap = new ConcurrentDictionary<Vector3i, BlockValue>();
|
||||
|
||||
private static readonly ConcurrentDictionary<Vector3i, float> ExtinguishPositions =
|
||||
new ConcurrentDictionary<Vector3i, float>();
|
||||
|
||||
private float _checkTime = 120f;
|
||||
private float _currentTime;
|
||||
private const float CheckTimeLights = 0.8f;
|
||||
private float _currentTimeLights;
|
||||
private float _fireDamage = 1f;
|
||||
|
||||
private float _smokeTime = 60f;
|
||||
private readonly GameRandom _random = GameManager.Instance.World.GetGameRandom();
|
||||
private bool _fireSpread = true;
|
||||
|
||||
|
||||
// Used to throttle sounds playing.
|
||||
private static readonly List<Vector3i> SoundPlaying = new List<Vector3i>();
|
||||
private static readonly List<Vector3i> ParticlePlaying = new List<Vector3i>();
|
||||
private const int MaxLights = 32;
|
||||
|
||||
private static readonly HashSet<Light> Shutoff =
|
||||
new HashSet<Light>();
|
||||
|
||||
private string _fireSound;
|
||||
private string _fireParticle;
|
||||
private string _smokeParticle;
|
||||
private const string SaveFile = "FireManager.dat";
|
||||
private ThreadManager.ThreadInfo _dataSaveThreadInfo;
|
||||
private float _chanceToExtinguish = 0.05f;
|
||||
public bool Enabled; // { private set; get; }
|
||||
|
||||
public static FireManager Instance { get; private set; }
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
Instance = new FireManager();
|
||||
Instance.ReadConfig();
|
||||
}
|
||||
|
||||
private void ReadConfig()
|
||||
{
|
||||
var fireSpreadString = "true";
|
||||
if (!StringParsers.ParseBool(fireSpreadString))
|
||||
{
|
||||
Debug.Log("Fire Spread Disabled.");
|
||||
_fireSpread = false;
|
||||
}
|
||||
|
||||
|
||||
Enabled = true;
|
||||
string option = "";
|
||||
bool optionFireManager = CustomGameOptions.GetBool("CustomFireManager");
|
||||
if (!optionFireManager)
|
||||
{
|
||||
Log.Out("Fire Manager is disabled.");
|
||||
Enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
option = "20";
|
||||
if (!string.IsNullOrEmpty(option))
|
||||
_checkTime = StringParsers.ParseFloat(option);
|
||||
|
||||
var strDamage = "50";
|
||||
if (!string.IsNullOrWhiteSpace(strDamage))
|
||||
_fireDamage = StringParsers.ParseFloat(strDamage);
|
||||
_currentTime = -1;
|
||||
|
||||
var smoke = "60";
|
||||
if (!string.IsNullOrWhiteSpace(smoke))
|
||||
_smokeTime = StringParsers.ParseFloat(smoke);
|
||||
|
||||
var strFireSound = "SCoreMediumLoop";
|
||||
if (!string.IsNullOrWhiteSpace(strFireSound))
|
||||
_fireSound = strFireSound;
|
||||
|
||||
if (_fireSound == "None")
|
||||
_fireSound = string.Empty;
|
||||
|
||||
Log.Out("Starting Fire Manager");
|
||||
|
||||
_fireParticle = "#@modfolder(zzz_REBIRTH__Utils):Resources/gupFireParticles.unity3d?gupBeavis05-Heavy";
|
||||
_smokeParticle = "#@modfolder(zzz_REBIRTH__Utils):Resources/PathSmoke.unity3d?P_PathSmoke_X";
|
||||
|
||||
var optionChanceToExtinguish = "0.05";
|
||||
if (!string.IsNullOrEmpty(option))
|
||||
_chanceToExtinguish = StringParsers.ParseFloat(optionChanceToExtinguish);
|
||||
|
||||
// Read the FireManager
|
||||
Load();
|
||||
|
||||
// Only run the Update on the server, then just distribute the data to the clients using NetPackages.
|
||||
if (!SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer) return;
|
||||
Log.Out($" :: Fire Interval Check time: {_checkTime}");
|
||||
|
||||
ModEvents.GameUpdate.RegisterHandler(FireUpdate);
|
||||
ModEvents.GameUpdate.RegisterHandler(LightsUpdate);
|
||||
}
|
||||
|
||||
#region LightCode
|
||||
|
||||
private void LightsUpdate()
|
||||
{
|
||||
// Make sure to only run it once
|
||||
lock (Locker)
|
||||
{
|
||||
_currentTimeLights -= Time.deltaTime;
|
||||
if (_currentTimeLights > 0f) return;
|
||||
_currentTimeLights = CheckTimeLights;
|
||||
ShutoffLights();
|
||||
CheckLights();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void ShutoffLights()
|
||||
{
|
||||
if (Shutoff.Count == 0) return;
|
||||
if (GameManager.Instance.IsPaused()) return;
|
||||
Shutoff.RemoveWhere(light => light == null);
|
||||
foreach (var light in Shutoff)
|
||||
{
|
||||
light.intensity -= Time.deltaTime;
|
||||
// Log.Out("Toning down {0}", light.intensity);
|
||||
if (light.intensity > 0f) continue;
|
||||
// Log.Out("Culling light out of this world");
|
||||
var gameObject = light.gameObject;
|
||||
gameObject.transform.parent = null;
|
||||
UnityEngine.Object.Destroy(gameObject);
|
||||
}
|
||||
|
||||
Shutoff.RemoveWhere(light => light.intensity <= 0f);
|
||||
}
|
||||
|
||||
private static void CheckLights()
|
||||
{
|
||||
if (GameManager.Instance.IsPaused()) return;
|
||||
var allLights = UnityEngine.Object.FindObjectsOfType<Light>();
|
||||
if (allLights.Length <= MaxLights) return;
|
||||
var curLights = new List<Light>();
|
||||
for (var n = 0; n < allLights.Length; n += 1)
|
||||
{
|
||||
if (allLights[n].name != "FireLight") continue;
|
||||
if (Shutoff.Contains(allLights[n])) continue;
|
||||
curLights.Add(allLights[n]);
|
||||
}
|
||||
|
||||
// AdvLogging.DisplayLog(AdvFeatureClass,$"Detect currently {curLights.Count} lights, {Shutoff.Count} being culled");
|
||||
// Do nothing if we are (or will be) within limits
|
||||
if (curLights.Count <= MaxLights) return;
|
||||
// Otherwise choose more lights to shutoff
|
||||
while (curLights.Count >= MaxLights)
|
||||
{
|
||||
var idx = GameManager.Instance.World.GetGameRandom().RandomRange(curLights.Count);
|
||||
if (Shutoff.Contains(curLights[idx])) continue;
|
||||
// Log.Out("Selected {0} for culling", idx);
|
||||
Shutoff.Add(curLights[idx]);
|
||||
curLights.RemoveAt(idx);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// Poor man's timed cache
|
||||
private void CheckExtinguishedPosition()
|
||||
{
|
||||
var worldTime = GameManager.Instance.World.GetWorldTime();
|
||||
foreach (var position in ExtinguishPositions)
|
||||
{
|
||||
Remove(position.Key);
|
||||
if (!(position.Value < worldTime) &&
|
||||
!GameManager.Instance.World.GetBlock(position.Key + Vector3i.down).isair) continue;
|
||||
ExtinguishPositions.TryRemove(position.Key, out var _);
|
||||
ClearPos(position.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public ConcurrentDictionary<Vector3i, BlockValue> GetFireMap()
|
||||
{
|
||||
return FireMap;
|
||||
}
|
||||
|
||||
public int CloseFires(Vector3i position, int range = 5)
|
||||
{
|
||||
var count = 0;
|
||||
for (var x = position.x - range; x <= position.x + range; x++)
|
||||
{
|
||||
for (var z = position.z - range; z <= position.z + range; z++)
|
||||
{
|
||||
for (int y = position.y - 2; y <= position.y + 2; y++)
|
||||
{
|
||||
var localPosition = new Vector3i(x, y, z);
|
||||
if (IsBurning(localPosition)) count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public bool IsPositionCloseToFire(Vector3i position, int range = 5)
|
||||
{
|
||||
for (var x = position.x - range; x <= position.x + range; x++)
|
||||
{
|
||||
for (var z = position.z - range; z <= position.z + range; z++)
|
||||
{
|
||||
for (var y = position.y - 2; y <= position.y + 2; y++)
|
||||
{
|
||||
var localPosition = new Vector3i(x, y, z);
|
||||
if (IsBurning(localPosition)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
private void FireUpdate()
|
||||
{
|
||||
// Make sure to only run it once
|
||||
lock (Locker)
|
||||
{
|
||||
_currentTime -= Time.deltaTime;
|
||||
if (_currentTime > 0f) return;
|
||||
|
||||
GameManager.Instance.StopCoroutine(CheckBlocks());
|
||||
GameManager.Instance.StartCoroutine(CheckBlocks());
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator CheckBlocks()
|
||||
{
|
||||
if (GameManager.Instance.IsPaused()) yield break;
|
||||
if (!GameManager.Instance.gameStateManager.IsGameStarted()) yield break;
|
||||
|
||||
//Log.Out(AdvFeatureClass,
|
||||
//$"Checking Blocks for Fire: {FireMap.Count} Blocks registered. Extinguished Blocks: {ExtinguishPositions.Count}");
|
||||
_currentTime = _checkTime;
|
||||
|
||||
|
||||
var changes = new List<BlockChangeInfo>();
|
||||
var neighbors = new List<Vector3i>();
|
||||
|
||||
CheckExtinguishedPosition();
|
||||
|
||||
var chunkCluster = GameManager.Instance.World.ChunkClusters[0];
|
||||
if (chunkCluster == null) yield break;
|
||||
|
||||
var counter = 0;
|
||||
|
||||
var rainfallValue = WeatherManager.Instance.GetCurrentRainfallValue();
|
||||
|
||||
foreach (var posDict in FireMap)
|
||||
{
|
||||
counter++;
|
||||
// only process 10 blocks per frame.
|
||||
if (counter % 10 == 0)
|
||||
yield return null;
|
||||
|
||||
var blockPos = posDict.Key;
|
||||
if (!IsFlammable(blockPos))
|
||||
{
|
||||
Remove(blockPos);
|
||||
continue;
|
||||
}
|
||||
|
||||
var block = GameManager.Instance.World.GetBlock(blockPos);
|
||||
// Get block specific damages
|
||||
var damage = (int)_fireDamage;
|
||||
if (block.Block.Properties.Contains("FireDamage"))
|
||||
damage = block.Block.Properties.GetInt("FireDamage");
|
||||
|
||||
if (block.Block.blockMaterial.Properties.Contains("FireDamage"))
|
||||
damage = block.Block.blockMaterial.Properties.GetInt("FireDamage");
|
||||
|
||||
if (block.Block.Properties.Contains("ChanceToExtinguish"))
|
||||
block.Block.Properties.ParseFloat("ChanceToExtinguish", ref _chanceToExtinguish);
|
||||
|
||||
block.damage += damage;
|
||||
|
||||
if (block.damage >= block.Block.MaxDamage)
|
||||
{
|
||||
block.Block.SpawnDestroyParticleEffect(GameManager.Instance.World, block, blockPos, 1f,
|
||||
block.Block.tintColor, -1);
|
||||
var blockValue2 = block.Block.DowngradeBlock;
|
||||
|
||||
if (block.Block.Properties.Values.ContainsKey("FireDowngradeBlock"))
|
||||
blockValue2 = Block.GetBlockValue(block.Block.Properties.Values["FireDowngradeBlock"]);
|
||||
|
||||
if (block.Block.Properties.Values.ContainsKey("Explosion.ParticleIndex") ||
|
||||
block.Block.Properties.Classes.ContainsKey("Explosion"))
|
||||
block.Block.OnBlockDestroyedByExplosion(GameManager.Instance.World, 0, blockPos, block, -1);
|
||||
|
||||
// Check if there's another placeholder for this block.
|
||||
if (!blockValue2.isair)
|
||||
blockValue2 = BlockPlaceholderMap.Instance.Replace(blockValue2,
|
||||
GameManager.Instance.World.GetGameRandom(), blockPos.x, blockPos.z);
|
||||
blockValue2.rotation = block.rotation;
|
||||
blockValue2.meta = block.meta;
|
||||
|
||||
block = blockValue2;
|
||||
}
|
||||
|
||||
if (!block.isair)
|
||||
{
|
||||
SingletonMonoBehaviour<ConnectionManager>.Instance.SendPackage(
|
||||
NetPackageManager.GetPackage<NetPackageAddFirePosition>().Setup(blockPos, -1));
|
||||
}
|
||||
else
|
||||
{
|
||||
SingletonMonoBehaviour<ConnectionManager>.Instance.SendPackage(
|
||||
NetPackageManager.GetPackage<NetPackageRemoveFirePosition>().Setup(blockPos, -1));
|
||||
}
|
||||
|
||||
changes.Add(new BlockChangeInfo(0, blockPos, block));
|
||||
|
||||
var rand = _random.RandomRange(0f, 1f);
|
||||
|
||||
var extinguishChange = _chanceToExtinguish;
|
||||
if (rainfallValue > 0.25)
|
||||
{
|
||||
extinguishChange = _chanceToExtinguish * 2f;
|
||||
}
|
||||
var blchanceToExtinguish = rand < extinguishChange;
|
||||
|
||||
// If the new block has changed, check to make sure the new block is flammable. Note: it checks the blockValue, not blockPos, since the change hasn't been committed yet.
|
||||
if (!IsFlammable(block) || block.isair || blchanceToExtinguish)
|
||||
{
|
||||
// queue up the change
|
||||
if (DynamicMeshManager.Instance != null)
|
||||
DynamicMeshManager.Instance.AddChunk(blockPos, true);
|
||||
|
||||
Extinguish(blockPos);
|
||||
continue;
|
||||
}
|
||||
|
||||
ToggleSound(blockPos, rand < 0.10);
|
||||
ToggleParticle(blockPos, true);
|
||||
|
||||
// If we are damaging a block, allow the fire to spread.
|
||||
if (_fireSpread)
|
||||
neighbors.AddRange(CheckNeighbors(blockPos));
|
||||
|
||||
FireMap[blockPos] = block;
|
||||
}
|
||||
|
||||
// Send all the changes in one shot
|
||||
if (changes.Count > 0)
|
||||
GameManager.Instance.SetBlocksRPC(changes);
|
||||
|
||||
if (_fireSpread == false) yield break;
|
||||
|
||||
// Spread the fire to the neighbors. We delay this here so the fire does not spread too quickly or immediately, getting stuck in the above loop.
|
||||
foreach (var pos in neighbors)
|
||||
Add(pos);
|
||||
|
||||
//Debug.Log($"Sound Counter: {SoundPlaying.Count}, Fire Counter: {FireMap.Count} Particle Count: {ParticlePlaying.Count}: Heat: {heatMeter}");
|
||||
}
|
||||
|
||||
private void ToggleSound(Vector3i blockPos, bool turnOn)
|
||||
{
|
||||
//if (SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer) return;
|
||||
if (!ThreadManager.IsMainThread()) return;
|
||||
// If there's a lot of fires going on, turn off the sounds.
|
||||
if (turnOn && FireMap.Count > 60)
|
||||
{
|
||||
turnOn = false;
|
||||
}
|
||||
|
||||
var sound = GetFireSound(blockPos);
|
||||
|
||||
if (string.IsNullOrEmpty(sound)) return;
|
||||
|
||||
if (turnOn)
|
||||
{
|
||||
if (SoundPlaying.Contains(blockPos))
|
||||
return;
|
||||
SoundPlaying.Add(blockPos);
|
||||
Manager.Play(blockPos, sound);
|
||||
return;
|
||||
}
|
||||
|
||||
// No sound?
|
||||
if (!SoundPlaying.Contains(blockPos)) return;
|
||||
Manager.Stop(blockPos, sound);
|
||||
SoundPlaying.Remove(blockPos);
|
||||
}
|
||||
|
||||
private void ToggleParticle(Vector3i blockPos, bool turnOn)
|
||||
{
|
||||
// if (SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer) return;
|
||||
if (!ThreadManager.IsMainThread()) return;
|
||||
|
||||
var randomFireParticle = GetRandomFireParticle(blockPos);
|
||||
if (turnOn)
|
||||
{
|
||||
if (ParticlePlaying.Contains(blockPos)) return;
|
||||
if (GameManager.Instance.HasBlockParticleEffect(blockPos)) return;
|
||||
ParticlePlaying.Add(blockPos);
|
||||
RebirthUtilities.addParticlesCentered(randomFireParticle, blockPos);
|
||||
return;
|
||||
}
|
||||
|
||||
ParticlePlaying.Remove(blockPos);
|
||||
RebirthUtilities.removeParticles(blockPos);
|
||||
}
|
||||
|
||||
private string GetFireSound(Vector3i blockPos)
|
||||
{
|
||||
var block = GameManager.Instance.World.GetBlock(blockPos);
|
||||
|
||||
var fireSound = _fireSound;
|
||||
if (block.Block.Properties.Contains("FireSound"))
|
||||
fireSound = block.Block.Properties.GetString("FireSound");
|
||||
return fireSound;
|
||||
}
|
||||
|
||||
private string GetRandomFireParticle(Vector3i blockPos)
|
||||
{
|
||||
var block = GameManager.Instance.World.GetBlock(blockPos);
|
||||
|
||||
var fireParticle = _fireParticle;
|
||||
if (block.Block.Properties.Contains("FireParticle"))
|
||||
fireParticle = block.Block.Properties.GetString("FireParticle");
|
||||
|
||||
if (block.Block.blockMaterial.Properties.Contains("FireParticle"))
|
||||
fireParticle = block.Block.blockMaterial.Properties.GetString("FireParticle");
|
||||
|
||||
var randomFire = ""; // Configuration.GetPropertyValue(AdvFeatureClass, "RandomFireParticle");
|
||||
if (string.IsNullOrEmpty(randomFire)) return fireParticle;
|
||||
var fireParticles = randomFire.Split(',');
|
||||
var randomIndex = _random.RandomRange(0, fireParticles.Length);
|
||||
fireParticle = fireParticles[randomIndex];
|
||||
|
||||
return fireParticle;
|
||||
}
|
||||
|
||||
private string GetRandomSmokeParticle(Vector3i blockPos)
|
||||
{
|
||||
var block = GameManager.Instance.World.GetBlock(blockPos);
|
||||
|
||||
var smokeParticle = _smokeParticle;
|
||||
if (block.Block.Properties.Contains("SmokeParticle"))
|
||||
smokeParticle = block.Block.Properties.GetString("SmokeParticle");
|
||||
|
||||
if (block.Block.blockMaterial.Properties.Contains("SmokeParticle"))
|
||||
smokeParticle = block.Block.blockMaterial.Properties.GetString("SmokeParticle");
|
||||
|
||||
var randomSmoke = ""; // Configuration.GetPropertyValue(AdvFeatureClass, "RandomSmokeParticle");
|
||||
if (string.IsNullOrEmpty(randomSmoke)) return smokeParticle;
|
||||
var smokeParticles = randomSmoke.Split(',');
|
||||
var randomIndex = GameManager.Instance.World.GetGameRandom().RandomRange(0, smokeParticles.Length);
|
||||
smokeParticle = smokeParticles[randomIndex];
|
||||
|
||||
return smokeParticle;
|
||||
}
|
||||
|
||||
// Check to see if the nearby blocks can catch fire.
|
||||
private static List<Vector3i> CheckNeighbors(Vector3i blockPos)
|
||||
{
|
||||
var neighbors = new List<Vector3i>();
|
||||
foreach (var direction in Vector3i.AllDirections)
|
||||
{
|
||||
var position = blockPos + direction;
|
||||
if (FireMap.ContainsKey(position))
|
||||
continue;
|
||||
if (IsFlammable(position))
|
||||
neighbors.Add(position);
|
||||
}
|
||||
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
private static bool IsNearWater(Vector3i blockPos)
|
||||
{
|
||||
foreach (var direction in Vector3i.AllDirections)
|
||||
{
|
||||
var position = blockPos + direction;
|
||||
var blockValue = GameManager.Instance.World.GetBlock(position);
|
||||
if (blockValue.isWater) return true;
|
||||
if (blockValue.Block is BlockLiquidv2) return true;
|
||||
// A21 water check.
|
||||
if (GameManager.Instance.World.GetWaterPercent(position) > 0.25f) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsFlammable(BlockValue blockValue)
|
||||
{
|
||||
if (blockValue.Block.HasAnyFastTags(FastTags<TagGroup.Global>.Parse("inflammable"))) return false;
|
||||
if (blockValue.ischild) return false;
|
||||
if (blockValue.isair) return false;
|
||||
if (blockValue.isWater) return false;
|
||||
|
||||
// if (blockValue.Block.Properties.Values.ContainsKey("Explosion.ParticleIndex")) return true;
|
||||
|
||||
if (blockValue.Block.HasAnyFastTags(FastTags<TagGroup.Global>.Parse("flammable"))) return true;
|
||||
var blockMaterial = blockValue.Block.blockMaterial;
|
||||
|
||||
var matID = "Mplants, Mcorn, Mhay"; // Configuration.GetPropertyValue(AdvFeatureClass, "MaterialID");
|
||||
if (matID.Contains(blockMaterial.id)) return true;
|
||||
|
||||
var matDamage = "wood, cloth, corn, grass, plastic, leaves, cactus, mushroom, hay, paper, trash, backpack, organic"; // Configuration.GetPropertyValue(AdvFeatureClass, "MaterialDamage");
|
||||
if (!string.IsNullOrEmpty(matDamage) && blockMaterial.DamageCategory != null)
|
||||
if (matDamage.Contains(blockMaterial.DamageCategory))
|
||||
return true;
|
||||
|
||||
var matSurface = "wood, cloth, corn, grass, plastic, leaves, cactus, mushroom, hay, paper, trash, backpack, organic"; // Configuration.GetPropertyValue(AdvFeatureClass, "MaterialSurface");
|
||||
if (string.IsNullOrEmpty(matSurface) || blockMaterial.SurfaceCategory == null) return false;
|
||||
return matSurface.Contains(blockMaterial.SurfaceCategory);
|
||||
}
|
||||
|
||||
private static bool IsFlammable(Vector3i blockPos)
|
||||
{
|
||||
if (GameManager.Instance.World.IsWithinTraderArea(blockPos)) return false;
|
||||
if (ExtinguishPositions.ContainsKey(blockPos)) return false;
|
||||
|
||||
// If its already burning, then don't do any other check
|
||||
if (IsBurning(blockPos)) return true;
|
||||
if (IsNearWater(blockPos)) return false;
|
||||
|
||||
// Check the block value.
|
||||
var blockValue = GameManager.Instance.World.GetBlock(blockPos);
|
||||
return IsFlammable(blockValue);
|
||||
}
|
||||
|
||||
private static void Write(BinaryWriter bw)
|
||||
{
|
||||
// Save the burning blocks.
|
||||
var writeOut = "";
|
||||
foreach (var temp in FireMap)
|
||||
writeOut += $"{temp.Key};";
|
||||
writeOut = writeOut.TrimEnd(';');
|
||||
bw.Write(writeOut);
|
||||
|
||||
// Save the blocks we've put out
|
||||
var writeOut2 = "";
|
||||
foreach (var temp in ExtinguishPositions.Keys)
|
||||
writeOut2 += $"{temp};";
|
||||
writeOut2 = writeOut2.TrimEnd(';');
|
||||
bw.Write(writeOut2);
|
||||
}
|
||||
|
||||
private void Read(BinaryReader br)
|
||||
{
|
||||
// Read burning blocks
|
||||
var positions = br.ReadString();
|
||||
foreach (var position in positions.Split(';'))
|
||||
{
|
||||
if (string.IsNullOrEmpty(position)) continue;
|
||||
var vector = StringParsers.ParseVector3i(position);
|
||||
AddBlock(vector);
|
||||
}
|
||||
|
||||
// Read extinguished blocks.
|
||||
var extingished = br.ReadString();
|
||||
foreach (var position in extingished.Split(';'))
|
||||
{
|
||||
if (string.IsNullOrEmpty(position)) continue;
|
||||
var vector = StringParsers.ParseVector3i(position);
|
||||
ExtinguishBlock(vector);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearPosOnly(Vector3i blockPos)
|
||||
{
|
||||
ToggleSound(blockPos, false);
|
||||
ToggleParticle(blockPos, false);
|
||||
|
||||
}
|
||||
public void ClearPos(Vector3i blockPos)
|
||||
{
|
||||
ClearPosOnly(blockPos);
|
||||
if (!SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer)
|
||||
{
|
||||
SingletonMonoBehaviour<ConnectionManager>.Instance.SendToServer(
|
||||
NetPackageManager.GetPackage<NetPackageRemoveParticleEffect>().Setup(blockPos, -1));
|
||||
return;
|
||||
}
|
||||
|
||||
SingletonMonoBehaviour<ConnectionManager>.Instance.SendPackage(
|
||||
NetPackageManager.GetPackage<NetPackageRemoveParticleEffect>().Setup(blockPos, -1));
|
||||
}
|
||||
|
||||
public void Add(Vector3i blockPos, int entityID = -1)
|
||||
{
|
||||
if (!IsFlammable(blockPos))
|
||||
return;
|
||||
|
||||
AddBlock(blockPos);
|
||||
|
||||
if (!SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer)
|
||||
{
|
||||
SingletonMonoBehaviour<ConnectionManager>.Instance.SendToServer(
|
||||
NetPackageManager.GetPackage<NetPackageAddFirePosition>().Setup(blockPos, entityID));
|
||||
return;
|
||||
}
|
||||
|
||||
SingletonMonoBehaviour<ConnectionManager>.Instance.SendPackage(
|
||||
NetPackageManager.GetPackage<NetPackageAddFirePosition>().Setup(blockPos, entityID));
|
||||
}
|
||||
|
||||
|
||||
// General call to remove the fire from a block, and add an extinguished counter, so blocks can be temporarily immune to restarting.
|
||||
public void Extinguish(Vector3i blockPos, int entityID = -1)
|
||||
{
|
||||
ExtinguishBlock(blockPos);
|
||||
if (!SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer)
|
||||
{
|
||||
SingletonMonoBehaviour<ConnectionManager>.Instance.SendToServer(
|
||||
NetPackageManager.GetPackage<NetPackageAddExtinguishPosition>().Setup(blockPos, entityID));
|
||||
return;
|
||||
}
|
||||
|
||||
SingletonMonoBehaviour<ConnectionManager>.Instance.SendPackage(
|
||||
NetPackageManager.GetPackage<NetPackageAddExtinguishPosition>().Setup(blockPos, entityID));
|
||||
}
|
||||
|
||||
public void Remove(Vector3i blockPos, int entityID = -1)
|
||||
{
|
||||
RemoveFire(blockPos);
|
||||
|
||||
if (!SingletonMonoBehaviour<ConnectionManager>.Instance.IsServer)
|
||||
{
|
||||
SingletonMonoBehaviour<ConnectionManager>.Instance.SendToServer(
|
||||
NetPackageManager.GetPackage<NetPackageRemoveFirePosition>().Setup(blockPos, entityID));
|
||||
return;
|
||||
}
|
||||
|
||||
SingletonMonoBehaviour<ConnectionManager>.Instance.SendPackage(
|
||||
NetPackageManager.GetPackage<NetPackageRemoveFirePosition>().Setup(blockPos, entityID));
|
||||
}
|
||||
|
||||
|
||||
public void RemoveFire(Vector3i blockPos)
|
||||
{
|
||||
//if (!FireMap.ContainsKey(blockPos)) return;
|
||||
ToggleSound(blockPos, false);
|
||||
ToggleParticle(blockPos, false);
|
||||
FireMap.TryRemove(blockPos, out _);
|
||||
}
|
||||
|
||||
public void ExtinguishBlock(Vector3i blockPos)
|
||||
{
|
||||
//Log.Out("FireManager-ExtinguishBlock START");
|
||||
var worldTime = GameManager.Instance.World.GetWorldTime();
|
||||
var expiry = worldTime + _smokeTime;
|
||||
|
||||
// Seems like sometimes the dedicated and clients are out of sync, so this is a shot in the dark to see if we just skip the expired position check, and just
|
||||
// keep resetting the expired time.
|
||||
ExtinguishPositions[blockPos] = expiry;
|
||||
FireMap.TryRemove(blockPos, out _);
|
||||
|
||||
var block = GameManager.Instance.World.GetBlock(blockPos);
|
||||
ToggleSound(blockPos, false);
|
||||
|
||||
if (block.isair || !(_smokeTime > 0))
|
||||
{
|
||||
//Log.Out("FireManager-ExtinguishBlock 1");
|
||||
return;
|
||||
}
|
||||
var randomSmokeParticle = GetRandomSmokeParticle(blockPos);
|
||||
//Log.Out("FireManager-ExtinguishBlock randomSmokeParticle: " + randomSmokeParticle);
|
||||
RebirthUtilities.addParticlesCentered(randomSmokeParticle, blockPos);
|
||||
}
|
||||
|
||||
|
||||
// Add flammable blocks to the Fire Map
|
||||
public void AddBlock(Vector3i blockPos)
|
||||
{
|
||||
var block = GameManager.Instance.World.GetBlock(blockPos);
|
||||
if (!FireMap.TryAdd(blockPos, block)) return;
|
||||
|
||||
ToggleSound(blockPos, true);
|
||||
ToggleParticle(blockPos, true);
|
||||
}
|
||||
|
||||
public static bool IsBurning(Vector3i blockPos)
|
||||
{
|
||||
return Instance.Enabled && FireMap.ContainsKey(blockPos);
|
||||
}
|
||||
|
||||
private int SaveDataThreaded(ThreadManager.ThreadInfo threadInfo)
|
||||
{
|
||||
var pooledExpandableMemoryStream =
|
||||
(PooledExpandableMemoryStream)threadInfo.parameter;
|
||||
var text = $"{GameIO.GetSaveGameDir()}/{SaveFile}";
|
||||
if (File.Exists(text))
|
||||
File.Copy(text, $"{GameIO.GetSaveGameDir()}/{SaveFile}.bak", true);
|
||||
|
||||
pooledExpandableMemoryStream.Position = 0L;
|
||||
StreamUtils.WriteStreamToFile(pooledExpandableMemoryStream, text);
|
||||
Log.Out("FireManager saved {0} bytes", new object[]
|
||||
{
|
||||
pooledExpandableMemoryStream.Length
|
||||
});
|
||||
MemoryPools.poolMemoryStream.FreeSync(pooledExpandableMemoryStream);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void Save()
|
||||
{
|
||||
if (_dataSaveThreadInfo == null || !ThreadManager.ActiveThreads.ContainsKey("silent_FireDataSave"))
|
||||
{
|
||||
Log.Out($"FireManager saving {FireMap.Count} Fires...");
|
||||
var pooledExpandableMemoryStream = MemoryPools.poolMemoryStream.AllocSync(true);
|
||||
using (var pooledBinaryWriter = MemoryPools.poolBinaryWriter.AllocSync(false))
|
||||
{
|
||||
pooledBinaryWriter.SetBaseStream(pooledExpandableMemoryStream);
|
||||
Write(pooledBinaryWriter);
|
||||
}
|
||||
|
||||
_dataSaveThreadInfo = ThreadManager.StartThread("silent_FireDataSave", null,
|
||||
SaveDataThreaded, null,
|
||||
System.Threading.ThreadPriority.Normal, pooledExpandableMemoryStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Out("Not Saving. Thread still running?");
|
||||
}
|
||||
}
|
||||
|
||||
private void Load()
|
||||
{
|
||||
var path = $"{GameIO.GetSaveGameDir()}/{SaveFile}";
|
||||
if (!Directory.Exists(GameIO.GetSaveGameDir()) || !File.Exists(path)) return;
|
||||
|
||||
try
|
||||
{
|
||||
using var fileStream = File.OpenRead(path);
|
||||
using var pooledBinaryReader = MemoryPools.poolBinaryReader.AllocSync(false);
|
||||
pooledBinaryReader.SetBaseStream(fileStream);
|
||||
Read(pooledBinaryReader);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
path = $"{GameIO.GetSaveGameDir()}/{SaveFile}.bak";
|
||||
if (File.Exists(path))
|
||||
{
|
||||
using var fileStream2 = File.OpenRead(path);
|
||||
using var pooledBinaryReader2 = MemoryPools.poolBinaryReader.AllocSync(false);
|
||||
pooledBinaryReader2.SetBaseStream(fileStream2);
|
||||
Read(pooledBinaryReader2);
|
||||
}
|
||||
}
|
||||
|
||||
Log.Out($"Fire Manager {path} Loaded: {FireMap.Count}");
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
//Log.Out("Removing all blocks that are on fire and smoke.");
|
||||
lock (Locker)
|
||||
{
|
||||
foreach (var position in FireMap.Keys)
|
||||
Remove(position);
|
||||
|
||||
foreach (var position in ExtinguishPositions.Keys)
|
||||
RebirthUtilities.removeParticles(position);
|
||||
|
||||
FireMap.Clear();
|
||||
ExtinguishPositions.Clear();
|
||||
Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Score/Fire/Scripts/MinEvent/MinEventActionAddFireDamage.cs
Normal file
81
Score/Fire/Scripts/MinEvent/MinEventActionAddFireDamage.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using JetBrains.Annotations;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
/// <summary>
|
||||
/// Set's a single block on fire.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This effect will set a block on fire, using the target's position, and the range. There is an optional delay time, which will delay the fire from starting.
|
||||
/// Example:
|
||||
/// <triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamage, SCore" target="positionAOE" range="5" delayTime="10" />
|
||||
/// </remarks>
|
||||
[UsedImplicitly]
|
||||
public class MinEventActionAddFireDamage : MinEventActionRemoveBuff
|
||||
{
|
||||
private static readonly string AdvFeatureClass = "FireManagement";
|
||||
private float _delayTime;
|
||||
|
||||
public override void Execute(MinEventParams @params)
|
||||
{
|
||||
if (FireManager.Instance == null) return;
|
||||
if (FireManager.Instance.Enabled == false) return;
|
||||
|
||||
var position = @params.Position;
|
||||
if (targetType != TargetTypes.positionAOE)
|
||||
{
|
||||
if (Voxel.voxelRayHitInfo.bHitValid)
|
||||
{
|
||||
var hitInfo = Voxel.voxelRayHitInfo;
|
||||
if (hitInfo == null) return;
|
||||
|
||||
// modification from FuriousRamsay to fix issue where the lookray is behind a door, which is setting fire to blocks on the other side of metal doors.
|
||||
var itemAction = @params.Self.inventory.holdingItemData.item.Actions[0];
|
||||
if (itemAction is ItemActionMelee)
|
||||
{
|
||||
float blockRange = 0;
|
||||
if (itemAction.Properties.Values.ContainsKey("Block_range"))
|
||||
{
|
||||
blockRange = StringParsers.ParseFloat(itemAction.Properties.Values["Block_range"]);
|
||||
}
|
||||
|
||||
if ((blockRange > 0) && (Vector3.Distance(hitInfo.hit.blockPos, @params.Position) > blockRange))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
position = hitInfo.hit.blockPos;
|
||||
}
|
||||
}
|
||||
|
||||
//AdvLogging.DisplayLog(AdvFeatureClass, $"Executing AddFireDamage() at {position} Self: {@params.Self.position} Range: {maxRange} Delay: {_delayTime}");
|
||||
Task.Delay((int)_delayTime)
|
||||
.ContinueWith(_ => AddFire(position));
|
||||
}
|
||||
|
||||
private void AddFire(Vector3 position)
|
||||
{
|
||||
var range = (int)maxRange;
|
||||
for (var x = -range; x <= range; x++)
|
||||
{
|
||||
for (var z = -range; z <= range; z++)
|
||||
{
|
||||
for (var y = -range; y <= range; y++)
|
||||
{
|
||||
var vector = new Vector3i(position.x + x, position.y + y, position.z + z);
|
||||
FireManager.Instance.Add(vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ParseXmlAttribute(XAttribute attribute)
|
||||
{
|
||||
var flag = base.ParseXmlAttribute(attribute);
|
||||
if (flag) return true;
|
||||
var name = attribute.Name.LocalName;
|
||||
if (name != "delayTime") return false;
|
||||
_delayTime = StringParsers.ParseFloat(attribute.Value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using JetBrains.Annotations;
|
||||
using System.Xml.Linq;
|
||||
|
||||
/// <summary>
|
||||
/// Spreads fire over a wider area than a single block.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This effect can allow fire to spread to to surrounding blocks. You can set up a filter based on the type of blocks you wanted affected.
|
||||
/// Example:
|
||||
/// <!-- The same type of block -->
|
||||
/// <triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamageCascade, SCore" range="4" filter="Type" />
|
||||
///
|
||||
/// <!-- Shares the same material -->
|
||||
/// <triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamageCascade, SCore" range="4" filter="Material" />
|
||||
///
|
||||
/// <!-- Shares the same material damage classification -->
|
||||
/// <triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamageCascade, SCore" range="4" filter="MaterialDamage" />
|
||||
///
|
||||
/// <!-- Shares the same material surface classification -->
|
||||
/// <triggered_effect trigger="onSelfDamagedBlock" action="AddFireDamageCascade, SCore" range="4" filter="MaterialSurface" />
|
||||
/// </remarks>
|
||||
[UsedImplicitly]
|
||||
public class MinEventActionAddFireDamageCascade : MinEventActionRemoveBuff
|
||||
{
|
||||
private enum FilterTypeCascade
|
||||
{
|
||||
Type,
|
||||
Material,
|
||||
MaterialDamage,
|
||||
MaterialSurface
|
||||
}
|
||||
|
||||
private FilterTypeCascade _filterType = FilterTypeCascade.Type;
|
||||
|
||||
public override void Execute(MinEventParams @params)
|
||||
{
|
||||
var position = @params.Position;
|
||||
if (targetType != TargetTypes.positionAOE)
|
||||
{
|
||||
if (Voxel.voxelRayHitInfo.bHitValid)
|
||||
{
|
||||
var hitInfo = Voxel.voxelRayHitInfo;
|
||||
if (hitInfo == null) return;
|
||||
position = hitInfo.hit.blockPos;
|
||||
}
|
||||
}
|
||||
SpreadFire(position);
|
||||
}
|
||||
|
||||
private void SpreadFire(Vector3 position)
|
||||
{
|
||||
var targetBlock = GameManager.Instance.World.GetBlock(new Vector3i(position));
|
||||
|
||||
var range = (int)maxRange;
|
||||
for (var x = -range; x <= range; x++)
|
||||
{
|
||||
for (var z = -range; z <= range; z++)
|
||||
{
|
||||
for (var y = -range; y <= range; y++)
|
||||
{
|
||||
var vector = new Vector3i(position.x + x, position.y + y, position.z + z);
|
||||
var neighborBlock = GameManager.Instance.World.GetBlock(vector);
|
||||
switch (_filterType)
|
||||
{
|
||||
case FilterTypeCascade.Type:
|
||||
if (neighborBlock.type == targetBlock.type)
|
||||
FireManager.Instance.Add(vector);
|
||||
break;
|
||||
case FilterTypeCascade.Material:
|
||||
if (neighborBlock.Block.blockMaterial.id == targetBlock.Block.blockMaterial.id)
|
||||
FireManager.Instance.Add(vector);
|
||||
break;
|
||||
case FilterTypeCascade.MaterialDamage:
|
||||
if (neighborBlock.Block.blockMaterial.DamageCategory ==
|
||||
targetBlock.Block.blockMaterial.DamageCategory)
|
||||
FireManager.Instance.Add(vector);
|
||||
break;
|
||||
case FilterTypeCascade.MaterialSurface:
|
||||
if (neighborBlock.Block.blockMaterial.SurfaceCategory ==
|
||||
targetBlock.Block.blockMaterial.SurfaceCategory)
|
||||
FireManager.Instance.Add(vector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override bool ParseXmlAttribute(XAttribute attribute)
|
||||
{
|
||||
var flag = base.ParseXmlAttribute(attribute);
|
||||
if (flag) return true;
|
||||
var name = attribute.Name.LocalName;
|
||||
if (name != "filter") return false;
|
||||
_filterType = EnumUtils.Parse<FilterTypeCascade>(attribute.Value, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using JetBrains.Annotations;
|
||||
using System.Xml.Linq;
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if there's any fire blocks within the specified range, using the player's position as center.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example:
|
||||
///
|
||||
/// The cvar specified, by default _closeFires, will contain the number of burning blocks in the range.
|
||||
/// <triggered_effect trigger="onSelfBuffUpdate" action="CheckFireProximity, SCore" range="5" cvar="_closeFires" />
|
||||
/// </remarks>
|
||||
[UsedImplicitly]
|
||||
public class MinEventActionCheckFireProximity : MinEventActionRemoveBuff
|
||||
{
|
||||
string cvar = "_closeFires";
|
||||
|
||||
|
||||
public override void Execute(MinEventParams @params)
|
||||
{
|
||||
if (FireManager.Instance.Enabled == false) return;
|
||||
|
||||
var position = new Vector3i(@params.Self.position);
|
||||
var count = FireManager.Instance.CloseFires(position, (int)maxRange);
|
||||
|
||||
if (count == 0)
|
||||
count = -1;
|
||||
|
||||
@params.Self.Buffs.SetCustomVar(cvar, count);
|
||||
}
|
||||
|
||||
public override bool ParseXmlAttribute(XAttribute attribute)
|
||||
{
|
||||
var flag = base.ParseXmlAttribute(attribute);
|
||||
if (flag) return true;
|
||||
var name = attribute.Name.LocalName;
|
||||
if (name != "cvar") return false;
|
||||
cvar = attribute.Value;
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
46
Score/Fire/Scripts/MinEvent/MinEventActionRemoveFire.cs
Normal file
46
Score/Fire/Scripts/MinEvent/MinEventActionRemoveFire.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
/// <summary>
|
||||
/// Remove Fire within the specified range, using the specified target.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Example:
|
||||
/// This will remove fire from all blocks with a range of 5 from the position of the target.
|
||||
/// <triggered_effect trigger="onSelfDamagedBlock" action="RemoveFire, SCore" target="positionAOE" range="5"/>
|
||||
/// </remarks>
|
||||
[UsedImplicitly]
|
||||
public class MinEventActionRemoveFire : MinEventActionRemoveBuff
|
||||
{
|
||||
private static readonly string AdvFeatureClass = "FireManagement";
|
||||
|
||||
public override void Execute(MinEventParams @params)
|
||||
{
|
||||
if (FireManager.Instance == null) return;
|
||||
if (FireManager.Instance.Enabled == false) return;
|
||||
|
||||
var position = @params.Position;
|
||||
if (targetType != TargetTypes.positionAOE)
|
||||
{
|
||||
if (Voxel.voxelRayHitInfo.bHitValid)
|
||||
{
|
||||
var hitInfo = Voxel.voxelRayHitInfo;
|
||||
if (hitInfo == null) return;
|
||||
position = hitInfo.hit.blockPos;
|
||||
}
|
||||
}
|
||||
|
||||
var range = (int)maxRange;
|
||||
for (var x = -range; x <= range; x++)
|
||||
{
|
||||
for (var z = -range; z <= range; z++)
|
||||
{
|
||||
for (var y = -range; y <= range; y++)
|
||||
{
|
||||
var vector = new Vector3i(position.x + x, position.y + y, position.z + z);
|
||||
if (!FireManager.IsBurning(vector)) continue;
|
||||
FireManager.Instance.Extinguish(vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
/// <summary>
|
||||
/// Distributes the call to all clients to extinguish a block
|
||||
/// </summary>
|
||||
|
||||
[UsedImplicitly]
|
||||
public class NetPackageAddExtinguishPosition : NetPackage
|
||||
{
|
||||
private Vector3i _position;
|
||||
private int _entityThatCausedIt;
|
||||
|
||||
public NetPackageAddExtinguishPosition Setup(Vector3i position, int entityThatCausedIt)
|
||||
{
|
||||
_position = position;
|
||||
_entityThatCausedIt = entityThatCausedIt;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override void read(PooledBinaryReader br)
|
||||
{
|
||||
_position = new Vector3i(br.ReadInt32(), br.ReadInt32(), br.ReadInt32());
|
||||
_entityThatCausedIt = br.ReadInt32();
|
||||
}
|
||||
|
||||
public override void write(PooledBinaryWriter bw)
|
||||
{
|
||||
base.write(bw);
|
||||
bw.Write(_position.x);
|
||||
bw.Write(_position.y);
|
||||
bw.Write(_position.z);
|
||||
bw.Write(_entityThatCausedIt);
|
||||
}
|
||||
|
||||
public override int GetLength()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
public override void ProcessPackage(World world, GameManager callbacks)
|
||||
{
|
||||
if (world == null || FireManager.Instance == null) return;
|
||||
|
||||
FireManager.Instance.ExtinguishBlock(_position);
|
||||
}
|
||||
}
|
||||
|
||||
47
Score/Fire/Scripts/NetPackage/NetPackageAddFirePosition.cs
Normal file
47
Score/Fire/Scripts/NetPackage/NetPackageAddFirePosition.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
/// <summary>
|
||||
/// Distributes the call to all clients to add a block that is considered burning.
|
||||
/// </summary>
|
||||
|
||||
[UsedImplicitly]
|
||||
public class NetPackageAddFirePosition : NetPackage
|
||||
{
|
||||
private Vector3i _position;
|
||||
private int _entityThatCausedIt;
|
||||
|
||||
public NetPackageAddFirePosition Setup(Vector3i position, int entityThatCausedIt)
|
||||
{
|
||||
_position = position;
|
||||
_entityThatCausedIt = entityThatCausedIt;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override void read(PooledBinaryReader br)
|
||||
{
|
||||
_position = new Vector3i(br.ReadInt32(), br.ReadInt32(), br.ReadInt32());
|
||||
_entityThatCausedIt = br.ReadInt32();
|
||||
}
|
||||
|
||||
public override void write(PooledBinaryWriter bw)
|
||||
{
|
||||
base.write(bw);
|
||||
bw.Write(_position.x);
|
||||
bw.Write(_position.y);
|
||||
bw.Write(_position.z);
|
||||
bw.Write(_entityThatCausedIt);
|
||||
}
|
||||
|
||||
public override int GetLength()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
public override void ProcessPackage(World world, GameManager callbacks)
|
||||
{
|
||||
if (world == null || FireManager.Instance == null) return;
|
||||
|
||||
FireManager.Instance.AddBlock(_position);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
/// <summary>
|
||||
/// Distributes the call to all clients to remove a block that is considered burning.
|
||||
/// </summary>
|
||||
|
||||
[UsedImplicitly]
|
||||
public class NetPackageRemoveFirePosition : NetPackage
|
||||
{
|
||||
private Vector3i _position;
|
||||
private int _entityThatCausedIt;
|
||||
|
||||
public NetPackageRemoveFirePosition Setup(Vector3i position, int entityThatCausedIt)
|
||||
{
|
||||
_position = position;
|
||||
_entityThatCausedIt = entityThatCausedIt;
|
||||
return this;
|
||||
}
|
||||
|
||||
public override void read(PooledBinaryReader br)
|
||||
{
|
||||
_position = new Vector3i(br.ReadInt32(), br.ReadInt32(), br.ReadInt32());
|
||||
_entityThatCausedIt = br.ReadInt32();
|
||||
}
|
||||
|
||||
public override void write(PooledBinaryWriter bw)
|
||||
{
|
||||
base.write(bw);
|
||||
bw.Write(_position.x);
|
||||
bw.Write(_position.y);
|
||||
bw.Write(_position.z);
|
||||
bw.Write(_entityThatCausedIt);
|
||||
}
|
||||
|
||||
public override int GetLength()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
public override void ProcessPackage(World world, GameManager callbacks)
|
||||
{
|
||||
if (world == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (FireManager.Instance != null)
|
||||
{
|
||||
FireManager.Instance.RemoveFire(_position);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
/// <summary>
|
||||
/// Distributes the call to remove a particle effect to all clients. This is used by the Fire management system.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This allows us to distribute which block is showing a fire particle.
|
||||
/// </remarks>
|
||||
///
|
||||
[UsedImplicitly]
|
||||
public class NetPackageRemoveParticleEffect : NetPackage
|
||||
{
|
||||
private Vector3i _position;
|
||||
private int _entityThatCausedIt;
|
||||
|
||||
public NetPackageRemoveParticleEffect Setup(Vector3i position, int entityThatCausedIt)
|
||||
{
|
||||
_position = position;
|
||||
_entityThatCausedIt = entityThatCausedIt;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public override void read(PooledBinaryReader br)
|
||||
{
|
||||
_position = new Vector3i(br.ReadInt32(), br.ReadInt32(), br.ReadInt32());
|
||||
_entityThatCausedIt = br.ReadInt32();
|
||||
}
|
||||
|
||||
public override void write(PooledBinaryWriter bw)
|
||||
{
|
||||
base.write(bw);
|
||||
bw.Write(_position.x);
|
||||
bw.Write(_position.y);
|
||||
bw.Write(_position.z);
|
||||
bw.Write(_entityThatCausedIt);
|
||||
}
|
||||
|
||||
public override int GetLength()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
public override void ProcessPackage(World world, GameManager callbacks)
|
||||
{
|
||||
if (world == null || FireManager.Instance == null) return;
|
||||
|
||||
FireManager.Instance.ClearPosOnly(_position);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user