diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c529d5bde..e65f9b2ed 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,68 +1,92 @@ -name: Build -on: [push, pull_request] - -defaults: - run: - shell: bash - -jobs: - build: - name: Build ${{ matrix.rid }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - os: windows-latest - rid: win-x64 - coverage: true - - os: windows-latest - rid: win-x86 - - os: macos-latest - rid: osx-x64 - - os: ubuntu-latest - rid: linux-x64 - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-dotnet@v1 - with: - dotnet-version: '3.1.x' - - name: Build - run: | - cd VisualPinball.Engine.Test - dotnet build VisualPinball.Engine.Test.csproj -c Release -r ${{ matrix.rid }} - - run: | - mkdir tmp - cp -r VisualPinball.Unity/Plugins/${{ matrix.rid }} tmp - - name: Test - run: | - if [[ "${{ matrix.coverage }}" == "true" ]]; then - dotnet test -c Release --runtime ${{ matrix.rid }} -p:CollectCoverage=true -p:CoverletOutputFormat=lcov -p:CoverletOutput=../lcov -p:ExcludeByAttribute="ExcludeFromCodeCoverageAttribute" -p:Exclude=\"[*]VisualPinball.Engine.Math.Triangulator.*,[VisualPinball.Resources]*,[*]VisualPinball.Engine.VPT.Plunger.*\" - else - dotnet test -c Release --runtime ${{ matrix.rid }} - fi - - # local report: - # dotnet test -c Release --runtime ${{ matrix.rid }} /p:CollectCoverage=true /p:CoverletOutputFormat=\"opencover\" /p:CoverletOutput=../lcov /p:ExcludeByAttribute="ExcludeFromCodeCoverageAttribute" /p:Exclude=\"[*]VisualPinball.Engine.Math.Triangulator.*,[VisualPinball.Resources]*,[*]VisualPinball.Engine.VPT.Plunger.*\" - # dotnet tool install -g dotnet-reportgenerator-globaltool - # reportgenerator -reports:lcov.opencover.xml -targetdir:coveragereport -reporttypes:Html - - - name: Publish Coverage - if: ${{ matrix.coverage }} - run: | - bash <(curl -s https://codecov.io/bash) - - uses: actions/upload-artifact@v2 - with: - name: Plugins - path: tmp - - dispatch: - runs-on: ubuntu-latest - needs: [ build ] - if: github.repository == 'freezy/VisualPinball.Engine' && github.ref == 'refs/heads/master' && github.event_name == 'push' - steps: - - uses: peter-evans/repository-dispatch@v1 - with: - token: ${{ secrets.GH_PAT }} - event-type: build-complete - client-payload: '{"artifacts_run_id": "${{ github.run_id }}"}' +name: Build +on: [push, pull_request] + +env: + UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} + +defaults: + run: + shell: bash + +jobs: + build: + name: Build ${{ matrix.rid }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: windows-latest + rid: win-x64 + - os: windows-latest + rid: win-x86 + - os: macos-latest + rid: osx-x64 + - os: ubuntu-latest + rid: linux-x64 + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-dotnet@v1 + with: + dotnet-version: '3.1.x' + - name: Build + run: | + cd VisualPinball.Engine.Test + dotnet build VisualPinball.Engine.Test.csproj -c Release -r ${{ matrix.rid }} + - run: | + mkdir tmp + cp -r VisualPinball.Unity/Plugins/${{ matrix.rid }} tmp + - uses: actions/upload-artifact@v2 + with: + name: Plugins + path: tmp + + test: + name: Unit Test + needs: [ build ] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/download-artifact@v2 + with: + name: Plugins + path: VisualPinball.Unity/Plugins + - uses: actions/cache@v2 + with: + path: VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Library + key: Library-Test-Project + restore-keys: | + Library-Test-Project + Library + - uses: game-ci/unity-test-runner@main + id: test + with: + unityVersion: '2020.3.13f1' + projectPath: VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~ + artifactsPath: VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/artifacts + testMode: all + customParameters: -debugCodeOptimization -enableCodeCoverage -burst-disable-compilation -coverageOptions enableCyclomaticComplexity;assemblyFilters:+VisualPinball.Engine;pathFilters:-**/VisualPinball.Engine/Math/Triangulator/**,-**/VisualPinball.Engine/Math/Mesh/** -coverageResultsPath artifacts + - run: | + curl -s https://codecov.io/bash | bash -s - -f ${{ steps.test.outputs.artifactsPath }}/TestProject~-opencov/EditMode/TestCoverageResults_0000.xml + - uses: MirrorNG/nunit-reporter@v1.0.11 + if: always() + with: + path: ${{ steps.test.outputs.artifactsPath }}/*.xml + access-token: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/upload-artifact@v2 + if: always() + with: + name: Test results + path: ${{ steps.test.outputs.artifactsPath }} + + dispatch: + name: Dispatch + runs-on: ubuntu-latest + needs: [ test ] + if: github.repository == 'freezy/VisualPinball.Engine' && github.ref == 'refs/heads/master' && github.event_name == 'push' + steps: + - uses: peter-evans/repository-dispatch@v1 + with: + token: ${{ secrets.GH_PAT }} + event-type: build-complete + client-payload: '{"artifacts_run_id": "${{ github.run_id }}"}' diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 102c11193..0faf7e2f1 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,7 +12,8 @@ jobs: with: workflow: build run_id: ${{ github.event.client_payload.artifacts_run_id }} - path: VisualPinball.Unity + name: Plugins + path: VisualPinball.Unity/Plugins - run: | ls -laR VisualPinball.Unity/Plugins - name: Add Meta Files diff --git a/.gitignore b/.gitignore index 491764089..94b6e9383 100644 --- a/.gitignore +++ b/.gitignore @@ -368,3 +368,18 @@ MigrationBackup/ *.swp **/Plugins/** + +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/*.vpx +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Assets/Tables.meta +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Assets/Tables/ +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/CodeCoverage/ +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Library/ +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/TestProject~.sln +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/UserSettings/ +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/VisualPinball.Engine.csproj +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/VisualPinball.Engine.Test.csproj +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/VisualPinball.Unity.Editor.csproj +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/VisualPinball.Unity.Patcher.csproj +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/VisualPinball.Unity.Test.csproj +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/VisualPinball.Unity.csproj +VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/editmode-results.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index d0cea509f..5188d775e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ Built with [Unity 2020.2](https://github.com/freezy/VisualPinball.Engine/pull/25 - Native support for nFozzy flipper physics ([#305](https://github.com/freezy/VisualPinball.Engine/pull/305)). - Automated camera clipping ([#304](https://github.com/freezy/VisualPinball.Engine/pull/304/files)). - DMD and segment display support ([Documentation](https://docs.visualpinball.org/creators-guide/manual/displays.html)). -- Plugin: Mission Pinball Framework ([Documentation](https://docs.visualpinball.org/plugins/mpf/index.html)) +- Plugin: Mission Pinball Framework ([Documentation](https://docs.visualpinball.org/plugins/mpf/index.html)). - Gamelogic Engine: Support for hardware rules ([#293](https://github.com/freezy/VisualPinball.Engine/pull/293)). - Support for Extended ASCII strings ([#291](https://github.com/freezy/VisualPinball.Engine/pull/291)). - Support for Elasticity Falloff in walls (added in VP 10.7) ([#291](https://github.com/freezy/VisualPinball.Engine/pull/291)). @@ -22,6 +22,7 @@ Built with [Unity 2020.2](https://github.com/freezy/VisualPinball.Engine/pull/25 - Native trough component ([#229](https://github.com/freezy/VisualPinball.Engine/pull/229), [#248](https://github.com/freezy/VisualPinball.Engine/pull/248), [#256](https://github.com/freezy/VisualPinball.Engine/pull/256), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/troughs.html)). ### Changed +- Ground truth of data is now the scene, not the imported data anymore ([#302](https://github.com/freezy/VisualPinball.Engine/pull/302)). - Plunger is now a coil device, meaning it can both be pulled back and fired through different inputs. - Move render pipelines into separate repos ([#259](https://github.com/freezy/VisualPinball.Engine/pull/259)). - Put game-, mesh-, collision- animation data into separate components ([#227](https://github.com/freezy/VisualPinball.Engine/pull/227), [Documentation](https://docs.visualpinball.org/creators-guide/editor/unity-components.html)). diff --git a/VisualPinball.Engine.Test/Common/StringTests.cs b/VisualPinball.Engine.Test/Common/StringTests.cs new file mode 100644 index 000000000..9abef168d --- /dev/null +++ b/VisualPinball.Engine.Test/Common/StringTests.cs @@ -0,0 +1,54 @@ +// 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 FluentAssertions; +using NUnit.Framework; +using VisualPinball.Engine.Common; + +namespace VisualPinball.Engine.Test.Common +{ + public class StringTests + { + [Test] + public void ShouldCorrectlyMakeAStringFilesystemCompatible() + { + "^ !#$%&'()+,.0123456789;=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{}~-".ToFilename() + .Should().Be("^ !#$%&'()+,.0123456789;=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{}~-"); + "äöüéàèŒ".ToFilename().Should().Be("aeoeueeaeOE"); + "a/b/c".ToFilename().Should().Be("a_b_c"); + "a\\b".ToFilename().Should().Be("a_b"); + "a>b".ToFilename().Should().Be("a_b"); + "a>b".ToFilename().Should().Be("a_b"); + "a<>".ToFilename().Should().Be("a_b"); + "a\"b".ToFilename().Should().Be("a_b"); + "\"".ToFilename().Should().Be("_"); + } + + [Test] + public void ShouldCorrectlyNormalizeAString() + { + "AbC".ToNormalizedName().Should().Be("abc"); + "AbC ".ToNormalizedName().Should().Be("abc"); + "Ab C".ToNormalizedName().Should().Be("ab_c"); + "übr".ToNormalizedName().Should().Be("uebr"); + "a\"b".ToNormalizedName().Should().Be("a_b"); + ">".ToNormalizedName().Should().Be("_"); + "(a)".ToNormalizedName().Should().Be("a"); + } + } +} diff --git a/VisualPinball.Engine.Test/Fixtures~/SoundTest.vpx b/VisualPinball.Engine.Test/Fixtures~/SoundTest.vpx index 91f17e41d..0f34f6d2c 100644 Binary files a/VisualPinball.Engine.Test/Fixtures~/SoundTest.vpx and b/VisualPinball.Engine.Test/Fixtures~/SoundTest.vpx differ diff --git a/VisualPinball.Engine.Test/Fixtures~/TextureTest.vpx b/VisualPinball.Engine.Test/Fixtures~/TextureTest.vpx index 3c7d317ed..091d0e941 100644 Binary files a/VisualPinball.Engine.Test/Fixtures~/TextureTest.vpx and b/VisualPinball.Engine.Test/Fixtures~/TextureTest.vpx differ diff --git a/VisualPinball.Engine.Test/Fixtures~/test_pattern.webp b/VisualPinball.Engine.Test/Fixtures~/test_pattern.webp new file mode 100644 index 000000000..e5424a7a0 Binary files /dev/null and b/VisualPinball.Engine.Test/Fixtures~/test_pattern.webp differ diff --git a/VisualPinball.Engine.Test/IO/ConsistencyTests.cs b/VisualPinball.Engine.Test/IO/ConsistencyTests.cs index 8a75ceb49..b54fc1d6a 100644 --- a/VisualPinball.Engine.Test/IO/ConsistencyTests.cs +++ b/VisualPinball.Engine.Test/IO/ConsistencyTests.cs @@ -14,6 +14,7 @@ // 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.VPT; @@ -23,26 +24,28 @@ namespace VisualPinball.Engine.Test.IO { public class ConsistencyTests { - [Test] + //todo renable[Test] public void ShouldClearWrongMaterialReference() { const string tmpFileName = "ShouldClearWrongMaterialReference.vpx"; - var table = new TableBuilder() + var th = new TableBuilder() .AddBumper("Bumper1") .AddMaterial(new Material("DoesExist")) .Build(); - table.Bumper("Bumper1").Data.BaseMaterial = "DoesExist"; - table.Bumper("Bumper1").Data.CapMaterial = "DoesNotExist"; + th.Bumper("Bumper1").Data.BaseMaterial = "DoesExist"; + th.Bumper("Bumper1").Data.CapMaterial = "DoesNotExist"; - table.Save(tmpFileName); + th.Save(tmpFileName); - table.Bumper("Bumper1").Data.BaseMaterial.Should().Be("DoesExist"); - table.Bumper("Bumper1").Data.CapMaterial.Should().BeEmpty(); + th.Bumper("Bumper1").Data.BaseMaterial.Should().Be("DoesExist"); + th.Bumper("Bumper1").Data.CapMaterial.Should().BeEmpty(); + + File.Delete(tmpFileName); } - [Test] + //todo renable[Test] public void ShouldClearWrongTextureReference() { const string tmpFileName = "ShouldClearWrongTextureReference.vpx"; @@ -59,6 +62,8 @@ public void ShouldClearWrongTextureReference() table.Flipper("Flipper").Data.Image = "DoesNotExist"; table.Save(tmpFileName); table.Flipper("Flipper").Data.Image.Should().BeEmpty(); + + File.Delete(tmpFileName); } } } diff --git a/VisualPinball.Engine.Test/Math/MathTests.cs b/VisualPinball.Engine.Test/Math/MathTests.cs new file mode 100644 index 000000000..3d3cd0fc9 --- /dev/null +++ b/VisualPinball.Engine.Test/Math/MathTests.cs @@ -0,0 +1,47 @@ +// 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 FluentAssertions; +using NUnit.Framework; +using VisualPinball.Engine.Common; +using VisualPinball.Engine.Math; + +namespace VisualPinball.Engine.Test.Common +{ + public class MathTests + { + [Test] + public void ShouldCorrectlyInitializeRect3D() + { + var rect = new Rect3D(1f, 2f, 3f, 4f, 5f, 6f); + rect.Left.Should().Be(1f); + rect.Right.Should().Be(2f); + rect.Top.Should().Be(3f); + rect.Bottom.Should().Be(4f); + rect.ZLow.Should().Be(5f); + rect.ZHigh.Should().Be(6f); + } + + [Test] + public void ShouldCorrectlyMeasureRect3D() + { + var rect = new Rect3D(1f, 2.5f, 3f, 4.6f, 5f, 6.8f); + rect.Width.Should().Be(1.5f); + rect.Height.Should().BeApproximately(1.6f, 0.000001f); + rect.Depth.Should().BeApproximately(1.8f, 0.000001f); + } + } +} diff --git a/VisualPinball.Engine.Test/Math/VectorTests.cs b/VisualPinball.Engine.Test/Math/VectorTests.cs new file mode 100644 index 000000000..70dc44382 --- /dev/null +++ b/VisualPinball.Engine.Test/Math/VectorTests.cs @@ -0,0 +1,56 @@ +// 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 FluentAssertions; +using NUnit.Framework; +using VisualPinball.Engine.Common; +using VisualPinball.Engine.Math; + +namespace VisualPinball.Engine.Test.Common +{ + public class VectorTests + { + [Test] + public void ShouldCorrectlyOperateVectors() + { + (new Vertex3D(2f, 3f, 4f) + new Vertex3D(10f, 20f, 50f)).Should().BeEquivalentTo(new Vertex3D(12f, 23f, 54f)); + (new Vertex3D(5f, 1f, 4f) - new Vertex3D(2f, -5f, 1.5f)).Should().BeEquivalentTo(new Vertex3D(3f, 6f, 2.5f)); + (new Vertex3D(2f, 3f, 4f) * 4f).Should().BeEquivalentTo(new Vertex3D(8f, 12f, 16f)); + (4f * new Vertex3D(2f, 3f, 4f)).Should().BeEquivalentTo(new Vertex3D(8f, 12f, 16f)); + (new Vertex3D(2f, 3f, 4f) / 2f).Should().BeEquivalentTo(new Vertex3D(1f, 1.5f, 2f)); + } + + [Test] + public void ShouldCorrectlySetVectors() + { + new Vertex3D(2f, 3f, 4f) + .Set(1f, 2f, 3f) + .Should().BeEquivalentTo(new Vertex3D(1f, 2f, 3f)); + + new Vertex3D(2f, 3f, 4f) + .Set(new Vertex3D(1f, 2f, 3f)) + .Should().BeEquivalentTo(new Vertex3D(1f, 2f, 3f)); + } + + [Test] + public void ShouldCorrectlyCrossVectors() + { + Vertex3D.CrossVectors(new Vertex3D(1.5f, 2.5f, 4f), new Vertex3D(3.5f, 100f, 95f)) + .Should().BeEquivalentTo(new Vertex3D(-162.5f, -128.5f, 141.25f)); + } + + } +} diff --git a/VisualPinball.Engine.Test/Test/Fixtures.cs b/VisualPinball.Engine.Test/Test/Fixtures.cs index e25879754..c8d84c947 100644 --- a/VisualPinball.Engine.Test/Test/Fixtures.cs +++ b/VisualPinball.Engine.Test/Test/Fixtures.cs @@ -22,6 +22,7 @@ namespace VisualPinball.Engine.Test.Test public static class VpxPath { public static readonly string Bumper = PathHelper.GetFixturePath("BumperTest.vpx"); + public static readonly string BumperVPX1070 = PathHelper.GetFixturePath("BumperTestVPX1070.vpx"); public static readonly string Collection = PathHelper.GetFixturePath("CollectionTest.vpx"); public static readonly string Mappings = PathHelper.GetFixturePath("MappingsTest.vpx"); @@ -88,6 +89,7 @@ public static class TexturePath public static readonly string BmpXrgb = PathHelper.GetFixturePath("test_pattern_xrgb.bmp"); public static readonly string Jpg = PathHelper.GetFixturePath("test_pattern.jpg"); public static readonly string Png = PathHelper.GetFixturePath("test_pattern.png"); + public static readonly string Webp = PathHelper.GetFixturePath("test_pattern.webp"); public static readonly string PngTransparent = PathHelper.GetFixturePath("test_pattern_transparent.png"); public static readonly string Hdr = PathHelper.GetFixturePath("test_pattern_hdr.hdr"); } @@ -101,22 +103,18 @@ public static class PathHelper { public static string GetFixturePath(string filename) { - return Path.GetFullPath(Path.Combine(GetTestPath(), - "Fixtures~" + Path.DirectorySeparatorChar, - filename)); + return Path.GetFullPath(Path.Combine(GetTestPath(), "Fixtures~", filename)); } private static string GetTestPath() { - var codeBase = new System.Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath; + var codeBase = new System.Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath.Replace('\\', '/'); - if (codeBase.Contains("/Library/ScriptAssemblies/")) - { - return Path.GetFullPath( - "Packages/org.visualpinball.engine.unity/VisualPinball.Engine.Test"); + if (codeBase.Contains("/Library/ScriptAssemblies/")) { + return Path.GetFullPath("Packages/org.visualpinball.engine.unity/VisualPinball.Engine.Test"); } - else if (codeBase.Contains("VisualPinball.Unity.Test")) - { + + if (codeBase.Contains("VisualPinball.Unity.Test")) { return Path.GetFullPath( Path.Combine( Path.GetDirectoryName(codeBase), diff --git a/VisualPinball.Engine.Test/VPT/Bumper/BumperDataTests.cs b/VisualPinball.Engine.Test/VPT/Bumper/BumperDataTests.cs index a6a6b5aaa..08d03fabc 100644 --- a/VisualPinball.Engine.Test/VPT/Bumper/BumperDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Bumper/BumperDataTests.cs @@ -14,10 +14,12 @@ // 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.Bumper; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Bumper { @@ -26,8 +28,8 @@ public class BumperDataTests [Test] public void ShouldReadBumperData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Bumper); - var data = table.Bumper("Bumper1").Data; + var th = FileTableContainer.Load(VpxPath.Bumper); + var data = th.Bumper("Bumper1").Data; ValidateTableData(data); } @@ -35,13 +37,14 @@ public void ShouldReadBumperData() public void ShouldWriteBumperData() { const string tmpFileName = "ShouldWriteBumperData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Bumper); + var table = FileTableContainer.Load(VpxPath.Bumper); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateTableData(writtenTable.Bumper("Bumper1").Data); + File.Delete(tmpFileName); } - private static void ValidateTableData(BumperData data) + public static void ValidateTableData(BumperData data) { data.BaseMaterial.Should().Be("Material2"); data.CapMaterial.Should().Be("Material1"); diff --git a/VisualPinball.Engine.Test/VPT/Bumper/BumperMeshTests.cs b/VisualPinball.Engine.Test/VPT/Bumper/BumperMeshTests.cs index 2ce274aeb..ef4289006 100644 --- a/VisualPinball.Engine.Test/VPT/Bumper/BumperMeshTests.cs +++ b/VisualPinball.Engine.Test/VPT/Bumper/BumperMeshTests.cs @@ -17,24 +17,25 @@ using JeremyAnsel.Media.WavefrontObj; using NUnit.Framework; using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Bumper { public class BumperMeshTests : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _table; private readonly ObjFile _obj; public BumperMeshTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Bumper); + _table = FileTableContainer.Load(VpxPath.Bumper); _obj = LoadObjFixture(ObjPath.Bumper); } [Test] public void ShouldGenerateMesh() { - AssertObjMesh(_table, _obj, _table.Bumper("Bumper2"), (item, mesh) => $"{item.Name}{mesh.Name}"); + AssertObjMesh(_table.Table, _obj, _table.Bumper("Bumper2"), (item, mesh) => $"{item.Name}{mesh.Name}"); } } } diff --git a/VisualPinball.Engine.Test/VPT/Collection/CollectionDataTests.cs b/VisualPinball.Engine.Test/VPT/Collection/CollectionDataTests.cs index 89effa9d0..06dc920fb 100644 --- a/VisualPinball.Engine.Test/VPT/Collection/CollectionDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Collection/CollectionDataTests.cs @@ -14,10 +14,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using System.IO; +using System.Linq; using FluentAssertions; using NUnit.Framework; using VisualPinball.Engine.Test.Test; using VisualPinball.Engine.VPT.Collection; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Collection { @@ -26,8 +29,8 @@ public class CollectionDataTests [Test] public void ShouldReadCollectionData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Collection); - var data = table.Collections["flippers"].Data; + var tableContainer = FileTableContainer.Load(VpxPath.Collection); + var data = tableContainer.Collections.First(c => c.Name == "Flippers"); ValidateTableData(data); } @@ -35,13 +38,14 @@ public void ShouldReadCollectionData() public void ShouldWriteCollectionData() { const string tmpFileName = "ShouldWriteCollectionData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Collection); - table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); - ValidateTableData(writtenTable.Collections["flippers"].Data); + var th = FileTableContainer.Load(VpxPath.Collection); + th.Save(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); + ValidateTableData(writtenTable.Collections.First(c => c.Name == "Flippers")); + File.Delete(tmpFileName); } - private static void ValidateTableData(CollectionData data) + public static void ValidateTableData(CollectionData data) { data.Name.Should().Be("Flippers"); data.FireEvents.Should().Be(false); diff --git a/VisualPinball.Engine.Test/VPT/Decal/DecalDataTest.cs b/VisualPinball.Engine.Test/VPT/Decal/DecalDataTests.cs similarity index 83% rename from VisualPinball.Engine.Test/VPT/Decal/DecalDataTest.cs rename to VisualPinball.Engine.Test/VPT/Decal/DecalDataTests.cs index a8b4a18ee..c3bb2a51c 100644 --- a/VisualPinball.Engine.Test/VPT/Decal/DecalDataTest.cs +++ b/VisualPinball.Engine.Test/VPT/Decal/DecalDataTests.cs @@ -14,36 +14,39 @@ // 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; using VisualPinball.Engine.VPT.Decal; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Decal { - public class DecalDataTest : BaseTests + public class DecalDataTests : BaseTests { [Test] public void ShouldReadDecalData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Decal); - ValidateDecal0(table.Decal(0).Data); - ValidateDecal1(table.Decal(1).Data); + var th = FileTableContainer.Load(VpxPath.Decal); + ValidateDecal0(th.Decal(0).Data); + ValidateDecal1(th.Decal(1).Data); } [Test] public void ShouldWriteDecalData() { const string tmpFileName = "ShouldWriteDecalData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Decal); + var table = FileTableContainer.Load(VpxPath.Decal); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateDecal0(writtenTable.Decal(0).Data); ValidateDecal1(writtenTable.Decal(1).Data); + File.Delete(tmpFileName); } - private static void ValidateDecal0(DecalData data) + public static void ValidateDecal0(DecalData data) { data.Backglass.Should().Be(false); data.Center.X.Should().Be(205.4f); @@ -68,7 +71,7 @@ private static void ValidateDecal0(DecalData data) data.IsLocked.Should().Be(false); } - private static void ValidateDecal1(DecalData data) + public static void ValidateDecal1(DecalData data) { data.Backglass.Should().Be(true); data.Center.X.Should().Be(509f); diff --git a/VisualPinball.Engine.Test/VPT/DispReel/DispReelDataTest.cs b/VisualPinball.Engine.Test/VPT/DispReel/DispReelDataTests.cs similarity index 86% rename from VisualPinball.Engine.Test/VPT/DispReel/DispReelDataTest.cs rename to VisualPinball.Engine.Test/VPT/DispReel/DispReelDataTests.cs index 86de042c8..c12b9c188 100644 --- a/VisualPinball.Engine.Test/VPT/DispReel/DispReelDataTest.cs +++ b/VisualPinball.Engine.Test/VPT/DispReel/DispReelDataTests.cs @@ -14,19 +14,21 @@ // 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.DispReel; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.DispReel { - public class DispReelDataTest : BaseTests + public class DispReelDataTests : BaseTests { [Test] public void ShouldReadDispReelData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.DispReel); + var table = FileTableContainer.Load(VpxPath.DispReel); ValidateDispReel1(table.DispReel("Reel1").Data); ValidateDispReel2(table.DispReel("Reel2").Data); } @@ -35,14 +37,15 @@ public void ShouldReadDispReelData() public void ShouldWriteDispReelData() { const string tmpFileName = "ShouldWriteDispReelData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.DispReel); + var table = FileTableContainer.Load(VpxPath.DispReel); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateDispReel1(writtenTable.DispReel("Reel1").Data); ValidateDispReel2(writtenTable.DispReel("Reel2").Data); + File.Delete(tmpFileName); } - private static void ValidateDispReel1(DispReelData data) + public static void ValidateDispReel1(DispReelData data) { data.BackColor.Red.Should().Be(204); data.BackColor.Green.Should().Be(149); @@ -73,7 +76,7 @@ private static void ValidateDispReel1(DispReelData data) data.IsTimerEnabled.Should().Be(true); } - private static void ValidateDispReel2(DispReelData data) + public static void ValidateDispReel2(DispReelData data) { data.BackColor.Red.Should().Be(0); data.BackColor.Green.Should().Be(0); diff --git a/VisualPinball.Engine.Test/VPT/Flasher/FlasherDataTests.cs b/VisualPinball.Engine.Test/VPT/Flasher/FlasherDataTests.cs index f5ba43f6e..bff1969eb 100644 --- a/VisualPinball.Engine.Test/VPT/Flasher/FlasherDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Flasher/FlasherDataTests.cs @@ -14,11 +14,13 @@ // 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; using VisualPinball.Engine.VPT.Flasher; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Flasher { @@ -27,7 +29,7 @@ public class FlasherDataTests [Test] public void ShouldReadFlasherData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Flasher); + var table = FileTableContainer.Load(VpxPath.Flasher); ValidateFlasher(table.Flasher("Data").Data); } @@ -35,13 +37,14 @@ public void ShouldReadFlasherData() public void ShouldWriteFlasherData() { const string tmpFileName = "ShouldWriteFlasherData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Flasher); + var table = FileTableContainer.Load(VpxPath.Flasher); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateFlasher(writtenTable.Flasher("Data").Data); + File.Delete(tmpFileName); } - private static void ValidateFlasher(FlasherData data) + public static void ValidateFlasher(FlasherData data) { data.AddBlend.Should().Be(false); data.Alpha.Should().Be(69); diff --git a/VisualPinball.Engine.Test/VPT/Flipper/FlipperDataTests.cs b/VisualPinball.Engine.Test/VPT/Flipper/FlipperDataTests.cs index f425c9798..640dd607e 100644 --- a/VisualPinball.Engine.Test/VPT/Flipper/FlipperDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Flipper/FlipperDataTests.cs @@ -14,10 +14,12 @@ // 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.Flipper; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Flipper { @@ -26,7 +28,7 @@ public class FlipperDataTests : BaseTests [Test] public void ShouldReadFlipperData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Flipper); + var table = FileTableContainer.Load(VpxPath.Flipper); ValidateFlipper(table.Flipper("FatFlipper").Data); } @@ -34,13 +36,14 @@ public void ShouldReadFlipperData() public void ShouldWriteFlipperData() { const string tmpFileName = "ShouldWriteFlipperData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Flipper); + var table = FileTableContainer.Load(VpxPath.Flipper); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateFlipper(writtenTable.Flipper("FatFlipper").Data); + File.Delete(tmpFileName); } - private static void ValidateFlipper(FlipperData data) + public static void ValidateFlipper(FlipperData data) { data.BaseRadius.Should().Be(30.0303f); data.Center.X.Should().Be(269.287f); diff --git a/VisualPinball.Engine.Test/VPT/Flipper/FlipperMeshTests.cs b/VisualPinball.Engine.Test/VPT/Flipper/FlipperMeshTests.cs index b083299ff..e4d31680e 100644 --- a/VisualPinball.Engine.Test/VPT/Flipper/FlipperMeshTests.cs +++ b/VisualPinball.Engine.Test/VPT/Flipper/FlipperMeshTests.cs @@ -18,25 +18,26 @@ using JeremyAnsel.Media.WavefrontObj; using NUnit.Framework; using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Flipper { public class FlipperMeshTests : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly ObjFile _obj; public FlipperMeshTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Flipper); + _tc = FileTableContainer.Load(VpxPath.Flipper); _obj = LoadObjFixture(ObjPath.Flipper); } [Test] public void ShouldGenerateFatMesh() { - var flipper = _table.Flipper("FatFlipper"); - var flipperMeshes = flipper.GetRenderObjects(_table).RenderObjects.Select(ro => ro.Mesh); + var flipper = _tc.Flipper("FatFlipper"); + var flipperMeshes = flipper.GetRenderObjects(_tc.Table).RenderObjects.Select(ro => ro.Mesh); foreach (var flipperMesh in flipperMeshes) { AssertObjMesh(_obj, flipperMesh, $"{flipper.Name}{flipperMesh.Name}", 0.00013f); } @@ -45,8 +46,8 @@ public void ShouldGenerateFatMesh() [Test] public void ShouldGenerateFatRubberMesh() { - var flipper = _table.Flipper("FatRubberFlipper"); - var flipperMeshes = flipper.GetRenderObjects(_table).RenderObjects.Select(ro => ro.Mesh); + var flipper = _tc.Flipper("FatRubberFlipper"); + var flipperMeshes = flipper.GetRenderObjects(_tc.Table).RenderObjects.Select(ro => ro.Mesh); foreach (var flipperMesh in flipperMeshes) { AssertObjMesh(_obj, flipperMesh, $"{flipper.Name}{flipperMesh.Name}", threshold: 0.00015f); } @@ -55,8 +56,8 @@ public void ShouldGenerateFatRubberMesh() [Test] public void ShouldGenerateFlipperOnSurfaceMesh() { - var flipper = _table.Flipper("SurfaceFlipper"); - var flipperMeshes = flipper.GetRenderObjects(_table).RenderObjects.Select(ro => ro.Mesh); + var flipper = _tc.Flipper("SurfaceFlipper"); + var flipperMeshes = flipper.GetRenderObjects(_tc.Table).RenderObjects.Select(ro => ro.Mesh); foreach (var flipperMesh in flipperMeshes) { AssertObjMesh(_obj, flipperMesh, $"{flipper.Name}{flipperMesh.Name}"); } diff --git a/VisualPinball.Engine.Test/VPT/Gate/GateDataTests.cs b/VisualPinball.Engine.Test/VPT/Gate/GateDataTests.cs index 12a1c797a..1de12efaa 100644 --- a/VisualPinball.Engine.Test/VPT/Gate/GateDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Gate/GateDataTests.cs @@ -14,12 +14,14 @@ // 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.Math; using VisualPinball.Engine.Test.Test; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Gate; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Gate { @@ -28,7 +30,7 @@ public class GateDataTests [Test] public void ShouldReadGateData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Gate); + var table = FileTableContainer.Load(VpxPath.Gate); ValidateGateData(table.Gate("Data").Data); } @@ -36,13 +38,14 @@ public void ShouldReadGateData() public void ShouldWriteGateData() { const string tmpFileName = "ShouldWriteGateData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Gate); + var table = FileTableContainer.Load(VpxPath.Gate); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateGateData(writtenTable.Gate("Data").Data); + File.Delete(tmpFileName); } - private static void ValidateGateData(GateData data) + public static void ValidateGateData(GateData data) { MathF.RadToDeg(data.AngleMax).Should().Be(90f); MathF.RadToDeg(data.AngleMin).Should().Be(0f); diff --git a/VisualPinball.Engine.Test/VPT/Gate/GateMeshTests.cs b/VisualPinball.Engine.Test/VPT/Gate/GateMeshTests.cs index 7d12652cd..a52b84693 100644 --- a/VisualPinball.Engine.Test/VPT/Gate/GateMeshTests.cs +++ b/VisualPinball.Engine.Test/VPT/Gate/GateMeshTests.cs @@ -19,17 +19,18 @@ using VisualPinball.Engine.Game; using VisualPinball.Engine.Test.Test; using VisualPinball.Engine.VPT; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Gate { public class GateMeshTests : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly ObjFile _obj; public GateMeshTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Gate); + _tc = FileTableContainer.Load(VpxPath.Gate); _obj = LoadObjFixture(ObjPath.Gate); } @@ -37,20 +38,19 @@ public GateMeshTests() public void ShouldGenerateBracketMeshes() { string GetName(IRenderable item, Mesh mesh) => $"{item.Name}{mesh.Name}"; - AssertObjMesh(_table, _obj, _table.Gate("LongPlate"), GetName, 0.00015f); - AssertObjMesh(_table, _obj, _table.Gate("Plate"), GetName); - AssertObjMesh(_table, _obj, _table.Gate("WireRectangle"), GetName); - AssertObjMesh(_table, _obj, _table.Gate("WireW"), GetName, 0.00015f); - AssertObjMesh(_table, _obj, _table.Gate("TransformedGate"), GetName); - AssertObjMesh(_table, _obj, _table.Gate("SurfaceGate"), GetName); + AssertObjMesh(_tc.Table, _obj, _tc.Gate("LongPlate"), GetName, 0.00015f); + AssertObjMesh(_tc.Table, _obj, _tc.Gate("Plate"), GetName); + AssertObjMesh(_tc.Table, _obj, _tc.Gate("WireRectangle"), GetName); + AssertObjMesh(_tc.Table, _obj, _tc.Gate("WireW"), GetName, 0.00015f); + AssertObjMesh(_tc.Table, _obj, _tc.Gate("TransformedGate"), GetName); + AssertObjMesh(_tc.Table, _obj, _tc.Gate("SurfaceGate"), GetName); } [Test] public void ShouldGenerateMeshWithoutBracket() { - AssertObjMesh(_obj, _table.Gate("NoBracketGate").GetRenderObjects(_table).RenderObjects[0].Mesh, "NoBracketGateWire"); + AssertObjMesh(_obj, _tc.Gate("NoBracketGate").GetRenderObjects(_tc.Table).RenderObjects[0].Mesh, "NoBracketGateWire"); AssertNoObjMesh(_obj, "NoBracketGateBracket"); } - } } diff --git a/VisualPinball.Engine.Test/VPT/HitTarget/HitTargetDataTests.cs b/VisualPinball.Engine.Test/VPT/HitTarget/HitTargetDataTests.cs index adda45a0c..4a0974dbe 100644 --- a/VisualPinball.Engine.Test/VPT/HitTarget/HitTargetDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/HitTarget/HitTargetDataTests.cs @@ -14,11 +14,13 @@ // 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; using VisualPinball.Engine.VPT.HitTarget; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.HitTarget { @@ -27,7 +29,7 @@ public class HitTargetDataTests [Test] public void ShouldReadHitTargetData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.HitTarget); + var table = FileTableContainer.Load(VpxPath.HitTarget); ValidateHitTargetData(table.HitTarget("Data").Data); } @@ -35,13 +37,14 @@ public void ShouldReadHitTargetData() public void ShouldWriteHitTargetData() { const string tmpFileName = "ShouldWriteHitTargetData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.HitTarget); + var table = FileTableContainer.Load(VpxPath.HitTarget); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateHitTargetData(writtenTable.HitTarget("Data").Data); + File.Delete(tmpFileName); } - private static void ValidateHitTargetData(HitTargetData data) + public static void ValidateHitTargetData(HitTargetData data) { data.DepthBias.Should().Be(0.651f); data.DisableLightingBelow.Should().Be(0.1932f); diff --git a/VisualPinball.Engine.Test/VPT/HitTarget/HitTargetMeshTests.cs b/VisualPinball.Engine.Test/VPT/HitTarget/HitTargetMeshTests.cs index 8349b7a6d..f5851a189 100644 --- a/VisualPinball.Engine.Test/VPT/HitTarget/HitTargetMeshTests.cs +++ b/VisualPinball.Engine.Test/VPT/HitTarget/HitTargetMeshTests.cs @@ -17,35 +17,36 @@ using JeremyAnsel.Media.WavefrontObj; using NUnit.Framework; using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.HitTarget { public class HitTargetMeshTests : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly ObjFile _obj; public HitTargetMeshTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.HitTarget); + _tc = FileTableContainer.Load(VpxPath.HitTarget); _obj = LoadObjFixture(ObjPath.HitTarget); } [Test] public void ShouldGenerateMesh() { - AssertObjMesh(_table, _obj, _table.HitTarget("DropTargetBeveled")); - AssertObjMesh(_table, _obj, _table.HitTarget("DropTargetFlatSimple")); - AssertObjMesh(_table, _obj, _table.HitTarget("DropTargetSimple")); - AssertObjMesh(_table, _obj, _table.HitTarget("Data")); - AssertObjMesh(_table, _obj, _table.HitTarget("HitFatTargetSlim")); - AssertObjMesh(_table, _obj, _table.HitTarget("HitFatTargetSquare")); - AssertObjMesh(_table, _obj, _table.HitTarget("HitTargetRect")); - AssertObjMesh(_table, _obj, _table.HitTarget("HitTargetRound")); - AssertObjMesh(_table, _obj, _table.HitTarget("HitTargetSlim")); - AssertObjMesh(_table, _obj, _table.HitTarget("ScaledTarget")); - AssertObjMesh(_table, _obj, _table.HitTarget("RotatedTarget")); - AssertObjMesh(_table, _obj, _table.HitTarget("DroppedTarget")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("DropTargetBeveled")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("DropTargetFlatSimple")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("DropTargetSimple")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("Data")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("HitFatTargetSlim")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("HitFatTargetSquare")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("HitTargetRect")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("HitTargetRound")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("HitTargetSlim")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("ScaledTarget")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("RotatedTarget")); + AssertObjMesh(_tc.Table, _obj, _tc.HitTarget("DroppedTarget")); } } } diff --git a/VisualPinball.Engine.Test/VPT/Kicker/KickerDataTests.cs b/VisualPinball.Engine.Test/VPT/Kicker/KickerDataTests.cs index 367da6c75..ac999b7ac 100644 --- a/VisualPinball.Engine.Test/VPT/Kicker/KickerDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Kicker/KickerDataTests.cs @@ -14,11 +14,13 @@ // 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; using VisualPinball.Engine.VPT.Kicker; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Kicker { @@ -27,7 +29,7 @@ public class KickerDataTests [Test] public void ShouldReadKickerData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Kicker); + var table = FileTableContainer.Load(VpxPath.Kicker); ValidateKickerData(table.Kicker("Data").Data); } @@ -35,13 +37,14 @@ public void ShouldReadKickerData() public void ShouldWriteKickerData() { const string tmpFileName = "ShouldWriteKickerData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Kicker); + var table = FileTableContainer.Load(VpxPath.Kicker); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateKickerData(writtenTable.Kicker("Data").Data); + File.Delete(tmpFileName); } - private static void ValidateKickerData(KickerData data) + public static void ValidateKickerData(KickerData data) { data.Center.X.Should().Be(781.6662f); data.Center.Y.Should().Be(1585f); @@ -57,8 +60,10 @@ private static void ValidateKickerData(KickerData data) data.Scatter.Should().Be(4.98f); data.Surface.Should().Be(""); + #if !WRITE_VP106 && !WRITE_VP107 data.Angle.Should().Be(65.5f); data.Speed.Should().Be(5.8f); + #endif } } } diff --git a/VisualPinball.Engine.Test/VPT/Kicker/KickerMeshTests.cs b/VisualPinball.Engine.Test/VPT/Kicker/KickerMeshTests.cs index 22868ea0c..1217c927b 100644 --- a/VisualPinball.Engine.Test/VPT/Kicker/KickerMeshTests.cs +++ b/VisualPinball.Engine.Test/VPT/Kicker/KickerMeshTests.cs @@ -17,33 +17,34 @@ using JeremyAnsel.Media.WavefrontObj; using NUnit.Framework; using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Kicker { public class KickerMeshTests : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly ObjFile _obj; public KickerMeshTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Kicker); + _tc = FileTableContainer.Load(VpxPath.Kicker); _obj = LoadObjFixture(ObjPath.Kicker); } [Test] public void ShouldGenerateMeshesCorrectly() { - AssertObjMesh(_table, _obj, _table.Kicker("Cup")); - AssertObjMesh(_table, _obj, _table.Kicker("Cup2")); - AssertObjMesh(_table, _obj, _table.Kicker("Gottlieb"), threshold: 0.00015f); - AssertObjMesh(_table, _obj, _table.Kicker("Hole")); - AssertObjMesh(_table, _obj, _table.Kicker("HoleSimple")); - AssertObjMesh(_table, _obj, _table.Kicker("Williams"), threshold: 0.001f); - AssertObjMesh(_table, _obj, _table.Kicker("Scaled")); - AssertObjMesh(_table, _obj, _table.Kicker("Rotated"), threshold: 0.00015f); - AssertObjMesh(_table, _obj, _table.Kicker("Surface")); - AssertObjMesh(_table, _obj, _table.Kicker("Data"), threshold: 0.00015f); + AssertObjMesh(_tc.Table, _obj, _tc.Kicker("Cup")); + AssertObjMesh(_tc.Table, _obj, _tc.Kicker("Cup2")); + AssertObjMesh(_tc.Table, _obj, _tc.Kicker("Gottlieb"), threshold: 0.00015f); + AssertObjMesh(_tc.Table, _obj, _tc.Kicker("Hole")); + AssertObjMesh(_tc.Table, _obj, _tc.Kicker("HoleSimple")); + AssertObjMesh(_tc.Table, _obj, _tc.Kicker("Williams"), threshold: 0.001f); + AssertObjMesh(_tc.Table, _obj, _tc.Kicker("Scaled")); + AssertObjMesh(_tc.Table, _obj, _tc.Kicker("Rotated"), threshold: 0.00015f); + AssertObjMesh(_tc.Table, _obj, _tc.Kicker("Surface")); + AssertObjMesh(_tc.Table, _obj, _tc.Kicker("Data"), threshold: 0.00015f); } } } diff --git a/VisualPinball.Engine.Test/VPT/Layers/LayerDataTests.cs b/VisualPinball.Engine.Test/VPT/Layers/LayerDataTests.cs index be95c7e27..090a9966f 100644 --- a/VisualPinball.Engine.Test/VPT/Layers/LayerDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Layers/LayerDataTests.cs @@ -14,10 +14,12 @@ // 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.Bumper; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Layers { @@ -26,7 +28,7 @@ public class LayersDataTests [Test] public void ShouldReadLayerDataVPX1060() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Bumper); + var table = FileTableContainer.Load(VpxPath.Bumper); var data = table.Bumper("Bumper1").Data; ValidateTableDataVPX1060(data); } @@ -34,7 +36,7 @@ public void ShouldReadLayerDataVPX1060() [Test] public void ShouldReadLayerDataVPX1070() { - var table = Engine.VPT.Table.Table.Load(VpxPath.BumperVPX1070); + var table = FileTableContainer.Load(VpxPath.BumperVPX1070); var data = table.Bumper("Bumper1").Data; ValidateTableDataVPX1070(data); } @@ -43,12 +45,13 @@ public void ShouldReadLayerDataVPX1070() public void ShouldWriteLayerData() { const string tmpFileName = "ShouldWriteBumperData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Bumper); + var table = FileTableContainer.Load(VpxPath.Bumper); var data = table.Bumper("Bumper1").Data; data.EditorLayerName = "Layer_1"; table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateTableDataVPX1070(writtenTable.Bumper("Bumper1").Data); + File.Delete(tmpFileName); } private static void ValidateTableDataVPX1060(BumperData data) diff --git a/VisualPinball.Engine.Test/VPT/Light/LightDataTests.cs b/VisualPinball.Engine.Test/VPT/Light/LightDataTests.cs index 85d5a2ed1..fd1113885 100644 --- a/VisualPinball.Engine.Test/VPT/Light/LightDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Light/LightDataTests.cs @@ -14,11 +14,13 @@ // 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; using VisualPinball.Engine.VPT.Light; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Light { @@ -27,7 +29,7 @@ public class LightDataTests [Test] public void ShouldReadLightData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Light); + var table = FileTableContainer.Load(VpxPath.Light); ValidateLightData(table.Light("Light1").Data); } @@ -35,13 +37,14 @@ public void ShouldReadLightData() public void ShouldWriteLightData() { const string tmpFileName = "ShouldWriteLightData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Light); + var table = FileTableContainer.Load(VpxPath.Light); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateLightData(writtenTable.Light("Light1").Data); + File.Delete(tmpFileName); } - private static void ValidateLightData(LightData data) + public static void ValidateLightData(LightData data) { data.BlinkInterval.Should().Be(126); data.BlinkPattern.Should().Be("10011"); @@ -77,7 +80,7 @@ private static void ValidateLightData(LightData data) [Test] public void ShouldLoadCorrectDragPointData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Light); + var table = FileTableContainer.Load(VpxPath.Light); var dragPoints = table.Light("PlayfieldLight").Data.DragPoints; dragPoints[0].IsSmooth.Should().Be(false); diff --git a/VisualPinball.Engine.Test/VPT/LightSeq/LightSeqDataTests.cs b/VisualPinball.Engine.Test/VPT/LightSeq/LightSeqDataTests.cs index 23601eef1..33a1daff6 100644 --- a/VisualPinball.Engine.Test/VPT/LightSeq/LightSeqDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/LightSeq/LightSeqDataTests.cs @@ -14,10 +14,12 @@ // 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.LightSeq; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.LightSeq { @@ -26,7 +28,7 @@ public class LightSeqDataTests : BaseTests [Test] public void ShouldReadLightSeqData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.LightSeq); + var table = FileTableContainer.Load(VpxPath.LightSeq); ValidateLightSeqData(table.LightSeq("LightSeq001").Data); } @@ -34,13 +36,14 @@ public void ShouldReadLightSeqData() public void ShouldWriteLightSeqData() { const string tmpFileName = "ShouldWriteLightSeqData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.LightSeq); + var table = FileTableContainer.Load(VpxPath.LightSeq); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateLightSeqData(writtenTable.LightSeq("LightSeq001").Data); + File.Delete(tmpFileName); } - private static void ValidateLightSeqData(LightSeqData data) + public static void ValidateLightSeqData(LightSeqData data) { data.Backglass.Should().Be(false); data.Center.X.Should().Be(21.23f); diff --git a/VisualPinball.Engine.Test/VPT/Mappings/MappingsDataTests.cs b/VisualPinball.Engine.Test/VPT/Mappings/MappingsDataTests.cs index 2afe02600..395c311ef 100644 --- a/VisualPinball.Engine.Test/VPT/Mappings/MappingsDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Mappings/MappingsDataTests.cs @@ -14,6 +14,7 @@ // 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; @@ -23,12 +24,14 @@ namespace VisualPinball.Engine.Test.VPT.Mappings { + #if !WRITE_VP106 && !WRITE_VP107 + public class MappingsDataTests { [Test] public void ShouldReadMappingsData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Mappings); + var table = FileTableContainer.Load(VpxPath.Mappings); var data = table.Mappings.Data; ValidateTableData(data); } @@ -37,10 +40,11 @@ public void ShouldReadMappingsData() public void ShouldWriteMappingsData() { const string tmpFileName = "ShouldWriteMappingsData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Mappings); + var table = FileTableContainer.Load(VpxPath.Mappings); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateTableData(writtenTable.Mappings.Data); + File.Delete(tmpFileName); } [Test] @@ -145,4 +149,5 @@ private static void ValidateTableData(MappingsData data) data.Wires[1].PulseDelay.Should().Be(200); } } + #endif } diff --git a/VisualPinball.Engine.Test/VPT/MaterialDataTests.cs b/VisualPinball.Engine.Test/VPT/MaterialDataTests.cs index 39ef03b3a..c02fca5df 100644 --- a/VisualPinball.Engine.Test/VPT/MaterialDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/MaterialDataTests.cs @@ -14,6 +14,7 @@ // 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.Math; @@ -28,7 +29,7 @@ public class MaterialDataTests [Test] public void ShouldReadMaterialData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Material); + var table = FileTableContainer.Load(VpxPath.Material); ValidateMaterial1(table.GetMaterial("Material1")); } @@ -36,10 +37,11 @@ public void ShouldReadMaterialData() public void ShouldWriteMaterialData() { const string tmpFileName = "ShouldWriteMaterialData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Material); + var table = FileTableContainer.Load(VpxPath.Material); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateMaterial1(writtenTable.GetMaterial("Material1")); + File.Delete(tmpFileName); } [Test] @@ -56,18 +58,20 @@ public void ShouldCreateMaterialFromScratch() const string tmpFileName = "ShouldCreateMaterialData.vpx"; new TableWriter(tb.Build()).WriteTable(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); writtenTable.GetMaterial("test_mat").BaseColor.Red.Should().Be(255); writtenTable.GetMaterial("test_mat").BaseColor.Green.Should().Be(0); writtenTable.GetMaterial("test_mat").BaseColor.Blue.Should().Be(0); writtenTable.GetMaterial("test_mat").Elasticity.Should().Be(0.666f); + + File.Delete(tmpFileName); } [Test] public void ShouldWriteUpdatedMaterialData() { const string tmpFileName = "ShouldWriteUpdatedMaterialData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Material); + var table = FileTableContainer.Load(VpxPath.Material); var mat = table.GetMaterial("Material1"); mat.Name = "MaterialUpdated"; @@ -87,7 +91,7 @@ public void ShouldWriteUpdatedMaterialData() mat.WrapLighting = 0.68f; table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); var material = writtenTable.GetMaterial("MaterialUpdated"); material.Name.Should().Be("MaterialUpdated"); material.BaseColor.Red.Should().Be(1); @@ -106,6 +110,7 @@ public void ShouldWriteUpdatedMaterialData() material.ScatterAngle.Should().Be(12.2f); material.Thickness.Should().BeApproximately(0.74f, 0.003f); material.WrapLighting.Should().Be(0.68f); + File.Delete(tmpFileName); } private void ValidateMaterial1(Material material) diff --git a/VisualPinball.Engine.Test/VPT/Plunger/PlungerDataTests.cs b/VisualPinball.Engine.Test/VPT/Plunger/PlungerDataTests.cs index 01926093b..78baaa1df 100644 --- a/VisualPinball.Engine.Test/VPT/Plunger/PlungerDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Plunger/PlungerDataTests.cs @@ -14,11 +14,13 @@ // 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; using VisualPinball.Engine.VPT.Plunger; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Plunger { @@ -27,7 +29,7 @@ public class PlungerDataTests [Test] public void ShouldReadPlungerData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Plunger); + var table = FileTableContainer.Load(VpxPath.Plunger); ValidatePlungerData1(table.Plunger("Plunger1").Data); ValidatePlungerData2(table.Plunger("Plunger2").Data); } @@ -36,14 +38,15 @@ public void ShouldReadPlungerData() public void ShouldWritePlungerData() { const string tmpFileName = "ShouldWritePlungerData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Plunger); + var table = FileTableContainer.Load(VpxPath.Plunger); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidatePlungerData1(writtenTable.Plunger("Plunger1").Data); ValidatePlungerData2(writtenTable.Plunger("Plunger2").Data); + File.Delete(tmpFileName); } - private static void ValidatePlungerData1(PlungerData data) + public static void ValidatePlungerData1(PlungerData data, bool validateTexture = true) { data.AnimFrames.Should().Be(7); data.AnimFrames.Should().Be(7); @@ -51,7 +54,9 @@ private static void ValidatePlungerData1(PlungerData data) data.Center.X.Should().Be(477f); data.Center.Y.Should().Be(983.2f); data.Height.Should().Be(20f); - data.Image.Should().Be("alphatest_100_50_0"); + if (validateTexture) { + data.Image.Should().Be("alphatest_100_50_0"); + } data.IsLocked.Should().Be(true); data.IsMechPlunger.Should().Be(true); data.IsReflectionEnabled.Should().Be(true); @@ -81,7 +86,7 @@ private static void ValidatePlungerData1(PlungerData data) data.ZAdjust.Should().Be(1.223f); } - private static void ValidatePlungerData2(PlungerData data) + public static void ValidatePlungerData2(PlungerData data) { data.AnimFrames.Should().Be(1); data.AutoPlunger.Should().Be(false); diff --git a/VisualPinball.Engine.Test/VPT/Primitive/PrimitiveDataTests.cs b/VisualPinball.Engine.Test/VPT/Primitive/PrimitiveDataTests.cs index 6c22bb5e4..1ee05c9c3 100644 --- a/VisualPinball.Engine.Test/VPT/Primitive/PrimitiveDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Primitive/PrimitiveDataTests.cs @@ -27,7 +27,7 @@ public class PrimitiveDataTests [Test] public void ShouldReadPrimitiveData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Primitive); + var table = FileTableContainer.Load(VpxPath.Primitive); ValidatePrimitiveData(table.Primitive("Cube").Data); } @@ -35,13 +35,13 @@ public void ShouldReadPrimitiveData() public void ShouldWritePrimitiveData() { const string tmpFileName = "ShouldWritePrimitiveData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Primitive); + var table = FileTableContainer.Load(VpxPath.Primitive); new TableWriter(table).WriteTable(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidatePrimitiveData(writtenTable.Primitive("Cube").Data); } - private static void ValidatePrimitiveData(PrimitiveData data) + public static void ValidatePrimitiveData(PrimitiveData data) { data.BackfacesEnabled.Should().Be(false); data.CollisionReductionFactor.Should().Be(0.6119f); diff --git a/VisualPinball.Engine.Test/VPT/Primitive/PrimitiveMeshTests.cs b/VisualPinball.Engine.Test/VPT/Primitive/PrimitiveMeshTests.cs index 5fe53b727..c3ccee386 100644 --- a/VisualPinball.Engine.Test/VPT/Primitive/PrimitiveMeshTests.cs +++ b/VisualPinball.Engine.Test/VPT/Primitive/PrimitiveMeshTests.cs @@ -21,45 +21,46 @@ using VisualPinball.Engine.Game; using VisualPinball.Engine.Test.Test; using VisualPinball.Engine.VPT; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Primitive { public class PrimitiveMeshTests : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly ObjFile _obj; public PrimitiveMeshTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Primitive); + _tc = FileTableContainer.Load(VpxPath.Primitive); _obj = LoadObjFixture(ObjPath.Primitive); } [Test] public void ShouldGenerateImportedMesh() { - var bookMesh = _table.Primitive("Books").GetRenderObjects(_table).RenderObjects[0].Mesh; + var bookMesh = _tc.Primitive("Books").GetRenderObjects(_tc.Table).RenderObjects[0].Mesh; AssertObjMesh(_obj, bookMesh, threshold: 0.00015f); } [Test] public void ShouldGenerateACube() { - var cubeMesh = _table.Primitive("Cube").GetRenderObjects(_table).RenderObjects[0].Mesh; + var cubeMesh = _tc.Primitive("Cube").GetRenderObjects(_tc.Table).RenderObjects[0].Mesh; AssertObjMesh(_obj, cubeMesh); } [Test] public void ShouldGenerateATriangle() { - var triangleMesh = _table.Primitive("Triangle").GetRenderObjects(_table).RenderObjects[0].Mesh; + var triangleMesh = _tc.Primitive("Triangle").GetRenderObjects(_tc.Table).RenderObjects[0].Mesh; AssertObjMesh(_obj, triangleMesh); } [Test] public void ShouldProvideCorrectTransformationMatrices() { - var rog = _table.Primitive("Primitive1").GetRenderObjects(_table, Origin.Original, false); + var rog = _tc.Primitive("Primitive1").GetRenderObjects(_tc.Table, Origin.Original, false); rog.TransformationMatrix.GetScaling().X.Should().Be(100f); rog.TransformationMatrix.GetScaling().Y.Should().Be(100f); @@ -67,22 +68,22 @@ public void ShouldProvideCorrectTransformationMatrices() rog.TransformationMatrix.GetTranslation().X.Should().Be(505f); rog.TransformationMatrix.GetTranslation().Y.Should().Be(1305f); - rog.TransformationMatrix.GetTranslation().Z.Should().Be(_table.TableHeight); + rog.TransformationMatrix.GetTranslation().Z.Should().Be(_tc.Table.TableHeight); } [Test] public void ShouldGenerateACompressedMesh() { - var table = Engine.VPT.Table.Table.Load(VpxPath.PrimitiveCompressed); + var th = FileTableContainer.Load(VpxPath.PrimitiveCompressed); var obj = LoadObjFixture(ObjPath.PrimitiveCompressed); - var compressedMesh = table.Primitive("compressed").GetRenderObjects(table).RenderObjects[0].Mesh; + var compressedMesh = th.Primitive("compressed").GetRenderObjects(th.Table).RenderObjects[0].Mesh; AssertObjMesh(obj, compressedMesh, threshold: 0.00015f); } [Test] public void ShouldGenerateAnAnimatedMesh() { - var table = Engine.VPT.Table.Table.Load(VpxPath.PrimitiveAnimated); + var table = FileTableContainer.Load(VpxPath.PrimitiveAnimated); var animatedPrimitive = table.Primitive("AnimatedPrimitive"); var mesh = animatedPrimitive.GetMesh(); diff --git a/VisualPinball.Engine.Test/VPT/Ramp/RampDataTests.cs b/VisualPinball.Engine.Test/VPT/Ramp/RampDataTests.cs index e1e175189..3dfeed191 100644 --- a/VisualPinball.Engine.Test/VPT/Ramp/RampDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Ramp/RampDataTests.cs @@ -14,11 +14,13 @@ // 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; using VisualPinball.Engine.VPT.Ramp; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Ramp { @@ -27,7 +29,7 @@ public class RampDataTests [Test] public void ShouldReadRampData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Ramp); + var table = FileTableContainer.Load(VpxPath.Ramp); ValidateRampData(table.Ramp("FlatL").Data); } @@ -35,13 +37,14 @@ public void ShouldReadRampData() public void ShouldWriteRampData() { const string tmpFileName = "ShouldWriteRampData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Ramp); + var table = FileTableContainer.Load(VpxPath.Ramp); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateRampData(writtenTable.Ramp("FlatL").Data); + File.Delete(tmpFileName); } - private static void ValidateRampData(RampData data) + public static void ValidateRampData(RampData data) { data.DepthBias.Should().Be(0.11254f); data.DragPoints.Length.Should().Be(3); @@ -73,7 +76,7 @@ private static void ValidateRampData(RampData data) [Test] public void ShouldLoadWireData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Ramp); + var table = FileTableContainer.Load(VpxPath.Ramp); var data = table.Ramp("Wire3R").Data; data.RampType.Should().Be(RampType.RampType3WireRight); diff --git a/VisualPinball.Engine.Test/VPT/Ramp/RampMeshTests.cs b/VisualPinball.Engine.Test/VPT/Ramp/RampMeshTests.cs index 80207548a..979e32ce2 100644 --- a/VisualPinball.Engine.Test/VPT/Ramp/RampMeshTests.cs +++ b/VisualPinball.Engine.Test/VPT/Ramp/RampMeshTests.cs @@ -18,17 +18,18 @@ using JeremyAnsel.Media.WavefrontObj; using NUnit.Framework; using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Ramp { public class RampMeshTests : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly ObjFile _obj; public RampMeshTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Ramp); + _tc = FileTableContainer.Load(VpxPath.Ramp); _obj = LoadObjFixture(ObjPath.Ramp); } @@ -71,8 +72,8 @@ public void ShouldGenerate4WireRamp() private void ShouldGenerate(string name) { - var ramp = _table.Ramp(name); - var rampMeshes = ramp.GetRenderObjects(_table).RenderObjects.Select(ro => ro.Mesh).ToArray(); + var ramp = _tc.Ramp(name); + var rampMeshes = ramp.GetRenderObjects(_tc.Table).RenderObjects.Select(ro => ro.Mesh).ToArray(); #if WIN64 const float threshold = 0.0001f; #else diff --git a/VisualPinball.Engine.Test/VPT/Rubber/RubberDataTest.cs b/VisualPinball.Engine.Test/VPT/Rubber/RubberDataTests.cs similarity index 85% rename from VisualPinball.Engine.Test/VPT/Rubber/RubberDataTest.cs rename to VisualPinball.Engine.Test/VPT/Rubber/RubberDataTests.cs index 603a63643..70d9720b1 100644 --- a/VisualPinball.Engine.Test/VPT/Rubber/RubberDataTest.cs +++ b/VisualPinball.Engine.Test/VPT/Rubber/RubberDataTests.cs @@ -14,19 +14,21 @@ // 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.Rubber; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Rubber { - public class RubberDataTest + public class RubberDataTests { [Test] public void ShouldReadRubberData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Rubber); + var table = FileTableContainer.Load(VpxPath.Rubber); ValidateRubberData1(table.Rubber("Rubber1").Data); ValidateRubberData2(table.Rubber("Rubber2").Data); } @@ -35,14 +37,15 @@ public void ShouldReadRubberData() public void ShouldWriteRubberData() { const string tmpFileName = "ShouldWriteRubberData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Rubber); + var table = FileTableContainer.Load(VpxPath.Rubber); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateRubberData1(writtenTable.Rubber("Rubber1").Data); ValidateRubberData2(writtenTable.Rubber("Rubber2").Data); + File.Delete(tmpFileName); } - private static void ValidateRubberData1(RubberData data) + public static void ValidateRubberData1(RubberData data) { data.DragPoints.Length.Should().Be(3); data.Elasticity.Should().Be(0.832f); @@ -68,7 +71,7 @@ private static void ValidateRubberData1(RubberData data) data.Points.Should().Be(true); } - private static void ValidateRubberData2(RubberData data) + public static void ValidateRubberData2(RubberData data) { data.DragPoints.Length.Should().Be(3); data.Elasticity.Should().Be(0.8f); diff --git a/VisualPinball.Engine.Test/VPT/Rubber/RubberMeshTest.cs b/VisualPinball.Engine.Test/VPT/Rubber/RubberMeshTest.cs index 5852d5eea..c6f9024cd 100644 --- a/VisualPinball.Engine.Test/VPT/Rubber/RubberMeshTest.cs +++ b/VisualPinball.Engine.Test/VPT/Rubber/RubberMeshTest.cs @@ -17,31 +17,32 @@ using JeremyAnsel.Media.WavefrontObj; using NUnit.Framework; using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Rubber { public class RubberMeshTest : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly ObjFile _obj; public RubberMeshTest() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Rubber); + _tc = FileTableContainer.Load(VpxPath.Rubber); _obj = LoadObjFixture(ObjPath.Rubber); } [Test] public void ShouldGenerateMesh() { - var rubberMesh = _table.Rubber("Rubber2").GetRenderObjects(_table).RenderObjects[0].Mesh; + var rubberMesh = _tc.Rubber("Rubber2").GetRenderObjects(_tc.Table).RenderObjects[0].Mesh; AssertObjMesh(_obj, rubberMesh, threshold: 0.00015f); } [Test] public void ShouldGenerateThickMesh() { - var rubberMesh = _table.Rubber("Rubber1").GetRenderObjects(_table).RenderObjects[0].Mesh; + var rubberMesh = _tc.Rubber("Rubber1").GetRenderObjects(_tc.Table).RenderObjects[0].Mesh; AssertObjMesh(_obj, rubberMesh, threshold: 0.001f); } } diff --git a/VisualPinball.Engine.Test/VPT/Sound/SoundDataTests.cs b/VisualPinball.Engine.Test/VPT/Sound/SoundDataTests.cs index d5d102026..c28c42cbd 100644 --- a/VisualPinball.Engine.Test/VPT/Sound/SoundDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Sound/SoundDataTests.cs @@ -14,6 +14,7 @@ // 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; @@ -28,18 +29,33 @@ public class SoundDataTests [Test] public void ShouldReadSoundData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Sound); - ValidateSoundData(table.Sounds["fx_bumper3"].Data); + var tableContainer = FileTableContainer.Load(VpxPath.Sound); + ValidateSoundData(tableContainer.GetSound("fx_bumper3").Data); } [Test] public void ShouldWriteSoundData() { const string tmpFileName = "ShouldWriteSoundData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Sound); - new TableWriter(table).WriteTable(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); - ValidateSoundData(writtenTable.Sounds["fx_bumper3"].Data); + var tableContainer = FileTableContainer.Load(VpxPath.Sound); + new TableWriter(tableContainer).WriteTable(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); + ValidateSoundData(writtenTable.GetSound("fx_bumper3").Data); + + File.Delete(tmpFileName); + } + + [Test] + public void ShouldReadMp3Data() + { + var tableContainer = FileTableContainer.Load(VpxPath.Sound); + tableContainer.GetSound("ANMLFarm_Cow moos 5 (ID 2385)_BSB").Data.GetFileData().Should().HaveCountGreaterThan(0); + } + [Test] + public void ShouldReadOggData() + { + var tableContainer = FileTableContainer.Load(VpxPath.Sound); + tableContainer.GetSound("ANMLFarm_Cow moos 3 (ID 2383)_BSB").Data.GetFileData().Should().HaveCountGreaterThan(0); } private static void ValidateSoundData(SoundData data) diff --git a/VisualPinball.Engine.Test/VPT/Spinner/SpinnerDataTests.cs b/VisualPinball.Engine.Test/VPT/Spinner/SpinnerDataTests.cs index 24c55a158..173a41b0b 100644 --- a/VisualPinball.Engine.Test/VPT/Spinner/SpinnerDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Spinner/SpinnerDataTests.cs @@ -14,10 +14,12 @@ // 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.Spinner; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Spinner { @@ -26,7 +28,7 @@ public class SpinnerDataTests [Test] public void ShouldReadSpinnerData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Spinner); + var table = FileTableContainer.Load(VpxPath.Spinner); ValidateSpinnerData(table.Spinner("Data").Data); } @@ -34,13 +36,14 @@ public void ShouldReadSpinnerData() public void ShouldWriteSpinnerData() { const string tmpFileName = "ShouldWriteSpinnerData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Spinner); + var table = FileTableContainer.Load(VpxPath.Spinner); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateSpinnerData(writtenTable.Spinner("Data").Data); + File.Delete(tmpFileName); } - private static void ValidateSpinnerData(SpinnerData data) + public static void ValidateSpinnerData(SpinnerData data) { data.AngleMax.Should().Be(50.698f); data.AngleMin.Should().Be(-12.87f); diff --git a/VisualPinball.Engine.Test/VPT/Spinner/SpinnerMeshTests.cs b/VisualPinball.Engine.Test/VPT/Spinner/SpinnerMeshTests.cs index 4f70a2a17..d0091b20b 100644 --- a/VisualPinball.Engine.Test/VPT/Spinner/SpinnerMeshTests.cs +++ b/VisualPinball.Engine.Test/VPT/Spinner/SpinnerMeshTests.cs @@ -19,17 +19,18 @@ using VisualPinball.Engine.Game; using VisualPinball.Engine.Test.Test; using VisualPinball.Engine.VPT; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Spinner { public class SpinnerMeshTests : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly ObjFile _obj; public SpinnerMeshTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Spinner); + _tc = FileTableContainer.Load(VpxPath.Spinner); _obj = LoadObjFixture(ObjPath.Spinner); } @@ -37,16 +38,16 @@ public SpinnerMeshTests() public void ShouldGenerateBracketMeshes() { string GetName(IRenderable item, Mesh mesh) => $"{item.Name}{mesh.Name}"; - AssertObjMesh(_table, _obj, _table.Spinner("Spinner"), GetName); - AssertObjMesh(_table, _obj, _table.Spinner("Transformed"), GetName); - AssertObjMesh(_table, _obj, _table.Spinner("Surface"), GetName); - AssertObjMesh(_table, _obj, _table.Spinner("Data"), GetName, 0.001f); + AssertObjMesh(_tc.Table, _obj, _tc.Spinner("Spinner"), GetName); + AssertObjMesh(_tc.Table, _obj, _tc.Spinner("Transformed"), GetName); + AssertObjMesh(_tc.Table, _obj, _tc.Spinner("Surface"), GetName); + AssertObjMesh(_tc.Table, _obj, _tc.Spinner("Data"), GetName, 0.001f); } [Test] public void ShouldGenerateMeshWithoutBracket() { - AssertObjMesh(_obj, _table.Spinner("WithoutBracket").GetRenderObjects(_table).RenderObjects[0].Mesh, "WithoutBracketPlate"); + AssertObjMesh(_obj, _tc.Spinner("WithoutBracket").GetRenderObjects(_tc.Table).RenderObjects[0].Mesh, "WithoutBracketPlate"); AssertNoObjMesh(_obj, "WithoutBracketBracket"); } diff --git a/VisualPinball.Engine.Test/VPT/Surface/SurfaceDataTests.cs b/VisualPinball.Engine.Test/VPT/Surface/SurfaceDataTests.cs index 7e448e3b1..140361ea7 100644 --- a/VisualPinball.Engine.Test/VPT/Surface/SurfaceDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Surface/SurfaceDataTests.cs @@ -14,10 +14,12 @@ // 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.Surface; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Surface { @@ -26,7 +28,7 @@ public class SurfaceDataTests [Test] public void ShouldReadSurfaceData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Surface); + var table = FileTableContainer.Load(VpxPath.Surface); ValidateSurfaceData(table.Surface("TopInvisible").Data); } @@ -34,13 +36,14 @@ public void ShouldReadSurfaceData() public void ShouldWriteSurfaceData() { const string tmpFileName = "ShouldWriteSurfaceData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Surface); + var table = FileTableContainer.Load(VpxPath.Surface); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateSurfaceData(writtenTable.Surface("TopInvisible").Data); + File.Delete(tmpFileName); } - private static void ValidateSurfaceData(SurfaceData data) + public static void ValidateSurfaceData(SurfaceData data) { data.DisableLightingBelow.Should().Be(0.6985f); data.DisableLightingTop.Should().BeInRange(0.129f, 0.13f); diff --git a/VisualPinball.Engine.Test/VPT/Surface/SurfaceMeshTests.cs b/VisualPinball.Engine.Test/VPT/Surface/SurfaceMeshTests.cs index dcdcd3d14..b7e32da40 100644 --- a/VisualPinball.Engine.Test/VPT/Surface/SurfaceMeshTests.cs +++ b/VisualPinball.Engine.Test/VPT/Surface/SurfaceMeshTests.cs @@ -18,33 +18,34 @@ using JeremyAnsel.Media.WavefrontObj; using NUnit.Framework; using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Surface { public class SurfaceMeshTests : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly ObjFile _obj; public SurfaceMeshTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Surface); + _tc = FileTableContainer.Load(VpxPath.Surface); _obj = LoadObjFixture(ObjPath.Surface); } [Test] public void ShouldGenerateTopAndSides() { - var surface = _table.Surface("Wall"); - var surfaceMeshes = surface.GetRenderObjects(_table).RenderObjects.Select(ro => ro.Mesh).ToArray(); + var surface = _tc.Surface("Wall"); + var surfaceMeshes = surface.GetRenderObjects(_tc.Table).RenderObjects.Select(ro => ro.Mesh).ToArray(); AssertObjMesh(_obj, surface.Name, surfaceMeshes); } [Test] public void ShouldGenerateOnlyTop() { - var surface = _table.Surface("SideInvisible"); - var surfaceMeshes = surface.GetRenderObjects(_table).RenderObjects + var surface = _tc.Surface("SideInvisible"); + var surfaceMeshes = surface.GetRenderObjects(_tc.Table).RenderObjects .Where(ro => ro.IsVisible) .Select(ro => ro.Mesh).ToArray(); AssertObjMesh(_obj, surface.Name, surfaceMeshes, 0.001f); @@ -53,8 +54,8 @@ public void ShouldGenerateOnlyTop() [Test] public void ShouldGenerateOnlySide() { - var surface = _table.Surface("TopInvisible"); - var surfaceMeshes = surface.GetRenderObjects(_table).RenderObjects + var surface = _tc.Surface("TopInvisible"); + var surfaceMeshes = surface.GetRenderObjects(_tc.Table).RenderObjects .Where(ro => ro.IsVisible) .Select(ro => ro.Mesh).ToArray(); AssertObjMesh(_obj, surface.Name, surfaceMeshes); diff --git a/VisualPinball.Engine.Test/VPT/Surface/SurfacePhysicsTests.cs b/VisualPinball.Engine.Test/VPT/Surface/SurfacePhysicsTests.cs index 2fa1cd96a..69dc4eb25 100644 --- a/VisualPinball.Engine.Test/VPT/Surface/SurfacePhysicsTests.cs +++ b/VisualPinball.Engine.Test/VPT/Surface/SurfacePhysicsTests.cs @@ -15,18 +15,19 @@ // along with this program. If not, see . using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Surface { public class SurfacePhysicsTests : BaseTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly Engine.VPT.Kicker.Kicker _kicker; public SurfacePhysicsTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Flipper); - _kicker = _table.Kicker("BallRelease"); + _tc = FileTableContainer.Load(VpxPath.Flipper); + _kicker = _tc.Kicker("BallRelease"); } // [Test] diff --git a/VisualPinball.Engine.Test/VPT/Table/TableDataTests.cs b/VisualPinball.Engine.Test/VPT/Table/TableDataTests.cs index 668e90426..d44fa3c7f 100644 --- a/VisualPinball.Engine.Test/VPT/Table/TableDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Table/TableDataTests.cs @@ -14,6 +14,7 @@ // 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.Common; @@ -28,57 +29,65 @@ public class TableDataTests : BaseTests [Test] public void ShouldReadTableData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Table); - ValidateTableData(table.Data); + var table = FileTableContainer.Load(VpxPath.Table); + ValidateTableData(table.Table.Data); } [Test] public void ShouldReadTableInfo() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Table); - - table.InfoAuthorEmail.Should().Be("test@vpdb.io"); - table.InfoAuthorName.Should().Be("Table Author"); - table.InfoAuthorWebsite.Should().Be("https://vpdb.io"); - table.InfoReleaseDate.Should().Be("2019-04-14"); - table.InfoBlurb.Should().Be("Short Blurb"); - table.InfoDescription.Should().Be("Description"); - table.InfoName.Should().Be("Table Name"); - table.InfoRules.Should().Be("Rules"); - table.InfoVersion.Should().Be("Version"); - table.TableInfo["customdata1"].Should().Be("customvalue1"); + var table = FileTableContainer.Load(VpxPath.Table); + ValidateTableInfo(table); } [Test] public void ShouldWriteTableData() { const string tmpFileName = "ShouldWriteTable.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Table); + var table = FileTableContainer.Load(VpxPath.Table); new TableWriter(table).WriteTable(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); - ValidateTableData(writtenTable.Data); + var writtenTable = FileTableContainer.Load(tmpFileName); + ValidateTableData(writtenTable.Table.Data); + + File.Delete(tmpFileName); } [Test] public void ShouldWriteCorrectHash() { const string tmpFileName = "ShouldWriteCorrectHash.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.TableChecksum); + var table = FileTableContainer.Load(VpxPath.TableChecksum); new TableWriter(table).WriteTable(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); writtenTable.FileHash.Should().Equal(table.FileHash); + + File.Delete(tmpFileName); } [Test] public void ShouldReadCustomInfoTags() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Table); + var table = FileTableContainer.Load(VpxPath.Table); table.CustomInfoTags.TagNames[0].Should().Be("customdata1"); table.CustomInfoTags.TagNames[1].Should().Be("foo"); } - private static void ValidateTableData(TableData data) + public static void ValidateTableInfo(FileTableContainer table) + { + table.InfoAuthorEmail.Should().Be("test@vpdb.io"); + table.InfoAuthorName.Should().Be("Table Author"); + table.InfoAuthorWebsite.Should().Be("https://vpdb.io"); + table.InfoReleaseDate.Should().Be("2019-04-14"); + table.InfoBlurb.Should().Be("Short Blurb"); + table.InfoDescription.Should().Be("Description"); + table.InfoName.Should().Be("Table Name"); + table.InfoRules.Should().Be("Rules"); + table.InfoVersion.Should().Be("Version"); + table.TableInfo["customdata1"].Should().Be("customvalue1"); + } + + public static void ValidateTableData(TableData data) { data.AngleTiltMax.Should().Be(0.60606f); data.AngleTiltMin.Should().Be(0.2033f); @@ -124,7 +133,7 @@ private static void ValidateTableData(TableData data) data.BgOffsetZ[BackglassIndex.FullSingleScreen].Should().Be(-50.223f); data.BloomStrength.Should().Be(1.5055f); data.Bottom.Should().Be(2224); - data.Code.Should().Be("Option Explicit\r\n"); + data.Code.Trim().Should().Be("Option Explicit"); data.ColorBackdrop.Red.Should().Be(31); data.ColorBackdrop.Green.Should().Be(32); data.ColorBackdrop.Blue.Should().Be(33); @@ -162,7 +171,6 @@ private static void ValidateTableData(TableData data) data.NudgeTime.Should().Be(6.2931f); data.NumCollections.Should().Be(0); data.NumFonts.Should().Be(0); - data.NumGameItems.Should().Be(1); data.NumMaterials.Should().Be(1); data.NumSounds.Should().Be(0); data.NumTextures.Should().Be(1); diff --git a/VisualPinball.Engine.Test/VPT/Table/TableMeshTests.cs b/VisualPinball.Engine.Test/VPT/Table/TableMeshTests.cs index 70bfc992b..d396b0574 100644 --- a/VisualPinball.Engine.Test/VPT/Table/TableMeshTests.cs +++ b/VisualPinball.Engine.Test/VPT/Table/TableMeshTests.cs @@ -17,24 +17,25 @@ using JeremyAnsel.Media.WavefrontObj; using NUnit.Framework; using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Table { public class TableMeshTests : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly ObjFile _obj; public TableMeshTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Table); + _tc = FileTableContainer.Load(VpxPath.Table); _obj = LoadObjFixture(ObjPath.Table); } [Test] public void ShouldGeneratePlayfieldCorrectly() { - var tableMesh = _table.GetRenderObjects(_table).RenderObjects[0].Mesh; + var tableMesh = _tc.Table.GetRenderObjects(_tc.Table).RenderObjects[0].Mesh; AssertObjMesh(_obj, tableMesh); } } diff --git a/VisualPinball.Engine.Test/VPT/Textbox/TextBoxDataTest.cs b/VisualPinball.Engine.Test/VPT/Textbox/TextBoxDataTests.cs similarity index 79% rename from VisualPinball.Engine.Test/VPT/Textbox/TextBoxDataTest.cs rename to VisualPinball.Engine.Test/VPT/Textbox/TextBoxDataTests.cs index 48cfbe702..7afcb57bc 100644 --- a/VisualPinball.Engine.Test/VPT/Textbox/TextBoxDataTest.cs +++ b/VisualPinball.Engine.Test/VPT/Textbox/TextBoxDataTests.cs @@ -14,6 +14,7 @@ // 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; @@ -23,26 +24,28 @@ namespace VisualPinball.Engine.Test.VPT.TextBox { - public class TextBoxDataTest : BaseTests + public class TextBoxDataTests : BaseTests { [Test] public void ShouldReadTextBoxData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.TextBox); - ValidateTableData(table.TextBox("TextBox001").Data); + var table = FileTableContainer.Load(VpxPath.TextBox); + ValidateTextBoxData(table.TextBox("TextBox001").Data); } [Test] public void ShouldWriteTextBoxData() { const string tmpFileName = "ShouldWriteTextBoxData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.TextBox); + var table = FileTableContainer.Load(VpxPath.TextBox); new TableWriter(table).WriteTable(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); - ValidateTableData(writtenTable.TextBox("TextBox001").Data); + var writtenTable = FileTableContainer.Load(tmpFileName); + ValidateTextBoxData(writtenTable.TextBox("TextBox001").Data); + + File.Delete(tmpFileName); } - private static void ValidateTableData(TextBoxData data) + public static void ValidateTextBoxData(TextBoxData data) { data.Align.Should().Be(TextAlignment.TextAlignCenter); data.BackColor.Red.Should().Be(0); diff --git a/VisualPinball.Engine.Test/VPT/TextureBitmapTests.cs b/VisualPinball.Engine.Test/VPT/TextureBitmapTests.cs index 8a68d1902..8d7f73cf4 100644 --- a/VisualPinball.Engine.Test/VPT/TextureBitmapTests.cs +++ b/VisualPinball.Engine.Test/VPT/TextureBitmapTests.cs @@ -17,23 +17,24 @@ using FluentAssertions; using NUnit.Framework; using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; using VisualPinball.Resources; namespace VisualPinball.Engine.Test.VPT { public class TextureBitmapTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; public TextureBitmapTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Texture); + _tc = FileTableContainer.Load(VpxPath.Texture); } [Test] public void ShouldAnalyzeAnOpaqueTexture() { - var texture = _table.Textures["test_pattern_png"]; + var texture = _tc.GetTexture("test_pattern_png"); var stats = texture.GetStats(); stats.Opaque.Should().Be(1f); @@ -44,7 +45,7 @@ public void ShouldAnalyzeAnOpaqueTexture() [Test] public void ShouldAnalyzeAnotherOpaqueTexture() { - var texture = _table.Textures["test_pattern_argb"]; + var texture = _tc.GetTexture("test_pattern_argb"); var stats = texture.GetStats(); stats.Opaque.Should().Be(1f); @@ -55,7 +56,7 @@ public void ShouldAnalyzeAnotherOpaqueTexture() [Test] public void ShouldAnalyzeATransparentTexture() { - var texture = _table.Textures["test_pattern_transparent"]; + var texture = _tc.GetTexture("test_pattern_transparent"); texture.Analyze(); var stats = texture.GetStats(); diff --git a/VisualPinball.Engine.Test/VPT/TextureDataTests.cs b/VisualPinball.Engine.Test/VPT/TextureDataTests.cs index d0d70c1de..23af08d93 100644 --- a/VisualPinball.Engine.Test/VPT/TextureDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/TextureDataTests.cs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using System.Data; using System.IO; using FluentAssertions; using NUnit.Framework; @@ -24,22 +25,21 @@ namespace VisualPinball.Engine.Test.VPT { public class TextureDataTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _table; public TextureDataTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Texture); + _table = FileTableContainer.Load(VpxPath.Texture); } [Test] public void ShouldLoadCorrectArgb() { - var texture = _table.Textures["test_pattern_argb"]; + var texture = _table.GetTexture("test_pattern_argb"); var blob = texture.FileContent; var image = File.ReadAllBytes(TexturePath.BmpArgb); texture.Data.Width.Should().Be(1024); texture.Data.Height.Should().Be(768); - texture.Data.InternalName.Should().Be("test_pattern_argb"); texture.Data.AlphaTestValue.Should().Be(1.0f); texture.Data.Path.Should().StartWith(@"C:\"); blob.Should().Equal(image); @@ -48,12 +48,11 @@ public void ShouldLoadCorrectArgb() [Test] public void ShouldLoadCorrectBmp() { - var texture = _table.Textures["test_pattern_bmp"]; + var texture = _table.GetTexture("test_pattern_bmp"); var blob = texture.FileContent; var image = File.ReadAllBytes(TexturePath.Bmp); texture.Data.Width.Should().Be(1024); texture.Data.Height.Should().Be(768); - texture.Data.InternalName.Should().Be("test_pattern_bmp"); texture.Data.AlphaTestValue.Should().Be(1.0f); texture.Data.Path.Should().StartWith(@"C:\"); blob.Should().Equal(image); @@ -62,12 +61,11 @@ public void ShouldLoadCorrectBmp() [Test] public void ShouldLoadCorrectExr() { - var texture = _table.Textures["test_pattern_exr"]; + var texture = _table.GetTexture("test_pattern_exr"); var blob = texture.FileContent; var image = File.ReadAllBytes(TexturePath.Exr); texture.Data.Width.Should().Be(587); texture.Data.Height.Should().Be(675); - texture.Data.InternalName.Should().Be("test_pattern_exr"); texture.Data.AlphaTestValue.Should().Be(1.0f); texture.Data.Path.Should().StartWith(@"C:\"); blob.Should().Equal(image); @@ -76,12 +74,11 @@ public void ShouldLoadCorrectExr() [Test] public void ShouldLoadCorrectHdr() { - var texture = _table.Textures["test_pattern_hdr"]; + var texture = _table.GetTexture("test_pattern_hdr"); var blob = texture.FileContent; var image = File.ReadAllBytes(TexturePath.Hdr); texture.Data.Width.Should().Be(1024); texture.Data.Height.Should().Be(512); - texture.Data.InternalName.Should().Be("test_pattern_hdr"); texture.Data.AlphaTestValue.Should().Be(1.0f); texture.Data.Path.Should().StartWith(@"C:\"); blob.Should().Equal(image); @@ -90,12 +87,11 @@ public void ShouldLoadCorrectHdr() [Test] public void ShouldLoadCorrectJpg() { - var texture = _table.Textures["test_pattern_jpg"]; + var texture = _table.GetTexture("test_pattern_jpg"); var blob = texture.FileContent; var image = File.ReadAllBytes(TexturePath.Jpg); texture.Data.Width.Should().Be(1024); texture.Data.Height.Should().Be(768); - texture.Data.InternalName.Should().Be("test_pattern_jpg"); texture.Data.AlphaTestValue.Should().Be(1.0f); texture.Data.Path.Should().StartWith(@"C:\"); blob.Should().Equal(image); @@ -104,12 +100,11 @@ public void ShouldLoadCorrectJpg() [Test] public void ShouldLoadCorrectPng() { - var texture = _table.Textures["test_pattern_png"]; + var texture = _table.GetTexture("test_pattern_png"); var blob = texture.FileContent; var image = File.ReadAllBytes(TexturePath.Png); texture.Data.Width.Should().Be(1024); texture.Data.Height.Should().Be(768); - texture.Data.InternalName.Should().Be("test_pattern_png"); texture.Data.AlphaTestValue.Should().Be(1.0f); texture.Data.Path.Should().StartWith(@"C:\"); blob.Should().Equal(image); @@ -118,13 +113,12 @@ public void ShouldLoadCorrectPng() [Test] public void ShouldLoadCorrectTransparentPng() { - var texture = _table.Textures["test_pattern_transparent"]; + var texture = _table.GetTexture("test_pattern_transparent"); var blob = texture.FileContent; var image = File.ReadAllBytes(TexturePath.PngTransparent); //File.WriteAllBytes(@"..\..\Fixtures\debug.bmp", textureData); texture.Data.Width.Should().Be(1024); texture.Data.Height.Should().Be(768); - texture.Data.InternalName.Should().Be("test_pattern_transparent"); texture.Data.AlphaTestValue.Should().Be(1.0f); texture.Data.Path.Should().StartWith(@"C:\"); blob.Should().Equal(image); @@ -133,13 +127,25 @@ public void ShouldLoadCorrectTransparentPng() [Test] public void ShouldLoadCorrectTransparentXrgb() { - var texture = _table.Textures["test_pattern_xrgb"]; + var texture = _table.GetTexture("test_pattern_xrgb"); var blob = texture.FileContent; var image = File.ReadAllBytes(TexturePath.BmpXrgb); //File.WriteAllBytes(@"..\..\Fixtures\debug.bmp", textureData); texture.Data.Width.Should().Be(1024); texture.Data.Height.Should().Be(768); - texture.Data.InternalName.Should().Be("test_pattern_xrgb"); + texture.Data.AlphaTestValue.Should().Be(1.0f); + texture.Data.Path.Should().StartWith(@"C:\"); + blob.Should().Equal(image); + } + + [Test] + public void ShouldLoadCorrectWebp() + { + var texture = _table.GetTexture("test_pattern_webp"); + var blob = texture.FileContent; + var image = File.ReadAllBytes(TexturePath.Webp); + texture.Data.Width.Should().Be(1024); + texture.Data.Height.Should().Be(768); texture.Data.AlphaTestValue.Should().Be(1.0f); texture.Data.Path.Should().StartWith(@"C:\"); blob.Should().Equal(image); @@ -150,8 +156,10 @@ public void ShouldWriteCorrectBinary() { const string tmpFileName = "ShouldWriteCorrectBinary.vpx"; new TableWriter(_table).WriteTable(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); - writtenTable.Textures["test_pattern_jpg"].Data.Binary.Data.Should().Equal(_table.Textures["test_pattern_jpg"].Data.Binary.Data); + var writtenTable = FileTableContainer.Load(tmpFileName); + writtenTable.GetTexture("test_pattern_jpg").Data.Binary.Data.Should().Equal(_table.GetTexture("test_pattern_jpg").Data.Binary.Data); + + File.Delete(tmpFileName); } [Test] @@ -159,8 +167,9 @@ public void ShouldWriteCorrectBitmap() { const string tmpFileName = "ShouldWriteCorrectBitmap.vpx"; new TableWriter(_table).WriteTable(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); - writtenTable.Textures["test_pattern_bmp"].Data.Bitmap.Bytes.Should().Equal(_table.Textures["test_pattern_bmp"].Data.Bitmap.Bytes); + var writtenTable = FileTableContainer.Load(tmpFileName); + writtenTable.GetTexture("test_pattern_bmp").Data.Bitmap.Bytes.Should().Equal(_table.GetTexture("test_pattern_bmp").Data.Bitmap.Bytes); + File.Delete(tmpFileName); } } } diff --git a/VisualPinball.Engine.Test/VPT/Timer/TimerDataTests.cs b/VisualPinball.Engine.Test/VPT/Timer/TimerDataTests.cs index b46ae0f33..c548f4d42 100644 --- a/VisualPinball.Engine.Test/VPT/Timer/TimerDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Timer/TimerDataTests.cs @@ -14,9 +14,11 @@ // 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.Table; using VisualPinball.Engine.VPT.Timer; namespace VisualPinball.Engine.Test.VPT.Timer @@ -26,7 +28,7 @@ public class TimerDataTests [Test] public void ShouldReadTimerData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Timer); + var table = FileTableContainer.Load(VpxPath.Timer); ValidateTimerData1(table.Timer("Timer1").Data); ValidateTimerData2(table.Timer("Timer2").Data); } @@ -35,14 +37,15 @@ public void ShouldReadTimerData() public void ShouldWriteTimerData() { const string tmpFileName = "ShouldWriteTimerData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Timer); + var table = FileTableContainer.Load(VpxPath.Timer); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateTimerData1(writtenTable.Timer("Timer1").Data); ValidateTimerData2(writtenTable.Timer("Timer2").Data); + File.Delete(tmpFileName); } - private static void ValidateTimerData1(TimerData data) + public static void ValidateTimerData1(TimerData data) { data.Backglass.Should().Be(false); data.Center.X.Should().Be(471.160583f); @@ -51,7 +54,7 @@ private static void ValidateTimerData1(TimerData data) data.TimerInterval.Should().Be(233); } - private static void ValidateTimerData2(TimerData data) + public static void ValidateTimerData2(TimerData data) { data.Backglass.Should().Be(true); } diff --git a/VisualPinball.Engine.Test/VPT/Trigger/TriggerDataTests.cs b/VisualPinball.Engine.Test/VPT/Trigger/TriggerDataTests.cs index 667156cd4..a46d5417d 100644 --- a/VisualPinball.Engine.Test/VPT/Trigger/TriggerDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Trigger/TriggerDataTests.cs @@ -14,10 +14,12 @@ // 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; +using VisualPinball.Engine.VPT.Table; using VisualPinball.Engine.VPT.Trigger; namespace VisualPinball.Engine.Test.VPT.Trigger @@ -27,7 +29,7 @@ public class TriggerDataTests [Test] public void ShouldReadTriggerData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Trigger); + var table = FileTableContainer.Load(VpxPath.Trigger); ValidateTriggerData(table.Trigger("Data").Data); } @@ -35,13 +37,14 @@ public void ShouldReadTriggerData() public void ShouldWriteTriggerData() { const string tmpFileName = "ShouldWriteTriggerData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Trigger); + var table = FileTableContainer.Load(VpxPath.Trigger); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateTriggerData(writtenTable.Trigger("Data").Data); + File.Delete(tmpFileName); } - private static void ValidateTriggerData(TriggerData data) + public static void ValidateTriggerData(TriggerData data) { data.AnimSpeed.Should().Be(12.432f); data.Center.X.Should().Be(542.732f); diff --git a/VisualPinball.Engine.Test/VPT/Trigger/TriggerMeshTests.cs b/VisualPinball.Engine.Test/VPT/Trigger/TriggerMeshTests.cs index 1d6bccd31..1ed66db4b 100644 --- a/VisualPinball.Engine.Test/VPT/Trigger/TriggerMeshTests.cs +++ b/VisualPinball.Engine.Test/VPT/Trigger/TriggerMeshTests.cs @@ -17,30 +17,31 @@ using JeremyAnsel.Media.WavefrontObj; using NUnit.Framework; using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.Test.VPT.Trigger { public class TriggerMeshTests : MeshTests { - private readonly Engine.VPT.Table.Table _table; + private readonly FileTableContainer _tc; private readonly ObjFile _obj; public TriggerMeshTests() { - _table = Engine.VPT.Table.Table.Load(VpxPath.Trigger); + _tc = FileTableContainer.Load(VpxPath.Trigger); _obj = LoadObjFixture(ObjPath.Trigger); } [Test] public void ShouldGenerateMeshesCorrectly() { - AssertObjMesh(_table, _obj, _table.Trigger("Button")); - AssertObjMesh(_table, _obj, _table.Trigger("Star"), threshold: 0.001f); - AssertObjMesh(_table, _obj, _table.Trigger("WireA")); - AssertObjMesh(_table, _obj, _table.Trigger("WireB")); - AssertObjMesh(_table, _obj, _table.Trigger("WireC")); - AssertObjMesh(_table, _obj, _table.Trigger("WireD")); - AssertObjMesh(_table, _obj, _table.Trigger("Surface")); + AssertObjMesh(_tc.Table, _obj, _tc.Trigger("Button")); + AssertObjMesh(_tc.Table, _obj, _tc.Trigger("Star"), threshold: 0.001f); + AssertObjMesh(_tc.Table, _obj, _tc.Trigger("WireA")); + AssertObjMesh(_tc.Table, _obj, _tc.Trigger("WireB")); + AssertObjMesh(_tc.Table, _obj, _tc.Trigger("WireC")); + AssertObjMesh(_tc.Table, _obj, _tc.Trigger("WireD")); + AssertObjMesh(_tc.Table, _obj, _tc.Trigger("Surface")); // the last two fail because vpx ignores thickness when exporting. // re-enable when fixed on vp side. diff --git a/VisualPinball.Engine.Test/VPT/Trough/TroughDataTests.cs b/VisualPinball.Engine.Test/VPT/Trough/TroughDataTests.cs index 5f7ee0a67..95ad75649 100644 --- a/VisualPinball.Engine.Test/VPT/Trough/TroughDataTests.cs +++ b/VisualPinball.Engine.Test/VPT/Trough/TroughDataTests.cs @@ -14,20 +14,24 @@ // 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; +using VisualPinball.Engine.VPT.Table; using VisualPinball.Engine.VPT.Trough; namespace VisualPinball.Engine.Test.VPT.Trough { public class TroughDataTests { + #if !WRITE_VP106 && !WRITE_VP107 + [Test] public void ShouldReadTroughData() { - var table = Engine.VPT.Table.Table.Load(VpxPath.Trough); + var table = FileTableContainer.Load(VpxPath.Trough); ValidateTroughData(table.Trough("Trough1").Data); } @@ -35,13 +39,14 @@ public void ShouldReadTroughData() public void ShouldWriteTroughData() { const string tmpFileName = "ShouldWriteTroughData.vpx"; - var table = Engine.VPT.Table.Table.Load(VpxPath.Trough); + var table = FileTableContainer.Load(VpxPath.Trough); table.Save(tmpFileName); - var writtenTable = Engine.VPT.Table.Table.Load(tmpFileName); + var writtenTable = FileTableContainer.Load(tmpFileName); ValidateTroughData(writtenTable.Trough("Trough1").Data); + File.Delete(tmpFileName); } - private static void ValidateTroughData(TroughData data) + public static void ValidateTroughData(TroughData data) { data.Type.Should().Be(TroughType.ModernOpto); data.BallCount.Should().Be(3); @@ -53,5 +58,7 @@ private static void ValidateTroughData(TroughData data) data.PlayfieldEntrySwitch.Should().Be("BallDrain"); data.PlayfieldExitKicker.Should().Be("BallRelease"); } + + #endif } } diff --git a/VisualPinball.Engine.Test/VisualPinball.Engine.Test.csproj b/VisualPinball.Engine.Test/VisualPinball.Engine.Test.csproj index 6abe93406..4851a8c20 100644 --- a/VisualPinball.Engine.Test/VisualPinball.Engine.Test.csproj +++ b/VisualPinball.Engine.Test/VisualPinball.Engine.Test.csproj @@ -28,9 +28,9 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + diff --git a/VisualPinball.Engine.sln b/VisualPinball.Engine.sln index af0df9885..9ddfa4d66 100644 --- a/VisualPinball.Engine.sln +++ b/VisualPinball.Engine.sln @@ -6,6 +6,26 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisualPinball.Resources", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisualPinball.Engine.Test", "VisualPinball.Engine.Test\VisualPinball.Engine.Test.csproj", "{3D642DA1-C750-4EB0-AE33-E2A2CDA3DDEB}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution", "Solution", "{E74E1502-B527-475D-BCEC-B8F60699BA5F}" +ProjectSection(SolutionItems) = preProject + LICENSE = LICENSE + README.md = README.md + .editorconfig = .editorconfig + .gitignore = .gitignore + CHANGELOG.md = CHANGELOG.md + CONTRIBUTING.md = CONTRIBUTING.md + package.json = package.json +EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Workflows", "Workflows", "{E6A28E8F-1DE7-4CF4-ADB7-A55A6E6467AF}" +ProjectSection(SolutionItems) = preProject + .github\workflows\build.yml = .github\workflows\build.yml + .github\workflows\dependents.yml = .github\workflows\dependents.yml + .github\workflows\documentation.yml = .github\workflows\documentation.yml + .github\workflows\publish.yml = .github\workflows\publish.yml + .github\workflows\release.yml = .github\workflows\release.yml +EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -53,4 +73,7 @@ Global {3D642DA1-C750-4EB0-AE33-E2A2CDA3DDEB}.Release|Any CPU.ActiveCfg = Release|Any CPU {3D642DA1-C750-4EB0-AE33-E2A2CDA3DDEB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {E6A28E8F-1DE7-4CF4-ADB7-A55A6E6467AF} = {E74E1502-B527-475D-BCEC-B8F60699BA5F} + EndGlobalSection EndGlobal diff --git a/VisualPinball.Engine/Common/StringExtensions.cs b/VisualPinball.Engine/Common/StringExtensions.cs index 62fc2c171..358a1c512 100644 --- a/VisualPinball.Engine/Common/StringExtensions.cs +++ b/VisualPinball.Engine/Common/StringExtensions.cs @@ -18,12 +18,45 @@ // ReSharper disable ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator using System.Collections.Generic; +using System.IO; using System.Text.RegularExpressions; namespace VisualPinball.Engine.Common { public static class StringExtensions { + private const string InvalidFilenameRegex = @"[^ !#$%&'()+,\.0123456789;=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]\^_`abcdefghijklmnopqrstuvwxyz{}~-]+"; + + public static string ToNormalizedName(this string name) + { + var normalizedName = Regex.Replace(name.RemoveDiacritics(), @"[^.\w\d-]+", "_").ToLower(); + return normalizedName.Length == 1 ? normalizedName : normalizedName.Trim('_'); + } + + public static string ToFilename(this string name) + { + var filename = Regex.Replace(name.RemoveDiacritics(), InvalidFilenameRegex, "_"); + return filename.Length == 1 ? filename : filename.Trim('_'); + } + + private static string RemoveDiacritics(this string s) + { + var text = ""; + foreach (var c in s) { + var len = text.Length; + foreach (var entry in ForeignCharacters) { + if (entry.Key.IndexOf(c) != -1) { + text += entry.Value; + break; + } + } + if (len == text.Length) { + text += c; + } + } + return text; + } + private static readonly Dictionary ForeignCharacters = new Dictionary { {"äæǽ", "ae"}, @@ -116,30 +149,5 @@ public static class StringExtensions {"Я", "Ya"}, {"я", "ya"}, }; - - public static string RemoveDiacritics(this string s) - { - var text = ""; - foreach (var c in s) { - var len = text.Length; - foreach (var entry in ForeignCharacters) { - if (entry.Key.IndexOf(c) != -1) { - text += entry.Value; - break; - } - } - - if (len == text.Length) { - text += c; - } - } - - return text; - } - - public static string ToNormalizedName(this string name) - { - return Regex.Replace(name.RemoveDiacritics(), @"[^.\w\d-]+", "_").Trim('_').ToLower(); - } } } diff --git a/VisualPinball.Engine/IO/BiffData.cs b/VisualPinball.Engine/IO/BiffData.cs index d74bbba13..12819a224 100644 --- a/VisualPinball.Engine/IO/BiffData.cs +++ b/VisualPinball.Engine/IO/BiffData.cs @@ -30,7 +30,7 @@ namespace VisualPinball.Engine.IO { public enum StoragePrefix { - GameItem, Collection, Sound, Image, Mappings + GameItem, VpeGameItem, Collection, Sound, Image, Mappings } /// @@ -47,7 +47,7 @@ public abstract class BiffData public string StorageName => _storageName ?? $"{StoragePrefix}{StorageIndex}"; public StoragePrefix StoragePrefix; - public int StorageIndex; + public int StorageIndex = -1; public readonly List UnknownRecords = new List(); private readonly string _storageName; diff --git a/VisualPinball.Engine/Math/DragPointData.cs b/VisualPinball.Engine/Math/DragPointData.cs index 480136b9e..28f9f2aaa 100644 --- a/VisualPinball.Engine/Math/DragPointData.cs +++ b/VisualPinball.Engine/Math/DragPointData.cs @@ -24,6 +24,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using VisualPinball.Engine.IO; using VisualPinball.Engine.VPT.Table; @@ -65,6 +66,7 @@ public class DragPointData : BiffData public float CalcHeight; + [ExcludeFromCodeCoverage] public override string ToString() { return $"DragPoint({Center.X}/{Center.Y}/{Center.Z}, {(IsSmooth ? "S" : "")}{(IsSlingshot ? "SS" : "")}{(HasAutoTexture ? "A" : "")})"; diff --git a/VisualPinball.Engine/Math/Matrix2D.cs b/VisualPinball.Engine/Math/Matrix2D.cs deleted file mode 100644 index 70382fc35..000000000 --- a/VisualPinball.Engine/Math/Matrix2D.cs +++ /dev/null @@ -1,67 +0,0 @@ -// 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 . - -namespace VisualPinball.Engine.Math -{ - public struct Matrix2D - { - public float M00; - public float M01; - public float M02; - public float M10; - public float M11; - public float M12; - public float M20; - public float M21; - public float M22; - - public Matrix2D(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) - { - M00 = m00; - M01 = m01; - M02 = m02; - M10 = m10; - M11 = m11; - M12 = m12; - M20 = m20; - M21 = m21; - M22 = m22; - } - - public static Matrix2D Identity = new Matrix2D( - 1f, 0f, 0f, - 0f, 1f, 0f, - 0f, 0f, 1f - ); - - public Matrix2D RotationAroundAxis(Vertex3D axis, float rSin, float rCos) - { - M00 = axis.X * axis.X + rCos * (1.0f - axis.X * axis.X); - M10 = axis.X * axis.Y * (1.0f - rCos) - axis.Z * rSin; - M20 = axis.Z * axis.X * (1.0f - rCos) + axis.Y * rSin; - - M01 = axis.X * axis.Y * (1.0f - rCos) + axis.Z * rSin; - M11 = axis.Y * axis.Y + rCos * (1.0f - axis.Y * axis.Y); - M21 = axis.Y * axis.Z * (1.0f - rCos) - axis.X * rSin; - - M02 = axis.Z * axis.X * (1.0f - rCos) - axis.Y * rSin; - M12 = axis.Y * axis.Z * (1.0f - rCos) + axis.X * rSin; - M22 = axis.Z * axis.Z + rCos * (1.0f - axis.Z * axis.Z); - - return this; - } - } -} diff --git a/VisualPinball.Engine/Math/Rect3D.cs b/VisualPinball.Engine/Math/Rect3D.cs index e43b13f4c..9f397764c 100644 --- a/VisualPinball.Engine/Math/Rect3D.cs +++ b/VisualPinball.Engine/Math/Rect3D.cs @@ -14,8 +14,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using VisualPinball.Engine.Common; - namespace VisualPinball.Engine.Math { public struct Rect3D @@ -31,16 +29,6 @@ public struct Rect3D public float Height => MathF.Abs(Top - Bottom); public float Depth => MathF.Abs(ZLow - ZHigh); - public Rect3D(bool init) - { - Left = Constants.FloatMax; - Right = -Constants.FloatMax; - Top = Constants.FloatMax; - Bottom = -Constants.FloatMax; - ZLow = Constants.FloatMax; - ZHigh = -Constants.FloatMax; - } - public Rect3D(float left, float right, float top, float bottom, float zLow, float zHigh) { Left = left; diff --git a/VisualPinball.Engine/Math/Vertex2D.cs b/VisualPinball.Engine/Math/Vertex2D.cs index da1080207..6eda6e8f8 100644 --- a/VisualPinball.Engine/Math/Vertex2D.cs +++ b/VisualPinball.Engine/Math/Vertex2D.cs @@ -15,6 +15,7 @@ // along with this program. If not, see . using System; +using System.Diagnostics.CodeAnalysis; using System.IO; namespace VisualPinball.Engine.Math @@ -40,18 +41,6 @@ public Vertex2D(BinaryReader reader, int len) } } - public Vertex2D Set(float x, float y) - { - X = x; - Y = y; - return this; - } - - public Vertex2D SetZero() - { - return Set(0, 0); - } - public static Vertex2D operator +(Vertex2D a, Vertex2D b) => new Vertex2D(a.X + b.X, a.Y + b.Y); public static Vertex2D operator -(Vertex2D a, Vertex2D b) => new Vertex2D(a.X - b.X, a.Y - b.Y); public static Vertex2D operator *(Vertex2D a, float b) => new Vertex2D(a.X * b, a.Y * b); @@ -69,21 +58,7 @@ public float Length() return MathF.Sqrt(X * X + Y * Y); } - public float LengthSq() - { - return X * X + Y * Y; - } - - public float Dot(Vertex2D pv) - { - return X * pv.X + Y * pv.Y; - } - - public bool Equals(Vertex2D v) - { - return X == v.X && Y == v.Y; - } - + [ExcludeFromCodeCoverage] public override string ToString() { return $"Vertex2D({X}/{Y})"; diff --git a/VisualPinball.Engine/Math/Vertex3D.cs b/VisualPinball.Engine/Math/Vertex3D.cs index 7235aa6f9..de077deb4 100644 --- a/VisualPinball.Engine/Math/Vertex3D.cs +++ b/VisualPinball.Engine/Math/Vertex3D.cs @@ -15,6 +15,7 @@ // along with this program. If not, see . using System; +using System.Diagnostics.CodeAnalysis; using System.IO; using VisualPinball.Engine.Common; @@ -37,13 +38,6 @@ public Vertex3D(float x, float y, float z) Z = z; } - public Vertex3D(Vertex3D v) - { - X = v.X; - Y = v.Y; - Z = v.Z; - } - public Vertex3D(BinaryReader reader, int len) { X = reader.ReadSingle(); @@ -63,16 +57,6 @@ public Vertex3D(BinaryReader reader, int len) public static Vertex3D operator *(Vertex3D a, float b) => new Vertex3D(a.X * b, a.Y * b, a.Z * b); public static Vertex3D operator *(float a, Vertex3D b) => b * a; public static Vertex3D operator /(Vertex3D a, float b) => new Vertex3D(a.X / b, a.Y / b, a.Z / b); - public static Vertex3D operator *(Matrix2D matrix, Vertex3D b) => new Vertex3D( - matrix.M00 * b.X + matrix.M01 * b.Y + matrix.M02 * b.Z, - matrix.M10 * b.X + matrix.M11 * b.Y + matrix.M12 * b.Z, - matrix.M20 * b.X + matrix.M21 * b.Y + matrix.M22 * b.Z - ); - - public static void Reset(Vertex3D v) - { - v.Set(0, 0, 0); - } public Vertex3D Set(Vertex3D v) { @@ -90,12 +74,7 @@ public Vertex3D Set(float x, float y, float z) return this; } - // public new Vertex3D Clone() - // { - // return new Vertex3D(this); - // } - - public new void Normalize() + public void Normalize() { var oneOverLength = 1.0f / Length(); X *= oneOverLength; @@ -112,66 +91,21 @@ public Vertex3D NormalizeSafe() return this; } - public new float Length() + public float Length() { return MathF.Sqrt(X * X + Y * Y + Z * Z); } - public new float LengthSq() + public float LengthSq() { return X * X + Y * Y + Z * Z; } - // public new Vertex3D DivideScalar(float scalar) - // { - // return MultiplyScalar(1 / scalar); - // } - - // public new Vertex3D MultiplyScalar(float scalar) - // { - // X *= scalar; - // Y *= scalar; - // Z *= scalar; - // return this; - // } - - // public Vertex3D ApplyMatrix2D(Matrix2D matrix) - // { - // var x = matrix.Matrix[0][0] * X + matrix.Matrix[0][1] * Y + matrix.Matrix[0][2] * Z; - // var y = matrix.Matrix[1][0] * X + matrix.Matrix[1][1] * Y + matrix.Matrix[1][2] * Z; - // var z = matrix.Matrix[2][0] * X + matrix.Matrix[2][1] * Y + matrix.Matrix[2][2] * Z; - // X = x; - // Y = y; - // Z = z; - // return this; - // } - public float Dot(Vertex3D v) { return X * v.X + Y * v.Y + Z * v.Z; } - // public Vertex3D Sub(Vertex3D v) - // { - // X -= v.X; - // Y -= v.Y; - // Z -= v.Z; - // return this; - // } - - // public Vertex3D Add(Vertex3D v) - // { - // X += v.X; - // Y += v.Y; - // Z += v.Z; - // return this; - // } - - // public Vertex3D Cross(Vertex3D v) - // { - // return CrossVectors(this, v); - // } - public static Vertex3D CrossVectors(Vertex3D a, Vertex3D b) { var ax = a.X; @@ -188,27 +122,12 @@ public static Vertex3D CrossVectors(Vertex3D a, Vertex3D b) ); } - public Vertex2D xy() - { - return new Vertex2D(X, Y); - } - - public new Vertex3D SetZero() - { - return Set(0f, 0f, 0f); - } - public bool IsZero() { return MathF.Abs(X) < Constants.FloatMin && MathF.Abs(Y) < Constants.FloatMin && MathF.Abs(Z) < Constants.FloatMin; } - public bool Equals(Vertex3D v) - { - return v.X == X && v.Y == Y && v.Z == Z; - } - public static Vertex3D CrossProduct(Vertex3D pv1, Vertex3D pv2) { return new Vertex3D( @@ -218,11 +137,6 @@ public static Vertex3D CrossProduct(Vertex3D pv1, Vertex3D pv2) ); } - public static Vertex3D CrossZ(float rz, Vertex3D v) - { - return new Vertex3D(-rz * v.Y, rz * v.X, 0); - } - public static Vertex3D GetRotatedAxis(float angle, Vertex3D axis, Vertex3D temp) { var u = axis; @@ -261,11 +175,10 @@ public Vertex3D MultiplyMatrixNoTranslate(Matrix3D matrix) return matrix.MultiplyMatrixNoTranslate(this); } + [ExcludeFromCodeCoverage] public override string ToString() { return $"Vertex3D({X}/{Y}/{Z})"; } - - public float Magnitude() => MathF.Sqrt(this.Dot(this)); } } diff --git a/VisualPinball.Engine/Math/Vertex3DNoTex2.cs b/VisualPinball.Engine/Math/Vertex3DNoTex2.cs index 0e30f9dc7..696583914 100644 --- a/VisualPinball.Engine/Math/Vertex3DNoTex2.cs +++ b/VisualPinball.Engine/Math/Vertex3DNoTex2.cs @@ -16,12 +16,13 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; namespace VisualPinball.Engine.Math { [Serializable] - public struct Vertex3DNoTex2 + public struct Vertex3DNoTex2 : IEquatable { public const int Size = 32; @@ -104,14 +105,7 @@ public Vertex3D GetVertex() { return new Vertex3D(X, Y, Z); } - public Vertex3D GetNormal() { - return new Vertex3D(Nx, Ny, Nz); - } - - public bool HasTextureCoordinates() { - return !float.IsNaN(Tu) && !float.IsNaN(Tv); - } - + [ExcludeFromCodeCoverage] public override string ToString() { return $"Vertex3DNoTex2({X}/{Y}/{Z}, {Nx}/{Ny}/{Nz}, {Tu}/{Tv})"; @@ -123,5 +117,19 @@ public void MultiplyMatrix(Matrix3D m) Y = v.Y; Z = v.Z; } + + public bool Equals(Vertex3DNoTex2 other) + { + return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && Nx.Equals(other.Nx) && Ny.Equals(other.Ny) && Nz.Equals(other.Nz) && Tu.Equals(other.Tu) && Tv.Equals(other.Tv); + } + public override bool Equals(object obj) + { + return obj is Vertex3DNoTex2 other && Equals(other); + } + + public override int GetHashCode() + { + return (X, Y, Z, Nx, Ny, Nz, Tu, Tv).GetHashCode(); + } } } diff --git a/VisualPinball.Engine/VPT/BinaryData.cs b/VisualPinball.Engine/VPT/BinaryData.cs index 010d9fc0e..1083f33af 100644 --- a/VisualPinball.Engine/VPT/BinaryData.cs +++ b/VisualPinball.Engine/VPT/BinaryData.cs @@ -63,6 +63,17 @@ public BinaryData(Resource res) : base(res.Name) Data = res.Data; } + public BinaryData(string name, byte[] data) : base(string.Empty) + { + Name = name; + Data = data; + } + + public void FreeBinaryData() + { + Data = new byte[0]; + } + protected override bool SkipWrite(BiffAttribute attr) { switch (attr.Name) { diff --git a/VisualPinball.Engine/VPT/Bitmap.cs b/VisualPinball.Engine/VPT/Bitmap.cs index f17c01e27..327195e23 100644 --- a/VisualPinball.Engine/VPT/Bitmap.cs +++ b/VisualPinball.Engine/VPT/Bitmap.cs @@ -86,6 +86,11 @@ public Bitmap(BinaryReader reader, int width, int height, int format = RGBA) Data = ToggleRgbBgr(Data); } + public void FreeBinaryData() + { + Data = new byte[0]; + } + public void WriteCompressed(BinaryWriter writer) { var lzwWriter = new LzwWriter(writer, ToggleRgbBgr(Data), Width * 4, Height, Pitch()); diff --git a/VisualPinball.Engine/VPT/Flipper/Flipper.cs b/VisualPinball.Engine/VPT/Flipper/Flipper.cs index fae6cbd52..a8881583d 100644 --- a/VisualPinball.Engine/VPT/Flipper/Flipper.cs +++ b/VisualPinball.Engine/VPT/Flipper/Flipper.cs @@ -17,6 +17,7 @@ using System.IO; using VisualPinball.Engine.Game; using VisualPinball.Engine.Math; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.VPT.Flipper { diff --git a/VisualPinball.Engine/VPT/Flipper/FlipperMeshGenerator.cs b/VisualPinball.Engine/VPT/Flipper/FlipperMeshGenerator.cs index e6231c58d..2d8588dc7 100644 --- a/VisualPinball.Engine/VPT/Flipper/FlipperMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Flipper/FlipperMeshGenerator.cs @@ -16,6 +16,8 @@ // ReSharper disable CompareOfFloatsByEqualityOperator +#nullable enable + using System; using System.Collections.Generic; using VisualPinball.Engine.Game; @@ -42,7 +44,7 @@ public FlipperMeshGenerator(FlipperData data) _data = data; } - public RenderObject GetRenderObject(Table.Table table, string id, Origin origin, bool asRightHanded) + public RenderObject? GetRenderObject(Table.Table table, string id, Origin origin, bool asRightHanded) { var meshes = GenerateMeshes(table); var (preVertexMatrix, preNormalsMatrix) = GetPreMatrix(table, origin, asRightHanded); @@ -94,7 +96,7 @@ public RenderObjectGroup GetRenderObjects(Table.Table table, Origin origin, bool return new RenderObjectGroup(_data.Name, "Flippers", postMatrix, renderObjects.ToArray()); } - protected override float BaseHeight(Table.Table table) + protected override float BaseHeight(Table.Table? table) { return 0f; // already in vertices } diff --git a/VisualPinball.Engine/VPT/Gate/GateData.cs b/VisualPinball.Engine/VPT/Gate/GateData.cs index ad06936ea..c2b8aec48 100644 --- a/VisualPinball.Engine/VPT/Gate/GateData.cs +++ b/VisualPinball.Engine/VPT/Gate/GateData.cs @@ -31,7 +31,7 @@ namespace VisualPinball.Engine.VPT.Gate { [Serializable] - public class GateData : ItemData, IPhysicalData + public class GateData : ItemData, IPhysicsMaterialData { public override string GetName() => Name; public override void SetName(string name) { Name = name; } diff --git a/VisualPinball.Engine/VPT/Gate/GateMeshGenerator.cs b/VisualPinball.Engine/VPT/Gate/GateMeshGenerator.cs index e12b00223..6823c7e2a 100644 --- a/VisualPinball.Engine/VPT/Gate/GateMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Gate/GateMeshGenerator.cs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#nullable enable + using System; using NLog; using VisualPinball.Engine.Game; @@ -72,9 +74,9 @@ public RenderObjectGroup GetRenderObjects(Table.Table table, Origin origin, bool ); } - protected override float BaseHeight(Table.Table table) + protected override float BaseHeight(Table.Table? table) { - return table.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y); + return table?.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y) ?? 0f; } private Mesh GetBaseMesh() diff --git a/VisualPinball.Engine/VPT/HitTarget/HitTargetData.cs b/VisualPinball.Engine/VPT/HitTarget/HitTargetData.cs index f40e6b9d4..9a0820971 100644 --- a/VisualPinball.Engine/VPT/HitTarget/HitTargetData.cs +++ b/VisualPinball.Engine/VPT/HitTarget/HitTargetData.cs @@ -31,7 +31,7 @@ namespace VisualPinball.Engine.VPT.HitTarget { [Serializable] - public class HitTargetData : ItemData, IPhysicalData + public class HitTargetData : ItemData, IPhysicsMaterialData { public override string GetName() => Name; public override void SetName(string name) { Name = name; } diff --git a/VisualPinball.Engine/VPT/HitTarget/HitTargetMeshGenerator.cs b/VisualPinball.Engine/VPT/HitTarget/HitTargetMeshGenerator.cs index a4da0f6d5..1d28478b3 100644 --- a/VisualPinball.Engine/VPT/HitTarget/HitTargetMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/HitTarget/HitTargetMeshGenerator.cs @@ -61,7 +61,7 @@ public RenderObjectGroup GetRenderObjects(Table.Table table, Origin origin, bool protected override float BaseHeight(Table.Table table) { - return table.TableHeight; + return table?.TableHeight ?? 0f; } private Mesh GetBaseMesh() diff --git a/VisualPinball.Engine/VPT/IItem.cs b/VisualPinball.Engine/VPT/IItem.cs index a7369d750..5f3280a0e 100644 --- a/VisualPinball.Engine/VPT/IItem.cs +++ b/VisualPinball.Engine/VPT/IItem.cs @@ -34,5 +34,7 @@ public interface IItem string ComponentName { get; } ItemSubComponent SubComponent { get; } string SubName { get; } + + void FreeBinaryData(); } } diff --git a/VisualPinball.Engine/VPT/Item.cs b/VisualPinball.Engine/VPT/Item.cs index d4d362bb9..41e5e15fe 100644 --- a/VisualPinball.Engine/VPT/Item.cs +++ b/VisualPinball.Engine/VPT/Item.cs @@ -57,6 +57,10 @@ public string Name public ItemSubComponent SubComponent { get; private set; } public string SubName { get; private set; } + public virtual void FreeBinaryData() + { + } + protected Item(TData data) { Data = data; diff --git a/VisualPinball.Engine/VPT/ItemData.cs b/VisualPinball.Engine/VPT/ItemData.cs index e0cb5dbd8..a311f2618 100644 --- a/VisualPinball.Engine/VPT/ItemData.cs +++ b/VisualPinball.Engine/VPT/ItemData.cs @@ -64,7 +64,7 @@ protected ItemData(string storageName) : base(storageName) } } - public interface IPhysicalData + public interface IPhysicsMaterialData { /// /// If , use this elasticity instead of the material's. diff --git a/VisualPinball.Engine/VPT/Kicker/KickerMeshGenerator.cs b/VisualPinball.Engine/VPT/Kicker/KickerMeshGenerator.cs index bf27228d0..3276aed67 100644 --- a/VisualPinball.Engine/VPT/Kicker/KickerMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Kicker/KickerMeshGenerator.cs @@ -72,7 +72,7 @@ public RenderObjectGroup GetRenderObjects(Table.Table table, Origin origin, bool protected override float BaseHeight(Table.Table table) { - return table.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y); + return table?.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y) ?? 0f; } private Mesh GetBaseMesh() diff --git a/VisualPinball.Engine/VPT/Light/LightMeshGenerator.cs b/VisualPinball.Engine/VPT/Light/LightMeshGenerator.cs index 4a58829d4..6813efa3b 100644 --- a/VisualPinball.Engine/VPT/Light/LightMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Light/LightMeshGenerator.cs @@ -93,7 +93,7 @@ public Matrix3D GetPostMatrix(Table.Table table, Origin origin) return new Matrix3D().SetTranslation( _data.Center.X, _data.Center.Y, - table.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y) * table.GetScaleZ() + (table?.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y) ?? 0f) * table?.GetScaleZ() ?? 1.0f ); case Origin.Global: diff --git a/VisualPinball.Engine/VPT/Mesh.cs b/VisualPinball.Engine/VPT/Mesh.cs index bcf138d99..d5841d702 100644 --- a/VisualPinball.Engine/VPT/Mesh.cs +++ b/VisualPinball.Engine/VPT/Mesh.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.IO; using VisualPinball.Engine.Common; @@ -33,7 +34,7 @@ namespace VisualPinball.Engine.VPT /// coordinates. /// [Serializable] - public class Mesh + public class Mesh : IEquatable { public string Name; public Vertex3DNoTex2[] Vertices; @@ -217,6 +218,7 @@ public static int[] PolygonToTriangles(IRenderVertex[] rgv, List poly) return tri.ToArray(); } + [ExcludeFromCodeCoverage] public static void ClosestPointOnPolygon(RenderVertex3D[] rgv, Vertex2D pvin, bool fClosed, out Vertex2D pvOut, out int piSeg) { var count = rgv.Length; @@ -373,7 +375,7 @@ private static bool LinesIntersect(IRenderVertex start1, IRenderVertex start2, I /// It is used primarily for storing animation frames. /// [Serializable] - public struct VertData + public struct VertData : IEquatable { public const int Size = 24; @@ -456,6 +458,7 @@ public VertData Clone() return vertex; } + [ExcludeFromCodeCoverage] public override string ToString() { return $"VertData({X}/{Y}/{Z}, {Nx}/{Ny}/{Nz})"; @@ -465,8 +468,86 @@ public Vertex3DNoTex2 ToVertex3DNoTex2() { return new Vertex3DNoTex2(X, Y, Z, Nx, Ny, Nz, 0f, 0f); } + + #region IEquatable + + public bool Equals(VertData other) + { + return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && Nx.Equals(other.Nx) && Ny.Equals(other.Ny) && Nz.Equals(other.Nz); + } + + public override bool Equals(object obj) + { + return obj is VertData other && Equals(other); + } + + public override int GetHashCode() + { + return (X, Y, Z, Nx, Ny, Nz).GetHashCode(); + } + + #endregion + } #endregion + + #region IEquatable + + public bool Equals(Mesh other) + { + if (ReferenceEquals(null, other)) { + return false; + } + if (ReferenceEquals(this, other)) { + return true; + } + if (!Name.Equals(other.Name) || Vertices.Length != other.Vertices.Length + || Indices.Length != other.Indices.Length + || AnimationFrames.Count != other.AnimationFrames.Count + || !AnimationDefaultPosition.Equals(other.AnimationDefaultPosition)) { + return false; + } + + for (var i = 0; i < Vertices.Length; i++) { + if (!Vertices[i].Equals(other.Vertices[i])) { + return false; + } + } + + for (var i = 0; i < Indices.Length; i++) { + if (!Indices[i].Equals(other.Indices[i])) { + return false; + } + } + + for (var i = 0; i < AnimationFrames.Count; i++) { + for (var j = 0; j < AnimationFrames[i].Length; j++) { + if (!AnimationFrames[i][j].Equals(other.AnimationFrames[i][j])) { + return false; + } + } + } + + return true; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) { + return false; + } + if (ReferenceEquals(this, obj)) { + return true; + } + return obj.GetType() == GetType() && Equals((Mesh)obj); + } + + public override int GetHashCode() + { + return (Name, Vertices, Indices, AnimationFrames, AnimationDefaultPosition).GetHashCode(); + } + + #endregion } } diff --git a/VisualPinball.Engine/VPT/MeshGenerator.cs b/VisualPinball.Engine/VPT/MeshGenerator.cs index 8003b5940..33dc52695 100644 --- a/VisualPinball.Engine/VPT/MeshGenerator.cs +++ b/VisualPinball.Engine/VPT/MeshGenerator.cs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#nullable enable + using System; using VisualPinball.Engine.Game; using VisualPinball.Engine.Math; @@ -22,24 +24,24 @@ namespace VisualPinball.Engine.VPT { public abstract class MeshGenerator { - protected abstract float BaseHeight(Table.Table table); + protected abstract float BaseHeight(Table.Table? table); protected abstract Vertex3D Position { get; } protected abstract Vertex3D Scale { get; } protected abstract float RotationZ { get; } - protected Tuple GetPreMatrix(Table.Table table, Origin origin, bool asRightHanded) + protected Tuple GetPreMatrix(Table.Table? table, Origin origin, bool asRightHanded) { // todo adjust position, see kicker.cpp#419+ switch (origin) { case Origin.Original: return asRightHanded - ? new Tuple(Matrix3D.RightHanded, null) - : new Tuple(Matrix3D.Identity, null); + ? new Tuple(Matrix3D.RightHanded, null) + : new Tuple(Matrix3D.Identity, null); case Origin.Global: var m = GetTransformationMatrix(table); return asRightHanded - ? new Tuple(m.Item1.Multiply(Matrix3D.RightHanded), m.Item2?.Multiply(Matrix3D.RightHanded)) + ? new Tuple(m.Item1.Multiply(Matrix3D.RightHanded), m.Item2?.Multiply(Matrix3D.RightHanded)) : m; default: throw new ArgumentOutOfRangeException(nameof(origin), origin, "Unknown origin " + origin); @@ -56,7 +58,7 @@ internal Matrix3D GetPostMatrix(Table.Table table, Origin origin) } } - protected virtual Tuple GetTransformationMatrix(Table.Table table) + protected virtual Tuple GetTransformationMatrix(Table.Table? table) { var scale = Scale; var position = Position; @@ -76,10 +78,10 @@ protected virtual Tuple GetTransformationMatrix(Table.Table var fullMatrix = scaleMatrix.Clone(); fullMatrix.Multiply(rotMatrix); fullMatrix.Multiply(transMatrix); - scaleMatrix.SetScaling(1.0f, 1.0f, table.GetScaleZ()); + scaleMatrix.SetScaling(1.0f, 1.0f, table?.GetScaleZ() ?? 1.0f); fullMatrix.Multiply(scaleMatrix); - return new Tuple(fullMatrix, null); + return new Tuple(fullMatrix, null); } } } diff --git a/VisualPinball.Engine/VPT/Primitive/Primitive.cs b/VisualPinball.Engine/VPT/Primitive/Primitive.cs index 24016f12a..450a53abe 100644 --- a/VisualPinball.Engine/VPT/Primitive/Primitive.cs +++ b/VisualPinball.Engine/VPT/Primitive/Primitive.cs @@ -17,6 +17,7 @@ using System.IO; using VisualPinball.Engine.Game; using VisualPinball.Engine.Math; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.VPT.Primitive { @@ -47,6 +48,11 @@ public Primitive(BinaryReader reader, string itemName) : this(new PrimitiveData( { } + public override void FreeBinaryData() + { + Data.FreeBinaryData(); + } + public static Primitive GetDefault(Table.Table table) { var primitiveData = new PrimitiveData(table.GetNewName("Primitive"), table.Width / 2f, table.Height / 2f); diff --git a/VisualPinball.Engine/VPT/Primitive/PrimitiveData.cs b/VisualPinball.Engine/VPT/Primitive/PrimitiveData.cs index 677473034..57723e3d9 100644 --- a/VisualPinball.Engine/VPT/Primitive/PrimitiveData.cs +++ b/VisualPinball.Engine/VPT/Primitive/PrimitiveData.cs @@ -31,7 +31,7 @@ namespace VisualPinball.Engine.VPT.Primitive { [Serializable] - public class PrimitiveData : ItemData, IPhysicalData + public class PrimitiveData : ItemData, IPhysicsMaterialData { public override string GetName() => Name; public override void SetName(string name) { Name = name; } @@ -181,6 +181,12 @@ public class PrimitiveData : ItemData, IPhysicalData public bool GetIsCollidable() => IsCollidable; public string GetPhysicsMaterial() => PhysicsMaterial; + public void FreeBinaryData() + { + Mesh = null; + CompressedAnimationVertices = new int[0]; + } + protected override bool SkipWrite(BiffAttribute attr) { switch (attr.Name) { diff --git a/VisualPinball.Engine/VPT/Primitive/PrimitiveMeshGenerator.cs b/VisualPinball.Engine/VPT/Primitive/PrimitiveMeshGenerator.cs index 1f26d11f4..8c532373e 100644 --- a/VisualPinball.Engine/VPT/Primitive/PrimitiveMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Primitive/PrimitiveMeshGenerator.cs @@ -18,6 +18,7 @@ using VisualPinball.Engine.Common; using VisualPinball.Engine.Game; using VisualPinball.Engine.Math; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Engine.VPT.Primitive { @@ -78,7 +79,7 @@ public Mesh GetTransformedMesh(Table.Table table, Origin origin, bool asRightHan protected override float BaseHeight(Table.Table table) { - return table.TableHeight; + return table?.TableHeight ?? 0f; } protected override Tuple GetTransformationMatrix(Table.Table table) @@ -89,7 +90,7 @@ protected override Tuple GetTransformationMatrix(Table.Table // translation matrix var transMatrix = new Matrix3D(); - transMatrix.SetTranslation(Position.X, Position.Y, Position.Z + table.TableHeight); + transMatrix.SetTranslation(Position.X, Position.Y, Position.Z + table?.TableHeight ?? 0f); // translation + rotation matrix var rotTransMatrix = new Matrix3D(); @@ -113,7 +114,7 @@ protected override Tuple GetTransformationMatrix(Table.Table var fullMatrix = scaleMatrix.Clone(); fullMatrix.Multiply(rotTransMatrix); fullMatrix.Multiply(transMatrix); // fullMatrix = Smatrix * RTmatrix * Tmatrix - scaleMatrix.SetScaling(1.0f, 1.0f, table.GetScaleZ()); + scaleMatrix.SetScaling(1.0f, 1.0f, table?.GetScaleZ() ?? 1f); fullMatrix.Multiply(scaleMatrix); return new Tuple(fullMatrix, null); diff --git a/VisualPinball.Engine/VPT/Ramp/RampData.cs b/VisualPinball.Engine/VPT/Ramp/RampData.cs index a819c336b..e447f2ae1 100644 --- a/VisualPinball.Engine/VPT/Ramp/RampData.cs +++ b/VisualPinball.Engine/VPT/Ramp/RampData.cs @@ -31,7 +31,7 @@ namespace VisualPinball.Engine.VPT.Ramp { [Serializable] - public class RampData : ItemData, IPhysicalData + public class RampData : ItemData, IPhysicsMaterialData { public override string GetName() => Name; public override void SetName(string name) { Name = name; } diff --git a/VisualPinball.Engine/VPT/Rubber/RubberData.cs b/VisualPinball.Engine/VPT/Rubber/RubberData.cs index bba808cae..61cda506c 100644 --- a/VisualPinball.Engine/VPT/Rubber/RubberData.cs +++ b/VisualPinball.Engine/VPT/Rubber/RubberData.cs @@ -31,7 +31,7 @@ namespace VisualPinball.Engine.VPT.Rubber { [Serializable] - public class RubberData : ItemData, IPhysicalData + public class RubberData : ItemData, IPhysicsMaterialData { public override string GetName() => Name; public override void SetName(string name) { Name = name; } diff --git a/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs b/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs index 876f55700..32e0b5ba5 100644 --- a/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Rubber/RubberMeshGenerator.cs @@ -16,6 +16,8 @@ // ReSharper disable CompareOfFloatsByEqualityOperator +#nullable enable + using System; using NLog; using VisualPinball.Engine.Common; @@ -63,7 +65,7 @@ public RenderObjectGroup GetRenderObjects(Table.Table table, Origin origin, bool )); } - protected override Tuple GetTransformationMatrix(Table.Table table) + protected override Tuple GetTransformationMatrix(Table.Table? table) { var fullMatrix = new Matrix3D(); var tempMat = new Matrix3D(); @@ -76,19 +78,19 @@ protected override Tuple GetTransformationMatrix(Table.Table var vertMatrix = new Matrix3D(); tempMat.SetTranslation(-Position.X, -Position.Y, -Position.Z); vertMatrix.Multiply(tempMat, fullMatrix); - tempMat.SetScaling(Scale.X, Scale.Y, Scale.Z * table.GetScaleZ()); + tempMat.SetScaling(Scale.X, Scale.Y, Scale.Z * table?.GetScaleZ() ?? 0f); vertMatrix.Multiply(tempMat); if (_data.Height == _data.HitHeight) { // do not z-scale the hit mesh - tempMat.SetTranslation(Position.X, Position.Y, _data.Height + table.TableHeight); + tempMat.SetTranslation(Position.X, Position.Y, _data.Height + table?.TableHeight ?? 0f); } else { - tempMat.SetTranslation(Position.X, Position.Y, _data.Height * table.GetScaleZ() + table.TableHeight); + tempMat.SetTranslation(Position.X, Position.Y, _data.Height * (table?.GetScaleZ() ?? 1f) + (table?.TableHeight ?? 0f)); } vertMatrix.Multiply(tempMat); - return new Tuple(vertMatrix, fullMatrix); + return new Tuple(vertMatrix, fullMatrix); } public Mesh GetMesh(Table.Table table, int acc = -1, bool createHitShape = false) @@ -241,7 +243,7 @@ public Mesh GetMesh(Table.Table table, int acc = -1, bool createHitShape = false return mesh; } - protected override float BaseHeight(Table.Table table) + protected override float BaseHeight(Table.Table? table) { return 0f; } diff --git a/VisualPinball.Engine/VPT/Sound/Sound.cs b/VisualPinball.Engine/VPT/Sound/Sound.cs index 38745f60a..203506acb 100644 --- a/VisualPinball.Engine/VPT/Sound/Sound.cs +++ b/VisualPinball.Engine/VPT/Sound/Sound.cs @@ -24,6 +24,8 @@ public class Sound : Item public override string ItemGroupName { get; } = "Sounds"; public override ItemType ItemType { get; } = ItemType.Sound; + public string FileExtension => Data.Path == null ? ".wav" : Path.GetExtension(Data.Path).ToLower(); + public Sound(string name) : this(new SoundData(name)) { Name = name; diff --git a/VisualPinball.Engine/VPT/Sound/SoundData.cs b/VisualPinball.Engine/VPT/Sound/SoundData.cs index d192f2b09..bee196893 100644 --- a/VisualPinball.Engine/VPT/Sound/SoundData.cs +++ b/VisualPinball.Engine/VPT/Sound/SoundData.cs @@ -16,6 +16,7 @@ using System; using System.IO; +using System.Net; using System.Text; using VisualPinball.Engine.Common; using VisualPinball.Engine.VPT.Table; @@ -39,6 +40,8 @@ public class SoundData : ItemData public int Balance; public int Fade; + public bool IsWav => Path.EndsWith(".wav", StringComparison.OrdinalIgnoreCase); + public SoundData(string name) : base(IO.StoragePrefix.Sound) { Name = name; @@ -53,26 +56,44 @@ public SoundData(BinaryReader reader, string storageName, int fileVersion) : bas Load(reader, fileVersion); } + public byte[] GetFileData() + { + using (var stream = new MemoryStream()) + using (var writer = new BinaryWriter(stream)) { + if (IsWav) { + WriteHeader(writer); + } + writer.Write(Data); + return stream.ToArray(); + } + } + public byte[] GetHeader() { using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { - writer.Write(Encoding.Default.GetBytes("RIFF")); - writer.Write(Data.Length + 36); - writer.Write(Encoding.Default.GetBytes("WAVE")); - writer.Write(Encoding.Default.GetBytes("fmt ")); - writer.Write(16); - writer.Write((short)Wfx.FormatTag); - writer.Write((short)Wfx.Channels); - writer.Write((int)Wfx.SamplesPerSec); - writer.Write((int)(Wfx.SamplesPerSec * Wfx.BitsPerSample * Wfx.Channels / 8)); - writer.Write((short)Wfx.BlockAlign); - writer.Write((short)Wfx.BitsPerSample); - writer.Write(Encoding.Default.GetBytes("data")); - writer.Write(Data.Length); + WriteHeader(writer); return stream.ToArray(); } } + private void WriteHeader(BinaryWriter writer) + { + writer.Write(Encoding.Default.GetBytes("RIFF")); // 4 + writer.Write(Data.Length + 36); // 4 + writer.Write(Encoding.Default.GetBytes("WAVE")); // 4 + writer.Write(Encoding.Default.GetBytes("fmt ")); // 4 + writer.Write(16); // 4 + writer.Write((short)Wfx.FormatTag); // 2 + writer.Write((short)Wfx.Channels); // 2 + writer.Write((int)Wfx.SamplesPerSec); // 4 + writer.Write((int)(Wfx.SamplesPerSec * Wfx.BitsPerSample * Wfx.Channels / 8)); // 4 + writer.Write((short)Wfx.BlockAlign); // 2 + writer.Write((short)Wfx.BitsPerSample); // 2 + writer.Write(Encoding.Default.GetBytes("data")); // 4 + writer.Write(Data.Length); // 4 + // total 44 bytes + } + private void Load(BinaryReader reader, int fileVersion) { var numValues = fileVersion < Constants.NewSoundFormatVersion ? 5 : 10; @@ -92,7 +113,11 @@ private void Load(BinaryReader reader, int fileVersion) len = reader.ReadInt32(); InternalName = Encoding.Default.GetString(reader.ReadBytes(len)); break; - case 3: Wfx = new WaveFormat(reader); break; + case 3: + if (IsWav) { + Wfx = new WaveFormat(reader); + } + break; case 4: len = reader.ReadInt32(); Data = reader.ReadBytes(len); @@ -117,7 +142,9 @@ public override void Write(BinaryWriter writer, HashWriter hashWriter) writer.Write(Encoding.Default.GetBytes(InternalName).Length); writer.Write(Encoding.Default.GetBytes(InternalName)); - Wfx.Write(writer); + if (IsWav) { + Wfx.Write(writer); + } writer.Write(Data.Length); writer.Write(Data); diff --git a/VisualPinball.Engine/VPT/Spinner/SpinnerMeshGenerator.cs b/VisualPinball.Engine/VPT/Spinner/SpinnerMeshGenerator.cs index 0e778cff1..053974839 100644 --- a/VisualPinball.Engine/VPT/Spinner/SpinnerMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Spinner/SpinnerMeshGenerator.cs @@ -99,7 +99,7 @@ private static Material GetBracketMaterial() protected override float BaseHeight(Table.Table table) { - return table.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y); + return table?.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y) ?? 0f; } #region Mesh Imports diff --git a/VisualPinball.Engine/VPT/Surface/SurfaceData.cs b/VisualPinball.Engine/VPT/Surface/SurfaceData.cs index b09accd03..07ad81e16 100644 --- a/VisualPinball.Engine/VPT/Surface/SurfaceData.cs +++ b/VisualPinball.Engine/VPT/Surface/SurfaceData.cs @@ -31,7 +31,7 @@ namespace VisualPinball.Engine.VPT.Surface { [Serializable] - public class SurfaceData : ItemData, IPhysicalData + public class SurfaceData : ItemData, IPhysicsMaterialData { public override string GetName() => Name; public override void SetName(string name) { Name = name; } diff --git a/VisualPinball.Engine/VPT/Table/CustomInfoTags.cs b/VisualPinball.Engine/VPT/Table/CustomInfoTags.cs index 236642e17..49a1c8fe0 100644 --- a/VisualPinball.Engine/VPT/Table/CustomInfoTags.cs +++ b/VisualPinball.Engine/VPT/Table/CustomInfoTags.cs @@ -47,6 +47,11 @@ public CustomInfoTags(BinaryReader reader) : this() Load(this, reader, Attributes); } + public void Load(BinaryReader reader) + { + Load(this, reader, Attributes); + } + public override void Write(BinaryWriter writer, HashWriter hashWriter) { WriteRecord(writer, Attributes, hashWriter); diff --git a/VisualPinball.Engine/VPT/Table/DefaultTableResourceContainer.cs b/VisualPinball.Engine/VPT/Table/DefaultTableResourceContainer.cs deleted file mode 100644 index 52e8e1f0e..000000000 --- a/VisualPinball.Engine/VPT/Table/DefaultTableResourceContainer.cs +++ /dev/null @@ -1,50 +0,0 @@ -// 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.Collections; -using System.Collections.Generic; - -namespace VisualPinball.Engine.VPT.Table -{ - /// - /// Provides a basic default implementation for ITableResourceContainer that stores T in a c# dict - /// - /// - public class DefaultTableResourceContainer : ITableResourceContainer where T : IItem - { - private Dictionary _dict = new Dictionary(); - - public int Count => _dict.Count; - public IEnumerable Values => _dict.Values; - - public T this[string k] => Get(k); - public T Get(string k) - { - _dict.TryGetValue(k.ToLower(), out T val); - return val; - } - public void Add(T value) => _dict[value.Name.ToLower()] = value; - public bool Remove(T value) => _dict.Remove(value.Name.ToLower()); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() - { - foreach (var kvp in _dict) { - yield return kvp.Value; - } - } - } -} diff --git a/VisualPinball.Engine/VPT/Table/FileTableContainer.cs b/VisualPinball.Engine/VPT/Table/FileTableContainer.cs new file mode 100644 index 000000000..eda43777b --- /dev/null +++ b/VisualPinball.Engine/VPT/Table/FileTableContainer.cs @@ -0,0 +1,173 @@ +// 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 System.IO; +using System.Linq; +using VisualPinball.Engine.VPT.Collection; + +namespace VisualPinball.Engine.VPT.Table +{ + public class FileTableContainer : TableContainer + { + public override Table Table { get; } + public override Dictionary TableInfo { get; } = new Dictionary(); + public override List Collections { get; } = new List(); + public override Mappings.Mappings Mappings => _mappings; + public override CustomInfoTags CustomInfoTags { get; } = new CustomInfoTags(); + public override IEnumerable Textures => _textures.Values; + public override IEnumerable Sounds => _sounds.Values; + + private readonly Dictionary _textures = new Dictionary(); + private readonly Dictionary _sounds = new Dictionary(); + + private Mappings.Mappings _mappings = new Mappings.Mappings(); + + public FileTableContainer(string name = "Table1") + { + Table = new Table(this, new TableData { Name = name }); + } + + public FileTableContainer(BinaryReader reader) + { + Table = new Table(this, new TableData(reader)); + } + + public void SetMappings(Mappings.Mappings mappings) + { + _mappings = mappings; + } + + /// + /// Adds a game item to the table. + /// + /// Game item instance + /// If set, re-computes the storage indices. Only needed when adding game items via the editor. + /// Game item type + /// Whe type of game item is unknown + public void Add(T item, bool updateStorageIndices = false) where T : IItem + { + var dict = GetItemDictionary(); + if (dict != null) { + AddItem(item.Name, item, dict, updateStorageIndices); + + } else { + var list = GetItemList(); + if (list != null) { + AddItem(item, list, updateStorageIndices); + + } else { + throw new ArgumentException("Unknown item type " + typeof(T) + "."); + } + } + } + + private void AddItem(string name, TItem item, IDictionary d, bool updateStorageIndices) where TItem : IItem + { + if (updateStorageIndices) { + item.StorageIndex = ItemDatas.Count(); + Table.Data.NumGameItems = item.StorageIndex + 1; + } + d[name] = item; + } + + private void AddItem(TItem item, ICollection d, bool updateStorageIndices) where TItem : IItem + { + if (updateStorageIndices) { + item.StorageIndex = ItemDatas.Count(); + } + d.Add(item); + } + + /// + /// Replaces all game items of a list with new game items. + /// + /// + /// + /// This only applied to Decals, because they are the only game items + /// that don't have a name. + /// + /// New list of game items + /// Game item type (only Decals) + /// If not decals + public void ReplaceAll(IEnumerable items) where T : IItem + { + var list = GetItemList(); + if (list == null) { + throw new ArgumentException("Cannot set all " + typeof(T) + "s (only Decals so far)."); + } + list.Clear(); + list.AddRange(items); + } + + /// + /// The API to load the table from a file. + /// + /// Path to the VPX file + /// If false, game items are not loaded. Useful when loading them on multiple threads. + /// The parsed table + public static FileTableContainer Load(string filename, bool loadGameItems = true) + { + return TableLoader.Load(filename, loadGameItems); + } + + + public override Material GetMaterial(string name) + { + if (Table.Data.Materials == null || name == null) { + return null; + } + + // ReSharper disable once LoopCanBeConvertedToQuery + foreach (var t in Table.Data.Materials) { + if (t.Name == name) { + return t; + } + } + + return null; + } + + public override Texture GetTexture(string name) + { + var tex = name == null || !_textures.ContainsKey(name.ToLower()) + ? null + : _textures[name.ToLower()]; + return tex; + } + + public int AddTexture(Texture texture) + { + _textures[texture.Name.ToLower()] = texture; + return _textures.Count; + } + + public Sound.Sound GetSound(string name) + { + var snd = name == null || !_sounds.ContainsKey(name.ToLower()) + ? null + : _sounds[name.ToLower()]; + return snd; + } + + public void AddSound(Sound.Sound sound) + { + _sounds[sound.Name.ToLower()] = sound; + } + } +} + diff --git a/VisualPinball.Engine/Math/Matrix2D.cs.meta b/VisualPinball.Engine/VPT/Table/FileTableContainer.cs.meta similarity index 83% rename from VisualPinball.Engine/Math/Matrix2D.cs.meta rename to VisualPinball.Engine/VPT/Table/FileTableContainer.cs.meta index 77ee453d3..d5206f3e7 100644 --- a/VisualPinball.Engine/Math/Matrix2D.cs.meta +++ b/VisualPinball.Engine/VPT/Table/FileTableContainer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a6c3cdb22cdfa774d96397e560bebf72 +guid: 653a1da4b61678346b9f2efbc4db7839 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/VisualPinball.Engine/VPT/Table/Table.cs b/VisualPinball.Engine/VPT/Table/Table.cs index 64e1b5ae7..f9eda88ef 100644 --- a/VisualPinball.Engine/VPT/Table/Table.cs +++ b/VisualPinball.Engine/VPT/Table/Table.cs @@ -14,11 +14,6 @@ // 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 System.IO; -using System.Linq; -using NLog; using VisualPinball.Engine.Game; using VisualPinball.Engine.Math; @@ -36,13 +31,6 @@ public class Table : Item, IRenderable public override string ItemGroupName { get; } = "Playfield"; public override ItemType ItemType { get; } = ItemType.Table; - public Vertex3D Position { get => new Vertex3D(0, 0, 0); set { } } - public float RotationY { get => 0; set { } } - - public CustomInfoTags CustomInfoTags { get; set; } - public int FileVersion { get; set; } - public byte[] FileHash { get; set; } - public float Width => Data.Right - Data.Left; public float Height => Data.Bottom - Data.Top; @@ -53,412 +41,59 @@ public class Table : Item, IRenderable public bool HasMeshAsPlayfield => _meshGenerator.HasMeshAsPlayfield; - public readonly Dictionary TableInfo = new Dictionary(); - public ITableResourceContainer Textures = new DefaultTableResourceContainer(); - public ITableResourceContainer Sounds = new DefaultTableResourceContainer(); - public readonly Dictionary Collections = new Dictionary(); - public Mappings.Mappings Mappings = new Mappings.Mappings(); - - #region GameItems - - private readonly Dictionary _bumpers = new Dictionary(); - private readonly List _decals = new List(); - private readonly Dictionary _dispReels = new Dictionary(); - private readonly Dictionary _flippers = new Dictionary(); - private readonly Dictionary _gates = new Dictionary(); - private readonly Dictionary _hitTargets = new Dictionary(); - private readonly Dictionary _kickers = new Dictionary(); - private readonly Dictionary _lights = new Dictionary(); - private readonly Dictionary _lightSeqs = new Dictionary(); - private readonly Dictionary _plungers = new Dictionary(); - private readonly Dictionary _flashers = new Dictionary(); - private readonly Dictionary _primitives = new Dictionary(); - private readonly Dictionary _ramps = new Dictionary(); - private readonly Dictionary _rubbers = new Dictionary(); - private readonly Dictionary _spinners = new Dictionary(); - private readonly Dictionary _surfaces = new Dictionary(); - private readonly Dictionary _textBoxes = new Dictionary(); - private readonly Dictionary _timers = new Dictionary(); - private readonly Dictionary _triggers = new Dictionary(); - private readonly Dictionary _troughs = new Dictionary(); - - public Bumper.Bumper Bumper(string name) => _bumpers[name]; - public Decal.Decal Decal(int i) => _decals[i]; - public DispReel.DispReel DispReel(string name) => _dispReels[name]; - public Flipper.Flipper Flipper(string name) => _flippers[name]; - public Gate.Gate Gate(string name) => _gates[name]; - public HitTarget.HitTarget HitTarget(string name) => _hitTargets[name]; - public Kicker.Kicker Kicker(string name) => _kickers[name]; - public Light.Light Light(string name) => _lights[name]; - public LightSeq.LightSeq LightSeq(string name) => _lightSeqs[name]; - public Plunger.Plunger Plunger(string name = null) => name == null ? _plungers.Values.FirstOrDefault() : _plungers[name]; - public Flasher.Flasher Flasher(string name) => _flashers[name]; - public Primitive.Primitive Primitive(string name) => _primitives[name]; - public Ramp.Ramp Ramp(string name) => _ramps[name]; - public Rubber.Rubber Rubber(string name) => _rubbers[name]; - public Spinner.Spinner Spinner(string name) => _spinners[name]; - public Surface.Surface Surface(string name) => _surfaces[name]; - public TextBox.TextBox TextBox(string name) => _textBoxes[name]; - public Timer.Timer Timer(string name) => _timers[name]; - public Trigger.Trigger Trigger(string name) => _triggers[name]; - public Trough.Trough Trough(string name) => _troughs[name]; - - public IEnumerable Renderables => new IRenderable[] { this } - .Concat(_bumpers.Values) - .Concat(_flippers.Values) - .Concat(_gates.Values) - .Concat(_hitTargets.Values) - .Concat(_kickers.Values) - .Concat(_lights.Values) - .Concat(_plungers.Values) - .Concat(_primitives.Values) - .Concat(_ramps.Values) - .Concat(_rubbers.Values) - .Concat(_spinners.Values) - .Concat(_surfaces.Values) - .Concat(_triggers.Values); - - /// - /// Game items that need to be converted but aren't rendered. - /// - public IEnumerable NonRenderables => new IItem[0] - .Concat(_troughs.Values); - - public IEnumerable GameItems => new IItem[] { } - .Concat(_bumpers.Values) - .Concat(_decals.Select(i => i)) - .Concat(_dispReels.Values) - .Concat(_flippers.Values) - .Concat(_flashers.Values) - .Concat(_gates.Values) - .Concat(_hitTargets.Values) - .Concat(_kickers.Values) - .Concat(_lights.Values) - .Concat(_lightSeqs.Values) - .Concat(_plungers.Values) - .Concat(_primitives.Values) - .Concat(_ramps.Values) - .Concat(_rubbers.Values) - .Concat(_spinners.Values) - .Concat(_surfaces.Values) - .Concat(_textBoxes.Values) - .Concat(_timers.Values) - .Concat(_triggers.Values) - .Concat(_troughs.Values); - - public IEnumerable ItemDatas => new ItemData[] { } - .Concat(_bumpers.Values.Select(i => i.Data)) - .Concat(_decals.Select(i => i.Data)) - .Concat(_dispReels.Values.Select(i => i.Data)) - .Concat(_flippers.Values.Select(i => i.Data)) - .Concat(_flashers.Values.Select(i => i.Data)) - .Concat(_gates.Values.Select(i => i.Data)) - .Concat(_hitTargets.Values.Select(i => i.Data)) - .Concat(_kickers.Values.Select(i => i.Data)) - .Concat(_lights.Values.Select(i => i.Data)) - .Concat(_lightSeqs.Values.Select(i => i.Data)) - .Concat(_plungers.Values.Select(i => i.Data)) - .Concat(_primitives.Values.Select(i => i.Data)) - .Concat(_ramps.Values.Select(i => i.Data)) - .Concat(_rubbers.Values.Select(i => i.Data)) - .Concat(_spinners.Values.Select(i => i.Data)) - .Concat(_surfaces.Values.Select(i => i.Data)) - .Concat(_textBoxes.Values.Select(i => i.Data)) - .Concat(_timers.Values.Select(i => i.Data)) - .Concat(_triggers.Values.Select(i => i.Data)) - .Concat(_troughs.Values.Select(i => i.Data)); - - public IEnumerable Switchables => new ISwitchable[0] - .Concat(_bumpers.Values) - .Concat(_flippers.Values) - .Concat(_gates.Values) - .Concat(_hitTargets.Values) - .Concat(_kickers.Values) - .Concat(_spinners.Values) - .Concat(_triggers.Values); - - public IEnumerable SwitchableDevices => new ISwitchableDevice[0] - .Concat(_troughs.Values); - - public IEnumerable Coilables => new ICoilable[0] - .Concat(_bumpers.Values) - .Concat(_flippers.Values) - .Concat(_kickers.Values); - - public IEnumerable CoilableDevices => new ICoilableDevice[0] - .Concat(_troughs.Values) - .Concat(_plungers.Values); - - public IEnumerable Lightables => new ILightable[0] - .Concat(_lights.Values) - .Concat(_flashers.Values); - - private void AddItem(string name, TItem item, IDictionary d, bool updateStorageIndices) where TItem : IItem - { - if (updateStorageIndices) { - item.StorageIndex = ItemDatas.Count(); - Data.NumGameItems = item.StorageIndex + 1; - } - d[name] = item; - } + public Vertex3D Position { get => new Vertex3D(0, 0, 0); set { } } + public float RotationY { get => 0; set { } } - private void AddItem(TItem item, ICollection d, bool updateStorageIndices) where TItem : IItem - { - if (updateStorageIndices) { - item.StorageIndex = ItemDatas.Count(); - } - d.Add(item); - } + private readonly TableContainer _tableContainer; + private readonly TableMeshGenerator _meshGenerator; - private Dictionary GetItemDictionary() where T : IItem + public Table(TableContainer tableContainer, TableData data) : base(data) { - if (typeof(T) == typeof(Bumper.Bumper)) { - return _bumpers as Dictionary; - } - if (typeof(T) == typeof(DispReel.DispReel)) { - return _dispReels as Dictionary; - } - - if (typeof(T) == typeof(Flipper.Flipper)) { - return _flippers as Dictionary; - } - - if (typeof(T) == typeof(Gate.Gate)) { - return _gates as Dictionary; - } - - if (typeof(T) == typeof(HitTarget.HitTarget)) { - return _hitTargets as Dictionary; - } - - if (typeof(T) == typeof(Kicker.Kicker)) { - return _kickers as Dictionary; - } - - if (typeof(T) == typeof(Light.Light)) { - return _lights as Dictionary; - } - - if (typeof(T) == typeof(LightSeq.LightSeq)) { - return _lightSeqs as Dictionary; - } - - if (typeof(T) == typeof(Plunger.Plunger)) { - return _plungers as Dictionary; - } - - if (typeof(T) == typeof(Flasher.Flasher)) { - return _flashers as Dictionary; - } - - if (typeof(T) == typeof(Primitive.Primitive)) { - return _primitives as Dictionary; - } - - if (typeof(T) == typeof(Ramp.Ramp)) { - return _ramps as Dictionary; - } - - if (typeof(T) == typeof(Rubber.Rubber)) { - return _rubbers as Dictionary; - } - - if (typeof(T) == typeof(Spinner.Spinner)) { - return _spinners as Dictionary; - } - - if (typeof(T) == typeof(Surface.Surface)) { - return _surfaces as Dictionary; - } - - if (typeof(T) == typeof(TextBox.TextBox)) { - return _textBoxes as Dictionary; - } - - if (typeof(T) == typeof(Timer.Timer)) { - return _timers as Dictionary; - } - - if (typeof(T) == typeof(Trigger.Trigger)) { - return _triggers as Dictionary; - } - - if (typeof(T) == typeof(Trough.Trough)) { - return _troughs as Dictionary; - } - - return null; - } - - private List GetItemList() { - if (typeof(T) == typeof(Decal.Decal)) { - return _decals as List; - } - - return null; + _tableContainer = tableContainer; + _meshGenerator = new TableMeshGenerator(_tableContainer); } - #endregion - - /// - /// Adds a game item to the table. - /// - /// Game item instance - /// If set, re-computes the storage indices. Only needed when adding game items via the editor. - /// Game item type - /// Whe type of game item is unknown - public void Add(T item, bool updateStorageIndices = false) where T : IItem + public float GetScaleZ() { - var dict = GetItemDictionary(); - if (dict != null) { - AddItem(item.Name, item, dict, updateStorageIndices); - - } else { - var list = GetItemList(); - if (list != null) { - AddItem(item, list, updateStorageIndices); - - } else { - throw new ArgumentException("Unknown item type " + typeof(T) + "."); - } - } + return Data.BgScaleZ?[Data.BgCurrentSet] ?? 1.0f; } - /// - /// Replaces all game items of a list with new game items. - /// - /// - /// - /// This only applied to Decals, because they are the only game items - /// that don't have a name. - /// - /// New list of game items - /// Game item type (only Decals) - /// If not decals - public void ReplaceAll(IEnumerable items) where T : IItem + public float GetSurfaceHeight(string surfaceName, float x, float y) { - var list = GetItemList(); - if (list == null) { - throw new ArgumentException("Cannot set all " + typeof(T) + "s (only Decals so far)."); + if (string.IsNullOrEmpty(surfaceName)) { + return TableHeight; } - list.Clear(); - list.AddRange(items); - } - /// - /// Checks whether a game item of a given type exists. - /// - /// Name of the game item - /// Type of the game item - /// True if the game item exists, false otherwise - public bool Has(string name) where T : IItem => GetItemDictionary().ContainsKey(name); - - /// - /// Returns all game items of a given type. - /// - /// Game item type - /// All game items stored in the table - /// If invalid game type - public TItem[] GetAll() where TItem : IItem - { - var dict = GetItemDictionary(); - if (dict != null) { - return dict.Values.ToArray(); + if (_tableContainer.Has(surfaceName)) { + return TableHeight + _tableContainer.Get(surfaceName).Data.HeightTop; } - var list = GetItemList(); - if (list != null) { - return list.ToArray(); - } - throw new ArgumentException("Unknown item type " + typeof(TItem) + "."); - } - - /// - /// Computes a new name for a game item. - /// - /// Prefix - /// Type of the game item - /// New name, a concatenation of the prefix and the next free index - public string GetNewName(string prefix) where T : IItem - { - var n = 0; - var dict = GetItemDictionary(); - do { - var elementName = $"{prefix}{++n}"; - if (!dict.ContainsKey(elementName)) { - return elementName; - } - } while (true); - } - /// - /// Removes a game item from the table. - /// - /// Name of the game item - /// Type of the game item - public void Remove(string name) where T : IItem - { - var dict = GetItemDictionary(); - if (!dict.ContainsKey(name)) { - return; - } - var removedStorageIndex = dict[name].StorageIndex; - var gameItems = ItemDatas; - foreach (var gameItem in gameItems) { - if (gameItem.StorageIndex > removedStorageIndex) { - gameItem.StorageIndex--; - } + if (_tableContainer.Has(surfaceName)) { + return TableHeight + _tableContainer.Get(surfaceName).GetSurfaceHeight(x, y, this); } - Data.NumGameItems = gameItems.Count() - 1; - dict.Remove(name); + // Logger.Warn( + // "[Table.getSurfaceHeight] Unknown surface {0}.\nAvailable surfaces: [ {1} ]\nAvailable ramps: [ {2} ]", + // surfaceName, + // string.Join(", ", _surfaces.Keys), + // string.Join(", ", _ramps.Keys) + // ); + return TableHeight; } - public TData[] GetAllData() where TItem : Item where TData : ItemData + public void SetupPlayfieldMesh() { - var dict = GetItemDictionary(); - if (dict != null) { - return dict.Values.Select(d => d.Data).ToArray(); + if (_tableContainer.Has("playfield_mesh")) { + _meshGenerator.SetFromPrimitive(_tableContainer.Get("playfield_mesh")); + _tableContainer.Remove("playfield_mesh"); } - var list = GetItemList(); - if (list != null) { - return list.Select(d => d.Data).ToArray(); - } - throw new ArgumentException("Unknown item type " + typeof(TItem) + "."); - } - - #region Table Info - public string InfoAuthorEmail => TableInfo.ContainsKey("AuthorEmail") ? TableInfo["AuthorEmail"] : null; - public string InfoAuthorName => TableInfo.ContainsKey("AuthorName") ? TableInfo["AuthorName"] : null; - public string InfoAuthorWebsite => TableInfo.ContainsKey("AuthorWebSite") ? TableInfo["AuthorWebSite"] : null; - public string InfoReleaseDate => TableInfo.ContainsKey("ReleaseDate") ? TableInfo["ReleaseDate"] : null; - public string InfoBlurb => TableInfo.ContainsKey("TableBlurb") ? TableInfo["TableBlurb"] : null; - public string InfoDescription => TableInfo.ContainsKey("TableDescription") ? TableInfo["TableDescription"] : null; - public string InfoName => TableInfo.ContainsKey("TableName") ? TableInfo["TableName"] : null; - public string InfoRules => TableInfo.ContainsKey("TableRules") ? TableInfo["TableRules"] : null; - public string InfoVersion => TableInfo.ContainsKey("TableVersion") ? TableInfo["TableVersion"] : null; - - #endregion - - private readonly TableMeshGenerator _meshGenerator; - - /// - /// The API to load the table from a file. - /// - /// Path to the VPX file - /// If false, game items are not loaded. Useful when loading them on multiple threads. - /// The parsed table - public static Table Load(string filename, bool loadGameItems = true) - { - return TableLoader.Load(filename, loadGameItems); } - public Table(TableData data) : base(data) + public int GetDetailLevel() { - _meshGenerator = new TableMeshGenerator(this); + return 10; // TODO } - public Table(BinaryReader reader) : this(new TableData(reader)) { } - #region IRenderable Matrix3D IRenderable.TransformationMatrix(Table table, Origin origin) => Matrix3D.Identity; @@ -475,91 +110,13 @@ public RenderObjectGroup GetRenderObjects(Table table, Origin origin = Origin.Gl #endregion - public bool IsCollidable => true; - public bool HasTrough => _troughs.Count > 0; - - public void Save(string fileName) - { - new TableWriter(this).WriteTable(fileName); - Logger.Info("File successfully saved to {0}.", fileName); - } - - public Material GetMaterial(string name) - { - if (Data.Materials == null || name == null) { - return null; - } - - // ReSharper disable once LoopCanBeConvertedToQuery - foreach (var t in Data.Materials) { - if (t.Name == name) { - return t; - } - } - - return null; - } - - public void SetTextureContainer(ITableResourceContainer container) - { - Textures = container; - } - - public Texture GetTexture(string name) - { - var tex = name == null - ? null - : Textures[name.ToLower()]; - return tex; - } - - public void SetSoundContainer(ITableResourceContainer container) - { - Sounds = container; - } - - public float GetScaleZ() - { - return Data.BgScaleZ?[Data.BgCurrentSet] ?? 1.0f; - } - - public void SetupPlayfieldMesh() - { - if (_primitives.ContainsKey("playfield_mesh")) { - _meshGenerator.SetFromPrimitive(_primitives["playfield_mesh"]); - _primitives.Remove("playfield_mesh"); - } - } - - public float GetSurfaceHeight(string surfaceName, float x, float y) - { - if (string.IsNullOrEmpty(surfaceName)) { - return TableHeight; - } - - if (_surfaces.ContainsKey(surfaceName)) { - return TableHeight + _surfaces[surfaceName].Data.HeightTop; - } - - if (_ramps.ContainsKey(surfaceName)) { - return TableHeight + _ramps[surfaceName].GetSurfaceHeight(x, y, this); - } - - // Logger.Warn( - // "[Table.getSurfaceHeight] Unknown surface {0}.\nAvailable surfaces: [ {1} ]\nAvailable ramps: [ {2} ]", - // surfaceName, - // string.Join(", ", _surfaces.Keys), - // string.Join(", ", _ramps.Keys) - // ); - return TableHeight; - } + #region Container Shortcuts - public int GetDetailLevel() - { - return 10; // TODO - } + public Material GetMaterial(string name) => _tableContainer.GetMaterial(name); + public Texture GetTexture(string dataImage) => _tableContainer.GetTexture(dataImage); + public string GetNewName(string name) where T : IItem => _tableContainer.GetNewName(name); - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + #endregion } } diff --git a/VisualPinball.Engine/VPT/Table/TableBuilder.cs b/VisualPinball.Engine/VPT/Table/TableBuilder.cs index 814406a2a..917f89b34 100644 --- a/VisualPinball.Engine/VPT/Table/TableBuilder.cs +++ b/VisualPinball.Engine/VPT/Table/TableBuilder.cs @@ -19,7 +19,6 @@ using VisualPinball.Engine.VPT.Bumper; using VisualPinball.Engine.VPT.Flipper; using VisualPinball.Engine.VPT.Light; -using VisualPinball.Engine.VPT.Rubber; using VisualPinball.Engine.VPT.Trough; namespace VisualPinball.Engine.VPT.Table @@ -29,16 +28,16 @@ public class TableBuilder private static int _tableItem; private int _gameItem = 0; - private readonly Table _table = new Table(new TableData()); + private readonly FileTableContainer _tableContainer = new FileTableContainer(); public TableBuilder() { - _table.Data.Name = $"Table${_tableItem++}"; + _tableContainer.Table.Data.Name = $"Table${_tableItem++}"; } public TableBuilder WithTableScript(string vbs) { - _table.Data.Code = vbs; + _tableContainer.Table.Data.Code = vbs; return this; } @@ -49,25 +48,23 @@ public TableBuilder AddBumper(string name) Center = new Vertex2D(500, 500) }; - _table.Add(new Bumper.Bumper(data)); + _tableContainer.Add(new Bumper.Bumper(data)); return this; } public TableBuilder AddMaterial(Material material) { - var mats = _table.Data.Materials.ToList(); + var mats = _tableContainer.Table.Data.Materials.ToList(); mats.Add(material); - _table.Data.Materials = mats.ToArray(); - _table.Data.NumMaterials = mats.Count; + _tableContainer.Table.Data.Materials = mats.ToArray(); + _tableContainer.Table.Data.NumMaterials = mats.Count; return this; } public TableBuilder AddTexture(string name) { - _table.Textures.Add(new Texture(name)); - _table.Data.NumTextures = _table.Textures.Count; - + _tableContainer.Table.Data.NumTextures = _tableContainer.AddTexture(new Texture(name)); return this; } @@ -77,32 +74,32 @@ public TableBuilder AddFlipper(string name) Name = name, Center = new Vertex2D(500, 500) }; - _table.Add(new Flipper.Flipper(data)); + _tableContainer.Add(new Flipper.Flipper(data)); return this; } public TableBuilder AddTrough(string name) { - var data = new TroughData($"GameItem{_gameItem++}") { + var data = new TroughData($"VpeGameItem{_gameItem++}") { Name = name }; - _table.Add(new Trough.Trough(data)); + _tableContainer.Add(new Trough.Trough(data)); return this; } public TableBuilder AddLight(string name) { - _table.Add(new Light.Light(new LightData(name, 500, 500))); + _tableContainer.Add(new Light.Light(new LightData(name, 500, 500))); return this; } - public Table Build(string name = null) + public FileTableContainer Build(string name = null) { if (name != null) { - _table.Data.Name = name; + _tableContainer.Table.Data.Name = name; } - return _table; + return _tableContainer; } } } diff --git a/VisualPinball.Engine/VPT/Table/TableContainer.cs b/VisualPinball.Engine/VPT/Table/TableContainer.cs new file mode 100644 index 000000000..15c0b05e6 --- /dev/null +++ b/VisualPinball.Engine/VPT/Table/TableContainer.cs @@ -0,0 +1,402 @@ +// 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 System.Linq; +using NLog; +using VisualPinball.Engine.Game; +using VisualPinball.Engine.VPT.Collection; + +namespace VisualPinball.Engine.VPT.Table +{ + public abstract class TableContainer + { + public abstract Table Table { get; } + public abstract Dictionary TableInfo { get; } + public abstract List Collections { get; } + public abstract Mappings.Mappings Mappings { get; } + public abstract CustomInfoTags CustomInfoTags { get; } + public abstract IEnumerable Textures { get; } + public abstract IEnumerable Sounds { get; } + + public abstract Material GetMaterial(string name); + + /// + /// Returns a texture for a given name. + /// + /// + /// + /// This is mainly used by the mesh generators that create a material. + /// + /// + /// Name of the texture, case insensitive. + /// Texture or null. + public abstract Texture GetTexture(string name); + + public int FileVersion { get; set; } + public byte[] FileHash { get; set; } + + public bool HasTrough => _troughs.Count > 0; + public int NumTextures => Table.Data.NumTextures; + public int NumGameItems => Table.Data.NumGameItems; + public int NumSounds => Table.Data.NumSounds; + public int NumCollections => Table.Data.NumCollections; + public int NumVpeGameItems => Table.Data.NumVpeGameItems; + + #region GameItems + + protected readonly Dictionary _bumpers = new Dictionary(); + protected readonly List _decals = new List(); + protected readonly Dictionary _dispReels = new Dictionary(); + protected readonly Dictionary _flashers = new Dictionary(); + protected readonly Dictionary _flippers = new Dictionary(); + protected readonly Dictionary _gates = new Dictionary(); + protected readonly Dictionary _hitTargets = new Dictionary(); + protected readonly Dictionary _kickers = new Dictionary(); + protected readonly Dictionary _lights = new Dictionary(); + protected readonly Dictionary _lightSeqs = new Dictionary(); + protected readonly Dictionary _plungers = new Dictionary(); + protected readonly Dictionary _primitives = new Dictionary(); + protected readonly Dictionary _ramps = new Dictionary(); + protected readonly Dictionary _rubbers = new Dictionary(); + protected readonly Dictionary _spinners = new Dictionary(); + protected readonly Dictionary _surfaces = new Dictionary(); + protected readonly Dictionary _textBoxes = new Dictionary(); + protected readonly Dictionary _timers = new Dictionary(); + protected readonly Dictionary _triggers = new Dictionary(); + protected readonly Dictionary _troughs = new Dictionary(); + + protected virtual void Clear() + { + _bumpers.Clear(); + _decals.Clear(); + _dispReels.Clear(); + _flashers.Clear(); + _flippers.Clear(); + _gates.Clear(); + _hitTargets.Clear(); + _kickers.Clear(); + _lights.Clear(); + _lightSeqs.Clear(); + _plungers.Clear(); + _primitives.Clear(); + _ramps.Clear(); + _rubbers.Clear(); + _spinners.Clear(); + _surfaces.Clear(); + _textBoxes.Clear(); + _timers.Clear(); + _triggers.Clear(); + _troughs.Clear(); + } + + public Bumper.Bumper Bumper(string name) => _bumpers[name]; + public Decal.Decal Decal(int i) => _decals[i]; + public DispReel.DispReel DispReel(string name) => _dispReels[name]; + public Flipper.Flipper Flipper(string name) => _flippers[name]; + public Gate.Gate Gate(string name) => _gates[name]; + public HitTarget.HitTarget HitTarget(string name) => _hitTargets[name]; + public Kicker.Kicker Kicker(string name) => _kickers[name]; + public Light.Light Light(string name) => _lights[name]; + public LightSeq.LightSeq LightSeq(string name) => _lightSeqs[name]; + public Plunger.Plunger Plunger(string name = null) => name == null ? _plungers.Values.FirstOrDefault() : _plungers[name]; + public Flasher.Flasher Flasher(string name) => _flashers[name]; + public Primitive.Primitive Primitive(string name) => _primitives[name]; + public Ramp.Ramp Ramp(string name) => _ramps[name]; + public Rubber.Rubber Rubber(string name) => _rubbers[name]; + public Spinner.Spinner Spinner(string name) => _spinners[name]; + public Surface.Surface Surface(string name) => _surfaces[name]; + public TextBox.TextBox TextBox(string name) => _textBoxes[name]; + public Timer.Timer Timer(string name) => _timers[name]; + public Trigger.Trigger Trigger(string name) => _triggers[name]; + public Trough.Trough Trough(string name) => _troughs[name]; + + public IEnumerable Renderables => new IRenderable[] { Table } + .Concat(_bumpers.Values) + .Concat(_flippers.Values) + .Concat(_gates.Values) + .Concat(_hitTargets.Values) + .Concat(_kickers.Values) + .Concat(_lights.Values) + .Concat(_plungers.Values) + .Concat(_primitives.Values) + .Concat(_ramps.Values) + .Concat(_rubbers.Values) + .Concat(_spinners.Values) + .Concat(_surfaces.Values) + .Concat(_triggers.Values); + + /// + /// Game items that need to be converted but aren't rendered. + /// + public IEnumerable NonRenderables => new IItem[0] + .Concat(_troughs.Values); + + public IEnumerable GameItems => new IItem[] { } + .Concat(_bumpers.Values) + .Concat(_decals.Select(i => i)) + .Concat(_dispReels.Values) + .Concat(_flippers.Values) + .Concat(_flashers.Values) + .Concat(_gates.Values) + .Concat(_hitTargets.Values) + .Concat(_kickers.Values) + .Concat(_lights.Values) + .Concat(_lightSeqs.Values) + .Concat(_plungers.Values) + .Concat(_primitives.Values) + .Concat(_ramps.Values) + .Concat(_rubbers.Values) + .Concat(_spinners.Values) + .Concat(_surfaces.Values) + .Concat(_textBoxes.Values) + .Concat(_timers.Values) + .Concat(_triggers.Values) + .Concat(_troughs.Values); + + public IEnumerable ItemDatas => new ItemData[] { } + .Concat(_bumpers.Values.Select(i => i.Data)) + .Concat(_decals.Select(i => i.Data)) + .Concat(_dispReels.Values.Select(i => i.Data)) + .Concat(_flippers.Values.Select(i => i.Data)) + .Concat(_flashers.Values.Select(i => i.Data)) + .Concat(_gates.Values.Select(i => i.Data)) + .Concat(_hitTargets.Values.Select(i => i.Data)) + .Concat(_kickers.Values.Select(i => i.Data)) + .Concat(_lights.Values.Select(i => i.Data)) + .Concat(_lightSeqs.Values.Select(i => i.Data)) + .Concat(_plungers.Values.Select(i => i.Data)) + .Concat(_primitives.Values.Select(i => i.Data)) + .Concat(_ramps.Values.Select(i => i.Data)) + .Concat(_rubbers.Values.Select(i => i.Data)) + .Concat(_spinners.Values.Select(i => i.Data)) + .Concat(_surfaces.Values.Select(i => i.Data)) + .Concat(_textBoxes.Values.Select(i => i.Data)) + .Concat(_timers.Values.Select(i => i.Data)) + .Concat(_triggers.Values.Select(i => i.Data)); + + + public IEnumerable VpeItemDatas => new ItemData[] { } + .Concat(_troughs.Values.Select(i => i.Data)); + + public IEnumerable Switchables => new ISwitchable[0] + .Concat(_bumpers.Values) + .Concat(_flippers.Values) + .Concat(_gates.Values) + .Concat(_hitTargets.Values) + .Concat(_kickers.Values) + .Concat(_spinners.Values) + .Concat(_triggers.Values); + + public IEnumerable SwitchableDevices => new ISwitchableDevice[0] + .Concat(_troughs.Values); + + public IEnumerable Coilables => new ICoilable[0] + .Concat(_bumpers.Values) + .Concat(_flippers.Values) + .Concat(_kickers.Values); + + public IEnumerable CoilableDevices => new ICoilableDevice[0] + .Concat(_troughs.Values) + .Concat(_plungers.Values); + + public IEnumerable Lightables => new ILightable[0] + .Concat(_lights.Values) + .Concat(_flashers.Values); + + protected Dictionary GetItemDictionary() where T : IItem + { + return GetItemDictionary(typeof(T)); + } + + protected Dictionary GetItemDictionary(Type t) where T : IItem + { + if (t == typeof(Bumper.Bumper)) { + return _bumpers as Dictionary; + } + if (t == typeof(DispReel.DispReel)) { + return _dispReels as Dictionary; + } + + if (t == typeof(Flipper.Flipper)) { + return _flippers as Dictionary; + } + + if (t == typeof(Gate.Gate)) { + return _gates as Dictionary; + } + + if (t == typeof(HitTarget.HitTarget)) { + return _hitTargets as Dictionary; + } + + if (t == typeof(Kicker.Kicker)) { + return _kickers as Dictionary; + } + + if (t == typeof(Light.Light)) { + return _lights as Dictionary; + } + + if (t == typeof(LightSeq.LightSeq)) { + return _lightSeqs as Dictionary; + } + + if (t == typeof(Plunger.Plunger)) { + return _plungers as Dictionary; + } + + if (t == typeof(Flasher.Flasher)) { + return _flashers as Dictionary; + } + + if (t == typeof(Primitive.Primitive)) { + return _primitives as Dictionary; + } + + if (t == typeof(Ramp.Ramp)) { + return _ramps as Dictionary; + } + + if (t == typeof(Rubber.Rubber)) { + return _rubbers as Dictionary; + } + + if (t == typeof(Spinner.Spinner)) { + return _spinners as Dictionary; + } + + if (t == typeof(Surface.Surface)) { + return _surfaces as Dictionary; + } + + if (t == typeof(TextBox.TextBox)) { + return _textBoxes as Dictionary; + } + + if (t == typeof(Timer.Timer)) { + return _timers as Dictionary; + } + + if (t == typeof(Trigger.Trigger)) { + return _triggers as Dictionary; + } + + if (t == typeof(Trough.Trough)) { + return _troughs as Dictionary; + } + + return null; + } + + protected List GetItemList() { + if (typeof(T) == typeof(Decal.Decal)) { + return _decals as List; + } + + return null; + } + + #endregion + + /// + /// Checks whether a game item of a given type exists. + /// + /// Name of the game item + /// Type of the game item + /// True if the game item exists, false otherwise + public bool Has(string name) where T : IItem => GetItemDictionary().ContainsKey(name); + public T Get(string name) where T : IItem => GetItemDictionary()[name]; + + public TData[] GetAllData() where TItem : Item where TData : ItemData + { + var dict = GetItemDictionary(); + if (dict != null) { + return dict.Values.Select(d => d.Data).ToArray(); + } + var list = GetItemList(); + if (list != null) { + return list.Select(d => d.Data).ToArray(); + } + throw new ArgumentException("Unknown item type " + typeof(TItem) + "."); + } + + /// + /// Removes a game item from the table. + /// + /// Name of the game item + /// Type of the game item + public void Remove(string name) where T : IItem + { + var dict = GetItemDictionary(); + if (!dict.ContainsKey(name)) { + return; + } + var removedStorageIndex = dict[name].StorageIndex; + var gameItems = ItemDatas; + foreach (var gameItem in gameItems) { + if (gameItem.StorageIndex > removedStorageIndex) { + gameItem.StorageIndex--; + } + } + + Table.Data.NumGameItems = gameItems.Count() - 1; + dict.Remove(name); + } + + /// + /// Computes a new name for a game item. + /// + /// Prefix + /// Type of the game item + /// New name, a concatenation of the prefix and the next free index + public string GetNewName(string prefix) where T : IItem + { + var n = 0; + var dict = GetItemDictionary(); + do { + var elementName = $"{prefix}{++n}"; + if (!dict.ContainsKey(elementName)) { + return elementName; + } + } while (true); + } + + #region Table Info + public string InfoAuthorEmail => TableInfo.ContainsKey("AuthorEmail") ? TableInfo["AuthorEmail"] : null; + public string InfoAuthorName => TableInfo.ContainsKey("AuthorName") ? TableInfo["AuthorName"] : null; + public string InfoAuthorWebsite => TableInfo.ContainsKey("AuthorWebSite") ? TableInfo["AuthorWebSite"] : null; + public string InfoReleaseDate => TableInfo.ContainsKey("ReleaseDate") ? TableInfo["ReleaseDate"] : null; + public string InfoBlurb => TableInfo.ContainsKey("TableBlurb") ? TableInfo["TableBlurb"] : null; + public string InfoDescription => TableInfo.ContainsKey("TableDescription") ? TableInfo["TableDescription"] : null; + public string InfoName => TableInfo.ContainsKey("TableName") ? TableInfo["TableName"] : null; + public string InfoRules => TableInfo.ContainsKey("TableRules") ? TableInfo["TableRules"] : null; + public string InfoVersion => TableInfo.ContainsKey("TableVersion") ? TableInfo["TableVersion"] : null; + + #endregion + + public virtual void Save(string fileName) + { + new TableWriter(this).WriteTable(fileName); + Logger.Info("File successfully saved to {0}.", fileName); + } + + protected static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + } +} + diff --git a/VisualPinball.Engine/VPT/Table/DefaultTableResourceContainer.cs.meta b/VisualPinball.Engine/VPT/Table/TableContainer.cs.meta similarity index 83% rename from VisualPinball.Engine/VPT/Table/DefaultTableResourceContainer.cs.meta rename to VisualPinball.Engine/VPT/Table/TableContainer.cs.meta index 54a64cd58..80c41de2e 100644 --- a/VisualPinball.Engine/VPT/Table/DefaultTableResourceContainer.cs.meta +++ b/VisualPinball.Engine/VPT/Table/TableContainer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 226b1b4bd7359a149a03e72a18e82798 +guid: c7d83b4929403de4494db31a3c07108e MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/VisualPinball.Engine/VPT/Table/TableData.cs b/VisualPinball.Engine/VPT/Table/TableData.cs index 2ec23b937..e06074b2d 100644 --- a/VisualPinball.Engine/VPT/Table/TableData.cs +++ b/VisualPinball.Engine/VPT/Table/TableData.cs @@ -337,6 +337,10 @@ public uint Light0Emission { [BiffMaterials("PHMA", IsPhysics = true, Pos = 106)] public Material[] Materials = new Material[0]; + // vpe-specific + [BiffInt("SVPE", Pos = 1000, IsVpeEnhancement = true)] + public int NumVpeGameItems; + // other stuff public int BgCurrentSet = BackglassIndex.Desktop; @@ -441,7 +445,7 @@ public override void Write(TItem obj, BinaryWriter writer, HashWriter has private void ParseMaterial(TableData tableData, BinaryReader reader, int len) { if (len < tableData.NumMaterials * MaterialData.Size) { - throw new ArgumentOutOfRangeException($"Cannot parse {tableData.NumMaterials} of {tableData.NumMaterials * MaterialData.Size} bytes from a {len} bytes buffer."); + throw new ArgumentOutOfRangeException($"Cannot parse {tableData.NumMaterials} materials of {tableData.NumMaterials * MaterialData.Size} bytes from a {len} bytes buffer."); } var materials = new Material[tableData.NumMaterials]; for (var i = 0; i < tableData.NumMaterials; i++) { diff --git a/VisualPinball.Engine/VPT/Table/TableLoader.cs b/VisualPinball.Engine/VPT/Table/TableLoader.cs index 3c3d96fbc..9cd21de27 100644 --- a/VisualPinball.Engine/VPT/Table/TableLoader.cs +++ b/VisualPinball.Engine/VPT/Table/TableLoader.cs @@ -15,10 +15,12 @@ // along with this program. If not, see . using System; +using System.Collections.Generic; using System.IO; using NLog; using OpenMcdf; using VisualPinball.Engine.IO; +using VisualPinball.Engine.VPT.Collection; namespace VisualPinball.Engine.VPT.Table { @@ -29,7 +31,7 @@ public static class TableLoader { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static Table Load(string filename, bool loadGameItems = true) + public static FileTableContainer Load(string filename, bool loadGameItems = true) { var cf = new CompoundFile(filename); try { @@ -39,20 +41,21 @@ public static Table Load(string filename, bool loadGameItems = true) var fileVersion = BitConverter.ToInt32(gameStorage.GetStream("Version").GetData(), 0); using (var stream = new MemoryStream(gameData.GetData())) using (var reader = new BinaryReader(stream)) { - var table = new Table(reader); + var tableContainer = new FileTableContainer(reader); - LoadTableInfo(table, cf.RootStorage, gameStorage); + LoadTableInfo(tableContainer, cf.RootStorage, gameStorage); if (loadGameItems) { - LoadGameItems(table, gameStorage); + LoadGameItems(tableContainer, gameStorage, tableContainer.NumGameItems, "GameItem"); + LoadGameItems(tableContainer, gameStorage, tableContainer.NumVpeGameItems, "VpeGameItem"); } - LoadTextures(table, gameStorage); - LoadSounds(table, gameStorage, fileVersion); - LoadCollections(table, gameStorage); - LoadMappings(table, gameStorage); - LoadTableMeta(table, gameStorage); + LoadTextures(tableContainer, gameStorage); + LoadSounds(tableContainer, gameStorage, fileVersion); + LoadCollections(tableContainer, gameStorage); + LoadMappings(tableContainer, gameStorage); + LoadTableMeta(tableContainer, gameStorage); - table.SetupPlayfieldMesh(); - return table; + tableContainer.Table.SetupPlayfieldMesh(); + return tableContainer; } } finally { @@ -60,14 +63,14 @@ public static Table Load(string filename, bool loadGameItems = true) } } - public static byte[][] ReadGameItems(string fileName, int numGameItems) + public static IEnumerable ReadGameItems(string fileName, int numGameItems, string storagePrefix) { var gameItemData = new byte[numGameItems][]; var cf = new CompoundFile(fileName); try { var storage = cf.RootStorage.GetStorage("GameStg"); for (var i = 0; i < numGameItems; i++) { - var itemName = $"GameItem{i}"; + var itemName = $"{storagePrefix}{i}"; var itemStream = storage.GetStream(itemName); gameItemData[i] = itemStream.GetData(); } @@ -112,17 +115,17 @@ public static void LoadGameItem(byte[] itemData, int storageIndex, out ItemType case ItemType.TextBox: item = new TextBox.TextBox(reader, itemName); break; 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, itemName); break; + case ItemType.Trough: item = new Trough.Trough(reader, $"VpeGameItem{storageIndex}"); break; default: Logger.Info("Unhandled item type " + itemType); itemType = ItemType.Invalid; break; } } - private static void LoadGameItems(Table table, CFStorage storage) + private static void LoadGameItems(FileTableContainer tableContainer, CFStorage storage, int count, string storagePrefix) { - for (var i = 0; i < table.Data.NumGameItems; i++) { - var itemName = $"GameItem{i}"; + for (var i = 0; i < count; i++) { + var itemName = $"{storagePrefix}{i}"; storage.TryGetStream(itemName, out var itemStream); if (itemStream == null) { Logger.Warn("Could not find stream {0}, skipping.", itemName); @@ -147,110 +150,110 @@ private static void LoadGameItems(Table table, CFStorage storage) switch (itemType) { case ItemType.Bumper: { var item = new VisualPinball.Engine.VPT.Bumper.Bumper(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Decal: { - table.Add(new VisualPinball.Engine.VPT.Decal.Decal(reader, itemName)); + tableContainer.Add(new VisualPinball.Engine.VPT.Decal.Decal(reader, itemName)); break; } case ItemType.DispReel: { var item = new VisualPinball.Engine.VPT.DispReel.DispReel(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Flasher: { var item = new VisualPinball.Engine.VPT.Flasher.Flasher(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Flipper: { var item = new VisualPinball.Engine.VPT.Flipper.Flipper(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Gate: { var item = new VisualPinball.Engine.VPT.Gate.Gate(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.HitTarget: { var item = new VisualPinball.Engine.VPT.HitTarget.HitTarget(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Kicker: { var item = new VisualPinball.Engine.VPT.Kicker.Kicker(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Light: { var item = new VisualPinball.Engine.VPT.Light.Light(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.LightSeq: { var item = new VisualPinball.Engine.VPT.LightSeq.LightSeq(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Plunger: { var item = new VisualPinball.Engine.VPT.Plunger.Plunger(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Primitive: { var item = new Primitive.Primitive(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Ramp: { var item = new Ramp.Ramp(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Rubber: { var item = new Rubber.Rubber(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Spinner: { var item = new Spinner.Spinner(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Surface: { var item = new Surface.Surface(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.TextBox: { var item = new TextBox.TextBox(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Timer: { var item = new Timer.Timer(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Trigger: { var item = new Trigger.Trigger(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } case ItemType.Trough: { var item = new Trough.Trough(reader, itemName); - table.Add(item); + tableContainer.Add(item); break; } } } } - private static void LoadTextures(Table table, CFStorage storage) + private static void LoadTextures(FileTableContainer tableContainer, CFStorage storage) { - for (var i = 0; i < table.Data.NumTextures; i++) { + for (var i = 0; i < tableContainer.NumTextures; i++) { var textureName = $"Image{i}"; storage.TryGetStream(textureName, out var textureStream); if (textureStream == null) { @@ -266,14 +269,14 @@ private static void LoadTextures(Table table, CFStorage storage) using (var stream = new MemoryStream(textureData)) using (var reader = new BinaryReader(stream)) { var texture = new Texture(reader, textureName); - table.Textures.Add(texture); + tableContainer.AddTexture(texture); } } } - private static void LoadCollections(Table table, CFStorage storage) + private static void LoadCollections(FileTableContainer tableContainer, CFStorage storage) { - for (var i = 0; i < table.Data.NumCollections; i++) { + for (var i = 0; i < tableContainer.NumCollections; i++) { var collectionName = $"Collection{i}"; storage.TryGetStream(collectionName, out var collectionStream); if (collectionStream == null) { @@ -282,29 +285,27 @@ private static void LoadCollections(Table table, CFStorage storage) } using (var stream = new MemoryStream(collectionStream.GetData())) using (var reader = new BinaryReader(stream)) { - var collection = new Collection.Collection(reader, collectionName); - table.Collections[collection.Name.ToLower()] = collection; + tableContainer.Collections.Add(new CollectionData(reader, collectionName)); } } } - private static void LoadMappings(Table table, CFStorage gameStorage) + private static void LoadMappings(FileTableContainer tableContainer, CFStorage gameStorage) { var name = "Mappings0"; gameStorage.TryGetStream(name, out var citStream); if (citStream != null) { using (var stream = new MemoryStream(citStream.GetData())) - using (var reader = new BinaryReader(stream)) - { - table.Mappings = new Mappings.Mappings(reader, name); + using (var reader = new BinaryReader(stream)) { + tableContainer.SetMappings(new Mappings.Mappings(reader, name)); } } } - private static void LoadSounds(Table table, CFStorage storage, int fileVersion) + private static void LoadSounds(FileTableContainer tableContainer, CFStorage storage, int fileVersion) { - for (var i = 0; i < table.Data.NumSounds; i++) { + for (var i = 0; i < tableContainer.NumSounds; i++) { var soundName = $"Sound{i}"; storage.TryGetStream(soundName, out var soundStream); if (soundStream == null) { @@ -315,12 +316,12 @@ private static void LoadSounds(Table table, CFStorage storage, int fileVersion) using (var stream = new MemoryStream(soundData)) using (var reader = new BinaryReader(stream)) { var sound = new Sound.Sound(reader, soundName, fileVersion); - table.Sounds.Add(sound); + tableContainer.AddSound(sound); } } } - private static void LoadTableInfo(Table table, CFStorage rootStorage, CFStorage gameStorage) + private static void LoadTableInfo(FileTableContainer tableContainer, CFStorage rootStorage, CFStorage gameStorage) { // first, although we can loop through entries, get them from the game storage, so we // know their order, which is important when writing back (because you know, hashing). @@ -328,7 +329,7 @@ private static void LoadTableInfo(Table table, CFStorage rootStorage, CFStorage if (citStream != null) { using (var stream = new MemoryStream(citStream.GetData())) using (var reader = new BinaryReader(stream)) { - table.CustomInfoTags = new CustomInfoTags(reader); + tableContainer.CustomInfoTags.Load(reader); } } @@ -342,18 +343,18 @@ private static void LoadTableInfo(Table table, CFStorage rootStorage, CFStorage if (item.IsStream) { var itemStream = item as CFStream; if (itemStream != null) { - table.TableInfo[item.Name] = BiffUtil.ParseWideString(itemStream.GetData()); + tableContainer.TableInfo[item.Name] = BiffUtil.ParseWideString(itemStream.GetData()); } } }, false); } - private static void LoadTableMeta(Table table, CFStorage gameStorage) + private static void LoadTableMeta(FileTableContainer tableContainer, CFStorage gameStorage) { // version gameStorage.TryGetStream("Version", out var versionBytes); if (versionBytes != null) { - table.FileVersion = BitConverter.ToInt32(versionBytes.GetData(), 0); + tableContainer.FileVersion = BitConverter.ToInt32(versionBytes.GetData(), 0); } else { Logger.Info("No Version under GameStg found, skipping."); } @@ -362,7 +363,7 @@ private static void LoadTableMeta(Table table, CFStorage gameStorage) // hash gameStorage.TryGetStream("Version", out var hashBytes); if (hashBytes != null) { - table.FileHash = hashBytes.GetData(); + tableContainer.FileHash = hashBytes.GetData(); } else { Logger.Info("No MAC under GameStg found, skipping."); } diff --git a/VisualPinball.Engine/VPT/Table/TableMeshGenerator.cs b/VisualPinball.Engine/VPT/Table/TableMeshGenerator.cs index fd14307fe..15c7ae008 100644 --- a/VisualPinball.Engine/VPT/Table/TableMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Table/TableMeshGenerator.cs @@ -24,28 +24,26 @@ public class TableMeshGenerator { public bool HasMeshAsPlayfield => _playfield != null; - private readonly Table _table; - private readonly TableData _data; + private readonly TableContainer _tableContainer; private Primitive.Primitive _playfield; - public TableMeshGenerator(Table table) + public TableMeshGenerator(TableContainer tableContainer) { - _data = table.Data; - _table = table; + _tableContainer = tableContainer; } public RenderObject GetRenderObject(bool asRightHanded = true) { - var material = new PbrMaterial(_table.GetMaterial(_data.PlayfieldMaterial), _table.GetTexture(_data.Image)); + var material = new PbrMaterial(_tableContainer.GetMaterial(_tableContainer.Table.Data.PlayfieldMaterial), _tableContainer.GetTexture(_tableContainer.Table.Data.Image)); return GetFromTableDimensions(asRightHanded, material); } public RenderObjectGroup GetRenderObjects(Table table, Origin origin, bool asRightHanded = true) { - var material = new PbrMaterial(table.GetMaterial(_data.PlayfieldMaterial), table.GetTexture(_data.Image)); + var material = new PbrMaterial(table.GetMaterial(_tableContainer.Table.Data.PlayfieldMaterial), table.GetTexture(_tableContainer.Table.Data.Image)); return HasMeshAsPlayfield ? _playfield.GetRenderObjects(table, origin, asRightHanded, "Table", material) - : new RenderObjectGroup(_data.Name, "Table", Matrix3D.Identity, GetFromTableDimensions(asRightHanded, material)); + : new RenderObjectGroup(_tableContainer.Table.Data.Name, "Table", Matrix3D.Identity, GetFromTableDimensions(asRightHanded, material)); } public void SetFromPrimitive(Primitive.Primitive primitive) @@ -56,13 +54,13 @@ public void SetFromPrimitive(Primitive.Primitive primitive) private RenderObject GetFromTableDimensions(bool asRightHanded, PbrMaterial material) { var rgv = new[] { - new Vertex3DNoTex2(_data.Left, _data.Top, _table.TableHeight), - new Vertex3DNoTex2(_data.Right, _data.Top, _table.TableHeight), - new Vertex3DNoTex2(_data.Right, _data.Bottom, _table.TableHeight), - new Vertex3DNoTex2(_data.Left, _data.Bottom, _table.TableHeight), + new Vertex3DNoTex2(_tableContainer.Table.Data.Left, _tableContainer.Table.Data.Top, _tableContainer.Table.TableHeight), + new Vertex3DNoTex2(_tableContainer.Table.Data.Right, _tableContainer.Table.Data.Top, _tableContainer.Table.TableHeight), + new Vertex3DNoTex2(_tableContainer.Table.Data.Right, _tableContainer.Table.Data.Bottom, _tableContainer.Table.TableHeight), + new Vertex3DNoTex2(_tableContainer.Table.Data.Left, _tableContainer.Table.Data.Bottom, _tableContainer.Table.TableHeight), }; var mesh = new Mesh { - Name = _data.Name, + Name = _tableContainer.Table.Data.Name, Vertices = rgv.Select(r => new Vertex3DNoTex2()).ToArray(), Indices = new [] { 0, 1, 3, 0, 3, 2 } }; @@ -93,7 +91,7 @@ private RenderObject GetFromTableDimensions(bool asRightHanded, PbrMaterial mate } return new RenderObject( - _data.Name, + _tableContainer.Table.Data.Name, asRightHanded ? mesh.Transform(Matrix3D.RightHanded) : mesh, material, true diff --git a/VisualPinball.Engine/VPT/Table/TableWriter.cs b/VisualPinball.Engine/VPT/Table/TableWriter.cs index a9a77745d..a818c5216 100644 --- a/VisualPinball.Engine/VPT/Table/TableWriter.cs +++ b/VisualPinball.Engine/VPT/Table/TableWriter.cs @@ -27,14 +27,14 @@ public class TableWriter { private const int VpFileFormatVersion = 1060; - private readonly Table _table; + private readonly TableContainer _tableContainer; private CompoundFile _cf; private CFStorage _gameStorage; - public TableWriter(Table table) + public TableWriter(TableContainer tableContainer) { - _table = table; + _tableContainer = tableContainer; } public void WriteTable(string fileName) @@ -54,7 +54,7 @@ public void WriteTable(string fileName) WriteGameItems(hashWriter); // 4. the rest, which isn't hashed. - WriteImages(); + WriteTextures(); WriteSounds(); // finally write hash @@ -81,20 +81,20 @@ private void WriteTableInfo(HashWriter hashWriter) } // 2. write custom tag names - _table.CustomInfoTags?.WriteData(_gameStorage, hashWriter); + _tableContainer.CustomInfoTags?.WriteData(_gameStorage, hashWriter); // 3. write custom tags - foreach (var tag in _table.CustomInfoTags?.TagNames ?? Array.Empty()) { + foreach (var tag in _tableContainer.CustomInfoTags?.TagNames ?? Array.Empty()) { WriteInfoTag(tableInfo, tag, hashWriter); } } private void WriteInfoTag(CFStorage tableInfo, string tag, HashWriter hashWriter) { - if (!_table.TableInfo.ContainsKey(tag)) { + if (!_tableContainer.TableInfo.ContainsKey(tag)) { return; } - WriteStream(tableInfo, tag, BiffUtil.GetWideString(_table.TableInfo[tag]), hashWriter); + WriteStream(tableInfo, tag, BiffUtil.GetWideString(_tableContainer.TableInfo[tag]), hashWriter); } private void WriteGameItems(HashWriter hashWriter) @@ -102,38 +102,34 @@ private void WriteGameItems(HashWriter hashWriter) // again, the order is important, because we're hashing at the same time. // 1. game data - _table.Data.WriteData(_gameStorage, hashWriter); + _tableContainer.Table.Data.WriteData(_gameStorage, hashWriter); // 2. game items - foreach (var writeable in _table.ItemDatas.OrderBy(gi => gi.StorageIndex)) { - - #if !WRITE_VP106 - - // clean material and texture references - CleanInvalidReferences(writeable, v => _table.GetMaterial(v)); - CleanInvalidReferences(writeable, v => _table.GetTexture(v)); - - #endif - - writeable.WriteData(_gameStorage); + foreach (var gameItem in _tableContainer.ItemDatas.OrderBy(gi => gi.StorageIndex)) { + gameItem.WriteData(_gameStorage); + } + #if !WRITE_VP106 && !WRITE_VP107 + foreach (var gameItem in _tableContainer.VpeItemDatas.OrderBy(gi => gi.StorageIndex)) { + gameItem.WriteData(_gameStorage); } + #endif // 3. Collections - var collections = _table.Collections.Values; - foreach (var collection in collections.Select(c => c.Data).OrderBy(c => c.StorageIndex)) { + var collections = _tableContainer.Collections; + foreach (var collection in collections.OrderBy(c => c.StorageIndex)) { collection.WriteData(_gameStorage, hashWriter); } // 5. Mappings #if !WRITE_VP106 && !WRITE_VP107 - _table.Mappings.Data.WriteData(_gameStorage); + _tableContainer.Mappings.Data.WriteData(_gameStorage); #endif } - private void WriteImages() + private void WriteTextures() { int i = 0; - foreach (var texture in _table.Textures.Values) { + foreach (var texture in _tableContainer.Textures) { texture.Data.StorageIndex = i++; texture.Data.WriteData(_gameStorage); } @@ -142,7 +138,7 @@ private void WriteImages() private void WriteSounds() { int i = 0; - foreach (var sound in _table.Sounds.Values) { + foreach (var sound in _tableContainer.Sounds) { sound.Data.StorageIndex = i++; sound.Data.WriteData(_gameStorage); } @@ -154,17 +150,6 @@ private static void WriteStream(CFStorage storage, string streamName, byte[] dat hashWriter?.Write(data); } - private static void CleanInvalidReferences(ItemData data, Func getter) where TAttr: Attribute - { - var refs = GetMembersWithAttribute(data); - foreach (var r in refs) { - var value = GetValue(r, data); - if (getter(value) == null) { - SetValue(r, data, string.Empty); - } - } - } - private static IEnumerable GetMembersWithAttribute(ItemData data) where TAttr: Attribute { return data.GetType() diff --git a/VisualPinball.Engine/VPT/Texture.cs b/VisualPinball.Engine/VPT/Texture.cs index 38c761f18..b5f3a7ea2 100644 --- a/VisualPinball.Engine/VPT/Texture.cs +++ b/VisualPinball.Engine/VPT/Texture.cs @@ -43,11 +43,15 @@ public class Texture : Item public int Width => Data.Width; public int Height => Data.Height; - public bool IsHdr => (Data.Path?.ToLower().EndsWith(".hdr") ?? false) || (Data.Path?.ToLower().EndsWith(".exr") ?? false); + public bool IsHdr => (Data.Path?.EndsWith(".hdr", StringComparison.OrdinalIgnoreCase) ?? false) + || (Data.Path?.EndsWith(".exr", StringComparison.OrdinalIgnoreCase) ?? false); + public bool IsWebp => Data.Path?.EndsWith(".webp", StringComparison.OrdinalIgnoreCase) ?? false; + + public bool ConvertToPng => Data.Bitmap != null; public string FileExtension { get { - if (Data.Path == null) { + if (Data.Path == null || ConvertToPng) { return ".png"; } var ext = Path.GetExtension(Data.Path).ToLower(); @@ -149,12 +153,16 @@ private TextureStats AnalyzeAlpha() } } - private Image GetImage() + public Image GetImage() { try { + var data = Data.Binary != null ? Data.Binary.Data : Data.Bitmap.Bytes; + if (data.Length == 0) { + throw new InvalidDataException("Image data is empty."); + } return Data.Binary != null - ? Image.NewFromBuffer(Data.Binary.Data) - : Image.NewFromMemory(Data.Bitmap.Bytes, Width, Height, 4, Enums.BandFormat.Uchar); + ? Image.NewFromBuffer(data) + : Image.NewFromMemory(data, Width, Height, 4, Enums.BandFormat.Uchar); } catch (Exception e) { Logger.Warn(e, "Error reading {0} ({1}) with libvips.", Name, Path.GetFileName(Data.Path)); diff --git a/VisualPinball.Engine/VPT/TextureData.cs b/VisualPinball.Engine/VPT/TextureData.cs index a7398d0b9..ed8fd8a2c 100644 --- a/VisualPinball.Engine/VPT/TextureData.cs +++ b/VisualPinball.Engine/VPT/TextureData.cs @@ -73,6 +73,12 @@ public TextureData(Resource res) : base(res.Name) Binary = new BinaryData(res); } + public void FreeBinaryData() + { + Binary?.FreeBinaryData(); + Bitmap?.FreeBinaryData(); + } + protected override bool SkipWrite(BiffAttribute attr) { switch (attr.Name) { diff --git a/VisualPinball.Engine/VPT/Trigger/TriggerMeshGenerator.cs b/VisualPinball.Engine/VPT/Trigger/TriggerMeshGenerator.cs index 091d81921..486522209 100644 --- a/VisualPinball.Engine/VPT/Trigger/TriggerMeshGenerator.cs +++ b/VisualPinball.Engine/VPT/Trigger/TriggerMeshGenerator.cs @@ -60,7 +60,7 @@ public RenderObjectGroup GetRenderObjects(Table.Table table, Origin origin, bool protected override float BaseHeight(Table.Table table) { - return table.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y); + return table?.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y) ?? 0f; } private Mesh GetMesh() diff --git a/VisualPinball.Engine/VPT/Trough/TroughData.cs b/VisualPinball.Engine/VPT/Trough/TroughData.cs index 104368a5c..7d60ca6f4 100644 --- a/VisualPinball.Engine/VPT/Trough/TroughData.cs +++ b/VisualPinball.Engine/VPT/Trough/TroughData.cs @@ -65,7 +65,7 @@ public class TroughData : ItemData [BiffInt("KTIM", Pos = 10)] public int KickTime = 100; - public TroughData(string name) : base(StoragePrefix.GameItem) + public TroughData(string name) : base(StoragePrefix.VpeGameItem) { Name = name; } diff --git a/VisualPinball.Engine/VisualPinball.Engine.csproj b/VisualPinball.Engine/VisualPinball.Engine.csproj index e94e1ea82..e119077c1 100644 --- a/VisualPinball.Engine/VisualPinball.Engine.csproj +++ b/VisualPinball.Engine/VisualPinball.Engine.csproj @@ -10,7 +10,7 @@ 0.1.0.0 0.1.0.0 0.1.0.0 - 7.3 + 8 false https://visualpinball.org https://user-images.githubusercontent.com/70426/101756172-0965a200-3ad6-11eb-8c71-edb751f0f5d5.png diff --git a/VisualPinball.Unity/Documentation~/creators-guide/editor/materials.md b/VisualPinball.Unity/Documentation~/creators-guide/editor/materials.md new file mode 100644 index 000000000..ae5577988 --- /dev/null +++ b/VisualPinball.Unity/Documentation~/creators-guide/editor/materials.md @@ -0,0 +1,44 @@ +--- +title: Materials +description: How VPE deals with materials. +--- + +# Materials + +Materials are what you apply to an object in order to make it look or behave like something in the real world. Materials are one of the key components of a table, because they define the visuals and the physical behavior. However, the term *material* can be confusing, because it can have different meanings. So let's define them first. + +## Rendered Materials + +We refer to rendered materials just as **materials**. They describe how a surface of a mesh is drawn on the sceen. In Unity, [materials](https://docs.unity3d.com/Manual/materials-introduction.html) and [shaders](https://docs.unity3d.com/Manual/Shaders.html) are closely linked - every material uses a shader, which you can configure. The most common shader is the [Lit shader](https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@12.0/manual/Lit-Shader.html), which works well for rigid materials that interact with light. + +A material typically includes one or more textures that define the color, normals, roughness, metalness and many more parameters on a per-pixel basis. + +> [!note] +> In Visual Pinball, materials don't include the texture. Instead, the texture is applied on a per-object basis. + +## Physics Materials + +We refer to how the material interacts with the ball during the physics simulation as the **physics material**. It has these properties: + +- **Elasticity** - The bounciness, how much the ball is thrown back when it collides. +- **Elasticity Falloff** - Pinball tables have a lot of rubber parts, and rubber has a special attribute: it gets less bouncy when hit at higher velocity. The falloff parameter controls how much. +- **Friction** - How much friction is applied when the ball rolls along this material. +- **Scatter** - Adds a random factor to the collision angle. + +Physics materials are a way to group common behavior among certain objects, but contrarily to rendered materials, you can also *not* assign a physics material to an object and set each of those four parameters individually. + +> [!note] +> In Visual Pinball, the physical parameters are part of the rendered material, so there is only one notion of material. + +## Conversion from Visual Pinball + +As mentioned above, there are two differences between Visual Pinball and VPE how materials are handled: + +1. VPE includes textures in the material, while Visual Pinball does not. +2. VPE differentiates between rendered and the physical material. + +When importing a `.vpx` file, VPE converts the "visual part" of Visual Pinball materials into materials for the current render pipeline. It does that by creating a new material for every material/texture combination in Visual Pinball. The materials are then written to the `Materials` asset folder of the imported table where they can be easily edited and referenced. Since Visual Pinball uses different shaders than Unity, the results of the conversion are approximations and should be heavily tweaked. + +Since VPE uses the same physics engine as Visual Pinball, the physical values of the materials don't need to be converted, they are copied 1:1 into a new physics material and saved in the asset folder. + +In case you're using the Unity editor for authoring a Visual Pinball table, you can still edit the original VPX materials using the materials manager. However, you'll notice that the physical attributes are missing, since they are now handled by physical material assets. That means when exporting, VPE will apply the physics values from the assets to the internal materials (the match between the material editor and the asset is done via name). \ No newline at end of file diff --git a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml index 25b1eeafd..0d948af46 100644 --- a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml +++ b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml @@ -16,6 +16,8 @@ items: - name: Unity Components href: editor/unity-components.md + - name: Materials + href: editor/materials.md - name: Switch Manager href: editor/switch-manager.md - name: Coil Manager diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointMenuItems.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointMenuItems.cs index 536570ba6..68486e342 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointMenuItems.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointMenuItems.cs @@ -30,7 +30,7 @@ private static DragPointData RetrieveDragPoint(IDragPointsItemInspector inspecto } // Drag Points - [MenuItem(ControlPointsMenuPath + "/IsSlingshot", false, 1)] + [MenuItem(ControlPointsMenuPath + "/Is Slingshot", false, 1)] private static void SlingShot(MenuCommand command) { if (!(command.context is IDragPointsItemInspector inspector)) { @@ -39,12 +39,13 @@ private static void SlingShot(MenuCommand command) var dragPoint = RetrieveDragPoint(inspector, command.userData); if (dragPoint != null) { - inspector.PrepareUndo("Toggle drag point slingshot"); + inspector.PrepareUndo("Toggle Drag Point Slingshot"); dragPoint.IsSlingshot = !dragPoint.IsSlingshot; + inspector.RebuildMeshes(); } } - [MenuItem(ControlPointsMenuPath + "/IsSlingshot", true)] + [MenuItem(ControlPointsMenuPath + "/Is Slingshot", true)] private static bool SlingshotValidate(MenuCommand command) { if (!(command.context is IDragPointsItemInspector inspector) || inspector.IsItemLocked()) { @@ -64,7 +65,7 @@ private static bool SlingshotValidate(MenuCommand command) return true; } - [MenuItem(ControlPointsMenuPath + "/IsSmooth", false, 1)] + [MenuItem(ControlPointsMenuPath + "/Is Smooth", false, 1)] private static void Smooth(MenuCommand command) { var inspector = command.context as IDragPointsItemInspector; @@ -74,12 +75,13 @@ private static void Smooth(MenuCommand command) var dragPoint = RetrieveDragPoint(inspector, command.userData); if (dragPoint != null) { - inspector.PrepareUndo("Toggle drag point smooth"); + inspector.PrepareUndo("Toggle Drag Point Smooth"); dragPoint.IsSmooth = !dragPoint.IsSmooth; + inspector.RebuildMeshes(); } } - [MenuItem(ControlPointsMenuPath + "/IsSmooth", true)] + [MenuItem(ControlPointsMenuPath + "/Is Smooth", true)] private static bool SmoothValidate(MenuCommand command) { if (!(command.context is IDragPointsItemInspector inspector) || inspector.IsItemLocked()) { diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointsHandler.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointsHandler.cs index 6f4b84c76..dfaa8a3c2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointsHandler.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointsHandler.cs @@ -171,20 +171,21 @@ public void AddDragPointOnTraveller() public void RemoveDragPoint(int controlId) { var idx = ControlPoints.FindIndex(controlPoint => controlPoint.ControlId == controlId); - if (idx >= 0) { - var removalOk = !ControlPoints[idx].DragPoint.IsLocked; - if (!removalOk) { - removalOk = EditorUtility.DisplayDialog("Locked DragPoint Removal", "This drag point is locked!\nAre you really sure you want to remove it?", "Yes", "No"); - } - - if (removalOk) { - var dragPoints = DragPointEditable.GetDragPoints().ToList(); - dragPoints.RemoveAt(idx); - DragPointEditable.SetDragPoints(dragPoints.ToArray()); - ControlPoints.RemoveAt(idx); - RebuildControlPoints(); - } + if (idx < 0) { + return; + } + var removalOk = !ControlPoints[idx].DragPoint.IsLocked; + if (!removalOk) { + removalOk = EditorUtility.DisplayDialog("Locked DragPoint Removal", "This drag point is locked!\nAre you really sure you want to remove it?", "Yes", "No"); + } + if (!removalOk) { + return; } + var dragPoints = DragPointEditable.GetDragPoints().ToList(); + dragPoints.RemoveAt(idx); + DragPointEditable.SetDragPoints(dragPoints.ToArray()); + + RebuildControlPoints(); } /// @@ -249,17 +250,18 @@ public bool UpdateDragPointsLock(bool itemLock) private void RebuildControlPoints() { ControlPoints.Clear(); - - for (var i = 0; i < DragPointEditable.GetDragPoints().Length; ++i) { + var dragPoints = DragPointEditable.GetDragPoints(); + for (var i = 0; i < dragPoints.Length; ++i) { var cp = new ControlPoint( - DragPointEditable.GetDragPoints()[i], + dragPoints[i], GUIUtility.GetControlID(FocusType.Passive), i, - DragPointEditable.GetDragPoints().Length >= 2 ? (float)i / (DragPointEditable.GetDragPoints().Length-1) : 0.0f + dragPoints.Length > 1 + ? (float)i / (dragPoints.Length - 1) + : 0.0f ); ControlPoints.Add(cp); } - CurveTravellerControlId = GUIUtility.GetControlID(FocusType.Passive); } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointsItemInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointsItemInspector.cs index 1d4570596..bacf85b47 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointsItemInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/DragPointsItemInspector.cs @@ -48,9 +48,14 @@ public abstract class DragPointsItemInspector : It /// private static Vector3 _storedControlPoint = Vector3.zero; + private IItemMainRenderableAuthoring _renderable; + + public void RebuildMeshes() => _renderable.RebuildMeshes(); + protected override void OnEnable() { base.OnEnable(); + _renderable = target as IItemMainRenderableAuthoring; DragPointsHandler = new DragPointsHandler(target); Undo.undoRedoPerformed += OnUndoRedoPerformed; } @@ -133,8 +138,9 @@ public void FlipDragPoints(FlipAxis flipAxis) return; } - PrepareUndo($"Flip drag points on {flipAxis} axis"); + PrepareUndo($"Flip-{flipAxis} Drag Points"); DragPointsHandler.FlipDragPoints(flipAxis); + RebuildMeshes(); } /// @@ -143,8 +149,8 @@ public void FlipDragPoints(FlipAxis flipAxis) public void RemapControlPoints() { var rebuilt = DragPointsHandler.RemapControlPoints(); - if (rebuilt && target is IItemMainRenderableAuthoring meshAuthoring) { - meshAuthoring.SetMeshDirty(); + if (rebuilt) { + RebuildMeshes(); } } @@ -163,8 +169,9 @@ public void AddDragPointOnTraveller() /// Control ID of the drag point to remove. public void RemoveDragPoint(int controlId) { - PrepareUndo($"Remove drag point at ID {controlId}"); + PrepareUndo("Remove Drag Point"); DragPointsHandler.RemoveDragPoint(controlId); + RebuildMeshes(); } /// @@ -173,18 +180,7 @@ public void RemoveDragPoint(int controlId) /// Message to appear in the UNDO menu public void PrepareUndo(string message) { - if (target == null) { - return; - } - - // Set MeshDirty to true there so it'll trigger again after Undo - var recordObjs = new List(); - if (target is IItemMainRenderableAuthoring meshAuthoring) { - meshAuthoring.SetMeshDirty(); - recordObjs.Add(this); - } - recordObjs.Add(target); - Undo.RecordObjects(recordObjs.ToArray(), $"Item {target} : {message}"); + Undo.RecordObjects(new []{this, target}, message); } public override void OnInspectorGUI() @@ -250,15 +246,13 @@ private void UpdateDragPointsLock() private void OnDragPointPositionChange(Vector3 newPos) { - PrepareUndo($"[{target?.name}] Change drag point position for {DragPointsHandler.SelectedControlPoints.Count} control points."); + _renderable.RebuildMeshes(); + PrepareUndo("Change Drag Point Position"); } private void OnUndoRedoPerformed() { RemapControlPoints(); - if (target is IItemMainRenderableAuthoring meshAuthoring) { - meshAuthoring.SetMeshDirty(); - } } protected virtual void OnSceneGUI() diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/IDragPointsItemInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/IDragPointsItemInspector.cs index 3af638cec..8228f819d 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/IDragPointsItemInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/DragPoint/IDragPointsItemInspector.cs @@ -83,5 +83,7 @@ public interface IDragPointsItemInspector /// /// Axis to flip on void FlipDragPoints(FlipAxis flipAxis); + + void RebuildMeshes(); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetImporter.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetImporter.cs deleted file mode 100644 index e31a297fe..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetImporter.cs +++ /dev/null @@ -1,45 +0,0 @@ -// 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 UnusedType.Global - -using NLog; - -using UnityEngine; - -using Logger = NLog.Logger; - -namespace VisualPinball.Unity.Editor -{ - [UnityEditor.AssetImporters.ScriptedImporter(2, "vpx")] - public class VpxAssetImporter : UnityEditor.AssetImporters.ScriptedImporter - { - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - - public override void OnImportAsset(UnityEditor.AssetImporters.AssetImportContext ctx) - { - Logger.Info("Importing VPX table at {0}...", ctx.assetPath); - - // create root object - var rootGameObj = new GameObject(); - // add lazy importer, will do a normal in memory import once the object ends up in a scene - rootGameObj.AddComponent(); - - ctx.AddObjectToAsset("main obj", rootGameObj); - ctx.SetMainObject(rootGameObj); - } - } -} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetLazyImporter.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetLazyImporter.cs deleted file mode 100644 index 4d75b242e..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetLazyImporter.cs +++ /dev/null @@ -1,58 +0,0 @@ -// 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 UnityEditor; -using UnityEngine; - -namespace VisualPinball.Unity.Editor -{ - /// - /// This component is attached to a game object when using the scripted importer for vpx files - /// (i.e. when you have a .vpx in the unity project itself). When the asset is then placed in - /// a scene, this executes the table importer flow and destroys itself. - /// - [ExecuteInEditMode] - public class VpxAssetLazyImporter : MonoBehaviour - { - [SerializeField] [HideInInspector] - private bool _importComplete = false; - - protected virtual void Awake() - { - if (_importComplete) return; - - var obj = PrefabUtility.GetCorrespondingObjectFromSource(gameObject); - if (obj == null) return; - - var path = AssetDatabase.GetAssetPath(obj); - - GameObject tableRoot = new GameObject(obj.name); - var converter = tableRoot.AddComponent(); - var table = TableLoader.LoadTable(path); - converter.Convert(Path.GetFileName(path), table); - - _importComplete = true; - } - - protected virtual void Update() - { - if (_importComplete) { - DestroyImmediate(gameObject); - } - } - } -} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetLazyImporter.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetLazyImporter.cs.meta deleted file mode 100644 index 203325f3f..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetLazyImporter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 072956061bfc0e7479f944e1ae91a4fd -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImageConverter.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImageConverter.cs new file mode 100644 index 000000000..592a58e1a --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImageConverter.cs @@ -0,0 +1,51 @@ +// 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 Texture = VisualPinball.Engine.VPT.Texture; + +namespace VisualPinball.Unity.Editor +{ + public static class VpxImageConverter + { + public static void WriteAsAsset(this Texture texture, string folder, bool skipIfExists) + { + var path = texture.GetUnityFilename(folder); + if (skipIfExists && File.Exists(path)) { + return; + } + + // convert if bmp + if (texture.ConvertToPng) { + using var im = texture.GetImage(); + im.Pngsave(path); + + } else if (texture.IsWebp) { + // write both original and png conversion + File.WriteAllBytes(path, texture.Content); + + using var im = texture.GetImage(); + im.Pngsave(Path.Combine( + Path.GetDirectoryName(path) ?? "", + Path.GetFileNameWithoutExtension(path) + ".png" + )); + + } else { // might need to convert other formats like webp + File.WriteAllBytes(path, texture.Content); + } + } + } +} diff --git a/VisualPinball.Engine/VPT/Table/ITableResourceContainer.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImageConverter.cs.meta similarity index 83% rename from VisualPinball.Engine/VPT/Table/ITableResourceContainer.cs.meta rename to VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImageConverter.cs.meta index 8269cf504..92ef38fa3 100644 --- a/VisualPinball.Engine/VPT/Table/ITableResourceContainer.cs.meta +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImageConverter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 9cd29d992ebc4a44b915322f9a8ef49e +guid: 5a8c5b64253b59348a3bc03c3f4664a4 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImportEngine.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImportEngine.cs index c4a1c75b8..5155c4d64 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImportEngine.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImportEngine.cs @@ -14,10 +14,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using System.Diagnostics; using System.IO; using NLog; using UnityEditor; using UnityEngine; +using VisualPinball.Engine.VPT.Table; using Logger = NLog.Logger; namespace VisualPinball.Unity.Editor @@ -26,41 +28,39 @@ public static class VpxImportEngine { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - /// - /// Import the table specified with the given path and assign it to the given parent. - /// - /// - /// - public static void Import( string vpxPath, GameObject parent, bool applyPatch = true, string tableName = null) + public static GameObject ImportIntoScene(string path, GameObject parent = null, bool applyPatch = true, string tableName = null, ConvertOptions options = null) { - var rootGameObj = ImportVpx(vpxPath, applyPatch, tableName); - - // if an object was selected in the editor, make it its parent - GameObjectUtility.SetParentAndAlign(rootGameObj, parent); - - // register undo system - Undo.RegisterCreatedObjectUndo(rootGameObj, "Import VPX table file"); - - // select imported object - Selection.activeObject = rootGameObj; - - Logger.Info("Imported {0}", vpxPath); + var sw = Stopwatch.StartNew(); + return ImportIntoScene(TableLoader.LoadTable(path), Path.GetFileName(path), parent, applyPatch, tableName, sw, options); } - private static GameObject ImportVpx(string path, bool applyPatch, string tableName) + public static GameObject ImportIntoScene(FileTableContainer tableContainer, string filename = "", GameObject parent = null, bool applyPatch = true, string tableName = null, Stopwatch sw = null, ConvertOptions options = null) { - // create root object - var rootGameObj = new GameObject(); - var importer = rootGameObj.AddComponent(); + sw ??= Stopwatch.StartNew(); + if (tableName == null && !string.IsNullOrEmpty(filename)) { + tableName = Path.GetFileNameWithoutExtension(filename); + } // load table - var table = TableLoader.LoadTable(path); + var loadedIn = sw.ElapsedMilliseconds; + var converter = new VpxSceneConverter(tableContainer, filename, options); + var tableGameObject = converter.Convert(applyPatch, tableName); + var convertedIn = sw.ElapsedMilliseconds; + + // if an object was selected in the editor, make it its parent + if (parent != null) { + GameObjectUtility.SetParentAndAlign(tableGameObject, parent); + } - Logger.Info("Importing Table\nInfoName={0}\nInfoAuthorName={1}", table.InfoName, table.InfoAuthorName); + // register undo system + Undo.RegisterCreatedObjectUndo(tableGameObject, "Import VPX table file"); + + // select imported object + Selection.activeObject = tableGameObject; - importer.Convert(Path.GetFileName(path), table, applyPatch, tableName); + Logger.Info($"Imported {filename} in {convertedIn}ms (loaded after {loadedIn}ms)."); - return rootGameObj; + return tableGameObject; } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImportWizard.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImportWizard.cs index 4ec2826b8..10ca67338 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImportWizard.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxImportWizard.cs @@ -158,7 +158,7 @@ public void OnGUI() { if (File.Exists(VpxImportWizardSettings.VpxPath)) { - VpxImportEngine.Import(VpxImportWizardSettings.VpxPath, null, VpxImportWizardSettings.ApplyPatch, VpxImportWizardSettings.TableName); + VpxImportEngine.ImportIntoScene(VpxImportWizardSettings.VpxPath, null, VpxImportWizardSettings.ApplyPatch, VpxImportWizardSettings.TableName); } else { diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxMenuImporter.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxMenuImporter.cs index b97418638..42c7ed22c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxMenuImporter.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxMenuImporter.cs @@ -18,30 +18,15 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global +using System.IO; using UnityEditor; -using UnityEngine; namespace VisualPinball.Unity.Editor { public static class VpxMenuImporter { - - [MenuItem("Visual Pinball/Import VPX", false, 1)] - public static void ImportVpxEditorMemory(MenuCommand menuCommand) - { - ImportVpxEditor(menuCommand); - } - - /// - /// Imports a Visual Pinball File (.vpx) into the Unity Editor.

- /// - /// The goal of this is to be able to iterate rapidly without having to - /// execute the runtime on every test. This importer also saves the - /// imported data to the Assets folder so a project with an imported table - /// can be saved and loaded - ///

- /// Context provided by the Editor - private static void ImportVpxEditor(MenuCommand menuCommand) + [MenuItem("Visual Pinball/Import VPX", false, 2)] + public static void ImportVpxIntoScene(MenuCommand menuCommand) { // open file dialog var vpxPath = EditorUtility.OpenFilePanelWithFilters("Import .VPX File", null, new[] { "Visual Pinball Table Files", "vpx" }); @@ -49,8 +34,7 @@ private static void ImportVpxEditor(MenuCommand menuCommand) return; } - // perform import - VpxImportEngine.Import(vpxPath, menuCommand.context as GameObject); + VpxImportEngine.ImportIntoScene(vpxPath, tableName: Path.GetFileNameWithoutExtension(vpxPath)); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs new file mode 100644 index 000000000..647f2dc83 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs @@ -0,0 +1,687 @@ +// 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 System.IO; +using System.Linq; +using NLog; +using UnityEditor; +using UnityEngine; +using VisualPinball.Engine.Common; +using VisualPinball.Engine.Game; +using VisualPinball.Engine.VPT; +using VisualPinball.Engine.VPT.Bumper; +using VisualPinball.Engine.VPT.Decal; +using VisualPinball.Engine.VPT.DispReel; +using VisualPinball.Engine.VPT.Flasher; +using VisualPinball.Engine.VPT.Flipper; +using VisualPinball.Engine.VPT.Gate; +using VisualPinball.Engine.VPT.HitTarget; +using VisualPinball.Engine.VPT.Kicker; +using VisualPinball.Engine.VPT.LightSeq; +using VisualPinball.Engine.VPT.Mappings; +using VisualPinball.Engine.VPT.Plunger; +using VisualPinball.Engine.VPT.Primitive; +using VisualPinball.Engine.VPT.Ramp; +using VisualPinball.Engine.VPT.Rubber; +using VisualPinball.Engine.VPT.Spinner; +using VisualPinball.Engine.VPT.Surface; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Engine.VPT.TextBox; +using VisualPinball.Engine.VPT.Timer; +using VisualPinball.Engine.VPT.Trigger; +using VisualPinball.Engine.VPT.Trough; +using Light = VisualPinball.Engine.VPT.Light.Light; +using Logger = NLog.Logger; +using Material = UnityEngine.Material; +using Mesh = UnityEngine.Mesh; +using Texture = UnityEngine.Texture; + +namespace VisualPinball.Unity.Editor +{ + public class VpxSceneConverter : ITextureProvider, IMaterialProvider, IMeshProvider + { + private readonly FileTableContainer _tableContainer; + private readonly Table _table; + private readonly ConvertOptions _options; + + private GameObject _tableGo; + private TableAuthoring _tableAuthoring; + + private GameObject _playfieldGo; + + private string _assetsPrefabs; + private string _assetsTextures; + private string _assetsMaterials; + private string _assetsPhysicsMaterials; + private string _assetsMeshes; + private string _assetsSounds; + + private readonly Dictionary _groupParents = new Dictionary(); + private readonly Dictionary _textures = new Dictionary(); + private readonly Dictionary _materials = new Dictionary(); + private readonly Dictionary _physicalMaterials = new Dictionary(); + + private readonly IPatcher _patcher; + private bool _applyPatch = true; + + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + /// + /// Creates a new converter for a new table + /// + /// Source table container + /// File name of the file being imported + /// Optional convert options + public VpxSceneConverter(FileTableContainer tableContainer, string fileName = "", ConvertOptions options = null) + { + _tableContainer = tableContainer; + _table = tableContainer.Table; + _patcher = PatcherManager.GetPatcher(); + _patcher?.Set(tableContainer, fileName); + _options = options ?? new ConvertOptions(); + } + + /// + /// Creates a converter based on an existing table in the scene. + /// + /// Existing component + public VpxSceneConverter(TableAuthoring tableAuthoring) + { + _options = new ConvertOptions(); + _tableGo = tableAuthoring.gameObject; + var tablePlayfieldAuthoring = _tableGo.GetComponentInChildren(); + if (!tablePlayfieldAuthoring) { + throw new InvalidOperationException("Cannot find playfield hierarchy."); + } + _playfieldGo = tablePlayfieldAuthoring.gameObject; + _tableAuthoring = tableAuthoring; + _table = tableAuthoring.Table; + + // get materials in scene + var guids = AssetDatabase.FindAssets("t:Material"); + foreach (var guid in guids) { + var assetPath = AssetDatabase.GUIDToAssetPath(guid); + var material = AssetDatabase.LoadAssetAtPath(assetPath); + if (material != null) { + _materials[material.name] = material; + } + } + + // get group parents in scene + for (var i = 0; i < _playfieldGo.transform.childCount; i++) { + var child = _playfieldGo.transform.GetChild(i); + var childGo = child.gameObject; + _groupParents[childGo.name] = childGo; + } + + CreateFileHierarchy(); + } + + public GameObject Convert(bool applyPatch = true, string tableName = null) + { + _applyPatch = applyPatch; + + CreateRootHierarchy(tableName); + CreateFileHierarchy(); + + ExtractPhysicsMaterials(); + ExtractTextures(); + ExtractSounds(); + + try { + // pause asset database refreshing + AssetDatabase.StartAssetEditing(); + + SaveData(); + SaveLegacyData(); + + ConvertGameItems(); + + } finally { + + // resume asset database refreshing + AssetDatabase.StopAssetEditing(); + AssetDatabase.Refresh(); + } + + FreeTextures(); + ConfigurePlayer(); + + return _tableGo; + } + + private void SaveData() + { + _tableAuthoring.Mappings = _tableContainer.Mappings.Data; + foreach (var key in _tableContainer.TableInfo.Keys) { + _tableAuthoring.TableInfo[key] = _tableContainer.TableInfo[key]; + } + _tableAuthoring.CustomInfoTags = _tableContainer.CustomInfoTags; + _tableAuthoring.Collections = _tableContainer.Collections; + } + + private void SaveLegacyData() + { + _tableAuthoring.LegacyContainer.Decals = _tableContainer.GetAllData(); + _tableAuthoring.LegacyContainer.DispReels = _tableContainer.GetAllData(); + _tableAuthoring.LegacyContainer.Flashers = _tableContainer.GetAllData(); + _tableAuthoring.LegacyContainer.LightSeqs = _tableContainer.GetAllData(); + _tableAuthoring.LegacyContainer.TextBoxes = _tableContainer.GetAllData(); + _tableAuthoring.LegacyContainer.Timers = _tableContainer.GetAllData(); + } + + private void ConvertGameItems() + { + var convertedItems = new Dictionary(); + var renderableLookup = new Dictionary(); + var renderables = from renderable in _tableContainer.Renderables + orderby renderable.SubComponent + select renderable; + + foreach (var renderable in renderables) { + + if (_applyPatch) { + _patcher?.ApplyPrePatches(renderable); + } + + var lookupName = renderable.Name.ToLower(); + renderableLookup[lookupName] = renderable; + + if (renderable.SubComponent == ItemSubComponent.None) { + // create object(s) + convertedItems[lookupName] = CreateGameObjects(renderable); + + } else { + // if the object's names was parsed to be part of another object, re-link to other object. + var parentName = renderable.ComponentName.ToLower(); + if (convertedItems.ContainsKey(parentName)) { + var parent = convertedItems[parentName]; + + var convertedItem = CreateGameObjects(renderable); + if (convertedItem.IsValidChild(parent)) { + + if (convertedItem.MeshAuthoring.Any()) { + + // move and rotate into parent + if (parent.MainAuthoring.IItem is IRenderable parentRenderable) { + renderable.Position -= parentRenderable.Position; + renderable.RotationY -= parentRenderable.RotationY; + } + + parent.DestroyMeshComponents(); + } + if (convertedItem.ColliderAuthoring != null) { + parent.DestroyColliderComponent(); + } + convertedItem.MainAuthoring.gameObject.transform.SetParent(parent.MainAuthoring.gameObject.transform, false); + convertedItems[lookupName] = convertedItem; + + } else { + + renderable.DisableSubComponent(); + + // invalid parenting, re-convert the item, because it returned only the sub component. + convertedItems[lookupName] = CreateGameObjects(renderable); + + // ..and destroy the other one + convertedItem.Destroy(); + } + + } else { + Logger.Warn($"Cannot find component \"{parentName}\" that is supposed to be the parent of \"{renderable.Name}\"."); + } + } + } + + // now we have all renderables imported, patch them. + foreach (var lookupName in convertedItems.Keys) { + + if (!convertedItems.ContainsKey(lookupName) || convertedItems[lookupName] == null) { + continue; + } + + if (!_applyPatch) { + continue; + } + foreach (var meshMb in convertedItems[lookupName].MeshAuthoring) { + _patcher?.ApplyPatches(renderableLookup[lookupName], meshMb.gameObject, _tableGo); + } + } + + // convert non-renderables + foreach (var item in _tableContainer.NonRenderables) { + + // create object(s) + CreateGameObjects(item); + } + } + + public IConvertedItem CreateGameObjects(IItem item) + { + var prefabPath = Path.Combine(_assetsPrefabs, $"{item.Name.ToFilename()}.prefab"); + var parentGo = GetGroupParent(item); + var loadFromPrefab = _options.SkipExistingPrefabs && File.Exists(prefabPath); + var itemGo = loadFromPrefab + ? PrefabUtility.InstantiatePrefab(AssetDatabase.LoadAssetAtPath(prefabPath)) as GameObject + : new GameObject(item.Name); + + itemGo!.transform.SetParent(parentGo.transform, false); + + var importedObject = SetupGameObjects(item, itemGo, loadFromPrefab); + foreach (var meshAuthoring in importedObject.MeshAuthoring) { + meshAuthoring.CreateMesh(itemGo.name, this, this, loadFromPrefab ? this : null, loadFromPrefab); + } + item.FreeBinaryData(); + + // apply transformation + if (item is IRenderable renderable) { + itemGo.transform.SetFromMatrix(renderable.TransformationMatrix(_table, Origin.Original).ToUnityMatrix()); + } + + if (!loadFromPrefab) { + CreateAssetFromGameObject(itemGo, !importedObject.IsProceduralMesh); + } + + return importedObject; + } + + private void CreateAssetFromGameObject(GameObject go, bool extractMesh) + { + var name = go.name; + var mfs = go.GetComponentsInChildren(); + + if (extractMesh) { + foreach (var mf in mfs) { + var suffix = mfs.Length == 1 ? "" : $" ({mf.gameObject.name})"; + var meshFilename = $"{name.ToFilename()}{suffix.ToFilename()}.mesh"; + var meshPath = Path.Combine(_assetsMeshes, meshFilename); + if (_options.SkipExistingMeshes && File.Exists(meshPath)) { + continue; + } + if (File.Exists(meshPath)) { + AssetDatabase.DeleteAsset(meshPath); + } + AssetDatabase.CreateAsset(mf.sharedMesh, meshPath); + } + } + + if (mfs.Length > 0) { + // Make sure the file name is unique, in case an existing Prefab has the same name. + var prefabPath = Path.Combine(_assetsPrefabs, $"{name.ToFilename()}.prefab"); + + if (File.Exists(prefabPath)) { + AssetDatabase.DeleteAsset(prefabPath); + } + PrefabUtility.SaveAsPrefabAssetAndConnect(go, prefabPath, InteractionMode.AutomatedAction); + } + } + + private IConvertedItem SetupGameObjects(IItem item, GameObject obj, bool loadedFromPrefab) + { + switch (item) { + case Bumper bumper: return bumper.SetupGameObject(obj, this, loadedFromPrefab); + case Flipper flipper: return flipper.SetupGameObject(obj, this, loadedFromPrefab); + case Gate gate: return gate.SetupGameObject(obj, this, loadedFromPrefab); + case HitTarget hitTarget: return hitTarget.SetupGameObject(obj, this, loadedFromPrefab); + case Kicker kicker: return kicker.SetupGameObject(obj, this, loadedFromPrefab); + case Light lt: return lt.SetupGameObject(obj, loadedFromPrefab); + case Plunger plunger: return plunger.SetupGameObject(obj, this, loadedFromPrefab); + case Primitive primitive: return primitive.SetupGameObject(obj, this, loadedFromPrefab); + case Ramp ramp: return ramp.SetupGameObject(obj, this, loadedFromPrefab); + case Rubber rubber: return rubber.SetupGameObject(obj, this, loadedFromPrefab); + case Spinner spinner: return spinner.SetupGameObject(obj, this, loadedFromPrefab); + case Surface surface: return surface.SetupGameObject(obj, this, loadedFromPrefab); + case Table table: return table.SetupGameObject(obj, this, loadedFromPrefab); + case Trigger trigger: return trigger.SetupGameObject(obj, this, loadedFromPrefab); + case Trough trough: return trough.SetupGameObject(obj, loadedFromPrefab); + } + + throw new InvalidOperationException("Unknown item " + item + " to setup!"); + } + + private void ExtractPhysicsMaterials() + { + try { + // pause asset database refreshing + AssetDatabase.StartAssetEditing(); + + foreach (var material in _table.Data.Materials) { + + // skip material if physics aren't set. + if (material.Elasticity == 0 && material.ElasticityFalloff == 0 && material.ScatterAngle == 0 && material.Friction == 0) { + continue; + } + SavePhysicsMaterial(material); + } + + } finally { + // resume asset database refreshing + AssetDatabase.StopAssetEditing(); + AssetDatabase.Refresh(); + } + + foreach (var material in _table.Data.Materials) { + _physicalMaterials[material.Name] = AssetDatabase.LoadAssetAtPath($"{_assetsPhysicsMaterials}/{material.Name}.asset"); + } + } + + private string SavePhysicsMaterial(Engine.VPT.Material material) + { + var path = $"{_assetsPhysicsMaterials}/{material.Name}.asset"; + if (_options.SkipExistingMaterials && File.Exists(path)) { + return path; + } + + var mat = ScriptableObject.CreateInstance(); + mat.Elasticity = material.Elasticity; + mat.ElasticityFalloff = material.ElasticityFalloff; + mat.ScatterAngle = material.ScatterAngle; + mat.Friction = material.Friction; + AssetDatabase.CreateAsset(mat, path); + + return path; + } + + private void ExtractTextures() + { + try { + // pause asset database refreshing + AssetDatabase.StartAssetEditing(); + + foreach (var texture in _tableContainer.Textures) { + texture.WriteAsAsset(_assetsTextures, _options.SkipExistingTextures); + } + + } finally { + // resume asset database refreshing + AssetDatabase.StopAssetEditing(); + AssetDatabase.Refresh(); + } + + // now they are in the asset database, we can load them. + foreach (var texture in _tableContainer.Textures) { + var path = texture.GetUnityFilename(_assetsTextures, texture.IsWebp ? ".png" : null); + var unityTexture = texture.IsHdr + ? (Texture)AssetDatabase.LoadAssetAtPath(path) ?? AssetDatabase.LoadAssetAtPath(path) + : AssetDatabase.LoadAssetAtPath(path); + _textures[texture.Name.ToLower()] = unityTexture; + var legacyTexture = new LegacyTexture(texture.Data, unityTexture); + if (texture.IsWebp) { + legacyTexture.OriginalPath = texture.GetUnityFilename(_assetsTextures); + } + _tableAuthoring.LegacyContainer.Textures.Add(legacyTexture); + } + + // todo lazy load and don't import local textures once they are in the prefabs + foreach (var texture in Engine.VPT.Texture.LocalTextures) { + var path = texture.GetUnityFilename(_assetsTextures); + var unityTexture = AssetDatabase.LoadAssetAtPath(path); + _textures[texture.Name.ToLower()] = unityTexture; + } + } + + private void FreeTextures() + { + foreach (var texture in _tableContainer.Textures) { + texture.Data.FreeBinaryData(); + } + } + + private void ExtractSounds() + { + try { + // pause asset database refreshing + AssetDatabase.StartAssetEditing(); + + foreach (var sound in _tableContainer.Sounds) { + var path = sound.GetUnityFilename(_assetsSounds); + if (_options.SkipExistingSounds && File.Exists(path)) { + continue; + } + File.WriteAllBytes(path, sound.Data.GetFileData()); + sound.Data.Path = path; + } + + } finally { + // resume asset database refreshing + AssetDatabase.StopAssetEditing(); + AssetDatabase.Refresh(); + } + + // now they are in the asset database, we can load them. + foreach (var sound in _tableContainer.Sounds) { + var unitySound = AssetDatabase.LoadAssetAtPath(sound.GetUnityFilename(_assetsSounds)); + _tableAuthoring.LegacyContainer.Sounds.Add(new LegacySound(sound.Data, unitySound)); + } + } + + private void ConfigurePlayer() + { + // add the player script and default game engine + _tableGo.AddComponent(); + var dga = _tableGo.AddComponent(); + + // add trough if none available + if (!_tableContainer.HasTrough) { + CreateTrough(); + } + + // populate mappings + if (_tableContainer.Mappings.IsEmpty()) { + _tableContainer.Mappings.PopulateSwitches(dga.AvailableSwitches, _tableContainer.Switchables, _tableContainer.SwitchableDevices); + _tableContainer.Mappings.PopulateCoils(dga.AvailableCoils, _tableContainer.Coilables, _tableContainer.CoilableDevices); + + // wire up plunger + var plunger = _tableContainer.Plunger(); + if (plunger != null) { + _tableContainer.Mappings.Data.AddWire(new MappingsWireData { + Description = "Plunger", + Source = SwitchSource.InputSystem, + SourceInputActionMap = InputConstants.MapCabinetSwitches, + SourceInputAction = InputConstants.ActionPlunger, + Destination = WireDestination.Device, + DestinationDevice = plunger.Name, + DestinationDeviceItem = Plunger.PullCoilId + }); + } + } + } + + private void CreateTrough() + { + var troughData = new TroughData("Trough") { + BallCount = 4, + SwitchCount = 4, + Type = TroughType.ModernMech + }; + if (_tableContainer.Has("BallRelease")) { + troughData.PlayfieldExitKicker = "BallRelease"; + } + if (_tableContainer.Has("Drain")) { + troughData.PlayfieldEntrySwitch = "Drain"; + } + var item = new Trough(troughData) { + StorageIndex = _tableContainer.ItemDatas.Count() + }; + CreateGameObjects(item); + } + + private void CreateFileHierarchy() + { + if (!Directory.Exists("Assets/Tables/")) { + Directory.CreateDirectory("Assets/Tables/"); + } + + var assetsTableRoot = $"Assets/Tables/{_tableGo.name}/"; + if (!Directory.Exists(assetsTableRoot)) { + Directory.CreateDirectory(assetsTableRoot); + } + + _assetsPrefabs = $"{assetsTableRoot}Prefabs/"; + if (!Directory.Exists(_assetsPrefabs)) { + Directory.CreateDirectory(_assetsPrefabs); + } + + _assetsTextures = $"{assetsTableRoot}Textures/"; + if (!Directory.Exists(_assetsTextures)) { + Directory.CreateDirectory(_assetsTextures); + } + + _assetsMaterials = $"{assetsTableRoot}Materials/"; + if (!Directory.Exists(_assetsMaterials)) { + Directory.CreateDirectory(_assetsMaterials); + } + + _assetsPhysicsMaterials = $"{assetsTableRoot}Physics Materials/"; + if (!Directory.Exists(_assetsPhysicsMaterials)) { + Directory.CreateDirectory(_assetsPhysicsMaterials); + } + + _assetsMeshes = $"{assetsTableRoot}Meshes/"; + if (!Directory.Exists(_assetsMeshes)) { + Directory.CreateDirectory(_assetsMeshes); + } + + _assetsSounds = $"{assetsTableRoot}Sounds/"; + if (!Directory.Exists(_assetsSounds)) { + Directory.CreateDirectory(_assetsSounds); + } + } + + private void CreateRootHierarchy(string tableName = null) + { + // set the GameObject name; this needs to happen after MakeSerializable because the name is set there as well + if (string.IsNullOrEmpty(tableName)) { + tableName = _table.Name; + + } else { + tableName = tableName + .Replace("%TABLENAME%", _table.Name) + .Replace("%INFONAME%", _tableContainer.InfoName); + } + + _tableGo = new GameObject(); + _playfieldGo = new GameObject("Playfield"); + var backglassGo = new GameObject("Backglass"); + var cabinetGo = new GameObject("Cabinet"); + + _tableAuthoring = _tableGo.AddComponent(); + _tableAuthoring.SetItem(_table, tableName); + + _playfieldGo.transform.SetParent(_tableGo.transform, false); + backglassGo.transform.SetParent(_tableGo.transform, false); + cabinetGo.transform.SetParent(_tableGo.transform, false); + + _playfieldGo.AddComponent(); + _playfieldGo.transform.localRotation = TablePlayfieldAuthoring.GlobalRotation; + _playfieldGo.transform.localPosition = new Vector3(-_table.Width / 2 * TablePlayfieldAuthoring.GlobalScale, 0f, _table.Height / 2 * TablePlayfieldAuthoring.GlobalScale); + _playfieldGo.transform.localScale = new Vector3(TablePlayfieldAuthoring.GlobalScale, TablePlayfieldAuthoring.GlobalScale, TablePlayfieldAuthoring.GlobalScale); + } + + private GameObject GetGroupParent(IItem item) + { + // create group parent if not created (if null, attach it to the table directly). + if (!string.IsNullOrEmpty(item.ItemGroupName)) { + if (!_groupParents.ContainsKey(item.ItemGroupName)) { + var parent = new GameObject(item.ItemGroupName); + parent.transform.SetParent(_playfieldGo.transform, false); + _groupParents[item.ItemGroupName] = parent; + } + } + var groupParent = !string.IsNullOrEmpty(item.ItemGroupName) + ? _groupParents[item.ItemGroupName] + : _playfieldGo; + + return groupParent; + } + + public Mesh GetMesh(string parentName, string name) + { + var filename = parentName == name + ? $"{parentName.ToFilename()}.mesh" + : $"{parentName.ToFilename()} ({name.ToFilename()}).mesh"; + var meshPath = Path.Combine(_assetsMeshes, filename); + return AssetDatabase.LoadAssetAtPath(meshPath); + } + + #region ITextureProvider + + public Texture GetTexture(string name) + { + if (!_textures.ContainsKey(name.ToLower())) { + throw new ArgumentException($"Texture \"{name.ToLower()}\" not loaded!"); + } + return _textures[name.ToLower()]; + } + + #endregion + + #region IMaterialProvider + + public bool HasMaterial(string name) => _materials.ContainsKey(name); + public Material GetMaterial(string name) => string.IsNullOrEmpty(name) ? null : _materials[name]; + public PhysicsMaterial GetPhysicsMaterial(string name) + { + if (string.IsNullOrEmpty(name)) { + return null; + } + if (_physicalMaterials.ContainsKey(name)) { + return _physicalMaterials[name]; + } + + var material = _tableAuthoring.Table.Data.Materials.FirstOrDefault(m => string.Equals(m.Name, name, StringComparison.CurrentCultureIgnoreCase)); + if (material != null) { + var path = SavePhysicsMaterial(material); + _physicalMaterials[material.Name] = AssetDatabase.LoadAssetAtPath(path); + return _physicalMaterials[material.Name]; + } + + return null; + } + + public void SaveMaterial(PbrMaterial vpxMaterial, Material material) + { + _materials[vpxMaterial.Id] = material; + var path = vpxMaterial.GetUnityFilename(_assetsMaterials); + if (_options.SkipExistingMaterials && File.Exists(path)) { + return; + } + AssetDatabase.CreateAsset(material, path); + } + + #endregion + } + + public class ConvertOptions + { + public bool SkipExistingTextures = true; + public bool SkipExistingSounds = true; + public bool SkipExistingMaterials = true; + public bool SkipExistingMeshes = true; + public bool SkipExistingPrefabs = true; + + public static readonly ConvertOptions SkipNone = new ConvertOptions + { + SkipExistingMaterials = false, + SkipExistingMeshes = false, + SkipExistingPrefabs = false, + SkipExistingSounds = false, + SkipExistingTextures = false + }; + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetImporter.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs.meta similarity index 83% rename from VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetImporter.cs.meta rename to VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs.meta index def433e33..c3c6abdeb 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxAssetImporter.cs.meta +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 718d6a0c402adef4c8c1e46a3f5c5275 +guid: 120b596a5c0233f4b955506c5fde7ff5 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/DotMatrixDisplayInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/DotMatrixDisplayInspector.cs index 71fc32bab..a8cb6a4ad 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/DotMatrixDisplayInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/DotMatrixDisplayInspector.cs @@ -30,7 +30,7 @@ public class DotMatrixDisplayInspector : DisplayInspector [NonSerialized] private DotMatrixDisplayAuthoring _mb; [NonSerialized] private DotMatrixDisplayAuthoring[] _mbs; - private void OnEnable() + private new void OnEnable() { _mb = target as DotMatrixDisplayAuthoring; base.OnEnable(); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/SegmentDisplayInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/SegmentDisplayInspector.cs index bbb877dc4..40fbeba45 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/SegmentDisplayInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/SegmentDisplayInspector.cs @@ -52,7 +52,7 @@ private static readonly (int, string)[] SeparatorTypes = { private string _testText; private bool _foldoutStyle = true; - private void OnEnable() + private new void OnEnable() { _mb = target as SegmentDisplayAuthoring; _mbs = targets.Select(t => t as SegmentDisplayAuthoring).ToArray(); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/TroughInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/TroughInspector.cs index aad1dc0eb..e88a75a5a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/TroughInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Inspectors/TroughInspector.cs @@ -92,7 +92,7 @@ public override void OnInspectorGUI() GUILayout.BeginVertical(); EditorGUILayout.LabelField("Switch status:", new GUIStyle(GUI.skin.label) { fontStyle = FontStyle.Bold }); - var troughApi = _table.GetComponent().TableApi.Trough(Item.Name); + var troughApi = _ta.GetComponent().TableApi.Trough(Item.Name); if (Data.Type != TroughType.ModernOpto && Data.Type != TroughType.ModernMech) { DrawSwitch("Drain Switch", troughApi.EntrySwitch); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilManager.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilManager.cs index 158f861fd..90a22e928 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilManager.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilManager.cs @@ -98,7 +98,7 @@ protected override void OnButtonBarGUI() if (GUILayout.Button("Populate All", GUILayout.ExpandWidth(false))) { RecordUndo("Populate all coil mappings"); - _tableAuthoring.Table.Mappings.PopulateCoils(GetAvailableEngineCoils(), _tableAuthoring.Table.Coilables, _tableAuthoring.Table.CoilableDevices); + _tableAuthoring.TableContainer.Mappings.PopulateCoils(GetAvailableEngineCoils(), _tableAuthoring.TableContainer.Coilables, _tableAuthoring.TableContainer.CoilableDevices); Reload(); LampManager.Refresh(); } @@ -214,7 +214,7 @@ private void RefreshCoils() private void RefreshCoilIds() { _gleCoils.Clear(); - _gleCoils.AddRange(_tableAuthoring.Table.Mappings.GetCoils(GetAvailableEngineCoils())); + _gleCoils.AddRange(_tableAuthoring.TableContainer.Mappings.GetCoils(GetAvailableEngineCoils())); } private GamelogicEngineCoil[] GetAvailableEngineCoils() diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Collections/CollectionManager.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Collections/CollectionManager.cs index 482c984e6..5c9a2effb 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Collections/CollectionManager.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Collections/CollectionManager.cs @@ -191,7 +191,7 @@ private void RebuildItemLists() rootCollection.AddChildren(itemNames.Select(n => new CollectionTreeElement(n)).ToArray()); //Keep the available items - var items = _tableAuthoring.Item.GameItems + var items = _tableAuthoring.TableContainer.GameItems .Where(i => !string.IsNullOrEmpty(i.Name) && !itemNames.Contains(i.Name)) .OrderBy(i => i.Name); rootAvailable.AddChildren(items.Select(i => new CollectionTreeElement(i.Name)).ToArray()); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ImageListData.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ImageListData.cs index ea3b31abc..5bbadecfb 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ImageListData.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ImageListData.cs @@ -14,27 +14,34 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using System.IO; + namespace VisualPinball.Unity.Editor { public class ImageListData : IManagerListData { [ManagerListColumn(Order = 0, Width = 200)] - public string Name => TextureData?.Name ?? ""; - [ManagerListColumn(Order = 1, Width = 200)] - public string Path => TextureData?.Path ?? ""; + public string Name => LegacyTexture.Name; + + [ManagerListColumn(Order = 1, Width = 300)] + public string Path => LegacyTexture.IsSet ? UnityEditor.AssetDatabase.GetAssetPath(LegacyTexture.Texture) : string.Empty; + [ManagerListColumn(Order = 2, HeaderName = "Image Size", Width = 100)] - public string ImageSize => TextureData == null ? "" : $"{TextureData.Width}x{TextureData.Height}"; + public string ImageSize => LegacyTexture.IsSet ? $"{LegacyTexture.Texture.width}x{LegacyTexture.Texture.height}" : string.Empty; + [ManagerListColumn(Order = 3, HeaderName = "In Use", Width = 50)] public bool InUse; + [ManagerListColumn(Order = 4, HeaderName = "Raw Size", Width = 100)] - public int RawSize { get { - if (TextureData == null) { return 0; } - if (TextureData.HasBitmap) { - return TextureData.Bitmap.Data.Length; - } - return TextureData.Binary.Bytes?.Length ?? 0; - } } - - public Engine.VPT.TextureData TextureData; + public long RawSize => LegacyTexture.IsSet ? LegacyTexture.Texture.width * LegacyTexture.Texture.height * 4 : 0; + + public readonly LegacyTexture LegacyTexture; + + public ImageListData(LegacyTexture legacyTexture, bool inUse) + { + LegacyTexture = legacyTexture; + InUse = inUse; + } + } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ImageManager.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ImageManager.cs index e1fc8be40..d7756beb3 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ImageManager.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ImageManager.cs @@ -14,13 +14,11 @@ // 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 System.IO; +using System.Linq; using NLog; using UnityEditor; using UnityEngine; -using VisualPinball.Engine.VPT; using Logger = NLog.Logger; namespace VisualPinball.Unity.Editor @@ -47,205 +45,94 @@ public override void OnEnable() } protected override void OnButtonBarGUI() { - if (GUILayout.Button("Update All", GUILayout.ExpandWidth(false))) { - UpdateAllImages(); + if (GUILayout.Button("Add Textures Referenced in Scene", GUILayout.ExpandWidth(false))) { + AddReferenced(); } } protected override void OnDataDetailGUI() { - SliderField("Alpha Mask", ref _selectedItem.TextureData.AlphaTestValue, 0, 255); - - EditorGUI.BeginChangeCheck(); - EditorGUILayout.BeginHorizontal(); - EditorGUILayout.PrefixLabel("Replace Image"); - var tex = (Texture2D)EditorGUILayout.ObjectField(null, typeof(Texture2D), false); - EditorGUILayout.EndHorizontal(); - if (EditorGUI.EndChangeCheck() && tex != null) { - ReplaceImageFromAsset(_selectedItem.TextureData, tex); - } - if (GUILayout.Button("Export Image")) { - ExportImage(); - } - if (GUILayout.Button("Export Image as PNG")) { - ExportImageAsPng(); - } + SliderField("Alpha Mask", ref _selectedItem.LegacyTexture.AlphaTestValue, 0, 255); + + if (_selectedItem.LegacyTexture.Texture != null) { - var unityTex = _tableAuthoring.GetTexture(_selectedItem.Name); - if (unityTex != null) { + if (GUILayout.Button("Locate")) { + EditorGUIUtility.PingObject(_selectedItem.LegacyTexture.Texture); + } + + const float padding = 4f; var rect = GUILayoutUtility.GetRect(new GUIContent(""), GUIStyle.none); - float aspect = (float)unityTex.height / unityTex.width; - rect.width = Mathf.Min(unityTex.width, rect.width); + var aspect = (float)_selectedItem.LegacyTexture.Texture.height / _selectedItem.LegacyTexture.Texture.width; + rect.yMin += padding; + rect.xMin += padding; + rect.width = Mathf.Min(_selectedItem.LegacyTexture.Texture.width, rect.width) - padding; rect.height = rect.width * aspect; - GUI.DrawTexture(rect, unityTex); - } - } + GUI.DrawTexture(rect, _selectedItem.LegacyTexture.Texture); - protected override void RenameExistingItem(ImageListData data, string newName) - { - string oldName = data.TextureData.Name; - - // give each editable item a chance to update its fields - string undoName = "Rename Image"; - foreach (var item in _tableAuthoring.GetComponentsInChildren()) { - RenameReflectedFields(undoName, item, item.TextureRefs, oldName, newName); + } else { + _selectedItem.LegacyTexture.Texture = (Texture)EditorGUILayout.ObjectField(_selectedItem.LegacyTexture.Texture, typeof(Texture), false); } - RecordUndo(undoName, data.TextureData); - - data.TextureData.Name = newName; } protected override List CollectData() { - List data = new List(); + var data = new List(); // collect list of in use textures - List inUseTextures = new List(); - foreach (var item in _tableAuthoring.GetComponentsInChildren()) { - var texRefs = item.TextureRefs; - if (texRefs == null) { continue; } - foreach (var texRef in texRefs) { - var texName = GetMemberValue(texRef, item.ItemData); - if (!string.IsNullOrEmpty(texName)) { - inUseTextures.Add(texName); - } - } - } + var inUseTextures = new HashSet(GetReferenced().Select(AssetDatabase.GetAssetPath)); - foreach (var t in _tableAuthoring.Textures) { - var texData = t.Data; - data.Add(new ImageListData { TextureData = texData, InUse = inUseTextures.Contains(texData.Name)}); + foreach (var t in _tableAuthoring.LegacyContainer.Textures) { + var inUse = false; + if (t.Texture != null) { + inUse = inUseTextures.Contains(AssetDatabase.GetAssetPath(t.Texture)); + } + data.Add(new ImageListData(t, inUse)); } return data; } - protected override void OnDataChanged(string undoName, ImageListData data) + private void AddReferenced() { - OnDataChanged(undoName, data.TextureData); - } + var inList = new HashSet(_tableAuthoring.LegacyContainer.Textures.Select(t => AssetDatabase.GetAssetPath(t.Texture))); - protected override void AddNewData(string undoName, string newName) { - Undo.RecordObject(_tableAuthoring, undoName); - - var newTex = new Engine.VPT.Texture(newName); - _tableAuthoring.Textures.Add(newTex); - _tableAuthoring.Item.Data.NumTextures = _tableAuthoring.Textures.Count; - } - - protected override void RemoveData(string undoName, ImageListData data) - { - Undo.RecordObject(_tableAuthoring, undoName); - - _tableAuthoring.Textures.Remove(data.Name); - _tableAuthoring.Item.Data.NumTextures = _tableAuthoring.Textures.Count; - } - - private void OnDataChanged(string undoName, TextureData textureData) - { - RecordUndo(undoName, textureData); - - // update any items using this tex - foreach (var item in _tableAuthoring.GetComponentsInChildren()) { - if (IsReferenced(item.TextureRefs, item.ItemData, textureData.Name)) { - item.MeshDirty = true; - Undo.RecordObject(item as UnityEngine.Object, undoName); + Undo.RecordObject(_tableAuthoring, "Add referenced textures"); + foreach (var refTexture in GetReferenced()) { + if (!inList.Contains(AssetDatabase.GetAssetPath(refTexture))) { + _tableAuthoring.LegacyContainer.Textures.Add(new LegacyTexture(refTexture)); } } + Reload(); } - private void RecordUndo(string undoName, TextureData textureData) + private IEnumerable GetReferenced() { - if (_tableAuthoring == null) { return; } - - // Run over table's texture scriptable object wrappers to find the one being edited and add to the undo stack - foreach (var tableTex in _tableAuthoring.Textures.SerializedObjects) { - if (tableTex.Data == textureData) { - Undo.RecordObject(tableTex, undoName); - break; + var referenced = new HashSet(); + foreach (var mr in _tableAuthoring.GetComponentsInChildren()) { + if (!mr.sharedMaterial) { + continue; } - } - } - - private void UpdateAllImages() - { - int countFound = 0; - foreach (var t in _tableAuthoring.Textures) { - if (File.Exists(t.Data.Path)) { - countFound++; - ReplaceImageFromPath(t.Data, t.Data.Path); + var mainTex = mr.sharedMaterial.mainTexture; + var normalTex = mr.sharedMaterial.GetTexture(RenderPipeline.Current.MaterialConverter.NormalMapProperty); + if (mainTex != null && !referenced.Contains(mainTex)) { + referenced.Add(mainTex); + } + if (normalTex != null && !referenced.Contains(normalTex)) { + referenced.Add(normalTex); } } - Logger.Info($"Update all images complete. Found files for {countFound} / {_tableAuthoring.Textures.Count}"); + return referenced; } - private void ReplaceImageFromPath(TextureData textureData, string path) { - if (_tableAuthoring == null || textureData == null || string.IsNullOrEmpty(path)) { return; } - - byte[] newBytes = null; - try { - newBytes = File.ReadAllBytes(path); - } catch (Exception ex) { - Logger.Error(ex); - } - if (newBytes == null) { return; } - - string undoName = "Replace Image"; - - _tableAuthoring.MarkDirty(textureData.Name); + protected override void AddNewData(string undoName, string newName) { Undo.RecordObject(_tableAuthoring, undoName); - OnDataChanged(undoName, textureData); - - textureData.Binary.Data = newBytes; - textureData.Binary.Size = newBytes.Length; - textureData.Path = path; - - // update size values assuming we loaded alright - var unityTex = _tableAuthoring.GetTexture(textureData.Name); - if (unityTex != null) { - textureData.Width = unityTex.width; - textureData.Height = unityTex.height; - } - } - - private void ReplaceImageFromAsset(TextureData textureData, Texture2D tex) - { - string path = AssetDatabase.GetAssetPath(tex); - if (!string.IsNullOrEmpty(path)) { - ReplaceImageFromPath(textureData, path); - } - } - - private void ExportImage() - { - if (_tableAuthoring == null || _selectedItem == null) { return; } - - var unityTex = _tableAuthoring.GetTexture(_selectedItem.TextureData.Name); - if (unityTex != null) { - string fileExt = Path.GetExtension(_selectedItem.TextureData.Path).TrimStart('.'); - if (string.IsNullOrEmpty(fileExt)) { - Logger.Error("Could not determine filetype from path"); - } - string savePath = EditorUtility.SaveFilePanelInProject("Export Image", unityTex.name, fileExt, "Export Image"); - if (!string.IsNullOrEmpty(savePath)) { - File.WriteAllBytes(savePath, _selectedItem.TextureData.Binary.Data); - AssetDatabase.ImportAsset(savePath); - } - } + _tableAuthoring.LegacyContainer.Textures.Add(new LegacyTexture()); } - private void ExportImageAsPng() + protected override void RemoveData(string undoName, ImageListData data) { - if (_tableAuthoring == null || _selectedItem == null) { return; } - - var unityTex = _tableAuthoring.GetTexture(_selectedItem.TextureData.Name); - if (unityTex != null) { - string savePath = EditorUtility.SaveFilePanelInProject("Export Image", unityTex.name, "png", "Export Image"); - if (!string.IsNullOrEmpty(savePath)) { - File.WriteAllBytes(savePath, unityTex.EncodeToPNG()); - AssetDatabase.ImportAsset(savePath); - } - } + Undo.RecordObject(_tableAuthoring, undoName); + _tableAuthoring.LegacyContainer.Textures.Remove(data.LegacyTexture); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Lamp/LampManager.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Lamp/LampManager.cs index fa875acd1..0e7ffc7c5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Lamp/LampManager.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Lamp/LampManager.cs @@ -100,7 +100,7 @@ protected override void OnButtonBarGUI() if (GUILayout.Button("Populate All", GUILayout.ExpandWidth(false))) { if (_tableAuthoring != null) { RecordUndo("Populate all lamp mappings"); - _tableAuthoring.Table.Mappings.PopulateLamps(GetAvailableEngineLamps(), _tableAuthoring.Table.Lightables); + _tableAuthoring.TableContainer.Mappings.PopulateLamps(GetAvailableEngineLamps(), _tableAuthoring.TableContainer.Lightables); Reload(); } } @@ -123,7 +123,7 @@ protected override void OnListViewItemRenderer(LampListData data, Rect cellRect, lampListData.Update(); - var lamp = _tableAuthoring.Table.Lightables.FirstOrDefault(c => c.Name == lampListData.PlayfieldItem); + var lamp = _tableAuthoring.TableContainer.Lightables.FirstOrDefault(c => c.Name == lampListData.PlayfieldItem); }); } @@ -200,7 +200,7 @@ private void RefreshLamps() private void RefreshLampIds() { _gleLamps.Clear(); - _gleLamps.AddRange(_tableAuthoring.Table.Mappings.GetLamps(GetAvailableEngineLamps())); + _gleLamps.AddRange(_tableAuthoring.TableContainer.Mappings.GetLamps(GetAvailableEngineLamps())); } private GamelogicEngineLamp[] GetAvailableEngineLamps() diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/MaterialManager.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/MaterialManager.cs index 157b7a6c0..e67dea895 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/MaterialManager.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/MaterialManager.cs @@ -28,9 +28,6 @@ public class MaterialManager : ManagerWindow { protected override string DataTypeName => "Material"; - private bool _foldoutVisual = true; - private bool _foldoutPhysics = true; - [MenuItem("Visual Pinball/Material Manager", false, 403)] public static void ShowWindow() { @@ -45,19 +42,7 @@ public override void OnEnable() protected override void OnDataDetailGUI() { - if (_foldoutPhysics = EditorGUILayout.BeginFoldoutHeaderGroup(_foldoutPhysics, "Physics")) { - EditorGUI.indentLevel++; - PhysicsOptions(); - EditorGUI.indentLevel--; - } - EditorGUILayout.EndFoldoutHeaderGroup(); - - if (_foldoutVisual = EditorGUILayout.BeginFoldoutHeaderGroup(_foldoutVisual, "Visual")) { - EditorGUI.indentLevel++; - VisualOptions(); - EditorGUI.indentLevel--; - } - EditorGUILayout.EndFoldoutHeaderGroup(); + VisualOptions(); } protected override void RenameExistingItem(MaterialListData data, string newName) @@ -104,23 +89,11 @@ protected override void OnDataChanged(string undoName, MaterialListData data) { foreach (var item in _tableAuthoring.GetComponentsInChildren()) { if (IsReferenced(item.MaterialRefs, item.ItemData, data.Material.Name)) { - item.MeshDirty = true; Undo.RecordObject(item as Object, undoName); } } } - private void PhysicsOptions() - { - var mat = _selectedItem?.Material; - if (mat == null) { return; } - - FloatField("Elasticity", ref mat.Elasticity); - FloatField("Elasticity Falloff", ref mat.ElasticityFalloff); - FloatField("Friction", ref mat.Friction); - FloatField("Scatter Angle", ref mat.ScatterAngle); - } - private void VisualOptions() { var mat = _selectedItem?.Material; diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/SoundListData.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/SoundListData.cs index 1a5dc13c3..585101b7f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/SoundListData.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/SoundListData.cs @@ -21,18 +21,23 @@ namespace VisualPinball.Unity.Editor class SoundListData : IManagerListData { [ManagerListColumn(Order = 0, Width = 200)] - public string Name => SoundData?.Name ?? ""; + public string Name => LegacySound.Name; [ManagerListColumn(Order = 1, Width = 200)] - public string Path => SoundData?.Path ?? ""; + public string Path => LegacySound.IsSet ? UnityEditor.AssetDatabase.GetAssetPath(LegacySound.AudioClip) : string.Empty; [ManagerListColumn(Order = 2, HeaderName = "Output Target", Width = 100)] - public string Output => SoundData == null ? "" : $"{(SoundData.OutputTarget == SoundOutTypes.Table ? "Table" : "BackGlass")}"; + public string Output => LegacySound == null ? "" : $"{(LegacySound.OutputTarget == SoundOutTypes.Table ? "Table" : "BackGlass")}"; [ManagerListColumn(Order = 3, HeaderName = "Volume", Width = 100)] - public string Volume => SoundData == null ? "" : $"{SoundData.Volume.PercentageToRatio()}"; + public string Volume => LegacySound == null ? "" : $"{LegacySound.Volume.PercentageToRatio()}"; [ManagerListColumn(Order = 4, HeaderName = "Balance", Width = 100)] - public string Balance => SoundData == null ? "" : $"{SoundData.Balance.PercentageToRatio()}"; + public string Balance => LegacySound == null ? "" : $"{LegacySound.Balance.PercentageToRatio()}"; [ManagerListColumn(Order = 5, HeaderName = "Fade", Width = 100)] - public string Fade => SoundData == null ? "" : $"{SoundData.Fade.PercentageToRatio()}"; + public string Fade => LegacySound == null ? "" : $"{LegacySound.Fade.PercentageToRatio()}"; - public Engine.VPT.Sound.SoundData SoundData; + public readonly LegacySound LegacySound; + + public SoundListData(LegacySound legacySound) + { + LegacySound = legacySound; + } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/SoundManager.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/SoundManager.cs index 807d2c776..3a3eb0cc6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/SoundManager.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/SoundManager.cs @@ -14,34 +14,30 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using NLog; using System.Collections.Generic; -using UnityEngine; using UnityEditor; -using VisualPinball.Engine.VPT.Sound; +using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Unity.Editor.Utils; namespace VisualPinball.Unity.Editor { - class SoundManager : ManagerWindow + internal class SoundManager : ManagerWindow { protected override string DataTypeName => "Sound"; protected override float DetailsMaxWidth => 500.0f; - private static readonly NLog.Logger Logger = LogManager.GetCurrentClassLogger(); - /// /// Sound positions display /// private bool _displaySoundPosition = true; - private bool _displayAllSounds = false; + private bool _displayAllSounds; /// /// Auto framing, going to Top view and frame on whole table when focused to ease sound position visualization /// private bool _autoFrame = true; - private bool _needFraming = false; + private bool _needFraming; /// /// Table & selected sound position & size used for display @@ -49,7 +45,6 @@ class SoundManager : ManagerWindow private Vector3 _tableCenter = Vector3.zero; private Vector3 _tableSize = Vector3.zero; private Vector3 _selectedSoundPos = Vector3.zero; - private float _selectedSoundSize = 0.0f; private readonly Color _selectedColor = Color.yellow; private readonly Color _unselectedColor = new Color(0.25f, 0.25f, 0.25f, 0.75f); @@ -60,24 +55,18 @@ class SoundManager : ManagerWindow /// Audio Data Playback & Visualization /// private float[] _audioSamples; - private AudioClip _audioCLip; private GameObject _audioSource; private AudioSource _audioSourceComp; - /// - /// DetailGui - /// - private static string[] _soundOutTypeStrings = { + private static readonly string[] SoundOutTypeStrings = { "Table", "Backglass", }; - private static byte[] _soundOutTypeValues = { + private static readonly byte[] SoundOutTypeValues = { SoundOutTypes.Table, SoundOutTypes.Backglass, }; - - [MenuItem("Visual Pinball/Sound Manager", false, 404)] public static void ShowWindow() { @@ -106,8 +95,9 @@ protected override void OnButtonBarGUI() private void InitAudioSource() { if (_audioSource == null) { - _audioSource = new GameObject("SoundManager AudioSource"); - _audioSource.hideFlags = HideFlags.HideAndDontSave; + _audioSource = new GameObject("SoundManager AudioSource") { + hideFlags = HideFlags.HideAndDontSave + }; _audioSource.AddComponent(); _audioSourceComp = _audioSource.GetComponent(); } @@ -132,7 +122,7 @@ public override void OnEnable() public override void OnDisable() { - GameObject.DestroyImmediate(_audioSource); + DestroyImmediate(_audioSource); _audioSource = null; _audioSourceComp = null; SceneView.duringSceneGui -= OnSceneGUI; @@ -143,30 +133,38 @@ protected override void OnDataDetailGUI() { InitAudioSource(); - DropDownField("Output Target", ref _selectedItem.SoundData.OutputTarget, _soundOutTypeStrings, _soundOutTypeValues); - SliderField("Volume", ref _selectedItem.SoundData.Volume, -100, 100); - SliderField("Balance", ref _selectedItem.SoundData.Balance, -100, 100); - SliderField("Fade (Rear->Front)", ref _selectedItem.SoundData.Fade, -100, 100); + DropDownField("Output Target", ref _selectedItem.LegacySound.OutputTarget, SoundOutTypeStrings, SoundOutTypeValues); + SliderField("Volume", ref _selectedItem.LegacySound.Volume, -100, 100); + SliderField("Balance", ref _selectedItem.LegacySound.Balance, -100, 100); + SliderField("Fade (Rear->Front)", ref _selectedItem.LegacySound.Fade, -100, 100); EditorGUILayout.Space(); - var wfx = _selectedItem.SoundData.Wfx; - GUILayout.Label($"Length : {_audioCLip.length} s, Channels : {wfx.Channels}, BPS : {wfx.BitsPerSample}, Freq : {wfx.SamplesPerSec}"); - - if (GUILayout.Button(new GUIContent() { image = EditorGUIUtility.IconContent("PlayButton").image })) { - _audioSource.transform.position = _selectedSoundPos; - _audioSourceComp.volume = (_selectedItem.SoundData.Volume + 100) / 200.0f; - _audioSourceComp.panStereo = _selectedItem.SoundData.Balance / 100.0f; - _audioSourceComp.clip = _audioCLip; - _audioSourceComp.Play(); + var wfx = _selectedItem.LegacySound.Wfx; + if (_selectedItem.LegacySound.AudioClip != null) { + GUILayout.Label($"Length : {_selectedItem.LegacySound.AudioClip.length} s, Channels : {wfx.Channels}, BPS : {wfx.BitsPerSample}, Freq : {wfx.SamplesPerSec}"); + + if (GUILayout.Button(new GUIContent() { image = EditorGUIUtility.IconContent("PlayButton").image })) { + _audioSource.transform.position = _selectedSoundPos; + _audioSourceComp.volume = (_selectedItem.LegacySound.Volume + 100) / 200.0f; + _audioSourceComp.panStereo = _selectedItem.LegacySound.Balance / 100.0f; + _audioSourceComp.clip = _selectedItem.LegacySound.AudioClip; + _audioSourceComp.Play(); + } + + EditorGUILayout.Space(); + Rect curveRect = GUILayoutUtility.GetLastRect(); + curveRect.x += 10.0f; + curveRect.y += curveRect.height; + curveRect.width -= 20.0f; + curveRect.height = 100.0f; + Rect r = AudioCurveRendering.BeginCurveFrame(curveRect); + AudioCurveRendering.DrawCurve(r, x => _audioSamples[(int)((_audioSamples.Length - 1) * x + 0.5f)], Color.green); + AudioCurveRendering.EndCurveFrame(); + + } else { + _selectedItem.LegacySound.AudioClip = (AudioClip)EditorGUILayout.ObjectField(_selectedItem.LegacySound.AudioClip, typeof(AudioClip), false); } - Rect curveRect = GUILayoutUtility.GetLastRect(); - curveRect.x += 10.0f; - curveRect.y += curveRect.height; - curveRect.width -= 20.0f; - curveRect.height = 100.0f; - Rect r = AudioCurveRendering.BeginCurveFrame(curveRect); - AudioCurveRendering.DrawCurve(r, x => _audioSamples[(int)(((_audioSamples.Length - 1) * x) + 0.5f)], Color.green); - AudioCurveRendering.EndCurveFrame(); + } private void OnFocus() @@ -197,25 +195,20 @@ protected override void OnDataSelected() if (_audioSource != null && _audioSourceComp.isPlaying) { _audioSourceComp.Stop(); } - _audioCLip = AudioClip.Create(_selectedItem.Name, _selectedItem.SoundData.Data.Length * 8 / _selectedItem.SoundData.Wfx.BitsPerSample, _selectedItem.SoundData.Wfx.Channels, (int)_selectedItem.SoundData.Wfx.SamplesPerSec, false); - _audioSamples = _selectedItem.SoundData.ToFloats(); - if (_audioSamples != null && _audioSamples.Length > 0) { - _audioCLip.SetData(_audioSamples, 0); + if (_selectedItem.LegacySound.AudioClip) { + _audioSamples = new float[_selectedItem.LegacySound.AudioClip.samples * _selectedItem.LegacySound.AudioClip.channels]; + _selectedItem.LegacySound.AudioClip.GetData(_audioSamples, 0); } } } - - private bool _shouldDisplaySoundPosition => ( _tableAuthoring != null && - Event.current.type == EventType.Repaint && - (EditorWindow.focusedWindow == this || (EditorWindow.focusedWindow == SceneView.lastActiveSceneView && Selection.activeObject == _tableAuthoring.gameObject)) && - _displaySoundPosition && - _selectedItem != null && - _selectedItem.SoundData.OutputTarget == SoundOutTypes.Table); + private bool ShouldDisplaySoundPosition => _tableAuthoring != null && Event.current.type == EventType.Repaint + && (focusedWindow == this || focusedWindow == SceneView.lastActiveSceneView && Selection.activeObject == _tableAuthoring.gameObject) + && _displaySoundPosition && _selectedItem != null && _selectedItem.LegacySound.OutputTarget == SoundOutTypes.Table; //Draw the sound position based on Balance/Fade data - private void RenderSound(SoundData data, bool selected) + private void RenderSound(LegacySound data, bool selected) { var sndPos = _tableCenter; sndPos.x += _tableSize.x * 0.5f * data.Balance.PercentageToRatio(); @@ -229,7 +222,7 @@ private void RenderSound(SoundData data, bool selected) //Volume goes from -100 to 100 -> ratio var sphereSizeRatio = (data.Volume + 100) * 0.005f; - var sphereSize = (sphereSizeRatio * (maxSphereSize - minSphereSize)); + var sphereSize = sphereSizeRatio * (maxSphereSize - minSphereSize); col.a = 0.05f; Handles.color = col; Handles.DrawSolidDisc(sndPos, Vector3.up, sphereSize); @@ -241,26 +234,27 @@ private void RenderSound(SoundData data, bool selected) if (selected) { _selectedSoundPos = sndPos; - _selectedSoundSize = sphereSize; } } private void OnSceneGUI(SceneView sceneView) { - if (_tableAuthoring == null) return; + if (_tableAuthoring == null || _selectedItem == null) { + return; + } var bb = _tableAuthoring.Item.BoundingBox; - var sndData = _selectedItem.SoundData; + var sndData = _selectedItem.LegacySound; _tableCenter = new Vector3((bb.Right - bb.Left) * 0.5f, (bb.Bottom - bb.Top) * 0.5f, (bb.ZHigh - bb.ZLow) * 0.5f); _tableCenter = _tableAuthoring.gameObject.transform.TransformPoint(_tableCenter); _tableSize = new Vector3(bb.Width, bb.Height, bb.Depth); _tableSize = _tableAuthoring.gameObject.transform.TransformVector(_tableSize); - if (_shouldDisplaySoundPosition) { + if (ShouldDisplaySoundPosition) { if (_displayAllSounds) { - foreach (var snd in _tableAuthoring.Sounds) { - if (snd.Data != sndData) { - RenderSound(snd.Data, false); + foreach (var snd in _tableAuthoring.LegacyContainer.Sounds) { + if (snd != sndData) { + RenderSound(snd, false); } } } @@ -281,66 +275,24 @@ private void OnSceneGUI(SceneView sceneView) } } - protected override void OnDataChanged(string undoName, SoundListData data) - { - OnDataChanged(undoName, data.SoundData); - } - - private void OnDataChanged(string undoName, SoundData data) - { - RecordUndo(undoName, data); - } - - private void RecordUndo(string undoName, SoundData data) - { - if (_tableAuthoring == null) { return; } - - // Run over table's sound scriptable object wrappers to find the one being edited and add to the undo stack - foreach (var tableTex in _tableAuthoring.Sounds.SerializedObjects) { - if (tableTex.Data == data) { - Undo.RecordObject(tableTex, undoName); - break; - } - } - } - protected override void AddNewData(string undoName, string newName) { Undo.RecordObject(_tableAuthoring, undoName); - - var newSnd = new Sound(newName); - _tableAuthoring.Sounds.Add(newSnd); - _tableAuthoring.Item.Data.NumSounds = _tableAuthoring.Sounds.Count; + _tableAuthoring.LegacyContainer.Sounds.Add(new LegacySound()); } protected override void RemoveData(string undoName, SoundListData data) { Undo.RecordObject(_tableAuthoring, undoName); - - _tableAuthoring.Sounds.Remove(data.Name); - _tableAuthoring.Item.Data.NumSounds = _tableAuthoring.Sounds.Count; - } - - protected override void RenameExistingItem(SoundListData data, string newName) - { - string oldName = data.SoundData.Name; - - // give each editable item a chance to update its fields - string undoName = "Rename Sound"; - RecordUndo(undoName, data.SoundData); - - data.SoundData.Name = newName; + _tableAuthoring.LegacyContainer.Sounds.Remove(data.LegacySound); } protected override List CollectData() { - List data = new List(); - - foreach (var snd in _tableAuthoring.Sounds) { - var sndData = snd.Data; - data.Add(new SoundListData { SoundData = sndData }); + var data = new List(); + foreach (var s in _tableAuthoring.LegacyContainer.Sounds) { + data.Add(new SoundListData(s)); } - return data; } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchManager.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchManager.cs index dc0d94d9b..05e076dd9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchManager.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchManager.cs @@ -107,7 +107,7 @@ protected override void OnButtonBarGUI() if (GUILayout.Button("Populate All", GUILayout.ExpandWidth(false))) { RecordUndo("Populate all switch mappings"); - _tableAuthoring.Table.Mappings.PopulateSwitches(GetAvailableEngineSwitches(), _tableAuthoring.Table.Switchables, _tableAuthoring.Table.SwitchableDevices); + _tableAuthoring.TableContainer.Mappings.PopulateSwitches(GetAvailableEngineSwitches(), _tableAuthoring.TableContainer.Switchables, _tableAuthoring.TableContainer.SwitchableDevices); Reload(); } @@ -211,7 +211,7 @@ private void RefreshSwitches() private void RefreshSwitchIds() { _gleSwitches.Clear(); - _gleSwitches.AddRange(_tableAuthoring.Table.Mappings.GetSwitchIds(GetAvailableEngineSwitches())); + _gleSwitches.AddRange(_tableAuthoring.TableContainer.Mappings.GetSwitchIds(GetAvailableEngineSwitches())); } private GamelogicEngineSwitch[] GetAvailableEngineSwitches() diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs index ec896ff34..a0a1db4b3 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Toolbox/ToolboxEditor.cs @@ -70,12 +70,9 @@ private void OnGUI() }; if (GUILayout.Button("New Table")) { - const string tableName = "Table1"; - var rootGameObj = new GameObject(); - var table = new Table(new TableData {Name = tableName}); - var converter = rootGameObj.AddComponent(); - converter.Convert(tableName, table); - DestroyImmediate(converter); + var tableContainer = new FileTableContainer(); + var converter = new VpxSceneConverter(tableContainer); + var rootGameObj = converter.Convert(false); Selection.activeGameObject = rootGameObj; Undo.RegisterCreatedObjectUndo(rootGameObj, "New Table"); } @@ -178,9 +175,9 @@ private static bool CreateButton(string label, Texture icon, float iconSize, GUI private void CreateItem(Func create, string actionName) where TItem : IItem { - var table = _tableAuthoring.Table; - var item = create(table); - table.Add(item, true); + var tableContainer = _tableAuthoring.TableContainer; + tableContainer.Refresh(); + var item = create(tableContainer.Table); Selection.activeGameObject = CreateRenderable(item); ItemCreated?.Invoke(Selection.activeGameObject); Undo.RegisterCreatedObjectUndo(Selection.activeGameObject, actionName); @@ -188,24 +185,10 @@ private void CreateItem(Func create, string actionName) whe private GameObject CreateRenderable(IItem item) { - var convertedItem = VpxConverter.CreateGameObjects(_tableAuthoring.Table, item, GetOrCreateParent(_tableAuthoring, item)); + var converter = new VpxSceneConverter(_tableAuthoring); + _tableAuthoring.TableContainer.Refresh(); + var convertedItem = converter.CreateGameObjects(item); return convertedItem.MainAuthoring.gameObject; } - - private static GameObject GetOrCreateParent(Component tb, IItem renderable) - { - var parent = string.IsNullOrEmpty(renderable.ItemGroupName) - ? tb.gameObject - : tb.gameObject.transform.Find(renderable.ItemGroupName)?.gameObject; - if (parent == null) { - parent = new GameObject(renderable.ItemGroupName); - parent.transform.parent = tb.gameObject.transform; - parent.transform.localPosition = Vector3.zero; - parent.transform.localRotation = Quaternion.identity; - parent.transform.localScale = Vector3.one; - } - - return parent; - } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperBaseMeshInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperBaseMeshInspector.cs index 3d3457cfb..a6e8ab634 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperBaseMeshInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperBaseMeshInspector.cs @@ -30,7 +30,7 @@ public override void OnInspectorGUI() return; } - MaterialField("Base Material", ref Data.BaseMaterial); + MaterialFieldLegacy("Base Material", ref Data.BaseMaterial); base.OnInspectorGUI(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperCapMeshInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperCapMeshInspector.cs index 01c96c41f..0e0b2f2d8 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperCapMeshInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperCapMeshInspector.cs @@ -31,7 +31,7 @@ public override void OnInspectorGUI() return; } - MaterialField("Cap Material", ref Data.CapMaterial); + MaterialFieldLegacy("Cap Material", ref Data.CapMaterial); base.OnInspectorGUI(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingMovementInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingAnimationInspector.cs similarity index 87% rename from VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingMovementInspector.cs rename to VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingAnimationInspector.cs index 5522c69cc..5cab136d2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingMovementInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingAnimationInspector.cs @@ -22,7 +22,7 @@ namespace VisualPinball.Unity.Editor { [CustomEditor(typeof(BumperRingAnimationAuthoring))] - public class BumperRingMovementInspector : ItemMovementInspector + public class BumperRingAnimationInspector : ItemAnimationInspector { public override void OnInspectorGUI() { diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingAnimationInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingAnimationInspector.cs.meta new file mode 100644 index 000000000..662dccfd2 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingAnimationInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95aa3bbfdda8b1e4185a1b3696e6443b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingMeshInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingMeshInspector.cs index 5654ad921..e2b2cc7c9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingMeshInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingMeshInspector.cs @@ -30,7 +30,7 @@ public override void OnInspectorGUI() return; } - MaterialField("Ring Material", ref Data.RingMaterial); + MaterialFieldLegacy("Ring Material", ref Data.RingMaterial); base.OnInspectorGUI(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingMovementInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingMovementInspector.cs.meta deleted file mode 100644 index 6a2fe4fb3..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperRingMovementInspector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 775c279142ff11240b3c4f44e8abfc8d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperSkirtMeshInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperSkirtMeshInspector.cs index d83ca5da2..36cec3afc 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperSkirtMeshInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Bumper/BumperSkirtMeshInspector.cs @@ -30,7 +30,7 @@ public override void OnInspectorGUI() return; } - MaterialField("Skirt Material", ref Data.SocketMaterial); + MaterialFieldLegacy("Skirt Material", ref Data.SocketMaterial); base.OnInspectorGUI(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperBaseMeshInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperBaseMeshInspector.cs index 0814ec7d5..259edca49 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperBaseMeshInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperBaseMeshInspector.cs @@ -30,8 +30,8 @@ public override void OnInspectorGUI() return; } - TextureField("Image", ref Data.Image); - MaterialField("Material", ref Data.Material); + TextureFieldLegacy( "VPX Image", ref Data.Image); + MaterialFieldLegacy("Material", ref Data.Material); base.OnInspectorGUI(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperInspector.cs index b39f0b944..3e6555a55 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperInspector.cs @@ -55,13 +55,13 @@ public override void OnInspectorGUI() EditorGUILayout.EndFoldoutHeaderGroup(); if (_foldoutBaseMesh = EditorGUILayout.BeginFoldoutHeaderGroup(_foldoutBaseMesh, "Base Mesh")) { - TextureField("Image", ref Data.Image); - MaterialField("Material", ref Data.Material); + TextureFieldLegacy("Texture", ref Data.Image); + MaterialFieldLegacy("Material", ref Data.Material); } EditorGUILayout.EndFoldoutHeaderGroup(); if (_foldoutRubberMesh = EditorGUILayout.BeginFoldoutHeaderGroup(_foldoutRubberMesh, "Rubber Mesh")) { - MaterialField("Rubber Material", ref Data.RubberMaterial); + MaterialFieldLegacy("Rubber Material", ref Data.RubberMaterial); ItemDataField("Rubber Thickness", ref Data.RubberThickness, onChanged: ItemAuthoring.OnRubberWidthUpdated); ItemDataField("Rubber Offset Height", ref Data.RubberHeight); ItemDataField("Rubber Width", ref Data.RubberWidth); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperRubberMeshInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperRubberMeshInspector.cs index 9b1cc75d8..ddefa30c7 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperRubberMeshInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Flipper/FlipperRubberMeshInspector.cs @@ -30,7 +30,7 @@ public override void OnInspectorGUI() return; } - MaterialField("Rubber Material", ref Data.RubberMaterial); + MaterialFieldLegacy("Rubber Material", ref Data.RubberMaterial); ItemDataField("Rubber Thickness", ref Data.RubberThickness); ItemDataField("Rubber Offset Height", ref Data.RubberHeight); ItemDataField("Rubber Width", ref Data.RubberWidth); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateInspector.cs index 0e2a6cc9b..e09e9c873 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Gate/GateInspector.cs @@ -44,7 +44,7 @@ protected void OnSceneGUI() if (transform != null && transform.parent != null) { position = transform.parent.TransformPoint(position); var axis = transform.TransformDirection(-Vector3.up); //Local direction of the gate gameObject is -up - var worldScale = 0.5f * VpxConverter.GlobalScale; + var worldScale = 0.5f * TablePlayfieldAuthoring.GlobalScale; var scale = Data.Length * worldScale; Handles.color = Color.white; Handles.DrawWireDisc(position, axis, scale); @@ -77,7 +77,7 @@ public override void OnInspectorGUI() if (_foldoutColorsAndFormatting = EditorGUILayout.BeginFoldoutHeaderGroup(_foldoutColorsAndFormatting, "Colors & Formatting")) { DropDownField("Type", ref Data.GateType, GateTypeLabels, GateTypeValues); ItemDataField("Show Bracket", ref Data.ShowBracket); - MaterialField("Material", ref Data.Material); + MaterialFieldLegacy("Material", ref Data.Material); } EditorGUILayout.EndFoldoutHeaderGroup(); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/HitTarget/HitTargetColliderInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/HitTarget/HitTargetColliderInspector.cs index 82141b29e..da56d6770 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/HitTarget/HitTargetColliderInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/HitTarget/HitTargetColliderInspector.cs @@ -34,7 +34,7 @@ public override void OnInspectorGUI() ItemDataField("Hit Threshold", ref Data.Threshold, false); EditorGUI.BeginDisabledGroup(Data.OverwritePhysics); - MaterialField("Physics Material", ref Data.PhysicsMaterial, false); + PhysicsMaterialField("Physics Material", ref ColliderAuthoring.PhysicsMaterial); EditorGUI.EndDisabledGroup(); ItemDataField("Overwrite Material Settings", ref Data.OverwritePhysics, false); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/HitTarget/HitTargetInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/HitTarget/HitTargetInspector.cs index 4c8fe9682..d558766b9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/HitTarget/HitTargetInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/HitTarget/HitTargetInspector.cs @@ -26,7 +26,6 @@ public class HitTargetInspector : ItemMainInspector : ItemInspector - where TMovementAuthoring : ItemMovementAuthoring + public class ItemAnimationInspector : ItemInspector + where TMovementAuthoring : ItemAnimationAuthoring where TData : ItemData where TItem : Item, IRenderable where TMainAuthoring : ItemMainRenderableAuthoring diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemAnimationInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemAnimationInspector.cs.meta new file mode 100644 index 000000000..3761e13fd --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemAnimationInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4375ce2f68fc4b4459e7b53e6a8c4b39 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemColliderInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemColliderInspector.cs index 9f36cc97d..2d3b8bc8c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemColliderInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemColliderInspector.cs @@ -124,7 +124,7 @@ protected bool HasErrors() private void NoDataError() { - EditorGUILayout.HelpBox($"Cannot find main component!\n\nYou must have a {typeof(TMainAuthoring).Name} component on either this GameObject, its parent or grand parent.", MessageType.Error); + EditorGUILayout.HelpBox($"Cannot find main component!\n\nYou must have a {typeof(TMainAuthoring).Name} component on this GameObject.", MessageType.Error); } private void InvalidParentError() diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemInspector.cs index 24f9ae8c3..47ad5ff19 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemInspector.cs @@ -24,6 +24,7 @@ using VisualPinball.Engine.Math; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Surface; +using Object = UnityEngine.Object; namespace VisualPinball.Unity.Editor { @@ -31,7 +32,7 @@ public abstract class ItemInspector : UnityEditor.Editor { public abstract MonoBehaviour UndoTarget { get; } - protected TableAuthoring _table; + protected TableAuthoring _ta; private AdvancedDropdownState _itemPickDropdownState; @@ -47,6 +48,7 @@ public abstract class ItemInspector : UnityEditor.Editor protected virtual void OnEnable() { + Undo.undoRedoPerformed += OnUndoRedoPerformed; // #if UNITY_EDITOR // // for convenience move item behavior to the top of the list @@ -63,12 +65,25 @@ protected virtual void OnEnable() // } // #endif - _table = (target as MonoBehaviour)?.gameObject.GetComponentInParent(); + _ta = (target as MonoBehaviour)?.gameObject.GetComponentInParent(); PopulateDropDownOptions(); } + private void OnUndoRedoPerformed() + { + switch (target) { + case IItemMeshAuthoring meshItem: + meshItem.IMainAuthoring.RebuildMeshes(); + break; + case IItemMainRenderableAuthoring mainItem: + mainItem.RebuildMeshes(); + break; + } + } + protected virtual void OnDisable() { + Undo.undoRedoPerformed -= OnUndoRedoPerformed; } public override void OnInspectorGUI() @@ -79,32 +94,30 @@ public override void OnInspectorGUI() GUILayout.Space(10); if (GUILayout.Button("Force Update Mesh")) { - item.SetMeshDirty(); + item.RebuildMeshes(); } - - item.RebuildMeshIfDirty(); } #endregion private void PopulateDropDownOptions() { - if (_table == null) return; + if (_ta == null) return; - if (_table.Data.Materials != null) { - _allMaterials = new string[_table.Data.Materials.Length + 1]; + if (_ta.Data.Materials != null) { + _allMaterials = new string[_ta.Data.Materials.Length + 1]; _allMaterials[0] = "- none -"; - for (var i = 0; i < _table.Data.Materials.Length; i++) { - _allMaterials[i + 1] = _table.Data.Materials[i].Name; + for (var i = 0; i < _ta.Data.Materials.Length; i++) { + _allMaterials[i + 1] = _ta.Data.Materials[i].Name; } Array.Sort(_allMaterials, 1, _allMaterials.Length - 1); } - if (_table.Textures != null) { - _allTextures = new string[_table.Textures.Count + 1]; - _allTextures[0] = "- none -"; - _table.Textures.Select(tex => tex.Name).ToArray().CopyTo(_allTextures, 1); - Array.Sort(_allTextures, 1, _allTextures.Length - 1); - } + // if (_table.Textures != null) { + // _allTextures = new string[_table.Textures.Count + 1]; + // _allTextures[0] = "- none -"; + // _table.Textures.Select(tex => tex.Name).ToArray().CopyTo(_allTextures, 1); + // Array.Sort(_allTextures, 1, _allTextures.Length - 1); + // } } protected void OnPreInspectorGUI() @@ -250,10 +263,10 @@ protected void ItemReferenceField(string label, st where TItemAuthoring : ItemAuthoring where TData : ItemData where TItem : Item, IRenderable { - if (!_refItems.ContainsKey(cacheKey) && _table != null) { + if (!_refItems.ContainsKey(cacheKey) && _ta != null) { var currentFieldName = field; - if (currentFieldName != null && _table.Table.Has(currentFieldName)) { - _refItems[cacheKey] = _table.gameObject.GetComponentsInChildren(true) + if (currentFieldName != null && _ta.TableContainer.Has(currentFieldName)) { + _refItems[cacheKey] = _ta.gameObject.GetComponentsInChildren(true) .FirstOrDefault(s => s.name == currentFieldName); } } @@ -294,9 +307,9 @@ protected void DropDownField(string label, ref T field, string[] optionString } } - protected void TextureField(string label, ref string field, bool dirtyMesh = true) + protected void TextureFieldLegacy(string label, ref string field, bool dirtyMesh = true) { - if (_table == null) return; + if (_ta == null) return; // if the field is set, but the tex isn't in our list, maybe it was added after this // inspector was instantiated, so re-grab our options from the table data @@ -312,14 +325,24 @@ protected void TextureField(string label, ref string field, bool dirtyMesh = tru } } EditorGUI.BeginChangeCheck(); - selectedIndex = EditorGUILayout.Popup(label, selectedIndex, _allTextures); + selectedIndex = EditorGUILayout.Popup("[VPX] " + label, selectedIndex, _allTextures); if (EditorGUI.EndChangeCheck() && selectedIndex >= 0 && selectedIndex < _allTextures.Length) { FinishEdit(label, dirtyMesh); field = selectedIndex == 0 ? string.Empty : _allTextures[selectedIndex]; } } - protected void MaterialField(string label, ref string field, bool dirtyMesh = true) + protected void PhysicsMaterialField(string label, ref PhysicsMaterial prevMat) + { + EditorGUI.BeginChangeCheck(); + var newMat = (PhysicsMaterial)EditorGUILayout.ObjectField(label, prevMat, typeof(PhysicsMaterial), false); + if (EditorGUI.EndChangeCheck()) { + Undo.RecordObject(UndoTarget, "Change physics material of " + UndoTarget.name); + prevMat = newMat; + } + } + + protected void MaterialFieldLegacy(string label, ref string field, bool dirtyMesh = true) { // if the field is set, but the material isn't in our list, maybe it was added after this // inspector was instantiated, so re-grab our mat options from the table data @@ -327,7 +350,7 @@ protected void MaterialField(string label, ref string field, bool dirtyMesh = tr PopulateDropDownOptions(); } - DropDownField(label, ref field, _allMaterials, _allMaterials, dirtyMesh); + DropDownField("[VPX] " + label, ref field, _allMaterials, _allMaterials, dirtyMesh); if (_allMaterials.Length > 0 && field == _allMaterials[0]) { field = string.Empty; // don't store the none value string in our data } @@ -342,7 +365,7 @@ protected void ObjectReferenceField(string label, string pickerLabel, string MonoBehaviour obj = null; if (!_objItems.ContainsKey(cacheKey)) { if (!string.IsNullOrEmpty(field)) { - obj = _table.gameObject.GetComponentsInChildren(true) + obj = _ta.gameObject.GetComponentsInChildren(true) .FirstOrDefault(s => s.Name == field) as MonoBehaviour; _objItems[cacheKey] = obj; } @@ -371,7 +394,7 @@ protected void ObjectReferenceField(string label, string pickerLabel, string var dropdown = new ItemSearchableDropdown( _itemPickDropdownState, - _table, + _ta, pickerLabel, item => { switch (item) { @@ -406,23 +429,20 @@ protected virtual void FinishEdit(string label, bool dirtyMesh = true) switch (target) { case IItemMeshAuthoring meshItem: - meshItem.IMainAuthoring.SetMeshDirty(); - Undo.RecordObject(UndoTarget, undoLabel); + Undo.RecordObjects(new Object[] {UndoTarget, UndoTarget.transform}, undoLabel); + meshItem.IMainAuthoring.RebuildMeshes(); break; case IItemColliderAuthoring colliderItem: - colliderItem.MainAuthoring.SetMeshDirty(); Undo.RecordObject(UndoTarget, undoLabel); break; case IItemMainRenderableAuthoring mainItem: - mainItem.SetMeshDirty(); - Undo.RecordObject(UndoTarget, undoLabel); + Undo.RecordObjects(new Object[] {UndoTarget, UndoTarget.transform}, undoLabel); + mainItem.RebuildMeshes(); break; } - EditorUtility.SetDirty(target); } - Undo.RecordObject(UndoTarget, undoLabel); if (target is IItemMainRenderableAuthoring item) { item.ItemDataChanged(); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemMovementInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemMovementInspector.cs.meta deleted file mode 100644 index 093195870..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/ItemMovementInspector.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b3ade9bf51966ad49a313e3686589a50 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs index e96de27af..ea3e90d3f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs @@ -40,7 +40,7 @@ public override void OnInspectorGUI() OnPreInspectorGUI(); if (_foldoutMesh = EditorGUILayout.BeginFoldoutHeaderGroup(_foldoutMesh, "Mesh")) { - MaterialField("Material", ref Data.Material); + MaterialFieldLegacy("Material", ref Data.Material); DropDownField("Display", ref Data.KickerType, KickerMeshInspector.KickerTypeLabels, KickerMeshInspector.KickerTypeValues); ItemDataField("Radius", ref Data.Radius); ItemDataField("Orientation", ref Data.Orientation); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerMeshInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerMeshInspector.cs index 97afcaf30..f29311fd0 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerMeshInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerMeshInspector.cs @@ -50,7 +50,7 @@ public override void OnInspectorGUI() return; } - MaterialField("Material", ref Data.Material); + MaterialFieldLegacy("Material", ref Data.Material); DropDownField("Display", ref Data.KickerType, KickerTypeLabels, KickerTypeValues); ItemDataField("Radius", ref Data.Radius); ItemDataField("Orientation", ref Data.Orientation); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Plunger/PlungerInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Plunger/PlungerInspector.cs index 9d071166a..6a928fd6a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Plunger/PlungerInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Plunger/PlungerInspector.cs @@ -51,8 +51,8 @@ public override void OnInspectorGUI() EditorGUI.EndDisabledGroup(); if (_foldoutColorsAndFormatting = EditorGUILayout.BeginFoldoutHeaderGroup(_foldoutColorsAndFormatting, "Colors & Formatting")) { - MaterialField("Material", ref Data.Material); - TextureField("Image", ref Data.Image); + MaterialFieldLegacy("Material", ref Data.Material); + TextureFieldLegacy("Texture", ref Data.Image); ItemDataField("Flat Frames", ref Data.AnimFrames); ItemDataField("Width", ref Data.Width); ItemDataField("Z Adjustment", ref Data.ZAdjust); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs index 7af542995..5367d2f6f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveColliderInspector.cs @@ -38,7 +38,7 @@ public override void OnInspectorGUI() EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup(Data.OverwritePhysics); - MaterialField("Physics Material", ref Data.PhysicsMaterial, false); + PhysicsMaterialField("Physics Material", ref ColliderAuthoring.PhysicsMaterial); EditorGUI.EndDisabledGroup(); ItemDataField("Overwrite Material Settings", ref Data.OverwritePhysics, false); EditorGUI.BeginDisabledGroup(!Data.OverwritePhysics); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveInspector.cs index bf74c3380..1ceeda074 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Primitive/PrimitiveInspector.cs @@ -28,7 +28,6 @@ public class PrimitiveInspector : ItemMainInspector0.1.0.0 0.1.0.0 0.1.0.0 - 7.3 + 8 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/ItemMatchAttribute.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/ItemMatchAttribute.cs index d0e62b25a..c931ab40f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/ItemMatchAttribute.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/ItemMatchAttribute.cs @@ -17,6 +17,7 @@ using System; using UnityEngine; using VisualPinball.Engine.Game; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Unity.Patcher { @@ -28,6 +29,6 @@ public abstract class ItemMatchAttribute : Attribute /// public string Ref; - public abstract bool Matches(Engine.VPT.Table.Table table, IRenderable item, GameObject obj); + public abstract bool Matches(FileTableContainer tableContainer, IRenderable item, GameObject obj); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/NameMatchAttribute.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/NameMatchAttribute.cs index 06fdbd27a..93b4757a2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/NameMatchAttribute.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/NameMatchAttribute.cs @@ -17,6 +17,7 @@ using System; using UnityEngine; using VisualPinball.Engine.Game; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Unity.Patcher { @@ -34,7 +35,7 @@ public NameMatchAttribute(string name) _name = name; } - public override bool Matches(Engine.VPT.Table.Table table, IRenderable item, GameObject obj) + public override bool Matches(FileTableContainer tableContainer, IRenderable item, GameObject obj) { return IgnoreCase ? string.Equals(item.Name, _name, StringComparison.CurrentCultureIgnoreCase) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/RenderPipelineAttribute.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/RenderPipelineAttribute.cs index 549b35a00..f245f74f0 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/RenderPipelineAttribute.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Item/RenderPipelineAttribute.cs @@ -16,6 +16,7 @@ using UnityEngine; using VisualPinball.Engine.Game; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Unity.Patcher.Matcher.Item { @@ -31,7 +32,7 @@ public RenderPipelineAttribute(RenderPipelineType type) _type = type; } - public override bool Matches(Engine.VPT.Table.Table table, IRenderable item, GameObject obj) + public override bool Matches(FileTableContainer tableContainer, IRenderable item, GameObject obj) { return RenderPipeline.Current.Type == _type; } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/AnyMatchAttribute.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/AnyMatchAttribute.cs index 6c282ee68..8c3a797f2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/AnyMatchAttribute.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/AnyMatchAttribute.cs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using VisualPinball.Engine.VPT.Table; + namespace VisualPinball.Unity.Patcher { /// @@ -21,7 +23,7 @@ namespace VisualPinball.Unity.Patcher /// public class AnyMatchAttribute : TableMatchAttribute { - public override bool Matches(Engine.VPT.Table.Table table, string fileName) + public override bool Matches(FileTableContainer tableContainer, string fileName) { return true; } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/MetaMatchAttribute.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/MetaMatchAttribute.cs index a92673e54..ca91255f2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/MetaMatchAttribute.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/MetaMatchAttribute.cs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using VisualPinball.Engine.VPT.Table; + namespace VisualPinball.Unity.Patcher { /// @@ -26,12 +28,12 @@ public class MetaMatchAttribute : TableMatchAttribute public string TableName; public string AuthorName; - public override bool Matches(Engine.VPT.Table.Table table, string fileName) + public override bool Matches(FileTableContainer tableContainer, string fileName) { - if (TableName != null && table.InfoName != TableName) { + if (TableName != null && tableContainer.InfoName != TableName) { return false; } - if (AuthorName != null && table.InfoAuthorName != AuthorName) { + if (AuthorName != null && tableContainer.InfoAuthorName != AuthorName) { return false; } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/RenderPipelineAttribute.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/RenderPipelineAttribute.cs index 00bc968e8..b892fc979 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/RenderPipelineAttribute.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/RenderPipelineAttribute.cs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using VisualPinball.Engine.VPT.Table; + namespace VisualPinball.Unity.Patcher.Matcher.Table { /// @@ -28,7 +30,7 @@ public RenderPipelineAttribute(RenderPipelineType type) _type = type; } - public override bool Matches(Engine.VPT.Table.Table table, string fileName) + public override bool Matches(FileTableContainer tableContainer, string fileName) { return RenderPipeline.Current.Type == _type; } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/TableMatchAttribute.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/TableMatchAttribute.cs index c7bdee14a..f0f488dd9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/TableMatchAttribute.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/TableMatchAttribute.cs @@ -15,12 +15,13 @@ // along with this program. If not, see . using System; +using VisualPinball.Engine.VPT.Table; namespace VisualPinball.Unity.Patcher { [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public abstract class TableMatchAttribute : Attribute { - public abstract bool Matches(Engine.VPT.Table.Table table, string fileName); + public abstract bool Matches(FileTableContainer tableContainer, string fileName); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/TableNameMatchAttribute.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/TableNameMatchAttribute.cs index fd68e462b..976760ee1 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/TableNameMatchAttribute.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/Table/TableNameMatchAttribute.cs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +using VisualPinball.Engine.VPT.Table; + namespace VisualPinball.Unity.Patcher.Matcher.Table { /// @@ -28,9 +30,9 @@ public TableNameMatchAttribute(string name) _name = name; } - public override bool Matches(Engine.VPT.Table.Table table, string fileName) + public override bool Matches(FileTableContainer tableContainer, string fileName) { - return _name == null || table.Data.Name == _name; + return _name == null || tableContainer.Table.Data.Name == _name; } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Patcher.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Patcher.cs index f328ccad7..7360914db 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Patcher.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Patcher.cs @@ -32,20 +32,20 @@ namespace VisualPinball.Unity.Patcher public class Patcher : IPatcher { private readonly List _patchers = new List(); - private Table _table; + private FileTableContainer _tableContainer; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public void SetTable(Table table, string fileName) + public void Set(FileTableContainer tableContainer, string fileName) { - _table = table; + _tableContainer = tableContainer; var types = typeof(Patcher).Assembly.GetTypes(); foreach (var type in types) { var classMatchers = type .GetCustomAttributes(typeof(TableMatchAttribute), false) .Select(a => a as TableMatchAttribute) .Where(a => a != null) - .Where(a => a.Matches(table, fileName)) + .Where(a => a.Matches(_tableContainer, fileName)) .ToArray(); if (classMatchers.Length > 0) { @@ -73,7 +73,7 @@ public void ApplyPrePatches(IRenderable item) if (methodInfo != null) { foreach (var methodMatcher in methodMatchers) { var validArgs = true; - if (methodMatcher.Matches(_table, item, null)) { + if (methodMatcher.Matches(_tableContainer, item, null)) { var patcherParamInfos = methodInfo.GetParameters(); var patcherParams = new object[patcherParamInfos.Length]; @@ -114,7 +114,7 @@ public void ApplyPatches(IRenderable item, GameObject gameObject, GameObject tab if (methodInfo != null) { foreach (var methodMatcher in methodMatchers) { var validArgs = true; - if (methodMatcher.Matches(_table, item, gameObject)) { + if (methodMatcher.Matches(_tableContainer, item, gameObject)) { var patcherParamInfos = methodInfo.GetParameters(); var patcherParams = new object[patcherParamInfos.Length]; @@ -139,7 +139,10 @@ public void ApplyPatches(IRenderable item, GameObject gameObject, GameObject tab } } else if (pi.ParameterType == typeof(Table)) { - patcherParams[pi.Position] = _table; + patcherParams[pi.Position] = _tableContainer.Table; + + } else if (pi.ParameterType == typeof(FileTableContainer)) { + patcherParams[pi.Position] = _tableContainer; } else if (pi.ParameterType.GetInterfaces().Contains(typeof(IItem)) && item.GetType() == pi.ParameterType) { patcherParams[pi.Position] = item; diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/Collider/QuadTreeTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/Collider/QuadTreeTests.cs deleted file mode 100644 index 780211f91..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/Collider/QuadTreeTests.cs +++ /dev/null @@ -1,54 +0,0 @@ -// 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 NUnit.Framework; - -namespace VisualPinball.Unity.Test -{ - [TestFixture] - [Category("Visual Pinball")] - public class QuadTreeTests - { - [Test] - public unsafe void ShouldSerializeCorrectly() - { - // var bounds = new Rect3D(true); - // var hitQuad = new HitQuadTree(new List { - // new LineSeg(new Vertex2D(1f, 2f), new Vertex2D(3f, 4f), 5f, 6f, ItemType.Table), - // new HitCircle(new Vertex2D(7f, 8f), 9f, 10f, 11f, ItemType.Table), - // new LineSeg(new Vertex2D(12f, 13f), new Vertex2D(14f, 15f), 16f, 17f, ItemType.Table), - // }, bounds); - // - // var quadTreeBlobAssetRef = QuadTreeBlob.CreateBlobAssetReference( - // hitQuad, - // new HitPlane(new Vertex3D(0, 0, 1), 10f), - // new HitPlane(new Vertex3D(0, 0, -1), 20f) - // ); - // ref var collider1 = ref quadTreeBlobAssetRef.Value.QuadTree.Bounds[0].Value; - // ref var collider2 = ref quadTreeBlobAssetRef.Value.QuadTree.Bounds[1].Value; - // ref var collider3 = ref quadTreeBlobAssetRef.Value.QuadTree.Bounds[2].Value; - // ref var collider4 = ref quadTreeBlobAssetRef.Value.PlayfieldCollider.Value; - - // Assert.AreEqual(ColliderType.Line, collider1.Type); - // Assert.AreEqual(ColliderType.Circle, collider2.Type); - // Assert.AreEqual(ColliderType.Line, collider3.Type); - // Assert.AreEqual(ColliderType.Plane, collider4.Type); - // fixed (Unity.Physics.Collider.Collider* collider = &collider4) { - // Assert.AreEqual(new float3(0f, 0f, 1f), ((PlaneCollider*)collider)->Normal); - // } - } - } -} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/Collider/QuadTreeTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/Collider/QuadTreeTests.cs.meta deleted file mode 100644 index 6fda92635..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/Collider/QuadTreeTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7f9e650f32e059343bc68df5f90c4c40 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/DOTS.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/DOTS.meta deleted file mode 100644 index f1ff7de3a..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/DOTS.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b60c1606ecd22bf4b9b7545ab58cd5e2 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/DOTS/DynamicStructTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/DOTS/DynamicStructTests.cs deleted file mode 100644 index 797a378c2..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/DOTS/DynamicStructTests.cs +++ /dev/null @@ -1,191 +0,0 @@ -// 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 NUnit.Framework; -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; -using Unity.Entities; -using Unity.Mathematics; - -namespace VisualPinball.Unity.Test -{ - [TestFixture] - public class DynamicStructTests - { - // [Test] - // public unsafe void ShouldSerializeBlobAssetReference() - // { - // var quadTreeBlobAssetRef = QuadTree.CreateBlobAssetReference(); - // - // ref var collider1 = ref quadTreeBlobAssetRef.Value.Colliders[0].Value; - // ref var collider2 = ref quadTreeBlobAssetRef.Value.Colliders[1].Value; - // - // Assert.AreEqual(ColliderType.Line, collider1.Type); - // //Assert.AreEqual(new Aabb(1f, 3f, 20f, 4f, 5f, 6f), collider1.Aabb); - // fixed (Collider* collider = &collider1) { - // Assert.AreEqual(new float2(1f, 20f), ((LineCollider*)collider)->V1); - // Assert.AreEqual(new float2(1f, 20f), ((LineCollider*)collider)->GetV1()); - // } - // Assert.AreEqual(ColliderType.Point, collider2.Type); - // } - - [Test] - public unsafe void ShouldSerializeStruc() - { - var coll = LineCollider.Create(new float2(1f, 2f), new float2(3f, 4f), 5f, 6f); - var collider = &coll; - Assert.AreEqual(new float2(1f, 2f), ((LineCollider*)collider)->V1); - } - - [Test] - public void ShouldSerializeBlobArray() - { - // var hit = new Hit3DPoly(new[] { new Vertex3D(1, 2, 3), new Vertex3D(4, 5, 6) }); - // var coll = Poly3DCollider.Create(hit); - // - // Assert.AreEqual(hit.Rgv[0].ToUnityFloat3(), coll.Value._rgv[0]); - // Assert.AreEqual(hit.Rgv[1].ToUnityFloat3(), coll.Value._rgv[1]); - } - } - - public struct QuadTree - { - public BlobArray> Colliders; - - public static BlobAssetReference CreateBlobAssetReference() - { - using (var builder = new BlobBuilder(Allocator.Temp)) { - ref var rootQuadTree = ref builder.ConstructRoot(); - - var colliders = builder.Allocate(ref rootQuadTree.Colliders, 2); - LineCollider.Create(builder, ref colliders[0], new float2(1f, 20f), new float2(3f, 4f), 5f, 6f); - PointCollider.Create(builder, ref colliders[1], new float3(7f, 8f, 9f)); - - return builder.CreateBlobAssetReference(Allocator.Persistent); - } - } - } - - public struct Collider : ICollider - { - public ColliderHeader Header; - - public ColliderType Type => Header.Type; - public Aabb Aabb => Header.Aabb; - } - - public struct LineCollider : ICollider - { - public ColliderHeader Header; - public float2 V1; - public float2 V2; - - public float2 GetV1() => V1; - - public static void Create(BlobBuilder builder, ref BlobPtr dest, float2 v1, float2 v2, float zLow, float zHigh) - { - ref var linePtr = ref UnsafeUtility.As, BlobPtr>(ref dest); - ref var collider = ref builder.Allocate(ref linePtr); - collider.Init(v1, v2, zLow, zHigh); - } - - public static Collider Create(float2 v1, float2 v2, float zLow, float zHigh) - { - var dest = default(LineCollider); - dest.Init(v1, v2, zLow, zHigh); - return UnsafeUtility.As(ref dest); - } - - private void Init(float2 v1, float2 v2, float zLow, float zHigh) - { - Header.Type = ColliderType.Line; - Header.Aabb = GetAabb(v1, v2, zLow, zHigh); - - V1 = v1; - V2 = v2; - } - - private static Aabb GetAabb(float2 v1, float2 v2, float zLow, float zHigh) => new Aabb( - math.min(v1.x, v2.x), - math.max(v1.x, v2.x), - math.min(v1.y, v2.y), - math.max(v1.y, v2.y), - zLow, - zHigh - ); - } - - public struct PointCollider : ICollider - { - public ColliderHeader Header; - public float3 Pos; - - public static void Create(BlobBuilder builder, ref BlobPtr dest, float3 pos) - { - ref var linePtr = ref UnsafeUtility.As, BlobPtr>(ref dest); - ref var collider = ref builder.Allocate(ref linePtr); - collider.Init(pos); - } - - private void Init(float3 pos) - { - Header.Type = ColliderType.Point; - Header.Aabb = GetAabb(pos); - - Pos = pos; - } - - private static Aabb GetAabb(float3 pos) => new Aabb(pos.x, pos.x, pos.y, pos.y, pos.z, pos.z); - } - - public struct ColliderHeader - { - public ColliderType Type; - public Aabb Aabb; - } - - public enum ColliderType - { - Line, - Point, - } - - public interface ICollider - { - - } - - - public struct Aabb - { - public float Left; - public float Top; - public float Right; - public float Bottom; - public float ZLow; - public float ZHigh; - - public Aabb(float left, float right, float top, float bottom, float zLow, float zHigh) - { - Left = left; - Right = right; - Top = top; - Bottom = bottom; - ZLow = zLow; - ZHigh = zHigh; - } - } -} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/DOTS/DynamicStructTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/DOTS/DynamicStructTests.cs.meta deleted file mode 100644 index 8551a8589..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/DOTS/DynamicStructTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 6c2cbe7d4c146e7428564082511cf0e5 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Assets/Scenes.meta similarity index 77% rename from VisualPinball.Unity/VisualPinball.Unity.Test/Physics.meta rename to VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Assets/Scenes.meta index ed794c662..138b8ac2a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics.meta +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Assets/Scenes.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5bb7e273c3ccd354fa3576e3c9206892 +guid: 21f3fc0d73db44ab7b41bbadc9087ed2 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Assets/Scenes/SampleScene.unity b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Assets/Scenes/SampleScene.unity new file mode 100644 index 000000000..c39e58143 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Assets/Scenes/SampleScene.unity @@ -0,0 +1,267 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 705507994} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_GateFitMode: 2 + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/Collider.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Assets/Scenes/SampleScene.unity.meta similarity index 67% rename from VisualPinball.Unity/VisualPinball.Unity.Test/Physics/Collider.meta rename to VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Assets/Scenes/SampleScene.unity.meta index 0768b117a..952bd1e9e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/Physics/Collider.meta +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Assets/Scenes/SampleScene.unity.meta @@ -1,6 +1,5 @@ fileFormatVersion: 2 -guid: 3b5f5527b3e96b049a85e85e177021f6 -folderAsset: yes +guid: 9fc0d4010bbf28b4594072e72b8655ab DefaultImporter: externalObjects: {} userData: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/manifest.json b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/manifest.json new file mode 100644 index 000000000..8b2a02847 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/manifest.json @@ -0,0 +1,38 @@ +{ + "dependencies": { + "com.unity.test-framework": "1.1.27", + "com.unity.testtools.codecoverage": "1.1.0", + "org.visualpinball.engine.unity": "file:../../../..", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/packages-lock.json b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/packages-lock.json new file mode 100644 index 000000000..f373e119d --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/Packages/packages-lock.json @@ -0,0 +1,465 @@ +{ + "dependencies": { + "com.unity.burst": { + "version": "1.4.4", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.mathematics": "1.2.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.collections": { + "version": "0.15.0-preview.21", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.test-framework.performance": "2.3.1-preview", + "com.unity.burst": "1.4.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.entities": { + "version": "0.17.0-preview.41", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.4.1", + "com.unity.properties": "1.5.0-preview", + "com.unity.serialization": "1.5.0-preview", + "com.unity.collections": "0.15.0-preview.21", + "com.unity.mathematics": "1.2.1", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.test-framework.performance": "2.3.1-preview", + "com.unity.nuget.mono-cecil": "0.1.6-preview.2", + "com.unity.jobs": "0.8.0-preview.23", + "com.unity.scriptablebuildpipeline": "1.9.0", + "com.unity.platforms": "0.10.0-preview.10" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ext.nunit": { + "version": "1.0.6", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.inputsystem": { + "version": "1.0.2", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.jobs": { + "version": "0.8.0-preview.23", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.collections": "0.15.0-preview.21", + "com.unity.mathematics": "1.2.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.mathematics": { + "version": "1.2.1", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.nuget.mono-cecil": { + "version": "0.1.6-preview.2", + "depth": 2, + "source": "registry", + "dependencies": { + "nuget.mono-cecil": "0.1.6-preview" + }, + "url": "https://packages.unity.com" + }, + "com.unity.nuget.newtonsoft-json": { + "version": "2.0.0-preview", + "depth": 3, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.platforms": { + "version": "0.10.0-preview.10", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.properties": "1.6.0-preview", + "com.unity.properties.ui": "1.6.2-preview.1", + "com.unity.scriptablebuildpipeline": "1.6.4-preview", + "com.unity.serialization": "1.6.2-preview" + }, + "url": "https://packages.unity.com" + }, + "com.unity.properties": { + "version": "1.6.0-preview", + "depth": 3, + "source": "registry", + "dependencies": { + "com.unity.nuget.mono-cecil": "0.1.6-preview.2", + "com.unity.test-framework.performance": "2.3.1-preview" + }, + "url": "https://packages.unity.com" + }, + "com.unity.properties.ui": { + "version": "1.6.2-preview.1", + "depth": 3, + "source": "registry", + "dependencies": { + "com.unity.properties": "1.6.0-preview", + "com.unity.serialization": "1.6.1-preview", + "com.unity.modules.uielements": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.rendering.hybrid": { + "version": "0.11.0-preview.42", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.entities": "0.17.0-preview.41" + }, + "url": "https://packages.unity.com" + }, + "com.unity.scriptablebuildpipeline": { + "version": "1.9.0", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.serialization": { + "version": "1.6.2-preview", + "depth": 3, + "source": "registry", + "dependencies": { + "com.unity.collections": "0.12.0-preview.13", + "com.unity.burst": "1.3.5", + "com.unity.jobs": "0.5.0-preview.14", + "com.unity.properties": "1.6.0-preview", + "com.unity.test-framework.performance": "2.3.1-preview" + }, + "url": "https://packages.unity.com" + }, + "com.unity.settings-manager": { + "version": "1.0.1", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.test-framework": { + "version": "1.1.27", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.test-framework.performance": { + "version": "2.3.1-preview", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.0", + "com.unity.nuget.newtonsoft-json": "2.0.0-preview" + }, + "url": "https://packages.unity.com" + }, + "com.unity.testtools.codecoverage": { + "version": "1.1.0", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.0.16", + "com.unity.settings-manager": "1.0.1" + }, + "url": "https://packages.unity.com" + }, + "nuget.mono-cecil": { + "version": "0.1.6-preview", + "depth": 3, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "org.visualpinball.engine.unity": { + "version": "file:../../../..", + "depth": 0, + "source": "local", + "dependencies": { + "com.unity.burst": "1.4.4", + "com.unity.collections": "0.15.0-preview.21", + "com.unity.entities": "0.17.0-preview.41", + "com.unity.rendering.hybrid": "0.11.0-preview.42", + "com.unity.jobs": "0.8.0-preview.23", + "com.unity.mathematics": "1.2.1", + "com.unity.inputsystem": "1.0.2", + "com.unity.test-framework": "1.1.22" + } + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.uielementsnative": "1.0.0" + } + }, + "com.unity.modules.uielementsnative": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/AudioManager.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/AudioManager.asset new file mode 100644 index 000000000..07ebfb05d --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/AudioManager.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 1024 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ClusterInputManager.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 000000000..e7886b266 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/DynamicsManager.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/DynamicsManager.asset new file mode 100644 index 000000000..cdc1f3eab --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0 + m_ClothInterCollisionStiffness: 0 + m_ContactsGeneration: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_AutoSimulation: 1 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 250, y: 250, z: 250} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_EnableUnifiedHeightmaps: 1 + m_DefaultMaxAngluarSpeed: 7 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/EditorBuildSettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 000000000..0147887ef --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: [] + m_configObjects: {} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/EditorSettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/EditorSettings.asset new file mode 100644 index 000000000..de5d0b2df --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/EditorSettings.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_ExternalVersionControlSupport: Visible Meta Files + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 0 + m_DefaultBehaviorMode: 0 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 0 + m_SpritePackerPaddingPower: 1 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref + m_ProjectGenerationRootNamespace: + m_CollabEditorSettings: + inProgressEnabled: 1 + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_AsyncShaderCompilation: 1 + m_EnterPlayModeOptionsEnabled: 0 + m_EnterPlayModeOptions: 3 + m_ShowLightmapResolutionOverlay: 1 + m_UseLegacyProbeSampleCount: 0 + m_SerializeInlineMappingsOnOneLine: 1 \ No newline at end of file diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/GraphicsSettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 000000000..43369e3c5 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,63 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_LegacyDeferred: + m_Mode: 1 + m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, + type: 0} + m_CustomRenderPipeline: {fileID: 0} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_LightsUseLinearIntensity: 0 + m_LightsUseColorTemperature: 0 + m_LogWhenShaderIsCompiled: 0 + m_AllowEnlightenSupportForUpgradedProject: 0 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/InputManager.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/InputManager.asset new file mode 100644 index 000000000..17c8f538e --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/InputManager.asset @@ -0,0 +1,295 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/NavMeshAreas.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 000000000..3b0b7c3d1 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,91 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/PackageManagerSettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 000000000..be4a7974e --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_EnablePreviewPackages: 0 + m_EnablePackageDependencies: 0 + m_AdvancedSettingsExpanded: 1 + m_ScopedRegistriesSettingsExpanded: 1 + oneTimeWarningShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_Capabilities: 7 + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_ErrorMessage: + m_Original: + m_Id: + m_Name: + m_Url: + m_Scopes: [] + m_IsDefault: 0 + m_Capabilities: 0 + m_Modified: 0 + m_Name: + m_Url: + m_Scopes: + - + m_SelectedScopeIndex: 0 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/Physics2DSettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 000000000..47880b1c8 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,56 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_AutoSimulation: 1 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 1 + m_AutoSyncTransforms: 0 + m_AlwaysShowColliders: 0 + m_ShowColliderSleep: 1 + m_ShowColliderContacts: 0 + m_ShowColliderAABB: 0 + m_ContactArrowScale: 0.2 + m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} + m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} + m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} + m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/PresetManager.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/PresetManager.asset new file mode 100644 index 000000000..67a94daef --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ProjectSettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ProjectSettings.asset new file mode 100644 index 000000000..fc810ffdf --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,678 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 22 + productGUID: 7b5d688dd16a2499a84b94d53fb84d92 + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: TestProject + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + m_HolographicTrackingLossScreen: {fileID: 0} + defaultScreenWidth: 1024 + defaultScreenHeight: 768 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 0 + m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + iosAllowHTTPDownload: 1 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 1 + androidBlitType: 0 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 1 + captureSingleScreen: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 1 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 0 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + stadiaPresentMode: 0 + stadiaTargetFramerate: 0 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 0 + vulkanEnableLateAcquireNextImage: 0 + m_SupportedAspectRatios: + 4:3: 1 + 5:4: 1 + 16:10: 1 + 16:9: 1 + Others: 1 + bundleVersion: 0.1 + preloadedAssets: [] + metroInputSource: 0 + wsaTransparentSwapchain: 0 + m_HolographicPauseOnTrackingLoss: 1 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + enable360StereoCapture: 0 + isWsaHolographicRemotingEnabled: 0 + enableFrameTimingStats: 0 + useHDRDisplay: 0 + D3DHDRBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 30 + resolutionScalingMode: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.1 + applicationIdentifier: {} + buildNumber: + Standalone: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 0 + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 19 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + APKExpansionFiles: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 1 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSTargetOSVersionString: 11.0 + tvOSSdkVersion: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: 11.0 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreenCustomXibPath: + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreeniPadCustomXibPath: + iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + shaderPrecisionModel: 0 + clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea + templatePackageId: com.unity.template.3d@5.0.4 + templateDefaultScene: Assets/Scenes/SampleScene.unity + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomProguardFile: 0 + AndroidTargetArchitectures: 1 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + AndroidMinifyWithR8: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: [] + m_BuildTargetBatching: + - m_BuildTarget: Standalone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: tvOS + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: Android + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: iPhone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: WebGL + m_StaticBatching: 0 + m_DynamicBatching: 0 + m_BuildTargetGraphicsJobs: + - m_BuildTarget: MacStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: Switch + m_GraphicsJobs: 1 + - m_BuildTarget: MetroSupport + m_GraphicsJobs: 1 + - m_BuildTarget: AppleTVSupport + m_GraphicsJobs: 0 + - m_BuildTarget: BJMSupport + m_GraphicsJobs: 1 + - m_BuildTarget: LinuxStandaloneSupport + m_GraphicsJobs: 1 + - m_BuildTarget: PS4Player + m_GraphicsJobs: 1 + - m_BuildTarget: iOSSupport + m_GraphicsJobs: 0 + - m_BuildTarget: WindowsStandaloneSupport + m_GraphicsJobs: 1 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobs: 1 + - m_BuildTarget: LuminSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AndroidPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: WebGLSupport + m_GraphicsJobs: 0 + m_BuildTargetGraphicsJobMode: + - m_BuildTarget: PS4Player + m_GraphicsJobMode: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobMode: 0 + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: AndroidPlayer + m_APIs: 150000000b000000 + m_Automatic: 0 + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: AppleTVSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: WebGLSupport + m_APIs: 0b000000 + m_Automatic: 1 + m_BuildTargetVRSettings: + - m_BuildTarget: Standalone + m_Enabled: 0 + m_Devices: + - Oculus + - OpenVR + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: [] + m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetNormalMapEncoding: [] + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + switchNMETAOverride: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchUseGOLDLinker: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchTitleNames_15: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchPublisherNames_15: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchTouchScreenUsage: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 0 + switchSupportedNpadCount: 8 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchPlayerConnectionEnabled: 1 + switchUseNewStyleFilepaths: 0 + switchUseMicroSleepForYield: 1 + switchMicroSleepForYieldTime: 25 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 1 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 0 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 16 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 1 + webGLWasmArithmeticExceptions: 0 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLDecompressionFallback: 0 + scriptingDefineSymbols: {} + additionalCompilerArguments: {} + platformArchitecture: {} + scriptingBackend: {} + il2cppCompilerConfiguration: {} + managedStrippingLevel: {} + incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 + allowUnsafeCode: 0 + useDeterministicCompilation: 1 + useReferenceAssemblies: 1 + enableRoslynAnalyzers: 1 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 1 + assemblyVersionValidation: 1 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: Template_3D + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: Template_3D + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} + metroSplashScreenUseBackgroundColor: 0 + platformCapabilities: {} + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} + cloudServicesEnabled: + UNet: 1 + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + apiCompatibilityLevel: 6 + activeInputHandler: 1 + cloudProjectId: + framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] + projectName: + organizationId: + cloudEnabled: 0 + legacyClampBlendShapeWeights: 0 + virtualTexturingSupportEnabled: 0 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ProjectVersion.txt b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ProjectVersion.txt new file mode 100644 index 000000000..95c2fc987 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 2020.3.13f1 +m_EditorVersionWithRevision: 2020.3.13f1 (71691879b7f5) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/QualitySettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/QualitySettings.asset new file mode 100644 index 000000000..7b7658d6e --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/QualitySettings.asset @@ -0,0 +1,232 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 5 + m_QualitySettings: + - serializedVersion: 2 + name: Very Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 15 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 1 + textureQuality: 1 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.3 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.4 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 16 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Medium + pixelLightCount: 1 + shadows: 1 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 1 + lodBias: 0.7 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 64 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: High + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Very High + pixelLightCount: 3 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 70 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1.5 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 1024 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Ultra + pixelLightCount: 4 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 4 + shadowDistance: 150 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 2 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4096 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + m_PerPlatformDefaultQuality: + Android: 2 + Lumin: 5 + Nintendo 3DS: 5 + Nintendo Switch: 5 + PS4: 5 + PSP2: 2 + Stadia: 5 + Standalone: 5 + WebGL: 3 + Windows Store Apps: 5 + XboxOne: 5 + iPhone: 2 + tvOS: 2 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/TagManager.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/TagManager.asset new file mode 100644 index 000000000..1c92a7840 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/TagManager.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 2 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/TimeManager.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/TimeManager.asset new file mode 100644 index 000000000..558a017e1 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/TimeManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: 0.02 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/UnityConnectSettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 000000000..6125b308a --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 0 + m_TestMode: 0 + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com + m_TestInitMode: 0 + CrashReportingSettings: + m_EventUrl: https://perf-events.cloud.unity3d.com + m_Enabled: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_TestMode: 0 + m_InitializeOnStartup: 1 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/VFXManager.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/VFXManager.asset new file mode 100644 index 000000000..3a95c98be --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/VFXManager.asset @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 0} + m_CopyBufferShader: {fileID: 0} + m_SortShader: {fileID: 0} + m_StripUpdateShader: {fileID: 0} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/VersionControlSettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 000000000..dca288142 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/XRSettings.asset b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/XRSettings.asset new file mode 100644 index 000000000..482590c19 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/TestProject~/ProjectSettings/XRSettings.asset @@ -0,0 +1,10 @@ +{ + "m_SettingKeys": [ + "VR Device Disabled", + "VR Device User Alert" + ], + "m_SettingValues": [ + "False", + "False" + ] +} \ No newline at end of file diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/Bumper.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/Bumper.meta deleted file mode 100644 index 17c393837..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/Bumper.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 48016f673620a854da6459b6e3f9b257 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/Bumper/BumperCollisionTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/Bumper/BumperCollisionTests.cs.meta deleted file mode 100644 index 9ba64dbde..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/Bumper/BumperCollisionTests.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 2d064609a2d85784d82bd201dd26c828 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/BumperTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/BumperTests.cs new file mode 100644 index 000000000..e668ed611 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/BumperTests.cs @@ -0,0 +1,95 @@ +// 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 System.Linq; +using NUnit.Framework; +using UnityEngine; +using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.Test.VPT.Bumper; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class BumperTests + { + [Test] + public void ShouldWriteImportedBumperData() + { + const string tmpFileName = "ShouldWriteBumperData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Bumper, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + BumperDataTests.ValidateTableData(writtenTable.Bumper("Bumper1").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + [Test] + public void ShouldWriteUpdatedBumperData() + { + const string tmpFileName = "ShouldWriteUpdatedBumperData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Bumper, options: ConvertOptions.SkipNone); + + var bumper = go.transform.GetComponentsInChildren().First(c => c.gameObject.name == "Bumper2"); + var bumperAuth = bumper.GetComponent(); + + bumperAuth.Data.Center.X = 128f; + bumperAuth.Data.Center.Y = 255f; + + go.GetComponent().TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + var writtenBumperData = writtenTable.Bumper("Bumper2").Data; + + Assert.AreEqual(128f, writtenBumperData.Center.X); + Assert.AreEqual(255f, writtenBumperData.Center.Y); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + [Test] + public void ShouldOnlyImportRing() + { + var table = new TableBuilder() + .AddBumper("Bumper") + .Build(); + + table.Bumper("Bumper").Data.IsBaseVisible = false; + table.Bumper("Bumper").Data.IsCapVisible = false; + table.Bumper("Bumper").Data.IsSocketVisible = false; + + var go = VpxImportEngine.ImportIntoScene(table, options: ConvertOptions.SkipNone); + + var baseGo = go.transform.Find("Playfield/Bumpers/Bumper/Base"); + var capGo = go.transform.Find("Playfield/Bumpers/Bumper/Cap"); + var socketGo = go.transform.Find("Playfield/Bumpers/Bumper/Skirt"); + var ringGo = go.transform.Find("Playfield/Bumpers/Bumper/Ring"); + + Assert.IsFalse(baseGo.GetComponent().enabled); + Assert.IsFalse(capGo.GetComponent().enabled); + Assert.IsFalse(socketGo.GetComponent().enabled); + Assert.IsTrue(ringGo.GetComponent().enabled); + + Object.DestroyImmediate(go); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/BumperTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/BumperTests.cs.meta new file mode 100644 index 000000000..c69a265f4 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/BumperTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37444b7cc7b307247a695e4b06703b3c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/FlipperTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/FlipperTests.cs new file mode 100644 index 000000000..1a9437c87 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/FlipperTests.cs @@ -0,0 +1,45 @@ +// 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.Flipper; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class FlipperTests + { + [Test] + public void ShouldWriteImportedFlipperData() + { + const string tmpFileName = "ShouldWriteFlipperData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Flipper, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + FlipperDataTests.ValidateFlipper(writtenTable.Flipper("FatFlipper").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/FlipperTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/FlipperTests.cs.meta new file mode 100644 index 000000000..f7bbbe70f --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/FlipperTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f9ffd3d80189c0c428c9b123e6814af8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/GateTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/GateTests.cs new file mode 100644 index 000000000..3eecc8519 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/GateTests.cs @@ -0,0 +1,45 @@ +// 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.Gate; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class GateTests + { + [Test] + public void ShouldWriteImportedGateData() + { + const string tmpFileName = "ShouldWriteGateData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Gate, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + GateDataTests.ValidateGateData(writtenTable.Gate("Data").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/GateTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/GateTests.cs.meta new file mode 100644 index 000000000..059edabd6 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/GateTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 30a5ff6330de39249bf639aa0882dc22 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/HitTargetTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/HitTargetTests.cs new file mode 100644 index 000000000..aa4f607a0 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/HitTargetTests.cs @@ -0,0 +1,44 @@ +// 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.HitTarget; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class HitTargetTests + { + [Test] + public void ShouldWriteImportedHitTargetData() + { + const string tmpFileName = "ShouldWriteHitTargetData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.HitTarget, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + HitTargetDataTests.ValidateHitTargetData(writtenTable.HitTarget("Data").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/HitTargetTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/HitTargetTests.cs.meta new file mode 100644 index 000000000..4b350f4b0 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/HitTargetTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ccb15060f888f14ca09b7ce0ebcb251 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/KickerTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/KickerTests.cs new file mode 100644 index 000000000..6e076fac8 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/KickerTests.cs @@ -0,0 +1,45 @@ +// 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.Kicker; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class KickerTests + { + [Test] + public void ShouldWriteImportedKickerData() + { + const string tmpFileName = "ShouldWriteKickerData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Kicker, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + KickerDataTests.ValidateKickerData(writtenTable.Kicker("Data").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/KickerTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/KickerTests.cs.meta new file mode 100644 index 000000000..87f5a069e --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/KickerTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9837e9bdeae4ef5409e1af0f73e91349 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LegacyDataTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LegacyDataTests.cs new file mode 100644 index 000000000..2de2c6036 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LegacyDataTests.cs @@ -0,0 +1,146 @@ +// 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 System.Linq; +using NUnit.Framework; +using UnityEngine; +using VisualPinball.Engine.Test.Test; +using VisualPinball.Engine.Test.VPT.Collection; +using VisualPinball.Engine.Test.VPT.Decal; +using VisualPinball.Engine.Test.VPT.DispReel; +using VisualPinball.Engine.Test.VPT.Flasher; +using VisualPinball.Engine.Test.VPT.LightSeq; +using VisualPinball.Engine.Test.VPT.TextBox; +using VisualPinball.Engine.Test.VPT.Timer; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class LegacyDataTests + { + [Test] + public void ShouldWriteImportedCollectionData() + { + const string tmpFileName = "ShouldWriteCollectionData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Collection, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + + var data = writtenTable.Collections.First(c => c.Name == "Flippers"); + CollectionDataTests.ValidateTableData(data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + [Test] + public void ShouldWriteImportedDecalData() + { + const string tmpFileName = "ShouldWriteDecalData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Decal, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + DecalDataTests.ValidateDecal0(writtenTable.Decal(0).Data); + DecalDataTests.ValidateDecal1(writtenTable.Decal(1).Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + [Test] + public void ShouldWriteImportedDispReelData() + { + const string tmpFileName = "ShouldWriteDispReelData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.DispReel, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + DispReelDataTests.ValidateDispReel1(writtenTable.DispReel("Reel1").Data); + DispReelDataTests.ValidateDispReel2(writtenTable.DispReel("Reel2").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + [Test] + public void ShouldWriteImportedFlasherData() + { + const string tmpFileName = "ShouldWriteFlasherData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Flasher, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + FlasherDataTests.ValidateFlasher(writtenTable.Flasher("Data").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + [Test] + public void ShouldWriteImportedLightSeqData() + { + const string tmpFileName = "ShouldWriteLightSeqData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.LightSeq, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + LightSeqDataTests.ValidateLightSeqData(writtenTable.LightSeq("LightSeq001").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + [Test] + public void ShouldWriteImportedTextBoxData() + { + const string tmpFileName = "ShouldWriteTextBoxData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.TextBox, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + TextBoxDataTests.ValidateTextBoxData(writtenTable.TextBox("TextBox001").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + [Test] + public void ShouldWriteImportedTimerData() + { + const string tmpFileName = "ShouldWriteTimerData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Timer, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + TimerDataTests.ValidateTimerData1(writtenTable.Timer("Timer1").Data); + TimerDataTests.ValidateTimerData2(writtenTable.Timer("Timer2").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LegacyDataTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LegacyDataTests.cs.meta new file mode 100644 index 000000000..07cad33a5 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LegacyDataTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 391716e0655b6d542ba7f102ab234c35 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LightTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LightTests.cs new file mode 100644 index 000000000..4d19829a9 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LightTests.cs @@ -0,0 +1,45 @@ +// 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.Light; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class LightTests + { + + [Test] + public void ShouldWriteImportedLightData() + { + const string tmpFileName = "ShouldWriteLightData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Light, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + LightDataTests.ValidateLightData(writtenTable.Light("Light1").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LightTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LightTests.cs.meta new file mode 100644 index 000000000..e4ac02c45 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/LightTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f26356f900c9ca34fb5b87c5b4d250b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PlungerTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PlungerTests.cs new file mode 100644 index 000000000..60beb2b74 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PlungerTests.cs @@ -0,0 +1,45 @@ +// 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.Plunger; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class PlungerTests + { + [Test] + public void ShouldWriteImportedPlungerData() + { + const string tmpFileName = "ShouldWritePlungerData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Plunger, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + PlungerDataTests.ValidatePlungerData1(writtenTable.Plunger("Plunger1").Data, false); + PlungerDataTests.ValidatePlungerData2(writtenTable.Plunger("Plunger2").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PlungerTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PlungerTests.cs.meta new file mode 100644 index 000000000..b9eb71097 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PlungerTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ba9d3989af52fc478466bee7dc6d391 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PrimitiveTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PrimitiveTests.cs new file mode 100644 index 000000000..2e228270f --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PrimitiveTests.cs @@ -0,0 +1,67 @@ +// 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.Primitive; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; +using Assert = Unity.Assertions.Assert; + +namespace VisualPinball.Unity.Test +{ + public class PrimitiveTests + { + [Test] + public void ShouldWriteImportedPrimitiveData() + { + const string tmpFileName = "ShouldWritePrimitiveData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Primitive, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + PrimitiveDataTests.ValidatePrimitiveData(writtenTable.Primitive("Cube").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + [Test] + public void ShouldWriteImportedMesh() + { + const string primitiveName = "Books"; + const string tmpFileName = "ShouldWriteImportedMesh.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Primitive, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + var writtenMesh = writtenTable.Primitive(primitiveName).GetMesh(); + + var table = FileTableContainer.Load(VpxPath.Primitive); + var originalMesh = table.Primitive(primitiveName).GetMesh(); + + Assert.AreEqual(originalMesh, writtenMesh); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PrimitiveTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PrimitiveTests.cs.meta new file mode 100644 index 000000000..a9c0a3b0a --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/PrimitiveTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8df96535dc568c14c9e0457ec42bb345 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RampTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RampTests.cs new file mode 100644 index 000000000..8b4c53596 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RampTests.cs @@ -0,0 +1,45 @@ +// 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.Ramp; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class RampTests + { + [Test] + public void ShouldWriteImportedRampData() + { + const string tmpFileName = "ShouldWriteRampData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Ramp, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + RampDataTests.ValidateRampData(writtenTable.Ramp("FlatL").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RampTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RampTests.cs.meta new file mode 100644 index 000000000..957c70d5f --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RampTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ccc7cc57e8daf1408e8cc992cdcb190 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RubberTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RubberTests.cs new file mode 100644 index 000000000..2d79f1a1a --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RubberTests.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.Rubber; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class RubberTests + { + [Test] + public void ShouldWriteImportedRubberData() + { + const string tmpFileName = "ShouldWriteRubberData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Rubber, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + RubberDataTests.ValidateRubberData1(writtenTable.Rubber("Rubber1").Data); + RubberDataTests.ValidateRubberData2(writtenTable.Rubber("Rubber2").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RubberTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RubberTests.cs.meta new file mode 100644 index 000000000..1b52458a4 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/RubberTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a243d076ec506a141bf81ce4784f1b75 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SpinnerTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SpinnerTests.cs new file mode 100644 index 000000000..7438a1190 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SpinnerTests.cs @@ -0,0 +1,45 @@ +// 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.Spinner; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class SpinnerTests + { + [Test] + public void ShouldWriteImportedSpinnerData() + { + const string tmpFileName = "ShouldWriteSpinnerData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Spinner, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + SpinnerDataTests.ValidateSpinnerData(writtenTable.Spinner("Data").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SpinnerTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SpinnerTests.cs.meta new file mode 100644 index 000000000..c761b4af8 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SpinnerTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 412ce854bbaf4454d931885048286405 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SurfaceTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SurfaceTests.cs new file mode 100644 index 000000000..86f6c3c55 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SurfaceTests.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.Spinner; +using VisualPinball.Engine.Test.VPT.Surface; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class SurfaceTests + { + [Test] + public void ShouldWriteImportedSurfaceData() + { + const string tmpFileName = "ShouldWriteSurfaceData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Surface, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + SurfaceDataTests.ValidateSurfaceData(writtenTable.Surface("TopInvisible").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SurfaceTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SurfaceTests.cs.meta new file mode 100644 index 000000000..00c12a887 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/SurfaceTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f731e6df31c9f644f914afffc9fbd67c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TableTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TableTests.cs new file mode 100644 index 000000000..b822e3367 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TableTests.cs @@ -0,0 +1,60 @@ +// 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.Flipper; +using VisualPinball.Engine.Test.VPT.Table; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class TableTests + { + [Test] + public void ShouldWriteImportedTableData() + { + const string tmpFileName = "ShouldWriteTableData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Table, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + TableDataTests.ValidateTableData(writtenTable.Table.Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + [Test] + public void ShouldWriteTableInfo() + { + const string tmpFileName = "ShouldWriteTableInfo.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Table, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + TableDataTests.ValidateTableInfo(writtenTable); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TableTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TableTests.cs.meta new file mode 100644 index 000000000..d1078d724 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TableTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a302c789e4636574d90811ec0cf8e295 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TriggerTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TriggerTests.cs new file mode 100644 index 000000000..b430462ae --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TriggerTests.cs @@ -0,0 +1,45 @@ +// 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.Trigger; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class TriggerTests + { + [Test] + public void ShouldWriteImportedTriggerData() + { + const string tmpFileName = "ShouldWriteTriggerData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Trigger, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + TriggerDataTests.ValidateTriggerData(writtenTable.Trigger("Data").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TriggerTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TriggerTests.cs.meta new file mode 100644 index 000000000..5c20f4d44 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TriggerTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8ef7b0c304a8d3345853f192f18b68fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TroughTests.cs b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TroughTests.cs new file mode 100644 index 000000000..d5aacbad6 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TroughTests.cs @@ -0,0 +1,44 @@ +// 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.Trough; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Unity.Editor; + +namespace VisualPinball.Unity.Test +{ + public class TroughTests + { + [Test] + public void ShouldWriteImportedTroughData() + { + const string tmpFileName = "ShouldWriteTroughData.vpx"; + var go = VpxImportEngine.ImportIntoScene(VpxPath.Trough, options: ConvertOptions.SkipNone); + var ta = go.GetComponent(); + ta.TableContainer.Save(tmpFileName); + + var writtenTable = FileTableContainer.Load(tmpFileName); + TroughDataTests.ValidateTroughData(writtenTable.Trough("Trough1").Data); + + File.Delete(tmpFileName); + Object.DestroyImmediate(go); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TroughTests.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TroughTests.cs.meta new file mode 100644 index 000000000..bb5cc0fbe --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/TroughTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b71267c88a401c349b2968fcab8d5721 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.asmdef b/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.asmdef index 17218ff70..ef22bd0d8 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.asmdef +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.asmdef @@ -9,7 +9,8 @@ "Unity.Transforms", "VisualPinball.Engine", "VisualPinball.Engine.Test", - "VisualPinball.Unity" + "VisualPinball.Unity", + "VisualPinball.Unity.Editor" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.csproj b/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.csproj index 88d8aacc5..568feebdd 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.csproj +++ b/VisualPinball.Unity/VisualPinball.Unity.Test/VisualPinball.Unity.Test.csproj @@ -20,8 +20,10 @@ + + @@ -29,7 +31,7 @@ - + @@ -48,4 +50,10 @@ ..\Plugins\.unity\Unity.Burst.dll + + + + + + diff --git a/VisualPinball.Unity/VisualPinball.Unity/Common/SerializableDictionary.cs b/VisualPinball.Unity/VisualPinball.Unity/Common/SerializableDictionary.cs index a7cd4603e..5229b8ce5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Common/SerializableDictionary.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Common/SerializableDictionary.cs @@ -21,7 +21,7 @@ namespace VisualPinball.Unity { [Serializable] - internal class SerializableDictionary : Dictionary, ISerializationCallbackReceiver + public class SerializableDictionary : Dictionary, ISerializationCallbackReceiver { [SerializeField] private List keys = new List(); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Extensions/MaterialExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/Extensions/MaterialExtensions.cs index b787916f6..0cad67128 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Extensions/MaterialExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Extensions/MaterialExtensions.cs @@ -18,6 +18,7 @@ using System; using System.Text; +using VisualPinball.Engine.Common; using VisualPinball.Engine.VPT; using Material = UnityEngine.Material; @@ -25,30 +26,22 @@ namespace VisualPinball.Unity { public static class MaterialExtensions { - public static Material ToUnityMaterial(this PbrMaterial vpxMaterial, TableAuthoring table, Type objectType, StringBuilder debug = null) + public static Material ToUnityMaterial(this PbrMaterial vpxMaterial, IMaterialProvider materialProvider, ITextureProvider textureProvider, Type objectType, StringBuilder debug = null) { - if (table != null) - { - var existingMat = table.GetMaterial(vpxMaterial); - if (existingMat != null) - { - return existingMat; - } + if (materialProvider.HasMaterial(vpxMaterial.Id)) { + return materialProvider.GetMaterial(vpxMaterial.Id); } - var unityMaterial = RenderPipeline.Current.MaterialConverter.CreateMaterial(vpxMaterial, table, objectType, debug); + var unityMaterial = RenderPipeline.Current.MaterialConverter.CreateMaterial(vpxMaterial, textureProvider, objectType, debug); - if (table != null) - { - table.AddMaterial(vpxMaterial, unityMaterial); - } + materialProvider.SaveMaterial(vpxMaterial, unityMaterial); return unityMaterial; } public static string GetUnityFilename(this PbrMaterial vpMat, string folderName) { - return $"{folderName}/{vpMat.Id}.mat"; + return $"{folderName}/{vpMat.Id.ToFilename()}.mat"; } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Extensions/MathExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/Extensions/MathExtensions.cs index 5fcf321dd..5a2e63cae 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Extensions/MathExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Extensions/MathExtensions.cs @@ -144,36 +144,11 @@ internal static Aabb ToAabb(this Rect3D rect) return new Aabb(rect.Left, rect.Right, rect.Top, rect.Bottom, rect.ZLow, rect.ZHigh); } - public static float PercentageToRatio(this float percent) - { - return percent * 0.01f; - } - public static float PercentageToRatio(this int percent) { return percent * 0.01f; } - public static float RatioToPercentage(this float ratio) - { - return ratio * 100.0f; - } - - public static float3x3 ToUnityFloat3x3(this Matrix2D matrix) - { - return new float3x3( - matrix.M00, - matrix.M01, - matrix.M02, - matrix.M10, - matrix.M11, - matrix.M12, - matrix.M20, - matrix.M21, - matrix.M22 - ); - } - public static float3 ToEuler(this quaternion quaternion) { var q = quaternion.value; double3 res; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Extensions/MeshExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/Extensions/MeshExtensions.cs index 8e0971fd7..051a08ba6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Extensions/MeshExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Extensions/MeshExtensions.cs @@ -17,6 +17,7 @@ using UnityEngine; using UnityEngine.Rendering; using VisualPinball.Engine.Math; +using Mesh = VisualPinball.Engine.VPT.Mesh; namespace VisualPinball.Unity { @@ -24,10 +25,11 @@ public static class MeshExtensions { public const string AnimationShape = "animation"; - public static Engine.VPT.Mesh ToVpMesh(this Mesh unityMesh) + public static Mesh ToVpMesh(this UnityEngine.Mesh unityMesh) { - var vpMesh = new Engine.VPT.Mesh(unityMesh.name); - vpMesh.Vertices = new Vertex3DNoTex2[unityMesh.vertexCount]; + var vpMesh = new Mesh(unityMesh.name) { + Vertices = new Vertex3DNoTex2[unityMesh.vertexCount] + }; var unityVertices = unityMesh.vertices; var unityNormals = unityMesh.normals; @@ -57,11 +59,11 @@ public static Engine.VPT.Mesh ToVpMesh(this Mesh unityMesh) for (var i = 0; i < frameCount; i++) { unityMesh.GetBlendShapeFrameVertices(animationIndex, i, deltaVertices, deltaNormals, null); - var frameData = new Engine.VPT.Mesh.VertData[unityMesh.vertexCount]; + var frameData = new Mesh.VertData[unityMesh.vertexCount]; for (var j = 0; j < unityMesh.vertexCount; j++) { var vertex = deltaVertices[j] + unityVertices[j]; var normal = deltaNormals[j] + unityNormals[j]; - frameData[j] = new Engine.VPT.Mesh.VertData( + frameData[j] = new Mesh.VertData( vertex.x, vertex.y, vertex.z, normal.x, normal.y, normal.z); } @@ -73,14 +75,14 @@ public static Engine.VPT.Mesh ToVpMesh(this Mesh unityMesh) return vpMesh; } - public static Mesh ToUnityMesh(this Engine.VPT.Mesh vpMesh, string name = null) + public static UnityEngine.Mesh ToUnityMesh(this Mesh vpMesh, string name = null) { - var mesh = new Mesh { name = name ?? vpMesh.Name }; + var mesh = new UnityEngine.Mesh { name = name ?? vpMesh.Name }; vpMesh.ApplyToUnityMesh(mesh); return mesh; } - public static void ApplyToUnityMesh(this Engine.VPT.Mesh vpMesh, Mesh mesh) + public static void ApplyToUnityMesh(this Mesh vpMesh, UnityEngine.Mesh mesh) { if (vpMesh.Indices.Length > 65535) { mesh.indexFormat = IndexFormat.UInt32; @@ -100,7 +102,7 @@ public static void ApplyToUnityMesh(this Engine.VPT.Mesh vpMesh, Mesh mesh) mesh.vertices = vertices; mesh.normals = normals; mesh.uv = uv; - //mesh.RecalculateBounds(); // redundant if setting tringles + //mesh.RecalculateBounds(); // redundant if setting triangles // faces mesh.triangles = vpMesh.Indices; @@ -120,8 +122,8 @@ public static void ApplyToUnityMesh(this Engine.VPT.Mesh vpMesh, Mesh mesh) deltaVertices[i] = blendVertices[i].ToUnityVector3() - vertices[i]; deltaNormals[i] = blendVertices[i].ToUnityNormalVector3() - normals[i]; } - mesh.SetUVs(Engine.VPT.Mesh.AnimationUVChannelVertices, deltaVertices); - mesh.SetUVs(Engine.VPT.Mesh.AnimationUVChannelNormals, deltaNormals); + mesh.SetUVs(Mesh.AnimationUVChannelVertices, deltaVertices); + mesh.SetUVs(Mesh.AnimationUVChannelNormals, deltaNormals); } else if (vpMesh.AnimationFrames.Count > 0) { @@ -146,12 +148,12 @@ public static void ApplyToUnityMesh(this Engine.VPT.Mesh vpMesh, Mesh mesh) } } - public static Vector3 ToUnityVector3(this Engine.VPT.Mesh.VertData vpVert) + public static Vector3 ToUnityVector3(this Mesh.VertData vpVert) { return new Vector3(vpVert.X, vpVert.Y, vpVert.Z); } - public static Vector3 ToUnityNormalVector3(this Engine.VPT.Mesh.VertData vpVert) + public static Vector3 ToUnityNormalVector3(this Mesh.VertData vpVert) { return new Vector3(vpVert.Nx, vpVert.Ny, vpVert.Nz); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Extensions/SoundExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/Extensions/SoundExtensions.cs index f53cf4b64..70b451645 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Extensions/SoundExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Extensions/SoundExtensions.cs @@ -14,54 +14,20 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using System.Collections.Generic; +using System.IO; +using VisualPinball.Engine.Common; using VisualPinball.Engine.VPT.Sound; namespace VisualPinball.Unity { public static class SoundExtensions { - /// - /// Convert SoundData samples to -1.0/1.0 range floats - /// - /// - /// - public static float[] ToFloats(this SoundData sndData) + public static string GetUnityFilename(this Sound vpSound, string folderName = null) { - var wfx = sndData.Wfx; - var samples = new List(); - - switch (wfx.BitsPerSample) { - case 8: { - foreach (var data in sndData.Data) { - samples.Add((data - 128) / 128.0f); - } - break; - } - - case 16: { - for (var i = 0; i < sndData.Data.Length; i += 2) { - var data2 = sndData.Data[i + 1]; - var sndVal = sndData.Data[i] | (data2 < 128 ? (data2 << 8) : ((data2 - 256) << 8)); - samples.Add(sndVal / 32768.0f); - } - break; - } - - case 24: { - for (var i = 0; i < sndData.Data.Length; i += 3) { - var data3 = sndData.Data[i + 2]; - var sndVal = sndData.Data[i] | (sndData.Data[i + 1] << 8) | (data3 < 128 ? (data3 << 16) : ((data3 - 256) << 16)); - samples.Add(sndVal / 8388608.0f); - } - break; - } - - default: - break; - } - - return samples.ToArray(); + var fileName = vpSound.Name.ToFilename() + vpSound.FileExtension; + return folderName != null + ? Path.Combine(folderName, fileName) + : fileName; } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Extensions/TextureExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/Extensions/TextureExtensions.cs index 9cf59af0d..d0f785cf8 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Extensions/TextureExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Extensions/TextureExtensions.cs @@ -15,6 +15,7 @@ // along with this program. If not, see . using System; +using System.IO; using UnityEngine; using VisualPinball.Engine.Common; using VisualPinball.Engine.VPT; @@ -31,14 +32,19 @@ public static Texture2D ToUnityTexture(this Engine.VPT.Texture vpTex) return vpTex.IsHdr ? FromHdrBinary(vpTex) : FromBinary(vpTex); } - public static string GetUnityFilename(this Engine.VPT.Texture vpTex, string folderName = null) + public static string GetUnityFilename(this Engine.VPT.Texture vpTex, string folderName = null, string ext = null) { - var fileName = $"{vpTex.Name.ToNormalizedName()}{vpTex.FileExtension}"; + var fileName = vpTex.Name.ToFilename() + vpTex.FileExtension; return folderName != null - ? $"{folderName}/{fileName}" - : $"{fileName}"; + ? ext == null + ? Path.Combine(folderName, fileName) + : Path.Combine(folderName, Path.GetFileNameWithoutExtension(fileName) + ext) + : ext == null + ? fileName + : Path.GetFileNameWithoutExtension(fileName) + ext; } + private static Texture2D FromBinary(Engine.VPT.Texture vpTex) { var unityTex = new Texture2D(vpTex.Width, vpTex.Height, TextureFormat.RGBA32, true) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs index a73bc2447..7a1065e9a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/CoilPlayer.cs @@ -16,7 +16,6 @@ using System.Collections.Generic; using NLog; -using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Table; using Logger = NLog.Logger; @@ -29,7 +28,7 @@ public class CoilPlayer private readonly Dictionary _coilDevices = new Dictionary(); private readonly Dictionary> _coilAssignments = new Dictionary>(); - private Table _table; + private TableContainer _tableContainer; private IGamelogicEngine _gamelogicEngine; private LampPlayer _lampPlayer; @@ -39,9 +38,9 @@ public class CoilPlayer internal void RegisterCoil(IItem item, IApiCoil coilApi) => _coils[item.Name] = coilApi; internal void RegisterCoilDevice(IItem item, IApiCoilDevice coilDeviceApi) => _coilDevices[item.Name] = coilDeviceApi; - public void Awake(Table table, IGamelogicEngine gamelogicEngine, LampPlayer lampPlayer) + public void Awake(TableContainer tableContainer, IGamelogicEngine gamelogicEngine, LampPlayer lampPlayer) { - _table = table; + _tableContainer = tableContainer; _gamelogicEngine = gamelogicEngine; _lampPlayer = lampPlayer; } @@ -49,7 +48,7 @@ public void Awake(Table table, IGamelogicEngine gamelogicEngine, LampPlayer lamp public void OnStart() { if (_gamelogicEngine != null) { - var config = _table.Mappings; + var config = _tableContainer.Mappings; _coilAssignments.Clear(); foreach (var coilData in config.Data.Coils) { switch (coilData.Destination) { @@ -115,7 +114,6 @@ private void HandleCoilEvent(object sender, CoilEventArgs coilEvent) { if (_coilAssignments.ContainsKey(coilEvent.Id)) { CoilStatuses[coilEvent.Id] = coilEvent.IsEnabled; - Debug.LogWarning($"Setting coil {coilEvent.Id} to {coilEvent.IsEnabled}."); foreach (var destConfig in _coilAssignments[coilEvent.Id]) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DisplayPlayer.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/DisplayPlayer.cs index 2be59761c..ea272e442 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/DisplayPlayer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/DisplayPlayer.cs @@ -17,7 +17,6 @@ using System.Collections.Generic; using NLog; using UnityEngine; -using VisualPinball.Engine.VPT.Table; using Logger = NLog.Logger; namespace VisualPinball.Unity @@ -29,7 +28,7 @@ public class DisplayPlayer private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public void Awake(Table _, IGamelogicEngine gamelogicEngine) + public void Awake(IGamelogicEngine gamelogicEngine) { _gamelogicEngine = gamelogicEngine; _gamelogicEngine.OnDisplaysAvailable += HandleDisplayAvailable; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/LampPlayer.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/LampPlayer.cs index 83e852642..3f60631d9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/LampPlayer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/LampPlayer.cs @@ -32,7 +32,7 @@ public class LampPlayer private readonly Dictionary> _lampAssignments = new Dictionary>(); private readonly Dictionary> _lampMappings = new Dictionary>(); - private Table _table; + private TableContainer _tableContainer; private IGamelogicEngine _gamelogicEngine; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); @@ -40,16 +40,16 @@ public class LampPlayer internal Dictionary LampStatuses { get; } = new Dictionary(); internal void RegisterLamp(IItem item, IApiLamp lampApi) => _lamps[item.Name] = lampApi; - public void Awake(Table table, IGamelogicEngine gamelogicEngine) + public void Awake(TableContainer tableContainer, IGamelogicEngine gamelogicEngine) { - _table = table; + _tableContainer = tableContainer; _gamelogicEngine = gamelogicEngine; } public void OnStart() { if (_gamelogicEngine != null) { - var config = _table.Mappings; + var config = _tableContainer.Mappings; _lampAssignments.Clear(); _lampMappings.Clear(); foreach (var lampData in config.Data.Lamps) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs index 762a8cfe3..06507c25a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs @@ -24,7 +24,6 @@ using UnityEngine.InputSystem; using VisualPinball.Engine.Common; using VisualPinball.Engine.Game; -using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Bumper; using VisualPinball.Engine.VPT.Flipper; using VisualPinball.Engine.VPT.Gate; @@ -51,7 +50,7 @@ public class Player : MonoBehaviour public TableApi TableApi { get; private set; } // shortcuts - public Matrix4x4 TableToWorld => transform.localToWorldMatrix; + public Matrix4x4 TableToWorld => GetComponentInChildren().transform.localToWorldMatrix; [NonSerialized] public IGamelogicEngine GamelogicEngine; @@ -63,6 +62,7 @@ public class Player : MonoBehaviour [HideInInspector] [SerializeField] public string physicsEngineId; // table related + private TableContainer _tableContainer; private readonly List _apis = new List(); private readonly List _initializables = new List(); private readonly List _colliderGenerators = new List(); @@ -116,22 +116,25 @@ private void Awake() var tableComponent = gameObject.GetComponent(); var engineComponent = GetComponent(); + tableComponent.TableContainer.Refresh(); + TableApi.Data = tableComponent.Data; _initializables.Add(TableApi); _colliderGenerators.Add(TableApi); Table = tableComponent.Table; //tableComponent.CreateTable(tableComponent.Data); + _tableContainer = tableComponent.TableContainer; BallManager = new BallManager(Table, TableToWorld); _inputManager = new InputManager(); _inputManager.Enable(HandleInput); if (engineComponent != null) { GamelogicEngine = engineComponent; - _lampPlayer.Awake(Table, GamelogicEngine); - _coilPlayer.Awake(Table, GamelogicEngine, _lampPlayer); - _switchPlayer.Awake(Table, GamelogicEngine, _inputManager); - _wirePlayer.Awake(Table, _inputManager, _switchPlayer); - _displayPlayer.Awake(Table, GamelogicEngine); + _lampPlayer.Awake(_tableContainer, GamelogicEngine); + _coilPlayer.Awake(_tableContainer, GamelogicEngine, _lampPlayer); + _switchPlayer.Awake(_tableContainer, GamelogicEngine, _inputManager); + _wirePlayer.Awake(_tableContainer, _inputManager, _switchPlayer); + _displayPlayer.Awake(GamelogicEngine); } EngineProvider.Set(physicsEngineId); @@ -181,12 +184,15 @@ private void OnDestroy() public void RegisterBumper(Bumper bumper, Entity entity, Entity parentEntity, GameObject go) { + var colliderAuth = go.GetComponent(); var bumperApi = new BumperApi(bumper, entity, parentEntity, this); TableApi.Bumpers[bumper.Name] = bumperApi; _apis.Add(bumperApi); _initializables.Add(bumperApi); - _colliderGenerators.Add(bumperApi); - _hittables[entity] = bumperApi; + if (colliderAuth) { + _colliderGenerators.Add(bumperApi); + _hittables[entity] = bumperApi; + } _switchPlayer.RegisterSwitch(bumper, bumperApi); _coilPlayer.RegisterCoil(bumper, bumperApi); _wirePlayer.RegisterWire(bumper, bumperApi); @@ -194,15 +200,18 @@ public void RegisterBumper(Bumper bumper, Entity entity, Entity parentEntity, Ga public void RegisterFlipper(Flipper flipper, Entity entity, Entity parentEntity, GameObject go) { + var colliderAuth = go.GetComponent(); var flipperApi = new FlipperApi(flipper, entity, parentEntity, this); TableApi.Flippers[flipper.Name] = flipperApi; _apis.Add(flipperApi); _initializables.Add(flipperApi); - _colliderGenerators.Add(flipperApi); + if (colliderAuth) { + _colliderGenerators.Add(flipperApi); + _collidables[entity] = flipperApi; + _hittables[entity] = flipperApi; + } Flippers[entity] = flipper; - _hittables[entity] = flipperApi; _rotatables[entity] = flipperApi; - _collidables[entity] = flipperApi; _switchPlayer.RegisterSwitch(flipper, flipperApi); _coilPlayer.RegisterCoil(flipper, flipperApi); _wirePlayer.RegisterWire(flipper, flipperApi); @@ -214,35 +223,44 @@ public void RegisterFlipper(Flipper flipper, Entity entity, Entity parentEntity, public void RegisterGate(Gate gate, Entity entity, Entity parentEntity, GameObject go) { + var colliderAuth = go.GetComponent(); var gateApi = new GateApi(gate, entity, parentEntity, this); TableApi.Gates[gate.Name] = gateApi; _apis.Add(gateApi); _initializables.Add(gateApi); - _colliderGenerators.Add(gateApi); - _hittables[entity] = gateApi; + if (colliderAuth) { + _colliderGenerators.Add(gateApi); + _hittables[entity] = gateApi; + } _rotatables[entity] = gateApi; _switchPlayer.RegisterSwitch(gate, gateApi); } public void RegisterHitTarget(HitTarget hitTarget, Entity entity, Entity parentEntity, GameObject go) { - var hitTargetApi = new HitTargetApi(hitTarget, entity, parentEntity, this); + var colliderAuth = go.GetComponent(); + var hitTargetApi = new HitTargetApi(hitTarget, entity, parentEntity, colliderAuth == null ? null : colliderAuth.PhysicsMaterial, this); TableApi.HitTargets[hitTarget.Name] = hitTargetApi; _apis.Add(hitTargetApi); _initializables.Add(hitTargetApi); - _colliderGenerators.Add(hitTargetApi); - _hittables[entity] = hitTargetApi; + if (colliderAuth) { + _colliderGenerators.Add(hitTargetApi); + _hittables[entity] = hitTargetApi; + } _switchPlayer.RegisterSwitch(hitTarget, hitTargetApi); } public void RegisterKicker(Kicker kicker, Entity entity, Entity parentEntity, GameObject go) { + var colliderAuth = go.GetComponent(); var kickerApi = new KickerApi(kicker, entity, parentEntity, this); TableApi.Kickers[kicker.Name] = kickerApi; _apis.Add(kickerApi); _initializables.Add(kickerApi); - _colliderGenerators.Add(kickerApi); - _hittables[entity] = kickerApi; + if (colliderAuth) { + _colliderGenerators.Add(kickerApi); + _hittables[entity] = kickerApi; + } _switchPlayer.RegisterSwitch(kicker, kickerApi); _coilPlayer.RegisterCoil(kicker, kickerApi); _wirePlayer.RegisterWire(kicker, kickerApi); @@ -277,62 +295,91 @@ public void RegisterPlunger(Plunger plunger, Entity entity, Entity parentEntity, public void RegisterPrimitive(Primitive primitive, Entity entity, Entity parentEntity, GameObject go) { - var primitiveApi = new PrimitiveApi(primitive, entity, parentEntity, this); + var colliderAuth = go.GetComponent(); + var primitiveApi = new PrimitiveApi(primitive, entity, parentEntity, colliderAuth == null ? null : colliderAuth.PhysicsMaterial, this); TableApi.Primitives[primitive.Name] = primitiveApi; _apis.Add(primitiveApi); - _colliderGenerators.Add(primitiveApi); + if (colliderAuth) { + _colliderGenerators.Add(primitiveApi); + _hittables[entity] = primitiveApi; + } _initializables.Add(primitiveApi); - _hittables[entity] = primitiveApi; } public void RegisterRamp(Ramp ramp, Entity entity, Entity parentEntity, GameObject go) { - var rampApi = new RampApi(ramp, entity, parentEntity, this); + var colliderAuth = go.GetComponent(); + var rampApi = new RampApi(ramp, entity, parentEntity, colliderAuth == null ? null : colliderAuth.PhysicsMaterial, this); TableApi.Ramps[ramp.Name] = rampApi; _apis.Add(rampApi); _initializables.Add(rampApi); - _colliderGenerators.Add(rampApi); + if (colliderAuth) { + _colliderGenerators.Add(rampApi); + } } public void RegisterRubber(Rubber rubber, Entity entity, Entity parentEntity, GameObject go) { - var rubberApi = new RubberApi(rubber, entity, parentEntity, this); + var colliderAuth = go.GetComponent(); + var rubberApi = new RubberApi(rubber, entity, parentEntity, colliderAuth == null ? null : colliderAuth.PhysicsMaterial, this); TableApi.Rubbers[rubber.Name] = rubberApi; _apis.Add(rubberApi); _initializables.Add(rubberApi); - _colliderGenerators.Add(rubberApi); - _hittables[entity] = rubberApi; + if (colliderAuth) { + _colliderGenerators.Add(rubberApi); + _hittables[entity] = rubberApi; + } } public void RegisterSurface(Surface surface, Entity entity, Entity parentEntity, GameObject go) { - var surfaceApi = new SurfaceApi(surface, entity, parentEntity, this); + var colliderAuth = go.GetComponent(); + var surfaceApi = new SurfaceApi(surface, entity, parentEntity, colliderAuth == null ? null : colliderAuth.PhysicsMaterial, this); TableApi.Surfaces[surface.Name] = surfaceApi; _apis.Add(surfaceApi); _initializables.Add(surfaceApi); - _colliderGenerators.Add(surfaceApi); - _hittables[entity] = surfaceApi; + if (colliderAuth) { + _colliderGenerators.Add(surfaceApi); + _hittables[entity] = surfaceApi; + } _slingshots[entity] = surfaceApi; } public void RegisterSpinner(Spinner spinner, Entity entity, Entity parentEntity, GameObject go) { + var colliderAuth = go.GetComponent(); var spinnerApi = new SpinnerApi(spinner, entity, parentEntity, this); TableApi.Spinners[spinner.Name] = spinnerApi; _apis.Add(spinnerApi); _initializables.Add(spinnerApi); - _colliderGenerators.Add(spinnerApi); + if (colliderAuth) { + _colliderGenerators.Add(spinnerApi); + } _spinnables[entity] = spinnerApi; _rotatables[entity] = spinnerApi; _switchPlayer.RegisterSwitch(spinner, spinnerApi); } - public void RegisterTrigger(Trigger trigger, Entity entity, Entity parentEntity) + public void RegisterTrigger(Trigger trigger, Entity entity, Entity parentEntity, GameObject go) { + var colliderAuth = go.GetComponent(); var triggerApi = new TriggerApi(trigger, entity, parentEntity, this); TableApi.Triggers[trigger.Name] = triggerApi; _apis.Add(triggerApi); _initializables.Add(triggerApi); + if (colliderAuth) { + _colliderGenerators.Add(triggerApi); + _hittables[entity] = triggerApi; + } + _switchPlayer.RegisterSwitch(trigger, triggerApi); + } + + public void RegisterTrigger(Trigger trigger, Entity entity) + { + var triggerApi = new TriggerApi(trigger, entity, Entity.Null, this); + TableApi.Triggers[trigger.Name] = triggerApi; + _apis.Add(triggerApi); + _initializables.Add(triggerApi); _colliderGenerators.Add(triggerApi); _hittables[entity] = triggerApi; _switchPlayer.RegisterSwitch(trigger, triggerApi); @@ -401,8 +448,8 @@ public void OnEvent(in EventData eventData) public void AddDynamicWire(string switchId, string coilId) { - var switchMapping = Table.Mappings.Data.Switches.FirstOrDefault(c => c.Id == switchId); - var coilMapping = Table.Mappings.Data.Coils.FirstOrDefault(c => c.Id == coilId); + var switchMapping = _tableContainer.Mappings.Data.Switches.FirstOrDefault(c => c.Id == switchId); + var coilMapping = _tableContainer.Mappings.Data.Coils.FirstOrDefault(c => c.Id == coilId); if (switchMapping == null) { Logger.Warn($"Cannot add new hardware rule for unknown switch \"{switchId}\"."); return; @@ -416,13 +463,13 @@ public void AddDynamicWire(string switchId, string coilId) _wirePlayer.AddWire(wireMapping); // this is for showing it in the editor during runtime only - Table.Mappings.Data.AddWire(wireMapping); + _tableContainer.Mappings.Data.AddWire(wireMapping); } public void RemoveDynamicWire(string switchId, string coilId) { - var switchMapping = Table.Mappings.Data.Switches.FirstOrDefault(c => c.Id == switchId); - var coilMapping = Table.Mappings.Data.Coils.FirstOrDefault(c => c.Id == coilId); + var switchMapping = _tableContainer.Mappings.Data.Switches.FirstOrDefault(c => c.Id == switchId); + var coilMapping = _tableContainer.Mappings.Data.Coils.FirstOrDefault(c => c.Id == coilId); if (switchMapping == null) { Logger.Warn($"Cannot remove hardware rule for unknown switch \"{switchId}\"."); return; @@ -436,7 +483,7 @@ public void RemoveDynamicWire(string switchId, string coilId) _wirePlayer.RemoveWire(wireMapping); // this is for the editor during runtime only - var wire = Table.Mappings.Data.Wires.FirstOrDefault(w => + var wire = _tableContainer.Mappings.Data.Wires.FirstOrDefault(w => w.Description == wireMapping.Description && w.SourceDevice == wireMapping.SourceDevice && w.SourceDeviceItem == wireMapping.SourceDeviceItem && @@ -448,7 +495,7 @@ public void RemoveDynamicWire(string switchId, string coilId) w.DestinationDeviceItem == wireMapping.DestinationDeviceItem && w.DestinationPlayfieldItem == wireMapping.DestinationPlayfieldItem ); - Table.Mappings.Data.RemoveWire(wire); + _tableContainer.Mappings.Data.RemoveWire(wire); } #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs index 39eeead81..0eba4ac76 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchHandler.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using NLog; using Unity.Entities; using UnityEngine; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchPlayer.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchPlayer.cs index b0908623b..5c25b6d5d 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchPlayer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/SwitchPlayer.cs @@ -31,7 +31,7 @@ public class SwitchPlayer private readonly Dictionary _switchDevices = new Dictionary(); private readonly Dictionary> _keySwitchAssignments = new Dictionary>(); - private Table _table; + private TableContainer _tableContainer; private IGamelogicEngine _gamelogicEngine; private InputManager _inputManager; @@ -47,9 +47,9 @@ public class SwitchPlayer public bool SwitchExists(string name) => _switches.ContainsKey(name); public bool SwitchDeviceExists(string name) => _switchDevices.ContainsKey(name); - public void Awake(Table table, IGamelogicEngine gamelogicEngine, InputManager inputManager) + public void Awake(TableContainer tableContainer, IGamelogicEngine gamelogicEngine, InputManager inputManager) { - _table = table; + _tableContainer = tableContainer; _gamelogicEngine = gamelogicEngine; _inputManager = inputManager; } @@ -59,7 +59,7 @@ public void OnStart() // hook-up game switches if (_gamelogicEngine != null) { - var config = _table.Mappings; + var config = _tableContainer.Mappings; _keySwitchAssignments.Clear(); foreach (var switchData in config.Data.Switches) { switch (switchData.Source) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/VisualPinballSimulationSystemGroup.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/VisualPinballSimulationSystemGroup.cs index 4bb0bb9f6..4f089b59c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/VisualPinballSimulationSystemGroup.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/VisualPinballSimulationSystemGroup.cs @@ -21,7 +21,6 @@ using Unity.Entities; using Unity.Transforms; using VisualPinball.Engine.Common; -using Debug = UnityEngine.Debug; namespace VisualPinball.Unity { diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/WirePlayer.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/WirePlayer.cs index 5c2f263e6..ccd14b564 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/WirePlayer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/WirePlayer.cs @@ -30,7 +30,7 @@ public class WirePlayer private readonly Dictionary _wireDevices = new Dictionary(); private readonly Dictionary> _keyWireAssignments = new Dictionary>(); - private Table _table; + private TableContainer _tableContainer; private InputManager _inputManager; private SwitchPlayer _switchPlayer; @@ -41,16 +41,16 @@ public class WirePlayer internal void RegisterWire(IItem item, IApiWireDest wireApi) => _wires[item.Name] = wireApi; internal void RegisterWireDevice(IItem item, IApiWireDeviceDest wireDeviceApi) => _wireDevices[item.Name] = wireDeviceApi; - public void Awake(Table table, InputManager inputManager, SwitchPlayer switchPlayer) + public void Awake(TableContainer tableContainer, InputManager inputManager, SwitchPlayer switchPlayer) { - _table = table; + _tableContainer = tableContainer; _inputManager = inputManager; _switchPlayer = switchPlayer; } public void OnStart() { - var config = _table.Mappings; + var config = _tableContainer.Mappings; _keyWireAssignments.Clear(); foreach (var wireData in config.Data.Wires) { AddWire(wireData); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Import/ConvertedItem.cs b/VisualPinball.Unity/VisualPinball.Unity/Import/ConvertedItem.cs new file mode 100644 index 000000000..ff873e5cd --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Import/ConvertedItem.cs @@ -0,0 +1,243 @@ +// 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 System.Linq; +using Unity.Entities; +using UnityEngine; +using VisualPinball.Engine.VPT; +using Object = UnityEngine.Object; + +namespace VisualPinball.Unity +{ + /// + /// An untyped interface for . + /// + public interface IConvertedItem + { + /// + /// Type of the main component. Used to check whether a sub component + /// has the correct parent. + /// + Type MainAuthoringType { get; } + + /// + /// Main authoring component + /// + IItemMainAuthoring MainAuthoring { get; } + + /// + /// List of mesh authoring components + /// + IEnumerable MeshAuthoring { get; } + + /// + /// Collider authoring component + /// + IItemColliderAuthoring ColliderAuthoring { get; } + + /// + /// If false, the mesh is saved as an asset in the asset folder. + /// + bool IsProceduralMesh { get; set; } + + /// + /// Checks whether this item is correctly attached to a given parent. + /// + /// Parent to check + /// true if valid, false otherwise. + bool IsValidChild(IConvertedItem parent); + + /// + /// Destroys the game item inclusively all children. + /// + void Destroy(); + + /// + /// Destroys the game items of all mesh components. Should only be + /// called when the mesh component sits on a different game object + /// than the main component. + /// + void DestroyMeshComponents(); + + /// + /// Destroys the collider component. If the collider component sits on + /// a different game object than the main component, the game object + /// is destroyed as well. + /// + void DestroyColliderComponent(); + } + + /// + /// A helper class that provides easy access to creating and destroying the + /// various authoring components. + /// + /// Item type + /// Data type + /// Main component type + public class ConvertedItem : IConvertedItem + where TItem : Item + where TData : ItemData + where TMainAuthoring : ItemMainAuthoring, IItemMainAuthoring + { + public Type MainAuthoringType => _mainAuthoring.GetType(); + + public TMainAuthoring Authoring => _mainAuthoring; + public IItemMainAuthoring MainAuthoring => _mainAuthoring; + public IEnumerable MeshAuthoring => _meshAuthoring; + public IItemColliderAuthoring ColliderAuthoring => _colliderAuthoring; + public bool IsProceduralMesh { get; set; } = true; + + private readonly TMainAuthoring _mainAuthoring; + private ItemColliderAuthoring _colliderAuthoring; + + private readonly TData _itemData; + private readonly GameObject _gameObject; + private readonly List _meshAuthoring = new List(); + + /// + /// Instantiates for new items. + /// + /// + /// Used when importing a new table. + /// + /// Freshly created game object + /// Item to assign to + /// If true, the main component is already assigned to the game object. + public ConvertedItem(GameObject gameObject, TItem item, bool componentsAdded) + { + _gameObject = gameObject; + _itemData = item.Data; + + _mainAuthoring = componentsAdded ? _gameObject.GetComponent() : _gameObject.AddComponent(); + if (_mainAuthoring == null) + { + var mainComp = _gameObject.GetComponent(); + if (mainComp != null) { + throw new Exception($"Prefab loaded but main component is of type {mainComp.GetType()} for item {item.Name} of type {item.GetType()}."); + } + throw new Exception($"Prefab loaded but has no main component applied ({item.Name})."); + } + _mainAuthoring.SetItem(item); + } + + /// + /// Instantiates for existing items. + /// + /// + /// Used when just creating a new item with the toolbox. + /// + /// Existing game object which already has the main component set. + public ConvertedItem(GameObject gameObject) + { + _gameObject = gameObject; + _itemData = _gameObject.GetComponent().Data; + } + + public void AddMeshAuthoring(string name, bool componentsAdded) where T : Component, IItemMeshAuthoring + { + if (componentsAdded) { + var meshGo = _mainAuthoring.transform.Find(name); + _meshAuthoring.Add(meshGo.GetComponent()); + + } else { + var meshGo = new GameObject(name); + meshGo.transform.SetParent(_mainAuthoring.transform, false); + var meshComp = meshGo.AddComponent(); + meshGo.layer = SceneTableContainer.ChildObjectsLayer; + _meshAuthoring.Add(meshComp); + } + } + + public void SetMeshAuthoring(bool componentsAdded) where T : Component, IItemMeshAuthoring + { + _meshAuthoring.Add( + componentsAdded + ? _gameObject.GetComponent() + : _gameObject.AddComponent() + ); + } + + public void SetColliderAuthoring(IMaterialProvider materialProvider, bool componentsAdded) where T : ItemColliderAuthoring + { + if (!_mainAuthoring.IsCollidable) { + return; + } + _colliderAuthoring = componentsAdded ? _gameObject.GetComponent() : _gameObject.AddComponent(); + if (_itemData is IPhysicsMaterialData physicsMaterialData) { + _colliderAuthoring.PhysicsMaterial = materialProvider.GetPhysicsMaterial(physicsMaterialData.GetPhysicsMaterial()); + } + } + + public void SetAnimationAuthoring(string name) where T : Component, IItemAnimationAuthoring + { + var go = _gameObject.transform.Find(name).gameObject; + go.AddComponent(); + } + + public IConvertedItem AddConvertToEntity(bool componentsAdded) + { + if (!componentsAdded) { + _gameObject.AddComponent(); + } + + return this; + } + + public void Destroy() + { + _mainAuthoring.Destroy(); + } + + public void Destroy() where T : Component + { + var childAuthoring = _gameObject.GetComponentInChildren(); + if (childAuthoring) { + Object.DestroyImmediate(childAuthoring.gameObject); + } + } + + public void DestroyMeshComponents() + { + if (_mainAuthoring is IItemMainRenderableAuthoring renderableAuthoring) { + renderableAuthoring.DestroyMeshComponent(); + _meshAuthoring.Clear(); + } + } + + public void DestroyColliderComponent() + { + if (_mainAuthoring is IItemMainRenderableAuthoring renderableAuthoring) { + renderableAuthoring.DestroyColliderComponent(); + _colliderAuthoring = null; + } + } + + public bool IsValidChild(IConvertedItem parent) + { + if (MeshAuthoring.Any()) { + return MeshAuthoring.First().ValidParents.Contains(parent.MainAuthoringType); + } + + if (_colliderAuthoring != null) { + return _colliderAuthoring.ValidParents.Contains(parent.MainAuthoringType); + } + + return _mainAuthoring.ValidParents.Contains(parent.MainAuthoringType); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/Import/ConvertedItem.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Import/ConvertedItem.cs.meta new file mode 100644 index 000000000..c8c6c004a --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Import/ConvertedItem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a95eb9c935948874f8a661ae6c84e80b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/Bumper/BumperCollisionTests.cs b/VisualPinball.Unity/VisualPinball.Unity/Import/IMaterialProvider.cs similarity index 64% rename from VisualPinball.Unity/VisualPinball.Unity.Test/VPT/Bumper/BumperCollisionTests.cs rename to VisualPinball.Unity/VisualPinball.Unity/Import/IMaterialProvider.cs index 723804faf..92c1ea7c5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Test/VPT/Bumper/BumperCollisionTests.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Import/IMaterialProvider.cs @@ -1,4 +1,4 @@ -// Visual Pinball Engine +// Visual Pinball Engine // Copyright (C) 2021 freezy and VPE Team // // This program is free software: you can redistribute it and/or modify @@ -14,26 +14,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using NUnit.Framework; -using VisualPinball.Engine.Test.Test; -using VisualPinball.Engine.VPT.Table; +using VisualPinball.Engine.VPT; +using Material = UnityEngine.Material; -namespace VisualPinball.Unity.Test +namespace VisualPinball.Unity { - public class BumperCollisionTests + public interface IMaterialProvider { - private Table _table; - - [SetUp] - public void Setup() - { - _table = Table.Load(VpxPath.Bumper); - } - - [Test] - public void TestSomething() - { - - } + bool HasMaterial(string name); + void SaveMaterial(PbrMaterial vpxMaterial, Material material); + Material GetMaterial(string name); + PhysicsMaterial GetPhysicsMaterial(string name); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Import/IMaterialProvider.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Import/IMaterialProvider.cs.meta new file mode 100644 index 000000000..fa65383dd --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Import/IMaterialProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 071022a51edd1f548962d397be15a24f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSound.cs b/VisualPinball.Unity/VisualPinball.Unity/Import/IMeshProvider.cs similarity index 60% rename from VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSound.cs rename to VisualPinball.Unity/VisualPinball.Unity/Import/IMeshProvider.cs index 37c830820..6d8d04521 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSound.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Import/IMeshProvider.cs @@ -14,16 +14,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using VisualPinball.Engine.VPT.Sound; +using UnityEngine; namespace VisualPinball.Unity { - /// - /// Scriptable object wrapper for plain VPX sound data. This will allow us to operate on sound data one a time - /// for things like undo tracking, rather than needing to serialize the whole table (sidecar) and everything on it - /// - public class TableSerializedSound : TableSerializedData + public interface IMeshProvider { - public static TableSerializedSound Create(SoundData data) => GenericCreate(data); + Mesh GetMesh(string parentName, string name); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Import/IMeshProvider.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Import/IMeshProvider.cs.meta new file mode 100644 index 000000000..335742078 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Import/IMeshProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed9b90a73ef832a4f863320c46e31e76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTexture.cs b/VisualPinball.Unity/VisualPinball.Unity/Import/ITextureProvider.cs similarity index 57% rename from VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTexture.cs rename to VisualPinball.Unity/VisualPinball.Unity/Import/ITextureProvider.cs index f6c86670a..3770abf21 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTexture.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Import/ITextureProvider.cs @@ -1,4 +1,4 @@ -// Visual Pinball Engine +// Visual Pinball Engine // Copyright (C) 2021 freezy and VPE Team // // This program is free software: you can redistribute it and/or modify @@ -14,16 +14,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using VisualPinball.Engine.VPT; +using UnityEngine; namespace VisualPinball.Unity { - /// - /// Scriptable object wrapper for plain VPX texture data. This will allow us to operate on texture data one a time - /// for things like undo tracking, rather than needing to serialize the whole table (sidecar) and everything on it - /// - public class TableSerializedTexture : TableSerializedData + public interface ITextureProvider { - public static TableSerializedTexture Create(TextureData data) => GenericCreate(data); + Texture GetTexture(string name); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Import/ITextureProvider.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Import/ITextureProvider.cs.meta new file mode 100644 index 000000000..510a4b378 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Import/ITextureProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f8571f2a0fec20243a15aec4242a4c2e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/Import/Job/TableLoader.cs b/VisualPinball.Unity/VisualPinball.Unity/Import/Job/TableLoader.cs index 5f513594d..7b68640d2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Import/Job/TableLoader.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Import/Job/TableLoader.cs @@ -48,104 +48,106 @@ namespace VisualPinball.Unity { public static class TableLoader { - public static Table LoadTable(string path) + public static FileTableContainer LoadTable(string path) { - var table = Table.Load(path, false); + var tableContainer = FileTableContainer.Load(path, false); - var job = new GameItemJob(table.Data.NumGameItems); - var gameItems = Engine.VPT.Table.TableLoader.ReadGameItems(path, table.Data.NumGameItems); - for (var i = 0; i < table.Data.NumGameItems; i++) { + var job = new GameItemJob(tableContainer.Table.Data.NumGameItems); + var gameItems = Engine.VPT.Table.TableLoader.ReadGameItems(path, tableContainer.Table.Data.NumGameItems, "GameItem") + .Concat(Engine.VPT.Table.TableLoader.ReadGameItems(path, tableContainer.Table.Data.NumVpeGameItems, "VpeGameItem")) + .ToArray(); + for (var i = 0; i < tableContainer.Table.Data.NumGameItems; i++) { job.Data[i] = MemHelper.FromByteArray(gameItems[i]); job.DataLength[i] = gameItems[i].Length; } // parse threaded - var handle = job.Schedule(table.Data.NumGameItems, 64); + var handle = job.Schedule(tableContainer.Table.Data.NumGameItems + tableContainer.Table.Data.NumVpeGameItems, 64); handle.Complete(); // update table with results - for (var i = 0; i < table.Data.NumGameItems; i++) { + for (var i = 0; i < tableContainer.Table.Data.NumGameItems; i++) { if (job.ItemObj[i].ToInt32() > 0) { var objHandle = (GCHandle) job.ItemObj[i]; switch ((ItemType)job.ItemType[i]) { case ItemType.Bumper: { - table.Add(objHandle.Target as Bumper); + tableContainer.Add(objHandle.Target as Bumper); break; } case ItemType.Decal: { - table.Add(objHandle.Target as Decal); + tableContainer.Add(objHandle.Target as Decal); break; } case ItemType.DispReel: { - table.Add(objHandle.Target as DispReel); + tableContainer.Add(objHandle.Target as DispReel); break; } case ItemType.Flasher: { - table.Add(objHandle.Target as Flasher); + tableContainer.Add(objHandle.Target as Flasher); break; } case ItemType.Flipper: { - table.Add(objHandle.Target as Flipper); + tableContainer.Add(objHandle.Target as Flipper); break; } case ItemType.Gate: { - table.Add(objHandle.Target as Gate); + tableContainer.Add(objHandle.Target as Gate); break; } case ItemType.HitTarget: { - table.Add(objHandle.Target as HitTarget); + tableContainer.Add(objHandle.Target as HitTarget); break; } case ItemType.Kicker: { - table.Add(objHandle.Target as Kicker); + tableContainer.Add(objHandle.Target as Kicker); break; } case ItemType.Light: { - table.Add(objHandle.Target as Light); + tableContainer.Add(objHandle.Target as Light); break; } case ItemType.LightSeq: { - table.Add(objHandle.Target as LightSeq); + tableContainer.Add(objHandle.Target as LightSeq); break; } case ItemType.Plunger: { - table.Add(objHandle.Target as Plunger); + tableContainer.Add(objHandle.Target as Plunger); break; } case ItemType.Primitive: { - table.Add(objHandle.Target as Primitive); + tableContainer.Add(objHandle.Target as Primitive); break; } case ItemType.Ramp: { - table.Add(objHandle.Target as Ramp); + tableContainer.Add(objHandle.Target as Ramp); break; } case ItemType.Rubber: { - table.Add(objHandle.Target as Rubber); + tableContainer.Add(objHandle.Target as Rubber); break; } case ItemType.Spinner: { - table.Add(objHandle.Target as Spinner); + tableContainer.Add(objHandle.Target as Spinner); break; } case ItemType.Surface: { - table.Add(objHandle.Target as Surface); + tableContainer.Add(objHandle.Target as Surface); break; } case ItemType.TextBox: { - table.Add(objHandle.Target as TextBox); + tableContainer.Add(objHandle.Target as TextBox); break; } case ItemType.Timer: { - table.Add(objHandle.Target as Timer); + tableContainer.Add(objHandle.Target as Timer); break; } case ItemType.Trigger: { - table.Add(objHandle.Target as Trigger); + tableContainer.Add(objHandle.Target as Trigger); break; } case ItemType.Trough: { - table.Add(objHandle.Target as Trough); + tableContainer.Add(objHandle.Target as Trough); break; } default: @@ -153,10 +155,10 @@ public static Table LoadTable(string path) } } } - table.SetupPlayfieldMesh(); + tableContainer.Table.SetupPlayfieldMesh(); job.Dispose(); - return table; + return tableContainer; } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Import/PatcherManager.cs b/VisualPinball.Unity/VisualPinball.Unity/Import/PatcherManager.cs index 996e16929..85a210d56 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Import/PatcherManager.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Import/PatcherManager.cs @@ -8,7 +8,7 @@ namespace VisualPinball.Unity { public interface IPatcher { - void SetTable(Table table, string filename); + void Set(FileTableContainer tableContainer, string filename); void ApplyPrePatches(IRenderable item); void ApplyPatches(IRenderable item, GameObject gameObject, GameObject tableGameObject); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Import/VpxConverter.cs b/VisualPinball.Unity/VisualPinball.Unity/Import/VpxConverter.cs deleted file mode 100644 index 801df1c45..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/Import/VpxConverter.cs +++ /dev/null @@ -1,403 +0,0 @@ -// 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 ConvertIfStatementToReturnStatement -// ReSharper disable ClassNeverInstantiated.Global -// ReSharper disable RedundantAssignment - -using System; -using System.Collections.Generic; -using System.Linq; -using NLog; -using UnityEngine; -using VisualPinball.Engine.Common; -using VisualPinball.Engine.Game; -using VisualPinball.Engine.VPT; -using VisualPinball.Engine.VPT.Bumper; -using VisualPinball.Engine.VPT.Decal; -using VisualPinball.Engine.VPT.DispReel; -using VisualPinball.Engine.VPT.Flasher; -using VisualPinball.Engine.VPT.Flipper; -using VisualPinball.Engine.VPT.Gate; -using VisualPinball.Engine.VPT.HitTarget; -using VisualPinball.Engine.VPT.Kicker; -using VisualPinball.Engine.VPT.LightSeq; -using VisualPinball.Engine.VPT.Mappings; -using VisualPinball.Engine.VPT.Plunger; -using VisualPinball.Engine.VPT.Primitive; -using VisualPinball.Engine.VPT.Ramp; -using VisualPinball.Engine.VPT.Rubber; -using VisualPinball.Engine.VPT.Spinner; -using VisualPinball.Engine.VPT.Surface; -using VisualPinball.Engine.VPT.Table; -using VisualPinball.Engine.VPT.TextBox; -using VisualPinball.Engine.VPT.Timer; -using VisualPinball.Engine.VPT.Trigger; -using VisualPinball.Engine.VPT.Trough; -using Logger = NLog.Logger; - -namespace VisualPinball.Unity -{ - public class VpxConverter : MonoBehaviour - { - private static readonly Quaternion GlobalRotation = Quaternion.Euler(-90, 0, 0); - public const float GlobalScale = 0.001f; - public const int ChildObjectsLayer = 16; - - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - - //private readonly Dictionary _renderObjects = new Dictionary(); - private readonly Dictionary _groupParents = new Dictionary(); - - private Table _table; - private TableAuthoring _tableAuthoring; - private bool _applyPatch = true; - private IPatcher _patcher; - - public void Convert(string fileName, Table table, bool applyPatch = true, string tableName = null) - { - _table = table; - - // TODO: implement disabling patching; not so obvious because of the static methods being used for the import - if( !applyPatch) - Logger.Warn("Disabling patch import not implemented yet!"); - - var go = gameObject; - - MakeSerializable(go, table); - - // set the GameObject name; this needs to happen after MakeSerializable because the name is set there as well - if (string.IsNullOrEmpty(tableName)) { - go.name = _table.Name; - - } else { - go.name = tableName - .Replace("%TABLENAME%", _table.Name) - .Replace("%INFONAME%", _table.InfoName); - } - - _patcher = PatcherManager.GetPatcher(); - _patcher?.SetTable(_table, fileName); - - // import - ConvertGameItems(go); - - // set root transformation - go.transform.localRotation = GlobalRotation; - go.transform.localPosition = new Vector3(-_table.Width / 2 * GlobalScale, 0f, _table.Height / 2 * GlobalScale); - go.transform.localScale = new Vector3(GlobalScale, GlobalScale, GlobalScale); - //ScaleNormalizer.Normalize(go, GlobalScale); - - // add the player script and default game engine - go.AddComponent(); - var dga = go.AddComponent(); - - // add trough if none available - if (!_table.HasTrough) { - CreateTrough(); - } - - // populate mappings - if (_table.Mappings.IsEmpty()) { - _table.Mappings.PopulateSwitches(dga.AvailableSwitches, table.Switchables, table.SwitchableDevices); - _table.Mappings.PopulateCoils(dga.AvailableCoils, table.Coilables, table.CoilableDevices); - - // wire up plunger - var plunger = _table.Plunger(); - if (plunger != null) { - _table.Mappings.Data.AddWire(new MappingsWireData { - Description = "Plunger", - Source = SwitchSource.InputSystem, - SourceInputActionMap = InputConstants.MapCabinetSwitches, - SourceInputAction = InputConstants.ActionPlunger, - Destination = WireDestination.Device, - DestinationDevice = plunger.Name, - DestinationDeviceItem = Plunger.PullCoilId - }); - } - } - - // don't need that anymore. - DestroyImmediate(this); - } - - private void ConvertGameItems(GameObject tableGameObject) - { - var convertedItems = new Dictionary(); - var renderableLookup = new Dictionary(); - var renderables = from renderable in _table.Renderables - orderby renderable.SubComponent - select renderable; - - foreach (var renderable in renderables) { - - _patcher?.ApplyPrePatches(renderable); - - var lookupName = renderable.Name.ToLower(); - renderableLookup[lookupName] = renderable; - - var groupParent = GetGroupParent(renderable); - - if (renderable.SubComponent == ItemSubComponent.None) { - // create object(s) - convertedItems[lookupName] = CreateGameObjects(_table, renderable, groupParent); - - } else { - // if the object's names was parsed to be part of another object, re-link to other object. - var parentName = renderable.ComponentName.ToLower(); - if (convertedItems.ContainsKey(parentName)) { - var parent = convertedItems[parentName]; - - var convertedItem = CreateGameObjects(_table, renderable, groupParent); - if (convertedItem.IsValidChild(parent)) { - - if (convertedItem.MeshAuthoring.Any()) { - - // move and rotate into parent - if (parent.MainAuthoring.IItem is IRenderable parentRenderable) { - renderable.Position -= parentRenderable.Position; - renderable.RotationY -= parentRenderable.RotationY; - } - - parent.DestroyMeshComponent(); - } - if (convertedItem.ColliderAuthoring != null) { - parent.DestroyColliderComponent(); - } - convertedItem.MainAuthoring.gameObject.transform.SetParent(parent.MainAuthoring.gameObject.transform, false); - convertedItems[lookupName] = convertedItem; - - } else { - - renderable.DisableSubComponent(); - - // invalid parenting, re-convert the item, because it returned only the sub component. - convertedItems[lookupName] = CreateGameObjects(_table, renderable, groupParent); - - // ..and destroy the other one - convertedItem.Destroy(); - } - - } else { - Logger.Warn($"Cannot find component \"{parentName}\" that is supposed to be the parent of \"{renderable.Name}\"."); - } - } - } - - // now we have all renderables imported, patch them. - foreach (var lookupName in convertedItems.Keys) { - foreach (var meshMb in convertedItems[lookupName].MeshAuthoring) { - _patcher?.ApplyPatches(renderableLookup[lookupName], meshMb.gameObject, tableGameObject); - } - } - - // convert non-renderables - foreach (var item in _table.NonRenderables) { - var groupParent = GetGroupParent(item); - - // create object(s) - CreateGameObjects(_table, item, groupParent); - } - } - - private GameObject GetGroupParent(IItem item) - { - // create group parent if not created (if null, attach it to the table directly). - if (!string.IsNullOrEmpty(item.ItemGroupName)) { - if (!_groupParents.ContainsKey(item.ItemGroupName)) { - var parent = new GameObject(item.ItemGroupName); - parent.transform.parent = gameObject.transform; - _groupParents[item.ItemGroupName] = parent; - } - } - var groupParent = !string.IsNullOrEmpty(item.ItemGroupName) - ? _groupParents[item.ItemGroupName] - : gameObject; - - return groupParent; - } - - public static ConvertedItem CreateGameObjects(Table table, IItem item, GameObject parent) - { - var obj = new GameObject(item.Name); - obj.transform.parent = parent.transform; - - var importedObject = SetupGameObjects(item, obj); - - // apply transformation - if (item is IRenderable renderable) { - obj.transform.SetFromMatrix(renderable.TransformationMatrix(table, Origin.Original).ToUnityMatrix()); - } - - return importedObject; - } - - private static ConvertedItem SetupGameObjects(IItem item, GameObject obj) - { - switch (item) { - case Bumper bumper: return bumper.SetupGameObject(obj); - case Flipper flipper: return flipper.SetupGameObject(obj); - case Gate gate: return gate.SetupGameObject(obj); - case HitTarget hitTarget: return hitTarget.SetupGameObject(obj); - case Kicker kicker: return kicker.SetupGameObject(obj); - case Engine.VPT.Light.Light lt: return lt.SetupGameObject(obj); - case Plunger plunger: return plunger.SetupGameObject(obj); - case Primitive primitive: return primitive.SetupGameObject(obj); - case Ramp ramp: return ramp.SetupGameObject(obj); - case Rubber rubber: return rubber.SetupGameObject(obj); - case Spinner spinner: return spinner.SetupGameObject(obj); - case Surface surface: return surface.SetupGameObject(obj); - case Table table: return table.SetupGameObject(obj); - case Trigger trigger: return trigger.SetupGameObject(obj); - case Trough trough: return trough.SetupGameObject(obj); - } - - throw new InvalidOperationException("Unknown item " + item + " to setup!"); - } - - private void MakeSerializable(GameObject go, Table table) - { - // add table component (plus other data) - _tableAuthoring = go.AddComponent(); - _tableAuthoring.SetItem(table); - - var sidecar = _tableAuthoring.GetOrCreateSidecar(); - - foreach (var key in table.TableInfo.Keys) { - sidecar.tableInfo[key] = table.TableInfo[key]; - } - - // copy each serializable ref into the sidecar's serialized storage - sidecar.textures.AddRange(table.Textures); - sidecar.sounds.AddRange(table.Sounds); - - // and tell the engine's table to now use the sidecar as its container so we can all operate on the same underlying container - table.SetTextureContainer(sidecar.textures); - table.SetSoundContainer(sidecar.sounds); - - sidecar.customInfoTags = table.CustomInfoTags; - sidecar.collections = table.Collections.Values.Select(c => c.Data).ToList(); - sidecar.mappings = table.Mappings.Data; - sidecar.decals = table.GetAllData(); - sidecar.dispReels = table.GetAllData(); - sidecar.flashers = table.GetAllData(); - sidecar.lightSeqs = table.GetAllData(); - sidecar.textBoxes = table.GetAllData(); - sidecar.timers = table.GetAllData(); - - Logger.Info("Collections saved: [ {0} ] [ {1} ]", - string.Join(", ", table.Collections.Keys), - string.Join(", ", sidecar.collections.Select(c => c.Name)) - ); - } - - private void CreateTrough() - { - var troughData = new TroughData("Trough") { - BallCount = 4, - SwitchCount = 4, - Type = TroughType.ModernMech - }; - if (_table.Has("BallRelease")) { - troughData.PlayfieldExitKicker = "BallRelease"; - } - if (_table.Has("Drain")) { - troughData.PlayfieldEntrySwitch = "Drain"; - } - var item = new Trough(troughData); - _table.Add(item, true); - CreateGameObjects(_tableAuthoring.Table, item, _tableAuthoring.gameObject); - } - } - - public class ConvertedItem - { - public readonly IItemMainAuthoring MainAuthoring; - public IEnumerable MeshAuthoring; - public IItemColliderAuthoring ColliderAuthoring; - - public ConvertedItem() - { - MainAuthoring = null; - MeshAuthoring = new IItemMeshAuthoring[0]; - ColliderAuthoring = null; - } - - public ConvertedItem(IItemMainAuthoring mainAuthoring) - { - MainAuthoring = mainAuthoring; - MeshAuthoring = new IItemMeshAuthoring[0]; - ColliderAuthoring = null; - } - - public ConvertedItem(IItemMainAuthoring mainAuthoring, IEnumerable meshAuthoring) - { - MainAuthoring = mainAuthoring; - MeshAuthoring = meshAuthoring; - ColliderAuthoring = null; - } - - public ConvertedItem(IItemMainAuthoring mainAuthoring, IEnumerable meshAuthoring, IItemColliderAuthoring colliderAuthoring) - { - MainAuthoring = mainAuthoring; - MeshAuthoring = meshAuthoring; - ColliderAuthoring = colliderAuthoring; - } - - public void Destroy() - { - MainAuthoring.Destroy(); - } - - public void DestroyMeshComponent() - { - if (MainAuthoring is IItemMainRenderableAuthoring renderableAuthoring) { - renderableAuthoring.DestroyMeshComponent(); - MeshAuthoring = new IItemMeshAuthoring[0]; - } - } - - public void DestroyColliderComponent() - { - if (MainAuthoring is IItemMainRenderableAuthoring renderableAuthoring) { - renderableAuthoring.DestroyColliderComponent(); - ColliderAuthoring = null; - } - } - - public bool IsValidChild(ConvertedItem parent) - { - if (MeshAuthoring.Any()) { - return MeshAuthoring.First().ValidParents.Contains(parent.MainAuthoring.GetType()); - } - - if (ColliderAuthoring != null) { - return ColliderAuthoring.ValidParents.Contains(parent.MainAuthoring.GetType()); - } - - return MainAuthoring.ValidParents.Contains(parent.MainAuthoring.GetType()); - } - - public static T CreateChild(GameObject obj, string name) where T : MonoBehaviour, IItemMeshAuthoring - { - var subObj = new GameObject(name); - subObj.transform.SetParent(obj.transform, false); - var comp = subObj.AddComponent(); - subObj.layer = VpxConverter.ChildObjectsLayer; - return comp; - } - } -} diff --git a/VisualPinball.Unity/VisualPinball.Unity/Import/VpxConverter.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Import/VpxConverter.cs.meta deleted file mode 100644 index 2b221f0d7..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/Import/VpxConverter.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: fb5ea193211a47f458df32d3486ec98b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ColliderData.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ColliderData.cs index d23bc0b8a..569c79e20 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ColliderData.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/ColliderData.cs @@ -14,7 +14,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using Unity.Collections; using Unity.Entities; namespace VisualPinball.Unity diff --git a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/StaticBroadPhaseSystem.cs b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/StaticBroadPhaseSystem.cs index bfad46357..44d652d8d 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/StaticBroadPhaseSystem.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Physics/Collision/StaticBroadPhaseSystem.cs @@ -15,7 +15,6 @@ // along with this program. If not, see . using NLog; -using Unity.Collections; using Unity.Entities; using Unity.Profiling; using Logger = NLog.Logger; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Rendering/IMaterialConverter.cs b/VisualPinball.Unity/VisualPinball.Unity/Rendering/IMaterialConverter.cs index 8dec939a4..cf1a4ba06 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Rendering/IMaterialConverter.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Rendering/IMaterialConverter.cs @@ -41,10 +41,12 @@ public interface IMaterialConverter /// Create a material for the currently detected graphics pipeline. /// /// - /// + /// /// Type of the item to which the material is applied (e.g. ) /// /// - Material CreateMaterial(PbrMaterial vpxMaterial, TableAuthoring table, Type objectType, StringBuilder debug = null); + Material CreateMaterial(PbrMaterial vpxMaterial, ITextureProvider textureProvider, Type objectType, StringBuilder debug = null); + + int NormalMapProperty { get; } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Rendering/Standard/StandardMaterialConverter.cs b/VisualPinball.Unity/VisualPinball.Unity/Rendering/Standard/StandardMaterialConverter.cs index 0653615d9..6f40b50ca 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Rendering/Standard/StandardMaterialConverter.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Rendering/Standard/StandardMaterialConverter.cs @@ -26,6 +26,7 @@ public class StandardMaterialConverter : IMaterialConverter { public Material DotMatrixDisplay => UnityEngine.Resources.Load("Materials/DotMatrixDisplayBuiltin"); public Material SegmentDisplay => UnityEngine.Resources.Load("Materials/SegmentDisplayBuiltin"); + public int NormalMapProperty => NormalMap; #region Shader Properties @@ -67,7 +68,7 @@ public static Material GetDefaultMaterial(BlendMode blendMode) throw new ArgumentOutOfRangeException("Undefined blend mode " + blendMode); } } - public Material CreateMaterial(PbrMaterial vpxMaterial, TableAuthoring table, Type objectType, StringBuilder debug = null) + public Material CreateMaterial(PbrMaterial vpxMaterial, ITextureProvider textureProvider, Type objectType, StringBuilder debug = null) { Material defaultMaterial = GetDefaultMaterial(vpxMaterial.MapBlendMode); @@ -110,18 +111,16 @@ public Material CreateMaterial(PbrMaterial vpxMaterial, TableAuthoring table, Ty unityMaterial.SetFloat(Smoothness, vpxMaterial.Roughness); // map - if (table != null && vpxMaterial.HasMap) - { - unityMaterial.SetTexture(BaseColorMap, table.GetTexture(vpxMaterial.Map.Name)); + if (vpxMaterial.HasMap) { + unityMaterial.SetTexture(BaseColorMap, textureProvider.GetTexture(vpxMaterial.Map.Name)); } // normal map - if (table != null && vpxMaterial.HasNormalMap) - { + if (vpxMaterial.HasNormalMap) { unityMaterial.EnableKeyword("_NORMALMAP"); unityMaterial.EnableKeyword("_NORMALMAP_TANGENT_SPACE"); - unityMaterial.SetTexture(NormalMap, table.GetTexture(vpxMaterial.NormalMap.Name)); + unityMaterial.SetTexture(NormalMap, textureProvider.GetTexture(vpxMaterial.NormalMap.Name)); } return unityMaterial; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallMovementSystem.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallMovementSystem.cs index 016af84b6..abb8133c0 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallMovementSystem.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallMovementSystem.cs @@ -31,7 +31,7 @@ internal class BallMovementSystem : SystemBase protected override void OnStartRunning() { - var root = Object.FindObjectOfType(); + var root = Object.FindObjectOfType(); var ltw = root.gameObject.transform.localToWorldMatrix; _baseTransform = new float4x4( ltw.m00, ltw.m01, ltw.m02, ltw.m03, diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs index 86be4567a..645e10711 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperApi.cs @@ -70,10 +70,10 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider { var height = table.GetSurfaceHeight(Data.Surface, Data.Center.X, Data.Center.Y); colliders.Add(new CircleCollider(Data.Center.ToUnityFloat2(), Data.Radius, height, - height + Data.HeightScale, GetColliderInfo(table), ColliderType.Bumper)); + height + Data.HeightScale, GetColliderInfo(), ColliderType.Bumper)); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(); #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperAuthoring.cs index edfa80d1e..612627b22 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperAuthoring.cs @@ -49,13 +49,6 @@ public class BumperAuthoring : ItemMainRenderableAuthoring, public ISwitchable Switchable => Item; - private void OnDestroy() - { - if (!Application.isPlaying) { - Table?.Remove(Name); - } - } - public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { Convert(entity, dstManager); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperExtensions.cs index 91244ca67..cc39d38e5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperExtensions.cs @@ -15,9 +15,7 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; using NLog; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Bumper; @@ -25,30 +23,23 @@ namespace VisualPinball.Unity { - internal static class BumperExtensions + public static class BumperExtensions { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static ConvertedItem SetupGameObject(this Bumper bumper, GameObject obj) + public static IConvertedItem SetupGameObject(this Bumper bumper, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(bumper); - var meshAuthoring = new List(); - BumperColliderAuthoring colliderAuthoring = null; - + var convertedItem = new ConvertedItem(obj, bumper, componentsAdded); switch (bumper.SubComponent) { case ItemSubComponent.None: - colliderAuthoring = obj.AddColliderComponent(bumper); - meshAuthoring.Add(ConvertedItem.CreateChild(obj, BumperMeshGenerator.Base)); - meshAuthoring.Add(ConvertedItem.CreateChild(obj, BumperMeshGenerator.Cap)); - - var ring = ConvertedItem.CreateChild(obj, BumperMeshGenerator.Ring); - var skirt = ConvertedItem.CreateChild(obj, BumperMeshGenerator.Skirt); - - ring.gameObject.AddComponent(); - skirt.gameObject.AddComponent(); - - meshAuthoring.Add(ring); - meshAuthoring.Add(skirt); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); + convertedItem.AddMeshAuthoring(BumperMeshGenerator.Base, componentsAdded); + convertedItem.AddMeshAuthoring(BumperMeshGenerator.Cap, componentsAdded); + convertedItem.AddMeshAuthoring(BumperMeshGenerator.Ring, componentsAdded); + convertedItem.AddMeshAuthoring(BumperMeshGenerator.Skirt, componentsAdded); + + convertedItem.SetAnimationAuthoring(BumperMeshGenerator.Ring); + convertedItem.SetAnimationAuthoring(BumperMeshGenerator.Skirt); break; case ItemSubComponent.Collider: { @@ -64,14 +55,8 @@ public static ConvertedItem SetupGameObject(this Bumper bumper, GameObject obj) default: throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); - } - - private static BumperColliderAuthoring AddColliderComponent(this GameObject obj, Bumper bumper) - { - return bumper.Data.IsCollidable ? obj.AddComponent() : null; + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperRingAnimationAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperRingAnimationAuthoring.cs index 2a72f76c6..0671453ec 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperRingAnimationAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperRingAnimationAuthoring.cs @@ -23,7 +23,7 @@ namespace VisualPinball.Unity { [AddComponentMenu("Visual Pinball/Animation/Bumper Ring Animation")] - public class BumperRingAnimationAuthoring : ItemMovementAuthoring, IConvertGameObjectToEntity + public class BumperRingAnimationAuthoring : ItemAnimationAuthoring, IConvertGameObjectToEntity { public override IEnumerable ValidParents { get; } = new Type[0]; // animation components only apply to their own diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperSkirtAnimationAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperSkirtAnimationAuthoring.cs index 6080d2545..1da770a70 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperSkirtAnimationAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperSkirtAnimationAuthoring.cs @@ -24,7 +24,7 @@ namespace VisualPinball.Unity { [AddComponentMenu("Visual Pinball/Animation/Bumper Skirt Animation")] - public class BumperSkirtAnimationAuthoring : ItemMovementAuthoring, IConvertGameObjectToEntity + public class BumperSkirtAnimationAuthoring : ItemAnimationAuthoring, IConvertGameObjectToEntity { public override IEnumerable ValidParents { get; } = new Type[0]; // animation components only apply to their own diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs index d553a6d6d..4eed4c578 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperApi.cs @@ -184,25 +184,25 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider baseRadius, height, height + Data.Height, - GetColliderInfo(table) + GetColliderInfo() ); - colliders.Add(new FlipperCollider(hitCircleBase, Data.FlipperRadius, Data.EndRadius, GetColliderInfo(table))); + colliders.Add(new FlipperCollider(hitCircleBase, Data.FlipperRadius, Data.EndRadius, GetColliderInfo())); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(); - protected override PhysicsMaterialData GetPhysicsMaterial(Table table) => new PhysicsMaterialData { - ElasticityFalloff = Data.OverridePhysics != 0 || table.Data.OverridePhysicsFlipper && table.Data.OverridePhysics != 0 + protected override PhysicsMaterialData GetPhysicsMaterial(PhysicsMaterial physicsMaterial) => new PhysicsMaterialData { + ElasticityFalloff = Data.OverridePhysics != 0 ? Data.OverrideElasticityFalloff : Data.ElasticityFalloff, - Elasticity = Data.OverridePhysics != 0 || table.Data.OverridePhysicsFlipper && table.Data.OverridePhysics != 0 + Elasticity = Data.OverridePhysics != 0 ? Data.OverrideElasticity : Data.Elasticity, - Friction = Data.OverridePhysics != 0 || table.Data.OverridePhysicsFlipper && table.Data.OverridePhysics != 0 + Friction = Data.OverridePhysics != 0 ? Data.OverrideFriction : Data.Friction, - ScatterAngleRad = math.radians(Data.OverridePhysics != 0 || table.Data.OverridePhysicsFlipper && table.Data.OverridePhysics != 0 + ScatterAngleRad = math.radians(Data.OverridePhysics != 0 ? Data.OverrideScatterAngle : Data.Scatter ) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperAuthoring.cs index 3864950e9..631145ac9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperAuthoring.cs @@ -27,6 +27,7 @@ using Unity.Entities; using Unity.Mathematics; using UnityEngine; +using UnityEngine.Profiling; using VisualPinball.Engine.Game; using VisualPinball.Engine.VPT.Flipper; using VisualPinball.Engine.VPT.Trigger; @@ -53,13 +54,6 @@ public class FlipperAuthoring : ItemMainRenderableAuthoring(Name); - } - } - public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { Convert(entity, dstManager); @@ -81,9 +75,7 @@ public void Convert(Entity entity, EntityManager dstManager, GameObjectConversio var trigger = CreateCorrectionTrigger(); var triggerEntity = dstManager.CreateEntity(typeof(TriggerStaticData)); dstManager.AddComponentData(triggerEntity, new TriggerStaticData()); - - // todo create special registration method since we don't need all the api stuff. - player.RegisterTrigger(trigger, triggerEntity, Entity.Null); + player.RegisterTrigger(trigger, triggerEntity); using (var builder = new BlobBuilder(Allocator.Temp)) { @@ -174,15 +166,13 @@ public void OnRubberWidthUpdated(float before, float after) return; } + var convertedItem = new ConvertedItem(gameObject); if (before == 0) { - ConvertedItem.CreateChild(gameObject, FlipperMeshGenerator.Rubber); + convertedItem.AddMeshAuthoring(FlipperMeshGenerator.Rubber, false); } if (after == 0) { - var rubberAuthoring = GetComponentInChildren(); - if (rubberAuthoring != null) { - DestroyImmediate(rubberAuthoring.gameObject); - } + convertedItem.Destroy(); } } @@ -285,8 +275,10 @@ public List GetEnclosingPolygon(float margin = 0.0F, float stepSize = 5 protected void OnDrawGizmosSelected() { + Profiler.BeginSample("FlipperAuthoring.OnDrawGizmosSelected"); var poly = GetEnclosingPolygon(); if (poly == null) { + Profiler.EndSample(); return; } @@ -317,6 +309,8 @@ protected void OnDrawGizmosSelected() Gizmos.DrawLine(transform.TransformPoint(last) , transform.TransformPoint(a)); Gizmos.DrawLine(transform.TransformPoint(last), transform.TransformPoint(b)); Gizmos.color = Color.white; + + Profiler.EndSample(); } private FlipperStaticData GetMaterialData() diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperCorrection.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperCorrection.cs index fe2baaa1f..226352243 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperCorrection.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperCorrection.cs @@ -14,10 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using Unity.Burst; using Unity.Mathematics; -using UnityEngine; - using Unity.Entities; namespace VisualPinball.Unity diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperExtensions.cs index 7a4300799..657fe0dde 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperExtensions.cs @@ -15,9 +15,7 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; using NLog; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Flipper; @@ -25,25 +23,18 @@ namespace VisualPinball.Unity { - internal static class FlipperExtensions + public static class FlipperExtensions { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static ConvertedItem SetupGameObject(this Flipper flipper, GameObject obj) + public static IConvertedItem SetupGameObject(this Flipper flipper, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(flipper); - var meshAuthoring = new List(); - FlipperColliderAuthoring colliderAuthoring = null; - + var convertedItem = new ConvertedItem(obj, flipper, componentsAdded); switch (flipper.SubComponent) { case ItemSubComponent.None: - colliderAuthoring = obj.AddComponent(); - - // if invisible in main component, we skip creation entirely, because we think users won't dynamically toggle visibility. - if (flipper.Data.IsVisible) { - meshAuthoring.Add(ConvertedItem.CreateChild(obj, FlipperMeshGenerator.Base)); - meshAuthoring.Add(ConvertedItem.CreateChild(obj, FlipperMeshGenerator.Rubber)); - } + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); + convertedItem.AddMeshAuthoring(FlipperMeshGenerator.Base, componentsAdded); + convertedItem.AddMeshAuthoring(FlipperMeshGenerator.Rubber, componentsAdded); break; case ItemSubComponent.Collider: { @@ -59,8 +50,8 @@ public static ConvertedItem SetupGameObject(this Flipper flipper, GameObject obj default: throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); + + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs index 03f49913e..5ade5e965 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateApi.cs @@ -91,7 +91,7 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider colliderGenerator.GenerateColliders(table, colliders); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(); #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateAuthoring.cs index 95602aed1..b3d654e1b 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateAuthoring.cs @@ -97,13 +97,6 @@ public override void Restore() } } - private void OnDestroy() - { - if (!Application.isPlaying) { - Table?.Remove(Name); - } - } - public override ItemDataTransformType EditorPositionType => ItemDataTransformType.ThreeD; public override Vector3 GetEditorPosition() => Data.Center.ToUnityVector3(Data.Height); public override void SetEditorPosition(Vector3 pos) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateColliderGenerator.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateColliderGenerator.cs index b55bab8c2..a31caaf74 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateColliderGenerator.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateColliderGenerator.cs @@ -66,10 +66,10 @@ private void GenerateGateCollider(Table table, ICollection colliders, _data.Center.Y + sn * (halfLength + PhysicsConstants.PhysSkin) ); - var lineSeg0 = new LineCollider(v1, v2, height, height + 2.0f * PhysicsConstants.PhysSkin, _api.GetColliderInfo(table)); - var lineSeg1 = new LineCollider(v2, v1, height, height + 2.0f * PhysicsConstants.PhysSkin, _api.GetColliderInfo(table)); + var lineSeg0 = new LineCollider(v1, v2, height, height + 2.0f * PhysicsConstants.PhysSkin, _api.GetColliderInfo()); + var lineSeg1 = new LineCollider(v2, v1, height, height + 2.0f * PhysicsConstants.PhysSkin, _api.GetColliderInfo()); - colliders.Add(new GateCollider(in lineSeg0, in lineSeg1, _api.GetColliderInfo(table))); + colliders.Add(new GateCollider(in lineSeg0, in lineSeg1, _api.GetColliderInfo())); } private void GenerateLineCollider(Table table, ICollection colliders, float height, float2 tangent) @@ -84,7 +84,7 @@ private void GenerateLineCollider(Table table, ICollection colliders, var rgv0 = center + (halfLength + PhysicsConstants.PhysSkin) * tangent; var rgv1 = center - (halfLength + PhysicsConstants.PhysSkin) * tangent; - var info = _api.GetColliderInfo(table, ItemType.Invalid); // hack to not treat this line seg as gate + var info = _api.GetColliderInfo(ItemType.Invalid); // hack to not treat this line seg as gate colliders.Add(new LineCollider(rgv0, rgv1, height, height + 2.0f * PhysicsConstants.PhysSkin, info)); //!! = ball diameter } @@ -100,7 +100,7 @@ private void GenerateBracketColliders(Table table, ICollection collid 0.01f, height, height + _data.Height, - _api.GetColliderInfo(table, ItemType.Invalid) // hack to not treat this hit circle as gate + _api.GetColliderInfo(ItemType.Invalid) // hack to not treat this hit circle as gate )); colliders.Add(new CircleCollider( @@ -108,7 +108,7 @@ private void GenerateBracketColliders(Table table, ICollection collid 0.01f, height, height + _data.Height, - _api.GetColliderInfo(table, ItemType.Invalid) // hack to not treat this hit circle as gate + _api.GetColliderInfo( ItemType.Invalid) // hack to not treat this hit circle as gate )); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateExtensions.cs index 44169743c..6ffb62831 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateExtensions.cs @@ -15,9 +15,7 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; using NLog; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Gate; @@ -25,28 +23,19 @@ namespace VisualPinball.Unity { - internal static class GateExtensions + public static class GateExtensions { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static ConvertedItem SetupGameObject(this Gate gate, GameObject obj) + public static IConvertedItem SetupGameObject(this Gate gate, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(gate); - var meshAuthoring = new List(); - GateColliderAuthoring colliderAuthoring = null; - + var convertedItem = new ConvertedItem(obj, gate, componentsAdded); switch (gate.SubComponent) { case ItemSubComponent.None: - // collider - colliderAuthoring = obj.AddColliderComponent(gate); - - // bracket mesh - meshAuthoring.Add(ConvertedItem.CreateChild(obj, GateMeshGenerator.Bracket)); - - // wire mesh - var wireMeshAuth = ConvertedItem.CreateChild(obj, GateMeshGenerator.Wire); - wireMeshAuth.gameObject.AddComponent(); - meshAuthoring.Add(wireMeshAuth); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); + convertedItem.AddMeshAuthoring(GateMeshGenerator.Bracket, componentsAdded); + convertedItem.AddMeshAuthoring(GateMeshGenerator.Wire, componentsAdded); + convertedItem.SetAnimationAuthoring(GateMeshGenerator.Wire); break; case ItemSubComponent.Collider: { @@ -62,13 +51,7 @@ public static ConvertedItem SetupGameObject(this Gate gate, GameObject obj) default: throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); - } - - private static GateColliderAuthoring AddColliderComponent(this GameObject obj, Gate gate) - { - return gate.Data.IsCollidable ? obj.AddComponent() : null; + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateWireAnimationAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateWireAnimationAuthoring.cs index d825ca9a6..37dcb6c79 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateWireAnimationAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateWireAnimationAuthoring.cs @@ -21,7 +21,7 @@ namespace VisualPinball.Unity { - public class GateWireAnimationAuthoring : ItemMovementAuthoring, IConvertGameObjectToEntity + public class GateWireAnimationAuthoring : ItemAnimationAuthoring, IConvertGameObjectToEntity { public override IEnumerable ValidParents { get; } = new Type[0]; // animation components only apply to their own diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs index 6620987d3..efedeaa08 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetApi.cs @@ -54,8 +54,10 @@ public bool IsDropped { set => SetIsDropped(value); } - internal HitTargetApi(HitTarget item, Entity entity, Entity parentEntity, Player player) : base(item, entity, parentEntity, player) + + internal HitTargetApi(HitTarget item, Entity entity, Entity parentEntity, PhysicsMaterial physicsMaterial, Player player) : base(item, entity, parentEntity, player) { + _physicsMaterial = physicsMaterial; } /// @@ -92,6 +94,8 @@ private void SetIsDropped(bool isDropped) #region Collider Generation + private readonly PhysicsMaterial _physicsMaterial; + protected override bool FireHitEvents => Data.UseHitEvent; protected override float HitThreshold => Data.Threshold; Entity IApiColliderGenerator.ColliderEntity => Entity; @@ -102,7 +106,7 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider colliderGenerator.GenerateColliders(table, colliders); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(_physicsMaterial); #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetAuthoring.cs index db8545fa0..5afbbfba6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetAuthoring.cs @@ -46,13 +46,6 @@ public class HitTargetAuthoring : ItemMainRenderableAuthoring Item; - private void OnDestroy() - { - if (!Application.isPlaying) { - Table?.Remove(Name); - } - } - public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { Convert(entity, dstManager); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetColliderAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetColliderAuthoring.cs index b113b4e81..dcdeab2e9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetColliderAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetColliderAuthoring.cs @@ -29,6 +29,6 @@ public class HitTargetColliderAuthoring : ItemColliderAuthoring ValidParents => ValidParentTypes; protected override IApiColliderGenerator InstantiateColliderApi(Player player, Entity entity, Entity parentEntity) - => new HitTargetApi(Item, entity, parentEntity, player); + => new HitTargetApi(Item, entity, parentEntity, PhysicsMaterial, player); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetColliderGenerator.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetColliderGenerator.cs index 0d0ea8a39..fe9ceb6a2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetColliderGenerator.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetColliderGenerator.cs @@ -114,22 +114,22 @@ private void GenerateDropTargetColliders(Table table, ICollection col var rgv1 = rgv3D[i1].ToUnityFloat3(); var rgv2 = rgv3D[i2].ToUnityFloat3(); - colliders.Add(new TriangleCollider(rgv0, rgv2, rgv1, GetColliderInfo(table, true))); + colliders.Add(new TriangleCollider(rgv0, rgv2, rgv1, GetColliderInfo(true))); if (addedEdges.ShouldAddHitEdge(i0, i1)) { - colliders.Add(new Line3DCollider(rgv0, rgv2, GetColliderInfo(table, true))); + colliders.Add(new Line3DCollider(rgv0, rgv2, GetColliderInfo(true))); } if (addedEdges.ShouldAddHitEdge(i1, i2)) { - colliders.Add(new Line3DCollider(rgv2, rgv1, GetColliderInfo(table, true))); + colliders.Add(new Line3DCollider(rgv2, rgv1, GetColliderInfo(true))); } if (addedEdges.ShouldAddHitEdge(i2, i0)) { - colliders.Add(new Line3DCollider(rgv1, rgv0, GetColliderInfo(table, true))); + colliders.Add(new Line3DCollider(rgv1, rgv0, GetColliderInfo(true))); } } // add collision vertices for (var i = 0; i < DropTargetHitPlaneVertices.Length; ++i) { - colliders.Add(new PointCollider(rgv3D[i].ToUnityFloat3(), GetColliderInfo(table, true))); + colliders.Add(new PointCollider(rgv3D[i].ToUnityFloat3(), GetColliderInfo(true))); } } } @@ -147,28 +147,28 @@ private void GenerateCollidables(Mesh hitMesh, EdgeSet addedEdges, bool setHitOb var rgv1 = hitMesh.Vertices[i1].ToUnityFloat3(); var rgv2 = hitMesh.Vertices[i2].ToUnityFloat3(); - colliders.Add(new TriangleCollider(rgv0, rgv2, rgv1, GetColliderInfo(table, setHitObject))); + colliders.Add(new TriangleCollider(rgv0, rgv2, rgv1, GetColliderInfo(setHitObject))); if (addedEdges.ShouldAddHitEdge(i0, i1)) { - colliders.Add(new Line3DCollider(rgv0, rgv2, GetColliderInfo(table, setHitObject))); + colliders.Add(new Line3DCollider(rgv0, rgv2, GetColliderInfo(setHitObject))); } if (addedEdges.ShouldAddHitEdge(i1, i2)) { - colliders.Add(new Line3DCollider(rgv2, rgv1, GetColliderInfo(table, setHitObject))); + colliders.Add(new Line3DCollider(rgv2, rgv1, GetColliderInfo(setHitObject))); } if (addedEdges.ShouldAddHitEdge(i2, i0)) { - colliders.Add(new Line3DCollider(rgv1, rgv0, GetColliderInfo(table, setHitObject))); + colliders.Add(new Line3DCollider(rgv1, rgv0, GetColliderInfo(setHitObject))); } } // add collision vertices foreach (var vertex in hitMesh.Vertices) { - colliders.Add(new PointCollider(vertex.ToUnityFloat3(), GetColliderInfo(table, setHitObject))); + colliders.Add(new PointCollider(vertex.ToUnityFloat3(), GetColliderInfo(setHitObject))); } } - private ColliderInfo GetColliderInfo(Table table, bool setHitObject) + private ColliderInfo GetColliderInfo(bool setHitObject) { - var info = _api.GetColliderInfo(table); + var info = _api.GetColliderInfo(); info.FireEvents = setHitObject && info.FireEvents; return info; } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetExtensions.cs index 25dfbdd94..8e0ca4c4e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetExtensions.cs @@ -15,9 +15,7 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; using NLog; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.HitTarget; @@ -25,20 +23,17 @@ namespace VisualPinball.Unity { - internal static class HitTargetExtensions + public static class HitTargetExtensions { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static ConvertedItem SetupGameObject(this HitTarget hitTarget, GameObject obj) + public static IConvertedItem SetupGameObject(this HitTarget hitTarget, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(hitTarget); - var meshAuthoring = new List(); - HitTargetColliderAuthoring colliderAuthoring = null; - + var convertedItem = new ConvertedItem(obj, hitTarget, componentsAdded); switch (hitTarget.SubComponent) { case ItemSubComponent.None: - colliderAuthoring = obj.AddColliderComponent(hitTarget); - meshAuthoring.Add(obj.AddComponent()); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); + convertedItem.SetMeshAuthoring(componentsAdded); break; case ItemSubComponent.Collider: { @@ -54,14 +49,8 @@ public static ConvertedItem SetupGameObject(this HitTarget hitTarget, GameObject default: throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); - } - private static HitTargetColliderAuthoring AddColliderComponent(this GameObject obj, HitTarget hitTarget) - { - return hitTarget.Data.IsCollidable ? obj.AddComponent() : null; + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetMovementSystem.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetMovementSystem.cs index a26bad507..9d1005a68 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetMovementSystem.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/HitTarget/HitTargetMovementSystem.cs @@ -30,7 +30,7 @@ internal class HitTargetMovementSystem : SystemBase protected override void OnStartRunning() { - var root = Object.FindObjectOfType(); + var root = Object.FindObjectOfType(); var ltw = root.gameObject.transform.localToWorldMatrix; _baseTransform = new float4x4( ltw.m00, ltw.m01, ltw.m02, ltw.m03, diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs index 355d89ed4..60e6914a7 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IApi.cs @@ -36,7 +36,7 @@ internal interface IApiInitializable public interface IApiColliderGenerator { void CreateColliders(Table table, List colliders); - ColliderInfo GetColliderInfo(Table table); + ColliderInfo GetColliderInfo(); Entity ColliderEntity { get; } bool IsColliderEnabled { get; } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMovementAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemAnimationAuthoring.cs similarity index 92% rename from VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMovementAuthoring.cs rename to VisualPinball.Unity/VisualPinball.Unity/VPT/IItemAnimationAuthoring.cs index 7fc5109c0..fdd0af2f2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMovementAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemAnimationAuthoring.cs @@ -16,7 +16,7 @@ namespace VisualPinball.Unity { - public interface IItemMovementAuthoring + public interface IItemAnimationAuthoring { } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemAnimationAuthoring.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemAnimationAuthoring.cs.meta new file mode 100644 index 000000000..96684803f --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemAnimationAuthoring.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22f4236678e3ee8409103407149d1b8b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemColliderAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemColliderAuthoring.cs index ca9aee470..0a0a7b9d8 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemColliderAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemColliderAuthoring.cs @@ -21,7 +21,7 @@ namespace VisualPinball.Unity { public interface IItemColliderAuthoring : IItemAuthoring { - IItemMainRenderableAuthoring MainAuthoring { get; } + IItemMainAuthoring MainAuthoring { get; } IEnumerable ValidParents { get; } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMainAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMainAuthoring.cs index a981d4c2c..306e72935 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMainAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMainAuthoring.cs @@ -24,6 +24,8 @@ namespace VisualPinball.Unity { public interface IItemMainAuthoring : IItemAuthoring { + void FillBinaryData(); + void FreeBinaryData(); IEnumerable ValidParents { get; } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMainRenderableAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMainRenderableAuthoring.cs index f9a9553f3..4fb4b4c4f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMainRenderableAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMainRenderableAuthoring.cs @@ -27,8 +27,7 @@ public interface IItemMainRenderableAuthoring : IItemMainAuthoring /// /// Sets the mesh of all mesh sub components to dirty. /// - void SetMeshDirty(); - void RebuildMeshIfDirty(); + void RebuildMeshes(); void DestroyMeshComponent(); void DestroyColliderComponent(); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMeshAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMeshAuthoring.cs index 8c2522aed..98ead4b62 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMeshAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMeshAuthoring.cs @@ -23,8 +23,6 @@ namespace VisualPinball.Unity { public interface IItemMeshAuthoring : IItemAuthoring { - bool MeshDirty { get; set; } - List MaterialRefs { get; } List TextureRefs { get; } @@ -32,6 +30,8 @@ public interface IItemMeshAuthoring : IItemAuthoring GameObject gameObject { get; } + void CreateMesh(string parentName, ITextureProvider texProvider, IMaterialProvider matProvider, IMeshProvider meshProvider, bool loadFromAsset); + void RebuildMeshes(); IEnumerable ValidParents { get; } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMovementAuthoring.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMovementAuthoring.cs.meta deleted file mode 100644 index 3ad3a21b1..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/IItemMovementAuthoring.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 73a8933e2b1bcc740b97b383ff67cb95 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMovementAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemAnimationAuthoring.cs similarity index 88% rename from VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMovementAuthoring.cs rename to VisualPinball.Unity/VisualPinball.Unity/VPT/ItemAnimationAuthoring.cs index 3ac0ce7c1..732cd4f26 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMovementAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemAnimationAuthoring.cs @@ -22,8 +22,8 @@ namespace VisualPinball.Unity { - public abstract class ItemMovementAuthoring : ItemSubAuthoring, - IItemMovementAuthoring + public abstract class ItemAnimationAuthoring : ItemSubAuthoring, + IItemAnimationAuthoring where TData : ItemData where TItem : Item, IRenderable where TMainAuthoring : ItemMainRenderableAuthoring diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemAnimationAuthoring.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemAnimationAuthoring.cs.meta new file mode 100644 index 000000000..902a118f8 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemAnimationAuthoring.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a806988655e114438439e39d55e88f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs index 348e2db50..e370fb91e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemApi.cs @@ -80,13 +80,12 @@ private protected void DestroyBall(Entity ballEntity) #region Collider - public virtual bool IsColliderEnabled => !(Data is IPhysicalData physicalData) || physicalData.GetIsCollidable(); + public virtual bool IsColliderEnabled => !(Data is IPhysicsMaterialData physicalData) || physicalData.GetIsCollidable(); protected virtual bool FireHitEvents { get; } = false; protected virtual float HitThreshold { get; } = 0; - protected virtual PhysicsMaterialData GetPhysicsMaterial(Table table) + protected virtual PhysicsMaterialData GetPhysicsMaterial(PhysicsMaterial mat) { - if (Data is IPhysicalData physicalData) { - var mat = table.GetMaterial(physicalData.GetPhysicsMaterial()); + if (Data is IPhysicsMaterialData physicalData) { var matData = new PhysicsMaterialData(); if (mat != null && !physicalData.GetOverwritePhysics()) { matData.Elasticity = mat.Elasticity; @@ -110,10 +109,10 @@ protected virtual PhysicsMaterialData GetPhysicsMaterial(Table table) /// /// Use this for colliders that are part of the quad tree. /// - /// - internal ColliderInfo GetColliderInfo(Table table) => GetColliderInfo(table, Item.ItemType); + /// physics material read from the collider component + internal ColliderInfo GetColliderInfo(PhysicsMaterial physicsMaterial = null) => GetColliderInfo(Item.ItemType, physicsMaterial); - internal ColliderInfo GetColliderInfo(Table table, ItemType itemType) + internal ColliderInfo GetColliderInfo(ItemType itemType, PhysicsMaterial physicsMaterial = null) { return new ColliderInfo { Id = -1, @@ -122,7 +121,7 @@ internal ColliderInfo GetColliderInfo(Table table, ItemType itemType) ParentEntity = ParentEntity, FireEvents = FireHitEvents, IsEnabled = IsColliderEnabled, - Material = GetPhysicsMaterial(table), + Material = GetPhysicsMaterial(physicsMaterial), HitThreshold = HitThreshold, }; } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemAuthoring.cs index 33959b635..b75ab6a45 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemAuthoring.cs @@ -69,8 +69,10 @@ public abstract class ItemAuthoring : MonoBehaviour, public bool IsLocked { get => Data.IsLocked; set => Data.IsLocked = value; } private Table _table; + private TableContainer _tableContainer; - protected Table Table => _table ?? (_table = GetComponentInParent()?.Item); + protected Table Table => _table ??= GetComponentInParent()?.Item; + protected TableContainer TableContainer => _tableContainer ??= GetComponentInParent()?.TableContainer; public virtual void ItemDataChanged() { diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemColliderAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemColliderAuthoring.cs index a2fe1c46b..21870f817 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemColliderAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemColliderAuthoring.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using Unity.Entities; using UnityEngine; +using UnityEngine.Profiling; using VisualPinball.Engine.Game; using VisualPinball.Engine.Math; using VisualPinball.Engine.VPT; @@ -27,12 +28,16 @@ namespace VisualPinball.Unity { + [DisallowMultipleComponent] public abstract class ItemColliderAuthoring : ItemSubAuthoring, IItemColliderAuthoring where TData : ItemData - where TItem : Item, IRenderable - where TMainAuthoring : ItemMainRenderableAuthoring + where TItem : Item + where TMainAuthoring : ItemMainAuthoring { + [SerializeField] + public PhysicsMaterial PhysicsMaterial; + [NonSerialized] public bool ShowGizmos; @@ -47,7 +52,7 @@ public abstract class ItemColliderAuthoring : Item public List Colliders { get; private set; } - public new IItemMainRenderableAuthoring MainAuthoring => base.MainAuthoring; + public new IItemMainAuthoring MainAuthoring => base.MainAuthoring; private readonly Entity _colliderEntity = new Entity {Index = -2, Version = 0}; @@ -55,12 +60,15 @@ public abstract class ItemColliderAuthoring : Item private void OnDrawGizmosSelected() { + Profiler.BeginSample("ItemColliderAuthoring.OnDrawGizmosSelected"); if (!ShowGizmos || !ShowAabbs && !ShowColliderMesh) { + Profiler.EndSample(); return; } var player = GetComponentInParent(); if (player == null) { + Profiler.EndSample(); return; } var api = InstantiateColliderApi(player, _colliderEntity, Entity.Null); @@ -80,6 +88,7 @@ private void OnDrawGizmosSelected() DrawCollider(ltw, col, i == SelectedCollider); } } + Profiler.EndSample(); } #region Collider Gizmos @@ -206,8 +215,8 @@ private void DrawCollider(Matrix4x4 ltw, ICollider hitObject, bool isSelected) } } - if (mesh == null) { - var ro = Item.GetRenderObject(Table, FlipperMeshGenerator.Rubber, Origin.Original); + if (mesh == null && Item is IRenderable renderableItem) { + var ro = renderableItem.GetRenderObject(Table, FlipperMeshGenerator.Rubber, Origin.Original); mesh = ro.Mesh.ToUnityMesh(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMainAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMainAuthoring.cs index 6b9d97fdd..cc50cd460 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMainAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMainAuthoring.cs @@ -25,11 +25,18 @@ namespace VisualPinball.Unity { + [DisallowMultipleComponent] public abstract class ItemMainAuthoring : ItemAuthoring, IItemMainAuthoring, ILayerableItemAuthoring, IIdentifiableItemAuthoring where TItem : Item where TData : ItemData { + /// + /// If false is returned, no colliders will be created. If your + /// component collides, but not per default, set this to true. + /// + public virtual bool IsCollidable => true; + #region Data /// @@ -41,7 +48,7 @@ public abstract class ItemMainAuthoring : ItemAuthoring - public override TItem Item => _item ?? (_item = InstantiateItem(_data)); + public override TItem Item => _item ??= InstantiateItem(_data); /// /// Applies the GameObject data to the item data. typically name and visibility. @@ -92,6 +99,15 @@ public void Destroy() #region Parenting + public virtual void FillBinaryData() + { + } + + public void FreeBinaryData() + { + Item.FreeBinaryData(); + } + /// /// List of types for parenting. Empty list if only to own parent. /// @@ -136,7 +152,7 @@ private IItemMainRenderableAuthoring FindParentAuthoring() } // search on grand parent - if (go.transform.parent.transform.parent != null) { + if (go.transform.parent != null && go.transform.parent.transform.parent != null) { ma = go.transform.parent.transform.parent.GetComponent(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMainRenderableAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMainRenderableAuthoring.cs index c0e08f6b7..04ab687c2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMainRenderableAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMainRenderableAuthoring.cs @@ -24,7 +24,8 @@ namespace VisualPinball.Unity { - public abstract class ItemMainRenderableAuthoring : ItemMainAuthoring, IItemMainRenderableAuthoring + public abstract class ItemMainRenderableAuthoring : ItemMainAuthoring, + IItemMainRenderableAuthoring where TItem : Item, IRenderable where TData : ItemData { @@ -37,6 +38,7 @@ public abstract class ItemMainRenderableAuthoring : ItemMainAuthor protected abstract Type ColliderAuthoringType { get; } + /// /// Returns all child mesh components linked to this data. /// @@ -50,24 +52,14 @@ public abstract class ItemMainRenderableAuthoring : ItemMainAuthor .Select(c => (IItemColliderAuthoring) c) .Where(ca => ca.ItemData == _data) : new IItemColliderAuthoring[0]; - public void SetMeshDirty() + public void RebuildMeshes() { foreach (var meshComponent in MeshComponents) { - meshComponent.MeshDirty = true; + meshComponent.RebuildMeshes(); } - } - public void RebuildMeshIfDirty() - { - foreach (var meshComponent in MeshComponents) { - if (meshComponent.MeshDirty) { - meshComponent.RebuildMeshes(); - } - } - - // update transform based on item data, but not for "Table" since its the effective "root" and the user might want to move it on their own var ta = GetComponentInParent(); - if (ta != this) { + if (ta != this && Item != null) { transform.SetFromMatrix(Item.TransformationMatrix(Table, Origin.Original).ToUnityMatrix()); } } @@ -116,24 +108,6 @@ protected void Convert(Entity entity, EntityManager dstManager) } } - protected virtual void OnDrawGizmos() - { - // handle dirty whenever scene view draws just in case a field or dependant changed and our - // custom inspector window isn't up to process it - RebuildMeshIfDirty(); - - // Draw invisible gizmos over top of the sub meshes of this item so clicking in the scene view - // selects the item itself first, which is most likely what the user would want - var mfs = GetComponentsInChildren(); - Gizmos.color = Color.clear; - Gizmos.matrix = Matrix4x4.identity; - foreach (var mf in mfs) { - var t = mf.transform; - if(mf.sharedMesh != null && mf.sharedMesh.vertexCount>0) - Gizmos.DrawMesh(mf.sharedMesh, t.position, t.rotation, t.lossyScale); - } - } - #region Tools public virtual ItemDataTransformType EditorPositionType => ItemDataTransformType.None; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMeshAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMeshAuthoring.cs index 038c41a3f..fe61b447a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMeshAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMeshAuthoring.cs @@ -24,14 +24,14 @@ namespace VisualPinball.Unity { - public abstract class ItemMeshAuthoring : ItemSubAuthoring, IItemMeshAuthoring + public abstract class ItemMeshAuthoring : ItemSubAuthoring, + IItemMeshAuthoring where TData : ItemData where TItem : Item, IRenderable where TAuthoring : ItemMainRenderableAuthoring { - public bool MeshDirty { get => _meshDirty; set => _meshDirty = value; } - public List MaterialRefs => _materialRefs ?? (_materialRefs = GetMembersWithAttribute()); - public List TextureRefs => _textureRefs ?? (_textureRefs = GetMembersWithAttribute()); + public List MaterialRefs => _materialRefs ??= GetMembersWithAttribute(); + public List TextureRefs => _textureRefs ??= GetMembersWithAttribute(); public IItemMainRenderableAuthoring IMainAuthoring => MainAuthoring; @@ -41,24 +41,11 @@ public abstract class ItemMeshAuthoring : ItemSubAutho private List _materialRefs; private List _textureRefs; - // for tracking if we need to rebuild the meshes (handled by the editor scripts) during undo/redo flows - [HideInInspector] - [SerializeField] - private bool _meshDirty; - #region Creation and destruction [HideInInspector] [SerializeField] - private bool _meshCreated; - - private void Awake() - { - if (!_meshCreated && gameObject.GetComponent() == null) { - CreateMesh(); - _meshCreated = true; - } - } + private bool _meshCreated = true; private void OnEnable() { @@ -90,33 +77,35 @@ public void RebuildMeshes() { UpdateMesh(); ItemDataChanged(); - _meshDirty = false; } - private void CreateMesh() + public void CreateMesh(string parentName, ITextureProvider texProvider, IMaterialProvider matProvider, IMeshProvider meshProvider, bool loadFromAsset) { var ta = GetComponentInParent(); var ro = Item.GetRenderObject(ta.Table, MeshId, Origin.Original, false); if (ro?.Mesh == null) { return; } - var mesh = ro.Mesh.ToUnityMesh($"{gameObject.name}_Mesh"); + var mesh = loadFromAsset + ? meshProvider.GetMesh(parentName, gameObject.name) + : ro.Mesh.ToUnityMesh($"{gameObject.name}_Mesh"); + enabled = ro.IsVisible; // apply mesh to game object - var mf = gameObject.AddComponent(); + var mf = loadFromAsset ? gameObject.GetComponent() : gameObject.AddComponent(); mf.sharedMesh = mesh; // apply material if (ro.Mesh.AnimationFrames.Count > 1) { // if number of animations frames are 1, the blend vertices are in the uvs are handle by the lerp shader. - var smr = gameObject.AddComponent(); - smr.sharedMaterial = ro.Material.ToUnityMaterial(ta, MainAuthoring.Item.GetType()); + var smr = loadFromAsset ? gameObject.GetComponent() : gameObject.AddComponent(); + smr.sharedMaterial = ro.Material.ToUnityMaterial(matProvider, texProvider, MainAuthoring.Item.GetType()); smr.sharedMesh = mesh; smr.SetBlendShapeWeight(0, ro.Mesh.AnimationDefaultPosition); smr.enabled = ro.IsVisible; } else { - var mr = gameObject.AddComponent(); - mr.sharedMaterial = ro.Material.ToUnityMaterial(ta, MainAuthoring.Item.GetType()); + var mr = loadFromAsset ? gameObject.GetComponent() : gameObject.AddComponent(); + mr.sharedMaterial = ro.Material.ToUnityMaterial(matProvider, texProvider, MainAuthoring.Item.GetType()); mr.enabled = ro.IsVisible; } } @@ -131,42 +120,19 @@ private void UpdateMesh() if (ro == null) { return; } - var mr = GetComponent(); var mf = GetComponent(); if (mf != null) { var unityMesh = mf.sharedMesh; - if (ro.Mesh != null) { - ro.Mesh.ApplyToUnityMesh(unityMesh); - } + ro.Mesh?.ApplyToUnityMesh(unityMesh); } - if (mr != null) { - if (ta != null) { - mr.sharedMaterial = ro.Material.ToUnityMaterial(ta, MainAuthoring.Item.GetType()); - } - mr.enabled = true; - } - } - - protected virtual void OnDrawGizmos() - { - // handle dirty whenever scene view draws just in case a field or dependant changed and our - // custom inspector window isn't up to process it - if (_meshDirty) { - RebuildMeshes(); - } - - // Draw invisible gizmos over top of the sub meshes of this item so clicking in the scene view - // selects the item itself first, which is most likely what the user would want - var mfs = GetComponentsInChildren(); - Gizmos.color = Color.clear; - Gizmos.matrix = Matrix4x4.identity; - foreach (var mf in mfs) { - var t = mf.transform; - if(mf.sharedMesh != null && mf.sharedMesh.vertexCount>0) - Gizmos.DrawMesh(mf.sharedMesh, t.position, t.rotation, t.lossyScale); - } + // if (mr != null) { + // if (ta != null) { + // mr.sharedMaterial = ro.Material.ToUnityMaterial(ta, MainAuthoring.Item.GetType()); + // } + // mr.enabled = true; + // } } private static List GetMembersWithAttribute() where TAttr: Attribute diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMovementAuthoring.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMovementAuthoring.cs.meta deleted file mode 100644 index d2cd66120..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemMovementAuthoring.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 77aa9ac03dbd4cc489a4afeddb587ef0 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemSubAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemSubAuthoring.cs index fd5981ec6..bd7f6f9d5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemSubAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/ItemSubAuthoring.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; -using VisualPinball.Engine.Game; using VisualPinball.Engine.VPT; namespace VisualPinball.Unity @@ -23,9 +22,9 @@ namespace VisualPinball.Unity /// Data type of the item /// Type of the main component, where the data is. public abstract class ItemSubAuthoring : ItemAuthoring - where TItem : Item, IRenderable + where TItem : Item where TData : ItemData - where TMainAuthoring : ItemMainRenderableAuthoring + where TMainAuthoring : ItemMainAuthoring { /// /// We're in a sub component here, so in order to retrieve the data, @@ -92,6 +91,10 @@ private TMainAuthoring FindMainAuthoring() if (ac != null) { return ac; } + if (this is IItemColliderAuthoring) { + // collider must be on the same game object + return null; + } // search on parent if (go.transform.parent != null) { @@ -105,6 +108,14 @@ private TMainAuthoring FindMainAuthoring() if (go.transform.parent.transform.parent != null) { ac = go.transform.parent.transform.parent.GetComponent(); } + if (ac != null) { + return ac; + } + + // search on great grand parent + if (go.transform.parent.transform.parent.transform.parent != null) { + ac = go.transform.parent.transform.parent.transform.parent.GetComponent(); + } if (ac == null) { Debug.LogWarning("No same- or parent authoring component found."); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs index 71b625b3e..1b52be2e1 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs @@ -200,10 +200,10 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider var radius = Data.Radius * (Data.LegacyMode ? Data.FallThrough ? 0.75f : 0.6f : 1f); colliders.Add(new CircleCollider(Data.Center.ToUnityFloat2(), radius, height, - height + Data.HitHeight, GetColliderInfo(table), ColliderType.KickerCircle)); + height + Data.HitHeight, GetColliderInfo(), ColliderType.KickerCircle)); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(); #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerAuthoring.cs index 74d1cd7ee..45c042ba6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerAuthoring.cs @@ -46,13 +46,6 @@ public class KickerAuthoring : ItemMainRenderableAuthoring, public ISwitchable Switchable => Item; - private void OnDestroy() - { - if (!Application.isPlaying) { - Table?.Remove(Name); - } - } - public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { Convert(entity, dstManager); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerExtensions.cs index 6f5ce2365..45953d55c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerExtensions.cs @@ -15,9 +15,7 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; using NLog; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Kicker; @@ -25,20 +23,17 @@ namespace VisualPinball.Unity { - internal static class KickerExtensions + public static class KickerExtensions { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static ConvertedItem SetupGameObject(this Kicker kicker, GameObject obj) + public static IConvertedItem SetupGameObject(this Kicker kicker, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(kicker); - var meshAuthoring = new List(); - KickerColliderAuthoring colliderAuthoring = null; - + var convertedItem = new ConvertedItem(obj, kicker, componentsAdded); switch (kicker.SubComponent) { case ItemSubComponent.None: - colliderAuthoring = obj.AddComponent(); - meshAuthoring.Add(obj.AddComponent()); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); + convertedItem.SetMeshAuthoring(componentsAdded); break; case ItemSubComponent.Collider: { @@ -54,9 +49,8 @@ public static ConvertedItem SetupGameObject(this Kicker kicker, GameObject obj) default: throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightAuthoring.cs index dc8dcd6fd..ed84116ed 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightAuthoring.cs @@ -151,18 +151,14 @@ public void OnBulbEnabled(bool bulbEnabledBefore, bool bulbEnabledAfter) return; } + var convertedItem = new ConvertedItem(gameObject); if (bulbEnabledAfter) { - ConvertedItem.CreateChild(gameObject, LightMeshGenerator.Bulb); - ConvertedItem.CreateChild(gameObject, LightMeshGenerator.Socket); + convertedItem.AddMeshAuthoring(LightMeshGenerator.Bulb, false); + convertedItem.AddMeshAuthoring(LightMeshGenerator.Socket, false); + } else { - var bulbMeshAuthoring = GetComponentInChildren(); - if (bulbMeshAuthoring != null) { - DestroyImmediate(bulbMeshAuthoring.gameObject); - } - var socketMeshAuthoring = GetComponentInChildren(); - if (socketMeshAuthoring != null) { - DestroyImmediate(socketMeshAuthoring.gameObject); - } + convertedItem.Destroy(); + convertedItem.Destroy(); } } @@ -174,7 +170,7 @@ public override void ItemDataChanged() _unityLight = GetComponentInChildren(includeInactive: true); if (_unityLight == null) { var lightObj = new GameObject("Light (Unity)") { - layer = VpxConverter.ChildObjectsLayer + layer = SceneTableContainer.ChildObjectsLayer }; lightObj.transform.parent = transform; lightObj.transform.localPosition = Vector3.zero; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightExtensions.cs index cae79e2b2..feff80245 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightExtensions.cs @@ -14,28 +14,26 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using System.Collections.Generic; using UnityEngine; using VisualPinball.Engine.VPT.Light; using Light = VisualPinball.Engine.VPT.Light.Light; namespace VisualPinball.Unity { - internal static class LightExtensions + public static class LightExtensions { - public static ConvertedItem SetupGameObject(this Light light, GameObject obj) + public static IConvertedItem SetupGameObject(this Light light, GameObject obj, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(light); - var meshAuthoring = new List(); + var convertedItem = new ConvertedItem(obj, light, componentsAdded); if (!light.Data.ShowBulbMesh) { - return new ConvertedItem(mainAuthoring); + return convertedItem; } - meshAuthoring.Add(ConvertedItem.CreateChild(obj, LightMeshGenerator.Bulb)); - meshAuthoring.Add(ConvertedItem.CreateChild(obj, LightMeshGenerator.Socket)); + convertedItem.AddMeshAuthoring(LightMeshGenerator.Bulb, componentsAdded); + convertedItem.AddMeshAuthoring(LightMeshGenerator.Socket, componentsAdded); - return new ConvertedItem(mainAuthoring, meshAuthoring); + return convertedItem; } } } diff --git a/VisualPinball.Engine/VPT/Table/ITableResourceContainer.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/PhysicsMaterial.cs similarity index 53% rename from VisualPinball.Engine/VPT/Table/ITableResourceContainer.cs rename to VisualPinball.Unity/VisualPinball.Unity/VPT/PhysicsMaterial.cs index 67140031b..939d29642 100644 --- a/VisualPinball.Engine/VPT/Table/ITableResourceContainer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/PhysicsMaterial.cs @@ -1,4 +1,4 @@ -// Visual Pinball Engine +// Visual Pinball Engine // Copyright (C) 2021 freezy and VPE Team // // This program is free software: you can redistribute it and/or modify @@ -14,22 +14,23 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using System.Collections.Generic; +using UnityEngine; -namespace VisualPinball.Engine.VPT.Table +namespace VisualPinball.Unity { /// - /// Dictionary-like interface for table global resources (such as images/textures) - /// Does not provide arbitrary key access, instead all access is implicit based on INameable.Name + /// A physical material used by the physics engine

+ /// + /// Materials are actually a big deal in VP, authors as well as players + /// tweak them all the time, so getting those from external assets instead + /// of writing them into the scene seems a good plan. ///

- /// - public interface ITableResourceContainer : IEnumerable where T : IItem + [CreateAssetMenu(fileName = "PhysicsMaterial", menuName = "Visual Pinball/Physics Material", order = 100)] + public class PhysicsMaterial : ScriptableObject { - int Count { get; } - IEnumerable Values { get; } - T this[string k] { get; } - T Get(string k); - void Add(T value); - bool Remove(T value); + public float Elasticity; + public float ElasticityFalloff; + public float Friction; + public float ScatterAngle; } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/PhysicsMaterial.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/PhysicsMaterial.cs.meta new file mode 100644 index 000000000..66b041371 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/PhysicsMaterial.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5fa7fff06a9fe954bb96788ed81eeb79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldAuthoring.cs index 3c5bcfb1d..fd958552a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldAuthoring.cs @@ -28,7 +28,7 @@ public class PlayfieldAuthoring : ItemMainRenderableAuthoring, { public override bool CanBeTransformed => false; - protected override Table InstantiateItem(TableData data) => GetComponentInParent().Table; + protected override Table InstantiateItem(TableData data) => GetComponentInParent()?.Table; protected override Type MeshAuthoringType { get; } = null; protected override Type ColliderAuthoringType { get; } = null; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldColliderAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldColliderAuthoring.cs index e6db9b7ab..8d1ac90b9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldColliderAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldColliderAuthoring.cs @@ -23,7 +23,7 @@ namespace VisualPinball.Unity { [AddComponentMenu("Visual Pinball/Collision/Playfield Collider")] - public class PlayfieldColliderAuthoring : ItemColliderAuthoring + public class PlayfieldColliderAuthoring : ItemColliderAuthoring { public static readonly Type[] ValidParentTypes = new Type[0]; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldExtensions.cs index 40626241d..f0631672e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Playfield/PlayfieldExtensions.cs @@ -14,24 +14,22 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT.Table; using VisualPinball.Unity.Playfield; namespace VisualPinball.Unity { - internal static class PlayfieldExtensions + public static class PlayfieldExtensions { - public static ConvertedItem SetupGameObject(this Table table, GameObject obj) + public static IConvertedItem SetupGameObject(this Table table, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - obj.AddComponent().SetItem(table); - obj.AddComponent(); - obj.AddComponent(); - obj.AddComponent(); - obj.name = "Default Playfield"; - - return new ConvertedItem(); + var convertedItem = new ConvertedItem(obj, table, componentsAdded) { + IsProceduralMesh = false + }; + convertedItem.SetMeshAuthoring(componentsAdded); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs index c7b01d0fe..8cf7a2d9b 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerApi.cs @@ -149,10 +149,10 @@ IApiCoil IApiCoilDevice.Coil(string coilId) void IApiColliderGenerator.CreateColliders(Table table, List colliders) { var zHeight = table.GetSurfaceHeight(Data.Surface, Data.Center.X, Data.Center.Y); - colliders.Add(new PlungerCollider(Data, zHeight, GetColliderInfo(table))); + colliders.Add(new PlungerCollider(Data, zHeight, GetColliderInfo())); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(); #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerAuthoring.cs index cc2cbc9fd..c1d476c1f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerAuthoring.cs @@ -24,6 +24,7 @@ using VisualPinball.Engine.Game.Engines; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Plunger; +using Mesh = VisualPinball.Engine.VPT.Mesh; namespace VisualPinball.Unity { @@ -154,56 +155,44 @@ public void OnTypeChanged(int plungerTypeBefore, int plungerTypeAfter) return; } + var convertedItem = new ConvertedItem(gameObject); switch (plungerTypeBefore) { case PlungerType.PlungerTypeFlat: // remove flat - var flatPlungerAuthoring = GetComponentInChildren(); - if (flatPlungerAuthoring != null) { - DestroyImmediate(flatPlungerAuthoring.gameObject); - } + convertedItem.Destroy(); // create rod - ConvertedItem.CreateChild(gameObject, PlungerMeshGenerator.Rod); + convertedItem.AddMeshAuthoring(PlungerMeshGenerator.Rod, false); if (plungerTypeAfter == PlungerType.PlungerTypeCustom) { // create spring - ConvertedItem.CreateChild(gameObject, PlungerMeshGenerator.Spring); + convertedItem.AddMeshAuthoring(PlungerMeshGenerator.Spring, false); } break; case PlungerType.PlungerTypeModern: if (plungerTypeAfter == PlungerType.PlungerTypeCustom) { // create spring - ConvertedItem.CreateChild(gameObject, PlungerMeshGenerator.Spring); + convertedItem.AddMeshAuthoring(PlungerMeshGenerator.Spring, false); } if (plungerTypeAfter == PlungerType.PlungerTypeFlat) { // remove rod - var rodPlungerAuthoring = GetComponentInChildren(); - if (rodPlungerAuthoring != null) { - DestroyImmediate(rodPlungerAuthoring.gameObject); - } + convertedItem.Destroy(); // create flat - ConvertedItem.CreateChild(gameObject, PlungerMeshGenerator.Flat); + convertedItem.AddMeshAuthoring(PlungerMeshGenerator.Flat, false); } break; case PlungerType.PlungerTypeCustom: // remove spring - var springPlungerAuthoring = GetComponentInChildren(); - if (springPlungerAuthoring != null) { - DestroyImmediate(springPlungerAuthoring.gameObject); - } + convertedItem.Destroy(); if (plungerTypeAfter == PlungerType.PlungerTypeFlat) { // remove rod - var rodPlungerAuthoring = GetComponentInChildren(); - if (rodPlungerAuthoring != null) { - DestroyImmediate(rodPlungerAuthoring.gameObject); - } - + convertedItem.Destroy(); // create flat - ConvertedItem.CreateChild(gameObject, PlungerMeshGenerator.Flat); + convertedItem.AddMeshAuthoring(PlungerMeshGenerator.Flat, false); } break; } @@ -213,8 +202,8 @@ public void OnTypeChanged(int plungerTypeBefore, int plungerTypeAfter) public void UpdateParkPosition(float pos) { - SetMaterialProperty(UVChannelVertices, Engine.VPT.Mesh.AnimationUVChannelVertices); - SetMaterialProperty(UVChannelNormals, Engine.VPT.Mesh.AnimationUVChannelNormals); + SetMaterialProperty(UVChannelVertices, Mesh.AnimationUVChannelVertices); + SetMaterialProperty(UVChannelNormals, Mesh.AnimationUVChannelNormals); switch (Data.Type) { case PlungerType.PlungerTypeFlat: { SetMaterialProperty(LerpPosition, pos); @@ -232,13 +221,6 @@ public void UpdateParkPosition(float pos) } } - private void OnDestroy() - { - if (!Application.isPlaying) { - Table?.Remove(Name); - } - } - public override ItemDataTransformType EditorPositionType => ItemDataTransformType.TwoD; public override Vector3 GetEditorPosition() => Data.Center.ToUnityVector3(0f); public override void SetEditorPosition(Vector3 pos) => Data.Center = pos.ToVertex2Dxy(); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerExtensions.cs index 74b8abdc6..877800307 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerExtensions.cs @@ -15,9 +15,7 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; using NLog; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Plunger; @@ -25,36 +23,32 @@ namespace VisualPinball.Unity { - internal static class PlungerExtensions + public static class PlungerExtensions { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static ConvertedItem SetupGameObject(this Plunger plunger, GameObject obj) + public static IConvertedItem SetupGameObject(this Plunger plunger, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(plunger); - var meshAuthoring = new List(); - PlungerColliderAuthoring colliderAuthoring = null; - + var convertedItem = new ConvertedItem(obj, plunger, componentsAdded); switch (plunger.SubComponent) { - case ItemSubComponent.None: { - colliderAuthoring = obj.AddComponent(); + case ItemSubComponent.None: + + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); switch (plunger.Data.Type) { case PlungerType.PlungerTypeFlat: - meshAuthoring.Add(ConvertedItem.CreateChild(obj, PlungerMeshGenerator.Flat)); + convertedItem.AddMeshAuthoring(PlungerMeshGenerator.Flat, componentsAdded); break; case PlungerType.PlungerTypeCustom: - meshAuthoring.Add(ConvertedItem.CreateChild(obj, PlungerMeshGenerator.Spring)); - meshAuthoring.Add(ConvertedItem.CreateChild(obj, PlungerMeshGenerator.Rod)); + convertedItem.AddMeshAuthoring(PlungerMeshGenerator.Spring, componentsAdded); + convertedItem.AddMeshAuthoring(PlungerMeshGenerator.Rod, componentsAdded); break; case PlungerType.PlungerTypeModern: - meshAuthoring.Add(ConvertedItem.CreateChild(obj, PlungerMeshGenerator.Rod)); + convertedItem.AddMeshAuthoring(PlungerMeshGenerator.Rod, componentsAdded); break; - } break; - } case ItemSubComponent.Collider: { Logger.Warn("Cannot parent a plunger collider to a different object than a plunger!"); @@ -69,8 +63,8 @@ public static ConvertedItem SetupGameObject(this Plunger plunger, GameObject obj default: throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); + + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs index ed093cead..5ed6be058 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveApi.cs @@ -35,12 +35,15 @@ public class PrimitiveApi : ItemApi, ///
public event EventHandler Hit; - internal PrimitiveApi(Primitive item, Entity entity, Entity parentEntity, Player player) : base(item, entity, parentEntity, player) + internal PrimitiveApi(Primitive item, Entity entity, Entity parentEntity, PhysicsMaterial physicsMaterial, Player player) : base(item, entity, parentEntity, player) { + _physicsMaterial = physicsMaterial; } #region Collider Generation + private readonly PhysicsMaterial _physicsMaterial; + protected override bool FireHitEvents => Data.HitEvent; protected override float HitThreshold => Data.Threshold; Entity IApiColliderGenerator.ColliderEntity => Entity; @@ -51,7 +54,7 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider colliderGenerator.GenerateColliders(table, colliders); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(_physicsMaterial); #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveAuthoring.cs index 6c1a6031e..ee5a71909 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveAuthoring.cs @@ -32,6 +32,7 @@ namespace VisualPinball.Unity [AddComponentMenu("Visual Pinball/Game Item/Primitive")] public class PrimitiveAuthoring : ItemMainRenderableAuthoring, IConvertGameObjectToEntity { + public override bool IsCollidable => !Data.IsToy; protected override Primitive InstantiateItem(PrimitiveData data) => new Primitive(data); protected override Type MeshAuthoringType { get; } = typeof(ItemMeshAuthoring); @@ -79,6 +80,20 @@ public override void Restore() } } + public override void FillBinaryData() + { + var meshAuth = GetComponent(); + if (!meshAuth) { + meshAuth = GetComponentInChildren(); + } + + var meshGo = meshAuth ? meshAuth.gameObject : gameObject; + var mf = meshGo.GetComponent(); + if (mf) { + Data.Mesh = mf.sharedMesh.ToVpMesh(); + } + } + public override ItemDataTransformType EditorPositionType => ItemDataTransformType.ThreeD; public override Vector3 GetEditorPosition() => Data.Position.ToUnityVector3(); public override void SetEditorPosition(Vector3 pos) => Data.Position = pos.ToVertex3D(); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderAuthoring.cs index b18a8b925..f8825c65e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderAuthoring.cs @@ -33,6 +33,6 @@ public class PrimitiveColliderAuthoring : ItemColliderAuthoring ValidParents => ValidParentTypes; protected override IApiColliderGenerator InstantiateColliderApi(Player player, Entity entity, Entity parentEntity) - => new PrimitiveApi(Item, entity, parentEntity, player); + => new PrimitiveApi(Item, entity, parentEntity, PhysicsMaterial, player); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderGenerator.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderGenerator.cs index e22c63f0b..b88dc20be 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderGenerator.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveColliderGenerator.cs @@ -32,7 +32,7 @@ namespace VisualPinball.Unity { public class PrimitiveColliderGenerator { - private readonly PrimitiveApi _api; + private readonly IApiColliderGenerator _api; private readonly PrimitiveData _data; private readonly PrimitiveMeshGenerator _meshGenerator; private bool _useAsPlayfield; @@ -68,7 +68,7 @@ internal void GenerateColliders(Table table, List colliders) mesh = ComputeReducedMesh(mesh, reducedVertices); } - ColliderUtils.GenerateCollidersFromMesh(table, mesh, _api.GetColliderInfo(table), colliders); + ColliderUtils.GenerateCollidersFromMesh(table, mesh, _api.GetColliderInfo(), colliders); } private static Mesh ComputeReducedMesh(Mesh mesh, uint reducedVertices) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveExtensions.cs index 40c3f925a..e1f15b3d9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Primitive/PrimitiveExtensions.cs @@ -15,54 +15,41 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Primitive; namespace VisualPinball.Unity { - internal static class PrimitiveExtensions + public static class PrimitiveExtensions { - public static ConvertedItem SetupGameObject(this Primitive primitive, GameObject obj) + public static IConvertedItem SetupGameObject(this Primitive primitive, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(primitive); - var meshAuthoring = new List(); - PrimitiveColliderAuthoring colliderAuthoring = null; + var convertedItem = new ConvertedItem(obj, primitive, componentsAdded) { + IsProceduralMesh = false + }; switch (primitive.SubComponent) { - case ItemSubComponent.None: { - colliderAuthoring = obj.AddColliderComponent(primitive); - meshAuthoring.Add(obj.AddComponent()); + case ItemSubComponent.None: + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); + convertedItem.SetMeshAuthoring(componentsAdded); break; - } case ItemSubComponent.Collider: { - colliderAuthoring = obj.AddColliderComponent(primitive); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); break; } case ItemSubComponent.Mesh: { - meshAuthoring.Add(obj.AddComponent()); + convertedItem.SetMeshAuthoring(componentsAdded); break; } default: throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); - } - private static PrimitiveColliderAuthoring AddColliderComponent(this GameObject obj, Primitive primitive) - { - // todo handle dynamic collision - if (!primitive.Data.IsToy && primitive.IsCollidable) { - return obj.AddComponent(); - } - return null; + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs index 13008a773..72fd6ee2d 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampApi.cs @@ -28,8 +28,9 @@ public class RampApi : ItemApi, ///
public event EventHandler Init; - internal RampApi(Engine.VPT.Ramp.Ramp item, Entity entity, Entity parentEntity, Player player) : base(item, entity, parentEntity, player) + internal RampApi(Engine.VPT.Ramp.Ramp item, Entity entity, Entity parentEntity, PhysicsMaterial physicsMaterial, Player player) : base(item, entity, parentEntity, player) { + _physicsMaterial = physicsMaterial; } #region Events @@ -44,6 +45,8 @@ void IApiInitializable.OnInit(BallManager ballManager) #region Collider Generation + private readonly PhysicsMaterial _physicsMaterial; + protected override bool FireHitEvents => Data.HitEvent; protected override float HitThreshold => Data.Threshold; Entity IApiColliderGenerator.ColliderEntity => Entity; @@ -54,7 +57,7 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider colliderGenerator.GenerateColliders(table, colliders); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(_physicsMaterial); #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampAuthoring.cs index ea911d6e9..89ee443e6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampAuthoring.cs @@ -84,13 +84,6 @@ public override void Restore() } } - private void OnDestroy() - { - if (!Application.isPlaying) { - Table?.Remove(Name); - } - } - public void UpdateMeshComponents(int rampTypeBefore, int rampTypeAfter) { var rampFlatBefore = rampTypeBefore == RampType.RampTypeFlat; @@ -99,24 +92,16 @@ public void UpdateMeshComponents(int rampTypeBefore, int rampTypeAfter) return; } + var convertedItem = new ConvertedItem(gameObject); if (rampFlatAfter) { - var flatRampAuthoring = GetComponentInChildren(); - if (flatRampAuthoring != null) { - DestroyImmediate(flatRampAuthoring.gameObject); - } - ConvertedItem.CreateChild(gameObject, RampMeshGenerator.Floor); - ConvertedItem.CreateChild(gameObject, RampMeshGenerator.Wall); + convertedItem.Destroy(); + convertedItem.AddMeshAuthoring(RampMeshGenerator.Floor, false); + convertedItem.AddMeshAuthoring(RampMeshGenerator.Wall, false); } else { - var flatFloorAuthoring = GetComponentInChildren(); - if (flatFloorAuthoring != null) { - DestroyImmediate(flatFloorAuthoring.gameObject); - } - var flatWallAuthoring = GetComponentInChildren(); - if (flatWallAuthoring != null) { - DestroyImmediate(flatWallAuthoring.gameObject); - } - ConvertedItem.CreateChild(gameObject, RampMeshGenerator.Wires); + convertedItem.Destroy(); + convertedItem.Destroy(); + convertedItem.AddMeshAuthoring(RampMeshGenerator.Wires, false); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampColliderAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampColliderAuthoring.cs index 96b6747c8..c93451fab 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampColliderAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampColliderAuthoring.cs @@ -31,6 +31,6 @@ public class RampColliderAuthoring : ItemColliderAuthoring ValidParents => ValidParentTypes; protected override IApiColliderGenerator InstantiateColliderApi(Player player, Entity entity, Entity parentEntity) - => new RampApi(Item, entity, parentEntity, player); + => new RampApi(Item, entity, parentEntity, PhysicsMaterial, player); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampColliderGenerator.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampColliderGenerator.cs index 9d2a27abf..25c893001 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampColliderGenerator.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampColliderGenerator.cs @@ -26,7 +26,7 @@ namespace VisualPinball.Unity { public class RampColliderGenerator { - private readonly RampApi _api; + private readonly IApiColliderGenerator _api; private readonly RampData _data; private readonly RampMeshGenerator _meshGenerator; @@ -64,12 +64,12 @@ internal void GenerateColliders(Table table, List colliders) // add joints at start and end of right wall if (i == 0) { colliders.Add(new LineZCollider(pv2, rgHeight1[0], rgHeight1[0] + wallHeightRight, - _api.GetColliderInfo(table))); + _api.GetColliderInfo())); } if (i == vertexCount - 2) { colliders.Add(new LineZCollider(pv3, rgHeight1[vertexCount - 1], rgHeight1[vertexCount - 1] + wallHeightRight, - _api.GetColliderInfo(table))); + _api.GetColliderInfo())); } } } @@ -88,12 +88,12 @@ internal void GenerateColliders(Table table, List colliders) // add joints at start and end of left wall if (i == 0) { colliders.Add(new LineZCollider(pv2, rgHeight1[vertexCount - 1], - rgHeight1[vertexCount - 1] + wallHeightLeft, _api.GetColliderInfo(table))); + rgHeight1[vertexCount - 1] + wallHeightLeft, _api.GetColliderInfo())); } if (i == vertexCount - 2) { colliders.Add(new LineZCollider(pv3, rgHeight1[0], rgHeight1[0] + wallHeightLeft, - _api.GetColliderInfo(table))); + _api.GetColliderInfo())); } } } @@ -123,15 +123,15 @@ internal void GenerateColliders(Table table, List colliders) // add joint for starting edge of ramp if (i == 0) { - colliders.Add(new Line3DCollider(rg0, rg1, _api.GetColliderInfo(table))); + colliders.Add(new Line3DCollider(rg0, rg1, _api.GetColliderInfo())); } // add joint for left edge - colliders.Add(new Line3DCollider(rg0, rg2, _api.GetColliderInfo(table))); + colliders.Add(new Line3DCollider(rg0, rg2, _api.GetColliderInfo())); // degenerate triangles happen if width is 0 at some point if (!TriangleCollider.IsDegenerate(rg0, rg1, rg2)) { - var ph3dPoly = new TriangleCollider(rg0, rg1, rg2, _api.GetColliderInfo(table)); + var ph3dPoly = new TriangleCollider(rg0, rg1, rg2, _api.GetColliderInfo()); colliders.Add(ph3dPoly); CheckJoint(isOldSet, in ph3dPolyOld, in ph3dPoly, table, colliders); @@ -145,10 +145,10 @@ internal void GenerateColliders(Table table, List colliders) rg2 = new float3(pv4.x, pv4.y, rgHeight1[i + 1]); // add joint for right edge - colliders.Add(new Line3DCollider(rg1, rg2, _api.GetColliderInfo(table))); + colliders.Add(new Line3DCollider(rg1, rg2, _api.GetColliderInfo())); if (!TriangleCollider.IsDegenerate(rg0, rg1, rg2)) { - var ph3dPoly = new TriangleCollider(rg0, rg1, rg2, _api.GetColliderInfo(table)); + var ph3dPoly = new TriangleCollider(rg0, rg1, rg2, _api.GetColliderInfo()); colliders.Add(ph3dPoly); CheckJoint(isOldSet, in ph3dPolyOld, in ph3dPoly, table, colliders); @@ -161,7 +161,7 @@ internal void GenerateColliders(Table table, List colliders) // add joint for final edge of ramp var v1 = new float3(pv4.x, pv4.y, rgHeight1[vertexCount - 1]); var v2 = new float3(pv3.x, pv3.y, rgHeight1[vertexCount - 1]); - colliders.Add(new Line3DCollider(v1, v2, _api.GetColliderInfo(table))); + colliders.Add(new Line3DCollider(v1, v2, _api.GetColliderInfo())); } // add outside bottom, @@ -181,7 +181,7 @@ internal void GenerateColliders(Table table, List colliders) var rg2 = new float3(pv3.x, pv3.y, rgHeight1[i + 1]); if (!TriangleCollider.IsDegenerate(rg0, rg1, rg2)) { - colliders.Add(new TriangleCollider(rg0, rg1, rg2, _api.GetColliderInfo(table))); + colliders.Add(new TriangleCollider(rg0, rg1, rg2, _api.GetColliderInfo())); } // right ramp triangle, order CW @@ -190,7 +190,7 @@ internal void GenerateColliders(Table table, List colliders) rg2 = new float3(pv1.x, pv1.y, rgHeight1[i]); if (!TriangleCollider.IsDegenerate(rg0, rg1, rg2)) { - colliders.Add(new TriangleCollider(rg0, rg1, rg2, _api.GetColliderInfo(table))); + colliders.Add(new TriangleCollider(rg0, rg1, rg2, _api.GetColliderInfo())); } } } @@ -223,10 +223,10 @@ private void GenerateWallLineSeg(float2 pv1, float2 pv2, bool pv3Exists, float h } else { colliders.Add(new LineCollider(pv1, pv2, height1, height2 + wallHeight, - _api.GetColliderInfo(table))); + _api.GetColliderInfo())); if (pv3Exists) { - colliders.Add(new LineZCollider(pv1, height1, height2 + wallHeight, _api.GetColliderInfo(table))); + colliders.Add(new LineZCollider(pv1, height1, height2 + wallHeight, _api.GetColliderInfo())); } } } @@ -242,7 +242,7 @@ private void CheckJoint(bool isOldSet, in TriangleCollider ph3d1, in TriangleCol } // By convention of the calling function, points 1 [0] and 2 [1] of the second polygon will // be the common-edge points - colliders.Add(new Line3DCollider(ph3d2.Rgv0, ph3d2.Rgv1, _api.GetColliderInfo(table))); + colliders.Add(new Line3DCollider(ph3d2.Rgv0, ph3d2.Rgv1, _api.GetColliderInfo())); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampExtensions.cs index ffd1c3987..aaa798eee 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ramp/RampExtensions.cs @@ -15,9 +15,7 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; using NLog; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Ramp; @@ -25,29 +23,26 @@ namespace VisualPinball.Unity { - internal static class RampExtensions + public static class RampExtensions { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static ConvertedItem SetupGameObject(this Ramp ramp, GameObject obj) + public static IConvertedItem SetupGameObject(this Ramp ramp, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(ramp); - var meshAuthoring = new List(); - RampColliderAuthoring colliderAuthoring = null; - + var convertedItem = new ConvertedItem(obj, ramp, componentsAdded); switch (ramp.SubComponent) { case ItemSubComponent.None: - colliderAuthoring = obj.AddColliderComponent(ramp); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); if (ramp.IsHabitrail) { - meshAuthoring.Add(ConvertedItem.CreateChild(obj, RampMeshGenerator.Wires)); + convertedItem.AddMeshAuthoring(RampMeshGenerator.Wires, componentsAdded); } else { - meshAuthoring.Add(ConvertedItem.CreateChild(obj, RampMeshGenerator.Floor)); - meshAuthoring.Add(ConvertedItem.CreateChild(obj, RampMeshGenerator.Wall)); + convertedItem.AddMeshAuthoring(RampMeshGenerator.Floor, componentsAdded); + convertedItem.AddMeshAuthoring(RampMeshGenerator.Wall, componentsAdded); } break; case ItemSubComponent.Collider: { - colliderAuthoring = obj.AddColliderComponent(ramp); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); break; } @@ -59,13 +54,8 @@ public static ConvertedItem SetupGameObject(this Ramp ramp, GameObject obj) default: throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); - } - private static RampColliderAuthoring AddColliderComponent(this GameObject obj, Ramp ramp) - { - return ramp.Data.IsCollidable ? obj.AddComponent() : null; + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberApi.cs index 1fbc2bfcc..6eb16c076 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberApi.cs @@ -34,12 +34,15 @@ public class RubberApi : ItemApi public event EventHandler Hit; - internal RubberApi(Engine.VPT.Rubber.Rubber item, Entity entity, Entity parentEntity, Player player) : base(item, entity, parentEntity, player) + internal RubberApi(Engine.VPT.Rubber.Rubber item, Entity entity, Entity parentEntity, PhysicsMaterial physicsMaterial, Player player) : base(item, entity, parentEntity, player) { + _physicsMaterial = physicsMaterial; } #region Collider Generation + private readonly PhysicsMaterial _physicsMaterial; + protected override bool FireHitEvents => Data.HitEvent; protected override float HitThreshold { get; } = 2.0f; // hard coded threshold for now Entity IApiColliderGenerator.ColliderEntity => Entity; @@ -50,7 +53,7 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider colliderGenerator.GenerateColliders(table, colliders); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(_physicsMaterial); #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberAuthoring.cs index 1871a6306..83277e539 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberAuthoring.cs @@ -43,13 +43,6 @@ public class RubberAuthoring : ItemMainRenderableAuthoring, .Concat(RubberMeshAuthoring.ValidParentTypes) .Distinct(); - private void OnDestroy() - { - if (!Application.isPlaying) { - Table?.Remove(Name); - } - } - public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { Convert(entity, dstManager); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberColliderAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberColliderAuthoring.cs index 3cb3062de..48d042df4 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberColliderAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberColliderAuthoring.cs @@ -29,6 +29,6 @@ public class RubberColliderAuthoring : ItemColliderAuthoring ValidParents => ValidParentTypes; protected override IApiColliderGenerator InstantiateColliderApi(Player player, Entity entity, Entity parentEntity) - => new RubberApi(Item, entity, parentEntity, player); + => new RubberApi(Item, entity, parentEntity, PhysicsMaterial, player); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberColliderGenerator.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberColliderGenerator.cs index 811459a64..1adae2ca4 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberColliderGenerator.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberColliderGenerator.cs @@ -23,7 +23,7 @@ namespace VisualPinball.Unity { public class RubberColliderGenerator { - private readonly RubberApi _api; + private readonly IApiColliderGenerator _api; private readonly RubberMeshGenerator _meshGenerator; public RubberColliderGenerator(RubberApi rubberApi) @@ -44,7 +44,7 @@ internal void GenerateColliders(Table table, List colliders) 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(table))); + colliders.Add(new TriangleCollider(rg0, rg1, rg2, _api.GetColliderInfo())); GenerateHitEdge(mesh, addedEdges, mesh.Indices[i], mesh.Indices[i + 2], table, colliders); GenerateHitEdge(mesh, addedEdges, mesh.Indices[i + 2], mesh.Indices[i + 1], table, colliders); @@ -53,7 +53,7 @@ internal void GenerateColliders(Table table, List colliders) // add collision vertices foreach (var mv in mesh.Vertices) { - colliders.Add(new PointCollider(mv.ToUnityFloat3(), _api.GetColliderInfo(table))); + colliders.Add(new PointCollider(mv.ToUnityFloat3(), _api.GetColliderInfo())); } } @@ -63,7 +63,7 @@ private void GenerateHitEdge(Mesh mesh, EdgeSet addedEdges, int i, int j, 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(table))); + colliders.Add(new Line3DCollider(v1, v2, _api.GetColliderInfo())); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberExtensions.cs index 8d1765bce..76d354094 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Rubber/RubberExtensions.cs @@ -15,36 +15,30 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Rubber; namespace VisualPinball.Unity { - internal static class RubberExtensions + public static class RubberExtensions { - public static ConvertedItem SetupGameObject(this Rubber rubber, GameObject obj) + public static IConvertedItem SetupGameObject(this Rubber rubber, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(rubber); - var meshAuthoring = new List(); - RubberColliderAuthoring colliderAuthoring = null; - + var convertedItem = new ConvertedItem(obj, rubber, componentsAdded); switch (rubber.SubComponent) { - case ItemSubComponent.None: { - colliderAuthoring = obj.AddColliderComponent(rubber); - meshAuthoring.Add(obj.AddComponent()); + case ItemSubComponent.None: + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); + convertedItem.SetMeshAuthoring(componentsAdded); break; - } case ItemSubComponent.Collider: { - colliderAuthoring = obj.AddColliderComponent(rubber); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); break; } case ItemSubComponent.Mesh: { - meshAuthoring.Add(obj.AddComponent()); + convertedItem.SetMeshAuthoring(componentsAdded); break; } @@ -52,8 +46,7 @@ public static ConvertedItem SetupGameObject(this Rubber rubber, GameObject obj) throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); + return convertedItem.AddConvertToEntity(componentsAdded); } private static RubberColliderAuthoring AddColliderComponent(this GameObject obj, Rubber rubber) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs index 502361fb4..ba82d132a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerApi.cs @@ -87,7 +87,7 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider colliderGenerator.GenerateColliders(table, colliders); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(); #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerAuthoring.cs index a6664785a..ddcf2b0d1 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerAuthoring.cs @@ -90,13 +90,6 @@ public override void Restore() // collision: spinners are always collidable } - private void OnDestroy() - { - if (!Application.isPlaying) { - Table?.Remove(Name); - } - } - public override ItemDataTransformType EditorPositionType => ItemDataTransformType.ThreeD; public override Vector3 GetEditorPosition() => Data.Center.ToUnityVector3(Data.Height); public override void SetEditorPosition(Vector3 pos) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerColliderGenerator.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerColliderGenerator.cs index fea04b7af..95455eab4 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerColliderGenerator.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerColliderGenerator.cs @@ -35,7 +35,7 @@ public SpinnerColliderGenerator(SpinnerApi spinnerApi) internal void GenerateColliders(Table table, List colliders) { var height = table.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y); - colliders.Add(new SpinnerCollider(_data, height, _api.GetColliderInfo(table))); + colliders.Add(new SpinnerCollider(_data, height, _api.GetColliderInfo())); if (_data.ShowBracket) { GenerateBracketColliders(table, colliders); } @@ -57,7 +57,7 @@ private void GenerateBracketColliders(Table table, ICollection collid _data.Length * 0.075f, height + _data.Height, height + h, - _api.GetColliderInfo(table) + _api.GetColliderInfo() )); colliders.Add(new CircleCollider( @@ -65,7 +65,7 @@ private void GenerateBracketColliders(Table table, ICollection collid _data.Length * 0.075f, height + _data.Height, height + h, - _api.GetColliderInfo(table) + _api.GetColliderInfo() )); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerExtensions.cs index 5a4bf0d96..157a7d006 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerExtensions.cs @@ -15,9 +15,7 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; using NLog; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Spinner; @@ -25,24 +23,19 @@ namespace VisualPinball.Unity { - internal static class SpinnerExtensions + public static class SpinnerExtensions { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static ConvertedItem SetupGameObject(this Spinner spinner, GameObject obj) + public static IConvertedItem SetupGameObject(this Spinner spinner, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var meshAuthoring = new List(); - var mainAuthoring = obj.AddComponent().SetItem(spinner); - SpinnerColliderAuthoring colliderAuthoring = null; - + var convertedItem = new ConvertedItem(obj, spinner, componentsAdded); switch (spinner.SubComponent) { case ItemSubComponent.None: - colliderAuthoring = obj.AddComponent(); - meshAuthoring.Add(ConvertedItem.CreateChild(obj, SpinnerMeshGenerator.Bracket)); - - var wireMeshAuth = ConvertedItem.CreateChild(obj, SpinnerMeshGenerator.Plate); - wireMeshAuth.gameObject.AddComponent(); - meshAuthoring.Add(wireMeshAuth); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); + convertedItem.AddMeshAuthoring(SpinnerMeshGenerator.Bracket, componentsAdded); + convertedItem.AddMeshAuthoring(SpinnerMeshGenerator.Plate, componentsAdded); + convertedItem.SetAnimationAuthoring(SpinnerMeshGenerator.Plate); break; case ItemSubComponent.Collider: { @@ -58,8 +51,8 @@ public static ConvertedItem SetupGameObject(this Spinner spinner, GameObject obj default: throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); + + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerPlateAnimationAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerPlateAnimationAuthoring.cs index 48a52ad17..7f4fd4b13 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerPlateAnimationAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerPlateAnimationAuthoring.cs @@ -22,7 +22,7 @@ namespace VisualPinball.Unity { - public class SpinnerPlateAnimationAuthoring : ItemMovementAuthoring, IConvertGameObjectToEntity + public class SpinnerPlateAnimationAuthoring : ItemAnimationAuthoring, IConvertGameObjectToEntity { public override IEnumerable ValidParents { get; } = new Type[0]; // animation components only apply to their own diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceApi.cs index a6a4b3ac1..c3621a774 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceApi.cs @@ -39,12 +39,15 @@ public class SurfaceApi : ItemApi public event EventHandler Slingshot; - internal SurfaceApi(Engine.VPT.Surface.Surface item, Entity entity, Entity parentEntity, Player player) : base(item, entity, parentEntity, player) + internal SurfaceApi(Engine.VPT.Surface.Surface item, Entity entity, Entity parentEntity, PhysicsMaterial physicsMaterial, Player player) : base(item, entity, parentEntity, player) { + _physicsMaterial = physicsMaterial; } #region Collider Generation + private readonly PhysicsMaterial _physicsMaterial; + protected override bool FireHitEvents { get; } = true; protected override float HitThreshold => Data.Threshold; Entity IApiColliderGenerator.ColliderEntity => Entity; @@ -55,7 +58,7 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider colliderGenerator.GenerateColliders(table, colliders); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(_physicsMaterial); #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceAuthoring.cs index 36e182ae3..d97f6307e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceAuthoring.cs @@ -83,13 +83,6 @@ public override void Restore() } } - private void OnDestroy() - { - if (!Application.isPlaying) { - Table?.Remove(Name); - } - } - public override ItemDataTransformType EditorPositionType => ItemDataTransformType.TwoD; public override Vector3 GetEditorPosition() { if (Data == null || Data.DragPoints.Length == 0) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceColliderAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceColliderAuthoring.cs index 22216d284..f48bb9cc9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceColliderAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceColliderAuthoring.cs @@ -32,6 +32,6 @@ public class SurfaceColliderAuthoring : ItemColliderAuthoring ValidParents => ValidParentTypes; protected override IApiColliderGenerator InstantiateColliderApi(Player player, Entity entity, Entity parentEntity) - => new SurfaceApi(Item, entity, parentEntity, player); + => new SurfaceApi(Item, entity, parentEntity, PhysicsMaterial, player); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceColliderGenerator.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceColliderGenerator.cs index 098079cfe..ce151ef17 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceColliderGenerator.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceColliderGenerator.cs @@ -26,7 +26,7 @@ namespace VisualPinball.Unity { public class SurfaceColliderGenerator { - private readonly SurfaceApi _api; + private readonly IApiColliderGenerator _api; private readonly SurfaceData _data; public SurfaceColliderGenerator(SurfaceApi surfaceApi) @@ -59,10 +59,10 @@ internal void GenerateColliders(Table table, List colliders) GenerateLinePolys(pv2, pv3, table, colliders); } - ColliderUtils.Generate3DPolyColliders(in rgv3Dt, table, _api.GetColliderInfo(table), colliders); + ColliderUtils.Generate3DPolyColliders(in rgv3Dt, table, _api.GetColliderInfo(), colliders); if (rgv3Db != null) { - ColliderUtils.Generate3DPolyColliders(in rgv3Db, table, _api.GetColliderInfo(table), colliders); + ColliderUtils.Generate3DPolyColliders(in rgv3Db, table, _api.GetColliderInfo(), colliders); } } @@ -75,29 +75,29 @@ private void GenerateLinePolys(RenderVertex2D pv1, Vertex2D pv2, Table table, IC var top = _data.HeightTop + table.TableHeight; if (!pv1.IsSlingshot) { - colliders.Add(new LineCollider(pv1.ToUnityFloat2(), pv2.ToUnityFloat2(), bottom, top, _api.GetColliderInfo(table))); + colliders.Add(new LineCollider(pv1.ToUnityFloat2(), pv2.ToUnityFloat2(), bottom, top, _api.GetColliderInfo())); } else { - colliders.Add(new LineSlingshotCollider(_data.SlingshotForce, pv1.ToUnityFloat2(), pv2.ToUnityFloat2(), bottom, top, _api.GetColliderInfo(table))); + colliders.Add(new LineSlingshotCollider(_data.SlingshotForce, pv1.ToUnityFloat2(), pv2.ToUnityFloat2(), bottom, top, _api.GetColliderInfo())); } if (_data.HeightBottom != 0) { // add lower edge as a line - colliders.Add(new Line3DCollider(new float3(pv1.X, pv1.Y, bottom), new float3(pv2.X, pv2.Y, bottom), _api.GetColliderInfo(table))); + colliders.Add(new Line3DCollider(new float3(pv1.X, pv1.Y, bottom), new float3(pv2.X, pv2.Y, bottom), _api.GetColliderInfo())); } // add upper edge as a line - colliders.Add(new Line3DCollider(new float3(pv1.X, pv1.Y, top), new float3(pv2.X, pv2.Y, top), _api.GetColliderInfo(table))); + colliders.Add(new Line3DCollider(new float3(pv1.X, pv1.Y, top), new float3(pv2.X, pv2.Y, top), _api.GetColliderInfo())); // create vertical joint between the two line segments - colliders.Add(new LineZCollider(pv1.ToUnityFloat2(), bottom, top, _api.GetColliderInfo(table))); + colliders.Add(new LineZCollider(pv1.ToUnityFloat2(), bottom, top, _api.GetColliderInfo())); // add upper and lower end points of line if (_data.HeightBottom != 0) { - colliders.Add(new PointCollider(new float3(pv1.X, pv1.Y, bottom), _api.GetColliderInfo(table))); + colliders.Add(new PointCollider(new float3(pv1.X, pv1.Y, bottom), _api.GetColliderInfo())); } - colliders.Add(new PointCollider(new float3(pv1.X, pv1.Y, top), _api.GetColliderInfo(table))); + colliders.Add(new PointCollider(new float3(pv1.X, pv1.Y, top), _api.GetColliderInfo())); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceExtensions.cs index 9ce8777ae..11399155f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Surface/SurfaceExtensions.cs @@ -15,50 +15,40 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Surface; namespace VisualPinball.Unity { - internal static class SurfaceExtensions + public static class SurfaceExtensions { - public static ConvertedItem SetupGameObject(this Surface surface, GameObject obj) + public static IConvertedItem SetupGameObject(this Surface surface, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(surface); - var meshAuthoring = new List(); - SurfaceColliderAuthoring colliderAuthoring = null; - + var convertedItem = new ConvertedItem(obj, surface, componentsAdded); switch (surface.SubComponent) { case ItemSubComponent.None: - colliderAuthoring = obj.AddColliderComponent(surface); - meshAuthoring.Add(ConvertedItem.CreateChild(obj, SurfaceMeshGenerator.Side)); - meshAuthoring.Add(ConvertedItem.CreateChild(obj, SurfaceMeshGenerator.Top)); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); + convertedItem.AddMeshAuthoring(SurfaceMeshGenerator.Side, componentsAdded); + convertedItem.AddMeshAuthoring(SurfaceMeshGenerator.Top, componentsAdded); break; case ItemSubComponent.Collider: { - colliderAuthoring = obj.AddColliderComponent(surface); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); break; } case ItemSubComponent.Mesh: { - meshAuthoring.Add(ConvertedItem.CreateChild(obj, SurfaceMeshGenerator.Side)); - meshAuthoring.Add(ConvertedItem.CreateChild(obj, SurfaceMeshGenerator.Top)); + convertedItem.AddMeshAuthoring(SurfaceMeshGenerator.Side, componentsAdded); + convertedItem.AddMeshAuthoring(SurfaceMeshGenerator.Top, componentsAdded); break; } default: throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); - } - private static SurfaceColliderAuthoring AddColliderComponent(this GameObject obj, Surface surface) - { - return surface.Data.IsCollidable ? obj.AddComponent() : null; + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/LegacyContainer.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/LegacyContainer.cs new file mode 100644 index 000000000..c75edfda8 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/LegacyContainer.cs @@ -0,0 +1,192 @@ +// 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 System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEngine; +using VisualPinball.Engine.VPT; +using VisualPinball.Engine.VPT.Decal; +using VisualPinball.Engine.VPT.DispReel; +using VisualPinball.Engine.VPT.Flasher; +using VisualPinball.Engine.VPT.LightSeq; +using VisualPinball.Engine.VPT.Sound; +using VisualPinball.Engine.VPT.TextBox; +using VisualPinball.Engine.VPT.Timer; +using Texture = UnityEngine.Texture; + +namespace VisualPinball.Unity +{ + /// + /// Legacy in VPE is data from Visual Pinball 10 that isn't used in VPE, + /// but still available to export. + /// + [Serializable] + public class LegacyContainer + { + public DecalData[] Decals; + public DispReelData[] DispReels; + public FlasherData[] Flashers; + public LightSeqData[] LightSeqs; + public TextBoxData[] TextBoxes; + public TimerData[] Timers; + public List Textures = new List(); + public List Sounds = new List(); + } + + [Serializable] + public class LegacySound + { + public string Name => AudioClip == null ? "" : AudioClip.name; + public string InternalName; + public string Path; + public WaveFormat Wfx; + public byte OutputTarget; + public int Volume; + public int Balance; + public int Fade; + + public AudioClip AudioClip; + + public bool IsSet => AudioClip != null; + + public LegacySound() + { + } + + public LegacySound(SoundData data, AudioClip audioClip) + { + AudioClip = audioClip; + InternalName = data.InternalName; + Path = data.Path; + Wfx = data.Wfx; + OutputTarget = data.OutputTarget; + Volume = data.Volume; + Balance = data.Balance; + Fade = data.Fade; + } + + public LegacySound(AudioClip audioClip) + { + AudioClip = audioClip; + InternalName = audioClip.name; + } + + public Sound ToSound() + { + if (AudioClip == null) { + throw new InvalidOperationException("Cannot convert to sound without audio clip!"); + } + var data = new SoundData(AudioClip.name) { + InternalName = InternalName, + Path = Path, + Wfx = Wfx, + OutputTarget = OutputTarget, + Volume = Volume, + Balance = Balance, + Fade = Fade + }; + data.Wfx.FormatTag = 1; + data.Wfx.Channels = (ushort)(AudioClip.channels == 2 ? 2 : 1); + data.Wfx.SamplesPerSec = (uint)AudioClip.frequency; + data.Wfx.BitsPerSample = 16; + data.Wfx.BlockAlign = (ushort)(data.Wfx.BitsPerSample / 8 * data.Wfx.Channels); + data.Wfx.AvgBytesPerSec = data.Wfx.SamplesPerSec * data.Wfx.BlockAlign; + + #if UNITY_EDITOR + var path = UnityEditor.AssetDatabase.GetAssetPath(AudioClip); + if (!string.IsNullOrEmpty(path)) { + var bytes = File.ReadAllBytes(path); + data.Data = path.ToLower().EndsWith(".wav") + ? bytes.Skip(44).ToArray() + : bytes; + } + #endif + + return new Sound(data); + } + } + + [Serializable] + public class LegacyTexture + { + public string Name => Texture == null ? "" : Texture.name; + public string InternalName; + public string Path; + public float AlphaTestValue; + public Texture Texture; + + /// + /// As textures are converted (e.g. webp), we convert to png so it can + /// be read by Unity, but keep the original file around to save it back + /// later. This points to the original file. + /// + public string OriginalPath; + + public bool IsSet => Texture != null; + + public LegacyTexture() + { + } + + public LegacyTexture(TextureData data, Texture texture) + { + InternalName = data.InternalName; + Path = data.Path; + AlphaTestValue = data.AlphaTestValue; + Texture = texture; + } + + public LegacyTexture(Texture texture) + { + Texture = texture; + InternalName = texture.name; + } + + public Engine.VPT.Texture ToTexture() + { + if (Texture == null) { + throw new InvalidOperationException("Cannot convert to texture without texture!"); + } + var data = new TextureData(Texture.name) { + InternalName = InternalName, + Path = Path, + AlphaTestValue = AlphaTestValue, + Width = Texture.width, + Height = Texture.height + }; + + #if UNITY_EDITOR + var path = OriginalPath != null && File.Exists(OriginalPath) + ? OriginalPath + : UnityEditor.AssetDatabase.GetAssetPath(Texture); + if (!string.IsNullOrEmpty(path)) { + var bytes = File.ReadAllBytes(path); + data.Binary = new BinaryData(Texture.name, bytes) { + InternalName = InternalName, + Path = path, + Size = bytes.Length, + }; + } + #endif + + return new Engine.VPT.Texture(data); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/LegacyContainer.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/LegacyContainer.cs.meta new file mode 100644 index 000000000..296ebb4b5 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/LegacyContainer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1641408d3d13c5d4e9da47f456751d14 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/SceneTableContainer.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/SceneTableContainer.cs new file mode 100644 index 000000000..d6587c527 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/SceneTableContainer.cs @@ -0,0 +1,362 @@ +// 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using UnityEngine; +using VisualPinball.Engine.VPT; +using VisualPinball.Engine.VPT.Collection; +using VisualPinball.Engine.VPT.Decal; +using VisualPinball.Engine.VPT.DispReel; +using VisualPinball.Engine.VPT.Flasher; +using VisualPinball.Engine.VPT.LightSeq; +using VisualPinball.Engine.VPT.Mappings; +using VisualPinball.Engine.VPT.Sound; +using VisualPinball.Engine.VPT.Table; +using VisualPinball.Engine.VPT.TextBox; +using VisualPinball.Engine.VPT.Timer; +using VisualPinball.Unity.Playfield; +using Material = VisualPinball.Engine.VPT.Material; +using Texture = VisualPinball.Engine.VPT.Texture; + +namespace VisualPinball.Unity +{ + public class SceneTableContainer : TableContainer + { + public override Table Table => _tableAuthoring.Table; + public override Dictionary TableInfo => _tableAuthoring.TableInfo; + public override List Collections => _tableAuthoring.Collections; + public override Mappings Mappings => new Mappings(_tableAuthoring.Mappings); + public override CustomInfoTags CustomInfoTags => _tableAuthoring.CustomInfoTags; + + public override IEnumerable Textures => _tableAuthoring.LegacyContainer.Textures + .Where(texture => texture.IsSet) + .Select(texture => texture.ToTexture()); + public override IEnumerable Sounds => _tableAuthoring.LegacyContainer.Sounds + .Where(sound => sound.IsSet) + .Select(sound => sound.ToSound()); + + public const int ChildObjectsLayer = 16; + + private readonly Dictionary _materials = new Dictionary(); + + public override Material GetMaterial(string name) + { + if (string.IsNullOrEmpty(name)) { + return null; + } + return _materials.ContainsKey(name.ToLower()) ? _materials[name.ToLower()] : null; + } + + public override Texture GetTexture(string name) + { + return null; + } + + private readonly TableAuthoring _tableAuthoring; + + public SceneTableContainer(TableAuthoring ta) + { + _tableAuthoring = ta; + } + + public void Refresh() + { + var stopWatch = Stopwatch.StartNew(); + Clear(); + WalkChildren(_tableAuthoring.transform, RefreshChild); + + foreach (var material in _tableAuthoring.Data.Materials) { + _materials[material.Name.ToLower()] = material; + } + + Logger.Info($"Refreshed {GameItems.Count()} game items and {_materials.Count} materials in {stopWatch.ElapsedMilliseconds}ms."); + } + + public override void Save(string fileName) + { + Refresh(); + FillBinaryData(); + PrepareForExport(); + + base.Save(fileName); + + FreeBinaryData(); + } + + private void PrepareForExport() + { + // fetch legacy items from container (because they are not in the scene) + foreach (var decal in _tableAuthoring.LegacyContainer.Decals) { + _decals.Add(new Decal(decal)); + } + foreach (var dispReel in _tableAuthoring.LegacyContainer.DispReels) { + _dispReels[dispReel.Name] = new DispReel(dispReel); + } + foreach (var flasher in _tableAuthoring.LegacyContainer.Flashers) { + _flashers[flasher.Name] = new Flasher(flasher); + } + foreach (var lightSeq in _tableAuthoring.LegacyContainer.LightSeqs) { + _lightSeqs[lightSeq.Name] = new LightSeq(lightSeq); + } + foreach (var textBox in _tableAuthoring.LegacyContainer.TextBoxes) { + _textBoxes[textBox.Name] = new TextBox(textBox); + } + foreach (var timer in _tableAuthoring.LegacyContainer.Timers) { + _timers[timer.Name] = new Timer(timer); + } + + // count stuff and update table data + Table.Data.NumCollections = Collections.Count; + Table.Data.NumFonts = 0; // todo handle fonts + Table.Data.NumGameItems = RecomputeGameItemStorageIDs(ItemDatas); + Table.Data.NumVpeGameItems = RecomputeGameItemStorageIDs(VpeItemDatas); + Table.Data.NumTextures = _tableAuthoring.LegacyContainer.Textures.Count(t => t.IsSet); + Table.Data.NumSounds = _tableAuthoring.LegacyContainer.Sounds.Count(t => t.IsSet); + + // update texture references + WalkChildren(_tableAuthoring.transform, SetTextureReference); + + // add/merge physical materials from asset folder + #if UNITY_EDITOR + var guids = UnityEditor.AssetDatabase.FindAssets("t:PhysicsMaterial", null); + foreach (var guid in guids) { + var assetPath = UnityEditor.AssetDatabase.GUIDToAssetPath(guid); + var matAsset = UnityEditor.AssetDatabase.LoadAssetAtPath(assetPath); + var name = Path.GetFileNameWithoutExtension(assetPath); + if (!_materials.ContainsKey(name.ToLower())) { + continue; + } + var matTable = _materials[name.ToLower()]; + matTable.Elasticity = matAsset.Elasticity; + matTable.ElasticityFalloff = matAsset.ElasticityFalloff; + matTable.Friction = matAsset.Friction; + matTable.ScatterAngle = matAsset.ScatterAngle; + } + #endif + Table.Data.NumMaterials = _materials.Count; + } + + private static void SetTextureReference(Component node) + { + var mr = node.GetComponent(); + if (!mr) { + return; + } + var meshAuthoring = node.GetComponent(); + if (meshAuthoring == null) { + return; + } + switch (meshAuthoring) { + case FlipperBaseMeshAuthoring flipperBase: { + flipperBase.MainAuthoring.Data.Image = GetTextureName(mr); + break; + } + case HitTargetMeshAuthoring hitTarget: { + hitTarget.MainAuthoring.Data.Image = GetTextureName(mr); + break; + } + case PlungerMeshAuthoring plunger: { + plunger.MainAuthoring.Data.Image = GetTextureName(mr); + break; + } + case PrimitiveMeshAuthoring primitive: { + primitive.MainAuthoring.Data.Image = GetTextureName(mr); + primitive.MainAuthoring.Data.NormalMap = GetNormalTextureName(mr); + break; + } + case RampFloorMeshAuthoring rampFloor: { + rampFloor.MainAuthoring.Data.Image = GetTextureName(mr); + break; + } + case RampWallMeshAuthoring rampWall: { + rampWall.MainAuthoring.Data.Image = GetTextureName(mr); + break; + } + case RubberMeshAuthoring rubber: { + rubber.MainAuthoring.Data.Image = GetTextureName(mr); + break; + } + case SpinnerBracketMeshAuthoring spinnerBracket: { + spinnerBracket.MainAuthoring.Data.Image = GetTextureName(mr); + break; + } + case SpinnerPlateMeshAuthoring spinnerPlate: { + spinnerPlate.MainAuthoring.Data.Image = GetTextureName(mr); + break; + } + case SurfaceSideMeshAuthoring surfaceSide: { + surfaceSide.MainAuthoring.Data.SideImage = GetTextureName(mr); + break; + } + case SurfaceTopMeshAuthoring surfaceTop: { + surfaceTop.MainAuthoring.Data.Image = GetTextureName(mr); + break; + } + case PlayfieldMeshAuthoring playfield: { + playfield.MainAuthoring.Data.Image = GetTextureName(mr); + break; + } + } + } + + private static string GetTextureName(Renderer mr) + { + if (mr == null || mr.sharedMaterial == null || mr.sharedMaterial.mainTexture == null) { + return string.Empty; + } + return mr.sharedMaterial.mainTexture.name; + } + + private static string GetNormalTextureName(Renderer mr) + { + if (mr == null || mr.sharedMaterial == null) { + return string.Empty; + } + var tex = mr.sharedMaterial.GetTexture(RenderPipeline.Current.MaterialConverter.NormalMapProperty); + return tex == null ? string.Empty : tex.name; + } + + private static int RecomputeGameItemStorageIDs(IEnumerable datas) + { + var itemDatas = datas.ToArray(); + var assignedItems = from d in itemDatas where d.StorageIndex > -1 orderby d.StorageIndex select d; + var unassignedItems = from d in itemDatas where d.StorageIndex == -1 select d; + var orderedItems = assignedItems.Concat(unassignedItems).ToArray(); + + if (orderedItems.Length != itemDatas.Length) { + throw new Exception($"Internal error, orderedItems.Length = {orderedItems.Length}, while itemDatas.Length = {itemDatas.Length}."); + } + + for (var i = 0; i < orderedItems.Length; i++) { + orderedItems[i].StorageIndex = i; + } + + return orderedItems.Length; + } + + private void FillBinaryData() + { + WalkChildren(_tableAuthoring.transform, FillBinaryData); + } + + private void FreeBinaryData() + { + WalkChildren(_tableAuthoring.transform, FreeBinaryData); + } + + private static void FillBinaryData(Transform transform) + { + var comp = transform.GetComponent(); + comp?.FillBinaryData(); + } + + private static void FreeBinaryData(Transform transform) + { + var comp = transform.GetComponent(); + comp?.FreeBinaryData(); + } + + private IEnumerable RetrieveSounds() + { + return new Sound[0]; + } + + protected override void Clear() + { + base.Clear(); + _materials.Clear(); + } + + private static void WalkChildren(IEnumerable node, Action action) + { + foreach (Transform childTransform in node) { + action(childTransform); + WalkChildren(childTransform, action); + } + } + + private void RefreshChild(Component node) + { + Add(node.GetComponent()); + } + + private void Add(IItemMainAuthoring comp) + { + if (comp == null) { + return; + } + switch (comp) { + case BumperAuthoring bumperAuthoring: + Add(comp.gameObject.name, bumperAuthoring.Item); + break; + case FlipperAuthoring flipperAuthoring: + Add(comp.gameObject.name, flipperAuthoring.Item); + break; + case GateAuthoring gateAuthoring: + Add(comp.gameObject.name, gateAuthoring.Item); + break; + case HitTargetAuthoring hitTargetAuthoring: + Add(comp.gameObject.name, hitTargetAuthoring.Item); + break; + case KickerAuthoring kickerAuthoring: + Add(comp.gameObject.name, kickerAuthoring.Item); + break; + case LightAuthoring lightAuthoring: + Add(comp.gameObject.name, lightAuthoring.Item); + break; + case PlungerAuthoring plungerAuthoring: + Add(comp.gameObject.name, plungerAuthoring.Item); + break; + case PrimitiveAuthoring primitiveAuthoring: + Add(comp.gameObject.name, primitiveAuthoring.Item); + break; + case RampAuthoring rampAuthoring: + Add(comp.gameObject.name, rampAuthoring.Item); + break; + case RubberAuthoring rubberAuthoring: + Add(comp.gameObject.name, rubberAuthoring.Item); + break; + case SpinnerAuthoring spinnerAuthoring: + Add(comp.gameObject.name, spinnerAuthoring.Item); + break; + case SurfaceAuthoring surfaceAuthoring: + Add(comp.gameObject.name, surfaceAuthoring.Item); + break; + case TriggerAuthoring triggerAuthoring: + Add(comp.gameObject.name, triggerAuthoring.Item); + break; + case TroughAuthoring troughAuthoring: + Add(comp.gameObject.name, troughAuthoring.Item); + break; + } + } + + private void Add(string name, T item) where T : IItem + { + var dict = GetItemDictionary(); + if (dict.ContainsKey(name)) { + Logger.Warn($"{item.GetType()} {name} already added."); + } else { + dict.Add(name, item); + } + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/SceneTableContainer.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/SceneTableContainer.cs.meta new file mode 100644 index 000000000..7b9b77c62 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/SceneTableContainer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed5f71f15d957ce44ada2164789d514a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs index 3b01b2f5f..586e51772 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs @@ -192,7 +192,7 @@ void IApiInitializable.OnInit(BallManager ballManager) } void IApiColliderGenerator.CreateColliders(Table table, List colliders) { - var info = ((IApiColliderGenerator)this).GetColliderInfo(table); + var info = ((IApiColliderGenerator)this).GetColliderInfo(); // simple outer borders: colliders.Add(new LineCollider( @@ -237,7 +237,7 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider ColliderUtils.Generate3DPolyColliders(rgv3D, table, info, colliders); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) + ColliderInfo IApiColliderGenerator.GetColliderInfo() { return new ColliderInfo { Id = -1, diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableAuthoring.cs index 87bbeb7b1..d0d37c55a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableAuthoring.cs @@ -16,6 +16,8 @@ // ReSharper disable ClassNeverInstantiated.Global // ReSharper disable FieldCanBeMadeReadOnly.Global +// ReSharper disable InconsistentNaming +// ReSharper disable CheckNamespace using System; using System.Collections.Generic; @@ -24,30 +26,9 @@ using UnityEngine; using VisualPinball.Engine.Common; using VisualPinball.Engine.VPT; -using VisualPinball.Engine.VPT.Bumper; using VisualPinball.Engine.VPT.Collection; -using VisualPinball.Engine.VPT.Decal; -using VisualPinball.Engine.VPT.DispReel; -using VisualPinball.Engine.VPT.Flasher; -using VisualPinball.Engine.VPT.Flipper; -using VisualPinball.Engine.VPT.Gate; -using VisualPinball.Engine.VPT.HitTarget; -using VisualPinball.Engine.VPT.Kicker; -using VisualPinball.Engine.VPT.Light; -using VisualPinball.Engine.VPT.LightSeq; using VisualPinball.Engine.VPT.Mappings; -using VisualPinball.Engine.VPT.Plunger; -using VisualPinball.Engine.VPT.Primitive; -using VisualPinball.Engine.VPT.Ramp; -using VisualPinball.Engine.VPT.Rubber; -using VisualPinball.Engine.VPT.Spinner; -using VisualPinball.Engine.VPT.Surface; using VisualPinball.Engine.VPT.Table; -using VisualPinball.Engine.VPT.TextBox; -using VisualPinball.Engine.VPT.Timer; -using VisualPinball.Engine.VPT.Trigger; -using VisualPinball.Engine.VPT.Trough; -using Light = VisualPinball.Engine.VPT.Light.Light; using Logger = NLog.Logger; using Material = UnityEngine.Material; using Texture = VisualPinball.Engine.VPT.Texture; @@ -57,72 +38,68 @@ namespace VisualPinball.Unity [AddComponentMenu("Visual Pinball/Table")] public class TableAuthoring : ItemMainRenderableAuthoring { - protected override Table InstantiateItem(TableData data) => RecreateTable(data); + #region Table Data + + [SerializeField] public MappingsData Mappings; + [SerializeField] public SerializableDictionary TableInfo = new SerializableDictionary(); + [SerializeField] public CustomInfoTags CustomInfoTags = new CustomInfoTags(); + [SerializeField] public LegacyContainer LegacyContainer = new LegacyContainer(); + [SerializeField] public List Collections = new List(); + + #endregion + + protected override Table InstantiateItem(TableData data) => new Table(TableContainer, data); protected override Type MeshAuthoringType { get; } = null; protected override Type ColliderAuthoringType { get; } = null; public override IEnumerable ValidParents => new Type[0]; - public Table Table => Item; - public TableSerializedTextureContainer Textures => _sidecar?.textures; - public TableSerializedSoundContainer Sounds => _sidecar?.sounds; - public List Collections => _sidecar?.collections; - public MappingsData Mappings => _sidecar?.mappings; - //public PatcherManager.Patcher Patcher { get; internal set; } + + public new Table Table => Item; + public new SceneTableContainer TableContainer => _tableContainer ??= new SceneTableContainer(this); + + [NonSerialized] + private SceneTableContainer _tableContainer; [HideInInspector] [SerializeField] public string physicsEngineId = "VisualPinball.Unity.DefaultPhysicsEngine"; [HideInInspector] [SerializeField] public string debugUiId; - [HideInInspector] [SerializeField] private TableSidecar _sidecar; + private readonly Dictionary _unityTextures = new Dictionary(); // note: this cache needs to be keyed on the engine material itself so that when its recreated due to property changes the unity material // will cache miss and get recreated as well - private readonly Dictionary _unityMaterials = new Dictionary(); + private readonly Dictionary _unityMaterials = new Dictionary(); /// /// Keeps a list of serializables names that need recreation, serialized and /// lazy so when undo happens they'll be considered dirty again /// - [HideInInspector] [SerializeField] private Dictionary> _dirtySerializables = new Dictionary>(); + [HideInInspector] [SerializeField] private readonly Dictionary> _dirtySerializables = new Dictionary>(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - //Private runtime values needed for camera adjustments. + private void Reset() + { + _tableContainer ??= new SceneTableContainer(this); + } + + //Private runtime values needed for camera adjustments. [HideInInspector] [SerializeField] public Bounds _tableBounds; [HideInInspector] [SerializeField] public Vector3 _tableCenter; public void Awake() { - //Store table information + //Store table information _tableBounds = GetTableBounds(); _tableCenter = GetTableCenter(); } protected virtual void Start() { - + if (EngineProvider.Exists) { EngineProvider.Get().Init(this); } } - protected override void OnDrawGizmos() - { - // do nothing, base class draws all child meshes for ease of selection, but - // that would just be everything at this level - } - - internal TableSidecar GetOrCreateSidecar() - { - if (_sidecar == null) { - _sidecar = ScriptableObject.CreateInstance(); - } - return _sidecar; - } - - public void AddTexture(string name, Texture2D texture) - { - _unityTextures[name.ToLower()] = texture; - } - public void RestoreCollections(List collections) { Collections.Clear(); @@ -191,9 +168,7 @@ public Texture2D GetTexture(string name) public void AddMaterial(PbrMaterial vpxMat, Material material) { - UnityEngine.Material oldMaterial = null; - _unityMaterials.TryGetValue(vpxMat.Id, out oldMaterial); - + _unityMaterials.TryGetValue(vpxMat.Id, out var oldMaterial); _unityMaterials[vpxMat.Id] = material; if (oldMaterial != null) { Destroy(oldMaterial); @@ -208,68 +183,6 @@ public Material GetMaterial(PbrMaterial vpxMat) return null; } - public Table CreateTable(TableData data) - { - Logger.Info("Restoring table..."); - // restore table data - var table = new Table(data); - - // restore table info - Logger.Info("Restoring table info..."); - foreach (var k in _sidecar.tableInfo.Keys) { - table.TableInfo[k] = _sidecar.tableInfo[k]; - } - - // restore custom info tags - table.CustomInfoTags = _sidecar.customInfoTags; - - // replace texture container - table.SetTextureContainer(_sidecar.textures); - - // replace sound container - table.SetSoundContainer(_sidecar.sounds); - - // restore custom info tags - table.Mappings = new Mappings(_sidecar.mappings); - - // restore game items with no game object (yet!) - table.ReplaceAll(_sidecar.decals.Select(d => new Decal(d))); - Restore(_sidecar.collections, table.Collections, d => new Collection(d)); - Restore(_sidecar.dispReels, table, d => new DispReel(d)); - Restore(_sidecar.flashers, table, d => new Flasher(d)); - Restore(_sidecar.lightSeqs, table, d => new LightSeq(d)); - Restore(_sidecar.plungers, table, d => new Plunger(d)); - Restore(_sidecar.textBoxes, table, d => new TextBox(d)); - Restore(_sidecar.timers, table, d => new Timer(d)); - - // restore game items - Logger.Info("Restoring game items..."); - Restore(table); - Restore(table); - Restore(table); - Restore(table); - Restore(table); - Restore(table); - Restore(table); - Restore(table); - Restore(table); - Restore(table); - Restore(table); - Restore(table); - Restore(table); - Restore(table); - - return table; - } - - public Table RecreateTable(TableData tableData) - { - var table = CreateTable(tableData); - - Logger.Info("Table restored."); - return table; - } - public Vector3 GetTableCenter() { var playfield = GetComponentInChildren().gameObject; @@ -282,7 +195,7 @@ public Bounds GetTableBounds() var tableBounds = new Bounds(); var mrs = GetComponentsInChildren(); - foreach(var mr in mrs) + foreach(var mr in mrs) { tableBounds.Encapsulate(mr.bounds); } @@ -293,39 +206,13 @@ public Bounds GetTableBounds() public void RepopulateHardware(IGamelogicEngine gle) { Mappings.RemoveAllSwitches(); - Table.Mappings.PopulateSwitches(gle.AvailableSwitches, Table.Switchables, Table.SwitchableDevices); + TableContainer.Mappings.PopulateSwitches(gle.AvailableSwitches, TableContainer.Switchables, TableContainer.SwitchableDevices); Mappings.RemoveAllCoils(); - Table.Mappings.PopulateCoils(gle.AvailableCoils, Table.Coilables, Table.CoilableDevices); + TableContainer.Mappings.PopulateCoils(gle.AvailableCoils, TableContainer.Coilables, TableContainer.CoilableDevices); Mappings.RemoveAllLamps(); - Table.Mappings.PopulateLamps(gle.AvailableLamps, Table.Lightables); - } - - private void Restore(Table table) where TData : ItemData - where TItem : Item - where TComp : ItemMainAuthoring - { - foreach (var component in GetComponentsInChildren(true)) - { - component.Restore(); - table.Add(component.Item); - } - } - - private static void Restore(IEnumerable src, IDictionary dest, Func create) where TData : ItemData where TItem : Item - { - foreach (var d in src) { - dest[d.GetName()] = create(d); - } + TableContainer.Mappings.PopulateLamps(gle.AvailableLamps, TableContainer.Lightables); } - - private static void Restore(IEnumerable src, Table table, Func create) where TData : ItemData where TItem : Item - { - foreach (var d in src) { - table.Add(create(d)); - } - } - } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TablePlayfieldAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TablePlayfieldAuthoring.cs new file mode 100644 index 000000000..ec7f355da --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TablePlayfieldAuthoring.cs @@ -0,0 +1,26 @@ +// 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; + +namespace VisualPinball.Unity +{ + public class TablePlayfieldAuthoring : MonoBehaviour + { + public static readonly Quaternion GlobalRotation = Quaternion.Euler(-90, 0, 0); + public const float GlobalScale = 0.001f; + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TablePlayfieldAuthoring.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TablePlayfieldAuthoring.cs.meta new file mode 100644 index 000000000..bd9d719fa --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TablePlayfieldAuthoring.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7857f23360bd1f741823291a51d861f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: d2cadd0664cbae64db585a1713f66a10, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedContainer.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedContainer.cs deleted file mode 100644 index dec497403..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedContainer.cs +++ /dev/null @@ -1,131 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Linq; -using VisualPinball.Engine.VPT; -using VisualPinball.Engine.VPT.Table; - -namespace VisualPinball.Unity -{ - /// - /// Base container class to handle in a Dictionary-like way objects based on generic class - /// - /// IItem derived class encapsulating the handled ItemData object - /// ItemData derived class which will be encapsulated in a - /// The full description of the which will be used in this container - public abstract class TableSerializedContainer : ITableResourceContainer - where T : IItem - where TData : ItemData - where TSerialized : TableSerializedData - { - public int Count => _serializedData.Count; - public IEnumerable Values => Data.Values; - public IEnumerable SerializedObjects => _serializedData; - - [UnityEngine.SerializeField] - protected List _serializedData = new List(); - - [UnityEngine.SerializeField] - protected bool _dictDirty; - - private Dictionary Data => _data == null || _dictDirty ? _data = CreateDict() : _data; - - private Dictionary _data; - - public T this[string k] => Get(k); - public T Get(string k) - { - Data.TryGetValue(k.ToLower(), out T val); - return val; - } - - protected abstract Dictionary CreateDict(); - protected abstract bool TryAddSerialized(T value); - - public void Add(T value) - { - Remove(value); - if (TryAddSerialized(value)) { - Data[value.Name.ToLower()] = value; - SetNameMapDirty(); - } - } - - public void AddRange(ITableResourceContainer values) - { - foreach(var value in values) { - Add(value); - } - } - - public bool Remove(T value) - { - return Remove(value.Name); - } - - public bool Remove(string name) - { - string lowerName = name.ToLower(); - bool found = false; - for (int i = 0; i < Data.Count; i++) { - if (_serializedData[i].Data.GetName().ToLower() == lowerName) { - _serializedData.RemoveAt(i); - found = true; - break; - } - } - if (found) { - Data.Remove(lowerName); - SetNameMapDirty(); - } - return found; - } - - public bool Move(string name, int newIdx) - { - if (newIdx < 0 || newIdx > _serializedData.Count - 1) { - return false; - } - - var foundItem = _serializedData.Where(d => string.Compare(d.Data.GetName(), name, StringComparison.InvariantCultureIgnoreCase) == 0).ToArray(); - if (foundItem.Length == 1) { - _serializedData.Remove(foundItem[0]); - _serializedData.Insert(newIdx, foundItem[0]); - SetNameMapDirty(); - return true; - } - - return false; - } - - protected void SetNameMapDirty() - { - _dictDirty = true; - } - - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() - { - foreach (var kvp in Data) { - yield return kvp.Value; - } - } - } -} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedContainer.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedContainer.cs.meta deleted file mode 100644 index 87ffcc6a8..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedContainer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4f50a6667fc75a04a92c35ab79456d3e -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedData.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedData.cs deleted file mode 100644 index a0a778f64..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedData.cs +++ /dev/null @@ -1,41 +0,0 @@ -// 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; - -namespace VisualPinball.Unity -{ - /// - /// ScriptableObject generic wrapper for any data which needs to be managed indepenently, e.g. for Undo tracking. - /// These objects types can be handled by - /// - /// The ItemData based class which will be wrapped into a ScriptableObject - /// - /// These wrapper are used by for Textures, Sounds to avoid undo operations on the whole structure - /// - public class TableSerializedData : ScriptableObject where TData : ItemData - { - public TData Data; - - public static T GenericCreate(TData data) where T : TableSerializedData - { - var tst = CreateInstance(); - tst.Data = data; - return tst; - } - } -} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedData.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedData.cs.meta deleted file mode 100644 index a38db06d9..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedData.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 15c9d1b3df3b69b4e8793620a271a49d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSound.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSound.cs.meta deleted file mode 100644 index 12cd3ebd0..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSound.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a3d2448751427b34bb165cc463b228e3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSoundContainer.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSoundContainer.cs deleted file mode 100644 index 544f38584..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSoundContainer.cs +++ /dev/null @@ -1,45 +0,0 @@ -// 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 VisualPinball.Engine.VPT.Sound; - -namespace VisualPinball.Unity -{ - /// - /// Implements a serializable Sound container that can replace the engine table container after import - /// - [Serializable] - public class TableSerializedSoundContainer : TableSerializedContainer - { - protected override bool TryAddSerialized(Sound value) - { - _serializedData.Add(TableSerializedSound.Create(value.Data)); - return true; - } - - protected override Dictionary CreateDict() - { - var dict = new Dictionary(); - foreach (var td in _serializedData) { - dict.Add(td.Data.Name.ToLower(), new Sound(td.Data)); - } - _dictDirty = false; - return dict; - } - } -} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSoundContainer.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSoundContainer.cs.meta deleted file mode 100644 index 167925dd9..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedSoundContainer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 13e2e0f77e6468a40922f88b4d83c62b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTexture.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTexture.cs.meta deleted file mode 100644 index f4b2bf92d..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTexture.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9094af530c6565a41adbda4a9e882954 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTextureContainer.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTextureContainer.cs deleted file mode 100644 index d9dc1ad0b..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTextureContainer.cs +++ /dev/null @@ -1,45 +0,0 @@ -// 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 VisualPinball.Engine.VPT; - -namespace VisualPinball.Unity -{ - /// - /// Implements a serializable texture container that can replace the engine table container after import - /// - [Serializable] - public class TableSerializedTextureContainer : TableSerializedContainer - { - protected override bool TryAddSerialized(Texture value) - { - _serializedData.Add(TableSerializedTexture.Create(value.Data)); - return true; - } - - protected override Dictionary CreateDict() - { - var dict = new Dictionary(); - foreach (var td in _serializedData) { - dict.Add(td.Data.Name.ToLower(), new Texture(td.Data)); - } - _dictDirty = false; - return dict; - } - } -} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTextureContainer.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTextureContainer.cs.meta deleted file mode 100644 index 73e92b923..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSerializedTextureContainer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9bfa19d2f857653429fed018ef7555de -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSidecar.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSidecar.cs deleted file mode 100644 index 09e281d38..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSidecar.cs +++ /dev/null @@ -1,53 +0,0 @@ -// 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.Collections.Generic; -using UnityEngine; -using VisualPinball.Engine.VPT.Collection; -using VisualPinball.Engine.VPT.Mappings; -using VisualPinball.Engine.VPT.Decal; -using VisualPinball.Engine.VPT.DispReel; -using VisualPinball.Engine.VPT.Flasher; -using VisualPinball.Engine.VPT.LightSeq; -using VisualPinball.Engine.VPT.Plunger; -using VisualPinball.Engine.VPT.Table; -using VisualPinball.Engine.VPT.TextBox; -using VisualPinball.Engine.VPT.Timer; - -namespace VisualPinball.Unity -{ - /// - /// This monobehavior is meant to hold all the (large) serialized data needed to reconstruct - /// a vpx table. We're storing this off on a different object so that selecting the table itself - /// doesn't cause the editor to slow to a crawl - /// - internal class TableSidecar : ScriptableObject - { - [HideInInspector] public Dictionary tableInfo = new SerializableDictionary(); - [HideInInspector] public TableSerializedTextureContainer textures = new TableSerializedTextureContainer(); - [HideInInspector] public CustomInfoTags customInfoTags; - [HideInInspector] public List collections; - [HideInInspector] public MappingsData mappings; - [HideInInspector] public DecalData[] decals; - [HideInInspector] public DispReelData[] dispReels; - [HideInInspector] public FlasherData[] flashers; - [HideInInspector] public LightSeqData[] lightSeqs; - [HideInInspector] public PlungerData[] plungers; - [HideInInspector] public TableSerializedSoundContainer sounds = new TableSerializedSoundContainer(); - [HideInInspector] public TextBoxData[] textBoxes; - [HideInInspector] public TimerData[] timers; - } -} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSidecar.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSidecar.cs.meta deleted file mode 100644 index 2c7f7f556..000000000 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableSidecar.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 4a59a6ef2ca62aa409c17c9383851d13 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs index 165372f09..3e6e07f4d 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerApi.cs @@ -64,7 +64,7 @@ void IApiColliderGenerator.CreateColliders(Table table, List collider colliderGenerator.GenerateColliders(table, colliders); } - ColliderInfo IApiColliderGenerator.GetColliderInfo(Table table) => GetColliderInfo(table); + ColliderInfo IApiColliderGenerator.GetColliderInfo() => GetColliderInfo(); #endregion diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerAuthoring.cs index 6f8f10ae0..c38782cd4 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerAuthoring.cs @@ -63,7 +63,7 @@ public void Convert(Entity entity, EntityManager dstManager, GameObjectConversio // register var trigger = GetComponent().Item; - transform.GetComponentInParent().RegisterTrigger(trigger, entity, ParentEntity); + transform.GetComponentInParent().RegisterTrigger(trigger, entity, ParentEntity, gameObject); } public override void Restore() @@ -85,13 +85,6 @@ public override void Restore() // todo handle IsEnabled } - private void OnDestroy() - { - if (!Application.isPlaying) { - Table?.Remove(Name); - } - } - public override ItemDataTransformType EditorPositionType => ItemDataTransformType.TwoD; public override Vector3 GetEditorPosition() => Data.Center.ToUnityVector3(0f); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerCollider.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerCollider.cs index 7476ef950..20266454c 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerCollider.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerCollider.cs @@ -16,7 +16,6 @@ using Unity.Collections; using Unity.Entities; -using UnityEngine; using VisualPinball.Engine.Common; using VisualPinball.Engine.Game; diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerColliderGenerator.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerColliderGenerator.cs index 2331d1a3f..26fa21580 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerColliderGenerator.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerColliderGenerator.cs @@ -51,7 +51,7 @@ private void GenerateRoundHitObjects(Table table, ICollection collide { var height = table.GetSurfaceHeight(_data.Surface, _data.Center.X, _data.Center.Y); colliders.Add(new CircleCollider(_data.Center.ToUnityFloat2(), _data.Radius, height, height + _data.HitHeight, - _api.GetColliderInfo(table), ColliderType.TriggerCircle)); + _api.GetColliderInfo(), ColliderType.TriggerCircle)); } private void GenerateCurvedHitObjects(Table table, List colliders) @@ -74,12 +74,12 @@ private void GenerateCurvedHitObjects(Table table, List colliders) AddLineSeg(pv2.ToUnityFloat2(), pv3.ToUnityFloat2(), height, table, colliders); } - ColliderUtils.Generate3DPolyColliders(rgv3D, table, _api.GetColliderInfo(table), colliders); + ColliderUtils.Generate3DPolyColliders(rgv3D, table, _api.GetColliderInfo(), colliders); } private void AddLineSeg(float2 pv1, float2 pv2, float height, Table table, ICollection colliders) { colliders.Add(new LineCollider(pv1, pv2, height, height + math.max(_data.HitHeight - 8.0f, 0f), - _api.GetColliderInfo(table), ColliderType.TriggerLine)); + _api.GetColliderInfo(), ColliderType.TriggerLine)); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerExtensions.cs index 00c55aead..b41d0bfa7 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerExtensions.cs @@ -15,9 +15,7 @@ // along with this program. If not, see . using System; -using System.Collections.Generic; using NLog; -using Unity.Entities; using UnityEngine; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Trigger; @@ -25,20 +23,17 @@ namespace VisualPinball.Unity { - internal static class TriggerExtensions + public static class TriggerExtensions { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public static ConvertedItem SetupGameObject(this Trigger trigger, GameObject obj) + public static IConvertedItem SetupGameObject(this Trigger trigger, GameObject obj, IMaterialProvider materialProvider, bool componentsAdded) { - var mainAuthoring = obj.AddComponent().SetItem(trigger); - var meshAuthoring = new List(); - TriggerColliderAuthoring colliderAuthoring = null; - + var convertedItem = new ConvertedItem(obj, trigger, componentsAdded); switch (trigger.SubComponent) { case ItemSubComponent.None: - colliderAuthoring = obj.AddComponent(); - meshAuthoring.Add(obj.AddComponent()); + convertedItem.SetColliderAuthoring(materialProvider, componentsAdded); + convertedItem.SetMeshAuthoring(componentsAdded); break; case ItemSubComponent.Collider: { @@ -50,12 +45,11 @@ public static ConvertedItem SetupGameObject(this Trigger trigger, GameObject obj Logger.Warn("Cannot parent a trigger mesh to a different object than a trigger!"); break; } - default: throw new ArgumentOutOfRangeException(); } - obj.AddComponent(); - return new ConvertedItem(mainAuthoring, meshAuthoring, colliderAuthoring); + + return convertedItem.AddConvertToEntity(componentsAdded); } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerMovementSystem.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerMovementSystem.cs index 408a40da7..7864b4993 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerMovementSystem.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerMovementSystem.cs @@ -30,7 +30,7 @@ internal class TriggerMovementSystem : SystemBase protected override void OnStartRunning() { - var root = Object.FindObjectOfType(); + var root = Object.FindObjectOfType(); var ltw = root.gameObject.transform.localToWorldMatrix; _baseTransform = new float4x4( ltw.m00, ltw.m01, ltw.m02, ltw.m03, diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughAuthoring.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughAuthoring.cs index e3f172cdf..0fa3f581e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughAuthoring.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughAuthoring.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using UnityEngine; +using UnityEngine.Profiling; using VisualPinball.Engine.Game.Engines; using VisualPinball.Engine.VPT; using VisualPinball.Engine.VPT.Kicker; @@ -47,17 +48,19 @@ private Vector3 EntryPos(float height) if (string.IsNullOrEmpty(Data.PlayfieldEntrySwitch)) { return Vector3.zero; } - if (Table.Has(Data.PlayfieldEntrySwitch)) { - return Table.Trigger(Data.PlayfieldEntrySwitch).Data.Center.ToUnityVector3(height); + if (TableContainer.Has(Data.PlayfieldEntrySwitch)) { + return TableContainer.Get(Data.PlayfieldEntrySwitch).Data.Center.ToUnityVector3(height); } - return Table.Has(Data.PlayfieldEntrySwitch) - ? Table.Kicker(Data.PlayfieldEntrySwitch).Data.Center.ToUnityVector3(height) + return TableContainer.Has(Data.PlayfieldEntrySwitch) + ? TableContainer.Get(Data.PlayfieldEntrySwitch).Data.Center.ToUnityVector3(height) : Vector3.zero; } private Vector3 ExitPos(float height) => string.IsNullOrEmpty(Data.PlayfieldExitKicker) ? Vector3.zero - : Table.Kicker(Data.PlayfieldExitKicker).Data.Center.ToUnityVector3(height); + : !TableContainer.Has(Data.PlayfieldExitKicker) + ? Vector3.zero + : TableContainer.Get(Data.PlayfieldExitKicker).Data.Center.ToUnityVector3(height); private void Awake() { @@ -71,6 +74,7 @@ public override void Restore() private void OnDrawGizmosSelected() { + Profiler.BeginSample("TroughAuthoring.OnDrawGizmosSelected"); if (!string.IsNullOrEmpty(Data.PlayfieldEntrySwitch) && !string.IsNullOrEmpty(Data.PlayfieldExitKicker)) { var ltw = GetComponentInParent().transform; var entryPos = EntryPos(0f); @@ -83,6 +87,7 @@ private void OnDrawGizmosSelected() DrawArrow(entryWorldPos, pos - entryWorldPos); DrawArrow(pos, exitWorldPos - pos); } + Profiler.EndSample(); } public void UpdatePosition() @@ -91,12 +96,5 @@ public void UpdatePosition() var pos = (EntryPos(75f) + ExitPos(75f)) / 2; transform.localPosition = pos; } - - private void OnDestroy() - { - if (!Application.isPlaying) { - Table?.Remove(Name); - } - } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughExtensions.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughExtensions.cs index 3f2d8d28e..3ef8171b1 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughExtensions.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trough/TroughExtensions.cs @@ -15,18 +15,17 @@ // along with this program. If not, see . using UnityEngine; +using VisualPinball.Engine.VPT.Trough; namespace VisualPinball.Unity { - internal static class TroughExtensions + public static class TroughExtensions { - public static ConvertedItem SetupGameObject(this Engine.VPT.Trough.Trough trough, GameObject obj) + public static IConvertedItem SetupGameObject(this Trough trough, GameObject obj, bool componentsAdded) { - var mainAuthoring = obj.AddComponent(); - mainAuthoring.SetItem(trough); - mainAuthoring.UpdatePosition(); - //obj.GetComponentInParent()?.RegisterTrough(trough, obj); - return new ConvertedItem(mainAuthoring); + var convertedItem = new ConvertedItem(obj, trough, componentsAdded); + convertedItem.Authoring.UpdatePosition(); + return convertedItem; } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VisualPinball.Unity.csproj b/VisualPinball.Unity/VisualPinball.Unity/VisualPinball.Unity.csproj index f3665cdc9..c1f5432a5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VisualPinball.Unity.csproj +++ b/VisualPinball.Unity/VisualPinball.Unity/VisualPinball.Unity.csproj @@ -8,7 +8,7 @@ 0.1.0.0 0.1.0.0 0.1.0.0 - 7.3 + 8 true @@ -69,6 +69,6 @@ - +