Add an engine-free capability event contract
Fork L (docs/headless-playground-cut.md): pickup, impact absorption, melee blade and propulsion are separate item capabilities that a future simulation will own; presentations subscribe and decide nothing. This stands up the wire shape only -- AbsorbEvent/GrabEvent/MeleeEvent/ThrustEvent plus a per-entity CapabilityEvents source (UniRx Subject<T> per kind, matching the idiom already used on Entity) -- with no publisher wired up yet. Compiles into the headless Aetheria.Shared build with no Unity dependency. AbsorbEvent carries the hit's DamageType (operator, 2026-09-17) so a future presenter can vary visuals per type; the damage-type mask itself belongs to the absorb capability's own data and is out of scope here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
47131ded68
commit
fdea06f27f
2 changed files with 135 additions and 0 deletions
124
Assets/Scripts/ServerShared/CapabilityEvents.cs
Normal file
124
Assets/Scripts/ServerShared/CapabilityEvents.cs
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
using System;
|
||||
using UniRx;
|
||||
using CultMath;
|
||||
|
||||
// Capability event contract (docs/headless-playground-cut.md fork L, operator ruling 2026-09-17):
|
||||
// pickup, impact absorption, melee blade and propulsion are separate item capabilities. Simulation
|
||||
// (not yet built -- this file only stands up the wire shape) will own each capability's rules and
|
||||
// emit these events; any number of presentations (the field shield today, later an IFS shatter
|
||||
// plane or an advected particle field) subscribe to the event kinds they visualize and decide
|
||||
// nothing about the rule. This file has no engine dependency: it compiles into the headless
|
||||
// Aetheria.Shared build (see Aetheria.Shared.csproj) with no publisher wired up yet.
|
||||
|
||||
// One absorbed impact: a hit landing on the item's shield/armor capability. DamageType rides along
|
||||
// so presenters can vary visuals per type; the damage-type mask itself belongs to the absorb
|
||||
// capability's own data and is out of scope for this cut (operator, 2026-09-17) -- this struct only
|
||||
// carries the hit's existing type through, unfiltered.
|
||||
public readonly struct AbsorbEvent
|
||||
{
|
||||
public readonly float3 Position;
|
||||
public readonly float3 Direction;
|
||||
public readonly float Magnitude;
|
||||
public readonly DamageType DamageType;
|
||||
|
||||
public AbsorbEvent(float3 position, float3 direction, float magnitude, DamageType damageType)
|
||||
{
|
||||
Position = position;
|
||||
Direction = direction;
|
||||
Magnitude = magnitude;
|
||||
DamageType = damageType;
|
||||
}
|
||||
}
|
||||
|
||||
// A timed grab's lifecycle (docs fork L: "a pickup is a timed grab of a selected item in range:
|
||||
// extend, envelop, pull"), generalized to any item capability that reaches out and returns with
|
||||
// something.
|
||||
public enum GrabPhase
|
||||
{
|
||||
Started,
|
||||
Extend,
|
||||
Envelop,
|
||||
Pull,
|
||||
Completed,
|
||||
Cancelled
|
||||
}
|
||||
|
||||
// The target is identified by a plain handle, not a Unity type: the simulation will own the real
|
||||
// target identity (a loot drop or item instance id) once the pickup capability exists. Today's only
|
||||
// publisher (the FieldShieldTest scene) hands out its own handles; nothing here interprets them.
|
||||
public readonly struct GrabEvent
|
||||
{
|
||||
public readonly int TargetHandle;
|
||||
public readonly GrabPhase Phase;
|
||||
public readonly float3 TargetPosition;
|
||||
public readonly float PhaseDuration;
|
||||
|
||||
public GrabEvent(int targetHandle, GrabPhase phase, float3 targetPosition, float phaseDuration)
|
||||
{
|
||||
TargetHandle = targetHandle;
|
||||
Phase = phase;
|
||||
TargetPosition = targetPosition;
|
||||
PhaseDuration = phaseDuration;
|
||||
}
|
||||
}
|
||||
|
||||
// One melee swing.
|
||||
public readonly struct MeleeEvent
|
||||
{
|
||||
public readonly float3 Direction;
|
||||
public readonly float Range;
|
||||
public readonly float Arc;
|
||||
public readonly float Duration;
|
||||
|
||||
public MeleeEvent(float3 direction, float range, float arc, float duration)
|
||||
{
|
||||
Direction = direction;
|
||||
Range = range;
|
||||
Arc = arc;
|
||||
Duration = duration;
|
||||
}
|
||||
}
|
||||
|
||||
// One frame of propulsion input. Twist is packed as a float2 (x: front, y: rear) rather than a
|
||||
// single scalar, mirroring the existing FieldDriver split between front and rear turn effect;
|
||||
// Throttle is carried separately from the planar thrust vector for presentations that want overall
|
||||
// engine intensity independent of direction (the field shield presentation does not use it today).
|
||||
public readonly struct ThrustEvent
|
||||
{
|
||||
public readonly float2 PlanarThrust;
|
||||
public readonly float Throttle;
|
||||
public readonly float2 Twist;
|
||||
|
||||
public ThrustEvent(float2 planarThrust, float throttle, float2 twist)
|
||||
{
|
||||
PlanarThrust = planarThrust;
|
||||
Throttle = throttle;
|
||||
Twist = twist;
|
||||
}
|
||||
}
|
||||
|
||||
// Per-entity (or per-item) source of capability events. One instance is owned by whatever will
|
||||
// eventually decide these rules; today the FieldShieldTest scene stands in for that owner. Follows
|
||||
// the Subject<T>-per-event-kind idiom already used on Entity (IncomingHit, HullDamage, etc): each
|
||||
// event kind gets its own stream, and a subscriber to one kind never sees another.
|
||||
public class CapabilityEvents
|
||||
{
|
||||
private readonly Subject<AbsorbEvent> _absorb = new Subject<AbsorbEvent>();
|
||||
private readonly Subject<GrabEvent> _grab = new Subject<GrabEvent>();
|
||||
private readonly Subject<MeleeEvent> _melee = new Subject<MeleeEvent>();
|
||||
private readonly Subject<ThrustEvent> _thrust = new Subject<ThrustEvent>();
|
||||
|
||||
public UniRx.IObservable<AbsorbEvent> Absorb => _absorb;
|
||||
public UniRx.IObservable<GrabEvent> Grab => _grab;
|
||||
public UniRx.IObservable<MeleeEvent> Melee => _melee;
|
||||
public UniRx.IObservable<ThrustEvent> Thrust => _thrust;
|
||||
|
||||
public void PublishAbsorb(AbsorbEvent e) => _absorb.OnNext(e);
|
||||
public void PublishGrab(GrabEvent e) => _grab.OnNext(e);
|
||||
public void PublishMelee(MeleeEvent e) => _melee.OnNext(e);
|
||||
public void PublishThrust(ThrustEvent e) => _thrust.OnNext(e);
|
||||
}
|
||||
11
Assets/Scripts/ServerShared/CapabilityEvents.cs.meta
Normal file
11
Assets/Scripts/ServerShared/CapabilityEvents.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f0e6d83e34144ce89bfbc7ef778f10a6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in a new issue