diff --git a/CHANGELOG.md b/CHANGELOG.md
index eaf06b255..1bb6f860e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,7 @@ Built with Unity 2021.3.0
### Added
- Scale support for rubbers.
+- Slingarm coil arms can now be any game objects, not just primitives ([#432](https://github.com/freezy/VisualPinball.Engine/pull/432)).
- Gate Lifter Component ([#418](https://github.com/freezy/VisualPinball.Engine/pull/418), [Documentation](https://docs.visualpinball.org/creators-guide/manual/mechanisms/lifting-gates.html)).
- Asset Browser ([#412](https://github.com/freezy/VisualPinball.Engine/pull/412))
- Trigger meshes can now be easily scaled ([#374](https://github.com/freezy/VisualPinball.Engine/pull/374))
@@ -55,6 +56,7 @@ Built with Unity 2021.3.0
- Put game-, mesh-, collision- animation data into separate components ([#227](https://github.com/freezy/VisualPinball.Engine/pull/227), [Documentation](https://docs.visualpinball.org/creators-guide/editor/unity-components.html)).
### Fixed
+- Default table import ([#434](https://github.com/freezy/VisualPinball.Engine/pull/434))
- Remaining ball spinning issue should now be solved ([#397](https://github.com/freezy/VisualPinball.Engine/pull/397)).
- Physics error when the ball would stop rotate ([#393](https://github.com/freezy/VisualPinball.Engine/pull/393)).
- Finally, ball rotation is rendered correctly ([#386](https://github.com/freezy/VisualPinball.Engine/pull/386)).
diff --git a/VisualPinball.Unity/Assets/Editor/Presets.meta b/VisualPinball.Unity/Assets/Editor/Presets.meta
new file mode 100644
index 000000000..f2d481bdc
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Presets.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c5510a3f3d1d161419d8b057586b5c8d
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VisualPinball.Unity/Assets/Editor/Presets/FBXImporter.preset b/VisualPinball.Unity/Assets/Editor/Presets/FBXImporter.preset
new file mode 100644
index 000000000..a5f6e7210
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Presets/FBXImporter.preset
@@ -0,0 +1,387 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!181963792 &2655988077585873504
+Preset:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_Name: FBXImporter
+ m_TargetType:
+ m_NativeTypeID: 1041
+ m_ManagedTypePPtr: {fileID: 0}
+ m_ManagedTypeFallback:
+ m_Properties:
+ - target: {fileID: 0}
+ propertyPath: m_ExternalObjects.Array.size
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_MaterialImportMode
+ value: 2
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_MaterialName
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_MaterialSearch
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_MaterialLocation
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_LegacyGenerateAnimations
+ value: 4
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_BakeSimulation
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ResampleCurves
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_OptimizeGameObjects
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_RemoveConstantScaleCurves
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_MotionNodeName
+ value:
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_RigImportErrors
+ value:
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_RigImportWarnings
+ value:
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AnimationImportErrors
+ value:
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AnimationImportWarnings
+ value:
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AnimationRetargetingWarnings
+ value:
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AnimationDoRetargetingWarnings
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ImportAnimatedCustomProperties
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ImportConstraints
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AnimationCompression
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AnimationRotationError
+ value: 0.5
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AnimationPositionError
+ value: 0.5
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AnimationScaleError
+ value: 0.5
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AnimationWrapMode
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ExtraExposedTransformPaths.Array.size
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ExtraUserProperties.Array.size
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ClipAnimations.Array.size
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_IsReadable
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_LODScreenPercentages.Array.size
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_GlobalScale
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_MeshCompression
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AddColliders
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_UseSRGBMaterialColor
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_SortHierarchyByName
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ImportVisibility
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ImportBlendShapes
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ImportCameras
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ImportLights
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_NodeNameCollisionStrategy
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: swapUVChannels
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: generateSecondaryUV
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_UseFileUnits
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: keepQuads
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: weldVertices
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: bakeAxisConversion
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_PreserveHierarchy
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: skinWeightsMode
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: maxBonesPerVertex
+ value: 4
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: minBoneWeight
+ value: 0.001
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: optimizeBones
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: meshOptimizationFlags
+ value: -1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: indexFormat
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: secondaryUVAngleDistortion
+ value: 8
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: secondaryUVAreaDistortion
+ value: 15.000001
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: secondaryUVHardAngle
+ value: 88
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: secondaryUVMarginMethod
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: secondaryUVMinLightmapResolution
+ value: 40
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: secondaryUVMinObjectScale
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: secondaryUVPackMargin
+ value: 4
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_UseFileScale
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: normalSmoothAngle
+ value: 60
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: normalImportMode
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: tangentImportMode
+ value: 3
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: normalCalculationMode
+ value: 4
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: blendShapeNormalImportMode
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: normalSmoothingSource
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ReferencedClips.Array.size
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_ImportAnimation
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_Human.Array.size
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_Skeleton.Array.size
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_ArmTwist
+ value: 0.5
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_ForeArmTwist
+ value: 0.5
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_UpperLegTwist
+ value: 0.5
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_LegTwist
+ value: 0.5
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_ArmStretch
+ value: 0.05
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_LegStretch
+ value: 0.05
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_FeetSpacing
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_GlobalScale
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_RootMotionBoneName
+ value:
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_HasTranslationDoF
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_HasExtraRoot
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanDescription.m_SkeletonHasParents
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_LastHumanDescriptionAvatarSource
+ value:
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AutoGenerateAvatarMappingIfUnspecified
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AnimationType
+ value: 2
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_HumanoidOversampling
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AvatarSetup
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AddHumanoidExtraRootOnlyWhenUsingAvatar
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AdditionalBone
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_UserData
+ value:
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AssetBundleName
+ value:
+ objectReference: {fileID: 0}
+ - target: {fileID: 0}
+ propertyPath: m_AssetBundleVariant
+ value:
+ objectReference: {fileID: 0}
+ m_ExcludedProperties: []
diff --git a/VisualPinball.Unity/Assets/Editor/Presets/FBXImporter.preset.meta b/VisualPinball.Unity/Assets/Editor/Presets/FBXImporter.preset.meta
new file mode 100644
index 000000000..00bcf7435
--- /dev/null
+++ b/VisualPinball.Unity/Assets/Editor/Presets/FBXImporter.preset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7e2a01c630aae224d9ae9b59eb25e743
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 2655988077585873504
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPostProcessor.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPostProcessor.cs
new file mode 100644
index 000000000..915179ff7
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPostProcessor.cs
@@ -0,0 +1,42 @@
+// Visual Pinball Engine
+// Copyright (C) 2022 freezy and VPE Team
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System.IO;
+using UnityEditor;
+using UnityEditor.Presets;
+
+namespace VisualPinball.Unity.Editor
+{
+ public class VpxPostProcessor : AssetPostprocessor
+ {
+ private static Preset _fbxPreset;
+
+ private void OnPreprocessAsset()
+ {
+ if (string.IsNullOrEmpty(assetPath)) {
+ return;
+ }
+
+ if (Path.GetDirectoryName(assetPath!)!.EndsWith("Meshes") && Path.GetExtension(assetPath).ToLowerInvariant() == ".fbx") {
+ if (_fbxPreset == null) {
+ const string presetPath = "Packages/org.visualpinball.engine.unity/VisualPinball.Unity/Assets/Editor/Presets";
+ _fbxPreset = AssetDatabase.LoadAssetAtPath($"{presetPath}/FBXImporter.preset");
+ }
+ _fbxPreset.ApplyTo(assetImporter);
+ }
+ }
+ }
+}
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPostProcessor.cs.meta b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPostProcessor.cs.meta
new file mode 100644
index 000000000..39a00f27b
--- /dev/null
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxPostProcessor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1eaf4cee41791d0458301a05e21463dc
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs
index 669101cf1..9fcc49485 100644
--- a/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs
+++ b/VisualPinball.Unity/VisualPinball.Unity.Editor/Import/VpxSceneConverter.cs
@@ -500,10 +500,35 @@ private void ConfigurePlayer(Dictionary components)
_tableGo.AddComponent();
var dga = _tableGo.AddComponent();
+ // add trough if none available
+ if (!_sourceContainer.HasTrough) {
+ CreateTrough(components);
+ }
+
// populate hardware
_tableComponent.RepopulateHardware(dga);
}
+ private void CreateTrough(Dictionary components)
+ {
+ var troughData = new TroughData("Trough") {
+ BallCount = 4,
+ SwitchCount = 4,
+ Type = TroughType.ModernMech
+ };
+ if (_sourceContainer.Has("BallRelease")) {
+ troughData.PlayfieldExitKicker = "BallRelease";
+ }
+ if (_sourceContainer.Has("Drain")) {
+ troughData.PlayfieldEntrySwitch = "Drain";
+ }
+ var item = new Trough(troughData) {
+ StorageIndex = _sourceContainer.ItemDatas.Count()
+ };
+
+ InstantiateAndPersistPrefab(item, components);
+ }
+
private void CreateFileHierarchy()
{
if (!Directory.Exists("Assets/Tables/")) {