| name | sdv-data-validation |
| description | This skill should be used when the user asks to "validate data structures", "check save format", "update config options", or discusses data persistence. Also use when modifying FavoritesModel.cs, ModConfig.cs, modData conventions, JSON save files, or when preparing migrations for breaking changes. |
| version | 1.0.0 |
SDV Data Validation
Validate data structures and prevent regressions in save formats, config, and modData conventions.
When to Use This Skill
- Modifying
Models/FavoritesModel.cs (FavoritesData, FavoriteOutfit)
- Modifying
ModConfig.cs
- Changing modData key conventions
- Adding new save data fields
- Before commits affecting data persistence
Data Structure Validation
FavoritesData Schema
public class FavoritesData
{
public List<FavoriteOutfit> Favorites { get; set; }
}
public class FavoriteOutfit
{
public bool isFavorite { get; set; } = false;
public string Name { get; set; } = "";
public string Category { get; set; } = "";
public int LastWorn { get; set; } = 0;
public Dictionary<string, string> Items { get; set; }
public Dictionary<string, string> ItemIds { get; set; }
public Dictionary<string, string> ItemColors { get; set; }
public string HairIndex { get; set; } = "";
public int Hair { get; set; } = 0;
public string AccessoryIndex { get; set; } = "";
public int Accessory { get; set; } = 0;
}
Validation Checks
Required Fields:
Item References:
Data Integrity:
ModConfig Validation
Current Schema
public sealed class ModConfig
{
public bool StartingDresser { get; set; } = true;
public bool RobinSellsDressers { get; set; } = true;
public bool TravelingMerchantSellsDressers { get; set; } = true;
public bool IncludeRingsInOutfits { get; set; } = true;
public bool IncludeFacialHair { get; set; } = false;
public bool IncludeModdedHairstyles { get; set; } = true;
public bool IncludeModdedAccessories { get; set; } = true;
public DresserSharingMode DresserInventorySharing { get; set; } = DresserSharingMode.Touching;
}
public enum DresserSharingMode { Individual, Touching, SameBuilding }
Validation Checks
When adding new config options:
GMCM Registration Pattern:
api.AddBoolOption(
mod: ModManifest,
name: () => "Option Name",
tooltip: () => "Description of what this does",
getValue: () => Config.OptionName,
setValue: v => Config.OptionName = v
);
ModData Key Conventions
Correct Format
item.modData[$"{ModId}/FavoriteItem"] = "value";
item.modData["LiminalWarmth.StardewOutfitManager/FavoriteItem"] = $"{item.Name}_{Guid.NewGuid()}";
Validation Checks
Migration for Legacy Keys
If old keys exist without prefix:
if (item.modData.TryGetValue("StardewOutfitManagerFavoriteItem", out string legacyValue))
{
item.modData[$"{ModId}/FavoriteItem"] = legacyValue;
item.modData.Remove("StardewOutfitManagerFavoriteItem");
}
Save File Paths
Correct Pattern
string path = $"data/favoritesData/{Game1.player.Name}_{Constants.SaveFolderName}_{Game1.player.UniqueMultiplayerID}.json";
Helper.Data.WriteJsonFile<FavoritesData>(path, data);
var loaded = Helper.Data.ReadJsonFile<FavoritesData>(path);
Validation Checks
Breaking Change Migration
When making breaking changes to data structures:
1. Identify Breaking Changes
Examples of breaking changes:
- Renaming a property
- Changing a property type
- Removing a required field
- Changing dictionary key format
2. Create Migration Code
private FavoritesData MigrateData(FavoritesData data, int fromVersion)
{
if (fromVersion < 2)
{
foreach (var outfit in data.Favorites)
{
}
}
if (fromVersion < 3)
{
foreach (var outfit in data.Favorites)
{
outfit.ItemColors ??= new Dictionary<string, string>();
}
}
return data;
}
3. Handle Null/Missing Fields
Always use null-safe access:
var hatTag = outfit.Items["Hat"];
if (outfit.Items?.TryGetValue("Hat", out string hatTag) == true)
{
}
outfit.Items ??= new Dictionary<string, string>();
outfit.ItemIds ??= new Dictionary<string, string>();
outfit.ItemColors ??= new Dictionary<string, string>();
Audit Output Format
## Data Validation Results
### Schema Issues
- [ ] FavoriteOutfit.Category allows invalid values (no validation)
- [ ] Missing null check for Items dictionary in LoadFavorites
### Config Issues
- [ ] New option `DebugMode` not registered in GMCM
### ModData Key Issues
- [ ] Legacy key "StardewOutfitManagerFavoriteItem" found in FavoritesMethods.cs:45
- Fix: Migrate to "LiminalWarmth.StardewOutfitManager/FavoriteItem"
### Breaking Changes
- [ ] Property renamed from `Outfit` to `Items` - migration required
### Passed Checks
- [x] All config options have defaults
- [x] Save paths include all required components
- [x] ItemIds use valid QualifiedItemId format
Quick Reference
Valid QualifiedItemId Prefixes
(O) Object
(BC) BigCraftable
(F) Furniture
(W) Weapon
(B) Boots
(H) Hat
(P) Pants
(S) Shirt
(T) Tool
(TR) Trinket
(R) Ring
Valid Category Values
"Spring"
"Summer"
"Fall"
"Winter"
"Special"
Valid Item Slot Keys
"Hat"
"Shirt"
"Pants"
"Shoes"
"LeftRing"
"RightRing"