diff --git a/NewHorizons/Builder/Body/RingBuilder.cs b/NewHorizons/Builder/Body/RingBuilder.cs index 805bdf59..f9a7d105 100644 --- a/NewHorizons/Builder/Body/RingBuilder.cs +++ b/NewHorizons/Builder/Body/RingBuilder.cs @@ -77,29 +77,47 @@ namespace NewHorizons.Builder.Body rot._localAxis = Vector3.down; } - // Collider can't be concave so nvm - /* - var collider = new GameObject("Collider"); - collider.SetActive(false); - collider.transform.parent = ringGO.transform; - collider.transform.localPosition = Vector3.zero; - collider.transform.localScale = Vector3.one; - collider.layer = 17; + // Funny collider thing + var ringVolume = new GameObject("RingVolume"); + ringVolume.SetActive(false); + ringVolume.transform.parent = ringGO.transform; + ringVolume.transform.localPosition = Vector3.zero; + ringVolume.transform.localScale = Vector3.one; + ringVolume.transform.localRotation = Quaternion.identity; + ringVolume.layer = LayerMask.NameToLayer("BasicEffectVolume"); - var mf = collider.AddComponent(); - mf.mesh = ringMesh; + var ringShape = ringVolume.AddComponent(); + ringShape.innerRadius = ring.InnerRadius; + ringShape.outerRadius = ring.OuterRadius; + ringShape.height = 2f; + ringShape.center = Vector3.zero; + ringShape.SetCollisionMode(Shape.CollisionMode.Volume); + ringShape.SetLayer(Shape.Layer.Default); + ringShape.layerMask = -1; + ringShape.pointChecksOnly = true; + + var trigger = ringVolume.AddComponent(); + trigger._shape = ringShape; - var mc = collider.AddComponent(); - mc.isTrigger = true; + var sfv = ringVolume.AddComponent(); + var fluidType = FluidVolume.Type.NONE; - var owCollider = collider.AddComponent(); - var trigger = collider.AddComponent(); - var sfv = collider.AddComponent(); - sfv._fluidType = FluidVolume.Type.SAND; - sfv._density = 2f; + if(!string.IsNullOrEmpty(ring.FluidType)) + { + try + { + fluidType = (FluidVolume.Type)Enum.Parse(typeof(FluidVolume.Type), ring.FluidType.ToUpper()); + } + catch (Exception ex) + { + Logger.LogError($"Couldn't parse fluid volume type [{ring.FluidType}]: {ex.Message}, {ex.StackTrace}"); + } + } - collider.SetActive(true); - */ + sfv._fluidType = fluidType; + sfv._density = 1f; + + ringVolume.SetActive(true); if (ring.Curve != null) { diff --git a/NewHorizons/Components/RingShape.cs b/NewHorizons/Components/RingShape.cs new file mode 100644 index 00000000..cb35b9e2 --- /dev/null +++ b/NewHorizons/Components/RingShape.cs @@ -0,0 +1,262 @@ +using System.Collections.Generic; +using UnityEngine; +using Logger = NewHorizons.Utility.Logger; + +namespace NewHorizons.Components +{ + public class RingShape : Shape + { + private Vector3 _center; + private float _innerRadius; + private float _outerRadius; + private float _height; + + private CylinderShape _innerCylinderShape; + private CylinderShape _outerCylinderShape; + + public Vector3 center + { + get { return _center; } + set + { + _center = value; + RecalculateLocalBounds(); + } + } + + public float innerRadius + { + get { return _innerRadius; } + set + { + _innerRadius = Mathf.Max(value, 0f); + RecalculateLocalBounds(); + + if (_innerCylinderShape) _innerCylinderShape.radius = _innerRadius; + } + } + + public float outerRadius + { + get { return _outerRadius; } + set + { + _outerRadius = Mathf.Max(value, 0f); + RecalculateLocalBounds(); + + if (_outerCylinderShape) _outerCylinderShape.radius = _outerRadius; + } + } + + public float height + { + get { return _height; } + set + { + _height = Mathf.Max(value, 0f); + RecalculateLocalBounds(); + + if (_innerCylinderShape) _innerCylinderShape.height = height + 30; + if (_outerCylinderShape) _outerCylinderShape.height = height; + } + } + + public override int layerMask + { + get { return base.layerMask; } + set + { + base.layerMask = value; + if (_innerCylinderShape) _innerCylinderShape.layerMask = value; + if (_outerCylinderShape) _outerCylinderShape.layerMask = value; + } + } + + public override bool pointChecksOnly + { + get { return base.pointChecksOnly; } + set + { + base.pointChecksOnly = value; + if (_innerCylinderShape) _innerCylinderShape.pointChecksOnly = value; + if (_outerCylinderShape) _outerCylinderShape.pointChecksOnly = value; + } + } + + public override void Awake() + { + base.Awake(); + + var innerCylinderGO = new GameObject("InnerCylinder"); + innerCylinderGO.layer = gameObject.layer; + innerCylinderGO.transform.parent = transform; + innerCylinderGO.transform.localPosition = Vector3.zero; + innerCylinderGO.transform.localRotation = Quaternion.identity; + _innerCylinderShape = innerCylinderGO.AddComponent(); + innerCylinderGO.AddComponent(); + _innerCylinderShape.OnCollisionEnter += OnInnerCollisionEnter; + _innerCylinderShape.OnCollisionExit += OnInnerCollisionExit; + + _innerCylinderShape.center = center; + _innerCylinderShape.height = height + 30; + _innerCylinderShape.radius = innerRadius; + _innerCylinderShape.layerMask = layerMask; + _innerCylinderShape.pointChecksOnly = pointChecksOnly; + + var outerCylinderGO = new GameObject("OuterCylinder"); + outerCylinderGO.layer = gameObject.layer; + outerCylinderGO.transform.parent = transform; + outerCylinderGO.transform.localPosition = Vector3.zero; + outerCylinderGO.transform.localRotation = Quaternion.identity; + _outerCylinderShape = outerCylinderGO.AddComponent(); + outerCylinderGO.AddComponent(); + _outerCylinderShape.OnCollisionEnter += OnOuterCollisionEnter; + _outerCylinderShape.OnCollisionExit += OnOuterCollisionExit; + + _outerCylinderShape.center = center; + _outerCylinderShape.height = height; + _outerCylinderShape.radius = outerRadius; + _outerCylinderShape.layerMask = layerMask; + _outerCylinderShape.pointChecksOnly = pointChecksOnly; + } + + public void OnDestroy() + { + if (_innerCylinderShape) + { + _innerCylinderShape.OnCollisionEnter -= OnInnerCollisionEnter; + _innerCylinderShape.OnCollisionExit -= OnInnerCollisionExit; + } + + if (_outerCylinderShape) + { + _outerCylinderShape.OnCollisionEnter -= OnOuterCollisionEnter; + _outerCylinderShape.OnCollisionExit -= OnOuterCollisionExit; + } + } + + public void Start() + { + RecalculateLocalBounds(); + } + + public override void OnEnable() + { + base.OnEnable(); + _innerCylinderShape?.OnEnable(); + _outerCylinderShape?.OnEnable(); + } + + public override void OnDisable() + { + base.OnDisable(); + _innerCylinderShape?.OnDisable(); + _outerCylinderShape?.OnDisable(); + } + + public override void SetCollisionMode(CollisionMode newCollisionMode) + { + base.SetCollisionMode(newCollisionMode); + _innerCylinderShape?.SetCollisionMode(newCollisionMode); + _outerCylinderShape?.SetCollisionMode(newCollisionMode); + } + + public override void SetLayer(Layer newLayer) + { + base.SetLayer(newLayer); + _innerCylinderShape?.SetLayer(newLayer); + _outerCylinderShape?.SetLayer(newLayer); + } + + public override void SetActivation(bool newActive) + { + base.SetActivation(newActive); + _innerCylinderShape?.SetActivation(newActive); + _outerCylinderShape?.SetActivation(newActive); + } + + public override Vector3 GetWorldSpaceCenter() + { + return transform.TransformPoint(_center); + } + + public override void RecalculateLocalBounds() + { + localBounds.Set(_center, outerRadius); + } + + public override bool PointInside(Vector3 point) + { + return (!_innerCylinderShape.PointInside(point) && _outerCylinderShape.PointInside(point)); + } + + private List _shapesInInner = new List(); + private List _shapesInOuter = new List(); + private List _shapesInside = new List(); + + private void UpdateCollisionStatus(Shape shape) + { + var inside = _shapesInside.Contains(shape); + var insideInner = _shapesInInner.Contains(shape); + var insideOuter = _shapesInOuter.Contains(shape); + + if (inside) + { + // If we've moved into the inner cylinder then we're not in the ring + // If we've excited the outer radius we're not in the ring either + if (insideInner || !insideOuter) + { + //Logger.Log($"Shape [{shape}] exited ring"); + FireCollisionExitEvent(shape); + _shapesInside.Remove(shape); + } + } + else + { + // If we've moved into the outer cylinder but not the inner one, we're now in the ring + if (insideOuter && !insideInner) + { + //Logger.Log($"Shape [{shape}] entered ring"); + FireCollisionEnterEvent(shape); + _shapesInside.Add(shape); + } + } + } + + public void OnInnerCollisionEnter(Shape shape) + { + //Logger.Log($"Shape [{shape}] entered inner radius"); + + _shapesInInner.Add(shape); + + UpdateCollisionStatus(shape); + } + + public void OnInnerCollisionExit(Shape shape) + { + //Logger.Log($"Shape [{shape}] exited inner radius"); + + _shapesInInner.Remove(shape); + + UpdateCollisionStatus(shape); + } + + public void OnOuterCollisionEnter(Shape shape) + { + //Logger.Log($"Shape [{shape}] entered outer radius"); + + _shapesInOuter.Add(shape); + + UpdateCollisionStatus(shape); + } + + public void OnOuterCollisionExit(Shape shape) + { + //Logger.Log($"Shape [{shape}] exited outer radius"); + + _shapesInOuter.Remove(shape); + + UpdateCollisionStatus(shape); + } + } +} diff --git a/NewHorizons/External/VariableSize/RingModule.cs b/NewHorizons/External/VariableSize/RingModule.cs index 60a6cd2d..86cda68c 100644 --- a/NewHorizons/External/VariableSize/RingModule.cs +++ b/NewHorizons/External/VariableSize/RingModule.cs @@ -15,5 +15,6 @@ namespace NewHorizons.External.VariableSize public string Texture { get; set; } public bool Unlit { get; set; } = false; public float RotationSpeed { get; set; } = 0f; + public string FluidType { get; set; } } } diff --git a/NewHorizons/schema.json b/NewHorizons/schema.json index 99d8aebc..eaf6d622 100644 --- a/NewHorizons/schema.json +++ b/NewHorizons/schema.json @@ -421,6 +421,18 @@ "default": 0, "description": "Allows the rings to rotate." }, + "fluidType": { + "type": "string", + "default": "NONE", + "description": "Fluid type for sounds/effects when colliding with this ring.", + "enum": [ + "NONE", + "WATER", + "CLOUD", + "SAND", + "PLASMA" + ] + }, "curve": { "$ref": "#/$defs/curve", "description": "Allows the rings to grow/shrink with time."