diff --git a/CHANGELOG.md b/CHANGELOG.md index 5093920c6..7f16fd730 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Built with Unity 2021.2. ### Added +- We got a new game item called *Metal Wire Guide* (thanks @Cupiii, [#366](https://github.com/freezy/VisualPinball.Engine/pull/366)) - A *Collision Switch* component ([#344](https://github.com/freezy/VisualPinball.Engine/pull/344), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/collision-switches.html)). - A *Rotator* component ([#337](https://github.com/freezy/VisualPinball.Engine/pull/337), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/rotators.html)). - A *Teleporter* component ([#336](https://github.com/freezy/VisualPinball.Engine/pull/336), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/teleporters.html)). diff --git a/VisualPinball.Engine.Test/Fixtures~/MetalWireGuideTest.vpx b/VisualPinball.Engine.Test/Fixtures~/MetalWireGuideTest.vpx new file mode 100644 index 000000000..3b0863c5a Binary files /dev/null and b/VisualPinball.Engine.Test/Fixtures~/MetalWireGuideTest.vpx differ diff --git a/VisualPinball.Engine.Test/Test/Fixtures.cs b/VisualPinball.Engine.Test/Test/Fixtures.cs index c8d84c947..db138eccd 100644 --- a/VisualPinball.Engine.Test/Test/Fixtures.cs +++ b/VisualPinball.Engine.Test/Test/Fixtures.cs @@ -53,6 +53,7 @@ public static class VpxPath public static readonly string Timer = PathHelper.GetFixturePath("TimerTest.vpx"); public static readonly string Trigger = PathHelper.GetFixturePath("TriggerTest.vpx"); public static readonly string Trough = PathHelper.GetFixturePath("TroughTest.vpx"); + public static readonly string MetalWireGuide = PathHelper.GetFixturePath("MetalWireGuideTest.vpx"); } public static class ObjPath @@ -79,6 +80,7 @@ public static class ObjPath public static readonly string Surface = PathHelper.GetFixturePath("SurfaceTest.obj"); public static readonly string Table = PathHelper.GetFixturePath("TableTest.obj"); public static readonly string Trigger = PathHelper.GetFixturePath("TriggerTest.obj"); + public static readonly string MetalWireGuide = PathHelper.GetFixturePath("MetalWireGuideTest.obj"); } public static class TexturePath diff --git a/VisualPinball.Engine.Test/VPT/MetalWireGuide/MetalWireDataTests.cs b/VisualPinball.Engine.Test/VPT/MetalWireGuide/MetalWireDataTests.cs new file mode 100644 index 000000000..6550c0eb5 --- /dev/null +++ b/VisualPinball.Engine.Test/VPT/MetalWireGuide/MetalWireDataTests.cs @@ -0,0 +1,103 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.IO; +using FluentAssertions; +using NUnit.Framework; +using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.MetalWireGuide; +using VisualPinball.Engine.VPT.Table; + +namespace VisualPinball.Engine.Test.VPT.MetalWireGuide +{ + public class MetalWireGuideDataTests + { + [Test] + public void ShouldReadMetalWireGuideData() + { + var table = FileTableContainer.Load(VpxPath.MetalWireGuide); + ValidateMetalWireGuideData1(table.MetalWireGuide("MetalWireGuide1").Data); + ValidateMetalWireGuideData2(table.MetalWireGuide("MetalWireGuide2").Data); + } + + [Test] + public void ShouldWriteMetalWireGuideData() + { + const string tmpFileName = "ShouldWriteMetalWireGuideData.vpx"; + var table = FileTableContainer.Load(VpxPath.MetalWireGuide); + table.Save(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); + ValidateMetalWireGuideData1(writtenTable.MetalWireGuide("MetalWireGuide1").Data); + ValidateMetalWireGuideData2(writtenTable.MetalWireGuide("MetalWireGuide2").Data); + File.Delete(tmpFileName); + } + + public static void ValidateMetalWireGuideData1(MetalWireGuideData data) + { + data.DragPoints.Length.Should().Be(3); + /* Todo: Test :-) + data.Elasticity.Should().Be(0.832f); + data.ElasticityFalloff.Should().Be(0.321f); + data.Friction.Should().Be(0.685f); + data.Height.Should().Be(25.556f); + data.HitEvent.Should().Be(false); + data.HitHeight.Should().Be(25.193f); + data.Image.Should().Be("test_pattern"); + data.IsCollidable.Should().Be(true); + data.IsReflectionEnabled.Should().Be(true); + data.IsVisible.Should().Be(true); + data.Material.Should().Be("Playfield"); + data.OverwritePhysics.Should().Be(true); + data.PhysicsMaterial.Should().Be(""); + data.RotX.Should().Be(65.23f); + data.RotY.Should().Be(75.273f); + data.RotZ.Should().Be(70.962f); + data.Scatter.Should().Be(5.225f); + data.ShowInEditor.Should().Be(false); + data.StaticRendering.Should().Be(true); + data.Thickness.Should().Be(12); + data.Points.Should().Be(true); + */ + } + + public static void ValidateMetalWireGuideData2(MetalWireGuideData data) + { + data.DragPoints.Length.Should().Be(2); + /* Todo Tests... :-) + data.Elasticity.Should().Be(0.8f); + data.ElasticityFalloff.Should().Be(0.3f); + data.Friction.Should().Be(0.6f); + data.Height.Should().Be(25f); + data.HitEvent.Should().Be(false); + data.HitHeight.Should().Be(25f); + data.Image.Should().Be(""); + data.IsCollidable.Should().Be(false); + data.IsReflectionEnabled.Should().Be(true); + data.IsVisible.Should().Be(true); + data.Material.Should().Be(""); + data.OverwritePhysics.Should().Be(true); + data.PhysicsMaterial.Should().Be(""); + data.RotX.Should().Be(0f); + data.RotY.Should().Be(0f); + data.RotZ.Should().Be(0f); + data.Scatter.Should().Be(5f); + data.ShowInEditor.Should().Be(false); + data.StaticRendering.Should().Be(false); + data.Thickness.Should().Be(8); + */ + } + } +} diff --git a/VisualPinball.Engine.Test/VPT/MetalWireGuide/MetalWireMeshTest.cs b/VisualPinball.Engine.Test/VPT/MetalWireGuide/MetalWireMeshTest.cs new file mode 100644 index 000000000..f02928d1d --- /dev/null +++ b/VisualPinball.Engine.Test/VPT/MetalWireGuide/MetalWireMeshTest.cs @@ -0,0 +1,49 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using JeremyAnsel.Media.WavefrontObj; +using NUnit.Framework; +using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; + +namespace VisualPinball.Engine.Test.VPT.MetalWireGuide +{ + public class MetalWireGuideMeshTest : MeshTests + { + private readonly FileTableContainer _tc; + private readonly ObjFile _obj; + + public MetalWireGuideMeshTest() + { + _tc = FileTableContainer.Load(VpxPath.MetalWireGuide); + _obj = LoadObjFixture(ObjPath.MetalWireGuide); + } + + //[Test] todo fix (and change for MetalWireGuide) + //public void ShouldGenerateMesh() + //{ + // var rubberMesh = _tc.Rubber("Rubber2").GetRenderObjects(_tc.Table).RenderObjects[0].Mesh; + // AssertObjMesh(_obj, rubberMesh, threshold: 0.00015f); + //} + + // [Test] todo fix (and change for MetalWireGuide) + //public void ShouldGenerateThickMesh() + //{ + // var rubberMesh = _tc.Rubber("Rubber1").GetRenderObjects(_tc.Table).RenderObjects[0].Mesh; + // AssertObjMesh(_obj, rubberMesh, threshold: 0.001f); + //} + } +} diff --git a/VisualPinball.Engine.Test/VisualPinball.Engine.Test.csproj b/VisualPinball.Engine.Test/VisualPinball.Engine.Test.csproj index 7ff303131..4b7be23a6 100644 --- a/VisualPinball.Engine.Test/VisualPinball.Engine.Test.csproj +++ b/VisualPinball.Engine.Test/VisualPinball.Engine.Test.csproj @@ -5,7 +5,7 @@ true VisualPinball.Engine.Test A .NET port of Visual Pinball in C# - freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli + freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli;Cupid Copyright 2021 freezy - <freezy@vpdb.io> 0.1.0.0 0.1.0.0 diff --git a/VisualPinball.Engine/Math/SplineVertex.cs b/VisualPinball.Engine/Math/SplineVertex.cs index a098fd5fb..0ba292219 100644 --- a/VisualPinball.Engine/Math/SplineVertex.cs +++ b/VisualPinball.Engine/Math/SplineVertex.cs @@ -39,19 +39,31 @@ public class SplineVertex public Vertex2D[] RgvLocal; - public SplineVertex(DragPointData[] dragPoints, int thickness, int tableDetailLevel, float accuracy, bool staticRendering = true, float margin = 0f) + public SplineVertex(DragPointData[] dragPoints, int thickness, int tableDetailLevel, float accuracy, bool staticRendering = true, float margin = 0f, bool loop = true) { - var vertices = GetCentralCurve(dragPoints, tableDetailLevel, accuracy, staticRendering); + var vertices = GetCentralCurve(dragPoints, tableDetailLevel, accuracy, staticRendering, loop: loop); var numVertices = vertices.Length; Cross = new bool[numVertices + 1]; MiddlePoints = new Vertex2D[numVertices + 1]; RgvLocal = new Vertex2D[(numVertices + 1) * 2]; - for (var i = 0; i < numVertices; i++) { - // prev and next wrap around as rubbers always loop + for (var i = 0; i < numVertices; i++) + { + // prev and next wrap around in loops var prev = vertices[i > 0 ? i - 1 : numVertices - 1]; var next = vertices[i < numVertices - 1 ? i + 1 : 0]; + + // .. but have to be corrected at start and end with "virtual vertices" continuing the spline when not looping, so cuts perpendicular to the tangents + // maybe fix ramps after that that also hat the same problem. + if (!loop && i == 0) { + prev = new RenderVertex2D(vertices[0].X*2-vertices[1].X, vertices[0].Y * 2 - vertices[1].Y); + } + if (!loop && i == (numVertices-1)) + { + next = new RenderVertex2D(vertices[numVertices-1].X * 2 - vertices[numVertices - 2].X, vertices[numVertices - 1].Y * 2 - vertices[numVertices - 2].Y); + } + var middle = vertices[i]; Cross[i] = middle.IsControlPoint; @@ -63,12 +75,13 @@ public SplineVertex(DragPointData[] dragPoints, int thickness, int tableDetailLe var normal1 = new Vertex2D(prev.Y - middle.Y, middle.X - prev.X); // vector vmiddle-vprev rotated RIGHT var normal2 = new Vertex2D(middle.Y - next.Y, next.X - middle.X); // vector vnext-vmiddle rotated RIGHT - // not needed special start/end handling as rubbers always loop, except for the case where there are only 2 control points - if (numVertices == 2 && i == numVertices - 1) { + // not needed special start/end handling as rubbers always loop, except for the case where there are only 2 control points + // I guess this does not work as intended, but could not figure out what was wrong. i think that somehow the normal of Node 1 is wrong. /cupiii + if (numVertices == 2 && i == numVertices - 1) { normal1.Normalize(); normal = normal1; - } else if (numVertices == 2 && i == 0) { + } else if (numVertices == 2 && i == 0) { normal2.Normalize(); normal = normal2; @@ -121,12 +134,17 @@ public SplineVertex(DragPointData[] dragPoints, int thickness, int tableDetailLe } } - Cross[numVertices] = vertices[0].IsControlPoint; - MiddlePoints[numVertices] = MiddlePoints[0]; - VertexCount = numVertices + 1; + if (loop) + VertexCount = numVertices; + else + { + MiddlePoints[numVertices] = MiddlePoints[0]; + Cross[numVertices] = vertices[0].IsControlPoint; + VertexCount = numVertices + 1; + } } - private static RenderVertex2D[] GetCentralCurve(DragPointData[] dragPoints, int tableDetailLevel, float acc, bool staticRendering = true) + private static RenderVertex2D[] GetCentralCurve(DragPointData[] dragPoints, int tableDetailLevel, float acc, bool staticRendering = true, bool loop = true) { float accuracy; @@ -141,7 +159,7 @@ private static RenderVertex2D[] GetCentralCurve(DragPointData[] dragPoints, int accuracy = 4.0f * MathF.Pow(10.0f, (10.0f - accuracy) * (float) (1.0 / 1.5)); } - return DragPoint.GetRgVertex(dragPoints, true, accuracy); + return DragPoint.GetRgVertex(dragPoints, loop, accuracy); } } } diff --git a/VisualPinball.Engine/VPT/ItemType.cs b/VisualPinball.Engine/VPT/ItemType.cs index a0d8cc706..b81a144e2 100644 --- a/VisualPinball.Engine/VPT/ItemType.cs +++ b/VisualPinball.Engine/VPT/ItemType.cs @@ -50,6 +50,7 @@ public enum ItemType Rubber = 21, HitTarget = 22, Count = 23, + MetalWireGuide = 24, Invalid = -1, // VPE internal diff --git a/VisualPinball.Engine/VPT/MetalWireGuide.meta b/VisualPinball.Engine/VPT/MetalWireGuide.meta new file mode 100644 index 000000000..03d3286dc --- /dev/null +++ b/VisualPinball.Engine/VPT/MetalWireGuide.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d2b47637016044e449395b9302c7a858 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Engine/VPT/MetalWireGuide/IMetalWireGuideData.cs b/VisualPinball.Engine/VPT/MetalWireGuide/IMetalWireGuideData.cs new file mode 100644 index 000000000..f442bfc82 --- /dev/null +++ b/VisualPinball.Engine/VPT/MetalWireGuide/IMetalWireGuideData.cs @@ -0,0 +1,31 @@ +// Visual Pinball Engine +// Copyright (C) 2020 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using VisualPinball.Engine.Math; + +namespace VisualPinball.Engine.VPT.MetalWireGuide +{ + public interface IMetalWireGuideData + { + DragPointData[] DragPoints { get; } + int Thickness { get; } + float Height { get; } + float Bendradius { get; } + float RotX { get; } + float RotY { get; } + float RotZ { get; } + } +} diff --git a/VisualPinball.Engine/VPT/MetalWireGuide/IMetalWireGuideData.cs.meta b/VisualPinball.Engine/VPT/MetalWireGuide/IMetalWireGuideData.cs.meta new file mode 100644 index 000000000..852a6c96a --- /dev/null +++ b/VisualPinball.Engine/VPT/MetalWireGuide/IMetalWireGuideData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c04bd7143df8951498caba013fd1002c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuide.cs b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuide.cs new file mode 100644 index 000000000..068f9c05a --- /dev/null +++ b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuide.cs @@ -0,0 +1,69 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.IO; +using VisualPinball.Engine.Game; +using VisualPinball.Engine.Math; + +namespace VisualPinball.Engine.VPT.MetalWireGuide +{ + public class MetalWireGuide : Item, IRenderable + { + public override string ItemGroupName => "MetalWireGuides"; + + public readonly MetalWireGuideMeshGenerator MeshGenerator; + + public MetalWireGuide(MetalWireGuideData data) : base(data) + { + MeshGenerator = new MetalWireGuideMeshGenerator(Data); + } + + public MetalWireGuide(BinaryReader reader, string itemName) : this(new MetalWireGuideData(reader, itemName)) + { + } + + public static MetalWireGuide GetDefault(Table.Table table) + { + var x = table.Width / 2f; + var y = table.Height / 2f; + var metalWireGuideData = new MetalWireGuideData(table.GetNewName("MetalWireGuide")) { + DragPoints = new[] { + new DragPointData(x, y - 100f) {IsSmooth = true }, + new DragPointData(x - 50f * MathF.Cos(MathF.PI / 4), y - 50f * MathF.Sin(MathF.PI / 4)) {IsSmooth = true }, + new DragPointData(x - 50f, y) {IsSmooth = true }, + new DragPointData(x - 50f * MathF.Cos(MathF.PI / 4), y + 50f * MathF.Sin(MathF.PI / 4)) {IsSmooth = true }, + new DragPointData(x, y + 50f) {IsSmooth = true }, + new DragPointData(x + 50f * MathF.Cos(MathF.PI / 4), y + 50f * MathF.Sin(MathF.PI / 4)) {IsSmooth = true }, + new DragPointData(x + 50f, y) {IsSmooth = true }, + new DragPointData(x + 50f * MathF.Cos(MathF.PI / 4), y - 50f * MathF.Sin(MathF.PI / 4)) {IsSmooth = true }, + } + }; + return new MetalWireGuide(metalWireGuideData); + } + + #region IRenderable + + Matrix3D IRenderable.TransformationMatrix(Table.Table table, Origin origin) => Matrix3D.Identity; + public Mesh GetMesh(string id, Table.Table table, Origin origin = Origin.Global, bool asRightHanded = true) + { + return MeshGenerator.GetMesh(table, Data); + } + + public PbrMaterial GetMaterial(string id, Table.Table table) => MeshGenerator.GetMaterial(table, Data); + + #endregion + } +} diff --git a/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuide.cs.meta b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuide.cs.meta new file mode 100644 index 000000000..59e05327e --- /dev/null +++ b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuide.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2465aad86669bea46bd07c503813aea7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideData.cs b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideData.cs new file mode 100644 index 000000000..1618a898b --- /dev/null +++ b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideData.cs @@ -0,0 +1,149 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#region ReSharper +// ReSharper disable UnassignedField.Global +// ReSharper disable StringLiteralTypo +// ReSharper disable FieldCanBeMadeReadOnly.Global +// ReSharper disable ConvertToConstant.Global +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using VisualPinball.Engine.IO; +using VisualPinball.Engine.Math; +using VisualPinball.Engine.VPT.Table; + +namespace VisualPinball.Engine.VPT.MetalWireGuide +{ + [Serializable] + public class MetalWireGuideData : ItemData, IMetalWireGuideData + { + public override string GetName() => Name; + public override void SetName(string name) { Name = name; } + + [BiffString("NAME", IsWideString = true, Pos = 8)] + public string Name = string.Empty; + + [BiffFloat("HTTP", Pos = 1)] + public float Height { get; set; } = 25f; + + [BiffFloat("HTHI", Pos = 2)] + public float HitHeight { get; set; } = 25f; + + [BiffInt("WDTP", Pos = 3)] + public int Thickness { get; set; } = 8; + + [BiffFloat("HTRD", Pos = 22)] + public float Bendradius { get; set; } = 8f; + + [BiffBool("HTEV", Pos = 4)] + public bool HitEvent = false; + + [BiffString("MATR", Pos = 5)] + public string Material = string.Empty; + + [BiffString("IMAG", Pos = 9)] + public string Image = string.Empty; + + [BiffFloat("ELAS", Pos = 10)] + public float Elasticity; + + [BiffFloat("ELFO", Pos = 11)] + public float ElasticityFalloff; + + [BiffFloat("RFCT", Pos = 12)] + public float Friction; + + [BiffFloat("RSCT", Pos = 13)] + public float Scatter; + + [BiffBool("CLDR", Pos = 14)] + public bool IsCollidable = true; + + [BiffBool("RVIS", Pos = 15)] + public bool IsVisible = true; + + [BiffBool("REEN", Pos = 21)] + public bool IsReflectionEnabled = true; + + [BiffBool("ESTR", Pos = 16)] + public bool StaticRendering = true; + + [BiffBool("ESIE", Pos = 17)] + public bool ShowInEditor = true; + + [BiffFloat("ROTX", Pos = 18)] + public float RotX { get; set; } = 0f; + + [BiffFloat("ROTY", Pos = 19)] + public float RotY { get; set; } = 0f; + + [BiffFloat("ROTZ", Pos = 20)] + public float RotZ { get; set; } = 0f; + + [BiffString("MAPH", Pos = 22)] + public string PhysicsMaterial = string.Empty; + + [BiffBool("OVPH", Pos = 23)] + public bool OverwritePhysics = false; + + [BiffDragPoint("DPNT", TagAll = true, Pos = 2000)] + public DragPointData[] DragPoints { get; set; } + + [BiffBool("TMON", Pos = 6)] + public bool IsTimerEnabled; + + [BiffInt("TMIN", Pos = 7)] + public int TimerInterval; + + [BiffTag("PNTS", Pos = 1999)] + public bool Points; + + public MetalWireGuideData() : base(StoragePrefix.GameItem) + { + } + + public MetalWireGuideData(string name) : base(StoragePrefix.GameItem) + { + Name = name; + } + + #region BIFF + + static MetalWireGuideData() + { + Init(typeof(MetalWireGuideData), Attributes); + } + + public MetalWireGuideData(BinaryReader reader, string storageName) : base(storageName) + { + Load(this, reader, Attributes); + } + + public override void Write(BinaryWriter writer, HashWriter hashWriter) + { + writer.Write((int)ItemType.MetalWireGuide); + WriteRecord(writer, Attributes, hashWriter); + WriteEnd(writer, hashWriter); + } + + private static readonly Dictionary> Attributes = new Dictionary>(); + + #endregion + } +} diff --git a/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideData.cs.meta b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideData.cs.meta new file mode 100644 index 000000000..fd529d5a8 --- /dev/null +++ b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41d6cb564dddd52499250e5a44a02176 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideMeshGenerator.cs b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideMeshGenerator.cs new file mode 100644 index 000000000..62ca3ad69 --- /dev/null +++ b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideMeshGenerator.cs @@ -0,0 +1,237 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable CompareOfFloatsByEqualityOperator + +#nullable enable + +using VisualPinball.Engine.Common; +using VisualPinball.Engine.Game; +using VisualPinball.Engine.Math; + +namespace VisualPinball.Engine.VPT.MetalWireGuide +{ + public class MetalWireGuideMeshGenerator + { + private readonly IMetalWireGuideData _data; + + private Vertex3D _middlePoint; + + public MetalWireGuideMeshGenerator(IMetalWireGuideData data) + { + _data = data; + } + + public Mesh GetTransformedMesh(float playfieldHeight, float meshHeight, int detailLevel, float bendradius, int acc = -1, bool createHitShape = false, float margin = 0f) + { + var mesh = GetMesh(playfieldHeight, meshHeight, detailLevel, bendradius, acc, createHitShape, margin); + return mesh.Transform(GetRotationMatrix()); + } + + public Mesh GetMesh(Table.Table table, MetalWireGuideData metalWireGuideData) + { + var mesh = GetTransformedMesh(table.TableHeight, _data.Height, table.GetDetailLevel(), _data.Bendradius); + mesh.Name = metalWireGuideData.Name; + var preMatrix = new Matrix3D(); + preMatrix.SetTranslation(0, 0, -_data.Height); + return mesh.Transform(preMatrix); + } + + public PbrMaterial GetMaterial(Table.Table table, MetalWireGuideData metalWireGuideData) + { + return new PbrMaterial(table.GetMaterial(metalWireGuideData.Material), table.GetTexture(metalWireGuideData.Image)); + } + + private Matrix3D GetRotationMatrix() + { + var fullMatrix = new Matrix3D(); + var tempMat = new Matrix3D(); + + tempMat.SetTranslation(-_middlePoint.X, -_middlePoint.Y, -_middlePoint.Z); + fullMatrix.Multiply(tempMat, fullMatrix); + + tempMat.RotateZMatrix(MathF.DegToRad(_data.RotZ)); + fullMatrix.Multiply(tempMat); + tempMat.RotateYMatrix(MathF.DegToRad(_data.RotY)); + fullMatrix.Multiply(tempMat); + tempMat.RotateXMatrix(MathF.DegToRad(_data.RotX)); + fullMatrix.Multiply(tempMat); + + tempMat.SetTranslation(_middlePoint.X, _middlePoint.Y, _middlePoint.Z); + fullMatrix.Multiply(tempMat); + + return fullMatrix; + } + + private Mesh GetMesh(float playfieldHeight, float meshHeight, int detailLevel, float bendradius, int acc = -1, bool createHitShape = false, float margin = 0f) + { + var mesh = new Mesh(); + // i dont understand the calculation of splineaccuracy here /cupiii + var accuracy = (int)(10.0f * 1.2f); + if (acc != -1) { // hit shapes and UI display have the same, static, precision + accuracy = acc; + } + + var splineAccuracy = acc != -1 ? 4.0f * MathF.Pow(10.0f, (10.0f - PhysicsConstants.HitShapeDetailLevel) * (float)(1.0 / 1.5)) : -1.0f; + SplineVertex sv = new SplineVertex(_data.DragPoints, _data.Thickness, detailLevel, splineAccuracy, margin: margin, loop: false); + + var height = playfieldHeight + meshHeight; + // hack - Component has to get edited. --- and TODO: Thickness should become a float. + var standheight = 50; + + // one ring for each Splinevertex, two for the stands, and "bendradius" tomes two for the bend (should be enough) + // todo: could be better, if accuracy was taken into account + var numRingsInBend = (int)(bendradius + 1); + var numRings = sv.VertexCount-1 + numRingsInBend * 2 + 2; + var numSegments = accuracy; + + var up = new Vertex3D(0f, 0f, 1f); + var points = new Vertex3D[numRings]; // middlepoints of rings + var tangents = new Vertex3D[numRings]; // pointing into the direction of the spline, even first and last + var right = new Vertex3D[numRings]; // pointing right, looking into tangent direction + var down = new Vertex3D[numRings]; // pointing down from tangent view + var accLength = new float[numRings]; // accumulated length of the wire beginning at 0; + + // copy the data from the pline into the middle of the new variables + for (int i = 0; i < sv.VertexCount-1; i++) + { + points[i + numRingsInBend + 1] = new Vertex3D(sv.MiddlePoints[i].X, sv.MiddlePoints[i].Y, height); + right[i + numRingsInBend + 1] = new Vertex3D(sv.RgvLocal[i].X - sv.MiddlePoints[i].X, sv.RgvLocal[i].Y - sv.MiddlePoints[i].Y, 0f); + right[i + numRingsInBend + 1].Normalize(); + tangents[i + numRingsInBend + 1] = Vertex3D.CrossProduct(right[i + numRingsInBend + 1], new Vertex3D(0f, 0f, 1f)); + tangents[i + numRingsInBend + 1].Normalize(); + } + + // first set up beginning of the stand + points[0] = points[numRingsInBend + 1] + tangents[numRingsInBend + 1] * bendradius * -1 + up * standheight * -1f; + tangents[0] = new Vertex3D(0f, 0f, 1f); + right[0] = right[numRingsInBend+1]; + // set up the first point of the bend + points[1] = points[numRingsInBend + 1] + tangents[numRingsInBend + 1] * bendradius * -1 + up * bendradius * -1f; + tangents[1] = tangents[0]; + right[1] = right[0]; + // now bend from point 1 to numRingsInBend+1(-1) + var diffXY = points[numRingsInBend + 1] - points[1]; + diffXY.Z = 0; + var diffZ = points[numRingsInBend + 1] - points[1]; + diffZ.X = 0; + diffZ.Y = 0; + for (int i = 1; i < (numRingsInBend+1); i++) + { + + points[numRingsInBend - i + 1] = points[1] + diffXY - (float)System.Math.Sin(System.Math.PI / 2 / numRingsInBend * i) * diffXY + (float)System.Math.Cos(System.Math.PI / 2 / numRingsInBend * i) * diffZ; + var tmp = tangents[numRingsInBend + 1]; + tmp.Normalize(); + tangents[numRingsInBend - i + 1] = tmp * (float)System.Math.Cos(System.Math.PI / 2 / numRingsInBend * i) + (float)System.Math.Sin(System.Math.PI / 2 / numRingsInBend * i) * up; + right[numRingsInBend - i + 1] = right[0]; + } + // set up last point + points[numRings-1] = points[(numRings - 1) - numRingsInBend - 1] + tangents[numRings - 1 - numRingsInBend - 1] * bendradius + up * standheight * -1f; + tangents[numRings-1] = new Vertex3D(0f, 0f, -1f); + right[numRings - 1] = right[(numRings - 1) - numRingsInBend - 1]; + // and the point before + points[numRings-2] = points[(numRings - 1) - numRingsInBend - 1] + tangents[numRings - 1 - numRingsInBend - 1] * bendradius + up * bendradius * -1f; + tangents[numRings - 2] = tangents[numRings - 1]; + right[numRings - 2] = right[numRings - 1]; + // now bend again + diffXY = points[numRings - 1 - numRingsInBend - 1] - points[numRings-2]; + diffXY.Z = 0; + diffZ = points[numRings - 1 - numRingsInBend - 1] - points[numRings - 2]; + diffZ.X = 0; + diffZ.Y = 0; + for (int i = 1; i < (numRingsInBend + 1); i++) + { + + points[numRings - 2 - numRingsInBend + i] = points[numRings - 2] + diffXY - (float)System.Math.Sin(System.Math.PI / 2 / numRingsInBend * i) * diffXY + (float)System.Math.Cos(System.Math.PI / 2 / numRingsInBend * i) * diffZ; + var tmp = tangents[numRings - 1 - numRingsInBend - 1]; + tmp.Normalize(); + tangents[numRings - 2 - numRingsInBend + i] = tmp * (float)System.Math.Cos(System.Math.PI / 2 / numRingsInBend * i) + (float)System.Math.Sin(System.Math.PI / 2 / numRingsInBend * i) * up*-1; + right[numRings - 2 - numRingsInBend + i] = right[numRings-1]; + } + + // calculate downvectors + for (int i = 0; i < numRings; i++) + { + down[i] = Vertex3D.CrossProduct(right[i], tangents[i]); + down[i].Normalize(); + } + + // For UV calculation we need the whole length of the wire + accLength[0] = 0.0f; + for (int i = 1; i < numRings; i++) + accLength[i] = accLength[i - 1] + (points[i]-points[i-1]).Length(); + var totalLength = accLength[numRings-1]; + + var numVertices = numRings * numSegments; + var numIndices = (numRings-1) * numSegments * 6; + mesh.Vertices = new Vertex3DNoTex2[numVertices]; + mesh.Indices = new int[numIndices]; + + // precalculate the rings (positive X is left, positive Y is up) Starting at the bottom clockwise (X=0, Y=1) + var ringsX = new float[numSegments]; + var ringsY = new float[numSegments]; + for (int i = 0; i < numSegments;i++) + { + ringsX[i] = -1.0f * (float)System.Math.Sin(System.Math.PI*2 * i / numSegments) * _data.Thickness; + ringsY[i] = -1.0f * (float)System.Math.Cos(System.Math.PI + System.Math.PI*2 * i / numSegments) * _data.Thickness; + } + + var verticesIndex = 0; + var indicesIndex = 0; + + // calculate Vertices first + for (int currentRing = 0; currentRing < numRings; currentRing++) + { + // calculate one ring + for (int currentSegment = 0; currentSegment < numSegments; currentSegment++) + { + mesh.Vertices[verticesIndex++] = new Vertex3DNoTex2 + { + X = points[currentRing].X + right[currentRing].X * ringsX[currentSegment] + down[currentRing].X * ringsY[currentSegment], + Y = points[currentRing].Y + right[currentRing].Y * ringsX[currentSegment] + down[currentRing].Y * ringsY[currentSegment], + Z = points[currentRing].Z + right[currentRing].Z * ringsX[currentSegment] + down[currentRing].Z * ringsY[currentSegment], + Nx = right[currentRing].X * ringsX[currentSegment] + down[currentRing].X * ringsY[currentSegment], + Ny = right[currentRing].Y * ringsX[currentSegment] + down[currentRing].Y * ringsY[currentSegment], + Nz = right[currentRing].Z * ringsX[currentSegment] + down[currentRing].Z * ringsY[currentSegment], + Tu = accLength[currentRing] / totalLength, + Tv = (float)currentSegment/((float)numSegments-1) + + }; + } + + + // could be integrated in above for loop, but better to read and will be optimized anyway by compiler + if (currentRing > 0) + { + for (int currentSegment = 0; currentSegment < numSegments; currentSegment++) + { + var csp1 = currentSegment + 1; + if (csp1 >= numSegments) + csp1 = 0; + mesh.Indices[indicesIndex++] = (currentRing - 1) * numSegments + currentSegment; + mesh.Indices[indicesIndex++] = currentRing * numSegments + currentSegment; + mesh.Indices[indicesIndex++] = currentRing * numSegments + csp1; + mesh.Indices[indicesIndex++] = (currentRing - 1) * numSegments + currentSegment; + mesh.Indices[indicesIndex++] = currentRing * numSegments + csp1; + mesh.Indices[indicesIndex++] = (currentRing - 1) * numSegments + csp1; + } + } + } + + return mesh; + } + } +} diff --git a/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideMeshGenerator.cs.meta b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideMeshGenerator.cs.meta new file mode 100644 index 000000000..2657ce29d --- /dev/null +++ b/VisualPinball.Engine/VPT/MetalWireGuide/MetalWireGuideMeshGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 181d3df3b2969c741aaa46c906d356ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Engine/VPT/Rubber/Rubber.cs b/VisualPinball.Engine/VPT/Rubber/Rubber.cs index 7f7df8810..50c5cbd72 100644 --- a/VisualPinball.Engine/VPT/Rubber/Rubber.cs +++ b/VisualPinball.Engine/VPT/Rubber/Rubber.cs @@ -19,6 +19,7 @@ using VisualPinball.Engine.Math; namespace VisualPinball.Engine.VPT.Rubber + { public class Rubber : Item, IRenderable { diff --git a/VisualPinball.Engine/VPT/Table/TableContainer.cs b/VisualPinball.Engine/VPT/Table/TableContainer.cs index bdedbcb89..653d1e0c7 100644 --- a/VisualPinball.Engine/VPT/Table/TableContainer.cs +++ b/VisualPinball.Engine/VPT/Table/TableContainer.cs @@ -78,6 +78,7 @@ public abstract class TableContainer protected readonly Dictionary _timers = new Dictionary(); protected readonly Dictionary _triggers = new Dictionary(); protected readonly Dictionary _troughs = new Dictionary(); + protected readonly Dictionary _metalWireGuides = new Dictionary(); protected virtual void Clear() { @@ -101,6 +102,7 @@ protected virtual void Clear() _timers.Clear(); _triggers.Clear(); _troughs.Clear(); + _metalWireGuides.Clear(); } public Bumper.Bumper Bumper(string name) => _bumpers[name.ToLower()]; @@ -123,6 +125,7 @@ protected virtual void Clear() public Timer.Timer Timer(string name) => _timers[name.ToLower()]; public Trigger.Trigger Trigger(string name) => _triggers[name.ToLower()]; public Trough.Trough Trough(string name) => _troughs[name.ToLower()]; + public MetalWireGuide.MetalWireGuide MetalWireGuide(string name) => _metalWireGuides[name.ToLower()]; public IEnumerable Renderables => Array.Empty() .Concat(_bumpers.Values) @@ -137,7 +140,8 @@ protected virtual void Clear() .Concat(_rubbers.Values) .Concat(_spinners.Values) .Concat(_surfaces.Values) - .Concat(_triggers.Values); + .Concat(_triggers.Values) + .Concat(_metalWireGuides.Values); /// /// Game items that need to be converted but aren't rendered. @@ -165,7 +169,8 @@ protected virtual void Clear() .Concat(_textBoxes.Values) .Concat(_timers.Values) .Concat(_triggers.Values) - .Concat(_troughs.Values); + .Concat(_triggers.Values) + .Concat(_metalWireGuides.Values); public IEnumerable ItemDatas => ItemSupportedDatas.Concat(ItemLegacyDatas); @@ -183,7 +188,8 @@ protected virtual void Clear() .Concat(_rubbers.Values.Select(i => i.Data)) .Concat(_spinners.Values.Select(i => i.Data)) .Concat(_surfaces.Values.Select(i => i.Data)) - .Concat(_triggers.Values.Select(i => i.Data)); + .Concat(_triggers.Values.Select(i => i.Data)) + .Concat(_metalWireGuides.Values.Select(i => i.Data)); public IEnumerable ItemLegacyDatas => new ItemData[] { } .Concat(_decals.Select(i => i.Data)) @@ -282,6 +288,12 @@ protected Dictionary GetItemDictionary(Type t) where T : IItem return _troughs as Dictionary; } + if (t == typeof(MetalWireGuide.MetalWireGuide)) + { + return _metalWireGuides as Dictionary; + } + + return null; } diff --git a/VisualPinball.Engine/VPT/Table/TableLoader.cs b/VisualPinball.Engine/VPT/Table/TableLoader.cs index 3af9fa966..8cb3110a1 100644 --- a/VisualPinball.Engine/VPT/Table/TableLoader.cs +++ b/VisualPinball.Engine/VPT/Table/TableLoader.cs @@ -114,6 +114,7 @@ public static void LoadGameItem(byte[] itemData, int storageIndex, out ItemType case ItemType.Timer: item = new Timer.Timer(reader, itemName); break; case ItemType.Trigger: item = new Trigger.Trigger(reader, itemName); break; case ItemType.Trough: item = new Trough.Trough(reader, $"VpeGameItem{storageIndex}"); break; + case ItemType.MetalWireGuide: item = new MetalWireGuide.MetalWireGuide(reader, itemName); break; default: Logger.Info("Unhandled item type " + itemType); itemType = ItemType.Invalid; break; @@ -245,6 +246,12 @@ private static void LoadGameItems(FileTableContainer tableContainer, CFStorage s tableContainer.Add(item); break; } + case ItemType.MetalWireGuide: + { + var item = new MetalWireGuide.MetalWireGuide(reader, itemName); + tableContainer.Add(item); + break; + } } } } diff --git a/VisualPinball.Engine/VisualPinball.Engine.csproj b/VisualPinball.Engine/VisualPinball.Engine.csproj index 9bdb13c87..bb59e5b5a 100644 --- a/VisualPinball.Engine/VisualPinball.Engine.csproj +++ b/VisualPinball.Engine/VisualPinball.Engine.csproj @@ -5,7 +5,7 @@ true VisualPinball.Engine The core of Visual Pinball ported to .NET - freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz + freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli;Cupid Copyright 2021 freezy - <freezy@vpdb.io> 0.1.0.0 0.1.0.0 diff --git a/VisualPinball.Resources/VisualPinball.Resources.csproj b/VisualPinball.Resources/VisualPinball.Resources.csproj index bad18b0b4..37b776f47 100644 --- a/VisualPinball.Resources/VisualPinball.Resources.csproj +++ b/VisualPinball.Resources/VisualPinball.Resources.csproj @@ -3,7 +3,7 @@ netstandard2.1 VisualPinball.Resources Meshes and Textures shipped with Visual Pinball - freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli + freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli;Cupid Copyright 2021 freezy - <freezy@vpdb.io> 0.1.0.0 0.1.0.0 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/metal_wire_guides.png b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/metal_wire_guides.png new file mode 100644 index 000000000..bcd4b400c Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/metal_wire_guides.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/metal_wire_guides.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/metal_wire_guides.png.meta new file mode 100644 index 000000000..45b7ded38 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/metal_wire_guides.png.meta @@ -0,0 +1,122 @@ +fileFormatVersion: 2 +guid: 5d6ea50630493e648bff754d64ed09ea +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 1 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/metal_wire_guides.png b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/metal_wire_guides.png new file mode 100644 index 000000000..0f1a7392b Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/metal_wire_guides.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/metal_wire_guides.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/metal_wire_guides.png.meta new file mode 100644 index 000000000..698743ea3 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/metal_wire_guides.png.meta @@ -0,0 +1,122 @@ +fileFormatVersion: 2 +guid: 8f5016f61fa493b4f820999b63081774 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 1 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/metal_wire_guides.png b/VisualPinball.Unity/Assets/Editor/Icons/large_green/metal_wire_guides.png new file mode 100644 index 000000000..086037ca1 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_green/metal_wire_guides.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/metal_wire_guides.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_green/metal_wire_guides.png.meta new file mode 100644 index 000000000..3b07734c8 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_green/metal_wire_guides.png.meta @@ -0,0 +1,122 @@ +fileFormatVersion: 2 +guid: 6a2ceb97b21b14042b0f928766d785c4 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 1 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/metal_wire_guides.png b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/metal_wire_guides.png new file mode 100644 index 000000000..9c266f30d Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/metal_wire_guides.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/metal_wire_guides.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/metal_wire_guides.png.meta new file mode 100644 index 000000000..64bdcbc64 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/metal_wire_guides.png.meta @@ -0,0 +1,122 @@ +fileFormatVersion: 2 +guid: bd8ddd3b9ba2b4546afbbcc3badeeeba +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 1 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/metal_wire_guides.png b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/metal_wire_guides.png new file mode 100644 index 000000000..fcfbae104 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/metal_wire_guides.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_blue/metal_wire_guides.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/metal_wire_guides.png.meta new file mode 100644 index 000000000..a491cead0 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_blue/metal_wire_guides.png.meta @@ -0,0 +1,122 @@ +fileFormatVersion: 2 +guid: a11e8e75e5068e146898cb04a4caa683 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/metal_wire_guides.png b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/metal_wire_guides.png new file mode 100644 index 000000000..322ebea87 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/metal_wire_guides.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/metal_wire_guides.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/metal_wire_guides.png.meta new file mode 100644 index 000000000..9f08ac9a2 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/metal_wire_guides.png.meta @@ -0,0 +1,122 @@ +fileFormatVersion: 2 +guid: cf79f97d67191d74f89ff6ef88a90e39 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/metal_wire_guides.png b/VisualPinball.Unity/Assets/Editor/Icons/small_green/metal_wire_guides.png new file mode 100644 index 000000000..7096f4921 Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_green/metal_wire_guides.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/metal_wire_guides.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_green/metal_wire_guides.png.meta new file mode 100644 index 000000000..46b45e5ab --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_green/metal_wire_guides.png.meta @@ -0,0 +1,122 @@ +fileFormatVersion: 2 +guid: 6cf673cf3917e0248b351b4296514c1d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/metal_wire_guides.png b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/metal_wire_guides.png new file mode 100644 index 000000000..9101a405f Binary files /dev/null and b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/metal_wire_guides.png differ diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/metal_wire_guides.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/metal_wire_guides.png.meta new file mode 100644 index 000000000..505c72fe3 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/metal_wire_guides.png.meta @@ -0,0 +1,122 @@ +fileFormatVersion: 2 +guid: 646999b23e4fc304f9277dee4ad46cd8 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Server + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Resources/Prefabs/MetalWireGuide.prefab b/VisualPinball.Unity/Assets/Resources/Prefabs/MetalWireGuide.prefab new file mode 100644 index 000000000..5efa4de90 --- /dev/null +++ b/VisualPinball.Unity/Assets/Resources/Prefabs/MetalWireGuide.prefab @@ -0,0 +1,113 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &5446999501863086646 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 657206998972773943} + - component: {fileID: 7950640923248477891} + - component: {fileID: 2107529826525245329} + - component: {fileID: -3250516992663423584} + - component: {fileID: 4392546155774236836} + - component: {fileID: 171621741425913877} + m_Layer: 0 + m_Name: MetalWireGuide + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &657206998972773943 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5446999501863086646} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &7950640923248477891 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5446999501863086646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f05deabc91c0d3d4db83a445f2a755b9, type: 3} + m_Name: + m_EditorClassIdentifier: + _isLocked: 0 + _editorLayer: 0 + _editorLayerName: + _editorLayerVisibility: 1 + _height: 25 + _thickness: 8 + Rotation: {x: 0, y: 0, z: 0} + _dragPoints: [] +--- !u!114 &2107529826525245329 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5446999501863086646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 735a13a6d901dbc4fb644b96ba7801ff, type: 3} + m_Name: + m_EditorClassIdentifier: + PhysicsMaterial: {fileID: 0} + ShowColliderMesh: 1 + ShowAabbs: 0 + HitEvent: 0 + HitHeight: 25 + OverwritePhysics: 0 + Elasticity: 0 + ElasticityFalloff: 0 + Friction: 0 + Scatter: 0 +--- !u!114 &-3250516992663423584 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5446999501863086646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bcc8f0e761a7bc145abb5a6f918953aa, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!33 &4392546155774236836 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5446999501863086646} + m_Mesh: {fileID: 0} +--- !u!114 &171621741425913877 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5446999501863086646} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ea7d7495833204790ba1d3a8755397f8, type: 3} + m_Name: + m_EditorClassIdentifier: + ConversionMode: 1 diff --git a/VisualPinball.Unity/Assets/Resources/Prefabs/MetalWireGuide.prefab.meta b/VisualPinball.Unity/Assets/Resources/Prefabs/MetalWireGuide.prefab.meta new file mode 100644 index 000000000..988f0cc41 --- /dev/null +++ b/VisualPinball.Unity/Assets/Resources/Prefabs/MetalWireGuide.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 073cf4ebd8b550b4699ac09545ec5673 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs index 82389a04a..d2b9922f8 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs @@ -46,6 +46,7 @@ using VisualPinball.Engine.VPT.Timer; using VisualPinball.Engine.VPT.Trigger; using VisualPinball.Engine.VPT.Trough; +using VisualPinball.Engine.VPT.MetalWireGuide; using VisualPinball.Unity.Playfield; using Light = VisualPinball.Engine.VPT.Light.Light; using Material = UnityEngine.Material; @@ -189,6 +190,7 @@ private void SaveLegacyData() _sourceContainer.WriteDataToDict(_tableComponent.LegacyContainer.Surfaces); _sourceContainer.WriteDataToDict(_tableComponent.LegacyContainer.Triggers); _sourceContainer.WriteDataToDict(_tableComponent.LegacyContainer.Bumpers); + _sourceContainer.WriteDataToDict(_tableComponent.LegacyContainer.MetalWireGuides); _tableComponent.LegacyContainer.Decals = _sourceContainer.GetAllData(); _tableComponent.LegacyContainer.DispReels = _sourceContainer.GetAllData(); @@ -331,20 +333,21 @@ private IVpxPrefab InstantiateAndParentPrefab(IItem item) private IVpxPrefab InstantiatePrefab(IItem item) { switch (item) { - case Bumper bumper: return bumper.InstantiatePrefab(); - case Flipper flipper: return flipper.InstantiatePrefab(); - case Gate gate: return gate.InstantiatePrefab(); - case HitTarget hitTarget: return hitTarget.InstantiatePrefab(); - case Kicker kicker: return kicker.InstantiatePrefab(); - case Light lt: return lt.InstantiatePrefab(_sourceTable); - case Plunger plunger: return plunger.InstantiatePrefab(); - case Primitive primitive: return primitive.InstantiatePrefab(_playfieldGo); - case Ramp ramp: return ramp.InstantiatePrefab(); - case Rubber rubber: return rubber.InstantiatePrefab(); - case Spinner spinner: return spinner.InstantiatePrefab(); - case Surface surface: return surface.InstantiatePrefab(); - case Trigger trigger: return trigger.InstantiatePrefab(); - case Trough trough: return trough.InstantiatePrefab(); + case Bumper bumper: return bumper.InstantiatePrefab(); + case Flipper flipper: return flipper.InstantiatePrefab(); + case Gate gate: return gate.InstantiatePrefab(); + case HitTarget hitTarget: return hitTarget.InstantiatePrefab(); + case Kicker kicker: return kicker.InstantiatePrefab(); + case Light lt: return lt.InstantiatePrefab(_sourceTable); + case Plunger plunger: return plunger.InstantiatePrefab(); + case Primitive primitive: return primitive.InstantiatePrefab(_playfieldGo); + case Ramp ramp: return ramp.InstantiatePrefab(); + case Rubber rubber: return rubber.InstantiatePrefab(); + case Spinner spinner: return spinner.InstantiatePrefab(); + case Surface surface: return surface.InstantiatePrefab(); + case Trigger trigger: return trigger.InstantiatePrefab(); + case Trough trough: return trough.InstantiatePrefab(); + case MetalWireGuide metalWireGuide : return metalWireGuide.InstantiatePrefab(); } throw new InvalidOperationException("Unknown item " + item + " to setup!"); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs index c451bd8bf..f10a44f06 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs @@ -34,6 +34,7 @@ using VisualPinball.Engine.VPT.Table; using VisualPinball.Engine.VPT.Trigger; using VisualPinball.Engine.VPT.Trough; +using VisualPinball.Engine.VPT.MetalWireGuide; using Light = VisualPinball.Engine.VPT.Light.Light; using Texture = UnityEngine.Texture; @@ -181,6 +182,12 @@ private void OnGUI() CreatePrefab("Slingshots", "Prefabs/Slingshot"); } + if (CreateButton("Metal Wire\nGuide", Icons.MetalWireGuide(color: iconColor), iconSize, buttonStyle)) + { + CreateItem(MetalWireGuide.GetDefault, "New MetalWireGuide"); + } + + GUILayout.EndHorizontal(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs index 347c8ff35..9a7af6c14 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs @@ -94,6 +94,7 @@ public IconVariant(string name, IconSize size, IconColor color) private const string TeleporterName = "teleporter"; private const string TriggerName = "trigger"; private const string TroughName = "trough"; + private const string MetalWireGuideName = "metal_wire_guides"; // colored private const string CoilEventName = "coil_event"; @@ -106,8 +107,7 @@ public IconVariant(string name, IconSize size, IconColor color) HitTargetName, KeyName, KickerName, LightGroupName, LightName, MechName, MechPinMameName, PlayfieldName, PlugName, PlungerName, PrimitiveName, RampName, RotatorName, RubberName, SlingshotName, SpinnerName, SurfaceName, SwitchNcName, SwitchNoName, TableName, TeleporterName, TriggerName, TroughName, - - CoilEventName, SwitchEventName, LampEventName, LampSeqName + CoilEventName, SwitchEventName, LampEventName, LampSeqName, MetalWireGuideName }; private readonly Dictionary _icons = new Dictionary(); @@ -167,6 +167,7 @@ private static IIconLookup[] GetLookups() { public static Texture2D LightGroup(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(LightGroupName, size, color); public static Texture2D Mech(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(MechName, size, color); public static Texture2D MechPinMame(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(MechPinMameName, size, color); + public static Texture2D MetalWireGuide(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(MetalWireGuideName, size, color); public static Texture2D Playfield(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(PlayfieldName, size, color); public static Texture2D Plug(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(PlugName, size, color); public static Texture2D Plunger(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(PlungerName, size, color); @@ -274,6 +275,7 @@ public Texture2D Lookup(T mb, IconSize size = IconSize.Large, IconColor color case TeleporterComponent _: return Icons.Teleporter(size, color); case TriggerComponent _: return Icons.Trigger(size, color); case TroughComponent _: return Icons.Trough(size, color); + case MetalWireGuideComponent _: return Icons.MetalWireGuide(size, color); case CollisionSwitchComponent _: return Icons.Switch(false, size, color); default: return null; } @@ -343,6 +345,9 @@ public void DisableGizmoIcons() Icons.DisableGizmo(); Icons.DisableGizmo(); Icons.DisableGizmo(); + Icons.DisableGizmo(); + Icons.DisableGizmo(); + Icons.DisableGizmo(); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide.meta new file mode 100644 index 000000000..32209ea42 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f036ffc59eafb434cb84fe88893813a5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideColliderInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideColliderInspector.cs new file mode 100644 index 000000000..33b690fde --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideColliderInspector.cs @@ -0,0 +1,88 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable AssignmentInConditionalExpression + +using UnityEditor; +using VisualPinball.Engine.VPT.MetalWireGuide; + +namespace VisualPinball.Unity.Editor +{ + [CustomEditor(typeof(MetalWireGuideColliderComponent)), CanEditMultipleObjects] + public class MetalWireGuideColliderInspector : ColliderInspector + { + private bool _foldoutMaterial = true; + private SerializedProperty _hitEventProperty; + private SerializedProperty _hitHeightProperty; + private SerializedProperty _overwritePhysicsProperty; + private SerializedProperty _physicsMaterialProperty; + private SerializedProperty _elasticityProperty; + private SerializedProperty _elasticityFalloffProperty; + private SerializedProperty _frictionProperty; + private SerializedProperty _scatterProperty; + + protected override void OnEnable() + { + base.OnEnable(); + + _hitEventProperty = serializedObject.FindProperty(nameof(MetalWireGuideColliderComponent.HitEvent)); + _hitHeightProperty = serializedObject.FindProperty(nameof(MetalWireGuideColliderComponent.HitHeight)); + + _overwritePhysicsProperty = serializedObject.FindProperty(nameof(MetalWireGuideColliderComponent.OverwritePhysics)); + _physicsMaterialProperty = serializedObject.FindProperty(nameof(ColliderComponent.PhysicsMaterial)); + _elasticityProperty = serializedObject.FindProperty(nameof(MetalWireGuideColliderComponent.Elasticity)); + _elasticityFalloffProperty = serializedObject.FindProperty(nameof(MetalWireGuideColliderComponent.ElasticityFalloff)); + _frictionProperty = serializedObject.FindProperty(nameof(MetalWireGuideColliderComponent.Friction)); + _scatterProperty = serializedObject.FindProperty(nameof(MetalWireGuideColliderComponent.Scatter)); + } + + public override void OnInspectorGUI() + { + + if (HasErrors()) { + return; + } + + BeginEditing(); + + OnPreInspectorGUI(); + + PropertyField(_hitEventProperty, "Has Hit Event"); + PropertyField(_hitHeightProperty, "Hit Height", updateColliders: true); + + // physics material + if (_foldoutMaterial = EditorGUILayout.BeginFoldoutHeaderGroup(_foldoutMaterial, "Physics Material")) { + EditorGUI.BeginDisabledGroup(_overwritePhysicsProperty.boolValue); + PropertyField(_physicsMaterialProperty, "Preset"); + EditorGUI.EndDisabledGroup(); + + PropertyField(_overwritePhysicsProperty); + + EditorGUI.BeginDisabledGroup(!_overwritePhysicsProperty.boolValue); + PropertyField(_elasticityProperty); + PropertyField(_elasticityFalloffProperty); + PropertyField(_frictionProperty); + PropertyField(_scatterProperty, "Scatter Angle"); + EditorGUI.EndDisabledGroup(); + } + EditorGUILayout.EndFoldoutHeaderGroup(); + + base.OnInspectorGUI(); + + EndEditing(); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideColliderInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideColliderInspector.cs.meta new file mode 100644 index 000000000..c5339348b --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideColliderInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e584fb57ba10628438f41ce0d4538c1e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideExtensions.cs new file mode 100644 index 000000000..ecd7942d5 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideExtensions.cs @@ -0,0 +1,30 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using UnityEngine; +using VisualPinball.Engine.VPT.MetalWireGuide; + +namespace VisualPinball.Unity.Editor +{ + public static class MetalWireGuideExtensions + { + internal static IVpxPrefab InstantiatePrefab(this MetalWireGuide metalWireGuide) + { + var prefab = UnityEngine.Resources.Load("Prefabs/MetalWireGuide"); + return new VpxPrefab(prefab, metalWireGuide); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideExtensions.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideExtensions.cs.meta new file mode 100644 index 000000000..d7f487241 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 692a65125db0eb54ba3ac6ad2621efbf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideInspector.cs new file mode 100644 index 000000000..d5ead010e --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideInspector.cs @@ -0,0 +1,96 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable AssignmentInConditionalExpression + +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; +using VisualPinball.Engine.Math; +using VisualPinball.Engine.VPT.MetalWireGuide; + +namespace VisualPinball.Unity.Editor +{ + [CustomEditor(typeof(MetalWireGuideComponent)), CanEditMultipleObjects] + public class MetalWireGuideInspector : MainInspector, IDragPointsInspector + { + + private SerializedProperty _heightProperty; + private SerializedProperty _thicknessProperty; + private SerializedProperty _rotationProperty; + private SerializedProperty _bendradius; + + protected override void OnEnable() + { + base.OnEnable(); + + + DragPointsHelper = new DragPointsInspectorHelper(MainComponent, this); + DragPointsHelper.OnEnable(); + + _heightProperty = serializedObject.FindProperty(nameof(MetalWireGuideComponent._height)); + _thicknessProperty = serializedObject.FindProperty(nameof(MetalWireGuideComponent._thickness)); + _rotationProperty = serializedObject.FindProperty(nameof(MetalWireGuideComponent.Rotation)); + _bendradius = serializedObject.FindProperty(nameof(MetalWireGuideComponent._bendradius)); + } + + protected override void OnDisable() + { + base.OnDisable(); + DragPointsHelper.OnDisable(); + } + + public override void OnInspectorGUI() + { + if (HasErrors()) { + return; + } + + BeginEditing(); + + OnPreInspectorGUI(); + + PropertyField(_rotationProperty, rebuildMesh: true); + PropertyField(_heightProperty, rebuildMesh: true); + PropertyField(_thicknessProperty, rebuildMesh: true); + PropertyField(_bendradius, rebuildMesh: true); + + DragPointsHelper.OnInspectorGUI(this); + + base.OnInspectorGUI(); + + EndEditing(); + } + + private void OnSceneGUI() + { + DragPointsHelper.OnSceneGUI(this); + } + + #region Dragpoint Tooling + + public bool DragPointsActive => true; + public DragPointData[] DragPoints { get => MainComponent.DragPoints; set => MainComponent.DragPoints = value; } + public Vector3 EditableOffset => new Vector3(0.0f, 0.0f, MainComponent._height); + public Vector3 GetDragPointOffset(float ratio) => Vector3.zero; + public bool PointsAreLooping => false; + public IEnumerable DragPointExposition => new[] { DragPointExposure.Smooth }; + public ItemDataTransformType HandleType => ItemDataTransformType.TwoD; + public DragPointsInspectorHelper DragPointsHelper { get; private set; } + + #endregion + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideInspector.cs.meta new file mode 100644 index 000000000..0aae8861f --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e94f80524d6f79747af961df618d2b75 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideMeshInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideMeshInspector.cs new file mode 100644 index 000000000..19ea4309f --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideMeshInspector.cs @@ -0,0 +1,36 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable AssignmentInConditionalExpression + +using UnityEditor; +using VisualPinball.Engine.VPT.MetalWireGuide; + +namespace VisualPinball.Unity.Editor +{ + [CustomEditor(typeof(MetalWireGuideMeshComponent)), CanEditMultipleObjects] + public class MetalWireGuideMeshInspector : MeshInspector + { + public override void OnInspectorGUI() + { + if (HasErrors()) { + return; + } + + EditorGUILayout.HelpBox("This component computes the metal wire guide meshes.", MessageType.Info); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideMeshInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideMeshInspector.cs.meta new file mode 100644 index 000000000..dc042eef4 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/MetalWireGuide/MetalWireGuideMeshInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2cc13a8d5490bb44582a79bf0f3439d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VisualPinball.Unity.Editor.csproj b/VisualPinball.Unity/VisualPinball.Unity.Editor/VisualPinball.Unity.Editor.csproj index f4f742070..dd556bf03 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VisualPinball.Unity.Editor.csproj +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VisualPinball.Unity.Editor.csproj @@ -3,7 +3,7 @@ netstandard2.1 VisualPinball.Unity.Editor A bridge between VisualPinball.Engine and Unity - freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli + freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli;Cupid Copyright 2021 freezy - <freezy@vpdb.io> 0.1.0.0 0.1.0.0 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/VisualPinball.Unity.Patcher.csproj b/VisualPinball.Unity/VisualPinball.Unity.Patcher/VisualPinball.Unity.Patcher.csproj index d25803d52..8b7f612b5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/VisualPinball.Unity.Patcher.csproj +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/VisualPinball.Unity.Patcher.csproj @@ -3,7 +3,7 @@ netstandard2.1 VisualPinball.Unity.Patcher A bridge between VisualPinball.Engine and Unity - freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli + freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli;Cupid Copyright 2021 freezy - <freezy@vpdb.io> 0.1.0.0 0.1.0.0 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/MetalWireGudieTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/MetalWireGudieTests.cs new file mode 100644 index 000000000..c3e61840e --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/MetalWireGudieTests.cs @@ -0,0 +1,46 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.IO; +using NUnit.Framework; +using UnityEngine; +using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.Test.VPT.MetalWireGuide; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class MetalWireGuideTests + { + [Test] + public void ShouldWriteImportedMetalWireGuideData() + { + const string tmpFileName = "ShouldWriteMetalWireGuideData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.MetalWireGuide, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + MetalWireGuideDataTests.ValidateMetalWireGuideData1(writtenTable.MetalWireGuide("MetalWireGuide1").Data); + MetalWireGuideDataTests.ValidateMetalWireGuideData2(writtenTable.MetalWireGuide("MetalWireGuide2").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/MetalWireGudieTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/MetalWireGudieTests.cs.meta new file mode 100644 index 000000000..2b71bfa80 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/MetalWireGudieTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d522663b483be2b46904b6462748d6af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.csproj b/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.csproj index c5df604a1..9ba7f113e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.csproj +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.csproj @@ -3,7 +3,7 @@ netcoreapp3.1 VisualPinball.Unity.Test A bridge between VisualPinball.Engine and Unity - freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli + freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli;Cupid Copyright 2021 freezy - <freezy@vpdb.io> 0.1.0.0 0.1.0.0 diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs index a6e842938..2d8268706 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs @@ -338,6 +338,11 @@ public void RegisterTrough(TroughComponent component) Register(new TroughApi(component.gameObject, this), component); } + public void RegisterMetalWireGuide(MetalWireGuideComponent component, Entity entity) + { + Register(new MetalWireGuideApi(component.gameObject, entity, this), component, entity); + } + private void Register(TApi api, MonoBehaviour component, Entity entity = default) where TApi : IApi { TableApi.Register(component, api); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Import/Job/TableLoader.cs b/VisualPinball.Unity/VisualPinball.Unity/Import/Job/TableLoader.cs index 722faebe1..8671db6fb 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Import/Job/TableLoader.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Import/Job/TableLoader.cs @@ -43,6 +43,7 @@ using VisualPinball.Engine.VPT.Timer; using VisualPinball.Engine.VPT.Trigger; using VisualPinball.Engine.VPT.Trough; +using VisualPinball.Engine.VPT.MetalWireGuide; namespace VisualPinball.Unity { @@ -150,6 +151,10 @@ public static FileTableContainer LoadTable(string path) tableContainer.Add(objHandle.Target as Trough); break; } + case ItemType.MetalWireGuide:{ + tableContainer.Add(objHandle.Target as MetalWireGuide); + break; + } default: throw new ArgumentException("Unknown item type " + (ItemType)job.ItemType[i] + "."); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ColliderHeader.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ColliderHeader.cs index 068cdb60a..d5ac67f53 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ColliderHeader.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ColliderHeader.cs @@ -50,7 +50,7 @@ public struct ColliderHeader /// check this in order to know whether to emit /// the hit event. /// - public bool IsPrimitive => ItemType == ItemType.Primitive || ItemType == ItemType.Ramp || ItemType == ItemType.Rubber; + public bool IsPrimitive => ItemType == ItemType.Primitive || ItemType == ItemType.Ramp || ItemType == ItemType.Rubber || ItemType == ItemType.MetalWireGuide; public void Init(ColliderInfo info, ColliderType colliderType) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide.meta new file mode 100644 index 000000000..3dccf30f5 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af8456f94f2fa334b9edc8f7175015b6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideApi.cs new file mode 100644 index 000000000..21a1e4db8 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideApi.cs @@ -0,0 +1,74 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using System.Collections.Generic; +using Unity.Entities; +using UnityEngine; +using VisualPinball.Engine.VPT.MetalWireGuide; + +namespace VisualPinball.Unity +{ + public class MetalWireGuideApi : CollidableApi, + IApi, IApiHittable + { + /// + /// Event emitted when the table is started. + /// + public event EventHandler Init; + + /// + /// Event emitted when the ball hits the metal wire gudie. + /// + public event EventHandler Hit; + + internal MetalWireGuideApi(GameObject go, Entity entity, Player player) : base(go, entity, player) + { + } + + #region Collider Generation + + protected override bool FireHitEvents => ColliderComponent.HitEvent; + protected override float HitThreshold => 2.0f; // hard coded threshold for now + + protected override void CreateColliders(List colliders, float margin) + { + var colliderGenerator = new MetalWireGuideColliderGenerator(this, new MetalWireGuideMeshGenerator(MainComponent)); + colliderGenerator.GenerateColliders(MainComponent.PlayfieldHeight, ColliderComponent.HitHeight, MainComponent.Bendradius, MainComponent.PlayfieldDetailLevel, colliders, margin); + } + + #endregion + + #region Events + + void IApi.OnInit(BallManager ballManager) + { + base.OnInit(ballManager); + Init?.Invoke(this, EventArgs.Empty); + } + + void IApi.OnDestroy() + { + } + + void IApiHittable.OnHit(Entity ballEntity, bool _) + { + Hit?.Invoke(this, new HitEventArgs(ballEntity)); + } + + #endregion + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideApi.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideApi.cs.meta new file mode 100644 index 000000000..9f1c40cff --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c7f5e1aa51bd3e545a93dbb82d8080eb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderComponent.cs new file mode 100644 index 000000000..9caee1a6a --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderComponent.cs @@ -0,0 +1,64 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// ReSharper disable InconsistentNaming + +using System; +using Unity.Entities; +using UnityEngine; +using VisualPinball.Engine.VPT.MetalWireGuide; + +namespace VisualPinball.Unity +{ + [AddComponentMenu("Visual Pinball/Collision/MetalWireGuide Collider")] + public class MetalWireGuideColliderComponent : ColliderComponent + { + #region Data + + [Tooltip("If set, a hit event is triggered.")] + public bool HitEvent; + + [Tooltip("Z-axis translation for the collider mesh.")] + public float HitHeight = 25f; + + [Tooltip("Ignore the assigned physics material above and use the value below.")] + public bool OverwritePhysics; + + [Min(0f)] + [Tooltip("Bounciness, also known as coefficient of restitution. Higher is more bouncy.")] + public float Elasticity; + + [Min(0f)] + [Tooltip("How much to decrease elasticity for fast impacts.")] + public float ElasticityFalloff; + + [Min(0)] + [Tooltip("Friction of the material.")] + public float Friction; + + [Range(-90f, 90f)] + [Tooltip("When hit, add a random angle between 0 and this value to the trajectory.")] + public float Scatter; + + #endregion + + public static readonly Type[] ValidParentTypes = Type.EmptyTypes; + + public override PhysicsMaterialData PhysicsMaterialData => GetPhysicsMaterialData(Elasticity, ElasticityFalloff, Friction, Scatter, OverwritePhysics); + protected override IApiColliderGenerator InstantiateColliderApi(Player player, Entity entity) + => new MetalWireGuideApi(gameObject, entity, player); + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderComponent.cs.meta new file mode 100644 index 000000000..b421778b7 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 735a13a6d901dbc4fb644b96ba7801ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 6cf673cf3917e0248b351b4296514c1d, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderGenerator.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderGenerator.cs new file mode 100644 index 000000000..97af246f9 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderGenerator.cs @@ -0,0 +1,69 @@ +// Visual Pinball Engine +// Copyright (C) 2020 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; +using VisualPinball.Engine.VPT; +using VisualPinball.Engine.VPT.MetalWireGuide; + +namespace VisualPinball.Unity +{ + public class MetalWireGuideColliderGenerator + { + private readonly IApiColliderGenerator _api; + private readonly MetalWireGuideMeshGenerator _meshGenerator; + + public MetalWireGuideColliderGenerator(MetalWireGuideApi metalWireGuideApi, MetalWireGuideMeshGenerator meshGenerator) + { + _api = metalWireGuideApi; + _meshGenerator = meshGenerator; + } + + internal void GenerateColliders(float playfieldHeight, float hitHeight, float bendradius, int detailLevel, List colliders, float margin) + { + var mesh = _meshGenerator.GetTransformedMesh(playfieldHeight, hitHeight, detailLevel, bendradius, 6, true, margin); //!! adapt hacky code in the function if changing the "6" here + var addedEdges = EdgeSet.Get(); + + // add collision triangles and edges + for (var i = 0; i < mesh.Indices.Length; i += 3) { + // NB: HitTriangle wants CCW vertices, but for rendering we have them in CW order + var rg0 = mesh.Vertices[mesh.Indices[i]].ToUnityFloat3(); + var rg1 = mesh.Vertices[mesh.Indices[i + 2]].ToUnityFloat3(); + var rg2 = mesh.Vertices[mesh.Indices[i + 1]].ToUnityFloat3(); + + colliders.Add(new TriangleCollider(rg0, rg1, rg2, _api.GetColliderInfo())); + + GenerateHitEdge(mesh, addedEdges, mesh.Indices[i], mesh.Indices[i + 2], colliders); + GenerateHitEdge(mesh, addedEdges, mesh.Indices[i + 2], mesh.Indices[i + 1], colliders); + GenerateHitEdge(mesh, addedEdges, mesh.Indices[i + 1], mesh.Indices[i], colliders); + } + + // add collision vertices + foreach (var mv in mesh.Vertices) { + colliders.Add(new PointCollider(mv.ToUnityFloat3(), _api.GetColliderInfo())); + } + } + + private void GenerateHitEdge(Mesh mesh, EdgeSet addedEdges, int i, int j, + ICollection colliders) + { + if (addedEdges.ShouldAddHitEdge(i, j)) { + var v1 = mesh.Vertices[i].ToUnityFloat3(); + var v2 = mesh.Vertices[j].ToUnityFloat3(); + colliders.Add(new Line3DCollider(v1, v2, _api.GetColliderInfo())); + } + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderGenerator.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderGenerator.cs.meta new file mode 100644 index 000000000..8259dab1e --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideColliderGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 006ddeefa3aadc849a05fa7fd77b74de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideComponent.cs new file mode 100644 index 000000000..d7da683af --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideComponent.cs @@ -0,0 +1,230 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#region ReSharper +// ReSharper disable CompareOfFloatsByEqualityOperator +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable InconsistentNaming +#endregion + +using System; +using System.Collections.Generic; +using Unity.Entities; +using UnityEngine; +using VisualPinball.Engine.Math; +using VisualPinball.Engine.VPT; +using VisualPinball.Engine.VPT.MetalWireGuide; +using VisualPinball.Engine.VPT.Table; + +namespace VisualPinball.Unity +{ + [AddComponentMenu("Visual Pinball/Game Item/Metal Wire Guide")] + public class MetalWireGuideComponent : MainRenderableComponent, + IMetalWireGuideData, IConvertGameObjectToEntity + { + #region Data + + [Tooltip("Height of the rubber (z-axis).")] + public float _height = 25f; + + [Min(0)] + [Tooltip("How thick the rubber band is rendered.")] + public int _thickness = 8; + + [Tooltip("Rotation on the playfield")] + public Vector3 Rotation; + + [Tooltip("Radius of the bend")] + public float _bendradius = 8f; + + [SerializeField] + private DragPointData[] _dragPoints; + + #endregion + + #region IMetalWireGuideData + + public DragPointData[] DragPoints { get => _dragPoints; set => _dragPoints = value; } + public int Thickness => _thickness; + public float Height => _height; + public float RotX => Rotation.x; + public float RotY => Rotation.y; + public float RotZ => Rotation.z; + public float Bendradius => _bendradius; + + #endregion + + #region Overrides + + public override ItemType ItemType => ItemType.MetalWireGuide; + public override string ItemName => "MetalWireGuide"; + + public override MetalWireGuideData InstantiateData() => new MetalWireGuideData(); + + protected override Type MeshComponentType { get; } = typeof(MeshComponent); + protected override Type ColliderComponentType { get; } = typeof(ColliderComponent); + + #endregion + + #region Transformation + + public override void OnPlayfieldHeightUpdated() => RebuildMeshes(); + + #endregion + + #region Conversion + + public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) + { + Convert(entity, dstManager); + + // register + transform.GetComponentInParent().RegisterMetalWireGuide(this, entity); + } + + public override IEnumerable SetData(MetalWireGuideData data) + { + var updatedComponents = new List { this }; + + // geometry + _height = data.Height; + Rotation = new Vector3(data.RotX, data.RotY, data.RotZ); + _thickness = data.Thickness; + DragPoints = data.DragPoints; + _bendradius = data.Bendradius; + + // collider data + var collComponent = GetComponent(); + if (collComponent) { + collComponent.enabled = data.IsCollidable; + + collComponent.HitEvent = data.HitEvent; + collComponent.HitHeight = data.HitHeight; + collComponent.OverwritePhysics = data.OverwritePhysics; + collComponent.Elasticity = data.Elasticity; + collComponent.ElasticityFalloff = data.ElasticityFalloff; + collComponent.Friction = data.Friction; + collComponent.Scatter = data.Scatter; + + updatedComponents.Add(collComponent); + } + + return updatedComponents; + } + + public override IEnumerable SetReferencedData(MetalWireGuideData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) + { + // mesh + var mesh = GetComponent(); + if (mesh) { + mesh.CreateMesh(data, table, textureProvider, materialProvider); + mesh.enabled = data.IsVisible; + SetEnabled(data.IsVisible); + } + + // collider data + var collComponent = GetComponentInChildren(); + if (collComponent) { + collComponent.PhysicsMaterial = materialProvider.GetPhysicsMaterial(data.PhysicsMaterial); + } + + return Array.Empty(); + } + + public override MetalWireGuideData CopyDataTo(MetalWireGuideData data, string[] materialNames, string[] textureNames, bool forExport) + { + // update the name + data.Name = name; + + // geometry + data.Height = _height; + data.RotX = Rotation.x; + data.RotY = Rotation.y; + data.RotZ = Rotation.z; + data.Thickness = _thickness; + data.Bendradius = _bendradius; + data.DragPoints = DragPoints; + + // visibility + data.IsVisible = GetEnabled(); + + // collision + var collComponent = GetComponentInChildren(); + if (collComponent) { + data.IsCollidable = collComponent.enabled; + + data.HitEvent = collComponent.HitEvent; + data.HitHeight = collComponent.HitHeight; + + data.PhysicsMaterial = collComponent.PhysicsMaterial ? collComponent.PhysicsMaterial.name : string.Empty; + data.OverwritePhysics = collComponent.OverwritePhysics; + data.Elasticity = collComponent.Elasticity; + data.ElasticityFalloff = collComponent.ElasticityFalloff; + data.Friction = collComponent.Friction; + data.Scatter = collComponent.Scatter; + + } else { + data.IsCollidable = false; + } + + return data; + } + + #endregion + + #region Editor Tooling + + private Vector3 DragPointCenter { + get { + var sum = Vertex3D.Zero; + foreach (var t in DragPoints) { + sum += t.Center; + } + var center = sum / DragPoints.Length; + return center.ToUnityVector3(); + } + } + + public override ItemDataTransformType EditorPositionType => ItemDataTransformType.ThreeD; + public override Vector3 GetEditorPosition() + { + var pos = DragPoints.Length == 0 ? Vector3.zero : DragPointCenter; + return new Vector3(pos.x, pos.y, _height); + } + public override void SetEditorPosition(Vector3 pos) { + if (DragPoints.Length == 0) { + return; + } + var diff = (pos - DragPointCenter).ToVertex3D(); + diff.Z = 0f; + foreach (var pt in DragPoints) { + pt.Center += diff; + } + _height = pos.z; + RebuildMeshes(); + } + + public override ItemDataTransformType EditorRotationType => ItemDataTransformType.ThreeD; + public override Vector3 GetEditorRotation() => Rotation; + public override void SetEditorRotation(Vector3 rot) { + Rotation = rot; + RebuildMeshes(); + } + + #endregion + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideComponent.cs.meta new file mode 100644 index 000000000..c408066ee --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f05deabc91c0d3d4db83a445f2a755b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 646999b23e4fc304f9277dee4ad46cd8, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideMeshComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideMeshComponent.cs new file mode 100644 index 000000000..392aba994 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideMeshComponent.cs @@ -0,0 +1,38 @@ +// Visual Pinball Engine +// Copyright (C) 2021 freezy and VPE Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System; +using UnityEngine; +using VisualPinball.Engine.VPT; +using VisualPinball.Engine.VPT.MetalWireGuide; +using VisualPinball.Engine.VPT.Table; +using Mesh = VisualPinball.Engine.VPT.Mesh; + +namespace VisualPinball.Unity +{ + [ExecuteInEditMode] + [AddComponentMenu("Visual Pinball/Mesh/Metal Wire Guide Mesh")] + public class MetalWireGuideMeshComponent : MeshComponent + { + public static readonly Type[] ValidParentTypes = Type.EmptyTypes; + + protected override Mesh GetMesh(MetalWireGuideData data) + => new MetalWireGuideMeshGenerator(MainComponent).GetTransformedMesh(MainComponent.PlayfieldHeight, MainComponent.Height, MainComponent.PlayfieldDetailLevel, MainComponent.Bendradius); + + protected override PbrMaterial GetMaterial(MetalWireGuideData data, Table table) + => new MetalWireGuideMeshGenerator(MainComponent).GetMaterial(table, data); + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideMeshComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideMeshComponent.cs.meta new file mode 100644 index 000000000..c026cfc21 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MetalWireGuide/MetalWireGuideMeshComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bcc8f0e761a7bc145abb5a6f918953aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: a11e8e75e5068e146898cb04a4caa683, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs index 015ae4220..578ada8df 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderComponent.cs @@ -65,6 +65,7 @@ public class PrimitiveColliderComponent : ColliderComponent GetPhysicsMaterialData(Elasticity, ElasticityFalloff, Friction, Scatter, OverwritePhysics); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveMeshComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveMeshComponent.cs index 2744aefe2..de85b983f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveMeshComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveMeshComponent.cs @@ -54,6 +54,7 @@ public class PrimitiveMeshComponent : MeshComponent Spinners = new SerializableDictionary(); public SerializableDictionary Surfaces = new SerializableDictionary(); public SerializableDictionary Triggers = new SerializableDictionary(); + public SerializableDictionary MetalWireGuides = new SerializableDictionary(); public DecalData[] Decals; public DispReelData[] DispReels; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/SceneTableContainer.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/SceneTableContainer.cs index 492741ce4..8a8433c10 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/SceneTableContainer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/SceneTableContainer.cs @@ -46,6 +46,7 @@ using VisualPinball.Engine.VPT.Timer; using VisualPinball.Engine.VPT.Trigger; using VisualPinball.Engine.VPT.Trough; +using VisualPinball.Engine.VPT.MetalWireGuide; using Light = VisualPinball.Engine.VPT.Light.Light; using Material = VisualPinball.Engine.VPT.Material; using Texture = VisualPinball.Engine.VPT.Texture; @@ -281,6 +282,10 @@ private void Add(IMainComponent comp, bool forExport) var troughData = troughComponent.CopyDataTo(new TroughData(), MaterialNames, TextureNames, forExport); Add(comp.gameObject.name, new Trough(troughData)); break; + case MetalWireGuideComponent metalWireGuideComponent: + var metalWireGuideData = metalWireGuideComponent.CopyDataTo(_tableComponent.LegacyContainer.MetalWireGuides.ContainsKey(name) ? _tableComponent.LegacyContainer.MetalWireGuides[name] : new MetalWireGuideData(), MaterialNames, TextureNames, forExport); + Add(comp.gameObject.name, new MetalWireGuide(metalWireGuideData)); + break; } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs index d1152ba8c..43852e5ef 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs @@ -45,6 +45,7 @@ public class TableApi : IApi private readonly Dictionary _teleportersByName = new Dictionary(); private readonly Dictionary _triggersByName = new Dictionary(); private readonly Dictionary _troughsByName = new Dictionary(); + private readonly Dictionary _metalWireGuidesByName = new Dictionary(); private readonly Dictionary _switchablesByName = new Dictionary(); private readonly Dictionary _hittablesByName = new Dictionary(); @@ -67,6 +68,7 @@ public class TableApi : IApi private readonly Dictionary _teleportersByComponent = new Dictionary(); private readonly Dictionary _triggersByComponent = new Dictionary(); private readonly Dictionary _troughsByComponent = new Dictionary(); + private readonly Dictionary _metalWireGuidesByComponent = new Dictionary(); private readonly Dictionary _switchablesByComponent = new Dictionary(); private readonly Dictionary _hittablesByComponent = new Dictionary(); @@ -199,6 +201,14 @@ public TableApi(Player player) public TroughApi Trough(string name) => Get(name); public TroughApi Trough(MonoBehaviour component) => Get(component); + /// + /// Returns a metal wire guide by name. + /// + /// Name of the metal wire guide + /// MetalWireGuide or `null` if no metal wire guide with that name exists. + public MetalWireGuideApi MetalWireGuide(string name) => Get(name); + public MetalWireGuideApi MetalWireGuide(MonoBehaviour component) => Get(component); + /// /// Returns a step rotator by name. /// @@ -295,6 +305,7 @@ private Dictionary GetNameDictionary(Type t) where T : IApi if (t == typeof(TeleporterApi)) return _teleportersByName as Dictionary; if (t == typeof(TriggerApi)) return _triggersByName as Dictionary; if (t == typeof(TroughApi)) return _troughsByName as Dictionary; + if (t == typeof(MetalWireGuideApi)) return _metalWireGuidesByName as Dictionary; // can be null, because we don't track all elements, namely hittable switches return null; @@ -322,6 +333,7 @@ private Dictionary GetComponentDictionary(Type t) where T : if (t == typeof(TeleporterApi)) return _teleportersByComponent as Dictionary; if (t == typeof(TriggerApi)) return _triggersByComponent as Dictionary; if (t == typeof(TroughApi)) return _troughsByComponent as Dictionary; + if (t == typeof(MetalWireGuideApi)) return _metalWireGuidesByComponent as Dictionary; // can be null, because we don't track all elements, namely hittable switches return null; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VisualPinball.Unity.csproj b/VisualPinball.Unity/VisualPinball.Unity/VisualPinball.Unity.csproj index 5d0563777..6519a3f1e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VisualPinball.Unity.csproj +++ b/VisualPinball.Unity/VisualPinball.Unity/VisualPinball.Unity.csproj @@ -3,7 +3,7 @@ netstandard2.1 VisualPinball.Unity A bridge between VisualPinball.Engine and Unity - freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli + freezy;ravarcade;shaderbytes;rbxnk;jsm174;Vroonsh;Rowlan;kleisauke;ecurtz;Pandeli;Cupid Copyright 2021 freezy - <freezy@vpdb.io> 0.1.0.0 0.1.0.0 diff --git a/package.json b/package.json index aea37b651..2c52aff61 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "Rowlan", "Kleis Auke Wolthuizen ", "Eli Curtz ", - "Pandeli" + "Pandeli", + "Cupid" ], "documentationUrl": "https://docs.visualpinball.org/", "changelogUrl": "https://docs.visualpinball.org/CHANGELOG.html",