mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-26 15:39:01 -07:00
Radicade Public Code
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using RadicadeServer.RecNet.Avatar;
|
||||
using RadicadeServer.RecNet.Enums.Store;
|
||||
using Xunit;
|
||||
|
||||
namespace RadicadeServer.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// The shipped consumable and equipment-skin catalogs come from DorkNet's extraction of the
|
||||
/// 2023 client's own asset configs (tools/import_dorknet_catalogs.py). These tests keep the two
|
||||
/// halves of each row honest: a consumable that has no client token spawns as
|
||||
/// "Unable to find consumable", and a skin without an exact prefab + guid pair does not resolve
|
||||
/// at all.
|
||||
/// </summary>
|
||||
public class DorkNetCatalogTests
|
||||
{
|
||||
private static string Fixture(string name) => Path.Combine(AppContext.BaseDirectory, "Fixtures", name);
|
||||
|
||||
private static List<ConsumableItem> ShippedConsumables()
|
||||
{
|
||||
var path = Fixture("consumables.json");
|
||||
Assert.True(File.Exists(path), $"missing fixture {path}");
|
||||
// Rarity is written as a name in the catalog, which is what the admin panel's own
|
||||
// options (JsonStringEnumConverter) accept.
|
||||
return JsonSerializer.Deserialize<List<ConsumableItem>>(
|
||||
File.ReadAllText(path),
|
||||
new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
Converters = { new JsonStringEnumConverter() }
|
||||
})
|
||||
?? new List<ConsumableItem>();
|
||||
}
|
||||
|
||||
private static List<EquipmentSkinItem> ShippedSkins()
|
||||
{
|
||||
var path = Fixture("equipment_skins.json");
|
||||
Assert.True(File.Exists(path), $"missing fixture {path}");
|
||||
return EquipmentSkinCatalog.Parse(File.ReadAllText(path));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShippedConsumablesAllResolveToAClientToken()
|
||||
{
|
||||
var rows = ShippedConsumables();
|
||||
|
||||
Assert.True(rows.Count >= 53, $"only {rows.Count} consumable(s) shipped");
|
||||
Assert.DoesNotContain(rows, row => string.IsNullOrWhiteSpace(row.ConsumableItemDesc));
|
||||
|
||||
// ToClientDesc leaves unknown names alone, so a row that comes back unchanged would be
|
||||
// served as its friendly name - exactly the bug that made gift boxes fail to spawn.
|
||||
var unresolved = rows
|
||||
.Where(row => ConsumableCatalog.ToClientDesc(row.ConsumableItemDesc) == row.ConsumableItemDesc)
|
||||
.Select(row => row.ConsumableItemDesc)
|
||||
.ToList();
|
||||
|
||||
Assert.Empty(unresolved);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShippedConsumablesAreDistinctAndCarryAFriendlyName()
|
||||
{
|
||||
var rows = ShippedConsumables();
|
||||
|
||||
Assert.Equal(
|
||||
rows.Count,
|
||||
rows.Select(row => row.ConsumableItemDesc).Distinct(StringComparer.OrdinalIgnoreCase).Count());
|
||||
Assert.DoesNotContain(rows, row => string.IsNullOrWhiteSpace(row.FriendlyName));
|
||||
Assert.Contains(rows, row => row.Rarity != Rarity.Common);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ShippedSkinsAllCarryThePairTheClientResolvesThemFrom()
|
||||
{
|
||||
var skins = ShippedSkins();
|
||||
|
||||
Assert.True(skins.Count >= 194, $"only {skins.Count} skin(s) shipped");
|
||||
Assert.DoesNotContain(skins, skin => string.IsNullOrWhiteSpace(skin.PrefabName));
|
||||
Assert.DoesNotContain(skins, skin => string.IsNullOrWhiteSpace(skin.ModificationGuid));
|
||||
Assert.DoesNotContain(skins, skin => string.IsNullOrWhiteSpace(skin.DisplayName));
|
||||
Assert.Equal(
|
||||
skins.Count,
|
||||
skins.Select(skin => skin.ModificationGuid).Distinct(StringComparer.OrdinalIgnoreCase).Count());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SkinsBecomeEquipmentRowsNamedFromTheCatalog()
|
||||
{
|
||||
var skin = new EquipmentSkinItem
|
||||
{
|
||||
PrefabName = "[PaintballGun]",
|
||||
ModificationGuid = "00000000-0000-0000-0000-000000000001",
|
||||
DisplayName = "Paintball Gun Skin Test",
|
||||
Tooltip = "Equipment skin for PaintballGun.",
|
||||
Rarity = Rarity.Uncommon
|
||||
};
|
||||
|
||||
var equipment = Assert.Single(EquipmentSkinCatalog.ToEquipment([skin]));
|
||||
|
||||
Assert.Equal("[PaintballGun]", equipment.PrefabName);
|
||||
Assert.Equal(skin.ModificationGuid, equipment.ModificationGuid);
|
||||
Assert.Equal("Paintball Gun Skin Test", equipment.FriendlyName);
|
||||
Assert.Equal("Equipment skin for PaintballGun.", equipment.Tooltip);
|
||||
Assert.Equal(Rarity.Uncommon, equipment.Rarity);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SkinsWithoutAPrefabOrGuidAreDropped()
|
||||
{
|
||||
var parsed = EquipmentSkinCatalog.Parse("""
|
||||
{ "items": [
|
||||
{ "prefab_name": "[Arrow]", "modification_guid": "aaa", "display_name": "Arrow Skin" },
|
||||
{ "prefab_name": "", "modification_guid": "bbb", "display_name": "No prefab" },
|
||||
{ "prefab_name": "[Basketball]", "modification_guid": "", "display_name": "No guid" }
|
||||
] }
|
||||
""");
|
||||
|
||||
Assert.Equal("[Arrow]", Assert.Single(parsed).PrefabName);
|
||||
Assert.Empty(EquipmentSkinCatalog.Parse("not json at all"));
|
||||
Assert.Empty(EquipmentSkinCatalog.Parse(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergingSkinsAddsOnlyThePairsMissingFromTheCatalog()
|
||||
{
|
||||
const string equipmentJson = """
|
||||
[ { "PrefabName": "[Arrow]", "ModificationGuid": "b862383e-0de3-492d-8f72-25e756287687",
|
||||
"FriendlyName": "[Arrow]", "Tooltip": "", "Rarity": 0 } ]
|
||||
""";
|
||||
const string skinsJson = """
|
||||
{ "items": [
|
||||
{ "prefab_name": "[Arrow]", "modification_guid": "b862383e-0de3-492d-8f72-25e756287687",
|
||||
"display_name": "Arrow Skin Vitton", "rarity": 10 },
|
||||
{ "prefab_name": "[Arrow]", "modification_guid": "aaaaaaaa-0000-0000-0000-000000000000",
|
||||
"display_name": "Arrow Skin Fresh", "rarity": 10 }
|
||||
] }
|
||||
""";
|
||||
|
||||
var merged = JsonSerializer.Deserialize<List<Equipment>>(
|
||||
EquipmentSkinCatalog.MergeInto(equipmentJson, skinsJson))!;
|
||||
|
||||
// The existing row keeps its place: a skin contributes only pairs the catalog lacks.
|
||||
Assert.Equal(2, merged.Count);
|
||||
Assert.Equal("[Arrow]", merged[0].FriendlyName);
|
||||
Assert.Equal("Arrow Skin Fresh", merged[1].FriendlyName);
|
||||
Assert.Equal(Rarity.Uncommon, merged[1].Rarity);
|
||||
|
||||
// Idempotent: merging the merged catalog again adds nothing.
|
||||
var again = JsonSerializer.Deserialize<List<Equipment>>(
|
||||
EquipmentSkinCatalog.MergeInto(
|
||||
EquipmentSkinCatalog.MergeInto(equipmentJson, skinsJson), skinsJson))!;
|
||||
Assert.Equal(2, again.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MergingAnUnreadableCatalogLeavesItAlone()
|
||||
{
|
||||
const string broken = "{ this is not an equipment list }";
|
||||
|
||||
Assert.Equal(broken, EquipmentSkinCatalog.MergeInto(broken, """{ "items": [ { "prefab_name": "[Arrow]", "modification_guid": "aaa" } ] }"""));
|
||||
Assert.Equal("[]", EquipmentSkinCatalog.MergeInto("[]", "{}"));
|
||||
Assert.Equal("[]", EquipmentSkinCatalog.MergeInto(null, null));
|
||||
}
|
||||
|
||||
/// <summary>How many rows repeat a prefab/guid pair another row already carries.</summary>
|
||||
private static int DuplicatePairs(List<Equipment> rows) =>
|
||||
rows.Count - rows
|
||||
.Select(row => $"{row.PrefabName}\u001f{row.ModificationGuid}")
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.Count();
|
||||
|
||||
[Fact]
|
||||
public void ShippedSkinsSurviveAMergeIntoTheShippedEquipmentCatalog()
|
||||
{
|
||||
var equipmentPath = Fixture("equipment.json");
|
||||
var skinsPath = Fixture("equipment_skins.json");
|
||||
if (!File.Exists(equipmentPath) || !File.Exists(skinsPath))
|
||||
{
|
||||
// Both fixtures are optional here; the shipped files themselves are what matters.
|
||||
return;
|
||||
}
|
||||
|
||||
var equipment = File.ReadAllText(equipmentPath);
|
||||
var merged = JsonSerializer.Deserialize<List<Equipment>>(
|
||||
EquipmentSkinCatalog.MergeInto(equipment, File.ReadAllText(skinsPath)))!;
|
||||
var before = JsonSerializer.Deserialize<List<Equipment>>(equipment)!;
|
||||
|
||||
Assert.True(merged.Count >= before.Count);
|
||||
// The shipped equipment.json already repeats some prefab/guid pairs, so the invariant is
|
||||
// that merging a skin never adds another row for a pair the catalog already had.
|
||||
Assert.Equal(DuplicatePairs(before), DuplicatePairs(merged));
|
||||
foreach (var skin in ShippedSkins())
|
||||
{
|
||||
Assert.Contains(merged, row =>
|
||||
string.Equals(row.PrefabName, skin.PrefabName, StringComparison.OrdinalIgnoreCase)
|
||||
&& string.Equals(row.ModificationGuid, skin.ModificationGuid, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user