Skip to content

Commit cc02eb4

Browse files
committed
packaging: Add .vpe packaging for visual scripting gamelogic.
Implement IPackable on VisualScriptingGamelogicEngine so its variable/event/display declarations and switch/coil/lamp/wire definitions round-trip through .vpe packages. Add a separate VisualScriptingGraphPackager that captures ScriptMachine/StateMachine components, Variables components, and the transitive closure of ScriptGraphAsset/StateGraphAsset they reference, remapping object references to stable ids so cross-graph links survive the round trip. Runtime-created graph assets are tracked and destroyed with the engine.
1 parent 199a295 commit cc02eb4

5 files changed

Lines changed: 476 additions & 1 deletion

Runtime/Gamelogic/VisualScriptingGamelogicEngine.cs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@
2727

2828
namespace VisualPinball.Unity.VisualScripting
2929
{
30+
[PackAs("VisualScriptingGameLogic")]
3031
[DisallowMultipleComponent]
3132
[AddComponentMenu("Pinball/Gamelogic Engine/Visual Scripting Game Logic")]
32-
public class VisualScriptingGamelogicEngine : MonoBehaviour, IGamelogicEngine, ISerializationCallbackReceiver
33+
public class VisualScriptingGamelogicEngine : MonoBehaviour, IGamelogicEngine, IGamelogicInputThreading, ISerializationCallbackReceiver, IPackable
3334
{
3435
public string Name => "Visual Scripting Gamelogic Engine";
36+
public GamelogicInputDispatchMode SwitchDispatchMode => GamelogicInputDispatchMode.MainThread;
3537

3638
[Tooltip("Define here the global variables of the Visual Scripting engine.")]
3739
public List<TableVariableDefinition> TableVariableDefinitions;
@@ -251,5 +253,40 @@ public void OnBeforeSerialize()
251253
public void OnAfterDeserialize()
252254
{
253255
}
256+
257+
#region Packaging
258+
259+
// Graph assets recreated at runtime when unpacking a .vpe table. They are plain in-memory
260+
// ScriptableObjects, so the table owns their lifetime and destroys them on teardown.
261+
[NonSerialized] private List<ScriptableObject> _runtimeGraphAssets;
262+
263+
public byte[] Pack() => VisualScriptingGamelogicEnginePackable.Pack(this);
264+
265+
public byte[] PackReferences(Transform root, PackagedRefs refs, PackagedFiles files)
266+
=> VisualScriptingGraphPackager.Pack(root, refs);
267+
268+
public void Unpack(byte[] bytes) => VisualScriptingGamelogicEnginePackable.Unpack(bytes, this);
269+
270+
public void UnpackReferences(byte[] bytes, Transform root, PackagedRefs refs, PackagedFiles files)
271+
=> _runtimeGraphAssets = VisualScriptingGraphPackager.Unpack(bytes, root, refs);
272+
273+
private void OnDestroy()
274+
{
275+
if (_runtimeGraphAssets == null) {
276+
return;
277+
}
278+
foreach (var asset in _runtimeGraphAssets) {
279+
if (asset != null) {
280+
if (Application.isPlaying) {
281+
Destroy(asset);
282+
} else {
283+
DestroyImmediate(asset);
284+
}
285+
}
286+
}
287+
_runtimeGraphAssets = null;
288+
}
289+
290+
#endregion
254291
}
255292
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Visual Pinball Engine
2+
// Copyright (C) 2026 freezy and VPE Team
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
// ReSharper disable InconsistentNaming
18+
19+
using System;
20+
using System.Collections.Generic;
21+
using VisualPinball.Engine.Game.Engines;
22+
23+
namespace VisualPinball.Unity.VisualScripting
24+
{
25+
/// <summary>
26+
/// The serializable configuration of the <see cref="VisualScriptingGamelogicEngine"/>: the
27+
/// variable, event and display declarations as well as the switch/coil/lamp/wire definitions
28+
/// the visual scripts address by id.
29+
///
30+
/// This is the <see cref="IPackable.Pack"/> payload. The actual visual scripting graphs (the
31+
/// <c>ScriptMachine</c>/<c>StateMachine</c> components and their graph assets) are packaged
32+
/// separately as references, see <see cref="VisualScriptingGraphPackager"/>.
33+
/// </summary>
34+
public struct VisualScriptingGamelogicEnginePackable
35+
{
36+
public List<TableVariableDefinition> TableVariableDefinitions;
37+
public List<PlayerVariableDefinition> PlayerVariableDefinitions;
38+
public List<EventDefinition> EventDefinitions;
39+
public DisplayDefinition[] Displays;
40+
public VisualScriptingSwitch[] Switches;
41+
public VisualScriptingCoil[] Coils;
42+
public VisualScriptingLamp[] Lamps;
43+
public GamelogicEngineWire[] Wires;
44+
45+
public static byte[] Pack(VisualScriptingGamelogicEngine gle)
46+
{
47+
return PackageApi.Packer.Pack(new VisualScriptingGamelogicEnginePackable {
48+
TableVariableDefinitions = gle.TableVariableDefinitions,
49+
PlayerVariableDefinitions = gle.PlayerVariableDefinitions,
50+
EventDefinitions = gle.EventDefinitions,
51+
Displays = gle.Displays,
52+
Switches = gle.Switches,
53+
Coils = gle.Coils,
54+
Lamps = gle.Lamps,
55+
Wires = gle.Wires,
56+
});
57+
}
58+
59+
public static void Unpack(byte[] bytes, VisualScriptingGamelogicEngine gle)
60+
{
61+
var data = PackageApi.Packer.Unpack<VisualScriptingGamelogicEnginePackable>(bytes);
62+
gle.TableVariableDefinitions = data.TableVariableDefinitions ?? new List<TableVariableDefinition>();
63+
gle.PlayerVariableDefinitions = data.PlayerVariableDefinitions ?? new List<PlayerVariableDefinition>();
64+
gle.EventDefinitions = data.EventDefinitions ?? new List<EventDefinition>();
65+
gle.Displays = data.Displays ?? Array.Empty<DisplayDefinition>();
66+
gle.Switches = data.Switches ?? Array.Empty<VisualScriptingSwitch>();
67+
gle.Coils = data.Coils ?? Array.Empty<VisualScriptingCoil>();
68+
gle.Lamps = data.Lamps ?? Array.Empty<VisualScriptingLamp>();
69+
gle.Wires = data.Wires ?? Array.Empty<GamelogicEngineWire>();
70+
}
71+
}
72+
}

Runtime/Packaging/VisualScriptingGamelogicEnginePackable.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)