4 using Microsoft.Xna.Framework;
6 using System.Collections.Generic;
7 using System.Collections.Immutable;
9 using System.Reflection;
11 using System.Xml.Linq;
17 public readonly ImmutableHashSet<Identifier>
Names;
21 Names = names.Select(n => n.ToIdentifier()).ToImmutableHashSet();
27 private class PrefabCollectionHandler
29 public readonly
object Collection;
30 public readonly MethodInfo AddMethod;
31 public readonly MethodInfo RemoveMethod;
32 public readonly MethodInfo SortAllMethod;
33 public readonly MethodInfo AddOverrideFileMethod;
34 public readonly MethodInfo RemoveOverrideFileMethod;
38 AddMethod.Invoke(Collection,
new object[] { p, isOverride });
43 RemoveMethod.Invoke(Collection,
new object[] { p });
48 AddOverrideFileMethod.Invoke(Collection,
new object[] { file });
53 RemoveOverrideFileMethod.Invoke(Collection,
new object[] { file });
58 SortAllMethod.Invoke(Collection,
null);
61 public PrefabCollectionHandler(Type type)
63 var collectionField = type.GetField($
"{type.Name}Prefabs", BindingFlags.Public | BindingFlags.Static);
64 if (collectionField is
null) {
throw new InvalidOperationException($
"Couldn't determine PrefabCollection for {type.Name}"); }
65 Collection = collectionField.GetValue(
null) ??
throw new InvalidOperationException($
"PrefabCollection for {type.Name} was null");
66 AddMethod = Collection.GetType().GetMethod(
"Add", BindingFlags.Public | BindingFlags.Instance);
67 RemoveMethod = Collection.GetType().GetMethod(
"Remove", BindingFlags.Public | BindingFlags.Instance);
68 AddOverrideFileMethod = Collection.GetType().GetMethod(
"AddOverrideFile", BindingFlags.Public | BindingFlags.Instance);
69 RemoveOverrideFileMethod = Collection.GetType().GetMethod(
"RemoveOverrideFile", BindingFlags.Public | BindingFlags.Instance);
70 SortAllMethod = Collection.GetType().GetMethod(
"SortAll", BindingFlags.Public | BindingFlags.Instance);
79 private readonly
static List<SoundPrefab> flowSounds =
new List<SoundPrefab>();
80 public static IReadOnlyList<SoundPrefab>
FlowSounds => flowSounds;
81 private readonly
static List<SoundPrefab> splashSounds =
new List<SoundPrefab>();
82 public static IReadOnlyList<SoundPrefab>
SplashSounds => splashSounds;
85 private readonly
static ImmutableDictionary<Type, PrefabCollectionHandler> derivedPrefabCollections;
86 private readonly
static ImmutableDictionary<Identifier, PrefabSelector<SoundPrefab>> prefabSelectors;
87 private readonly
static ImmutableDictionary<Identifier, List<SoundPrefab>> prefabsWithTag;
92 var types = ReflectionUtils.GetDerivedNonAbstract<
SoundPrefab>();
95 t.GetCustomAttribute<
TagNames>().
Names.Select(n => (n, t))).ToImmutableDictionary();
96 derivedPrefabCollections = types.Select(t => (t,
new PrefabCollectionHandler(t))).ToImmutableDictionary();
98 var prefabSelectorFields = typeof(
SoundPrefab).GetFields(BindingFlags.Public | BindingFlags.Static)
100 prefabSelectors = prefabSelectorFields.Select(f => (f.Name.ToIdentifier(), (
PrefabSelector<SoundPrefab>)f.GetValue(
null))).ToImmutableDictionary();
102 var prefabsOfTagName = typeof(
SoundPrefab).GetFields(BindingFlags.Static | BindingFlags.NonPublic)
103 .Where(f => f.FieldType == typeof(List<SoundPrefab>));
104 prefabsWithTag = prefabsOfTagName.Select(f => (f.Name.Substring(0, f.Name.Length-6).ToIdentifier(), (List<SoundPrefab>)f.GetValue(
null))).ToImmutableDictionary();
109 if (derivedPrefabCollections.ContainsKey(p.GetType()))
111 derivedPrefabCollections[p.GetType()].Add(p, isOverride);
113 if (prefabSelectors.ContainsKey(p.
ElementName)) { prefabSelectors[p.ElementName].Add(p, isOverride); }
114 UpdateSoundsWithTag();
118 if (derivedPrefabCollections.ContainsKey(p.GetType()))
120 derivedPrefabCollections[p.GetType()].Remove(p);
123 UpdateSoundsWithTag();
124 SoundPlayer.DisposeDisabledMusic();
128 derivedPrefabCollections.Values.ForEach(h => h.SortAll());
129 prefabSelectors.Values.ForEach(h => h.Sort());
131 onAddOverrideFile: (file) => {derivedPrefabCollections.Values.ForEach(h => h.AddOverrideFile(file)); },
132 onRemoveOverrideFile: (file) => { derivedPrefabCollections.Values.ForEach(h => h.RemoveOverrideFile(file)); }
136 private static void UpdateSoundsWithTag()
138 foreach (var tag
in prefabsWithTag.Keys)
140 var list = prefabsWithTag[tag];
142 list.AddRange(
Prefabs.Where(p => p.ElementName == tag));
143 list.Sort((p1, p2) =>
145 if (p1.ContentFile.ContentPackage.Index < p2.ContentFile.ContentPackage.Index) { return -1; }
146 if (p1.ContentFile.ContentPackage.Index > p2.ContentFile.ContentPackage.Index) { return 1; }
147 if (p2.Element.ComesAfter(p1.Element)) { return -1; }
148 if (p1.Element.ComesAfter(p2.Element)) { return 1; }
156 Identifier id = base.DetermineIdentifier(element);
159 if (
id.IsEmpty) {
id = Path.GetFileNameWithoutExtension(element.GetAttributeStringUnrestricted(
"path",
"")).ToIdentifier(); }
160 if (
id.IsEmpty) {
id = Path.GetFileNameWithoutExtension(element.GetAttributeStringUnrestricted(
"file",
"")).ToIdentifier(); }
164 id = $
"{element.Name}_{id}".ToIdentifier();
166 string damageSoundType = element.GetAttributeString(
"damagesoundtype",
"");
167 if (!damageSoundType.IsNullOrEmpty())
169 id = $
"{id}_{damageSoundType}".ToIdentifier();
172 string musicType = element.GetAttributeString(
"type",
"");
173 if (!musicType.IsNullOrEmpty())
175 id = $
"{id}_{musicType}".ToIdentifier();
212 [TagNames(
"damagesound")]
267 [TagNames(
"guisound")]
readonly bool MuteIntensityTracks
BackgroundMusic(ContentXElement element, SoundsFile file)
readonly Vector2 IntensityRange
readonly bool ContinueFromPreviousTime
readonly bool StartFromRandomTime
readonly? float ForceIntensityTrack
static readonly PrefabCollection< BackgroundMusic > BackgroundMusicPrefabs
Base class for content file types, which are loaded from filelist.xml via reflection....
static readonly ContentPath Empty
float GetAttributeFloat(string key, float def)
Identifier NameAsIdentifier()
Vector2 GetAttributeVector2(string key, in Vector2 def)
ContentPath? GetAttributeContentPath(string key)
bool GetAttributeBool(string key, bool def)
XAttribute? GetAttribute(string name)
Identifier GetAttributeIdentifier(string key, string def)
DamageSound(ContentXElement element, SoundsFile file)
readonly Identifier RequiredTag
static readonly PrefabCollection< DamageSound > DamageSoundPrefabs
readonly Identifier DamageType
readonly Vector2 DamageRange
static readonly PrefabCollection< GUISound > GUISoundPrefabs
GUISound(ContentXElement element, SoundsFile file)
readonly GUISoundType Type
static Sounds.SoundManager SoundManager
readonly Identifier Identifier
SoundPrefab(ContentXElement element, SoundsFile file, bool stream=false)
static IReadOnlyList< SoundPrefab > FlowSounds
static readonly PrefabSelector< SoundPrefab > WaterAmbienceIn
static readonly PrefabCollection< SoundPrefab > Prefabs
readonly ContentPath SoundPath
static readonly ImmutableDictionary< Identifier, Type > TagToDerivedPrefab
static readonly PrefabSelector< SoundPrefab > WaterAmbienceOut
static IReadOnlyList< SoundPrefab > SplashSounds
override Identifier DetermineIdentifier(XElement element)
static readonly PrefabSelector< SoundPrefab > WaterAmbienceMoving
static readonly PrefabSelector< SoundPrefab > StartupSound
readonly Identifier ElementName
readonly ContentXElement Element
Sound LoadSound(string filename, bool stream=false)
TagNames(params string[] names)
readonly ImmutableHashSet< Identifier > Names