From d050bc4703054c555739ae7e2f056d06188b8dbf Mon Sep 17 00:00:00 2001 From: freezy Date: Fri, 22 Oct 2021 00:02:42 +0200 Subject: [PATCH 01/25] fix: Kicker handle direction. --- .../VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs index 85f8c37b8..01a1c3648 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs @@ -103,8 +103,8 @@ private void OnSceneGUI() var from = MainComponent.GetBallCreationPosition().ToUnityVector3(); var l = 20f * coil.Speed; var dir = new Vector3( - l * math.cos(math.radians(coil.Angle)), l * math.sin(math.radians(coil.Angle)), + -l * math.cos(math.radians(coil.Angle)), l * math.sin(math.radians(coil.Inclination)) ); var to = from + dir; From 597d4dc10a7cb21f3443cb661444acc7e78bdc9e Mon Sep 17 00:00:00 2001 From: freezy Date: Fri, 22 Oct 2021 00:03:06 +0200 Subject: [PATCH 02/25] t2: Link locks and kickback. --- .../Matcher/TablePatcher.cs | 5 ++-- .../Patcher/Tables/Terminator2.cs | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs index 7e1ff7b7d..3b7da0f51 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs @@ -423,7 +423,8 @@ protected static void LinkLights(GameObject go, params string[] lightNames) /// The name that the coil device's GameObject has to match in order to be linked. /// The ID of the coil mapping that the coil device will be linked to /// The coil device to be linked - protected static void LinkCoil(TableComponent tableComponent, string elementName, string coilId, ICoilDeviceComponent coilDevice) + /// If set, it's the device item, otherwise the first item of the device. + protected static void LinkCoil(TableComponent tableComponent, string elementName, string coilId, ICoilDeviceComponent coilDevice, string deviceItem = null) { if (!string.Equals(coilDevice.gameObject.name, elementName, StringComparison.OrdinalIgnoreCase)) { return; @@ -433,7 +434,7 @@ protected static void LinkCoil(TableComponent tableComponent, string elementName return; } coilMapping.Device = coilDevice; - coilMapping.DeviceItem = coilDevice.AvailableCoils.First().Id; + coilMapping.DeviceItem = deviceItem ?? coilDevice.AvailableCoils.First().Id; } /// diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs index e9f8f913c..ec8a49afa 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs @@ -105,6 +105,18 @@ private static void SetupMapping(GameObject tableGo) // shooter LinkSwitch(tc, "sw78", "78", kicker); LinkCoil(tc, "sw78", "09", kicker); + + // top lock + LinkCoil(tc, "sw55", "10", kicker); + + // left lock + LinkCoil(tc, "sw51", "16", kicker); + } + + var plungers = tableGo.GetComponentsInChildren(); + foreach (var plunger in plungers) { + // kickback + LinkCoil(tc, "Plunger1", "08", plunger, PlungerComponent.FireCoilId); } } @@ -330,6 +342,22 @@ public void SkullKicker(KickerComponent kickerComponent) kickerComponent.Coils[0].Angle = 72; } + [NameMatch("sw55")] + public void TopLock(KickerComponent kickerComponent) + { + kickerComponent.Coils[0].Name = "kicker_coil"; + kickerComponent.Coils[0].Speed = 5; + kickerComponent.Coils[0].Angle = 270; + } + + [NameMatch("sw51")] + public void LeftLock(KickerComponent kickerComponent) + { + kickerComponent.Coils[0].Name = "kicker_coil"; + kickerComponent.Coils[0].Speed = 13; + kickerComponent.Coils[0].Angle = 160; + } + #endregion #region Drop Target Banks From bb45d602bfc9511b796b0486e87da66bcaf5f3e5 Mon Sep 17 00:00:00 2001 From: freezy Date: Fri, 22 Oct 2021 21:34:31 +0200 Subject: [PATCH 03/25] fix: Also match ramps when retrieving surface. --- .../VisualPinball.Unity/VPT/Bumper/BumperComponent.cs | 2 +- .../VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs | 2 +- .../VisualPinball.Unity/VPT/Gate/GateComponent.cs | 2 +- .../VisualPinball.Unity/VPT/Kicker/KickerComponent.cs | 2 +- .../VisualPinball.Unity/VPT/Light/LightComponent.cs | 2 +- VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs | 2 +- .../VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs | 2 +- .../VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs | 2 +- .../VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs index 9c7750026..87a5ffeea 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Bumper/BumperComponent.cs @@ -215,7 +215,7 @@ public override IEnumerable SetData(BumperData data) public override IEnumerable SetReferencedData(BumperData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); UpdateTransforms(); // children visibility diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs index 771ba5855..6ea2aef75 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Flipper/FlipperComponent.cs @@ -253,7 +253,7 @@ public override IEnumerable SetData(FlipperData data) public override IEnumerable SetReferencedData(FlipperData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); UpdateTransforms(); // children mesh creation and visibility diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs index 053803db9..febbf4612 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Gate/GateComponent.cs @@ -211,7 +211,7 @@ public override IEnumerable SetData(GateData data) public override IEnumerable SetReferencedData(GateData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); // visibility foreach (var mf in GetComponentsInChildren()) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs index 4ee8a9c22..dfe3263d0 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerComponent.cs @@ -216,7 +216,7 @@ public override IEnumerable SetData(KickerData data) public override IEnumerable SetReferencedData(KickerData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); return Array.Empty(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightComponent.cs index 478e372ec..692a558b3 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Light/LightComponent.cs @@ -301,7 +301,7 @@ public override IEnumerable SetData(LightData data) public override IEnumerable SetReferencedData(LightData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); // visibility if (!data.ShowBulbMesh) { diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs index 4969f625d..c5eecb062 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/MainComponent.cs @@ -55,7 +55,7 @@ public int PlayfieldDetailLevel { public abstract ItemType ItemType { get; } - protected T FindComponent(Dictionary components, string surfaceName) where T : class, IMainComponent + protected T FindComponent(Dictionary components, string surfaceName) where T : class { return (components != null && components.ContainsKey(surfaceName.ToLower()) ? components[surfaceName.ToLower()] diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs index bd658722e..3d71472a3 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Plunger/PlungerComponent.cs @@ -245,7 +245,7 @@ public override IEnumerable SetData(PlungerData data) public override IEnumerable SetReferencedData(PlungerData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); // rod mesh var rodMesh = GetComponentInChildren(true); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs index 4f85ad30b..5c82f73ef 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Spinner/SpinnerComponent.cs @@ -199,7 +199,7 @@ public override IEnumerable SetData(SpinnerData data) public override IEnumerable SetReferencedData(SpinnerData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); return Array.Empty(); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs index 7798d3cf6..ec7a03048 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Trigger/TriggerComponent.cs @@ -174,7 +174,7 @@ public override IEnumerable SetData(TriggerData data) public override IEnumerable SetReferencedData(TriggerData data, Table table, IMaterialProvider materialProvider, ITextureProvider textureProvider, Dictionary components) { - Surface = FindComponent(components, data.Surface); + Surface = FindComponent(components, data.Surface); // mesh var meshComponent = GetComponent(); From 53ca89c1ddc914d30f893279d13e164c5c4144ab Mon Sep 17 00:00:00 2001 From: freezy Date: Fri, 22 Oct 2021 22:27:01 +0200 Subject: [PATCH 04/25] editor: Don't show coil and switch devices with no items in picker, and an error message if already selected. --- .../Common/ObjectReferencePicker.cs | 16 ++++++++--- .../Managers/Coil/CoilListViewItemRenderer.cs | 2 +- .../Managers/ListViewItemRenderer.cs | 27 ++++++++++++++++--- .../Switch/SwitchListViewItemRenderer.cs | 2 +- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/ObjectReferencePicker.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/ObjectReferencePicker.cs index 843011716..3e986a3dc 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/ObjectReferencePicker.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/ObjectReferencePicker.cs @@ -15,6 +15,7 @@ // along with this program. If not, see . using System; +using System.Linq; using UnityEditor; using UnityEditor.IMGUI.Controls; using UnityEngine; @@ -38,7 +39,7 @@ public ObjectReferencePicker(string pickerTitle, TableComponent tableComp, bool _showIcon = showIcon; } - public void Render(Rect pos, T currentObj, Action onUpdated) + public void Render(Rect pos, T currentObj, Action onUpdated, Func filter = null) { // render content var content = currentObj == null @@ -70,7 +71,8 @@ public void Render(Rect pos, T currentObj, Action onUpdated) _itemPickDropdownState, _tableComp, _pickerTitle, - onUpdated + onUpdated, + filter ); dropdown.Show(pos); } @@ -90,10 +92,13 @@ public class ItemSearchableDropdown : AdvancedDropdown where T : class, IIden private readonly TableComponent _tableComponent; private readonly Action _onElementSelected; + private readonly Func _filter; - public ItemSearchableDropdown(AdvancedDropdownState state, TableComponent tableComponent, string title, Action onElementSelected) : base(state) + public ItemSearchableDropdown(AdvancedDropdownState state, TableComponent tableComponent, + string title, Action onElementSelected, Func filter) : base(state) { _onElementSelected = onElementSelected; + _filter = filter; _tableComponent = tableComponent; minimumSize = new Vector2(200, 300); _title = title; @@ -102,7 +107,10 @@ public ItemSearchableDropdown(AdvancedDropdownState state, TableComponent tableC protected override AdvancedDropdownItem BuildRoot() { var node = new AdvancedDropdownItem(_title); - var elements = _tableComponent.GetComponentsInChildren(); + var elements = _filter == null + ? _tableComponent.GetComponentsInChildren() + : _tableComponent.GetComponentsInChildren().Where(_filter); + node.AddChild(new ElementDropdownItem(null)); foreach (var element in elements) { node.AddChild(new ElementDropdownItem(element)); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilListViewItemRenderer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilListViewItemRenderer.cs index 798db5eac..3ad000a3d 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilListViewItemRenderer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Coil/CoilListViewItemRenderer.cs @@ -152,7 +152,7 @@ protected override void RenderDeviceElement(CoilListData coilListData, Rect cell coilListData.Device = item; UpdateDeviceItem(coilListData); updateAction(coilListData); - }); + }, item => item.AvailableCoils.Any()); } protected override Texture GetIcon(CoilListData coilListData) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs index 3f394d97e..94a289926 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs @@ -138,13 +138,34 @@ protected void RenderDevice(TListData listData, Rect cellRect, Action private void RenderDeviceItemElement(TListData listData, Rect cellRect, Action updateAction) { + // sets the item if only one coil UpdateDeviceItem(listData); - var onlyOneDeviceItem = listData.DeviceComponent != null && listData.DeviceComponent.AvailableDeviceItems.Count() == 1; - if (onlyOneDeviceItem && string.IsNullOrEmpty(listData.DeviceComponent.AvailableDeviceItems.First().Description)) { + var numDeviceItems = listData.DeviceComponent == null ? -1 : listData.DeviceComponent.AvailableDeviceItems.Count(); + + // no coils: show error + if (numDeviceItems == 0) { + var icon = EditorGUIUtility.IconContent("Error@2x").image; + var iconRect = cellRect; + iconRect.width = 20; + var guiColor = GUI.color; + GUI.color = Color.clear; + EditorGUI.DrawTextureTransparent(iconRect, icon, ScaleMode.ScaleToFit); + GUI.color = guiColor; + cellRect.x += 20; + + var s = new GUIStyle(EditorStyles.label) { normal = { textColor = new Color(1f, 0.431f, 0.25f) } }; + EditorGUI.LabelField(cellRect, "No coils!", s); + return; + } + + // only one coil with no description: show nothing + if (numDeviceItems == 1 && string.IsNullOrEmpty(listData.DeviceComponent!.AvailableDeviceItems.First().Description)) { return; } - EditorGUI.BeginDisabledGroup(listData.DeviceComponent == null || onlyOneDeviceItem); + + // disable if nothing to select + EditorGUI.BeginDisabledGroup(numDeviceItems <= 1); var currentIndex = 0; var labels = Array.Empty(); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchListViewItemRenderer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchListViewItemRenderer.cs index c07d0257f..53f7e3790 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchListViewItemRenderer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/Switch/SwitchListViewItemRenderer.cs @@ -220,7 +220,7 @@ protected override void RenderDeviceElement(SwitchListData switchListData, Rect switchListData.Device = component; UpdateDeviceItem(switchListData); updateAction(switchListData); - }); + }, switchDevice => switchDevice.AvailableSwitches.Any()); } private void RenderPulseDelay(SwitchListData switchListData, Rect cellRect, Action updateAction) From 6f205ab426cff5f454ea6524792db3ae8bcebddd Mon Sep 17 00:00:00 2001 From: freezy Date: Fri, 22 Oct 2021 22:27:21 +0200 Subject: [PATCH 05/25] editor: Fix kicker gizmo for zero vectors. --- .../VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs index 01a1c3648..31c158aa5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs @@ -101,7 +101,7 @@ private void OnSceneGUI() foreach (var coil in MainComponent.Coils) { var from = MainComponent.GetBallCreationPosition().ToUnityVector3(); - var l = 20f * coil.Speed; + var l = coil.Speed == 0 ? 1f : 20f * coil.Speed; var dir = new Vector3( l * math.sin(math.radians(coil.Angle)), -l * math.cos(math.radians(coil.Angle)), @@ -109,8 +109,9 @@ private void OnSceneGUI() ); var to = from + dir; var worldDir = transform.TransformDirection(math.normalize( to - from)); + var length = coil.Speed == 0 ? 0.1f : coil.Speed / 10f; - Handles.ArrowHandleCap(-1, position, Quaternion.LookRotation(worldDir), coil.Speed / 10f, EventType.Repaint); + Handles.ArrowHandleCap(-1, position, Quaternion.LookRotation(worldDir), length, EventType.Repaint); } } } From ffa1509c450bea4f33d69f9bc488039ec9b24b65 Mon Sep 17 00:00:00 2001 From: freezy Date: Fri, 22 Oct 2021 22:31:18 +0200 Subject: [PATCH 06/25] editor: Also update the mapping if number of items goes to 0. --- .../Managers/ListViewItemRenderer.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs index 94a289926..e2c464afa 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Managers/ListViewItemRenderer.cs @@ -188,9 +188,12 @@ private void RenderDeviceItemElement(TListData listData, Rect cellRect, Action listData.DeviceComponent!.AvailableDeviceItems.First().Id, + 0 => null, + _ => listData.DeviceItem + }; } protected Rect RenderIcon(TListData listData, Rect cellRect) From ec92cccd22012275cbf6a25803171f9f3e9d17d2 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 23 Oct 2021 00:38:35 +0200 Subject: [PATCH 07/25] teleporter: Add component and API. --- .../VisualPinball.Unity/VPT/Mech/CannonApi.cs | 34 ++++++-- .../VPT/Mech/CannonComponent.cs | 34 ++++++-- .../VPT/Teleporter/TeleporterApi.cs | 82 +++++++++++++++++++ .../VPT/Teleporter/TeleporterApi.cs.meta | 11 +++ .../VPT/Teleporter/TeleporterComponent.cs | 72 ++++++++++++++++ .../Teleporter/TeleporterComponent.cs.meta | 11 +++ 6 files changed, 226 insertions(+), 18 deletions(-) create mode 100644 VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs.meta create mode 100644 VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs.meta diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs index f610492bb..c5841be08 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonApi.cs @@ -1,9 +1,25 @@ -using System; -using Logger = NLog.Logger; -using NLog; -using UnityEngine; - -namespace VisualPinball.Unity +// 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 Logger = NLog.Logger; +using NLog; +using UnityEngine; + +namespace VisualPinball.Unity { public class CannonApi : IApi, IApiSwitchDevice, IApiCoilDevice { @@ -26,7 +42,7 @@ private enum Direction public event EventHandler Init; - private bool _enabled; + private bool _enabled; private float _position; private Direction _direction; @@ -158,5 +174,5 @@ void IApi.OnDestroy() Logger.Info($"Destroying {_cannonComponent.name}"); } } -} - +} + diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs index c8e0c6e94..4b37ce6b7 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Mech/CannonComponent.cs @@ -1,10 +1,26 @@ -using System.Collections.Generic; -using UnityEngine; -using VisualPinball.Engine.Game.Engines; -using Logger = NLog.Logger; -using NLog; - -namespace VisualPinball.Unity +// 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.Game.Engines; +using Logger = NLog.Logger; +using NLog; + +namespace VisualPinball.Unity { [AddComponentMenu("Visual Pinball/Game Item/Cannon")] public class CannonComponent : MonoBehaviour, ISwitchDeviceComponent, ICoilDeviceComponent @@ -57,5 +73,5 @@ public void UpdateRotation(float y) transform.rotation = rotation; } - } -} + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs new file mode 100644 index 000000000..86664ba1f --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs @@ -0,0 +1,82 @@ +// 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 ConvertIfStatementToSwitchStatement + +using System; +using Logger = NLog.Logger; +using NLog; +using UnityEngine; + +namespace VisualPinball.Unity +{ + public class TeleporterApi : IApi, IApiCoilDevice + { + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + private readonly TeleporterComponent _teleporterComponent; + private readonly Player _player; + + private DeviceCoil _teleporterCoil; + private KickerApi _portalA; + private KickerApi _portalB; + + public event EventHandler Init; + + internal TeleporterApi(GameObject go, Player player) + { + _teleporterComponent = go.GetComponentInChildren(); + _player = player; + } + + void IApi.OnInit(BallManager ballManager) + { + _teleporterCoil = new DeviceCoil(OnTeleport); + _portalA = _player.TableApi.Kicker(_teleporterComponent.PortalA); + _portalB = _player.TableApi.Kicker(_teleporterComponent.PortalB); + + Init?.Invoke(this, EventArgs.Empty); + } + + IApiCoil IApiCoilDevice.Coil(string _) => _teleporterCoil; + + private void OnTeleport() + { + var ballInPortalA = _portalA.HasBall(); + var ballInPortalB = _portalB.HasBall(); + if (ballInPortalA && ballInPortalB || !ballInPortalA && !ballInPortalB) { + // duh, do nothing. + return; + } + + if (ballInPortalA) { + var ballData = _portalA.GetBallData(); + _portalA.DestroyBall(); + _portalB.CreateSizedBallWithMass(ballData.Radius, ballData.Mass); + + } else { + var ballData = _portalB.GetBallData(); + _portalB.DestroyBall(); + _portalA.CreateSizedBallWithMass(ballData.Radius, ballData.Mass); + } + } + + void IApi.OnDestroy() + { + } + } +} + diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs.meta new file mode 100644 index 000000000..71a09f5da --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4a0a07c989322cf429cf5f8bc775f906 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs new file mode 100644 index 000000000..c68d0d066 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs @@ -0,0 +1,72 @@ +// 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.Game.Engines; +using Logger = NLog.Logger; +using NLog; + +namespace VisualPinball.Unity +{ + [AddComponentMenu("Visual Pinball/Game Item/Teleporter")] + public class TeleporterComponent : MonoBehaviour, ICoilDeviceComponent + { + #region Data + + public KickerComponent PortalA; + + public KickerComponent PortalB; + + public float TimeMs; + + #endregion + + #region Overrides and Constants + + public const string CoilItem = "teleport"; + + private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + #endregion + + #region Wiring + + IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils; + IEnumerable IWireableComponent.AvailableWireDestinations => AvailableCoils; + IEnumerable IDeviceComponent.AvailableDeviceItems => AvailableCoils; + + public IEnumerable AvailableCoils => new[] { + new GamelogicEngineCoil(CoilItem) { + Description = "Teleport Ball" + } + }; + + #endregion + + private void Awake() + { + var player = GetComponentInParent(); + if (player == null) + { + Logger.Error($"Cannot find player for cannon {name}."); + return; + } + + player.RegisterTeleporter(this); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs.meta new file mode 100644 index 000000000..d7769dbae --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 14a789bd4f52b574a926b9b3282627b2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {fileID: 2800000, guid: 57668c3df120da245975f2022cbf0551, type: 3} + userData: + assetBundleName: + assetBundleVariant: From ed387414d68cc3ef2a6e17feec09fe9d5a8846db Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 23 Oct 2021 00:39:04 +0200 Subject: [PATCH 08/25] editor: Add teleporter icon. --- .../Editor/Icons/large_blue/teleporter.png | Bin 0 -> 14079 bytes .../Icons/large_blue/teleporter.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/large_gray/teleporter.png | Bin 0 -> 14115 bytes .../Icons/large_gray/teleporter.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/large_green/teleporter.png | Bin 0 -> 14093 bytes .../Icons/large_green/teleporter.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/large_orange/teleporter.png | Bin 0 -> 14107 bytes .../Icons/large_orange/teleporter.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/small_blue/teleporter.png | Bin 0 -> 994 bytes .../Icons/small_blue/teleporter.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/small_gray/teleporter.png | Bin 0 -> 1000 bytes .../Icons/small_gray/teleporter.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/small_green/teleporter.png | Bin 0 -> 992 bytes .../Icons/small_green/teleporter.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/small_orange/teleporter.png | Bin 0 -> 999 bytes .../Icons/small_orange/teleporter.png.meta | 108 ++++++++++++++++++ .../VisualPinball.Unity.Editor/Utils/Icons.cs | 10 +- .../VisualPinball.Unity/Game/Player.cs | 5 + .../VPT/Kicker/KickerApi.cs | 20 ++++ 19 files changed, 896 insertions(+), 3 deletions(-) create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_orange/teleporter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_orange/teleporter.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_blue/teleporter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_blue/teleporter.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_gray/teleporter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_gray/teleporter.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_green/teleporter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_green/teleporter.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_orange/teleporter.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_orange/teleporter.png.meta diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png new file mode 100644 index 0000000000000000000000000000000000000000..5c92a93277c4605ec77ee166ed9ddb36e1d0529a GIT binary patch literal 14079 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

=msnMGOF9Lle=SnM&NlQwLbm#eHRp;=3nsNg{| zGDZ5mVx#*qTx@_Z$l_n6bA=Xw-HpD;Tw;US>%I&}+vc}%Q;+E)-+@;zc0BKxtqdio zS3!yLuL854@O{fA0eKc?tqXJ`;Llw)+-P~vpP@U_cx&EG!n&kdWca8WJWkJIdPS_0 z5lBitWi4)u=s0wCZ2R}2_Pp8S2hw<71SxdxUN8Xl?y?UaKe*$P)^8q1y^`W%Dm4{+ z{t}B%dd_@vP$hIKFlqboyg`4#(!9gw+PEn-NSfGdT^=E?ghoGnB>%;o zjw+WYRXgfoDh^ZEPob{kVvC{8@K!?V@pbA7ddK>b*f&-@Y+Hq~i6>e|B;^!+&pAMP zCJB%|2Z)d?-UFWZ84*=(=6NM^|AD=a!rM*ig%IIV@tMd`{ zBfd%qF7;5Xq5<|qFP3fRENpBCV-U-a&!|16*_k9GBkh&tk4ty>hL}51y%KWE@gFdT z$A3oNWA{NKlo)3Oki1Eah4|sLk1S_3&z(Vy+*ut}7uleIPK5*KleGS*ZjvOPCye9w zzl$pB0!%f9BOj!}DeY8H3WNTKUg=%EPQRjo0YnDGxygUCFYYSpjz88Wh{ugcbED-Rd zaTRSKRNuJXXZL9#XfMSX=x{&){?kPQmJnL$>N97!4AJ4oAKpJL_Un}>Pynd>FO-1w zq#My?0CZ*$u^;eaBYlUi<7IG8;;l8^!G|q#N=QJq`s)hyL-=A|_Lx#fyCa3kold99 z`f|Z?ezFqp&o8L}$noDyqqfuyr9{S6{nSU2_J9pGp#uPB-*g6+p$K8+e40v)f1+|J za5Rz*V8X9;;9NI5+gB5M0vO82r5O;8>%d=%sx@Qbk<>N|4=W0k%Rwi>Tx_sC8Njql z#E?#c7q^gc{NGYz$PgMVhI0}y+y#j5Y+vQgkl8BZXLJ9)kK&~RT-QnD@TSA37xc}< zBOL#DixMY75Jq;GeJg)vme%^y@rjHCB5sFQINs?B_8oGh2HTHDqv^U3#!a#0=o|@h z#@OmC;{1U`A;1Eup#QI;A}wlP{4b9H($#X)an=9JVssbM15VHVvum-Py!S<{t2acP zjRn}Whmld6mK`OZWc?M`&%Z+g?sZ{U4NePm)j_#onHARuN>s|Krr~09>58UV_hP@_ z>(v4@?4g*tQT0nSN(@QxKWn+ugox$L9J-)B2Z}@VqJ-6mAvqo9e}h|uxd3)Ro{m2}K=06qyN zk{Mib^ptr51!9PcL%0}OA;=vev-n!YW(*__wTsXGqhabkb!Xgp_G!B_nn#7MidNfw{_x;hQ+=$*DlpK98 zY@pJ@lFBiRS(%lDT`bn31_>8b_CZ?3D(#XKUvbg>MI&!VKqoGx(iX@}LU!4Dly)S) zT^KYEVD2ERlvAMq<|Ka9VDEDAnFDvQMYo-g5>+dCaR~lqjv^oe-h+RPXLnAX*4UVp zMDb1=^ez${rq0`K-{sqzqF81C)#iV@ck_qz3H;QqG@h*$txYefuI^KN{U#!_6ut1D zg?{9&WhoxnwoY(}luHUtCw}^cW8SK6g~$|H=hF}0*Z-#;knLLz9j=Pac!jzk zTfk(OAWqd9PNA4n$Umu#D18jiocVC%B3lcMWT-U^nlHJii3$kpG{(MD`l93xt3nv+ zVyaAs%2k3+cc58M86jfOL)_pZ} zh{(Kd8Jt@4j_+v|pLrm@4&9hAH*l}iH8A6zy%eZhVh$Hv54j*1j#?b)P*ItG!=`pv z)&AO?Ve+Fx4GH|_vC@>P1sf=@?216}_LBQ$of?E=$che+pDn)WN~9k7pOTBu81$=! z;f2ifc-Rr)=6;J&EtednX8(4{7Dinro7Uc?EJ$zy@W-y2rr{!j3-9K!mceO|MMgf- zf&z5^F(^Cc#^_ET58gRS6Qy~K_(z-VGOJOgLzzB1r)8zCG>Z9!O;*cv?&Z!Hs3OCZ271t7yH=m=fha;zZruSrHH*e{SV`pUG5z4CH#lAYd2Eu8j1dLx zg^T*l=9R)qlugfn-|i$ok2RROP(S*NV!o0JS2JF$w3O*F%Z;Yn4HDolnXS&C4Ge=A zW+>`XNQABs8fEUEi&{F-EiqD%1@3h%(?wj*L?dWFGE;N^Gr(1^66R$x(#yx^6;X|f zx8;d(6xX6>&PzaW^u>JCSn*jey&IjH&~WcTkIhs5M1SL+W@0g-_3e%qRcsmB=(JBL zqutKz?!5uZ_PbruINm6TrsKCy9BrGG6N;#t zGl^~mL11=E^>AT!Hy)f3w(AH)qH$E!}~^p^?8Zpve>pRY9Yox28VW}cW= zz5Dk1*Ji8vBgK4DSK<=G)8(2L59fA9SiBW8x$X93tIqWTxc$)KNy4s!%^g;6oB=34 zJ6fDW;p?{yB^TKLGQdm0z%NArFf$1b5iU$v3&Q%?^p)9j%GYXaOXrDk=#%Oh!|>QQ z-J5!6eW|9>!$nw|pPMwMpjPNwLHh>8Ooe1Y&Xy3J8ZA$UHw&y(M782E<+i=?N{TSG&(v@gB9v^_Q0wzT`=R96v_$Qu&Ea z-j62aIe<(SJ7F~F4W2U$RSG{{cFVQ7J?GcR1p=+*1xs=R^-Nl*?73_WE}DvA{HGcO zP*HBiV-3jFouUroUVxL-w=ue;c64Z3B)U^)bRUqtOZ@zXiL$^=YS(`!2I2w-1{>!= z2^Y9AwOJ+&@W;o(y@zev)v2qSHZ0(_3(0M;CA_};g#vX|)b~23xn;gGO%x5Xy9@e3e+N&(6&LFV{X(azFcPITgv}8CgwYjw z93bRiPT4|?4Di@HTK)iE`Dc>D13$kD@B@-xx6x}py6Q5hE=E9i z@2gCzuF>oh9XF}>#+=Z-sg$iQK-Hmu7rq9XIBeCrgOKy&qn=>oxSJW`P*+~#TEr-b z=E~kk+>ztYZFJKIcfJ$jMV#0%oygbW28iu6E<6 zu4$fV2P{uBjqDuWb-=JS8^Vhs378_{r#H(;U3rb8ti=->$oM5{y zf#yodD52-}MuALv;^t*#z6HAxM%?3!CWKFnq(}%=iUpQf{&R8=&|z}Xuv`W28SBA- zP}N2{vW+<3F_F{$u`X4@@zcJk1u;l0r+ged?uux0qrV!Ir%=J=AJOGPMAhH4ZYx7v z1GE&7i;6I)ZcHm^pu*v#adXw1kryDH40?9RRD?*9+}-A;tue5d>q9OE8Rb1NiF}ku zyg`vqET*ISbzdQu$Fg|-Fs}^EEph-=Yvx|IpF*N~_PdalzbX>%cn|pyE#4pq_xfLQ zhVU``XfY$Ds|HMhl8w>10Tx3J_q~b5*um4Eo}8pM&~9TnF|1q)!GB*({ZwSU@CAdd z96Ob<@%>OfMaW>(E2EkpPPavd5eKhl&Xw0+mA+J!b!s+AAnoZrZQ^95I(x91&q3LA z#OX;4XbOFLgX71pl)Z}}K{Um0%p+HE9s0%LRT>AS*xuGA)c-2-MPgRTuk(v`gxRsvBs*ZH+i)2n>|XP~$>FJ3y71 z^bh+bX^{+%J^+Ve&UA~AR6E?GW~=B8@}dgl=6JA~ zyi=P?(=Yln_bPCesfFH0^DZ9hU`v0Uc1!!+S6=ZI9ATt78 zG}bqjj_DZMAhc+$5ct^87)G*{KN#wgm&UFLHP~9@$1_hX5}*s$HyKY%*XH6yaV5s=12-^qIv{Q z3D1#Z)t4Iu0&gMai*tJY(}4fjFpWSumCMdF*JYD;fBL|oKB>a|)RaRrNLLWTO}`-B ztC&Kz;!exnjOZ}|<1SI*&>yp3Df2q*%$L(HoCs)LS4|E&*v>6%Wqxb z&Z-!4KQVxvI%*y6Q$%$-Z(dA8uV}Q;x3vg%-M12{fczEuUKhBZQK{E>V^nFD03X>` z`4n+ns`M=VAqm^=5^jWN)Lhb_(-%T`S*J}0Hh4z~4$esb5S)&xnp zGX;Zen7(Gm_M!bS0U@GnDO}LEIR&}%37ej~#ty=OS*{0V-(smpK%WjqG1;YHFPpx+ zze!Se{m*HJu6B)PExynm;H#-K*Ifwjp0sAz{uZ$kHQ#;tc$ZdB^Y}FQ64Q+RZFVK$ zPKn;b$HLQJtGq}o-TkV{=s70by21>nRa@g$!+8z)oZO1C4{3D@+u9R+2I*?}FpGf8 zDX*p-SgQJ2X3z_VJ-ib1cc`i$F{L4Jd<-Y|K#n?K%Vd&|i?LZf1eF>dDQefi5|tU~(Me=8a0r~UJQ zTcK@gJUiGZQNkS*WbA#GFFG4kF4cYKGQ!{FI)uH$sQ2qT*3-^}hZu|nsw501OMBMt z$^L)_^9ac&PknM2(2i~o^@(X|gqS?@D+j9IDGal6BbpZsh~L76D4Scn5Q6vq5FBp( zwHQ%12c+s|Z=I^ZI8=LoGxA#U*l)tSDUq71EbteHT!-MxeG<=gS($Ir+!Ho{>#v`LV^6Nf77k(a6`u6;m&CcvHypY^pdlu9hVu< zG~~u`_%ma8rI?U4V&IfRg~RV$GP?6Vw-OkV7h~6tudgK#b6s?C&!{ZePLkQTsz1^; z)^T~_rl00lz=6b{JWsI~0$zKs%NU=c{Y-j{ioc`G7-i16TQ?rL;%epZ$p)HX)hAw!-)Yt;B0TlsjjEBdh5mG$z1nvUUflm4YjLuz3YruzUTWP$oWo-I_Z~3gI znDFkgGFXib&f*GZjc(e}J z<6ChQ1_TT?%$X_b-{gwB0A4-hBX4y5)i&|96$tKJo!W`!pA5^O#xA~*7QSqHk&`~; zIs(mWZ;avJQSdvDg*JD=-M#=PBoWnj@#6`5c0`R88g%vry4gg}L=ZuYze_UCKQQEP z59CA)GOONg^WI^t*d|R$nhceP#X8q-x|OFlM0(rZs_8;-bdAz7NXR|CZ|E^9Z~x#y zkMgCrMLrphY73m17O~zVd&Dy8GZaRo(3DVH{O+Qt$VJx^Hf~!JWl|7j4Cj#guqETL z@>{QacLrLtj1M(-(zkUyHaKxf<@f-eaJqPh6C}J`Kwm4==r((A6m6k) z?HPi!Bw|0oPjbmA+`l~(1NkT6hfi_oIVaK7x|@mQZ&#a?2dUtmE}3_g_#>&BE|ZRI zf?`~xQ4fLO6kVZF*=kN4kkv6oI62*)hs--%b!}pGXKKIea&UiYayz_rk5Ibbm8Umd zI=U%&;C$AZs{}&J;^tkxs&Q8}`S}Z%*#=s!PaXeE^QdU>GCMWh%T_bc0AdPc7HNCd z8y$z={@7b;#eO+Z_+hAZ_wlzXF0eZKua0|~xkV1S=fsmsc%@zo#%h3hVVvQ@BmIX^ znhm2aN1pAMHCc$r*4=4-y6wYLm9C^!sYBCwb^GivVCm;~wV(a?Zp$Y{))fcqXaQax z3C};YIL5+%7%FQ{G@k%Je@=-pJ?M2sjKZIMs3YmEInYb7brWkjQ(yc58Lw{$7P+tw}Kr2z{lrTFt(t*ji?yuD9$Hq}6O`*FpQ+ zi|FNu5^PiXtX5uPxw$SD)%K67`0Qq_iN$!VOQ|AY<~YMK1}+{qBw}#RDox^lGgvZI za#v_!euu4psehwSg+9fmTrhW=i9PCDwcGg7d9{7v*q#^o@xSymkG%NaQ}q5)u5>`W zaKtWltZep=E)AGiWFVr7Jy#dwp)cjrT^F$GmDMjY>QW7h?DX8=r@Qe>l-u4pwJN z-#Y`9aa@_5FAaCCU7tX>tr`av?fbv&u3$l~S5mOcqc5X+)Hv((5u*Q6Co#U7=#_Bg z4ES|Qcdc|XWaK0-kj{GkG#Z(J!4tKbdw&}LI;E#pIvsf>CeRc&cV@Om$(0jP>igvI z@^tU_6>h-nTs9&c`A!KIP-UCrKYyJ4v&CpHkka$_6<|~>Bk(=o5)%8lH!NIE%&&cyekIaC7>7z>F;;V5 z*YzjD`-l0fa)3F=?dNbqoM}bU0VJs*QDOJggnYiMjWC;zE?rebI%Dv999=WSf*Slf zl1(({LH0Crpf;s*@5jzL5rdQHb3pzk_wa-Iym3M1xVPgT@8!5`HGeC`Qu*QoJ#_{nv#$;~?m7le70(oBgw3G*Svk zH%RX8bNu`T&mZvpVdv~?cIM2?J$KAp*S-H4=-r||ckvtmfLcpa-4Fl-{1pMnQSf6w zWcUPrQ21(E1OQ;c^zQ@xH9Rc^fE#G3s~U%7ZcP93%4o0L-dSSL-0CX9DKm~2;PgmM z0b)T`n9;m|+n@BM@bj}c5_0v@IZa0ORop6fF*mcmVyuuwZpTF0^u#ogRzhs%bVl>? zfp2h7P|#mn4E|sY9`qIZ98qHDv;@^#S;AfF7T;?bdIXVU zWsq&M*XplyQ{^>LF05vLV}_5Gr*3e&#>9QQTG$%AVsg)T!ZvNiRhLi6iII z!m~AAqe5E;z6UtD2LNkBl653o;%KcLvzO?3pB{7+5?=#xC$8Ycu+>s-QnX6$_KD*5 zcjAC~OW>5DO!f*u|2-+ADmn?c$W@y(6JG#aV`97K->=_&;^WCT?|-4jsuu;$-?br~ zTpK&#W`$}=fw6AkNk7u3b#pC}(h8xA0(-5y>YSC60z~Ob2o#ze7h*EvVToS;bNi=$ z0EE>cG?Ru1aYnt-6)?-q~!> zU$X)+@_c3Bnm=j#h#R0;lDQgd4NS63M<77^bCw(d7}`V5;<-FlE^KdsG9HbUt{+x% zABjT}R4P<0+p`n*cguEWC8%b*iJJn)&Gms{)DC~%C-xiwJLB|I*P&^Cl;60MmU@`bdZ3KKEK`Oq_t3S zsrkt^lW%-9&i8rm!5_LUs>XJo?X(Ah?`|I^F)v zh9;~cz<)A6lC_Cnk^&CJ!sU0P^r)*?Ngz-uQTjKy@sTa!K}^qUTKwEWl*lj(SWvV& z(X!lbcv~kMb$#Umz$O1O&pddT)zkZ58|gxKzJs5M2G(#n#bcM~CX>a!bkY)Mrqh>~ zw1dZc8sK)-{`LV}rp|jNhn-IyVQ;G3ZAvY<+AYhzt?TwXp7P`tO8(pKfTzQl9fpQ` zTkG5524L0R{Lw*@PMe0KaxII$aCSNs))+6Va!hN>JIwZ}}*6-N65p`EI^bUA!FFB;h8*v}Z{|CS5A9#75L7x3RW#69Bld*--g{l8~I zhADp=XH;=j$M&pZY*x2Xb3OHTmpm80d~FG3kUk+XpzZvY#~@S|lcaJhd`Pm-MuC`q ztuy;Ey)sDnrn0q{(f%^N7Z#a#u01oL;kWqyDyK_2Q%62Xj7l-ul+OGH3U`V;721{S zm43uM$FcDcV%Ih;5wiGxQ?ezaIvLPWep1GNW%_d2aiCgybO`{b+65dZ1*0hou=(`V3rc)fTUUW>T4dgE4TNuz z8AUs{y~6*Y|Dv);wc(`Ax6VS+p=(AoB0S$CE29LPFAFhVtFw;bCMT(}lqtQ8drNVC z!vXZcyoY@unP|2u;POFV{qZ`9ps?}A!e53lkBf^nTLIR8a;ziXMS=5W>V#04EMG~0 zlfA4_l696CLvZv|i2QvRZ!r*HQSv#V>a1oI;Zm4fsWVv+OhxrZ6)RGy zc#(v|X<4D%q?!tACcn^^GpEb%+1>cAj-u|+ZOFLnIukkCwd%jZBoj7P<09?TKsvjI z!W5mNG5dn?mpE4lJ7yDeYnAw2$Z98p|6#KD+uBgl-Urye&eXhmf4tZ||LV-Mu@{$f z>^7!^D7TA;c|~*p_tK=&=4o@4_o48U=r;ucUfnhuNNpytoEj@T`2<(s94=kak2A9A z?3cZ?HRv%VZb-!=*geJZe(Ha`vg*O^5HH%{t1Sxtd`oFd8%EU z<^b4OVC(pzA^4Q>q7}ngL^N7rYW3K9Wd$)OCMqykfNa}(W}14jd)Mw()TNLc2x1l0Pcqkw5x;?c!)%>OJmB-Z@ z|FS=Dhb&EVJjS@TJhHI4`I!riK+l)9&SDEJIV&j3!HkCMeBf_$Nq0BZ>Yct4HCrSY zY=ZQC?X_jw#@Jum@HsVTDrs&hsb#Hal0i@n%`X zmyE+m3l~T%d4A2P(hK>j4}^RfRM2%=m4Qr&9`%R&F*AmwIQ?&*@(RzyQ%`2^FG!Sz zIzs=N(g4Mo`~%ir!3)2xE&8S0UVNEMZfg#dtLG=bUU*a7kP|E5iS!g?0@w41CGjrm z>EyIgq7-q$Z?wXl!Nwp7m~3-zCp{!^{SeFLTr{Ujb^2u?iJZGyA0a75P@veKqoG(* zueo#OCqO%#-@H5c;?iJrbV<8({2TbBYgqy^kZWk)EE^e1z6G0!af;CyYyRLWkzUM`5q(6K08N!CSwxPVdOnPGk*Zg|rf$s`g z0w3^=rV`UmX;|@f$$)|U$9}pBV#9AZ)=O!)%}_Xp*73caW*^t+y~|x=>n8A3 zXveL+#)cV{5(p+M0$qLuZT1>7%G=R`v{g+G;MY z0)I!)L&<#Jv?QJf%w6XmxY!$Q9eCDXr0c~qdZ7F66oSuMz68wYsXHnbfIIcE!&ofR zR(%GwtcsN=hnMhMOKUc~V24NTkyvCM)@YSaQN zj{wgY|7KO*I*<`n{xaF0xzA-F_m}9!LMC&M5^6+(s>XBo>WRdx-SnPiW0T@x2_v%1;P9@q8GlrzOSDN7E-w*?du@7m zyd*QY9DhzW&`AUVZa3GpXOF0GQP)u<`&vf0JPtD}!c5T%<1M=^Qi)Wt`x;N#0!hNnwb|2-Cs_WsN)Y;UWhv^S7dc{B zeJ^Y2wCV1$8ajsG^9_Vv@YW^)KVQ<2TuB-jdyFS;6zgAq@)PAt0Tf?6VGRcBzkZD{ zA>7#zcgV?K8q}R`tA9$>YJnq zQZr#BV04fNLZ?riKJr9@P&Y}RNx$T)Qo8v$SWZ|~k@od2Kjv4B4-V(t?YNsB$Fhkw z9|k)Hp2vN9trcFzIMf6*n4mxr&Uzpvbu{Cn=i=;iFO7{&Nk)ZpP;dOk2>14 zo0qU8z}8&M(@@V*F?ThWy5fzvH@l1^X+u+t#^GZ}PJ#5+~&BTV4Q2eOIhNNR*Pt?mGH_nve8?Z|E(`Ca| zJz4GcXUkr`ioQm}%r_@2Mh~s#S-kW>hBP(LMu#=5%x!GKW1C)o`nP1t))kfT5WYHH zE&3F6`Ak#}!D2KxS@@h4`#zkP!yxkAg-S^(?k63NephJ-@Fl#uoA#Yj{Uf>BJIy0H z3UkjP^q|s98uK8}DKey{9CM-=ClN1iD^eyHyTLTAxS=i;FQH~<^6NLe8bi$0nYwU+QFNf znljl@u?2tMb6!p;Ewi02$ca@X3|&EBL0BH{>M zFwXPK^y(x;#$DuBHcXUpM0Ry4@$AWZTUUz$vEq(fu&ijVKfTtApS{`UiDT5o4OHd# z6M14jKi9yTKDU|A&PaXNQ$X};Yj~uxaKy9Q5t%GoG8|l$?hrjqHsDW<-t_SCNV-T($)4!+$8EPKNBAs;X{sAY zaqfF=lh>Nog-{YR-7s)!lSI9Y682w@xryF>S#H}J{SBG`*MFU+zjlfVM1aRF=h`SH zz&eilO_YcNACp^o%0*zVayj?)wcl#5YmL*XKP|{jQD!OJ6O#rK_}>>fpJk)$R3<^` zQxoUcGL_Jla46BIP0PK>oRcg>^ksz;BES>)4oN?Ut8 za?SlXc=Gh*z!VAiYw_E1fe$^=2l*Zk>oq?Dk$%<0rrp-U_lC*NNU;voLW|3EJY0Xh z)R1;0im}($e!K$}k-xy#oZJKzKitbELkr|XXgw0}peHY>g1(=&Z9-Pu!E_4)n`|cI z>Wur*=h4zt_^y-fQ=Bg^o1s_gNLR$iwp}{piREABDO&Bn!XoYUu+Aqz2WBDkN?G~Y z=-Ap_e>&eat1)waUk|X6-$Vovo^%s{+#SfPqQJ$;`;6grUq>>j$+s;nzaCa!c&P`K z7kY9D$7p*xB9%>d6K7#yo~@89Mavw-??&x~Y z0}HhDQxbw>xr&~SCMCd-UtuUU&J)+4?1;3{+RGjSWvy&!^6Tm_M>OFnFZbGRx8b3F zz!&GEF`7zfc=c#rlKYZ+5xTW4vIj<|rk}iH6BWJ%akpj3L*?~&!ZtTi6{di#& zVE-_HS{^oonnJUhaa(QFKR02Qc#FD7fx*;GW-gJGCJcRv8W8*B~5a5R$ zLwx$h0Q^xpna!Kyp7N}0I}tEU?M3?bTPpQYmM5^h39y-uepYR&Z1lm}mH|&B(GwVO zLIAtofdY$g)E9i{i7lJB?{Ctw_FZMuAHzTbKy;xLo3E-2Xseth*MupjPw={*X%jB` zeDJ}o!Rw|P<3C(fX~Y26_VHfbiw!_7R-=TNA)ewe;QuE?SB5!=R0j2+#=9;79!P2{ zvkKDb@>PWytCi6SY=Aq`fD!>f`Fs{N=%IsYtP)Hm6j3VZSk^#~0Iq&*EaMx~5fxwF zRdSN9*HCM~{i1AO@crNZ&tJPKMFQ*s5l5#_Ji&V&02sT`oQ_Dkb1*@+pdkZz;1{B! z9FYd>F!l{IEB(jcA7El9u)RH0w3vcTt!ij;j0LUs93$F`LCkg zU2&%Udwf3J72Bxq&`-&aQNIZ{STA-gBPRA&(>_(T`5QCQ0l0-t)m_KKM*0_M%~QU9 zuIx_Pv3;mKRm+<83@C~+ju!<$qtoOQv%jznb*a-Xu_x(KIz2$I@x5g?>?|aDvOLW> zr`+Q=f|1G4>qCBF;gQhahFw6n9&ok7kt>mpFs(WT$vd6d-wU~X z&2nkc?kH~ilSfKTExv;kwe}-ih+7#y|5p#_HoxZXjokaRLiH0~j^7Be`5wy~lWm?j z-Oea@`#w^?fF?D1J?6(AwE0re;go))?7x4n)~}zqD{w?cLnj3C?tX%>uwZ9{*NU?!mVXzC1c%T zQ6}AE>9aVH)foDzZbhO=SNnFA*+3L#&F{YS2!}N?Lwn}1r1<2xNm&Vh)#S6-L(npwXn4F?$bcC2*y{P8?4tf!TLNvlws!9wB-6P1f*k)UqW;do%LqTE5MeAc_x zI$MeytOX)wGU)+TXh)YHBEqW$843m4A5raZg5Dh%PFTm~3i3?Pz5Dosc}18%nDfQdnW&Q3vT#{ny{P`D1PhzdJiKYnWzCT!A(78R&S4pyIqL-+ z5r9ihkF?kf|C(=xJJCGv^-gjp!bohd@>L|I9r@&99EFRl@>|q(AJX#Gc#Wiucg)f8 z30~OS>`3<5p$&en=PjcoO#_6;RCMNbuYYX>4uhZD@WeS#X4_h@#Ta~F*c=zU&|cVl zmB!8a`v%6yk&?TR+~va!dtaXz$1jHBGxe~66rVW!aF*_zY;_9L*&Fbiz5>c)pGMbc ze77k+EVgrmPpQH~wey9} z1ba|O{PI`!Maeiq!kI3cdb~y6h(SBFqW%J&jl-^IPDh|K5 zXskf3$hG{|O^Ai+8Vp30j393Vte8?IqeQ8t&9!4Q(KRNpfvu~|G!tQyPM$!JM{t4g z>G&aMP;GVXjN{z+__+`j_-Oqj=AHMj`{ThL(hyxAC>9B4L{M#Of9q7@xwgX~$#fie z+*Tpvq#Afj;T{)FjdyD;K+S(6kM50dLjo}-sOv{;mC&uCPWgzUv=aJm7}+p!v#9>Y zx=(iA@arVNs*;p{4YE`yW;P~^uTmlbg0YRaaj}2N%Vef?c;@PgYo&CNp!d25j5loV zHA$RVtgFnvPNWZA+<6Gr<93S6Q#S9o;U%*lyt44~{0bJ`)(Xk5Z¬R*4{tUSy&8endqspc51iz97zIa43Bcx}N}XgHPgz6u^`Y%dv52#s;?Wjs5=0 z6^a{qCkhrQa3=$z2U8#Misq_dad8vXad@cQef)j*kJZR*rwH)P-Ni;$BZP009;+5DP&b?t~?Pbjw$T+hH}3=7mc<_8qZ%(qZ7-9 z>@}}jXaH`ix>qF`fKeR59xE{Ue(bW$mBn8lDCp>JY;H#U!)yM6aw;%vwe|8ENO9@6 zcoOyUG)CtFH#dzWa7*v@z10V(o^qXM#flr-IzICdhL#umKsok=*F7#HEQ&GbQ6E-Sx=hie|6}F)}G~&DEtDcr11Xo zLkPK@%i&^V`c{dHR4Q$ZmjhylU;iwRK84G?F3Ip4J-QZP?asGNy!y8K=22MDPR|Ls z-H*}7w_q`BLOyBG@`2!O?LYqnVYHcpZA2Xiw>&8cG^#OY1@wWwYULYm=i50^g6Fyc zGQ{UeApAC~3Rfi!NF*}7fmQf2U0#6U6YWf3M+rI}C4r{*n?%|{BpA}dCIRvo2A@s>6|KD!NyNU%oMDj8`%Q6SMU zB~0>zh*su12Zdi$(PfgN2?pP306VWncMf)1y@CQmwh6$)+n+wfD?oqkuE(bZfnpw{ z1j{U^6RYZhq}B)ZRR#(uaA1Z47aSqmt@A7pg}Y3?M*~DIwZ6&`rajmNA0r5bjEKXh z$cdMWd-sl&b;Y4ddACIl@VFScoS&d^pnSm;rL;kfxZ_xYTwYEsTU5N421#@mhr_5c zZL|}^NQ-0gXY})Zm4vr4Ybla%EWNjGI*lNX>isC~szf|qvx31h$7H&K3jibwZYy!g zv#R94nAz$2T_kWbE|)xeNdiu9|2IGZV~Va;2qUuXPaULK=d{2rDxBR}w&Lv&J1%!T zq!+4LO$wv2Xx7QC&q1&>12B1{*bztYIFJMD#FOn5#0zIYK8P|PcNKPrvKJTCN1Onv z7W$hP=~GOOJ$bcEKJL$xt%bcrd8HeH9`dVggVCU@AMOmFulSl>7sWnMJKwY=!~t31 z`(z_YxA_kN`eKXu44q5pJGCNO->w^KD3G62dx?AY_*7)+NjWL@Mjkvve75=B;(=}D zl+{SBj~XM4xch)4x;v6RfpmE28xx?ZL4h_d_n1?2V-h63)ADdWVLI-cI}u}T&?ph1 z52qPmZ?pk!|68~}@5dkaJpCKsMC1|_KRk?bl{nHbcpE0Tzl!N#1lMyXMGs9ZGrkx~ zUWA44!7(u3i~PF`j(K{WNXvQ+*3`o3N*+2|U(1FrNqbbn({ z-nj|@zUu_II91z=42 zwIQE20LFS(_6m>#^-^aRzlMl6-~_2(9Ua$NqCg7fC~=%fhGsHo-;HD^i}E6Nq(LkX zeUR0@X>ot|MwE+-2@gWFhoR~LTJF_jOkG|e?4M2El4^E1?sFa^MF*qAXD>&fYT`*# zrgch&h~67>QHVrKjhz7jCSDVoyYFViD{)Yu+!eQr$r8fBE?}Hq+yycWkAohL2Z_RNSCwBlU z8lS=?FYGJ4a32x5@#6($nWN-TzSmi`b&q)&K{TFUxiA^b>3&0=8hFwAYMB_(yo->wj}Tb)W6M@Q zd5gznpQorp(r{#=o@WyJ6Q78&f)Jg{DL(<1XjDqoR1v0u2ptSMZx}17IWAhZxPk6f zVjYu;$Bh*3LUWj;9h(`F0V^1Aswqc3;BJ&1|DcHY><<$Bs-U);U=Z|YC`ylA+#Adz z!uH+8Fo}AuYzi-G_Rnh74@)3%{}t&#)Yp6h*+~wExSller6=RfMz*=W@C$UoPdyK?VCd%2>bhPk)@0pPs;uutk|!= zdYd#u?6zJqmesy|Dlo!)yHsy<##m#IE8FnD7}1UQJns6~4hTJ};{js@3EMbjeoKbW z+DARrv}*#ew>=ovXi2{`dj7t;)%Dakr^I<@cN` zuy%LBw?)du=rh50L4uQruH6H3F{!c27d7;7^k~V@3$^3Au);Ii#I(`UkoW+J##hfS zUhBnNuF<|zd#8QBL5s+0VUQ+E?96hDV*ut`j21UtCOal3+aHsuXAoR=$tGVKQsp-W znlLI}FSqW<>QEap{Hx;ub7gL2%NpO1;qhOZ$SuIe1TpFH@8hfXx@Iz@1SYA4#Ka@Iy?WKy>jM)U5YL}23j6z{(iAEa8- z>s0zjCF2_j(7W^7s-+M6p$Zg|nOAa`y=qPxQGsKmJ&uQm()W%8C0*o!%BxBDxK|KM zrZP!)N0l+toYA*c+fzbsgA+u4i*4$oNTDKsU!-{{!HCKD=adDb0B7MdfZNrad;5gb zeq_t>fYvVNRfTB==_e6i-nq$;gRQ~ivT<{^Dyyyg)SFCyR-n(F`e6Ct6Twk$5f z%osK!ZFUcjE<`F`IkbOtj6lQJKIsZ?`%268nl3~!=FPAENhcHct!8!AbJ$`-!+D`d zNZBzgiR=8PPH5~co}9&+?_`wB;5sAH(giA&RQfJJL3^vKrE8VT)%y2c0U--)6&2}& z;I?q0c$O(qqt5b@GeCXRTw^Y}0R8R>6`sqfCD-r6dzcZ0dY^(}zEd?-CTY&_l?+2B z{rH{K{Ia-f3}lq7;4-JtM5{>oc*t`ln5FxUQB|xAIyX&D^>s$B%fRzK1?%%TNj zZ%c{Ptq^u%d>aGYN*jQdjG1 z=p?xd`2pP<+F_rRyNE_l#r#R72G#d>Uf`jSS0Xfq0wuH6B@Y88S&WowQ^{7!S1s$Z zO-$enh2H}0wtkFq7ip7xNyf}m`NlT>$PJmZtE=s}7L)&+7MNMggjNu0-z<)t5U zsvlOlaH>==rtzfU;cR}+?x#hc4a;=4CngRk+!g7XZh3c6WeaVY-)(lg&6f^n=M4O> z%su)_c4+l@2x6Ns?(b}lE*ZUo1b*wE7$r36w!=HgOeHxmEQ}vh>$*t>p20@pe&1s@ zM1HR8L@Xt;^Wkb$z$7N$si>w)6f4~_JZx0D_<|sUG0-};Wx1LE>!Jb3kMX-vn;cs( z(U2e?^eQqxy=1fyiT%~h6*xr`^7@xq$>qWT1!V!-a-;cY_Z1(it#Y9yEmW;I(*kU* zwV>ajFyzKD#sB8&1rtpQ+h9or3Q={?f&fAM`H9joUVujqc_cC_k@q%@U z>5Mi$Q;8>|t1g?rP6b=%PhI&yh}aWcpP0D(J;A7sLkMPm*04 zJSI zyetQej89&6a-oGdoNY7AeWgv1+Xe#C(3Z=PR>$W&XutKHK3cuk(JG?{6iag^zli%U z%5j&B?nx##%zIeo`un`f5?vQCdNEep=R=*!*a?DM$YE{TTDjw||Fs5kfchyMc>B^K zZT7hzPlJ2DD;FJ!r{HHES~pOD(JL>st86q$08{4X_0A6~es!PWnKtnG-qDh=^OTF2 zwBM)5=1P2`BtG!otOdVYN8UgMMi-j!RoOMrpVu@H+O1O5*EwXmz9znAYUyp^8Z4T| z|Mb^Py<6>nlMRS;et&~<=Zg@%K$H!psV+PPcDjfM7ecuMn2U>Z(S!T)I^emt!@81C zx#(xk@XzKuD(YaH{68K2g>;)TyE#41FT#Hhp}Dv64-Obt-dK^mbv!e%RhU8`umYMA z1=27>-e+B2gtty zLXn{SlEuTNUF4XPsg1(RDoPwyRJUhe%SI#-zP Qz#;)!8hYxbYIYC*AHKX_RR910 literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png.meta new file mode 100644 index 000000000..dbc4bde6d --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: b69f01a1d3ebdbb45a757af9834de674 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png new file mode 100644 index 0000000000000000000000000000000000000000..f59101e4293ebbf19a1b906dea26625a1e8deeb2 GIT binary patch literal 14093 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 BWhVdt literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png.meta new file mode 100644 index 000000000..a6a1f2a43 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 6e0922aff57702e438b1a1fbc3f7e825 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/teleporter.png new file mode 100644 index 0000000000000000000000000000000000000000..ede56a80cf44c2e125283237d5094263500a3206 GIT binary patch literal 14107 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 O0000L1SrRx0Z2KX8FvNX0}Zzc zN{|@9Jj#jzXL-*V{x%`dG~r^D_UWK-0KS?@9Kfmu z-~~0S&jk{zTS!U@{uXX$WzC8mmbgP<*r=Q4~un@U*N77eK#u(+PkvvI8QM&B|zLRcAYa&T4?lmbMDL#Fc!bK#URk`yOX@Nl%jVO5Y32n-2=oSTPAe&T5Re z4N8}V8rMxH#)@YquX>Vt1s-LEcPthqTSpP;ED3=6_GR7q70*~9E3Q?yWHfzAjFwCt zuuZO1axgC|70`D-3XZmeT1wv{H9e&JE$O zqg}2H^8~6NaKYH1H|iwXl%%gyYu}f@&+$~uZ-B~b9dPA}`zLfm?AtP5B6?=Ryl1$w3U7h3q0J!4~TcbB6>Qe4PJsztg%9+ce;GNHk<(nKM?)dqlIx-|e zm~HlwUTZ7JYrSb~{j-5-VXTUjTZY5l`O_!X2m_9};+?Gje)NCV>m7d6Iu1|({{YTA VPT _icons = new Dictionary(); @@ -121,6 +122,7 @@ private Icons() public static Texture2D Spinner(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(SpinnerName, size, color); public static Texture2D Surface(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(SurfaceName, size, color); public static Texture2D Table(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(TableName, size, color); + public static Texture2D Teleporter(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(TeleporterName, size, color); public static Texture2D Trigger(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(TriggerName, size, color); public static Texture2D Trough(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(TroughName, size, color); public static Texture2D Slingshot(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(SlingshotName, size, color); @@ -152,6 +154,7 @@ public static Texture2D ByComponent(T mb, IconSize size = IconSize.Large, Ico case SpinnerComponent _: return Spinner(size, color); case SlingshotComponent _: return Slingshot(size, color); case SurfaceComponent _: return Surface(size, color); + case TeleporterComponent _: return Teleporter(size, color); case TriggerComponent _: return Trigger(size, color); case TroughComponent _: return Trough(size, color); default: return null; @@ -215,6 +218,7 @@ public static void DisableGizmoIcons() DisableGizmo(); DisableGizmo(); DisableGizmo(); + DisableGizmo(); DisableGizmo(); DisableGizmo(); DisableGizmo(); diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs index 0c9ecdd32..68cd10352 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/Player.cs @@ -294,6 +294,11 @@ public void RegisterSurface(SurfaceComponent component, Entity entity, Entity pa Register(new SurfaceApi(component.gameObject, entity, parentEntity, this), component, entity); } + public void RegisterTeleporter(TeleporterComponent component) + { + Register(new TeleporterApi(component.gameObject, this), component); + } + public void RegisterTrigger(TriggerComponent component, Entity entity, Entity parentEntity) { Register(new TriggerApi(component.gameObject, entity, parentEntity, this), component, entity); diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs index 5ff8f40ad..8fed6e36e 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Kicker/KickerApi.cs @@ -108,6 +108,26 @@ public void DestroyBall() (this as IApiSwitch).DestroyBall(ballEntity); } + ///

+ /// Checks whether the kicker contains a ball. + /// + /// True if there is a ball in the kicker, false otherwise. + public bool HasBall() + { + var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; + var kickerCollisionData = entityManager.GetComponentData(Entity); + return kickerCollisionData.HasBall; + } + + internal BallData GetBallData() + { + var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; + var kickerCollisionData = entityManager.GetComponentData(Entity); + return kickerCollisionData.HasBall + ? entityManager.GetComponentData(kickerCollisionData.BallEntity) + : default; + } + #region Wiring public bool IsSwitchEnabled => SwitchHandler.IsEnabled; From 1e63d540bf3328c0cfc321b1062ba5ed15c6f443 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 23 Oct 2021 01:09:29 +0200 Subject: [PATCH 09/25] t2: More material fixes. --- .../Matcher/TablePatcher.cs | 18 +++++++ .../Patcher/Tables/Terminator2.cs | 53 +++++++++++++++++-- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs index 3b7da0f51..caf7796ba 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs @@ -240,6 +240,24 @@ protected static void SpotAngle(GameObject go, float outer, float inner) } } + + /// + /// Sets the angle of a spot light. + /// + /// + /// Supports multiple light sources. + /// + /// Game object of the spot light + /// Outer angle of the spot + /// Inner angle of the spot, in percent of the outer angle + protected static void PointRange(GameObject go, float outer, float inner) + { + var lights = go.GetComponentsInChildren(); + foreach (var light in lights) { + RenderPipeline.Current.LightConverter.SpotLight(light, outer, inner); + } + } + /// /// Sets a light source to pyramid spotlight and sets its parameters. /// diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs index ec8a49afa..ce1d2ab45 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs @@ -22,6 +22,7 @@ using System.Linq; using UnityEditor; using UnityEngine; +using UnityEngine.Experimental.GlobalIllumination; using VisualPinball.Engine.Math; using VisualPinball.Engine.VPT; using Color = UnityEngine.Color; @@ -209,6 +210,16 @@ public void Disable(GameObject go) go.SetActive(false); } + + [NameMatch("Wall002")] + [NameMatch("Wall003")] + public void InvisibleWall(GameObject go) + { + foreach (var mr in go.GetComponentsInChildren()) { + mr.gameObject.SetActive(false); + } + } + #endregion #region Flippers @@ -375,14 +386,43 @@ public void CreateDropTargetBank(GameObject dropTargetGo, DropTargetComponent dr #region Materials [NameMatch("_Plastics")] + [NameMatch("_RedPlastics")] [NameMatch("_RightRampPlastic")] - public void FixPlasticsMaterial(GameObject go) + [NameMatch("_StarPosts")] + public void FixTranslucentMaterials(GameObject go) { var material = go.GetComponent().sharedMaterial; RenderPipeline.Current.MaterialConverter.SetDiffusionProfile(material, DiffusionProfileTemplate.Plastics); RenderPipeline.Current.MaterialConverter.SetMaterialType(material, MaterialType.Translucent); } + [NameMatch("Cab_DT")] + [NameMatch("L52")] + [NameMatch("LSling")] + [NameMatch("Rubber2")] + [NameMatch("Rubber7")] + [NameMatch("SLING1")] + [NameMatch("T2_Gun")] + [NameMatch("_Apron")] + [NameMatch("_ChromeRails")] + [NameMatch("_CliffyPosts")] + [NameMatch("_LeftRampMetal")] + [NameMatch("_MetalPosts")] + [NameMatch("_Rubbers")] + [NameMatch("_Screws")] + [NameMatch("_SteelWalls")] + [NameMatch("_Targets")] + [NameMatch("_Washers")] + [NameMatch("_Wireforms")] + [NameMatch("batleft")] + [NameMatch("batright")] + [NameMatch("sw53")] + public void FixSolidMaterials(GameObject go) + { + var material = go.GetComponent().sharedMaterial; + RenderPipeline.Current.MaterialConverter.SetMaterialType(material, MaterialType.Standard); + } + [NameMatch("_HKShip")] public void FixShip(GameObject go) { @@ -463,9 +503,6 @@ private static void CreateFlasher28(GameObject playfieldGo) #region Global Illumination - [NameMatch("B1")] - [NameMatch("B2")] - [NameMatch("B3")] [NameMatch("GI_1")] [NameMatch("GI_2")] [NameMatch("GI_3")] @@ -551,6 +588,14 @@ public void GiIntensity(GameObject go) [NameMatch("GI_28")] public void GiDisable(GameObject go) => go.SetActive(false); + [NameMatch("B1")] + [NameMatch("B2")] + [NameMatch("B3")] + public void Bumpers(GameObject go) + { + LightIntensity(go, 1000f); + LightTemperature(go, 2700f); + } #endregion #region Insert Links From f3e778d3691d98b2185b49037166e3820dec3aa4 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 23 Oct 2021 01:09:45 +0200 Subject: [PATCH 10/25] project: Add missing meta. --- .../VisualPinball.Unity/VPT/Teleporter.meta | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter.meta diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter.meta b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter.meta new file mode 100644 index 000000000..f4319c4f5 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ce0e4c62b28a8974398843e1b0b4d79a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 9f443078a02f1c550c32c90c6cbc7191b9c7f208 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 23 Oct 2021 22:06:27 +0200 Subject: [PATCH 11/25] fix: Alignment of object picker when indented. --- .../Common/TypeRestrictionPropertyDrawer.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs index 1fb88abc3..a83221f09 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs @@ -56,14 +56,16 @@ public override void OnGUI(Rect pos, SerializedProperty property, GUIContent lab var ta = go.GetComponentInParent(); var field = property.objectReferenceValue; + var indentedOffset = EditorGUI.indentLevel * 15f; + pos = EditorGUI.PrefixLabel(pos, label); if (!string.IsNullOrEmpty(attrib.DeviceItem) && attrib.DeviceType != null) { - pos.width = pos.width / 2f + 10f; + const float padding = 4f; + pos.width = (pos.width - padding + indentedOffset) / 2f; DevicePicker(pos, property, attrib, comp, field, ta); - pos.width -= 10f; - pos.x += pos.width; + pos.x += pos.width + padding - indentedOffset; DeviceItemDropdown(pos, property, attrib, field); } else { @@ -155,21 +157,21 @@ private void DeviceItemDropdown(Rect pos, SerializedProperty property, TypeRestr if (attrib.DeviceType == typeof(ICoilDeviceComponent) && field is ICoilDeviceComponent coilDeviceComponent) { count = coilDeviceComponent.AvailableCoils.Count(); - firstItemDescription = coilDeviceComponent.AvailableCoils.First().Description; + firstItemDescription = count > 0 ? coilDeviceComponent.AvailableCoils.First().Description : string.Empty; labels = coilDeviceComponent.AvailableCoils.Select(s => s.Description).ToArray(); ids = coilDeviceComponent.AvailableCoils.Select(s => s.Id).ToArray(); currentIndex = coilDeviceComponent.AvailableCoils.TakeWhile(s => s.Id != deviceItemPropField.stringValue).Count(); } if (attrib.DeviceType == typeof(ISwitchDeviceComponent) && field is ISwitchDeviceComponent switchDeviceComponent) { count = switchDeviceComponent.AvailableSwitches.Count(); - firstItemDescription = switchDeviceComponent.AvailableSwitches.First().Description; + firstItemDescription = count > 0 ? switchDeviceComponent.AvailableSwitches.First().Description : string.Empty; labels = switchDeviceComponent.AvailableSwitches.Select(s => s.Description).ToArray(); ids = switchDeviceComponent.AvailableSwitches.Select(s => s.Id).ToArray(); currentIndex = switchDeviceComponent.AvailableSwitches.TakeWhile(s => s.Id != deviceItemPropField.stringValue).Count(); } if (attrib.DeviceType == typeof(ILampDeviceComponent) && field is ILampDeviceComponent lampDeviceComponent) { count = lampDeviceComponent.AvailableLamps.Count(); - firstItemDescription = lampDeviceComponent.AvailableLamps.First().Description; + firstItemDescription = count > 0 ? lampDeviceComponent.AvailableLamps.First().Description : string.Empty; labels = lampDeviceComponent.AvailableLamps.Select(s => s.Description).ToArray(); ids = lampDeviceComponent.AvailableLamps.Select(s => s.Id).ToArray(); currentIndex = lampDeviceComponent.AvailableLamps.TakeWhile(s => s.Id != deviceItemPropField.stringValue).Count(); From 9e78ba353a203799b51f140499afe5ac03a4931c Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 23 Oct 2021 22:22:09 +0200 Subject: [PATCH 12/25] teleporter: Add remaining attributes. --- .../Common/TypeRestrictionPropertyDrawer.cs | 10 ++- .../VPT/Teleporter.meta | 8 +++ .../VPT/Teleporter/TeleporterInspector.cs | 62 +++++++++++++++++++ .../Teleporter/TeleporterInspector.cs.meta | 11 ++++ .../VPT/Teleporter/TeleporterApi.cs | 4 +- .../VPT/Teleporter/TeleporterComponent.cs | 22 ++++++- 6 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter.meta create mode 100644 VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs.meta diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs index a83221f09..77eaeb57b 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Common/TypeRestrictionPropertyDrawer.cs @@ -177,9 +177,15 @@ private void DeviceItemDropdown(Rect pos, SerializedProperty property, TypeRestr currentIndex = lampDeviceComponent.AvailableLamps.TakeWhile(s => s.Id != deviceItemPropField.stringValue).Count(); } + if (field != null && count == 0) { + deviceItemPropField.stringValue = null; + deviceItemPropField.serializedObject.ApplyModifiedProperties(); + return; + } + if (field != null && count == 1) { - deviceItemPropField.stringValue = ids[0]; - deviceItemPropField.serializedObject.ApplyModifiedProperties(); + deviceItemPropField.stringValue = ids[0]; + deviceItemPropField.serializedObject.ApplyModifiedProperties(); if (string.IsNullOrEmpty(firstItemDescription)) { return; } diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter.meta new file mode 100644 index 000000000..910c1e38b --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1ff4e3d75b370148b959b0272fb348f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs new file mode 100644 index 000000000..971b20043 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs @@ -0,0 +1,62 @@ +// 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 UnityEditor; +using UnityEngine; + +namespace VisualPinball.Unity.Editor +{ + [CustomEditor(typeof(TeleporterComponent)), CanEditMultipleObjects] + public class TeleporterInspector : ItemInspector + { + private SerializedProperty _bidirectionalProperty; + private SerializedProperty _kickAfterTeleportationProperty; + private SerializedProperty _kickDelayProperty; + private SerializedProperty _fromKickerProperty; + private SerializedProperty _toKickerProperty; + + protected override MonoBehaviour UndoTarget => target as MonoBehaviour; + + protected override void OnEnable() + { + base.OnEnable(); + + _bidirectionalProperty = serializedObject.FindProperty(nameof(TeleporterComponent.Bidirectional)); + _kickAfterTeleportationProperty = serializedObject.FindProperty(nameof(TeleporterComponent.KickAfterTeleportation)); + _kickDelayProperty = serializedObject.FindProperty(nameof(TeleporterComponent.KickDelay)); + _fromKickerProperty = serializedObject.FindProperty(nameof(TeleporterComponent.FromKicker)); + _toKickerProperty = serializedObject.FindProperty(nameof(TeleporterComponent.ToKicker)); + } + + public override void OnInspectorGUI() + { + BeginEditing(); + + OnPreInspectorGUI(); + + PropertyField(_bidirectionalProperty, "Bi-Directional"); + PropertyField(_kickAfterTeleportationProperty, "Kick After Teleport"); + PropertyField(_kickDelayProperty, "Wait Before Kick (s)"); + + PropertyField(_fromKickerProperty); + PropertyField(_toKickerProperty); + + base.OnInspectorGUI(); + + EndEditing(); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs.meta new file mode 100644 index 000000000..77be5481b --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eda12254ad6c8504280d727e59dec3c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs index 86664ba1f..c17c732d2 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs @@ -45,8 +45,8 @@ internal TeleporterApi(GameObject go, Player player) void IApi.OnInit(BallManager ballManager) { _teleporterCoil = new DeviceCoil(OnTeleport); - _portalA = _player.TableApi.Kicker(_teleporterComponent.PortalA); - _portalB = _player.TableApi.Kicker(_teleporterComponent.PortalB); + _portalA = _player.TableApi.Kicker(_teleporterComponent.FromKicker); + _portalB = _player.TableApi.Kicker(_teleporterComponent.ToKicker); Init?.Invoke(this, EventArgs.Empty); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs index c68d0d066..a7dfdb591 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +// ReSharper disable InconsistentNaming + using System.Collections.Generic; using UnityEngine; using VisualPinball.Engine.Game.Engines; @@ -27,11 +29,25 @@ public class TeleporterComponent : MonoBehaviour, ICoilDeviceComponent { #region Data - public KickerComponent PortalA; + [Tooltip("If set, the teleporter also teleports into the opposite direction.")] + public bool Bidirectional; + + [Tooltip("If set, the ball is automatically popped out of the destination kicker upon arrival.")] + public bool KickAfterTeleportation = true; + + [Min(0)] + [Tooltip("The time in seconds between the ball arriving at the destination kicker and being popped out of the kicker.")] + public float KickDelay = 0.5f; - public KickerComponent PortalB; + [Tooltip("The kicker where the ball is teleported from.")] + [TypeRestriction(typeof(KickerComponent), PickerLabel = "Kickers", DeviceItem = nameof(FromKickerItem), DeviceType = typeof(ICoilDeviceComponent))] + public KickerComponent FromKicker; + public string FromKickerItem = string.Empty; - public float TimeMs; + [Tooltip("The kicker where the ball is teleported into.")] + [TypeRestriction(typeof(KickerComponent), PickerLabel = "Kickers", DeviceItem = nameof(ToKickerItem), DeviceType = typeof(ICoilDeviceComponent))] + public KickerComponent ToKicker; + public string ToKickerItem = string.Empty; #endregion From fa1258fcd3cb2e49328076a563ad566984182fa5 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 23 Oct 2021 22:30:12 +0200 Subject: [PATCH 13/25] teleporter: Add kick feature to API. --- .../VPT/Teleporter/TeleporterApi.cs | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs index c17c732d2..527ac1ba5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs @@ -27,26 +27,26 @@ public class TeleporterApi : IApi, IApiCoilDevice { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private readonly TeleporterComponent _teleporterComponent; + private readonly TeleporterComponent _component; private readonly Player _player; private DeviceCoil _teleporterCoil; - private KickerApi _portalA; - private KickerApi _portalB; + private KickerApi _fromKicker; + private KickerApi _toKicker; public event EventHandler Init; internal TeleporterApi(GameObject go, Player player) { - _teleporterComponent = go.GetComponentInChildren(); + _component = go.GetComponentInChildren(); _player = player; } void IApi.OnInit(BallManager ballManager) { _teleporterCoil = new DeviceCoil(OnTeleport); - _portalA = _player.TableApi.Kicker(_teleporterComponent.FromKicker); - _portalB = _player.TableApi.Kicker(_teleporterComponent.ToKicker); + _fromKicker = _player.TableApi.Kicker(_component.FromKicker); + _toKicker = _player.TableApi.Kicker(_component.ToKicker); Init?.Invoke(this, EventArgs.Empty); } @@ -55,22 +55,32 @@ void IApi.OnInit(BallManager ballManager) private void OnTeleport() { - var ballInPortalA = _portalA.HasBall(); - var ballInPortalB = _portalB.HasBall(); + if (_toKicker == null || _fromKicker == null) { + Logger.Warn($"[teleporter {_component.name}] Cannot teleport due to missing kicker configuration."); + return; + } + + var ballInPortalA = _fromKicker.HasBall(); + var ballInPortalB = _toKicker.HasBall(); if (ballInPortalA && ballInPortalB || !ballInPortalA && !ballInPortalB) { // duh, do nothing. return; } if (ballInPortalA) { - var ballData = _portalA.GetBallData(); - _portalA.DestroyBall(); - _portalB.CreateSizedBallWithMass(ballData.Radius, ballData.Mass); + var ballData = _fromKicker.GetBallData(); + _fromKicker.DestroyBall(); + _toKicker.CreateSizedBallWithMass(ballData.Radius, ballData.Mass); + + if (_component.KickAfterTeleportation && !string.IsNullOrEmpty(_component.ToKickerItem)) { + var kickerCoil = (_toKicker as IApiCoilDevice).Coil(_component.ToKickerItem); + kickerCoil.OnCoil(true); + } } else { - var ballData = _portalB.GetBallData(); - _portalB.DestroyBall(); - _portalA.CreateSizedBallWithMass(ballData.Radius, ballData.Mass); + var ballData = _toKicker.GetBallData(); + _toKicker.DestroyBall(); + _fromKicker.CreateSizedBallWithMass(ballData.Radius, ballData.Mass); } } From ab07494eeaa68eb5deb22e64c28911d1749a2398 Mon Sep 17 00:00:00 2001 From: freezy Date: Sat, 23 Oct 2021 22:33:31 +0200 Subject: [PATCH 14/25] kicker: Fix z-position of direction handle. --- .../VPT/Kicker/KickerInspector.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs index 31c158aa5..d05526341 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Kicker/KickerInspector.cs @@ -97,7 +97,10 @@ private void OnSceneGUI() Handles.color = Color.cyan; var transform = MainComponent.transform; - var position = transform.parent.TransformPoint(MainComponent.GetEditorPosition()); + var localPos = MainComponent.GetEditorPosition(); + localPos.z = MainComponent.PositionZ; + + var worldPos = transform.parent.TransformPoint(localPos); foreach (var coil in MainComponent.Coils) { var from = MainComponent.GetBallCreationPosition().ToUnityVector3(); @@ -111,7 +114,7 @@ private void OnSceneGUI() var worldDir = transform.TransformDirection(math.normalize( to - from)); var length = coil.Speed == 0 ? 0.1f : coil.Speed / 10f; - Handles.ArrowHandleCap(-1, position, Quaternion.LookRotation(worldDir), length, EventType.Repaint); + Handles.ArrowHandleCap(-1, worldPos, Quaternion.LookRotation(worldDir), length, EventType.Repaint); } } } From 774722bf263cf609b0641be01a84d38efd6da14d Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 24 Oct 2021 00:04:16 +0200 Subject: [PATCH 15/25] editor: Add camera script. --- .../Game/CameraTranslateAndOrbit.cs | 142 ++++++++++++++++++ .../Game/CameraTranslateAndOrbit.cs.meta | 11 ++ .../Game/DebugBallComponent.cs | 73 +++++++++ .../Game/DebugBallComponent.cs.meta | 11 ++ 4 files changed, 237 insertions(+) create mode 100644 VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs.meta create mode 100644 VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs create mode 100644 VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs.meta diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs new file mode 100644 index 000000000..450e712ac --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs @@ -0,0 +1,142 @@ +using UnityEngine; +using UnityEngine.InputSystem; + +/// +/// A simple camera orbit script that works with Unity's new Input System. +/// +public class CameraTranslateAndOrbit : MonoBehaviour +{ + public float zoomSpeed = 0.1f; + + public Transform transformCache; + public bool isAnimating; + + public GameObject dummyForRotation; + public Transform dummyTransform; + + private float _radius; + private Vector3 _focusPoint; + private float _radiusCurrent = 15f; + private bool _isTrackingMouse0; + private Vector2 _mouse0StartPosition; + + private bool _isTrackingMouse1; + private Vector2 _mouse1StartPosition; + + public Vector3 positionOffset = Vector3.zero; + private Vector3 _positionOffsetCurrent = Vector3.zero; + + private Quaternion _rot2 = Quaternion.identity; + + private const float RadiusMin = 0.5f; + + private void Start() + { + _radius = Vector3.Distance(Vector3.zero, transform.position); + transformCache = transform; + _focusPoint = transformCache.forward * -1f * _radius; + _positionOffsetCurrent = positionOffset; + _radiusCurrent = _radius; + dummyForRotation = new GameObject(); + dummyTransform = dummyForRotation.transform; + + dummyTransform.rotation = transformCache.rotation; + dummyTransform.position = transformCache.position; + _rot2 = transformCache.rotation; + } + + + private void OrbitAroundObject(Vector3 newOffset, float radiusRef) + { + positionOffset = newOffset; + _positionOffsetCurrent = positionOffset; + _radius = radiusRef; + _radiusCurrent = _radius; + } + + + // Update is called once per frame + private void Update() + { + transformCache.position = dummyTransform.position = Vector3.zero; + + var hasHitRestrictedHitArea = false; + if (Mouse.current == null) { + return; + } + + if (Mouse.current.leftButton.wasPressedThisFrame) { + _mouse0StartPosition = Mouse.current.position.ReadValue(); + _isTrackingMouse0 = true; + } + + if (_mouse0StartPosition.x < 200f && _mouse0StartPosition.y > Screen.height - 200f) { + hasHitRestrictedHitArea = true; + } + + if (!hasHitRestrictedHitArea) { + if (_isTrackingMouse0) { + Vector3 mousePositionDifference = Mouse.current.position.ReadValue() - _mouse0StartPosition; + dummyTransform.Rotate(Vector3.up, mousePositionDifference.x * 0.4f, Space.World); + + dummyTransform.Rotate(dummyTransform.right.normalized, mousePositionDifference.y * -0.4f, + Space.World); + _rot2 = dummyTransform.rotation; + _mouse0StartPosition = Mouse.current.position.ReadValue(); + } + transformCache.rotation = Quaternion.Lerp(transformCache.rotation, _rot2, Time.deltaTime * 4f); + } + + + if (Mouse.current.leftButton.wasReleasedThisFrame) { + _isTrackingMouse0 = false; + } + + + if (Mouse.current.rightButton.wasPressedThisFrame) { + _mouse1StartPosition = Mouse.current.position.ReadValue(); + _isTrackingMouse1 = true; + } + + if (!hasHitRestrictedHitArea) { + if (_isTrackingMouse1) { + var mousePositionDifference = Mouse.current.position.ReadValue() - _mouse1StartPosition; + //Vector3 XZPlanerDirection = transformCache.forward.normalized; + //XZPlanerDirection.y = 0; + + positionOffset += transformCache.up.normalized * (mousePositionDifference.y * -(_radius / 2f / 100f)); + + positionOffset += transformCache.right.normalized * + (mousePositionDifference.x * -(_radius / 2f / 100f)); + /* + if(positionOffset.y < 0){ + positionOffset.y = 0; + }*/ + + _mouse1StartPosition = Mouse.current.position.ReadValue(); + } + } + + if (Mouse.current.rightButton.wasReleasedThisFrame) { + _isTrackingMouse1 = false; + } + + if (!hasHitRestrictedHitArea) { + if (!isAnimating) { + var delta = Mouse.current.scroll.y.ReadValue() / 1000f * zoomSpeed * -_radius; + _radius += delta; + if (_radius < RadiusMin) { + var radDiff = RadiusMin - _radius; + positionOffset += transformCache.forward * (radDiff * 4f); + _radius = RadiusMin; + } + } + } + + _positionOffsetCurrent = Vector3.Lerp(_positionOffsetCurrent, positionOffset, Time.deltaTime * 4f); + _radiusCurrent = Mathf.Lerp(_radiusCurrent, _radius, Time.deltaTime * 4f); + _focusPoint = transformCache.forward * -1f * _radiusCurrent; + transformCache.position = _focusPoint + _positionOffsetCurrent; + dummyTransform.position = transformCache.position; + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs.meta new file mode 100644 index 000000000..d24c39a80 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/CameraTranslateAndOrbit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2bbdee04830a45449bbceaa234a2a2b6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs new file mode 100644 index 000000000..be938401a --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs @@ -0,0 +1,73 @@ +// 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 Unity.Mathematics; +using UnityEditor; +using UnityEngine; +using UnityEngine.InputSystem; + +namespace VisualPinball.Unity +{ + [ExecuteAlways] + public class DebugBallComponent : MonoBehaviour + { + + private PlayfieldComponent _playfield; + + private void Awake() + { + _playfield = GetComponentInChildren(); + } + + private void Update() + { + if (Camera.main == null || _playfield == null) { + return; + } + + if (Mouse.current.middleButton.wasPressedThisFrame) { + var mouseOnScreenPos = Mouse.current.position.ReadValue(); + var ray = Camera.main.ScreenPointToRay(mouseOnScreenPos); + + Debug.Log($"Ray = {ray.origin} -> {ray.direction} ({mouseOnScreenPos})"); + + // if (Physics.Raycast(ray, out var hit, 100)) { + // Debug.Log($"Got a hit: {hit.transform.gameObject.name}"); + // } else { + // Debug.Log($"Not hit."); + // } + } + } + + private void OnDrawGizmos() + { + var ltw = _playfield.transform.localToWorldMatrix; + var origin = ltw.MultiplyPoint(Vector3.zero); + var up = ltw.MultiplyPoint(new Vector3(0, 0, 500f)); + var normal = up - origin; + normal.Normalize(); + + var cameraWorld = SceneView.lastActiveSceneView.camera.transform.position; + + //var plane = new Plane(Vector3.forward, m_DistanceFromCamera); + + Ray ray = SceneView.lastActiveSceneView.camera.ScreenPointToRay(Event.current.mousePosition); + + Gizmos.DrawLine(Vector3.zero, normal); + } + } +} diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs.meta new file mode 100644 index 000000000..d9e82ff95 --- /dev/null +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57cf09880101f8a40afd18dcf469b554 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From fc04ecd23593f88f4c1119863e39ea0c59ced5aa Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 24 Oct 2021 01:13:57 +0200 Subject: [PATCH 16/25] editor: Fiddle with ray projection. --- .../Game/DebugBallComponent.cs | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs index be938401a..becfa0293 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs @@ -15,6 +15,8 @@ // along with this program. If not, see . using System; +using Codice.CM.Common.Merge; +using NLog.LayoutRenderers.Wrappers; using Unity.Mathematics; using UnityEditor; using UnityEngine; @@ -55,19 +57,30 @@ private void Update() private void OnDrawGizmos() { - var ltw = _playfield.transform.localToWorldMatrix; - var origin = ltw.MultiplyPoint(Vector3.zero); - var up = ltw.MultiplyPoint(new Vector3(0, 0, 500f)); - var normal = up - origin; - normal.Normalize(); - var cameraWorld = SceneView.lastActiveSceneView.camera.transform.position; + var playfieldTransform = _playfield.transform; + var ltw = playfieldTransform.localToWorldMatrix; + var wtl = playfieldTransform.worldToLocalMatrix; - //var plane = new Plane(Vector3.forward, m_DistanceFromCamera); + var z = _playfield.PlayfieldHeight; + var p1 = ltw.MultiplyPoint(new Vector3(-100f, 100f, z)); + var p2 = ltw.MultiplyPoint(new Vector3(100f, 100f, z)); + var p3 = ltw.MultiplyPoint(new Vector3(100f, -100f, z)); - Ray ray = SceneView.lastActiveSceneView.camera.ScreenPointToRay(Event.current.mousePosition); + Gizmos.DrawLine(p1, p2); + Gizmos.DrawLine(p2, p3); + Gizmos.DrawLine(p3, p1); - Gizmos.DrawLine(Vector3.zero, normal); + var planeWorld = new Plane(); + planeWorld.Set3Points(p1, p2, p3); + + var ray = SceneView.lastActiveSceneView.camera.ScreenPointToRay(Event.current.mousePosition); + if (planeWorld.Raycast(ray, out var enter)) { + var playfieldPosWorld = ray.GetPoint(enter); + var playfieldPosLocal = wtl.MultiplyPoint(playfieldPosWorld); + + Debug.Log($"Position on playfield: {playfieldPosLocal}"); + } } } } From 7b46632851590470743a31939b4c354f44513669 Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 24 Oct 2021 20:56:10 +0200 Subject: [PATCH 17/25] editor: Fix ray caster. --- .../Game/DebugBallComponent.cs | 66 ++++++++----------- 1 file changed, 27 insertions(+), 39 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs index becfa0293..8eb6701bd 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs @@ -14,25 +14,36 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using System; -using Codice.CM.Common.Merge; -using NLog.LayoutRenderers.Wrappers; -using Unity.Mathematics; using UnityEditor; using UnityEngine; using UnityEngine.InputSystem; namespace VisualPinball.Unity { - [ExecuteAlways] public class DebugBallComponent : MonoBehaviour { private PlayfieldComponent _playfield; + private Matrix4x4 _ltw; + private Matrix4x4 _wtl; + + private Plane _playfieldPlane; + private GameObject _ball; private void Awake() { _playfield = GetComponentInChildren(); + _ball = _playfield.transform.Find("Ball").gameObject; + + var playfieldTransform = _playfield.transform; + _ltw = playfieldTransform.localToWorldMatrix; + _wtl = playfieldTransform.worldToLocalMatrix; + + var z = _playfield.PlayfieldHeight; + var p1 = _ltw.MultiplyPoint(new Vector3(-100f, 100f, z)); + var p2 = _ltw.MultiplyPoint(new Vector3(100f, 100f, z)); + var p3 = _ltw.MultiplyPoint(new Vector3(100f, -100f, z)); + _playfieldPlane.Set3Points(p1, p2, p3); } private void Update() @@ -41,45 +52,22 @@ private void Update() return; } - if (Mouse.current.middleButton.wasPressedThisFrame) { + if (Mouse.current.middleButton.isPressed) { var mouseOnScreenPos = Mouse.current.position.ReadValue(); var ray = Camera.main.ScreenPointToRay(mouseOnScreenPos); - Debug.Log($"Ray = {ray.origin} -> {ray.direction} ({mouseOnScreenPos})"); - - // if (Physics.Raycast(ray, out var hit, 100)) { - // Debug.Log($"Got a hit: {hit.transform.gameObject.name}"); - // } else { - // Debug.Log($"Not hit."); - // } - } - } - - private void OnDrawGizmos() - { - - var playfieldTransform = _playfield.transform; - var ltw = playfieldTransform.localToWorldMatrix; - var wtl = playfieldTransform.worldToLocalMatrix; - - var z = _playfield.PlayfieldHeight; - var p1 = ltw.MultiplyPoint(new Vector3(-100f, 100f, z)); - var p2 = ltw.MultiplyPoint(new Vector3(100f, 100f, z)); - var p3 = ltw.MultiplyPoint(new Vector3(100f, -100f, z)); - - Gizmos.DrawLine(p1, p2); - Gizmos.DrawLine(p2, p3); - Gizmos.DrawLine(p3, p1); - - var planeWorld = new Plane(); - planeWorld.Set3Points(p1, p2, p3); + if (_playfieldPlane.Raycast(ray, out var enter)) { + var playfieldPosWorld = ray.GetPoint(enter); + var playfieldPosLocal = _wtl.MultiplyPoint(playfieldPosWorld); - var ray = SceneView.lastActiveSceneView.camera.ScreenPointToRay(Event.current.mousePosition); - if (planeWorld.Raycast(ray, out var enter)) { - var playfieldPosWorld = ray.GetPoint(enter); - var playfieldPosLocal = wtl.MultiplyPoint(playfieldPosWorld); + var ballPosLocal = _ball.transform.localPosition; + ballPosLocal.x = playfieldPosLocal.x; + ballPosLocal.y = playfieldPosLocal.y; + _ball.transform.localPosition = ballPosLocal; - Debug.Log($"Position on playfield: {playfieldPosLocal}"); + } else { + Debug.Log($"Missed."); + } } } } From 5a5462764ec6cdf921c140e6f3474a9dcbcb3016 Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 24 Oct 2021 21:41:59 +0200 Subject: [PATCH 18/25] debug: Manual ball roller working! --- .../Game/DebugBallComponent.cs | 90 +++++++++++++++---- .../VisualPinball.Unity/VPT/Ball/BallData.cs | 3 + .../VPT/Ball/BallVelocitySystem.cs | 11 ++- 3 files changed, 87 insertions(+), 17 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs index 8eb6701bd..3aed3f0fd 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs @@ -14,7 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using UnityEditor; +using Unity.Collections; +using Unity.Entities; +using Unity.Mathematics; using UnityEngine; using UnityEngine.InputSystem; @@ -28,12 +30,14 @@ public class DebugBallComponent : MonoBehaviour private Matrix4x4 _wtl; private Plane _playfieldPlane; - private GameObject _ball; + + private EntityManager _entityManager; + private Entity _ballEntity; + private EntityQuery _ballEntityQuery; private void Awake() { _playfield = GetComponentInChildren(); - _ball = _playfield.transform.Find("Ball").gameObject; var playfieldTransform = _playfield.transform; _ltw = playfieldTransform.localToWorldMatrix; @@ -44,6 +48,9 @@ private void Awake() var p2 = _ltw.MultiplyPoint(new Vector3(100f, 100f, z)); var p3 = _ltw.MultiplyPoint(new Vector3(100f, -100f, z)); _playfieldPlane.Set3Points(p1, p2, p3); + + _entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; + _ballEntityQuery = _entityManager.CreateEntityQuery(typeof(BallData)); } private void Update() @@ -52,23 +59,74 @@ private void Update() return; } - if (Mouse.current.middleButton.isPressed) { - var mouseOnScreenPos = Mouse.current.position.ReadValue(); - var ray = Camera.main.ScreenPointToRay(mouseOnScreenPos); - - if (_playfieldPlane.Raycast(ray, out var enter)) { - var playfieldPosWorld = ray.GetPoint(enter); - var playfieldPosLocal = _wtl.MultiplyPoint(playfieldPosWorld); + // find nearest ball + if (Mouse.current.middleButton.wasPressedThisFrame) { + if (GetCursorPositionOnPlayfield(out var mousePosition)) { + var ballEntities = _ballEntityQuery.ToEntityArray(Allocator.Temp); + var nearestDistance = float.PositiveInfinity; + BallData nearestBall = default; + var ballFound = false; + foreach (var ballEntity in ballEntities) { + var ballData = _entityManager.GetComponentData(ballEntity); + if (ballData.IsFrozen) { + continue; + } + var distance = math.distance(mousePosition, ballData.Position.xy); + if (distance < nearestDistance) { + nearestDistance = distance; + nearestBall = ballData; + ballFound = true; + _ballEntity = ballEntity; + } + } - var ballPosLocal = _ball.transform.localPosition; - ballPosLocal.x = playfieldPosLocal.x; - ballPosLocal.y = playfieldPosLocal.y; - _ball.transform.localPosition = ballPosLocal; + if (ballFound) { + UpdateBall(ref nearestBall, mousePosition); + } + } - } else { - Debug.Log($"Missed."); + } else if (Mouse.current.middleButton.isPressed) { + if (GetCursorPositionOnPlayfield(out var mousePosition)) { + var ballData = _entityManager.GetComponentData(_ballEntity); + UpdateBall(ref ballData, mousePosition); } } + + if (Mouse.current.middleButton.wasReleasedThisFrame) { + var ballData = _entityManager.GetComponentData(_ballEntity); + ballData.ManualControl = false; + _entityManager.SetComponentData(_ballEntity, ballData); + } + } + + private void UpdateBall(ref BallData ballData, float2 position) + { + ballData.ManualControl = true; + ballData.ManualPosition = position; + _entityManager.SetComponentData(_ballEntity, ballData); + } + + private bool GetCursorPositionOnPlayfield(out float2 position) + { + if (Camera.main == null) { + position = float2.zero; + return false; + } + + var mouseOnScreenPos = Mouse.current.position.ReadValue(); + var ray = Camera.main.ScreenPointToRay(mouseOnScreenPos); + + if (_playfieldPlane.Raycast(ray, out var enter)) { + var playfieldPosWorld = ray.GetPoint(enter); + var playfieldPosLocal = _wtl.MultiplyPoint(playfieldPosWorld); + + position = new float2(playfieldPosLocal.x, playfieldPosLocal.y); + + // todo check playfield bounds + return true; + } + position = float2.zero; + return false; } } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallData.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallData.cs index 66a8f476f..89890b652 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallData.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallData.cs @@ -34,6 +34,9 @@ internal struct BallData : IComponentData public bool IsFrozen; public int RingCounterOldPos; + public bool ManualControl; + public float2 ManualPosition; + public float3 OldVelocity; public Aabb Aabb { diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallVelocitySystem.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallVelocitySystem.cs index 774330782..86d5448b9 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallVelocitySystem.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallVelocitySystem.cs @@ -47,7 +47,16 @@ protected override void OnUpdate() marker.Begin(); - ball.Velocity += gravity * (float)PhysicsConstants.PhysFactor; + if (ball.ManualControl) { + ball.Velocity *= 0.5f; // Null out most of the X/Y velocity, want a little bit so the ball can sort of find its way out of obstacles. + ball.Velocity += new float3( + math.max(-10.0f, math.min(10.0f, (ball.ManualPosition.x - ball.Position.x) * (float)(1.0/10.0))), + math.max(-10.0f, math.min(10.0f, (ball.ManualPosition.y - ball.Position.y) * (float)(1.0/10.0))), + -2.0f + ); + } else { + ball.Velocity += gravity * (float)PhysicsConstants.PhysFactor; + } marker.End(); From c1ba0ac39e7dad7806601b7c99d9d3f9f51b9ee9 Mon Sep 17 00:00:00 2001 From: freezy Date: Sun, 24 Oct 2021 23:46:16 +0200 Subject: [PATCH 19/25] editor: Update icons and add ball roller to table during import. --- .../Editor/Icons/large_blue/ball_roller.png | Bin 0 -> 6143 bytes .../Icons/large_blue/ball_roller.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/large_blue/teleporter.png | Bin 14079 -> 7475 bytes .../Editor/Icons/large_gray/ball_roller.png | Bin 0 -> 6171 bytes .../Icons/large_gray/ball_roller.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/large_gray/teleporter.png | Bin 14115 -> 7495 bytes .../Editor/Icons/large_green/ball_roller.png | Bin 0 -> 6155 bytes .../Icons/large_green/ball_roller.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/large_green/teleporter.png | Bin 14093 -> 7496 bytes .../Editor/Icons/large_orange/ball_roller.png | Bin 0 -> 6158 bytes .../Icons/large_orange/ball_roller.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/large_orange/teleporter.png | Bin 14107 -> 7500 bytes .../Editor/Icons/small_blue/ball_roller.png | Bin 0 -> 528 bytes .../Icons/small_blue/ball_roller.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/small_blue/teleporter.png | Bin 994 -> 592 bytes .../Editor/Icons/small_gray/ball_roller.png | Bin 0 -> 533 bytes .../Icons/small_gray/ball_roller.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/small_gray/teleporter.png | Bin 1000 -> 620 bytes .../Editor/Icons/small_green/ball_roller.png | Bin 0 -> 531 bytes .../Icons/small_green/ball_roller.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/small_green/teleporter.png | Bin 992 -> 598 bytes .../Editor/Icons/small_orange/ball_roller.png | Bin 0 -> 534 bytes .../Icons/small_orange/ball_roller.png.meta | 108 ++++++++++++++++++ .../Editor/Icons/small_orange/teleporter.png | Bin 999 -> 601 bytes .../Import/VpxSceneConverter.cs | 1 + .../VisualPinball.Unity.Editor/Utils/Icons.cs | 44 +++---- ...allComponent.cs => BallRollerComponent.cs} | 3 +- ...nt.cs.meta => BallRollerComponent.cs.meta} | 4 +- 28 files changed, 887 insertions(+), 29 deletions(-) create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_gray/ball_roller.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_gray/ball_roller.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_orange/ball_roller.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/large_orange/ball_roller.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_blue/ball_roller.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_blue/ball_roller.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png.meta create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_orange/ball_roller.png create mode 100644 VisualPinball.Unity/Assets/Editor/Icons/small_orange/ball_roller.png.meta rename VisualPinball.Unity/VisualPinball.Unity/Game/{DebugBallComponent.cs => BallRollerComponent.cs} (95%) rename VisualPinball.Unity/VisualPinball.Unity/Game/{DebugBallComponent.cs.meta => BallRollerComponent.cs.meta} (61%) diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png new file mode 100644 index 0000000000000000000000000000000000000000..da9b4ab3abd46fe01d282d4df7b64d123abd31eb GIT binary patch literal 6143 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 literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png.meta new file mode 100644 index 000000000..8e44f72f4 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 5a048f1cf2c31c142866a8c295b2b50d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 1 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/large_blue/teleporter.png index 5c92a93277c4605ec77ee166ed9ddb36e1d0529a..be843ffa69b1a310fa1cfe14d0c2cd9972e04b1e 100644 GIT binary patch literal 7475 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 BWhVdt diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_orange/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/large_orange/ball_roller.png new file mode 100644 index 0000000000000000000000000000000000000000..1bd7082d863b6702c8908fc0100fa9c5e6c3e8c3 GIT binary patch literal 6158 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 literal 14107 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 SajD7x0000{;j;T+QBLDA9 z=fs0V?iuRN+(=H3z8x=o|~tqA%Ha4>4}scFjRHD8N=@+#oXt2?^}YK zS)gq4El=%$vVZ%YjPGTP6-Up?*o+RkV6cp@KF6D>?hurd-rb%X(WA zZI>qtjxe=%FL2ZznIEVA6SwEwIo`Hnn`bLR_rl1!fE3KQl9ZfouBV=o8 zBSt%igw3L)bPvD_7wv>Ix2%OLl45f-cb6<(L;e9JrGH;J0eY6XCFHVc_WJ4o%J1AR zud^9Ru?P*ii&3_u>pS;=lpZ?FYgK|{vhK#Oye=FlCr;f>tAq=h4*S|Fr-B002ovPDHLkV1j=H2*UsX delta 952 zcmV;p14sPO1mXvfIDZ3_Nklo2^|B$Vc4HalIg- zk17r(CxX;)tcVP-9U{6{aWLR^rs)}GOhg)bs3D2yhsvw#Q-EU5f{5N>K0WV}h(17Z z+n@l6h^SO?FvKb!vBF>41==Q5c{PB=J`>R&B6=dC5Wpl{a7&}CF$L%g+g8d?j5Hd*>&gC!(1x(N$4bYyhoo!Mbiv>*(VScXav0i2+E_t`)q5ld|Y zzeExdj!fyRIIx0-xMmi!uLPl@Y!S4B`D}{eXLEK7Q-7mA2|XH@3)<_)B0er0b4TL+ zY7cD%e3;h-&Ci{nfc&ZQDsAY?nPnr{q-!fmLQjW%IiEGv(-11JhQ7v#F!pz~*4Oj3 zT0J47-5~5}P2D=Q+ow$|Z6plZYtWb{^A4`!V1za^F?QzgU7z)~WT(vA16r_8!8Fzg z0ZGv(LVq9aySio=c>1&gYKn&Zc3_|PSnQoBBOA#vpoK86OA=#O&!N$SQ!#^= zR5;dRT2$=P_s6J=7Djb;5NOc=lvCQ$yMTHpPXvfo!r<7?nM1-8$Gptd0CDq4Kx!=} z9>}7>e7m49nXhxxaH6$%rQ@n2sIS0P960AfQGc@YDZ+y#9#B_amV=M*jpftgrhUVb zQIEx-(wwfemRZ``2A%j)qcKO<5vEGihp0zrkLLX<#aeidSvs@V1~$*GG8LF%nZ3- zp28?Vc5pbc67!IZ&GB7)$Nwgx2b{3AdQu_|>vT2lX=Cefk#-9-nxW1^4 z^n%t9I?dj~YN3D}%cQaMX9L2*R1_)qa50CY diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png new file mode 100644 index 0000000000000000000000000000000000000000..cc423caac466867bbe3dc1ae0b7ea94dc7e679f3 GIT binary patch literal 533 zcmV+w0_y#VP)l*K-hq6P&UX0K?fIPRf+$_c9bfg)Tb(^U(fdUozsiDu3-$i90lbB8bA}MZ(W(x z%ehzpzzzV`05FrjdIx|5OOvfLebJ&;$vvc3+(Ji%U8YP)%)d60gBp6 z``Ajc4gWdk!l|o6B-5h{>`)PE4LfAkBP`mN(GWBAP_iVi)xsKG?mP--fg_cZ?QO0b zW@3Y4fVd3gQI`IdK0r5swM&uEpqNG&pYjRcxD*Nr`X8ATx6L5Fr1Y{<2+*n{*X8K6 z9#W#d$j!N^q$~Ih&Adj6?W1y6t@dhcP_)O!zX(xY+tBNe>V8m1nOJk00n>_ XO1+h!Qsnrf00000NkvXXu0mjfQn&Nk literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png.meta new file mode 100644 index 000000000..ef9537a87 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 3dcb1474894669c41ada07e2c9b6395b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_gray/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/small_gray/teleporter.png index 0c75d225a480192e28f16d2ae91b4c8f38033b14..9b92087d07264b00ae8583eb6df47876603c8961 100644 GIT binary patch delta 575 zcmV-F0>J&~2kZopIDY~jNkl3`{4s4}cx27Ad7#O>iBQRL9H|P!M z4d@Lx0^MxM14m$F=s=~mV$2a>W2i(G^aZ)pK;k40NPVS9A-0o;@7F$CtyU;YQt29i zHh{oD2my=)XLA#)G*GE@4?rKlrDb>lU?4c_#}7&Yl}Zl*bbk^|eHEN_qnk?cSieP< zOad9HBb8oT)w@Nd((@he-lr?C7L`i39UvoheY?Kty3TuyIx097(9k#N)OFpdWc_U! zuJ0$9W9mh47XEjpeWH&)Q%|>PL6+>sV_qyOl@6$e&IM;<BrWAm+NQEZkDIwG(sT{Vg~Q}0o)VAVVWg%LlbVQsQj(pJx3m1#}N24A*B$BxD6W z02ynM)$PdAnG!blci|LKcG_S2TFjd zWo`sH$(p^c+JMrTJIQf&DmWYY23^M}Su*LFyD61!C7741&g*xL$ju^U-@pF&{CaCN z?!SG3Rw!|7F}Y81!g*7LvfD+j>ztIOjs^+l90h2YBga8isF=IRb)7TljEZ?0Eoq%U zP-=^5yEx5cyPX!Tb&LwmCMmXJ(=ys<+Fn1VKjmGAc2BXayC-h~@B@_S=wg$!=m!7* N002ovPDHLkV1ku7384T0 delta 958 zcmV;v13~=k1n38lIDZ40Nkl>s0hXCc6a{zBSo*8!q z;5`ku2}+O%z#>bN9%p&S8U8XMP&eUlH15)4p8)&;a1WqKV5kt>u&7w9Pv{eV{|w-Z znZyCCYCvuPe1D|7%V!KTW7YO>G;aAoC+cs}DPy)aP{w9NPw9T!TwD`=@2o*dZDusf z(qt(=T9a^1U>}{+YE5NLQAaJX7|NpSv_R;{YA7qSA+D%F0uwvBikShtpl0>CKq8e( zT^&D1u}Vj_I$4@HL7V(69BwbgRI#WLw88OQhLLA834aUQq9HW{7S|JcGLBV#TzbZi z)bHgQ+DQ0xuMb+DdqD~Lb2u936=S(@EF_m&uA-zFXzh~a453%$$?;}osF z9;5$>*cj1ZMkoPvURpvbbI+vKD zYn&N^%757=VjB~?re^2{+SCGS%RqkJvCTV9_PZ)0D`_9lxpJ>hv9+pawCK)Tv4Acd z+h$O#aGb@os@QexU$HV;TGiQ3pz{i#vZbv;FL5PbD-dIZ?!L#FUDA`}yu$Ya^X9#R zG**lQkn;-TZG+Nfp~h9yiLv6D$*Z2EUV>+7;(r~BMakAtL^_KDpuT-scRt`5D`dsB zs+NqVFNx8DsROpjl?tv_uj|=qmD8$>(PAdB7uG`kUdpy;CjcTA_3qDArE1NVr$6y( zB>7fAbwi))=cjEtT9@Le8z6RyWEMtWMZqHIW zU4MjD>W<2}A^df;%avgsLG=SJ7#s9jokZ)B^mS_O`||fW9*g-6P+6@#u3T~dlx~Q8 zTjp~_&rG@Z>sy#UAsf7$C}m%gi95cjbNp`rx4dDi^`=B!%3Y|(6Lmy6b6FI;^I5Tc zlVij!Kc7`chC~Rn&0f-LO$B+SH;t`-Ha9RWOjMC_!*JL;fBM84p~o>-yp#3ckN(ek gxx=qp#{ml9AGE1ZVOGO8YybcN07*qoM6N<$g49{lApigX diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png new file mode 100644 index 0000000000000000000000000000000000000000..3bd86bb30fe7d5a376fc44bf423009d607e093a1 GIT binary patch literal 531 zcmV+u0_^>XP)e%zJB5=cB{UTG;$N z#9tXtJ$31h^88d4rO~P<=Mi=v0@nG?MA5q7OmrT$LT1?6_l~d5ir3(mI}IpmtL$SZ zr8fMhLS|lF9U_??d|-!)P-oa7vmRm5zO06rp@)(sd94xF>T(xQI13!9oN8}#(=d}7 z6a&O(AWyRNFZ2Pr0jzzB#0JGQ!uV8A_{OJDOwhl`q_}Md@g=2~lVX6@J-Mz%r}L1K z^hItVvs$@=U(?KMrPMyEcGYRGrUq5FgVQB2`8#~Fr_%L>+Vp2bXicD@H4ab!_y#wn VmDJETG4=oe002ovPDHLkV1k1i>?QyJ literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png.meta new file mode 100644 index 000000000..014c48b35 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_green/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 07cd7e11b2f26e847b8c55e0598d135d +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_green/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/small_green/teleporter.png index 4063c96f8f3c1c1f26def344745d77fca5fc6d11..54cacbc1750e7cb23563dede65b1915dffffc79e 100644 GIT binary patch delta 553 zcmV+^0@nTD2i63TIDY~NNkl3_k9oX8Qpy}3;k*%D-V)g>P0lfje z0Y{*VXXF!PWK1{493gB>rb_e$xzs@77#pO%Ql#LY_~G;SW8dv|JH(RG;t{|IKw==| z0G6D|!o-ROs>VCWZTa(`03u*+lp7Fn_hWT~;z zqOxjmiz+ROBinsSPeCoJv=})+mYRg#`o8PD;6Cc8z$+!~gd(@hg=@~__F!xkEPt1V`~#}A7*GK8EMrT^RoCcs z)gF}Y+)b{t8E0}C8np6JvSiaccVB5SY%tEN82Mz|g$Fb*94G}&+ePbu3noUrTtPacRrB(STXL8lzD3--2 rqit(_N+N$MxXzuPYFSTD!35w3y#?nxOO@;S00000NkvXXu0mjf&WI8S delta 950 zcmV;n14;bW1mFjdIDZ3@Nklk6vkhz?(q%G4Pxa0ggE3VNgSI-b;%BsDzjJr0_x%iuPiI{B-6tNk=Q*zuMHrE{A`&&>@s}(IH zFIn@C+9FH~I7S0l%@@{W^~DAYNmz87762V+9eHPV*cB~^VM4=DAu@m!RP8W@TOZafF4Vs@@K>_(QE#s_VEa!%eWK!2ul=zMg`_6o}R8K*qWjt~`Y9?%uX6kKD> z5Kx9b0e||a*i|*d(9x$AP+bc0+kt)FW3jiQjBKQ1Kv%-OHig=*Uc#aWAH@t>7>-S+ zP~jMhX;HDu*q@>@T5HwWL7=M!pnRllT#c}kX97eSVR-E8%pvKCb6#$1fV}xAAe9wE z2jr^3e7m44p7^t$_F^!bkLc26KzX8)}^+g`0oKd7xOhxJ`P7X9@+g1xFN6|nJ*DMv%uLe zZ(+uO?BH^ul730X?)Wa=<9`#;J#N@qy(tlwa@XSVT)d)OnJh}U^Vy($lT zbO{jZn7x75d;vL?hsMr78;};}qDZ+zI4>NXKW##dFv6T0+{xPSNB?KN-r={c^8h8H Ye`>fF^R+fh({si!JWU!U#&e@-u|s)8}-auk#kXaG&1zID~5 zo)l~W06PF!1HerA>J0!63D1wAL5=n#1xo>7Z>WR7X~Of;E1e?k(szVJJpe$^uC{iR zmizN;sZDxHczy^0s_W>+5)!rR$5^)C#+aI6`` zqI95{L%lBq4Y5ykpf3*f@ENqV%r|T+Xu|Uo`l3axBH?-c<7U2LwTFq!d)uMTM}wW! zuxUTUUl~t5b?Kh+{9Fa4(W)iq5q9qb*80vw(Yi=@-gwxgVA$FBhOc_XtM|*D1{Aeb z_OX>>8~(Et%&DtGB-5h{>`)PE4LfAkBP`liry*wOp=3#3YlQ7|x$`KT1x{2>wYRxx zn28OF0pc={M_Kw;`T*Sk)-FXtgJK$Ce5xmW<5DOj=wD<~+}4BmlG4jcAwbKPTvwyh zdPs@-B3BAlDp&9unt3}ZwvVb^wc4w(LDlVGbqS3A4xj8Pvwfj9{n_AK6R2;E0~7$h Y0TuL=Y$7O4_W%F@07*qoM6N<$f+m{sod5s; literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/ball_roller.png.meta new file mode 100644 index 000000000..20716c40d --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: 41211858d62e7904ab09fc592d292bba +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/small_orange/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/small_orange/teleporter.png index 2aa623527f61f638f4c050eb19de5a911bc73ced..161aabda98242270d5763c3c180f110e65ad0c9f 100644 GIT binary patch delta 556 zcmV+{0@MBH2iXLWIDY~QNkl3`X4s31Z12o+_GBUXwfg3 z@XitF4LCyNi80+6a{)_XW1~v+1-aBf;y4aSeWggjKk>uo@5jE|@Av3RTJlE#V*rtX zkOEjSp)wPzGf*x048R<~gQa^5V8Mi%mkphOYRQ)XCKZN$F@K?^`Ae^TtluI_R)Nel z(UKQd4Q^2_d3IvE&*>?sMYZH(2gqF0&|5!nofq6k9TnXQXc`(cah-Q7QUB7#*3T=9 zG4;uWO8+a)gSEPqfoxuz#SptOC@#_!z6vZJ=#H#-Mi5m-XcBl(-D?06hVj8h+Y6s11?==WzZs^JgcZXCPs0eWO4^Q_u^LrM6AC z9Zf1zMM!V*;iIiX!e&t|c^|+lCGChJH_wF|Ce-d|Y=03fZA1P6)shb>0Q#1(Ipn%& z^t$Q*N_Xxm*V%*#wF(Vd_$XPj>YaO_B_CB7=T$xO$+`;QORxk?TBX&sFifaXD>Ug^x0!)-{e| uNf%|bZY8ac=}!gMrPEU>>**<&0Q>-|Bj$&j_15eF0000P z9;u}Z)=75VH90}4vaT}B1u|Tqf&(DI2~v6VKk_iPGlW4ZQvMBL7~7xUdwza)-aI}& z;u!SyC@5b+51^v~eP=&djM5%}A-^sGTt!)t9};3QO4}SW;eVq%%8H?WXJge9@}6I( z{5%2hG0KXY13?-%F+@q&7J%C*EBf-D?RtT^24J8E1`@!}#V9>L1SrRx0Z2KX8FvNX z0}ZzcN{|@9Jj#jzXL-*V{x%`dG~r^D_UWK-0KS?@ z9KfmuL+t5~-_YCMvVv4SD zW(X>0n}3*XOzfJPp&w||2&gRs`EAEG?>X5Ys*J3qeL!c*y*?$@s-DuKJ8#7TI(KZF zL9xPd7SpO?*Rg-i%4lg-XFGw;YJkd?whFz(m3*T>j1l_#9%pt*Pm=RW-wVu}4+_#) zF$qAxgC|70`D-3XZmeT1w zw0}}}RL%|IucKYA4D$r4A8^6gpf~Cy+LWZPQ)}Oszt8bh%x{3oY8`Opiu)&YL+sl! zUm|*D!o6SL!VC%7;^jmo`;tuD@m-zc{{Xn-4O^o(CF)Y{LOmX components) { // add the player script and default game engine _tableGo.AddComponent(); + _tableGo.AddComponent(); var dga = _tableGo.AddComponent(); // populate hardware diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs index 2c5ce4361..505b7a28f 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Utils/Icons.cs @@ -36,6 +36,7 @@ public IconVariant(string name, IconSize size, IconColor color) } } + private const string BallRollerName = "ball_roller"; private const string BumperName = "bumper"; private const string BoltName = "bolt"; private const string CoilName = "coil"; @@ -66,9 +67,9 @@ public IconVariant(string name, IconSize size, IconColor color) private const string SwitchNoName = "switch_no"; private static readonly string[] Names = { - BumperName, BoltName, CoilName, DropTargetName, DropTargetBankName, FlasherName, FlipperName, HitTargetName, GateName, KeyName, KickerName, LightGroupName, - LightName, PlayfieldName, PlungerName, PlugName, PrimitiveName, RampName, RubberName, SpinnerName, SurfaceName, TableName, TriggerName, TeleporterName, - TroughName, SlingshotName, SwitchNcName, SwitchNoName + BallRollerName, BumperName, BoltName, CoilName, DropTargetName, DropTargetBankName, FlasherName, FlipperName, HitTargetName, GateName, KeyName, + KickerName, LightGroupName, LightName, PlayfieldName, PlungerName, PlugName, PrimitiveName, RampName, RubberName, SpinnerName, SurfaceName, + TableName, TeleporterName, TriggerName, TroughName, SlingshotName, SwitchNcName, SwitchNoName }; private readonly Dictionary _icons = new Dictionary(); @@ -86,16 +87,12 @@ public IconVariant(string name, IconSize size, IconColor color) private Icons() { const string iconPath = "Packages/org.visualpinball.engine.unity/VisualPinball.Unity/Assets/Editor/Icons"; - foreach (var name in Names) - { - foreach (var size in Enum.GetValues(typeof(IconSize)).Cast()) - { - foreach (var color in Enum.GetValues(typeof(IconColor)).Cast()) - { + foreach (var name in Names) { + foreach (var size in Enum.GetValues(typeof(IconSize)).Cast()) { + foreach (var color in Enum.GetValues(typeof(IconColor)).Cast()) { var variant = new IconVariant(name, size, color); var path = $"{iconPath}/{size.ToString().ToLower()}_{color.ToString().ToLower()}/{name}.png"; - if (File.Exists(path)) - { + if (File.Exists(path)) { _icons[variant] = AssetDatabase.LoadAssetAtPath(path); } } @@ -103,6 +100,7 @@ private Icons() } } + public static Texture2D BallRoller(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BallRollerName, size, color); public static Texture2D Bumper(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(BumperName, size, color); public static Texture2D DropTarget(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(DropTargetName, size, color); public static Texture2D DropTargetBank(IconSize size = IconSize.Large, IconColor color = IconColor.Gray) => Instance.GetItem(DropTargetBankName, size, color); @@ -134,8 +132,8 @@ private Icons() public static Texture2D ByComponent(T mb, IconSize size = IconSize.Large, IconColor color = IconColor.Gray) where T : class { - switch (mb) - { + switch (mb) { + case BallRollerComponent _: return BallRoller(size, color); case BumperComponent _: return Bumper(size, color); case DropTargetComponent _: return DropTarget(size, color); case DropTargetBankComponent _: return DropTargetBank(size, color); @@ -164,6 +162,7 @@ public static Texture2D ByComponent(T mb, IconSize size = IconSize.Large, Ico [MenuItem("Visual Pinball/Editor/Disable Gizmo Icons", false, 510)] public static void DisableGizmoIcons() { + DisableGizmo(); DisableGizmo(); DisableGizmo(); DisableGizmo(); @@ -227,35 +226,30 @@ public static void DisableGizmoIcons() public static void ApplyToComponent(Object target, Texture2D tex) where T : MonoBehaviour { - if (target == null || tex == null) - { + if (target == null || tex == null) { throw new ArgumentNullException(); } - SetIconForObject.Invoke(null, new object[] { target, tex }); + SetIconForObject.Invoke(null, new object[]{ target, tex }); DisableGizmo(); var monoScript = target as MonoScript; - if (monoScript) - { - CopyMonoScriptIconToImporters.Invoke(null, new object[] { monoScript }); + if (monoScript) { + CopyMonoScriptIconToImporters.Invoke(null, new object[]{ monoScript }); } } private Texture2D GetItem(string name, IconSize size, IconColor color) { var variant = new IconVariant(name, size, color); - if (!_icons.ContainsKey(variant)) - { + if (!_icons.ContainsKey(variant)) { variant = new IconVariant(name, IconSize.Large, color); } - if (!_icons.ContainsKey(variant)) - { + if (!_icons.ContainsKey(variant)) { variant = new IconVariant(name, IconSize.Large, IconColor.Gray); } - if (!_icons.ContainsKey(variant)) - { + if (!_icons.ContainsKey(variant)) { throw new InvalidOperationException($"Cannot find {variant.Size} {variant.Name} icon of color {variant.Color}."); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs similarity index 95% rename from VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs rename to VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs index 3aed3f0fd..ae7a1d475 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs @@ -22,9 +22,8 @@ namespace VisualPinball.Unity { - public class DebugBallComponent : MonoBehaviour + public class BallRollerComponent : MonoBehaviour { - private PlayfieldComponent _playfield; private Matrix4x4 _ltw; private Matrix4x4 _wtl; diff --git a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs.meta b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs.meta similarity index 61% rename from VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs.meta rename to VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs.meta index d9e82ff95..720d88f71 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/Game/DebugBallComponent.cs.meta +++ b/VisualPinball.Unity/VisualPinball.Unity/Game/BallRollerComponent.cs.meta @@ -1,11 +1,11 @@ fileFormatVersion: 2 -guid: 57cf09880101f8a40afd18dcf469b554 +guid: f1b73baf8371338429320656a070566d MonoImporter: externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 - icon: {instanceID: 0} + icon: {fileID: 2800000, guid: 41211858d62e7904ab09fc592d292bba, type: 3} userData: assetBundleName: assetBundleVariant: From a91c9f57f108f833ff0563584d141eb7aec2c77d Mon Sep 17 00:00:00 2001 From: freezy Date: Mon, 25 Oct 2021 00:00:49 +0200 Subject: [PATCH 20/25] fix: Properly register teleporter. --- .../VisualPinball.Unity/VPT/Table/TableApi.cs | 42 ++++++++++++------- .../VPT/Teleporter/TeleporterComponent.cs | 4 ++ 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs index f5b64795f..8a075d197 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Table/TableApi.cs @@ -27,43 +27,47 @@ public class TableApi : IApi #region Dictionaries private readonly Dictionary _bumpersByName = new Dictionary(); - private readonly Dictionary _flippersByName = new Dictionary(); + private readonly Dictionary _cannonsByName = new Dictionary(); + private readonly Dictionary _mechsByName = new Dictionary(); private readonly Dictionary _dropTargetsByName = new Dictionary(); + private readonly Dictionary _dropTargetBanksByName = new Dictionary(); + private readonly Dictionary _flippersByName = new Dictionary(); private readonly Dictionary _gatesByName = new Dictionary(); private readonly Dictionary _hitTargetsByName = new Dictionary(); private readonly Dictionary _kickersByName = new Dictionary(); private readonly Dictionary _lightsByName = new Dictionary(); private readonly Dictionary _lightGroupsByName = new Dictionary(); private readonly Dictionary _plungersByName = new Dictionary(); + private readonly Dictionary _primitivesByName = new Dictionary(); private readonly Dictionary _rampsByName = new Dictionary(); private readonly Dictionary _rubbersByName = new Dictionary(); private readonly Dictionary _spinnersByName = new Dictionary(); private readonly Dictionary _surfacesByName = new Dictionary(); + private readonly Dictionary _teleportersByName = new Dictionary(); private readonly Dictionary _triggersByName = new Dictionary(); private readonly Dictionary _troughsByName = new Dictionary(); - private readonly Dictionary _primitivesByName = new Dictionary(); - private readonly Dictionary _cannonsByName = new Dictionary(); - private readonly Dictionary _dropTargetBanksByName = new Dictionary(); private readonly Dictionary _bumpersByComponent = new Dictionary(); - private readonly Dictionary _flippersByComponent = new Dictionary(); + private readonly Dictionary _cannonsByComponent = new Dictionary(); + private readonly Dictionary _mechsByComponent = new Dictionary(); private readonly Dictionary _dropTargetsByComponent = new Dictionary(); + private readonly Dictionary _dropTargetBanksByComponent = new Dictionary(); + private readonly Dictionary _flippersByComponent = new Dictionary(); private readonly Dictionary _gatesByComponent = new Dictionary(); private readonly Dictionary _hitTargetsByComponent = new Dictionary(); private readonly Dictionary _kickersByComponent = new Dictionary(); private readonly Dictionary _lightsByComponent = new Dictionary(); private readonly Dictionary _lightGroupsByComponent = new Dictionary(); private readonly Dictionary _plungersByComponent = new Dictionary(); + private readonly Dictionary _primitivesByComponent = new Dictionary(); private readonly Dictionary _rampsByComponent = new Dictionary(); private readonly Dictionary _rubbersByComponent = new Dictionary(); private readonly Dictionary _spinnersByComponent = new Dictionary(); private readonly Dictionary _surfacesByComponent = new Dictionary(); + private readonly Dictionary _teleportersByComponent = new Dictionary(); private readonly Dictionary _triggersByComponent = new Dictionary(); private readonly Dictionary _troughsByComponent = new Dictionary(); - private readonly Dictionary _primitivesByComponent = new Dictionary(); - private readonly Dictionary _cannonsByComponent = new Dictionary(); - private readonly Dictionary _dropTargetBanksByComponent = new Dictionary(); #endregion @@ -242,46 +246,52 @@ internal void Register(MonoBehaviour component, T api) where T : IApi private Dictionary GetNameDictionary(Type t) where T : IApi { if (t == typeof(BumperApi)) return _bumpersByName as Dictionary; - if (t == typeof(FlipperApi)) return _flippersByName as Dictionary; + if (t == typeof(CannonApi)) return _cannonsByName as Dictionary; + if (t == typeof(CannonApi)) return _mechsByName as Dictionary; if (t == typeof(DropTargetApi)) return _dropTargetsByName as Dictionary; + if (t == typeof(DropTargetBankApi)) return _dropTargetBanksByName as Dictionary; + if (t == typeof(FlipperApi)) return _flippersByName as Dictionary; if (t == typeof(GateApi)) return _gatesByName as Dictionary; if (t == typeof(HitTargetApi)) return _hitTargetsByName as Dictionary; if (t == typeof(KickerApi)) return _kickersByName as Dictionary; if (t == typeof(LightApi)) return _lightsByName as Dictionary; if (t == typeof(LightGroupApi)) return _lightGroupsByName as Dictionary; if (t == typeof(PlungerApi)) return _plungersByName as Dictionary; + if (t == typeof(PrimitiveApi)) return _primitivesByName as Dictionary; + if (t == typeof(PrimitiveApi)) return _primitivesByName as Dictionary; if (t == typeof(RampApi)) return _rampsByName as Dictionary; if (t == typeof(RubberApi)) return _rubbersByName as Dictionary; if (t == typeof(SpinnerApi)) return _spinnersByName as Dictionary; if (t == typeof(SurfaceApi)) return _surfacesByName as Dictionary; + if (t == typeof(TeleporterApi)) return _teleportersByName as Dictionary; if (t == typeof(TriggerApi)) return _triggersByName as Dictionary; if (t == typeof(TroughApi)) return _troughsByName as Dictionary; - if (t == typeof(PrimitiveApi)) return _primitivesByName as Dictionary; - if (t == typeof(CannonApi)) return _cannonsByName as Dictionary; - if (t == typeof(DropTargetBankApi)) return _dropTargetBanksByName as Dictionary; throw new ArgumentException($"Unknown API type {t}."); } private Dictionary GetComponentDictionary(Type t) where T : IApi { if (t == typeof(BumperApi)) return _bumpersByComponent as Dictionary; - if (t == typeof(FlipperApi)) return _flippersByComponent as Dictionary; + if (t == typeof(CannonApi)) return _cannonsByComponent as Dictionary; + if (t == typeof(CannonApi)) return _mechsByComponent as Dictionary; if (t == typeof(DropTargetApi)) return _dropTargetsByComponent as Dictionary; + if (t == typeof(DropTargetBankApi)) return _dropTargetBanksByComponent as Dictionary; + if (t == typeof(FlipperApi)) return _flippersByComponent as Dictionary; if (t == typeof(GateApi)) return _gatesByComponent as Dictionary; if (t == typeof(HitTargetApi)) return _hitTargetsByComponent as Dictionary; if (t == typeof(KickerApi)) return _kickersByComponent as Dictionary; if (t == typeof(LightApi)) return _lightsByComponent as Dictionary; if (t == typeof(LightGroupApi)) return _lightGroupsByComponent as Dictionary; if (t == typeof(PlungerApi)) return _plungersByComponent as Dictionary; + if (t == typeof(PrimitiveApi)) return _primitivesByComponent as Dictionary; + if (t == typeof(PrimitiveApi)) return _primitivesByComponent as Dictionary; if (t == typeof(RampApi)) return _rampsByComponent as Dictionary; if (t == typeof(RubberApi)) return _rubbersByComponent as Dictionary; if (t == typeof(SpinnerApi)) return _spinnersByComponent as Dictionary; if (t == typeof(SurfaceApi)) return _surfacesByComponent as Dictionary; + if (t == typeof(TeleporterApi)) return _teleportersByComponent as Dictionary; if (t == typeof(TriggerApi)) return _triggersByComponent as Dictionary; if (t == typeof(TroughApi)) return _troughsByComponent as Dictionary; - if (t == typeof(PrimitiveApi)) return _primitivesByComponent as Dictionary; - if (t == typeof(CannonApi)) return _cannonsByComponent as Dictionary; - if (t == typeof(DropTargetBankApi)) return _dropTargetBanksByComponent as Dictionary; throw new ArgumentException($"Unknown API type {t}."); } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs index a7dfdb591..fee378346 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs @@ -73,6 +73,8 @@ public class TeleporterComponent : MonoBehaviour, ICoilDeviceComponent #endregion + #region Runtime + private void Awake() { var player = GetComponentInParent(); @@ -84,5 +86,7 @@ private void Awake() player.RegisterTeleporter(this); } + + #endregion } } From bf1763a94e90be0f5df096ba21598ecad2ef87d5 Mon Sep 17 00:00:00 2001 From: freezy Date: Mon, 25 Oct 2021 00:10:06 +0200 Subject: [PATCH 21/25] t2: Setup teleporter. --- .../Matcher/TablePatcher.cs | 5 +++++ .../Patcher/Tables/Terminator2.cs | 18 ++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs index caf7796ba..274e99ea5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Matcher/TablePatcher.cs @@ -142,6 +142,11 @@ protected static TroughComponent CreateTrough(GameObject tableGo, GameObject par return troughComponent; } + protected T FindSiblingComponent(MonoBehaviour mb, string name) where T : MonoBehaviour + { + return mb.gameObject.transform.parent.transform.Find(name).gameObject.GetComponent(); + } + ///

/// Creates a drop target bank component. /// diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs index ce1d2ab45..127ce3eb6 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs @@ -19,10 +19,10 @@ // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global +using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; -using UnityEngine.Experimental.GlobalIllumination; using VisualPinball.Engine.Math; using VisualPinball.Engine.VPT; using Color = UnityEngine.Color; @@ -119,6 +119,13 @@ private static void SetupMapping(GameObject tableGo) // kickback LinkCoil(tc, "Plunger1", "08", plunger, PlungerComponent.FireCoilId); } + + var teleporters = tableGo.GetComponentsInChildren(); + foreach (var teleporter in teleporters) { + + // skull kicker + LinkCoil(tc, "sw76", "01", teleporter, TeleporterComponent.CoilItem); + } } private static void SetupDmd(GameObject tableGo) @@ -348,9 +355,12 @@ public void Shooter(KickerComponent kickerComponent) [NameMatch("sw76")] public void SkullKicker(KickerComponent kickerComponent) { - kickerComponent.Coils[0].Name = "kicker_coil"; - kickerComponent.Coils[0].Speed = 15; - kickerComponent.Coils[0].Angle = 72; + kickerComponent.Coils.Clear(); + var tp = kickerComponent.gameObject.AddComponent(); + tp.FromKicker = kickerComponent; + tp.ToKicker = FindSiblingComponent(kickerComponent, "sw76a"); + tp.ToKickerItem = tp.ToKicker.AvailableCoils.First().Id; + tp.KickAfterTeleportation = true; } [NameMatch("sw55")] From 6fc464ce9776764e921d3e502efa2f61249a603e Mon Sep 17 00:00:00 2001 From: freezy Date: Mon, 25 Oct 2021 00:24:11 +0200 Subject: [PATCH 22/25] doc: Add a page about teleporters. --- .../manual/mechanisms/slingshots.md | 6 +++ .../mechanisms/teleporter-inspector.png | Bin 0 -> 13371 bytes .../manual/mechanisms/teleporters.md | 44 ++++++++++++++++++ .../Documentation~/creators-guide/toc.yml | 2 + 4 files changed, 52 insertions(+) create mode 100644 VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporter-inspector.png create mode 100644 VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md index 415025a41..9e12add05 100644 --- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md +++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/slingshots.md @@ -1,3 +1,9 @@ +--- +uid: slingshots +title: Slingshots +description: How to animate VPE's slingshots +--- + # Slingshots Slingshots are most commonly located just above the flippers. They usually consist of two "blade" switches on the inner side of a triangular rubber. Between the switches there is a coil driven arm that propels the ball away from the slingshot when either switch closes. diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporter-inspector.png b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporter-inspector.png new file mode 100644 index 0000000000000000000000000000000000000000..c0f25ce4f50f8fc882bd632bf981f8a3345c9ca1 GIT binary patch literal 13371 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 AQ2+n{ literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md new file mode 100644 index 000000000..299bbec8f --- /dev/null +++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md @@ -0,0 +1,44 @@ +--- +uid: teleporters +title: Teleporters +description: VPE can teleport the ball from one kicker to another. +--- + +# Teleporters + +Sometimes, it's easier to teleport the ball from one place to another instead of setting up the physical environment to simulate the actual movement. VPE provides a simple component that destroys a ball at kicker A and creates a new one at kicker B. + +> [!NOTE] +> Please note that you shouldn't be using teleporters when the ball is visible, because it breaks the natural flow of the ball and looks choppy. + + +## Setup + + +Teleporter Inspector + +In order to create a new teleporter, select the GameObject you want to add it to, click on *Add Component* and select *Visual Pinball -> Game Item -> Teleporter*. You can choose any GameObject, although we recommend putting it on same GameObject as the source kicker. + +> [!NOTE] +> The teleporter's features are very basic. If there is need, we will add more features like teleportation to multiple types of game elements or the possibility to teleport in both directions. + +### Eject After Teleport + +Once the ball is created at the destination kicker, it can ejected immediately or after a delay (see next section), or it can stay in the kicker. + +If disabled, this option makes the destination kicker keep the ball until it's explicitly ejected trough the kicker's coil. + + +### Wait Before Eject + +You should use teleporters only for trajectories that are hidden and that emulate a physical ball going from A to B. In that case, the time it would take for the ball to travel from A to B can be simulated by waiting for the destination kicker to pop out the ball. + +This is the time in seconds that is waited before the ball is ejected from the destination kicker, but only if *Eject After Teleport* is enabled. + +### From Kicker + +A reference to the source kicker. Note that if you use this kicker for teleportation only, it's recommended to remove any coils from the kicker, since it will make it easier to select the right element when linking to it in the Coil Manager. + +### To Kicker + +The destination kicker. Here you also select a coil in case the ball is ejected after teleportation. \ 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 63dd79668..be45f7606 100644 --- a/VisualPinball.Unity/Documentation~/creators-guide/toc.yml +++ b/VisualPinball.Unity/Documentation~/creators-guide/toc.yml @@ -49,5 +49,7 @@ href: manual/mechanisms/slingshots.md - name: Light Groups href: manual/mechanisms/light-groups.md + - name: Teleporters + href: manual/mechanisms/teleporters.md - name: Drop Target Banks href: manual/mechanisms/drop-target-banks.md From bf6967478232e78dcdf12e6b656cbea0fa1d8f18 Mon Sep 17 00:00:00 2001 From: freezy Date: Mon, 25 Oct 2021 00:48:55 +0200 Subject: [PATCH 23/25] teleporter: Adapt code to documentation. --- .../VPT/Teleporter/TeleporterInspector.cs | 11 ++--- .../Patcher/Tables/Terminator2.cs | 4 +- .../VPT/Ball/BallManager.cs | 2 +- .../VPT/Teleporter/TeleporterApi.cs | 40 ++++++++++++------- .../VPT/Teleporter/TeleporterComponent.cs | 11 ++--- 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs index 971b20043..b9226c109 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/VPT/Teleporter/TeleporterInspector.cs @@ -22,7 +22,6 @@ namespace VisualPinball.Unity.Editor [CustomEditor(typeof(TeleporterComponent)), CanEditMultipleObjects] public class TeleporterInspector : ItemInspector { - private SerializedProperty _bidirectionalProperty; private SerializedProperty _kickAfterTeleportationProperty; private SerializedProperty _kickDelayProperty; private SerializedProperty _fromKickerProperty; @@ -34,9 +33,8 @@ protected override void OnEnable() { base.OnEnable(); - _bidirectionalProperty = serializedObject.FindProperty(nameof(TeleporterComponent.Bidirectional)); - _kickAfterTeleportationProperty = serializedObject.FindProperty(nameof(TeleporterComponent.KickAfterTeleportation)); - _kickDelayProperty = serializedObject.FindProperty(nameof(TeleporterComponent.KickDelay)); + _kickAfterTeleportationProperty = serializedObject.FindProperty(nameof(TeleporterComponent.EjectAfterTeleportation)); + _kickDelayProperty = serializedObject.FindProperty(nameof(TeleporterComponent.EjectDelay)); _fromKickerProperty = serializedObject.FindProperty(nameof(TeleporterComponent.FromKicker)); _toKickerProperty = serializedObject.FindProperty(nameof(TeleporterComponent.ToKicker)); } @@ -47,9 +45,8 @@ public override void OnInspectorGUI() OnPreInspectorGUI(); - PropertyField(_bidirectionalProperty, "Bi-Directional"); - PropertyField(_kickAfterTeleportationProperty, "Kick After Teleport"); - PropertyField(_kickDelayProperty, "Wait Before Kick (s)"); + PropertyField(_kickAfterTeleportationProperty, "Eject After Teleport"); + PropertyField(_kickDelayProperty, "Wait Before Eject (s)"); PropertyField(_fromKickerProperty); PropertyField(_toKickerProperty); diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs index 127ce3eb6..48ccbebd4 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs @@ -122,7 +122,7 @@ private static void SetupMapping(GameObject tableGo) var teleporters = tableGo.GetComponentsInChildren(); foreach (var teleporter in teleporters) { - + // skull kicker LinkCoil(tc, "sw76", "01", teleporter, TeleporterComponent.CoilItem); } @@ -360,7 +360,7 @@ public void SkullKicker(KickerComponent kickerComponent) tp.FromKicker = kickerComponent; tp.ToKicker = FindSiblingComponent(kickerComponent, "sw76a"); tp.ToKickerItem = tp.ToKicker.AvailableCoils.First().Id; - tp.KickAfterTeleportation = true; + tp.EjectAfterTeleportation = true; } [NameMatch("sw55")] diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallManager.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallManager.cs index a3e2be90b..669950667 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallManager.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Ball/BallManager.cs @@ -104,7 +104,7 @@ public void CreateEntity(GameObject ballGo, int id, in float3 worldPos, in float ecb.AddComponent(entity, new BallData { Id = id, - IsFrozen = false, + IsFrozen = kickerEntity != Entity.Null, Position = localPos, Radius = radius, Mass = mass, diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs index 527ac1ba5..c56dd538a 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterApi.cs @@ -19,6 +19,8 @@ using System; using Logger = NLog.Logger; using NLog; +using Unity.Entities; +using Unity.Mathematics; using UnityEngine; namespace VisualPinball.Unity @@ -33,6 +35,7 @@ public class TeleporterApi : IApi, IApiCoilDevice private DeviceCoil _teleporterCoil; private KickerApi _fromKicker; private KickerApi _toKicker; + private readonly VisualPinballSimulationSystemGroup _simulationSystemGroup; public event EventHandler Init; @@ -40,6 +43,7 @@ internal TeleporterApi(GameObject go, Player player) { _component = go.GetComponentInChildren(); _player = player; + _simulationSystemGroup = World.DefaultGameObjectInjectionWorld.GetOrCreateSystem(); } void IApi.OnInit(BallManager ballManager) @@ -60,27 +64,35 @@ private void OnTeleport() return; } - var ballInPortalA = _fromKicker.HasBall(); - var ballInPortalB = _toKicker.HasBall(); - if (ballInPortalA && ballInPortalB || !ballInPortalA && !ballInPortalB) { + var ballInSrc = _fromKicker.HasBall(); + var ballInDst = _toKicker.HasBall(); + if (!ballInSrc || ballInDst) { // duh, do nothing. return; } - if (ballInPortalA) { - var ballData = _fromKicker.GetBallData(); - _fromKicker.DestroyBall(); - _toKicker.CreateSizedBallWithMass(ballData.Radius, ballData.Mass); + var ballData = _fromKicker.GetBallData(); + _fromKicker.DestroyBall(); + _toKicker.CreateSizedBallWithMass(ballData.Radius, ballData.Mass); - if (_component.KickAfterTeleportation && !string.IsNullOrEmpty(_component.ToKickerItem)) { - var kickerCoil = (_toKicker as IApiCoilDevice).Coil(_component.ToKickerItem); - kickerCoil.OnCoil(true); - } + // if no eject, we're done here. + if (!_component.EjectAfterTeleportation) { + return; + } + + if (_component.EjectDelay > 0) { + _simulationSystemGroup.ScheduleAction((int)math.round(_component.EjectDelay * 1000f), Eject); } else { - var ballData = _toKicker.GetBallData(); - _toKicker.DestroyBall(); - _fromKicker.CreateSizedBallWithMass(ballData.Radius, ballData.Mass); + Eject(); + } + } + + private void Eject() + { + if (!string.IsNullOrEmpty(_component.ToKickerItem)) { + var kickerCoil = (_toKicker as IApiCoilDevice).Coil(_component.ToKickerItem); + kickerCoil.OnCoil(true); } } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs index fee378346..e5ad013a0 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs @@ -29,22 +29,17 @@ public class TeleporterComponent : MonoBehaviour, ICoilDeviceComponent { #region Data - [Tooltip("If set, the teleporter also teleports into the opposite direction.")] - public bool Bidirectional; - [Tooltip("If set, the ball is automatically popped out of the destination kicker upon arrival.")] - public bool KickAfterTeleportation = true; + public bool EjectAfterTeleportation = true; [Min(0)] [Tooltip("The time in seconds between the ball arriving at the destination kicker and being popped out of the kicker.")] - public float KickDelay = 0.5f; + public float EjectDelay = 0.5f; [Tooltip("The kicker where the ball is teleported from.")] - [TypeRestriction(typeof(KickerComponent), PickerLabel = "Kickers", DeviceItem = nameof(FromKickerItem), DeviceType = typeof(ICoilDeviceComponent))] public KickerComponent FromKicker; - public string FromKickerItem = string.Empty; - [Tooltip("The kicker where the ball is teleported into.")] + [Tooltip("The kicker where the ball is teleported into, and which coil should be used to pop the ball out.")] [TypeRestriction(typeof(KickerComponent), PickerLabel = "Kickers", DeviceItem = nameof(ToKickerItem), DeviceType = typeof(ICoilDeviceComponent))] public KickerComponent ToKicker; public string ToKickerItem = string.Empty; From b06e17510d342017f8c14f837326f79808aab5ad Mon Sep 17 00:00:00 2001 From: DanLShane <92692744+DanLShane@users.noreply.github.com> Date: Mon, 25 Oct 2021 12:17:53 -0400 Subject: [PATCH 24/25] Update teleporters.md --- .../creators-guide/manual/mechanisms/teleporters.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md index 299bbec8f..c8263319e 100644 --- a/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md +++ b/VisualPinball.Unity/Documentation~/creators-guide/manual/mechanisms/teleporters.md @@ -24,7 +24,7 @@ In order to create a new teleporter, select the GameObject you want to add it to ### Eject After Teleport -Once the ball is created at the destination kicker, it can ejected immediately or after a delay (see next section), or it can stay in the kicker. +Once the ball is created at the destination kicker, it can be ejected immediately or after a delay (see next section), or it can stay in the kicker. If disabled, this option makes the destination kicker keep the ball until it's explicitly ejected trough the kicker's coil. @@ -41,4 +41,4 @@ A reference to the source kicker. Note that if you use this kicker for teleporta ### To Kicker -The destination kicker. Here you also select a coil in case the ball is ejected after teleportation. \ No newline at end of file +The destination kicker. Here you also select a coil in case the ball is ejected after teleportation. From f2453fdd601e81f5e8ac2ce0cb0713075b004c32 Mon Sep 17 00:00:00 2001 From: freezy Date: Tue, 26 Oct 2021 23:51:35 +0200 Subject: [PATCH 25/25] doc: Update Changelog. --- CHANGELOG.md | 3 ++- .../Patcher/Tables/Terminator2.cs | 19 ++++++++++++++----- .../VPT/Teleporter/TeleporterComponent.cs | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da5906e21..f2ff87577 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ Built with Unity 2020.3. ### Added -- A *Drop Target Bank* component ([#333](https://github.com/freezy/VisualPinball.Engine/pull/333), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/drop-target-banks.html)). +- A *Teleporter* component ([#336](https://github.com/freezy/VisualPinball.Engine/pull/336), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/drop-target-banks.html)). +- A *Drop Target Bank* component ([#333](https://github.com/freezy/VisualPinball.Engine/pull/333), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/teleporters.html)). - Editor: Enable manual trigger for coils, switches, lamps and wires during gameplay ([#332](https://github.com/freezy/VisualPinball.Engine/pull/332)) - Support for dynamic wires, also known as *Fast Flip* ([#330](https://github.com/freezy/VisualPinball.Engine/pull/330), [Documentation](https://docs.visualpinball.org/creators-guide/editor/wire-manager.html#dynamic)). - Component for light groups, allowing easy grouping of GI lamps. ([#330](https://github.com/freezy/VisualPinball.Engine/pull/330) [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/light-groups.html)). diff --git a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs index 48ccbebd4..3f0238ce3 100644 --- a/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs +++ b/VisualPinball.Unity/VisualPinball.Unity.Patcher/Patcher/Tables/Terminator2.cs @@ -19,11 +19,11 @@ // ReSharper disable UnusedMember.Global // ReSharper disable UnusedType.Global -using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using VisualPinball.Engine.Math; +using VisualPinball.Engine.PinMAME; using VisualPinball.Engine.VPT; using Color = UnityEngine.Color; @@ -72,7 +72,7 @@ private static void SetupPinMame(GameObject tableGo, GameObject playfieldGo) // GLE Object.DestroyImmediate(tableGo.GetComponent()); - var pinmameGle = tableGo.AddComponent(); + var pinmameGle = tableGo.AddComponent(); pinmameGle.Game = new Engine.PinMAME.Games.Terminator2(); pinmameGle.romId = "t2_l82"; tableComponent.RepopulateHardware(pinmameGle); @@ -347,7 +347,7 @@ public void FixSw17(KickerComponent kickerComponent) [NameMatch("sw78")] public void Shooter(KickerComponent kickerComponent) { - kickerComponent.Coils[0].Name = "kicker_coil"; + kickerComponent.Coils[0].Name = "Shooter"; kickerComponent.Coils[0].Speed = 50; kickerComponent.Coils[0].Angle = 0; } @@ -360,13 +360,22 @@ public void SkullKicker(KickerComponent kickerComponent) tp.FromKicker = kickerComponent; tp.ToKicker = FindSiblingComponent(kickerComponent, "sw76a"); tp.ToKickerItem = tp.ToKicker.AvailableCoils.First().Id; + tp.EjectDelay = 0; tp.EjectAfterTeleportation = true; } + [NameMatch("sw76a")] + public void Teleporter(KickerComponent kickerComponent) + { + kickerComponent.Coils[0].Name = "Teleporter Out"; + kickerComponent.Coils[0].Speed = 15; + kickerComponent.Coils[0].Angle = 72; + } + [NameMatch("sw55")] public void TopLock(KickerComponent kickerComponent) { - kickerComponent.Coils[0].Name = "kicker_coil"; + kickerComponent.Coils[0].Name = "Kick Out"; kickerComponent.Coils[0].Speed = 5; kickerComponent.Coils[0].Angle = 270; } @@ -374,7 +383,7 @@ public void TopLock(KickerComponent kickerComponent) [NameMatch("sw51")] public void LeftLock(KickerComponent kickerComponent) { - kickerComponent.Coils[0].Name = "kicker_coil"; + kickerComponent.Coils[0].Name = "Kick Out"; kickerComponent.Coils[0].Speed = 13; kickerComponent.Coils[0].Angle = 160; } diff --git a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs index e5ad013a0..706681aa5 100644 --- a/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs +++ b/VisualPinball.Unity/VisualPinball.Unity/VPT/Teleporter/TeleporterComponent.cs @@ -25,6 +25,7 @@ namespace VisualPinball.Unity { [AddComponentMenu("Visual Pinball/Game Item/Teleporter")] + [HelpURL("https://docs.visualpinball.org/creators-guide/manual/mechanisms/teleporters.html")] public class TeleporterComponent : MonoBehaviour, ICoilDeviceComponent { #region Data

=msnMGOF9Lle=SnM&NlQwLbm#eHRp;=3nsNg{| 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�A#SiB(slYeH7?2!lAS3ywM0g|d&|tr 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 EzpmP6e*gdg literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/ball_roller.png.meta new file mode 100644 index 000000000..0e2eb408e --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: d875bb1b18c51e34ea79a43799ce38ff +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 1 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/large_gray/teleporter.png index de5efdad2ce6a5d823739b29ac3da53c0db960da..2204a85cb38c926ced937066475083b48f5c3dbc 100644 GIT binary patch literal 7495 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 VE@$m#W}qGqT$Z~z=Gpt7_#as!cHjU2 literal 14115 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¬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 Qz#;)!8hYxbYIYC*AHKX_RR910 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png b/VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png new file mode 100644 index 0000000000000000000000000000000000000000..5023593046d790a5142d3e53ec9fdc6d071d00a4 GIT binary patch literal 6155 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 literal 0 HcmV?d00001 diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png.meta b/VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png.meta new file mode 100644 index 000000000..dff6a6f39 --- /dev/null +++ b/VisualPinball.Unity/Assets/Editor/Icons/large_green/ball_roller.png.meta @@ -0,0 +1,108 @@ +fileFormatVersion: 2 +guid: e22f43052894ced418fa3ca9b311742a +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 1 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 512 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png b/VisualPinball.Unity/Assets/Editor/Icons/large_green/teleporter.png index f59101e4293ebbf19a1b906dea26625a1e8deeb2..ab99e4a2170d282a7a6c5fbb5f31fd52e52e2b02 100644 GIT binary patch literal 7496 zcmZX32{_bW^!NGB3^ODqTND|Qtz;`{GgDM5A^Nq+QW6zeLz4N5s3?^dNtsGfenf~8 zMog5Q%FUh=r@&M`-}H)nJPA#+f7 zWzX)(>rC_7Jv?@hRFU<4X_}!?$#iC)0zmPOMUyw0Tn0v+ep|*yT`P>mFu-g7ZHzxK zlZYe5i%z5%51YnDg&r&8jUolits=Hmuq{9Qi8NroVhle_VD?0kfW_k*y9E^z|6a