Wwise Audio Integration

This commit is contained in:
Reinier Vens 2021-04-30 06:39:57 +01:00
commit 7d67d7ec2c
72 changed files with 4551 additions and 11819 deletions

View file

@ -39,6 +39,12 @@ public class AetherDriveData : BehaviorData
[Inspectable, JsonProperty("passiveCoupling"), Key(10), RuntimeInspectable]
public PerformanceStat PassiveCoupling;
[InspectableAudioParameter, JsonProperty("rpmAudio"), Key(11), RuntimeInspectable]
public uint RpmAudioParameter;
[InspectableAudioParameter, JsonProperty("torqueAudio"), Key(12), RuntimeInspectable]
public uint TorqueRatioAudioParameter;
public override Behavior CreateInstance(EquippedItem item)
{
@ -119,6 +125,10 @@ public class AetherDrive : Behavior
var torqueRatio = actualRpmDelta / potentialRpmDelta;
var draw = torqueRatio * Evaluate(_data.EnergyDraw) / 3;
Item.SetAudioParameter(SpecialAudioParameter.Intensity, max(max(_axis.x, _axis.y), _axis.z));
Item.SetAudioParameter(_data.RpmAudioParameter, (Rpm.x + Rpm.y + Rpm.z) / 3 / MaximumRpm);
Item.SetAudioParameter(_data.TorqueRatioAudioParameter, max(max(torqueRatio.x, torqueRatio.y), torqueRatio.z));
if (Entity.TryConsumeEnergy((draw.x + draw.y + draw.z)*dt))
{
Rpm += actualRpmDelta;

View file

@ -127,6 +127,7 @@ public class ChargedWeapon : InstantWeapon
if (_charging)
{
_charge += dt / ChargeTime;
Item.SetAudioParameter(SpecialAudioParameter.ChargeLevel, saturate(_charge));
if (!_charged)
{
AddHeat(ChargeHeat * (dt / ChargeTime));
@ -143,6 +144,7 @@ public class ChargedWeapon : InstantWeapon
_coolingDown = true;
_charge = 0;
OnFailed?.Invoke();
Item.FireAudioEvent(ChargedWeaponAudioEvent.Fail);
CauseDamage(_data.FailureDamage);
}
}
@ -154,6 +156,7 @@ public class ChargedWeapon : InstantWeapon
if(!_charging && !_coolingDown)
{
OnStartCharging?.Invoke();
Item.FireAudioEvent(ChargedWeaponAudioEvent.Start);
_charging = true;
_charged = false;
}
@ -169,6 +172,7 @@ public class ChargedWeapon : InstantWeapon
_charge = 0;
}
OnStopCharging?.Invoke();
Item.FireAudioEvent(ChargedWeaponAudioEvent.Stop);
_charging = false;
}
}

View file

@ -165,7 +165,8 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
OnCooldownComplete?.Invoke();
}
}
var firedThisFrame = false;
_burstTimer += dt;
while (_burstRemaining > 0 && _burstTimer > 0)
{
@ -180,6 +181,11 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
_burstRemaining--;
_burstTimer -= _burstInterval;
OnFire?.Invoke();
if(!firedThisFrame)
{
Item.FireAudioEvent(WeaponAudioEvent.Fire);
firedThisFrame = true;
}
CauseWearDamage(1);
AddHeat(Heat);
Entity.VisibilitySources[this] = Visibility;

View file

@ -140,6 +140,8 @@ public class Reactor : Behavior, IOrderedBehavior, IDisposable
CurrentLoadRatio = 1;
}
Item.SetAudioParameter(SpecialAudioParameter.Intensity, max(.25f, 1 - 1 / CurrentLoadRatio));
AddHeat(heat);
return true;
}

View file

@ -72,6 +72,7 @@ public class Thruster : Behavior, IAnalogBehavior
public override bool Execute(float dt)
{
Item.SetAudioParameter(SpecialAudioParameter.Intensity, _input);
if(_input > .01f && Entity.TryConsumeEnergy(_input * Evaluate(_data.EnergyUsage)))
{
Thrust = Evaluate(_data.Thrust);

View file

@ -19,6 +19,9 @@ public class InspectableTextAssetAttribute : PreferredInspectorAttribute { }
public class InspectableTemperatureAttribute : PreferredInspectorAttribute { }
public class InspectableAnimationCurveAttribute : PreferredInspectorAttribute { }
public class InspectableColorAttribute : PreferredInspectorAttribute { }
public class InspectableSoundBankAttribute : PreferredInspectorAttribute { }
public class InspectableAudioParameterAttribute : PreferredInspectorAttribute { }
public class InspectableSchematicShapeAttribute : PreferredInspectorAttribute { }
public class InspectableEnumValuesAttribute : PreferredInspectorAttribute
{

View file

@ -1033,6 +1033,7 @@ public class EquippedItem
private bool _thermalOnline;
private bool _durabilityOnline;
public WwiseMetaSoundBank SoundBank;
public Behavior[] Behaviors { get; }
public Dictionary<int, BehaviorGroup> BehaviorGroups { get; }
@ -1053,6 +1054,10 @@ public class EquippedItem
public ReadOnlyReactiveProperty<bool> Active { get; }
public ItemManager ItemManager { get; }
public Subject<uint> AudioEvents { get; } = new Subject<uint>();
public Subject<(uint id, float v)> AudioParameters { get; } = new Subject<(uint id, float v)>();
public Dictionary<uint, float> AudioParameterValues { get; } = new Dictionary<uint, float>();
public float Temperature
{
get
@ -1062,8 +1067,77 @@ public class EquippedItem
return sum/InsetShape.Coordinates.Length;
}
}
//private bool _online;
public void FireAudioEvent(uint eventId, bool skipVerify = false)
{
if(SoundBank != null && (skipVerify || SoundBank.IncludedEvents.Any(o => o.Id == eventId)))
AudioEvents.OnNext(eventId);
}
public void FireAudioEvent(WwiseSoundBinding soundBinding)
{
FireAudioEvent(soundBinding.PlayEvent);
}
public void PlaySound(WwiseLoopingSoundBinding soundBinding)
{
FireAudioEvent(soundBinding.PlayEvent);
}
public void StopSound(WwiseLoopingSoundBinding soundBinding)
{
FireAudioEvent(soundBinding.StopEvent);
}
public void FireAudioEvent(WeaponAudioEvent weaponAudioEvent)
{
if (SoundBank == null) return;
var eventObject = SoundBank.GetEvent(weaponAudioEvent);
if (eventObject == null)
{
ItemManager.Log($"Attempted to trigger {Enum.GetName(typeof(WeaponAudioEvent), weaponAudioEvent)} weapon audio event, but the soundbank doesn't support it!");
return;
}
FireAudioEvent(eventObject.Id, true);
}
public void FireAudioEvent(ChargedWeaponAudioEvent weaponAudioEvent)
{
if (SoundBank == null) return;
var eventObject = SoundBank.GetEvent(weaponAudioEvent);
if (eventObject == null)
{
ItemManager.Log($"Attempted to trigger {Enum.GetName(typeof(ChargedWeaponAudioEvent), weaponAudioEvent)} weapon audio event, but the soundbank doesn't support it!");
return;
}
FireAudioEvent(eventObject.Id, true);
}
public void SetAudioParameter(uint id, float v, bool skipVerify = false)
{
if (SoundBank != null && (skipVerify || SoundBank.GameParameters.Any(o => o.Id == id)))
{
AudioParameterValues[id] = v;
AudioParameters.OnNext((id, v));
}
}
// public void SetAudioParameter(WwiseParameterBinding binding)
// {
// FireAudioEvent(binding.Parameter);
// }
public void SetAudioParameter(SpecialAudioParameter p, float v)
{
if (SoundBank == null) return;
var metaObject = SoundBank.GetParameter(p);
if (metaObject == null)
{
ItemManager.Log($"Attempted to set {Enum.GetName(typeof(ChargedWeaponAudioEvent), p)} audio parameter, but the soundbank doesn't support it!");
return;
}
SetAudioParameter(metaObject.Id, v, true);
}
public EquippedItem(ItemManager itemManager, EquippableItem item, int2 position, Entity entity)
{
@ -1152,6 +1226,11 @@ public class EquippedItem
public void Update(float delta)
{
foreach (var audioStat in Data.AudioStats)
{
SetAudioParameter(audioStat.Parameter, Evaluate(audioStat.Stat));
}
if (Active.Value)
{
foreach (var group in BehaviorGroups.Values)

View file

@ -170,4 +170,32 @@ public enum TemperatureUnit
Kelvin,
Celsius,
Fahrenheit
}
public enum WeaponAudioEvent
{
Fire,
Hit,
Miss
}
public enum ChargedWeaponAudioEvent
{
Start,
Stop,
Fail
}
public enum SpecialAudioParameter
{
ShipVelocity,
ChargeLevel,
TargetLock,
Intensity,
}
public enum LoopingAudioEvent
{
Play,
Stop
}

View file

@ -234,7 +234,7 @@ public abstract class ItemData : DatabaseEntry, INamedEntry
[Inspectable, JsonProperty("mass"), Key(4)]
public float Mass;
[Inspectable, JsonProperty("shape"), Key(5)]
[InspectableSchematicShape, JsonProperty("shape"), Key(5)]
public Shape Shape;
// Heat needed to change temperature of 1 gram by 1 degree
@ -347,11 +347,17 @@ public abstract class EquippableItemData : CraftedItemData
[Inspectable, JsonProperty("resilience"), Key(18)]
public float ThermalResilience = 1;
[Inspectable, JsonProperty("sfx"), Key(19)]
public string SoundEffectTrigger;
// [Inspectable, JsonProperty("sfx"), Key(19)]
// public string SoundEffectTrigger;
[InspectableTexture, JsonProperty("actionIcon"), Key(20)]
public string ActionBarIcon;
[InspectableSoundBank, JsonProperty("soundBank"), Key(21)]
public uint SoundBank;
[Inspectable, JsonProperty("audioStats"), Key(22)]
public List<AudioStat> AudioStats = new List<AudioStat>();
[IgnoreMember]
public abstract HardpointType HardpointType { get; }
@ -391,10 +397,20 @@ public abstract class EquippableItemData : CraftedItemData
}
}
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class AudioStat
{
[InspectableAudioParameter, JsonProperty("parameter"), Key(0)]
public uint Parameter;
[Inspectable, JsonProperty("stat"), Key(1)]
public PerformanceStat Stat = new PerformanceStat();
}
[RethinkTable("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class GearData : EquippableItemData
{
[Inspectable, JsonProperty("hardpointType"), Key(21)]
[Inspectable, JsonProperty("hardpointType"), Key(23)]
public HardpointType Hardpoint;
[IgnoreMember] public override HardpointType HardpointType => Hardpoint;
@ -403,56 +419,57 @@ public class GearData : EquippableItemData
[RethinkTable("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class CargoBayData : EquippableItemData
{
[Inspectable, JsonProperty("interiorShape"), Key(21)]
[Inspectable, JsonProperty("interiorShape"), Key(24)]
public Shape InteriorShape;
[IgnoreMember] public override HardpointType HardpointType => HardpointType.Tool;
}
[RethinkTable("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class DockingBayData : CargoBayData
{
[Inspectable, JsonProperty("maxSize"), Key(22)]
[Inspectable, JsonProperty("maxSize"), Key(25)]
public int2 MaxSize;
}
[RethinkTable("Items"), MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class WeaponItemData : GearData
{
[Inspectable, JsonProperty("range"), Key(22)]
[Inspectable, JsonProperty("range"), Key(24)]
public WeaponRange WeaponRange;
[Inspectable, JsonProperty("caliber"), Key(23)]
[Inspectable, JsonProperty("caliber"), Key(25)]
public WeaponCaliber WeaponCaliber;
[Inspectable, JsonProperty("weaponType"), Key(24)]
[Inspectable, JsonProperty("weaponType"), Key(26)]
public WeaponType WeaponType;
[Inspectable, JsonProperty("fireTypes"), Key(25)]
[Inspectable, JsonProperty("fireTypes"), Key(27)]
public WeaponFireType WeaponFireTypes;
[Inspectable, JsonProperty("modifiers"), Key(26)]
[Inspectable, JsonProperty("modifiers"), Key(28)]
public WeaponModifiers WeaponModifiers;
}
[RethinkTable("Items"), Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class HullData : EquippableItemData
{
[Inspectable, JsonProperty("hardpoints"), Key(21)]
[Inspectable, JsonProperty("hardpoints"), Key(23)]
public List<HardpointData> Hardpoints = new List<HardpointData>();
[InspectablePrefab, JsonProperty("prefab"), Key(22)]
[InspectablePrefab, JsonProperty("prefab"), Key(24)]
public string Prefab;
[Inspectable, JsonProperty("hullType"), Key(23)]
[Inspectable, JsonProperty("hullType"), Key(25)]
public HullType HullType;
[Inspectable, JsonProperty("gridOffset"), Key(24)]
[Inspectable, JsonProperty("gridOffset"), Key(26)]
public float GridOffset;
[Inspectable, JsonProperty("armor"), Key(25)]
[Inspectable, JsonProperty("armor"), Key(27)]
public float Armor;
[Inspectable, JsonProperty("drag"), Key(26)]
[Inspectable, JsonProperty("drag"), Key(28)]
public float Drag;
[IgnoreMember]

View file

@ -13,7 +13,7 @@ using Unity.Mathematics;
Union(1, typeof(LoginMessage)),
Union(2, typeof(RegisterMessage)),
Union(3, typeof(VerifyMessage)),
Union(4, typeof(ErrorMessage)),
Union(4, typeof(NetErrorMessage)),
Union(5, typeof(LoginSuccessMessage)),
Union(6, typeof(ChatMessage)),
Union(7, typeof(ChatBroadcastMessage)),
@ -53,7 +53,7 @@ public class VerifyMessage : Message
}
[MessagePackObject]
public class ErrorMessage : Message
public class NetErrorMessage : Message
{
[Key(0)] public string Error;
}

View file

@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
[JsonObject]
public class WwiseMetadataFile
{
public WwiseMetaSoundBanksInfo SoundBanksInfo;
}
[JsonObject]
public class WwiseMetaSoundBanksInfo
{
public WwiseMetaSoundBank[] SoundBanks;
private Dictionary<uint, WwiseMetaSoundBank> _soundBanks;
public WwiseMetaSoundBank GetSoundBank(uint id)
{
if (_soundBanks == null) _soundBanks = SoundBanks.ToDictionary(sb => sb.Id);
return _soundBanks[id];
}
}
[JsonObject]
public class WwiseMetaSoundBank
{
public uint Id;
public string ShortName;
public WwiseMetaObject[] IncludedEvents;
public WwiseMetaObject[] GameParameters;
public WwiseMetaObject GetEvent(WeaponAudioEvent weaponAudioEvent)
{
return weaponAudioEvent switch
{
WeaponAudioEvent.Fire => IncludedEvents?.FirstOrDefault(e => e.Name.EndsWith("_fire")),
WeaponAudioEvent.Hit => IncludedEvents?.FirstOrDefault(e => e.Name.EndsWith("_hit")),
WeaponAudioEvent.Miss => IncludedEvents?.FirstOrDefault(e => e.Name.EndsWith("_miss")),
_ => throw new ArgumentOutOfRangeException(nameof(weaponAudioEvent), weaponAudioEvent, null)
};
}
public WwiseMetaObject GetEvent(ChargedWeaponAudioEvent chargedWeaponAudioEvent)
{
return chargedWeaponAudioEvent switch
{
ChargedWeaponAudioEvent.Start => IncludedEvents?.FirstOrDefault(e => e.Name.EndsWith("_charge_play")),
ChargedWeaponAudioEvent.Stop => IncludedEvents?.FirstOrDefault(e => e.Name.EndsWith("_charge_stop")),
ChargedWeaponAudioEvent.Fail => IncludedEvents?.FirstOrDefault(e => e.Name.EndsWith("_fail")),
_ => throw new ArgumentOutOfRangeException(nameof(chargedWeaponAudioEvent), chargedWeaponAudioEvent, null)
};
}
public WwiseMetaObject GetEvent(LoopingAudioEvent loopingAudioEvent)
{
return loopingAudioEvent switch
{
LoopingAudioEvent.Play => IncludedEvents?.FirstOrDefault(e => e.Name.EndsWith("_play")),
LoopingAudioEvent.Stop => IncludedEvents?.FirstOrDefault(e => e.Name.EndsWith("_stop")),
_ => throw new ArgumentOutOfRangeException(nameof(loopingAudioEvent), loopingAudioEvent, null)
};
}
public WwiseMetaObject GetParameter(SpecialAudioParameter audioParameter)
{
return audioParameter switch
{
SpecialAudioParameter.ShipVelocity => GameParameters?.FirstOrDefault(p => p.Name == "ship_velocity"),
SpecialAudioParameter.ChargeLevel => GameParameters?.FirstOrDefault(p => p.Name == "charge_level"),
SpecialAudioParameter.TargetLock => GameParameters?.FirstOrDefault(p => p.Name == "target_locking"),
SpecialAudioParameter.Intensity => GameParameters?.FirstOrDefault(p => p.Name == "sfx_shared_intensity"),
_ => throw new ArgumentOutOfRangeException(nameof(audioParameter), audioParameter, null)
};
}
}
[JsonObject]
public class WwiseMetaObject
{
public uint Id;
public string Name;
public string ObjectPath;
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0a12363ee8ef43b399bf91ca099947a9
timeCreated: 1619664281

View file

@ -0,0 +1,22 @@
using MessagePack;
using Newtonsoft.Json;
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class WwiseSoundBinding
{
[Key(0), JsonProperty("playEvent")]
public uint PlayEvent;
}
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
public class WwiseLoopingSoundBinding : WwiseSoundBinding
{
[Key(1), JsonProperty("stopEvent")]
public uint StopEvent;
}
// public class WwiseParameterBinding
// {
// [Key(0), JsonProperty("parameter")]
// public uint Parameter;
// }

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2e128c1cb68f481c9a846344e8283014
timeCreated: 1619729875