Lower advertised held input values
This commit is contained in:
parent
f6fb8a5b17
commit
140e1bd963
11 changed files with 317 additions and 21 deletions
|
|
@ -192,6 +192,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
WitnessReceipt lookReceipt = null;
|
||||
WitnessReceipt focusReceipt = null;
|
||||
WitnessReceipt tractorReceipt = null;
|
||||
WitnessReceipt tractorReleaseReceipt = null;
|
||||
WitnessReceipt actionReceipt = null;
|
||||
EveUnityShotReceipt observedShot = null;
|
||||
EveUnityCombatPresentation observedCombat = null;
|
||||
|
|
@ -202,6 +203,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
float aimDotDistance = 0f;
|
||||
int cockpitProgressCount = 0;
|
||||
float tractorBeamPower = 0f;
|
||||
float tractorReleasedPower = 1f;
|
||||
int tractorBeamParticleSystemCount = 0;
|
||||
|
||||
try
|
||||
|
|
@ -385,7 +387,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
Assert.That(beamPresentation.ActivationActionId, Is.Not.Empty,
|
||||
"The beam presentation does not name an advertised generic action.");
|
||||
var tractorVersion = runtime.ActiveVersion;
|
||||
var tractor = host.SubmitAdvertisedActionIntent(playerId, beamPresentation.ActivationActionId);
|
||||
var tractor = host.SubmitAdvertisedActionValueIntent(playerId, beamPresentation.ActivationActionId, 1f);
|
||||
var tractorDeadline = Time.realtimeSinceStartup + 12f;
|
||||
while (Time.realtimeSinceStartup < tractorDeadline &&
|
||||
(runtime.LastReceipt == null || runtime.LastReceipt.CommandId != tractor.CommandId ||
|
||||
|
|
@ -600,6 +602,29 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(mapCapturePath)));
|
||||
File.WriteAllBytes(mapCapturePath, pixels.EncodeToPNG());
|
||||
Assert.That(new FileInfo(mapCapturePath).Length, Is.GreaterThan(1024));
|
||||
var tractorReleaseVersion = runtime.ActiveVersion;
|
||||
var tractorRelease = host.SubmitAdvertisedActionValueIntent(
|
||||
playerId,
|
||||
beamPresentation.ActivationActionId,
|
||||
0f);
|
||||
var tractorReleaseDeadline = Time.realtimeSinceStartup + 12f;
|
||||
while (Time.realtimeSinceStartup < tractorReleaseDeadline &&
|
||||
(runtime.LastReceipt == null || runtime.LastReceipt.CommandId != tractorRelease.CommandId ||
|
||||
!string.Equals(runtime.LastReceipt.State, "reconciled", StringComparison.OrdinalIgnoreCase) ||
|
||||
runtime.ActiveVersion < runtime.LastReceipt.SourceVersion ||
|
||||
EveUnityBeamPresentation.FindAll(runtime.ActiveProjection).Single().Power >
|
||||
beamPresentation.ActivationThreshold))
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(0.1f);
|
||||
runtime.Refresh();
|
||||
}
|
||||
AssertReconciledProviderReceipt(runtime.LastReceipt, tractorRelease.CommandId,
|
||||
provider.Selection.ProviderId, provider.Selection.SurfaceId, tractorReleaseVersion);
|
||||
tractorReleaseReceipt = WitnessReceipt.From("beam-release", runtime.LastReceipt);
|
||||
beamRenderer.RefreshNow();
|
||||
Assert.That(beamRenderer.TryGetPower(beamPresentation.Id, out tractorReleasedPower), Is.True);
|
||||
Assert.That(tractorReleasedPower, Is.Zero,
|
||||
"Released held input did not return the daemon-authored tractor presentation to zero.");
|
||||
WriteWitnessFacts(
|
||||
initialVersion,
|
||||
runtime.ActiveVersion,
|
||||
|
|
@ -615,6 +640,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
lookReceipt,
|
||||
focusReceipt,
|
||||
tractorReceipt,
|
||||
tractorReleaseReceipt,
|
||||
actionReceipt,
|
||||
observedShot,
|
||||
shieldRatioBefore,
|
||||
|
|
@ -631,6 +657,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
pilotBrightPixelCount,
|
||||
cockpitProgressCount,
|
||||
tractorBeamPower,
|
||||
tractorReleasedPower,
|
||||
tractorBeamParticleSystemCount,
|
||||
playerRendererFacts);
|
||||
}
|
||||
|
|
@ -665,6 +692,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
WitnessReceipt look,
|
||||
WitnessReceipt targeting,
|
||||
WitnessReceipt tractor,
|
||||
WitnessReceipt tractorRelease,
|
||||
WitnessReceipt action,
|
||||
EveUnityShotReceipt shot,
|
||||
float shieldRatioBefore,
|
||||
|
|
@ -681,6 +709,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
int pilotBrightPixelCount,
|
||||
int cockpitProgressCount,
|
||||
float tractorBeamPower,
|
||||
float tractorReleasedPower,
|
||||
int tractorBeamParticleSystemCount,
|
||||
RendererFact[] playerRendererFacts)
|
||||
{
|
||||
|
|
@ -695,6 +724,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
aimPresentation = look != null && aimDotDistance >= 49.9f,
|
||||
targeting = targeting != null,
|
||||
beamPresentation = tractor != null && tractorBeamPower > 0.01f && tractorBeamParticleSystemCount > 0,
|
||||
beamRelease = tractorRelease != null && tractorReleasedPower == 0f,
|
||||
action = action != null,
|
||||
combatPresentation = shot != null,
|
||||
shotId = shot?.ShotId ?? "",
|
||||
|
|
@ -721,13 +751,14 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
pilotBrightPixelCount = pilotBrightPixelCount,
|
||||
cockpitProgressCount = cockpitProgressCount,
|
||||
tractorBeamPower = tractorBeamPower,
|
||||
tractorReleasedPower = tractorReleasedPower,
|
||||
tractorBeamParticleSystemCount = tractorBeamParticleSystemCount,
|
||||
playerRenderers = playerRendererFacts,
|
||||
mapChannelRendererCount = mapChannelRendererCount,
|
||||
mapChangedPixels = mapChangedPixels,
|
||||
pilotCameraExcludesMapChannel = pilotCameraExcludesMapChannel,
|
||||
mapCameraIncludesMapChannel = mapCameraIncludesMapChannel,
|
||||
receipts = new[] { movement, look, targeting, tractor, action }
|
||||
receipts = new[] { movement, look, targeting, tractor, tractorRelease, action }
|
||||
};
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path)));
|
||||
File.WriteAllText(path, JsonUtility.ToJson(document, true));
|
||||
|
|
@ -743,6 +774,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
public bool aimPresentation;
|
||||
public bool targeting;
|
||||
public bool beamPresentation;
|
||||
public bool beamRelease;
|
||||
public bool action;
|
||||
public bool combatPresentation;
|
||||
public string shotId;
|
||||
|
|
@ -769,6 +801,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests
|
|||
public int pilotBrightPixelCount;
|
||||
public int cockpitProgressCount;
|
||||
public float tractorBeamPower;
|
||||
public float tractorReleasedPower;
|
||||
public int tractorBeamParticleSystemCount;
|
||||
public RendererFact[] playerRenderers;
|
||||
public int mapChannelRendererCount;
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
"dependencies": {
|
||||
"org.gamecult.cultlib": "1.0.13",
|
||||
"org.gamecult.eve.plugin-fields": "0.1.1",
|
||||
"org.gamecult.eve.surface": "0.2.1",
|
||||
"org.gamecult.eve.surface": "0.2.2",
|
||||
"com.unity.mathematics": "1.3.2",
|
||||
"com.unity.modules.particlesystem": "1.0.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,14 @@ namespace GameCult.Eve.Surface
|
|||
[Key(5)] public string Availability { get; set; } = "available";
|
||||
[Key(6)] public string SourceRef { get; set; } = "";
|
||||
[Key(7)] public Dictionary<string, string> Payload { get; set; } = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||
[Key(8)] public EveInputValueDocument? InputValue { get; set; }
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed class EveInputValueDocument
|
||||
{
|
||||
[Key(0)] public string Model { get; set; } = "";
|
||||
[Key(1)] public string PayloadKey { get; set; } = "";
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "org.gamecult.eve.surface",
|
||||
"displayName": "Eve Surface Contract",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.2",
|
||||
"unity": "2021.3",
|
||||
"description": "Unity-compatible DTOs for gamecult.eve.surface.v1 documents.",
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using GameCult.Eve.Surface;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace GameCult.Eve.UnityScene
|
||||
{
|
||||
public sealed class EveUnityAdvertisedInputAction
|
||||
{
|
||||
public const string ButtonHoldValueModel = "button-hold.v1";
|
||||
public const string AxisValueModel = "axis.v1";
|
||||
|
||||
private readonly EveInputActionDocument _action;
|
||||
|
||||
private EveUnityAdvertisedInputAction(EveInputActionDocument action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public string ActionId => _action.ActionId ?? "";
|
||||
public string Operation => _action.Operation ?? "";
|
||||
public string Availability => _action.Availability ?? "";
|
||||
public string InputValueModel => _action.InputValue?.Model ?? "";
|
||||
public string InputValuePayloadKey => _action.InputValue?.PayloadKey ?? "";
|
||||
public bool IsButtonHold => string.Equals(InputValueModel, ButtonHoldValueModel, StringComparison.Ordinal);
|
||||
|
||||
public static EveUnityAdvertisedInputAction Resolve(EveInputCapabilityDocument? capability, string actionId)
|
||||
{
|
||||
if (capability == null)
|
||||
throw new InvalidOperationException("The provider did not advertise an input capability.");
|
||||
var action = (capability.Actions ?? Array.Empty<EveInputActionDocument>()).FirstOrDefault(candidate =>
|
||||
string.Equals(candidate?.ActionId, actionId, StringComparison.Ordinal));
|
||||
if (action == null || string.IsNullOrWhiteSpace(action.Operation))
|
||||
throw new InvalidOperationException($"Input action '{actionId}' is not advertised with an operation.");
|
||||
if (!string.Equals(action.Availability, "available", StringComparison.OrdinalIgnoreCase))
|
||||
throw new InvalidOperationException($"Input action '{actionId}' is not available.");
|
||||
return new EveUnityAdvertisedInputAction(action);
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, string> BuildPayload(string entityId, float? inputValue = null)
|
||||
{
|
||||
var payload = _action.Payload == null
|
||||
? new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
: new Dictionary<string, string>(_action.Payload, StringComparer.Ordinal);
|
||||
payload["entityId"] = entityId ?? "";
|
||||
payload["actionId"] = ActionId;
|
||||
|
||||
if (inputValue.HasValue)
|
||||
{
|
||||
if (float.IsNaN(inputValue.Value) || float.IsInfinity(inputValue.Value))
|
||||
throw new ArgumentOutOfRangeException(nameof(inputValue), "Input action value must be finite.");
|
||||
if (string.IsNullOrWhiteSpace(InputValueModel) || string.IsNullOrWhiteSpace(InputValuePayloadKey))
|
||||
throw new InvalidOperationException($"Input action '{ActionId}' does not advertise a value payload.");
|
||||
payload[InputValuePayloadKey] = inputValue.Value.ToString("R", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c7555b03e7f9451aa891e92958b845c5
|
||||
|
|
@ -203,21 +203,21 @@ namespace GameCult.Eve.UnityScene
|
|||
string actionId,
|
||||
DateTimeOffset? issuedAt = null)
|
||||
{
|
||||
var capability = InputCapability ??
|
||||
throw new InvalidOperationException("The provider did not advertise an input capability.");
|
||||
var action = Array.Find(capability.Actions ?? Array.Empty<EveInputActionDocument>(), candidate =>
|
||||
string.Equals(candidate?.ActionId, actionId, StringComparison.Ordinal));
|
||||
if (action == null || string.IsNullOrWhiteSpace(action.Operation))
|
||||
throw new InvalidOperationException($"Input action '{actionId}' is not advertised with an operation.");
|
||||
if (!string.Equals(action.Availability, "available", StringComparison.OrdinalIgnoreCase))
|
||||
throw new InvalidOperationException($"Input action '{actionId}' is not available.");
|
||||
var action = EveUnityAdvertisedInputAction.Resolve(InputCapability, actionId);
|
||||
return RequireRuntime().SubmitCommandIntent(action.Operation, action.BuildPayload(entityId), issuedAt);
|
||||
}
|
||||
|
||||
var payload = action.Payload == null
|
||||
? new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
: new Dictionary<string, string>(action.Payload, StringComparer.Ordinal);
|
||||
payload["entityId"] = entityId ?? "";
|
||||
payload["actionId"] = action.ActionId;
|
||||
return RequireRuntime().SubmitCommandIntent(action.Operation, payload, issuedAt);
|
||||
public EveSurfaceCommandRequest SubmitAdvertisedActionValueIntent(
|
||||
string entityId,
|
||||
string actionId,
|
||||
float inputValue,
|
||||
DateTimeOffset? issuedAt = null)
|
||||
{
|
||||
var action = EveUnityAdvertisedInputAction.Resolve(InputCapability, actionId);
|
||||
return RequireRuntime().SubmitCommandIntent(
|
||||
action.Operation,
|
||||
action.BuildPayload(entityId, inputValue),
|
||||
issuedAt);
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameCult.Eve.Surface;
|
||||
using UnityEngine;
|
||||
|
|
@ -32,6 +33,10 @@ namespace GameCult.Eve.UnityScene
|
|||
private bool _hasLookYaw;
|
||||
private float _pendingLookHorizontal;
|
||||
private string _lookOwnerKey = "";
|
||||
private readonly Dictionary<string, HeldBindingState> _heldBindings =
|
||||
new Dictionary<string, HeldBindingState>(StringComparer.Ordinal);
|
||||
|
||||
public Func<string, bool?>? DigitalControlReader { get; set; }
|
||||
|
||||
public EveUnityPlayableWorldClientHost? Host
|
||||
{
|
||||
|
|
@ -39,6 +44,7 @@ namespace GameCult.Eve.UnityScene
|
|||
set
|
||||
{
|
||||
if (ReferenceEquals(host, value)) return;
|
||||
ReleaseHeldActions();
|
||||
host = value;
|
||||
ResetLookState();
|
||||
}
|
||||
|
|
@ -105,6 +111,21 @@ namespace GameCult.Eve.UnityScene
|
|||
resolvedActionId);
|
||||
}
|
||||
|
||||
public EveSurfaceCommandRequest? SubmitActionValue(
|
||||
string actionId,
|
||||
float inputValue,
|
||||
DateTimeOffset? issuedAt = null)
|
||||
{
|
||||
var resolvedHost = ResolveHost();
|
||||
if (resolvedHost?.ActiveWorld == null || string.IsNullOrWhiteSpace(actionId))
|
||||
return null;
|
||||
return resolvedHost.SubmitAdvertisedActionValueIntent(
|
||||
resolvedHost.ActiveWorld.PlayerEntityId,
|
||||
actionId,
|
||||
inputValue,
|
||||
issuedAt);
|
||||
}
|
||||
|
||||
public EveSurfaceCommandRequest? SubmitLookInput(
|
||||
float horizontalDelta,
|
||||
DateTimeOffset? issuedAt = null)
|
||||
|
|
@ -178,11 +199,98 @@ namespace GameCult.Eve.UnityScene
|
|||
_nextCommandAt = Time.unscaledTime + Math.Max(0.01f, commandIntervalSeconds);
|
||||
SubmitMoveVectorInput(Input.GetAxisRaw(horizontalAxis), Input.GetAxisRaw(verticalAxis));
|
||||
SubmitPendingLookInput();
|
||||
SubmitChangedHeldActions();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(actionButton) && Input.GetButtonDown(actionButton))
|
||||
SubmitPrimaryAction();
|
||||
}
|
||||
|
||||
private void SubmitChangedHeldActions()
|
||||
{
|
||||
var resolvedHost = ResolveHost();
|
||||
var capability = resolvedHost?.InputCapability;
|
||||
if (resolvedHost?.ActiveWorld == null || capability == null)
|
||||
return;
|
||||
|
||||
var profile = (capability.DefaultProfiles ?? Array.Empty<EveInputProfileDocument>())
|
||||
.FirstOrDefault(value => string.Equals(value.DeviceClass, "keyboard-mouse", StringComparison.Ordinal));
|
||||
var retained = new HashSet<string>(StringComparer.Ordinal);
|
||||
foreach (var binding in profile?.Bindings ?? Array.Empty<EveInputBindingDocument>())
|
||||
{
|
||||
var action = (capability.Actions ?? Array.Empty<EveInputActionDocument>())
|
||||
.FirstOrDefault(candidate => string.Equals(candidate.ActionId, binding.ActionId, StringComparison.Ordinal));
|
||||
if (action?.InputValue == null ||
|
||||
!string.Equals(action.InputValue.Model, EveUnityAdvertisedInputAction.ButtonHoldValueModel, StringComparison.Ordinal) ||
|
||||
!TryReadDigitalGesture(binding.Gesture, out var pressed))
|
||||
continue;
|
||||
|
||||
var stateKey = string.IsNullOrWhiteSpace(binding.BindingId) ? binding.ActionId : binding.BindingId;
|
||||
retained.Add(stateKey);
|
||||
if (!_heldBindings.TryGetValue(stateKey, out var previous))
|
||||
{
|
||||
_heldBindings[stateKey] = new HeldBindingState(binding.ActionId, pressed);
|
||||
if (pressed) SubmitActionValue(binding.ActionId, 1f);
|
||||
continue;
|
||||
}
|
||||
if (previous.Pressed == pressed) continue;
|
||||
_heldBindings[stateKey] = new HeldBindingState(binding.ActionId, pressed);
|
||||
SubmitActionValue(binding.ActionId, pressed ? 1f : 0f);
|
||||
}
|
||||
|
||||
foreach (var stale in _heldBindings.Keys.Where(key => !retained.Contains(key)).ToArray())
|
||||
{
|
||||
var previous = _heldBindings[stale];
|
||||
if (previous.Pressed) TrySubmitRelease(previous.ActionId);
|
||||
_heldBindings.Remove(stale);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryReadDigitalGesture(EveInputGestureDocument? gesture, out bool pressed)
|
||||
{
|
||||
pressed = false;
|
||||
if (gesture == null ||
|
||||
!(string.Equals(gesture.Kind, "direct", StringComparison.Ordinal) ||
|
||||
string.Equals(gesture.Kind, "chord", StringComparison.Ordinal)))
|
||||
return false;
|
||||
var controls = gesture.Controls ?? Array.Empty<string>();
|
||||
if (controls.Length == 0) return false;
|
||||
foreach (var control in controls)
|
||||
{
|
||||
var value = DigitalControlReader?.Invoke(control) ?? ReadStandardDigitalControl(control);
|
||||
if (!value.HasValue) return false;
|
||||
if (!value.Value) return true;
|
||||
}
|
||||
pressed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool? ReadStandardDigitalControl(string control)
|
||||
{
|
||||
if (string.Equals(control, "mouse.primary", StringComparison.Ordinal)) return Input.GetMouseButton(0);
|
||||
if (string.Equals(control, "mouse.secondary", StringComparison.Ordinal)) return Input.GetMouseButton(1);
|
||||
if (string.Equals(control, "mouse.middle", StringComparison.Ordinal)) return Input.GetMouseButton(2);
|
||||
const string keyboardPrefix = "keyboard.";
|
||||
if (control != null && control.StartsWith(keyboardPrefix, StringComparison.Ordinal) &&
|
||||
Enum.TryParse(control.Substring(keyboardPrefix.Length), true, out KeyCode key))
|
||||
return Input.GetKey(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnDisable() => ReleaseHeldActions();
|
||||
|
||||
private void ReleaseHeldActions()
|
||||
{
|
||||
foreach (var state in _heldBindings.Values)
|
||||
if (state.Pressed) TrySubmitRelease(state.ActionId);
|
||||
_heldBindings.Clear();
|
||||
}
|
||||
|
||||
private void TrySubmitRelease(string actionId)
|
||||
{
|
||||
try { SubmitActionValue(actionId, 0f); }
|
||||
catch (InvalidOperationException) { }
|
||||
}
|
||||
|
||||
private EveUnityPlayableWorldClientHost? ResolveHost()
|
||||
{
|
||||
if (host != null)
|
||||
|
|
@ -207,6 +315,18 @@ namespace GameCult.Eve.UnityScene
|
|||
_pendingLookHorizontal = 0f;
|
||||
_lookOwnerKey = "";
|
||||
}
|
||||
|
||||
private readonly struct HeldBindingState
|
||||
{
|
||||
public HeldBindingState(string actionId, bool pressed)
|
||||
{
|
||||
ActionId = actionId ?? "";
|
||||
Pressed = pressed;
|
||||
}
|
||||
|
||||
public string ActionId { get; }
|
||||
public bool Pressed { get; }
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct EveUnityPlayableWorldLookDirection
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GameCult.Eve.Surface;
|
||||
using NUnit.Framework;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace GameCult.Eve.UnityScene.Tests
|
||||
{
|
||||
public sealed class EveUnityAdvertisedInputActionTests
|
||||
{
|
||||
[Test]
|
||||
public void HeldValueOverridesAdvertisedPayloadWithoutMutatingCapability()
|
||||
{
|
||||
var sourcePayload = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["scalarValue"] = "0"
|
||||
};
|
||||
var action = EveUnityAdvertisedInputAction.Resolve(new EveInputCapabilityDocument
|
||||
{
|
||||
Actions = new[]
|
||||
{
|
||||
new EveInputActionDocument
|
||||
{
|
||||
ActionId = "pilot.scoop",
|
||||
Operation = "aetheria.daemon.commands.SetTractorPower",
|
||||
Availability = "available",
|
||||
Payload = sourcePayload,
|
||||
InputValue = new EveInputValueDocument
|
||||
{
|
||||
Model = EveUnityAdvertisedInputAction.ButtonHoldValueModel,
|
||||
PayloadKey = "scalarValue"
|
||||
}
|
||||
}
|
||||
}
|
||||
}, "pilot.scoop");
|
||||
|
||||
var pressed = action.BuildPayload("entity.4", 1f);
|
||||
var released = action.BuildPayload("entity.4", 0f);
|
||||
|
||||
Assert.That(action.IsButtonHold, Is.True);
|
||||
Assert.That(pressed["scalarValue"], Is.EqualTo("1"));
|
||||
Assert.That(released["scalarValue"], Is.EqualTo("0"));
|
||||
Assert.That(pressed["entityId"], Is.EqualTo("entity.4"));
|
||||
Assert.That(pressed["actionId"], Is.EqualTo("pilot.scoop"));
|
||||
Assert.That(sourcePayload["scalarValue"], Is.EqualTo("0"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ValueFailsClosedWhenActionDoesNotAdvertiseValueContract()
|
||||
{
|
||||
var action = EveUnityAdvertisedInputAction.Resolve(new EveInputCapabilityDocument
|
||||
{
|
||||
Actions = new[]
|
||||
{
|
||||
new EveInputActionDocument
|
||||
{
|
||||
ActionId = "pilot.dock",
|
||||
Operation = "aetheria.daemon.commands.DockNearest",
|
||||
Availability = "available"
|
||||
}
|
||||
}
|
||||
}, "pilot.dock");
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => action.BuildPayload("entity.4", 1f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a60138c42bf44c2ba38309b21a886c93
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"name": "org.gamecult.eve.unity-scene",
|
||||
"displayName": "Eve Unity Scene Lowering",
|
||||
"version": "0.3.30",
|
||||
"version": "0.3.31",
|
||||
"unity": "2021.3",
|
||||
"description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.",
|
||||
"dependencies": {
|
||||
"org.gamecult.cultlib": "1.0.13",
|
||||
"org.gamecult.eve.plugin-fields": "0.1.1",
|
||||
"org.gamecult.eve.surface": "0.2.1",
|
||||
"org.gamecult.eve.surface": "0.2.2",
|
||||
"com.unity.mathematics": "1.3.2",
|
||||
"com.unity.modules.particlesystem": "1.0.0"
|
||||
},
|
||||
|
|
|
|||
Reference in a new issue