261 lines
10 KiB
C#
261 lines
10 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using AibisDream.Kit;
|
|
using AibisDream.SaveSystem;
|
|
using FMOD;
|
|
using FMOD.Studio;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using NUnit.Framework;
|
|
|
|
namespace AibisDream.SystemEditor.Tests
|
|
{
|
|
public sealed class AudioGlobalParameterSnapshotTests
|
|
{
|
|
[Test]
|
|
public void SetFromYarn_TracksOnlySuccessfulUniqueNames()
|
|
{
|
|
var api = new FakeFmodGlobalParameterApi();
|
|
api.SetByNameResults["missing"] = RESULT.ERR_EVENT_NOTFOUND;
|
|
var registry = new YarnGlobalParameterRegistry(api);
|
|
|
|
Assert.That(registry.SetFromYarn("reverb", 0.4f), Is.EqualTo(RESULT.OK));
|
|
Assert.That(registry.SetFromYarn("REVERB", 0.7f), Is.EqualTo(RESULT.OK));
|
|
Assert.That(
|
|
registry.SetFromYarn("missing", 1f),
|
|
Is.EqualTo(RESULT.ERR_EVENT_NOTFOUND));
|
|
|
|
Assert.That(registry.TrackedNames, Has.Count.EqualTo(1));
|
|
Assert.That(registry.TrackedNames.Single(), Is.EqualTo("reverb"));
|
|
Assert.That(api.SetByNameCalls[0].IgnoreSeekSpeed, Is.False);
|
|
Assert.That(api.SetByNameCalls[1].IgnoreSeekSpeed, Is.False);
|
|
}
|
|
|
|
[Test]
|
|
public void CaptureFinalValues_ReadsFmodFinalValueAndRetainsFailuresForRetry()
|
|
{
|
|
var api = new FakeFmodGlobalParameterApi();
|
|
api.Reads["stage"] = new ParameterRead(9f, 2.37f, RESULT.OK);
|
|
api.Reads["missing"] = new ParameterRead(0f, 0f, RESULT.ERR_EVENT_NOTFOUND);
|
|
var registry = new YarnGlobalParameterRegistry(api);
|
|
registry.SetFromYarn("stage", 9f);
|
|
registry.SetFromYarn("missing", 1f);
|
|
var warnings = new List<string>();
|
|
|
|
var snapshot = registry.CaptureFinalValues(warnings.Add);
|
|
|
|
Assert.That(snapshot, Has.Count.EqualTo(1));
|
|
Assert.That(snapshot["stage"], Is.EqualTo(2.37f));
|
|
Assert.That(snapshot["stage"], Is.Not.EqualTo(9f));
|
|
Assert.That(registry.TrackedNames, Is.EquivalentTo(new[] { "stage", "missing" }));
|
|
Assert.That(warnings, Has.Count.EqualTo(1));
|
|
StringAssert.Contains("missing", warnings[0]);
|
|
}
|
|
|
|
[Test]
|
|
public void ResetToDefaults_RemovesOnlyParametersThatFmodResetSuccessfully()
|
|
{
|
|
var goodId = new PARAMETER_ID { data1 = 1, data2 = 2 };
|
|
var failedId = new PARAMETER_ID { data1 = 3, data2 = 4 };
|
|
var api = new FakeFmodGlobalParameterApi();
|
|
api.Descriptions["good"] = new ParameterDescriptionRead(
|
|
new PARAMETER_DESCRIPTION { id = goodId, defaultvalue = 0.25f },
|
|
RESULT.OK);
|
|
api.Descriptions["failed"] = new ParameterDescriptionRead(
|
|
new PARAMETER_DESCRIPTION { id = failedId, defaultvalue = 0.75f },
|
|
RESULT.OK);
|
|
api.SetByIdResults[failedId] = RESULT.ERR_INVALID_PARAM;
|
|
var registry = new YarnGlobalParameterRegistry(api);
|
|
registry.SetFromYarn("good", 1f);
|
|
registry.SetFromYarn("failed", 1f);
|
|
var warnings = new List<string>();
|
|
|
|
registry.ResetToDefaults(warnings.Add);
|
|
|
|
Assert.That(registry.TrackedNames, Is.EquivalentTo(new[] { "failed" }));
|
|
Assert.That(api.SetByIdCalls, Has.Count.EqualTo(2));
|
|
var goodReset = api.SetByIdCalls.Single(call => call.Id.Equals(goodId));
|
|
Assert.That(goodReset.Value, Is.EqualTo(0.25f));
|
|
Assert.That(goodReset.IgnoreSeekSpeed, Is.True);
|
|
Assert.That(warnings, Has.Count.EqualTo(1));
|
|
StringAssert.Contains("failed", warnings[0]);
|
|
}
|
|
|
|
[Test]
|
|
public void RestoreFinalValues_JumpsImmediatelyThenNextYarnTargetUsesSeekSpeed()
|
|
{
|
|
var api = new FakeFmodGlobalParameterApi();
|
|
api.SetByNameResults["missing"] = RESULT.ERR_EVENT_NOTFOUND;
|
|
var registry = new YarnGlobalParameterRegistry(api);
|
|
var warnings = new List<string>();
|
|
|
|
registry.RestoreFinalValues(
|
|
new Dictionary<string, float>
|
|
{
|
|
["stage"] = 2.37f,
|
|
["missing"] = 1f
|
|
},
|
|
warnings.Add);
|
|
registry.SetFromYarn("stage", 3f);
|
|
|
|
Assert.That(api.SetByNameCalls, Has.Count.EqualTo(3));
|
|
Assert.That(api.SetByNameCalls[0].Value, Is.EqualTo(2.37f));
|
|
Assert.That(api.SetByNameCalls[0].IgnoreSeekSpeed, Is.True);
|
|
Assert.That(api.SetByNameCalls[1].Name, Is.EqualTo("missing"));
|
|
Assert.That(api.SetByNameCalls[1].IgnoreSeekSpeed, Is.True);
|
|
Assert.That(api.SetByNameCalls[2].Value, Is.EqualTo(3f));
|
|
Assert.That(api.SetByNameCalls[2].IgnoreSeekSpeed, Is.False);
|
|
Assert.That(registry.TrackedNames, Is.EquivalentTo(new[] { "stage" }));
|
|
Assert.That(warnings, Has.Count.EqualTo(1));
|
|
StringAssert.Contains("missing", warnings[0]);
|
|
}
|
|
|
|
[Test]
|
|
public void AudioSnapshotDto_RoundTripsFinalValuesWithoutChangingSchema()
|
|
{
|
|
var source = new SaveSnapshot();
|
|
source.sections[SnapshotProviderIds.Audio] = new AudioSnapshotDto
|
|
{
|
|
ambState = "Dream",
|
|
yarnGlobalParameters = new Dictionary<string, float>
|
|
{
|
|
["reverb"] = 0.42f,
|
|
["hs1LogStage"] = 2.37f
|
|
}
|
|
};
|
|
|
|
var json = JsonConvert.SerializeObject(source);
|
|
var restored = JsonConvert.DeserializeObject<SaveSnapshot>(json);
|
|
var audio = ((JObject)restored.sections[SnapshotProviderIds.Audio])
|
|
.ToObject<AudioSnapshotDto>();
|
|
|
|
Assert.That(restored.schemaVersion, Is.EqualTo(2));
|
|
Assert.That(SaveSnapshotSchema.CurrentVersion, Is.EqualTo(2));
|
|
Assert.That(audio.yarnGlobalParameters["reverb"], Is.EqualTo(0.42f));
|
|
Assert.That(audio.yarnGlobalParameters["hs1LogStage"], Is.EqualTo(2.37f));
|
|
}
|
|
|
|
private readonly struct SetByNameCall
|
|
{
|
|
internal SetByNameCall(string name, float value, bool ignoreSeekSpeed)
|
|
{
|
|
Name = name;
|
|
Value = value;
|
|
IgnoreSeekSpeed = ignoreSeekSpeed;
|
|
}
|
|
|
|
internal string Name { get; }
|
|
internal float Value { get; }
|
|
internal bool IgnoreSeekSpeed { get; }
|
|
}
|
|
|
|
private readonly struct SetByIdCall
|
|
{
|
|
internal SetByIdCall(PARAMETER_ID id, float value, bool ignoreSeekSpeed)
|
|
{
|
|
Id = id;
|
|
Value = value;
|
|
IgnoreSeekSpeed = ignoreSeekSpeed;
|
|
}
|
|
|
|
internal PARAMETER_ID Id { get; }
|
|
internal float Value { get; }
|
|
internal bool IgnoreSeekSpeed { get; }
|
|
}
|
|
|
|
private readonly struct ParameterRead
|
|
{
|
|
internal ParameterRead(float value, float finalValue, RESULT result)
|
|
{
|
|
Value = value;
|
|
FinalValue = finalValue;
|
|
Result = result;
|
|
}
|
|
|
|
internal float Value { get; }
|
|
internal float FinalValue { get; }
|
|
internal RESULT Result { get; }
|
|
}
|
|
|
|
private readonly struct ParameterDescriptionRead
|
|
{
|
|
internal ParameterDescriptionRead(
|
|
PARAMETER_DESCRIPTION description,
|
|
RESULT result)
|
|
{
|
|
Description = description;
|
|
Result = result;
|
|
}
|
|
|
|
internal PARAMETER_DESCRIPTION Description { get; }
|
|
internal RESULT Result { get; }
|
|
}
|
|
|
|
private sealed class FakeFmodGlobalParameterApi : IFmodGlobalParameterApi
|
|
{
|
|
internal readonly Dictionary<string, RESULT> SetByNameResults =
|
|
new(System.StringComparer.OrdinalIgnoreCase);
|
|
internal readonly Dictionary<string, ParameterRead> Reads =
|
|
new(System.StringComparer.OrdinalIgnoreCase);
|
|
internal readonly Dictionary<string, ParameterDescriptionRead> Descriptions =
|
|
new(System.StringComparer.OrdinalIgnoreCase);
|
|
internal readonly Dictionary<PARAMETER_ID, RESULT> SetByIdResults = new();
|
|
internal readonly List<SetByNameCall> SetByNameCalls = new();
|
|
internal readonly List<SetByIdCall> SetByIdCalls = new();
|
|
|
|
public RESULT SetParameterByName(
|
|
string name,
|
|
float value,
|
|
bool ignoreSeekSpeed)
|
|
{
|
|
SetByNameCalls.Add(new SetByNameCall(name, value, ignoreSeekSpeed));
|
|
return SetByNameResults.TryGetValue(name, out var result)
|
|
? result
|
|
: RESULT.OK;
|
|
}
|
|
|
|
public RESULT GetParameterByName(
|
|
string name,
|
|
out float value,
|
|
out float finalValue)
|
|
{
|
|
if (Reads.TryGetValue(name, out var read))
|
|
{
|
|
value = read.Value;
|
|
finalValue = read.FinalValue;
|
|
return read.Result;
|
|
}
|
|
|
|
value = 0f;
|
|
finalValue = 0f;
|
|
return RESULT.OK;
|
|
}
|
|
|
|
public RESULT GetParameterDescriptionByName(
|
|
string name,
|
|
out PARAMETER_DESCRIPTION description)
|
|
{
|
|
if (Descriptions.TryGetValue(name, out var read))
|
|
{
|
|
description = read.Description;
|
|
return read.Result;
|
|
}
|
|
|
|
description = default;
|
|
return RESULT.ERR_EVENT_NOTFOUND;
|
|
}
|
|
|
|
public RESULT SetParameterById(
|
|
PARAMETER_ID id,
|
|
float value,
|
|
bool ignoreSeekSpeed)
|
|
{
|
|
SetByIdCalls.Add(new SetByIdCall(id, value, ignoreSeekSpeed));
|
|
return SetByIdResults.TryGetValue(id, out var result)
|
|
? result
|
|
: RESULT.OK;
|
|
}
|
|
}
|
|
}
|
|
}
|