2017-12-22 04:26:04 +08:00
|
|
|
|
using CodeWalker.GameFiles;
|
|
|
|
|
using SharpDX;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace CodeWalker.World
|
|
|
|
|
{
|
2022-01-13 02:07:07 +08:00
|
|
|
|
public class AudioZones
|
2017-12-22 04:26:04 +08:00
|
|
|
|
{
|
|
|
|
|
public volatile bool Inited = false;
|
|
|
|
|
public GameFileCache GameFileCache;
|
|
|
|
|
|
|
|
|
|
public List<AudioPlacement> Zones = new List<AudioPlacement>();
|
|
|
|
|
public List<AudioPlacement> Emitters = new List<AudioPlacement>();
|
|
|
|
|
public List<AudioPlacement> AllItems = new List<AudioPlacement>();
|
|
|
|
|
|
2018-12-26 21:20:39 +08:00
|
|
|
|
public Dictionary<RelFile, AudioPlacement[]> PlacementsDict = new Dictionary<RelFile, AudioPlacement[]>();
|
2017-12-22 04:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
|
|
|
|
|
{
|
|
|
|
|
Inited = false;
|
|
|
|
|
|
|
|
|
|
GameFileCache = gameFileCache;
|
|
|
|
|
|
|
|
|
|
Zones.Clear();
|
|
|
|
|
Emitters.Clear();
|
|
|
|
|
AllItems.Clear();
|
|
|
|
|
|
|
|
|
|
|
2018-12-26 21:20:39 +08:00
|
|
|
|
List<AudioPlacement> placements = new List<AudioPlacement>();
|
2017-12-22 04:26:04 +08:00
|
|
|
|
|
2022-01-13 02:07:07 +08:00
|
|
|
|
foreach (var relfile in GameFileCache.AudioDatRelFiles)
|
2017-12-22 04:26:04 +08:00
|
|
|
|
{
|
2022-01-13 02:07:07 +08:00
|
|
|
|
if (relfile == null) continue;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
|
2022-01-13 02:07:07 +08:00
|
|
|
|
placements.Clear();
|
2018-12-26 21:20:39 +08:00
|
|
|
|
|
2022-01-13 02:07:07 +08:00
|
|
|
|
CreatePlacements(relfile, placements, true);
|
2018-12-26 21:20:39 +08:00
|
|
|
|
|
2022-01-13 02:07:07 +08:00
|
|
|
|
PlacementsDict[relfile] = placements.ToArray();
|
2017-12-22 04:26:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AllItems.AddRange(Zones);
|
|
|
|
|
AllItems.AddRange(Emitters);
|
|
|
|
|
|
|
|
|
|
Inited = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-12-26 21:20:39 +08:00
|
|
|
|
private void CreatePlacements(RelFile relfile, List<AudioPlacement> placements, bool addtoLists = false)
|
|
|
|
|
{
|
|
|
|
|
foreach (var reldata in relfile.RelDatas)
|
|
|
|
|
{
|
|
|
|
|
AudioPlacement placement = null;
|
|
|
|
|
if (reldata is Dat151AmbientZone)
|
|
|
|
|
{
|
|
|
|
|
placement = new AudioPlacement(relfile, reldata as Dat151AmbientZone);
|
|
|
|
|
if (addtoLists) Zones.Add(placement);
|
|
|
|
|
}
|
2021-11-06 18:37:58 +08:00
|
|
|
|
else if (reldata is Dat151AmbientRule)
|
2018-12-26 21:20:39 +08:00
|
|
|
|
{
|
2021-11-06 18:37:58 +08:00
|
|
|
|
placement = new AudioPlacement(relfile, reldata as Dat151AmbientRule);
|
2018-12-26 21:20:39 +08:00
|
|
|
|
if (addtoLists) Emitters.Add(placement);
|
|
|
|
|
}
|
|
|
|
|
if (placement != null)
|
|
|
|
|
{
|
|
|
|
|
placements.Add(placement);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void GetPlacements(List<RelFile> relfiles, List<AudioPlacement> placements)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
foreach (var relfile in relfiles)
|
|
|
|
|
{
|
|
|
|
|
AudioPlacement[] fileplacements = null;
|
|
|
|
|
if (!PlacementsDict.TryGetValue(relfile, out fileplacements))
|
|
|
|
|
{
|
|
|
|
|
List<AudioPlacement> newplacements = new List<AudioPlacement>();
|
|
|
|
|
CreatePlacements(relfile, newplacements);
|
|
|
|
|
fileplacements = newplacements.ToArray();
|
|
|
|
|
PlacementsDict[relfile] = fileplacements;
|
|
|
|
|
}
|
|
|
|
|
if (fileplacements != null)
|
|
|
|
|
{
|
|
|
|
|
placements.AddRange(fileplacements);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2017-12-22 04:26:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public class AudioPlacement
|
|
|
|
|
{
|
2017-12-22 08:25:19 +08:00
|
|
|
|
public string Name { get; set; }
|
|
|
|
|
public MetaHash NameHash { get; set; }
|
2017-12-22 04:26:04 +08:00
|
|
|
|
public RelFile RelFile { get; set; }
|
2017-12-23 04:56:39 +08:00
|
|
|
|
public Dat151AmbientZone AudioZone { get; set; }
|
2021-11-06 18:37:58 +08:00
|
|
|
|
public Dat151AmbientRule AudioEmitter { get; set; }
|
2017-12-22 04:26:04 +08:00
|
|
|
|
public Dat151ZoneShape Shape { get; set; }
|
|
|
|
|
public string ShortTypeName { get; set; }
|
|
|
|
|
public string FullTypeName { get; set; }
|
|
|
|
|
public Vector3 InnerPos { get; set; }
|
|
|
|
|
public Vector3 InnerMin { get; set; }
|
|
|
|
|
public Vector3 InnerMax { get; set; }
|
|
|
|
|
public float InnerRad { get; set; }
|
|
|
|
|
public Quaternion InnerOri { get; set; }
|
|
|
|
|
public Vector3 OuterPos { get; set; }
|
|
|
|
|
public Vector3 OuterMin { get; set; }
|
|
|
|
|
public Vector3 OuterMax { get; set; }
|
|
|
|
|
public float OuterRad { get; set; }
|
|
|
|
|
public Quaternion OuterOri { get; set; }
|
2017-12-24 19:49:04 +08:00
|
|
|
|
public Vector3 Position { get; set; }
|
2017-12-22 04:26:04 +08:00
|
|
|
|
public Vector3 HitboxMin { get; set; }
|
|
|
|
|
public Vector3 HitboxMax { get; set; }
|
2017-12-24 19:49:04 +08:00
|
|
|
|
public Quaternion Orientation { get; set; }
|
|
|
|
|
public Quaternion OrientationInv { get; set; }
|
2017-12-22 04:26:04 +08:00
|
|
|
|
public float HitSphereRad { get; set; }
|
|
|
|
|
|
|
|
|
|
|
2017-12-23 04:56:39 +08:00
|
|
|
|
public AudioPlacement(RelFile rel, Dat151AmbientZone zone)
|
2017-12-22 04:26:04 +08:00
|
|
|
|
{
|
|
|
|
|
RelFile = rel;
|
|
|
|
|
AudioZone = zone;
|
|
|
|
|
ShortTypeName = "AudioZone";
|
|
|
|
|
FullTypeName = "Audio Zone";
|
2018-12-26 21:20:39 +08:00
|
|
|
|
|
|
|
|
|
UpdateFromZone();
|
|
|
|
|
}
|
2021-11-06 18:37:58 +08:00
|
|
|
|
public AudioPlacement(RelFile rel, Dat151AmbientRule emitter)
|
2018-12-26 21:20:39 +08:00
|
|
|
|
{
|
|
|
|
|
RelFile = rel;
|
|
|
|
|
AudioEmitter = emitter;
|
|
|
|
|
ShortTypeName = "AudioEmitter";
|
|
|
|
|
FullTypeName = "Audio Emitter";
|
|
|
|
|
|
|
|
|
|
UpdateFromEmitter();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void UpdateFromZone()
|
|
|
|
|
{
|
|
|
|
|
if (AudioZone == null) return;
|
|
|
|
|
var zone = AudioZone;
|
|
|
|
|
|
2017-12-22 08:25:19 +08:00
|
|
|
|
Name = zone.Name;
|
|
|
|
|
NameHash = zone.NameHash;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
Shape = zone.Shape;
|
2017-12-22 04:26:04 +08:00
|
|
|
|
|
|
|
|
|
float deg2rad = (float)(Math.PI / 180.0);
|
|
|
|
|
|
|
|
|
|
switch (zone.Shape)
|
|
|
|
|
{
|
|
|
|
|
case Dat151ZoneShape.Box:
|
2021-11-06 18:37:58 +08:00
|
|
|
|
InnerPos = zone.PlaybackZonePosition;
|
|
|
|
|
InnerMax = zone.PlaybackZoneSize * 0.5f;
|
2017-12-22 04:26:04 +08:00
|
|
|
|
InnerMin = -InnerMax;
|
2021-11-06 18:37:58 +08:00
|
|
|
|
InnerOri = Quaternion.RotationAxis(Vector3.UnitZ, zone.PlaybackZoneAngle * deg2rad);
|
2017-12-22 04:26:04 +08:00
|
|
|
|
break;
|
|
|
|
|
case Dat151ZoneShape.Sphere:
|
2021-11-06 18:37:58 +08:00
|
|
|
|
InnerPos = zone.PlaybackZonePosition;
|
2017-12-22 08:25:19 +08:00
|
|
|
|
InnerOri = Quaternion.Identity;
|
2021-11-06 18:37:58 +08:00
|
|
|
|
InnerRad = zone.PlaybackZoneSize.X;
|
|
|
|
|
OuterRad = zone.ActivationZoneSize.X;
|
2017-12-22 04:26:04 +08:00
|
|
|
|
break;
|
|
|
|
|
case Dat151ZoneShape.Line:
|
2021-11-06 18:37:58 +08:00
|
|
|
|
InnerPos = zone.PlaybackZonePosition;
|
2017-12-22 04:26:04 +08:00
|
|
|
|
InnerMin = new Vector3(-1.0f, -1.0f, 0.0f);
|
2021-11-06 18:37:58 +08:00
|
|
|
|
InnerMax = new Vector3(1.0f, 1.0f, (zone.PlaybackZoneSize - zone.PlaybackZonePosition).Length());
|
|
|
|
|
InnerOri = Quaternion.Invert(Quaternion.LookAtLH(zone.PlaybackZonePosition, zone.PlaybackZoneSize, Vector3.UnitZ));
|
2017-12-22 04:26:04 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-06 18:37:58 +08:00
|
|
|
|
OuterPos = zone.ActivationZonePosition;
|
|
|
|
|
OuterMax = zone.ActivationZoneSize * 0.5f;
|
2017-12-22 04:26:04 +08:00
|
|
|
|
OuterMin = -OuterMax;
|
2021-11-06 18:37:58 +08:00
|
|
|
|
OuterOri = Quaternion.RotationAxis(Vector3.UnitZ, zone.ActivationZoneAngle * deg2rad);
|
2017-12-22 04:26:04 +08:00
|
|
|
|
|
|
|
|
|
bool useouter = ((InnerMax.X == 0) || (InnerMax.Y == 0) || (InnerMax.Z == 0));
|
2017-12-22 08:25:19 +08:00
|
|
|
|
if (useouter && (zone.Shape != Dat151ZoneShape.Sphere))
|
|
|
|
|
{ } //not sure what these are yet!
|
2017-12-24 19:49:04 +08:00
|
|
|
|
Position = useouter ? OuterPos : InnerPos;
|
2017-12-22 04:26:04 +08:00
|
|
|
|
HitboxMax = useouter ? OuterMax : InnerMax;
|
|
|
|
|
HitboxMin = useouter ? OuterMin : InnerMin;
|
2017-12-24 19:49:04 +08:00
|
|
|
|
Orientation = useouter ? OuterOri : InnerOri;
|
|
|
|
|
OrientationInv = Quaternion.Invert(Orientation);
|
2017-12-22 08:25:19 +08:00
|
|
|
|
HitSphereRad = InnerRad;
|
|
|
|
|
if (zone.Shape == Dat151ZoneShape.Sphere)
|
|
|
|
|
{
|
2017-12-24 19:49:04 +08:00
|
|
|
|
Position = InnerPos;
|
2017-12-22 08:25:19 +08:00
|
|
|
|
}
|
2018-12-26 21:20:39 +08:00
|
|
|
|
|
2017-12-22 04:26:04 +08:00
|
|
|
|
}
|
2018-12-26 21:20:39 +08:00
|
|
|
|
|
|
|
|
|
public void UpdateFromEmitter()
|
2017-12-22 04:26:04 +08:00
|
|
|
|
{
|
2018-12-26 21:20:39 +08:00
|
|
|
|
if (AudioEmitter == null) return;
|
|
|
|
|
var emitter = AudioEmitter;
|
|
|
|
|
|
2017-12-22 08:25:19 +08:00
|
|
|
|
Name = emitter.Name;
|
|
|
|
|
NameHash = emitter.NameHash;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
Shape = Dat151ZoneShape.Sphere;
|
2017-12-22 04:26:04 +08:00
|
|
|
|
|
2017-12-24 19:49:04 +08:00
|
|
|
|
Orientation = Quaternion.Identity;
|
|
|
|
|
OrientationInv = Quaternion.Identity;
|
2017-12-22 04:26:04 +08:00
|
|
|
|
InnerPos = emitter.Position;
|
2017-12-22 08:25:19 +08:00
|
|
|
|
OuterPos = InnerPos;
|
2017-12-22 04:26:04 +08:00
|
|
|
|
InnerRad = emitter.InnerRad;
|
|
|
|
|
OuterRad = emitter.OuterRad;
|
|
|
|
|
|
|
|
|
|
bool useouter = (InnerRad == 0);
|
2017-12-22 08:25:19 +08:00
|
|
|
|
if (useouter)
|
|
|
|
|
{
|
|
|
|
|
InnerRad = 1;
|
|
|
|
|
}
|
2017-12-24 19:49:04 +08:00
|
|
|
|
Position = InnerPos;
|
2017-12-22 08:25:19 +08:00
|
|
|
|
HitSphereRad = InnerRad;// useouter ? OuterRad : InnerRad;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
|
2017-12-22 04:26:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void SetPosition(Vector3 pos)
|
|
|
|
|
{
|
|
|
|
|
bool useouter = ((InnerMax.X == 0) || (InnerMax.Y == 0) || (InnerMax.Z == 0));
|
|
|
|
|
Vector3 delta = pos - InnerPos;
|
|
|
|
|
InnerPos = pos;
|
|
|
|
|
OuterPos += delta;
|
2017-12-24 19:49:04 +08:00
|
|
|
|
Position = useouter ? OuterPos : InnerPos;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
|
|
|
|
|
if (AudioZone != null)
|
|
|
|
|
{
|
2021-11-06 18:37:58 +08:00
|
|
|
|
AudioZone.PlaybackZonePosition = InnerPos;
|
|
|
|
|
AudioZone.ActivationZonePosition = OuterPos;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
}
|
|
|
|
|
if (AudioEmitter != null)
|
|
|
|
|
{
|
|
|
|
|
AudioEmitter.Position = InnerPos;
|
|
|
|
|
}
|
2017-12-22 04:26:04 +08:00
|
|
|
|
}
|
|
|
|
|
public void SetOrientation(Quaternion ori)
|
|
|
|
|
{
|
2017-12-24 19:49:04 +08:00
|
|
|
|
Orientation = ori;
|
|
|
|
|
OrientationInv = Quaternion.Invert(ori);
|
2017-12-22 04:26:04 +08:00
|
|
|
|
|
2018-12-26 21:20:39 +08:00
|
|
|
|
Vector3 t = ori.Multiply(Vector3.UnitX);
|
|
|
|
|
float angl = (float)Math.Atan2(t.Y, t.X);
|
|
|
|
|
while (angl < 0) angl += ((float)Math.PI * 2.0f);
|
|
|
|
|
float rad2deg = (float)(180.0 / Math.PI);
|
|
|
|
|
float dangl = angl * rad2deg;
|
|
|
|
|
uint uangl = (uint)dangl;
|
|
|
|
|
|
|
|
|
|
|
2017-12-22 04:26:04 +08:00
|
|
|
|
if (InnerOri == OuterOri)
|
|
|
|
|
{
|
2017-12-24 19:49:04 +08:00
|
|
|
|
InnerOri = Orientation;
|
|
|
|
|
OuterOri = Orientation;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
if (AudioZone != null)
|
|
|
|
|
{
|
2021-11-06 18:37:58 +08:00
|
|
|
|
AudioZone.PlaybackZoneAngle = uangl;
|
|
|
|
|
AudioZone.ActivationZoneAngle = uangl;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
}
|
2017-12-22 04:26:04 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//not sure yet how to allow independent rotation of inner & outer boxes...
|
|
|
|
|
//maybe only in project window?
|
|
|
|
|
bool useouter = ((InnerMax.X == 0) || (InnerMax.Y == 0) || (InnerMax.Z == 0));
|
|
|
|
|
if (useouter)
|
|
|
|
|
{
|
2017-12-24 19:49:04 +08:00
|
|
|
|
OuterOri = Orientation;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
if (AudioZone != null)
|
|
|
|
|
{
|
2021-11-06 18:37:58 +08:00
|
|
|
|
AudioZone.ActivationZoneAngle = uangl;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
}
|
2017-12-22 04:26:04 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-12-24 19:49:04 +08:00
|
|
|
|
InnerOri = Orientation;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
if (AudioZone != null)
|
|
|
|
|
{
|
2021-11-06 18:37:58 +08:00
|
|
|
|
AudioZone.PlaybackZoneAngle = uangl;
|
2018-12-26 21:20:39 +08:00
|
|
|
|
}
|
2017-12-22 04:26:04 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-24 19:49:04 +08:00
|
|
|
|
|
|
|
|
|
public string GetNameString()
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrEmpty(Name)) return Name;
|
|
|
|
|
return NameHash.ToString();
|
|
|
|
|
}
|
2017-12-22 04:26:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|