Repository navigation
Player plugin system, native outputs and shared native windows - #588
Merged
Merged
Conversation
- New ResourceKind.Outputs carries every lamp, solenoid, GI string and mech by the controller's own number, with the value's semantics (binary, levels, physical, position) and maximum, plus a poll-end marker. It is separate from the mapped Controller resource, so role-less controller bindings stay unambiguous. - Gamelogic engines opt in through IGamelogicNativeOutputs; GamelogicPluginResources publishes the outputs resource. - Height-one displays are published as Segments resources with layout and hardware hints. IPluginSegmentSource announces the display's order and element count before the first frame. - Choice, action and validation requests carry the table package (PluginPackageReference), for catalogs that look next to the table.
One native library, VisualPinballNativeWindows (VPNW_ API), extracted from PinUp's desktop output so every plugin can present a Unity render texture in a borderless desktop window: Direct3D11/12 with DirectComposition on Windows, Metal on macOS, Vulkan/X11 on Linux. Sources and fixtures live in Native~/NativeWindows. Binaries are built locally and ignored, like NativeInput. Managed side in VisualPinball.Unity: NativeWindowSurface (placement, z-order, placement mode, diagnostics; reports unsupported instead of throwing when the library is missing) and NativeWindowHost, one shared presenter issuing a draw/present event pair per frame and draining deferred GPU releases.
Groups native sources under a VisualPinball-prefixed folder that Unity still ignores, since the package root is the repository root.
|
…ents - An unresponsive or emergency-stopped plugin keeps its scopes (native handles, device leases) until its running hooks and Quiescence have finished, instead of losing them while its worker still runs. Such instances are quarantined and block a new instance of the plugin until they have drained. The host tracks every running lifecycle hook per instance for this. - The identification display encoding is chosen from what the consumer accepts. A later consumer must accept the encoding already delivered. - A successful settings apply keeps edits made while it was running, instead of reverting them to the saved profile. - Segment sources announce their layout and hardware with their order and size. - The packaged game identity cache compares paths ordinally, so case-distinct files on Linux no longer share an entry. - The macOS native window keeps its drawable at the window's pixel size after a resize or display change.
Every public type and member of the plugin API now has XML documentation saying what it is for, with a use case from the Player, PinUP, B2S, DMD or PinMAME integrations, examples for what plugins implement or call, and the threading, lifetime and ownership rules. This covers the descriptors and runtime hooks, the configuration schema, store and global settings, the runtime helpers, the resource registry and display sources, the Unity plugin contracts and the native window service. One-line enums and interfaces are split over several lines so that each member can carry its own comment; no code changed.
XML documentation for the resource contracts (kinds, descriptors, selections, controller, display, segment, audio and surface payloads), the ready-made signal sources, the plugin host and its quarantine rules, settings sessions and packaged game identification. One-line enums and interfaces are split so each member can carry its own comment; no code changed.
A binding refused because another consumer holds a raw identification encoding it cannot read now retries as soon as that lease ends, instead of staying blocked until the game restarts. - DisplayFormatNegotiator signals when its last identification lease is released. - The gamelogic bridge forwards that through the new PluginResourceRegistry.NotifyChanged, which raises ResourceChangeKind.Changed. - Bindings guard against re-entrant refreshes. A notice caused by releasing a binding's own view does not retry the same attempt, and a binding disposed from a notification stays disposed.
…bridge XML documentation for the resource registry and bindings, display format negotiation and the gamelogic resources bridge, including the table of resources a gamelogic engine publishes. No code changed.
…ts view A binding ignored every notice while releasing its view, so a display published or withdrawn during that release left it with stale candidates. Now it only ignores change notices that cannot help it: the one for the resource it is releasing, and those for resources outside its selection, as an engine-wide format lease raises for every display. Publications and withdrawals always trigger another pass.
- Mapped lamp events on the controller resource now carry what their raw values mean. The rules come from the table's lamp mapping, the same ones LampPlayer applies: on/off lamps are binary, fading lamps run to their fading steps, and RGB channels run to 255. Consumers without native outputs, such as a backglass, no longer light faded lamps or GI levels fully. Numeric IDs are registered with and without leading zeros, as LampPlayer does. - A display selection with the presentation intent and a chosen resource ID also matches the presentation views derived from that display, and prefers them. A display picked by hand keeps its colorization.
Wheel zoom-out multiplied the radius without an upper bound, sending the camera to float-precision distances where SendMouseEvents fails with "Screen position out of view frustum".
CabinetScreenComponent marks a renderer as the backglass, topper, DMD, full DMD or a custom screen of the cabinet, with an optional root to hide when no plugin provides it. CabinetScreenBinder shows the surface a plugin publishes for the role in the screen's material slot, picking among providers by a preference order. A DMD screen only shows a plugin's DMD when the gamelogic engine announces none. SurfaceRoles lists the well-known role names.
PluginField.Multiple lets a choice field pick any number of catalog items, stored as a list of IDs, validated and checked against the catalog like single choices. PluginSettingsSnapshot.Strings reads such lists.
Exports only packed whatever an earlier "Generate Screenshot" had left behind, so a removed screenshot folder silently produced packages without table images, and stale ones shipped otherwise. The export runner now renders them first, dropping old and partial ones, and asks before exporting without them. Screenshots are always lit with the bundled studio HDRI at exposure 4.5; the HDRI the default pointed to had never been committed. The camera's aspect is set to the portrait render target before framing, since its gate-fitted field of view otherwise followed the Game view and shrank the table.
Hybrid inserts show their authored intensity outside play mode and were never switched, so the lights-on and lights-off shots came out the same. The generator now drives every insert, including its extra bulbs, on for the lights-on shot and off otherwise, restoring them afterwards. GI, bulbs and flashers stay off in all shots.
Coil mappings are resolved to the insert bulbs they drive, directly by bulb, through a lamp above the insert, or per group member, and those bulbs stay off in the lights-on shot.
The orphan group pass picked up the spill lights and meshes of inserts parented under a light group and switched them off in the lights-on shot, overriding the insert pass.
A lamp above an insert drives only its main bulb, and only while no mapping takes that bulb over; extra bulbs follow their own mappings. The screenshot generator now records the bulbs mappings drive directly and applies a flasher lamp above an insert to the main bulb only, so normal bulbs no longer stay dark.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the plugin system the Player uses to load optional integrations (PinUP, DMD, B2S backglasses, …), plus the shared services those plugins need.
Plugin system (
VisualPinball.Plugins, MIT)Native outputs and segment displays
ResourceKind.Outputscarries every lamp, solenoid, GI string and mech by the controller's own number, with its value semantics (binary, levels, physical, position) and a poll-end marker. It is separate from the mappedControllerresource, so role-less controller bindings stay unambiguous.IGamelogicNativeOutputs.Segmentsresources. Each announces its layout, order and element count before its first frame.PluginPackageReference).Shared native windows
VisualPinballNativeWindows(VPNW_API), presents a Unity render texture in a borderless desktop window:VisualPinball.Native~/NativeWindows. Binaries are built locally and gitignored, like NativeInput's; only their.metafiles are committed.VisualPinball.UnitygetsNativeWindowSurfaceand a sharedNativeWindowHostpresenter.Other
Related PRs
All of these are on the
feat/player-pluginsbranch: