Skip to content

Commit ec68a72

Browse files
committed
Warn when AWC names collide in the first 8 characters
The game identifies a wavepack by the first 8 characters of its name (RAGE truncates them; visible in FiveM's PatchAudioWavePackOverlay 8-char base-pack match). Two AWCs that match in the first 8 chars resolve to the same bank, so one loads and the rest go silent. Preflight now warns on that collision (no length enforcement - a long but 8-char-unique name is fine).
1 parent c174670 commit ec68a72

3 files changed

Lines changed: 47 additions & 0 deletions

File tree

SirenSharp.Tests/PreflightServiceTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,32 @@ public void EmptyProject_IsBlockingError()
2121
Assert.Contains(report.Items, d => d.Code == DiagnosticCodes.ProjectEmpty);
2222
}
2323

24+
[Fact]
25+
public void AwcNamesSharingFirst8Chars_WarnCollision()
26+
{
27+
using var dir = new TempDir();
28+
var project = new Project("demo", dir.File("demo.ssproj"));
29+
// Distinct names, but identical in the first 8 chars -> same wavepack in-game.
30+
project.SoundSets.Add(new SoundSet("policecar1"));
31+
project.SoundSets.Add(new SoundSet("policecar2"));
32+
33+
var report = Preflight.Inspect(project);
34+
Assert.Contains(report.Warnings, d => d.Code == DiagnosticCodes.AwcNameCollision);
35+
}
36+
37+
[Fact]
38+
public void AwcNamesDifferingWithin8Chars_NoCollision()
39+
{
40+
using var dir = new TempDir();
41+
var project = new Project("demo", dir.File("demo.ssproj"));
42+
project.SoundSets.Add(new SoundSet("lspd"));
43+
project.SoundSets.Add(new SoundSet("bcso"));
44+
project.SoundSets.Add(new SoundSet("fire_dept")); // 9 chars but unique in 8 -> fine
45+
46+
var report = Preflight.Inspect(project);
47+
Assert.DoesNotContain(report.Items, d => d.Code == DiagnosticCodes.AwcNameCollision);
48+
}
49+
2450
[Fact]
2551
public void DuplicateSoundsetNames_AreBlockingError()
2652
{

SirenSharp/Models/Diagnostic.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public static class DiagnosticCodes
4646
public const string AwcDuplicateName = "AWC.DUPLICATE_NAME";
4747
public const string AwcInvalidName = "AWC.INVALID_NAME";
4848
public const string AwcNoSirens = "AWC.NO_SIRENS";
49+
public const string AwcNameCollision = "AWC.NAME_COLLISION";
4950
public const string SirenDuplicateName = "SIREN.DUPLICATE_NAME";
5051
public const string SirenInvalidName = "SIREN.INVALID_NAME";
5152
public const string SirenMissingFile = "SIREN.MISSING_FILE";

SirenSharp/Services/Preflight/PreflightChecks.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,26 @@ public IEnumerable<Diagnostic> Inspect(Project project)
3333
DiagnosticCodes.AwcDuplicateName,
3434
name);
3535
}
36+
37+
// The game identifies wavepacks (AWCs) by the first 8 characters of the name only
38+
// (RAGE truncates them; see FiveM's PatchAudioWavePackOverlay 8-char match). Two AWCs
39+
// whose names match in the first 8 chars resolve to the same bank, so only one loads
40+
// and the other plays silent in-game - even though both names look distinct here.
41+
var prefixCollisions = project.SoundSets
42+
.Where(s => !string.IsNullOrEmpty(s.Name))
43+
.GroupBy(s => s.Name.ToLowerInvariant().Substring(0, Math.Min(8, s.Name.Length)))
44+
.Where(g => g.Select(s => s.Name).Distinct().Count() > 1);
45+
46+
foreach (var group in prefixCollisions)
47+
{
48+
var names = string.Join(", ", group.Select(s => s.Name).Distinct());
49+
yield return new Diagnostic(
50+
DiagnosticSeverity.Warning,
51+
$"AWCs {names} share the same first 8 characters ('{group.Key}'). The game uses only the first 8 characters to identify a wavepack, so these resolve to the same bank - only one will load and the others will be silent in-game.",
52+
DiagnosticCodes.AwcNameCollision,
53+
group.Key,
54+
"Make the first 8 characters of each AWC name unique.");
55+
}
3656
}
3757
}
3858

0 commit comments

Comments
 (0)