From 7b0ea11bebca2c97bf9498118ae70aaff1c16851 Mon Sep 17 00:00:00 2001 From: SinZ Date: Sun, 15 Oct 2023 11:49:09 +1100 Subject: [PATCH 1/8] Initial development on a data generation tool + analyzer for detecting misuse of ContentManagers --- .../Program.cs | 107 +++++++ ...BuildConfig.Analyzer.DataGeneration.csproj | 25 ++ .../ContentManagerAnalyzerTests.cs | 90 ++++++ .../1.5.6.22018.json | 233 ++++++++++++++++ .../1.6.0.23268.json | 262 ++++++++++++++++++ .../ContentManagerAnalyzer.cs | 89 ++++++ .../SMAPI.ModBuildConfig.Analyzer.csproj | 5 + src/SMAPI.sln | 9 +- 8 files changed, 819 insertions(+), 1 deletion(-) create mode 100644 src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/Program.cs create mode 100644 src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/SMAPI.ModBuildConfig.Analyzer.DataGeneration.csproj create mode 100644 src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs create mode 100644 src/SMAPI.ModBuildConfig.Analyzer/1.5.6.22018.json create mode 100644 src/SMAPI.ModBuildConfig.Analyzer/1.6.0.23268.json create mode 100644 src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs diff --git a/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/Program.cs b/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/Program.cs new file mode 100644 index 000000000..f7d3fb3b7 --- /dev/null +++ b/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/Program.cs @@ -0,0 +1,107 @@ +using System.Text.Json; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Collections.Generic; +using StardewModdingAPI.ModBuildConfig.Analyzer; +using StardewModdingAPI.Toolkit; + +Console.WriteLine("Hello, World!"); + +var stardew = AssemblyDefinition.ReadAssembly("Stardew Valley.dll"); + +Dictionary AssetMap = new Dictionary(); + +List messagesForLater = new(); +foreach (var module in stardew.Modules) +{ + var types = module.GetTypes().Where(type => type.BaseType != null); + + foreach (var type in types) + { + foreach (var method in type.Methods) + { + if (method.HasBody) + { + + ILProcessor cil = method.Body.GetILProcessor(); + Collection instructions = cil.Body.Instructions; + + Instruction prevInstruction = Instruction.Create(OpCodes.Nop); + foreach (var instruction in instructions) + { + if (instruction.OpCode.Code == Code.Nop) + continue; + if (instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Callvirt || instruction.OpCode == OpCodes.Newobj) + { + var methodInstruction = (MethodReference)instruction.Operand; + if (methodInstruction.Name == "Load") { + if (methodInstruction.DeclaringType.FullName != "StardewValley.LocalizedContentManager") + { + Console.WriteLine("Found a Load that was not StardewValley.LocalizedContentManager " + method.DeclaringType.FullName); + continue; + } + var genericMethod = (GenericInstanceMethod)methodInstruction; + string genericParameter = genericMethod.GenericArguments[0]?.FullName ?? ""; + string? assetName = null; + if (prevInstruction.OpCode == OpCodes.Ldstr) + { + assetName = (string)prevInstruction.Operand; + } + else + { + messagesForLater.Add($"{method.FullName} is calling Load {methodInstruction} (prev instruction: {prevInstruction})"); + } + if (assetName != null) + { + if (AssetMap.TryGetValue(assetName, out string existingType)) + { + if (genericParameter != existingType) + { + Console.WriteLine($"Found a new use of {assetName}: Previously {existingType} now {genericParameter}"); + } + } + else + { + AssetMap[assetName] = genericParameter; + } + } + } + } + prevInstruction = instruction; + } + } + } + } +} + + +Directory.CreateDirectory("outputs"); +var currentVersion = new SemanticVersion(stardew.Name.Version); +HashSet missingAssets = new(); +foreach (string file in Directory.GetFiles("outputs")) +{ + if (file.EndsWith(stardew.Name.Version + ".json")) continue; + var otherVersion = new SemanticVersion(Path.GetFileNameWithoutExtension(file), true); + if (otherVersion.IsNewerThan(currentVersion)) continue; + try + { + var versionInfo = JsonSerializer.Deserialize(File.ReadAllText(file)); + foreach (var (asset, type) in versionInfo.AssetMap) + { + if (!AssetMap.ContainsKey(asset)) + { + missingAssets.Add(asset); + } + } + } + catch { } +} +string jsonOutput = JsonSerializer.Serialize(new VersionModel(AssetMap, missingAssets), new JsonSerializerOptions +{ + WriteIndented = true, +}); +File.WriteAllText($"outputs/{stardew.Name.Version}.json", jsonOutput); + + + + diff --git a/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/SMAPI.ModBuildConfig.Analyzer.DataGeneration.csproj b/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/SMAPI.ModBuildConfig.Analyzer.DataGeneration.csproj new file mode 100644 index 000000000..c53790785 --- /dev/null +++ b/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/SMAPI.ModBuildConfig.Analyzer.DataGeneration.csproj @@ -0,0 +1,25 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + + + + + + + + + + diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs new file mode 100644 index 000000000..c87a4eb84 --- /dev/null +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs @@ -0,0 +1,90 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using NUnit.Framework; +using SMAPI.ModBuildConfig.Analyzer.Tests.Framework; +using StardewModdingAPI.ModBuildConfig.Analyzer; + +namespace SMAPI.ModBuildConfig.Analyzer.Tests +{ + /// Unit tests for . + [TestFixture] + public class ContentManagerAnalyzerTests : DiagnosticVerifier + { + /********* + ** Fields + *********/ + /// Sample C# mod code, with a {{test-code}} placeholder for the code in the Entry method to test. + const string SampleProgram = @" + using System; + using System.Collections.Generic; + using StardewValley; + using Netcode; + using SObject = StardewValley.Object; + + namespace SampleMod + { + class ModEntry + { + public void Entry() + { + {{test-code}} + } + } + } + "; + + /// The line number where the unit tested code is injected into . + private const int SampleCodeLine = 14; + + /// The column number where the unit tested code is injected into . + private const int SampleCodeColumn = 25; + + + /********* + ** Unit tests + *********/ + /// Test that no diagnostics are raised for an empty code block. + [TestCase] + public void EmptyCode_HasNoDiagnostics() + { + // arrange + string test = @""; + + // assert + this.VerifyCSharpDiagnostic(test); + } + + /// Test that the expected diagnostic message is raised for avoidable net field references. + /// The code line to test. + /// The column within the code line where the diagnostic message should be reported. + /// The expression which should be reported. + /// The net type name which should be reported. + /// The suggested property name which should be reported. + [TestCase("Game1.content.Load>(\"Data\\\\Fish\");", 0, "Data\\Fish", "System.Collections.Generic.Dictionary", "System.Collections.Generic.Dictionary")] + public void BadType_RaisesDiagnostic(string codeText, int column, string assetName, string expectedType, string suggestedType) + { + // arrange + string code = SampleProgram.Replace("{{test-code}}", codeText); + DiagnosticResult expected = new() + { + Id = "AvoidContentManagerBadType", + Message = $"'{assetName}' uses the {suggestedType} type, but {expectedType} is in use instead. See https://smapi.io/package/avoid-contentmanager-type for details.", + Severity = DiagnosticSeverity.Error, + Locations = new[] { new DiagnosticResultLocation("Test0.cs", SampleCodeLine, SampleCodeColumn + column) } + }; + + // assert + this.VerifyCSharpDiagnostic(code, expected); + } + + + /********* + ** Helpers + *********/ + /// Get the analyzer being tested. + protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer() + { + return new ContentManagerAnalyzer(); + } + } +} diff --git a/src/SMAPI.ModBuildConfig.Analyzer/1.5.6.22018.json b/src/SMAPI.ModBuildConfig.Analyzer/1.5.6.22018.json new file mode 100644 index 000000000..f2f933062 --- /dev/null +++ b/src/SMAPI.ModBuildConfig.Analyzer/1.5.6.22018.json @@ -0,0 +1,233 @@ +{ + "AssetMap": { + "TileSheets\\tools": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\springobjects": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Fonts\\SpriteFont1": "Microsoft.Xna.Framework.Graphics.SpriteFont", + "Fonts\\SmallFont": "Microsoft.Xna.Framework.Graphics.SpriteFont", + "Fonts\\tinyFont": "Microsoft.Xna.Framework.Graphics.SpriteFont", + "Fonts\\tinyFontBorder": "Microsoft.Xna.Framework.Graphics.SpriteFont", + "Data\\ObjectInformation": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\ClothingInformation": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\BigCraftablesInformation": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\Achievements": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\CraftingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\CookingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "LooseSprites\\Cursors": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Cursors2": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Giftbox": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\ControllerMaps": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\NPCGiftTastes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\SecretNotes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "LooseSprites\\Concessions": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\birds": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\daybg": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\nightbg": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\MenuTiles": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\MenuTilesUncolored": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\lantern": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\windowLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\sconceLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\greenLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\indoorWindowLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\shadow": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\animations": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\crops": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\emotes": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\debris": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\Craftables": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\rain": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\BuffsIcons": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\ObjectContextTags": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Characters\\Farmer\\hairstyles": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\shirts": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\pants": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\hats": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\accessories": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\furniture": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\furnitureFront": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\ChairTiles": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\font_bold": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\font_colored": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\weapons": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\Projectiles": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\George": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Evelyn": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Alex": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Emily": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Haley": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Jodi": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Sam": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Vincent": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Clint": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Lewis": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Caroline": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Abigail": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Pierre": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Gus": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Pam": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Penny": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Harvey": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Elliott": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Maru": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Robin": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Demetrius": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Sebastian": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Linus": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Wizard": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Marnie": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Shane": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Jas": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Leah": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Dwarf": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Krobus": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\MrQi": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Sandy": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Bouncer": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Gunther": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Marlon": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Henchman": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Willy": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\ParrotBoy": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Birdie": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Kent": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\NPCDispositions": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "BuildingUpgrades\\Greenhouse": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\Quests": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\weapons": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\furniture": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\mail": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\Monsters": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Maps\\Festivals": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Movies": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\temporary_sprites_1": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\critters": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\bushes": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\MovieTheaterScreen_TileSheet": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Wilderness Golem": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\HomeRenovations": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.HomeRenovations.HomeRenovation\u003E", + "LooseSprites\\GemBird": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\SpecialOrders": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.SpecialOrderData\u003E", + "Minigames\\Clouds": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\Blueprints": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "LooseSprites\\robinAtWork": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\shoeColors": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\skinColors": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\SpousePatios": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Buildings\\houses": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\FarmAnimals": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\Fish": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "LooseSprites\\Lighting\\projectorLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\fishTankLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\SeaMonster": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\Crops": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\HairData": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\ChairTiles": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Portraits\\AnsweringMachine": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\Locations": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\Events\\FarmHouse": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\Events\\Trailer": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\EngagementDialogue": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Characters\\Dialogue\\MarriageDialogue": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Characters\\Dialogue\\rainy": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\animationDescriptions": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\AdditionalFarms": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModFarmType\u003E", + "Data\\AdditionalLanguages": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModLanguage\u003E", + "Data\\Festivals\\FestivalDates": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\Furniture": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\Boots": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\hats": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data//CookingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\achievements": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\AdditionalWallpaperFlooring": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModWallpaperOrFlooring\u003E", + "TerrainFeatures\\Flooring": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TerrainFeatures\\Flooring_winter": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\fruitTrees": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "TileSheets\\fruitTrees": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TerrainFeatures\\hoeDirt": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TerrainFeatures\\hoeDirtDark": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TerrainFeatures\\hoeDirtSnow": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TerrainFeatures\\Quartz": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TerrainFeatures\\mushroom_tree": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TerrainFeatures\\tree_palm2": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TerrainFeatures\\tree_palm": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\AquariumFish": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\AquariumFish": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Portraits\\Bear": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\TV\\TipChannel": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\TV\\CookingChannel": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Maps\\walls_and_floors": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\Bundles": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Minigames\\Darts": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Minigames\\boatJourneyMap": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Effects\\ShadowRemoveMG3.8.0": "Microsoft.Xna.Framework.Graphics.Effect", + "LooseSprites\\CraneGame": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Minigames\\MineCart": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Minigames\\MaruComet": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Minigames\\jojacorps": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\boardGame": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\boardGameBorder": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\cowPhotos": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\cowPhotosWinter": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Minigames\\Intro": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\spring_outdoorsTileSheet": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\nightSceneMaru": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\nightSceneMaruTrees": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\SpecialOrdersBoard": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\PaintData": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "LooseSprites\\dye_bench": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\FieldOfficeDonationMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\ForgeMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\EmoteMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\letterBG": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\tailoring": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\TailoringRecipes": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Crafting.TailorItemRecipe\u003E", + "Strings\\credits": "System.Collections.Generic.List\u00601\u003CSystem.String\u003E", + "LooseSprites\\Billboard": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\buildingPlacementTiles": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\textBox": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\chatBox": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\emojis": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\SecretNotesImages": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\farmMap": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites//temporary_sprites_1": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\JunimoNote": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\LanguageButtons": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\map": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Minigames\\TitleButtons": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\TutorialImages\\FarmTut": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\Events\\AbandonedJojaMart": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "LooseSprites\\WillysBoat": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\parrots": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\SafariGuy": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\LightRays": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Cloudy_Ocean_BG": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Cloudy_Ocean_BG_Night": "Microsoft.Xna.Framework.Graphics.Texture2D", + "VolcanoLayouts\\Layouts": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\MoviesReactions": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.MovieCharacterReaction\u003E", + "Data\\ConcessionTastes": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.ConcessionTaste\u003E", + "Data\\Movies": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Movies.MovieData\u003E", + "Data\\Concessions": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.ConcessionItemData\u003E", + "Portraits\\Gil": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Dobson": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\steamAnimation": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\swimShadow": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\CommunityCenter_Refurbished": "xTile.Map", + "Data\\SpouseRooms": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "LooseSprites\\JojaCDForm": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Morris": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\Mountain-BridgeFixed": "xTile.Map", + "Characters\\Monsters\\Shadow Brute": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Shadow Shaman": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Shadow Sniper": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Frost Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Lava Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Iridium Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Green Slime": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\FishPondData": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.FishPond.FishPondData\u003E", + "LooseSprites\\ParrotPlatform": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\SandDuggy": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\SuspensionBridge": "Microsoft.Xna.Framework.Graphics.Texture2D" + }, + "FormerAssets": [] +} \ No newline at end of file diff --git a/src/SMAPI.ModBuildConfig.Analyzer/1.6.0.23268.json b/src/SMAPI.ModBuildConfig.Analyzer/1.6.0.23268.json new file mode 100644 index 000000000..1f1cb2982 --- /dev/null +++ b/src/SMAPI.ModBuildConfig.Analyzer/1.6.0.23268.json @@ -0,0 +1,262 @@ +{ + "AssetMap": { + "TileSheets\\tools": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\springobjects": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Fonts\\SpriteFont1": "Microsoft.Xna.Framework.Graphics.SpriteFont", + "Fonts\\SmallFont": "Microsoft.Xna.Framework.Graphics.SpriteFont", + "Fonts\\tinyFont": "Microsoft.Xna.Framework.Graphics.SpriteFont", + "Data\\Objects": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Objects.ObjectData\u003E", + "Data\\BigCraftables": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.BigCraftables.BigCraftableData\u003E", + "Data\\Achievements": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\CraftingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\CookingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "LooseSprites\\Cursors": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Cursors2": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Giftbox": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\ControllerMaps": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\NPCGiftTastes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "LooseSprites\\Concessions": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\birds": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\daybg": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\nightbg": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\MenuTiles": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\MenuTilesUncolored": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\lantern": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\windowLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\sconceLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\greenLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\indoorWindowLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\shadow": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\animations": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\Buildings": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Buildings.BuildingData\u003E", + "Data\\Characters": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Characters.CharacterData\u003E", + "Data\\Crops": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Crops.CropData\u003E", + "Data\\FarmAnimals": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.FarmAnimals.FarmAnimalData\u003E", + "Data\\FloorsAndPaths": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.FloorsAndPaths.FloorPathData\u003E", + "Data\\FruitTrees": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.FruitTrees.FruitTreeData\u003E", + "Data\\LocationContexts": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.LocationContexts.LocationContextData\u003E", + "Data\\Pants": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Pants.PantsData\u003E", + "Data\\Pets": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Pets.PetData\u003E", + "Data\\Shirts": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Shirts.ShirtData\u003E", + "Data\\Tools": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Tools.ToolData\u003E", + "Data\\Weapons": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Weapons.WeaponData\u003E", + "TileSheets\\crops": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\emotes": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\debris": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\Craftables": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\rain": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\BuffsIcons": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\hairstyles": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\shirts": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\pants": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\hats": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\accessories": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\ChairTiles": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\font_bold": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\font_colored": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\weapons": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\Projectiles": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\Bundles": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\PassiveFestivals": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.PassiveFestivalData\u003E", + "Data\\Locations": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Locations.LocationData\u003E", + "Portraits\\MrQi": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\AnsweringMachine": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\mail": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Minigames\\Clouds": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\Quests": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\Shops": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Shops.ShopData\u003E", + "Data\\Monsters": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Maps\\Festivals": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Movies": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\temporary_sprites_1": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\critters": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\bushes": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\MovieTheaterScreen_TileSheet": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Wilderness Golem": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\HairData": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Characters\\Farmer\\shoeColors": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Farmer\\skinColors": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\HomeRenovations": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.HomeRenovations.HomeRenovation\u003E", + "LooseSprites\\GemBird": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\Machines": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Machines.MachineData\u003E", + "Data\\Fish": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "LooseSprites\\Lighting\\projectorLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Lighting\\fishTankLight": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Buildings\\houses": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\ChairTiles": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\GarbageCans": "StardewValley.GameData.GarbageCans.GarbageCanData", + "Data\\Minecarts": "StardewValley.GameData.Minecarts.MinecartData", + "Data\\Events\\FarmHouse": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\Events\\Trailer": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\SecretNotes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", + "Data\\EngagementDialogue": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\animationDescriptions": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\Fences": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Fences.FenceData\u003E", + "Data\\AdditionalFarms": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModFarmType\u003E", + "LooseSprites\\SeaMonster": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\AdditionalLanguages": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModLanguage\u003E", + "Data\\Festivals\\FestivalDates": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\Weddings": "StardewValley.GameData.Weddings.WeddingData", + "Data//CookingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "LooseSprites\\Map": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\WorldMap": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.WorldMaps.WorldMapRegionData\u003E", + "Data\\GiantCrops": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.GiantCrops.GiantCropData\u003E", + "TerrainFeatures\\hoeDirt": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TerrainFeatures\\hoeDirtDark": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TerrainFeatures\\hoeDirtSnow": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\WildTrees": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.WildTrees.WildTreeData\u003E", + "Data\\SpecialOrders": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.SpecialOrders.SpecialOrderData\u003E", + "Data\\Boots": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "LooseSprites\\AquariumFish": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\AquariumFish": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\Furniture": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\hats": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\TV\\TipChannel": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\TV\\CookingChannel": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Data\\AdditionalWallpaperFlooring": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModWallpaperOrFlooring\u003E", + "Maps\\walls_and_floors": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\IncomingPhoneCalls": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.IncomingPhoneCallData\u003E", + "Minigames\\boatJourneyMap": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Effects\\ShadowRemoveMG3.8.0": "Microsoft.Xna.Framework.Graphics.Effect", + "LooseSprites\\CraneGame": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Minigames\\Darts": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\boardGame": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\boardGameBorder": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Minigames\\jojacorps": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\cowPhotos": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\cowPhotosWinter": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Minigames\\Intro": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\spring_outdoorsTileSheet": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Minigames\\MaruComet": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Minigames\\MineCart": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\nightSceneMaru": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\nightSceneMaruTrees": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Strings\\credits": "System.Collections.Generic.List\u00601\u003CSystem.String\u003E", + "LooseSprites\\Billboard": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\PaintData": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "LooseSprites\\textBox": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\chatBox": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\emojis": "Microsoft.Xna.Framework.Graphics.Texture2D", + "TileSheets\\SecretNotesImages": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\dye_bench": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\EmoteMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\FieldOfficeDonationMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\ForgeMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites//temporary_sprites_1": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\JunimoNote": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\LanguageButtons": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\letterBG": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\SpecialOrdersBoard": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\tailoring": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\TailoringRecipes": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Crafting.TailorItemRecipe\u003E", + "Minigames\\TitleButtons": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\TutorialImages\\FarmTut": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\Events\\AbandonedJojaMart": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", + "Portraits\\Gil": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\MonsterSlayerQuests": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.MonsterSlayerQuestData\u003E", + "LooseSprites\\steamAnimation": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\swimShadow": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\WillysBoat": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Dobson": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\CommunityCenter_Refurbished": "xTile.Map", + "LooseSprites\\parrots": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\SafariGuy": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\LightRays": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Cloudy_Ocean_BG": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\Cloudy_Ocean_BG_Night": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\JojaCDForm": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Portraits\\Morris": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\MuseumRewards": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Museum.MuseumRewards\u003E", + "Portraits\\Abigail": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Maps\\Mountain-BridgeFixed": "xTile.Map", + "Data\\MoviesReactions": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.MovieCharacterReaction\u003E", + "Data\\ConcessionTastes": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.ConcessionTaste\u003E", + "Data\\Movies": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Movies.MovieData\u003E", + "Data\\Concessions": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.ConcessionItemData\u003E", + "Characters\\Monsters\\Shadow Brute": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Shadow Shaman": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Shadow Sniper": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Frost Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Lava Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Iridium Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Characters\\Monsters\\Green Slime": "Microsoft.Xna.Framework.Graphics.Texture2D", + "VolcanoLayouts\\Layouts": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Buildings\\Error": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\FishPondData": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.FishPonds.FishPondData\u003E", + "LooseSprites\\ParrotPlatform": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\SandDuggy": "Microsoft.Xna.Framework.Graphics.Texture2D", + "LooseSprites\\SuspensionBridge": "Microsoft.Xna.Framework.Graphics.Texture2D", + "Data\\AudioChanges": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.AudioCueData\u003E" + }, + "FormerAssets": [ + "Fonts\\tinyFontBorder", + "Data\\ObjectInformation", + "Data\\ClothingInformation", + "Data\\BigCraftablesInformation", + "Data\\ObjectContextTags", + "TileSheets\\furniture", + "TileSheets\\furnitureFront", + "Portraits\\George", + "Portraits\\Evelyn", + "Portraits\\Alex", + "Portraits\\Emily", + "Portraits\\Haley", + "Portraits\\Jodi", + "Portraits\\Sam", + "Portraits\\Vincent", + "Portraits\\Clint", + "Portraits\\Lewis", + "Portraits\\Caroline", + "Portraits\\Pierre", + "Portraits\\Gus", + "Portraits\\Pam", + "Portraits\\Penny", + "Portraits\\Harvey", + "Portraits\\Elliott", + "Portraits\\Maru", + "Portraits\\Robin", + "Portraits\\Demetrius", + "Portraits\\Sebastian", + "Portraits\\Linus", + "Portraits\\Wizard", + "Portraits\\Marnie", + "Portraits\\Shane", + "Portraits\\Jas", + "Portraits\\Leah", + "Portraits\\Dwarf", + "Portraits\\Krobus", + "Portraits\\Sandy", + "Portraits\\Bouncer", + "Portraits\\Gunther", + "Portraits\\Marlon", + "Portraits\\Henchman", + "Portraits\\Willy", + "Portraits\\ParrotBoy", + "Portraits\\Birdie", + "Portraits\\Kent", + "Data\\NPCDispositions", + "BuildingUpgrades\\Greenhouse", + "Data\\weapons", + "Data\\furniture", + "Data\\Blueprints", + "LooseSprites\\robinAtWork", + "Data\\SpousePatios", + "Characters\\Dialogue\\MarriageDialogue", + "Characters\\Dialogue\\rainy", + "Data\\achievements", + "TerrainFeatures\\Flooring", + "TerrainFeatures\\Flooring_winter", + "Data\\fruitTrees", + "TileSheets\\fruitTrees", + "TerrainFeatures\\Quartz", + "TerrainFeatures\\mushroom_tree", + "TerrainFeatures\\tree_palm2", + "TerrainFeatures\\tree_palm", + "Portraits\\Bear", + "LooseSprites\\buildingPlacementTiles", + "LooseSprites\\farmMap", + "LooseSprites\\map", + "Data\\SpouseRooms" + ] +} \ No newline at end of file diff --git a/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs new file mode 100644 index 000000000..a5124554d --- /dev/null +++ b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Reflection; +using System.IO; +using Newtonsoft.Json; +using System.Text.RegularExpressions; + +namespace StardewModdingAPI.ModBuildConfig.Analyzer +{ + public class VersionModel + { + public VersionModel(Dictionary assetMap, HashSet missingAssets) + { + this.AssetMap = assetMap; + this.FormerAssets = missingAssets; + } + + public Dictionary AssetMap { get; set; } + public HashSet FormerAssets { get; set; } + } + + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class ContentManagerAnalyzer : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics { get; } + public VersionModel OneSixRules { get; } + + + /// The diagnostic info for an avoidable net field access. + private readonly DiagnosticDescriptor AvoidBadTypeRule = new( + id: "AvoidContentManagerBadType", + title: "Avoid incorrectly typing ContentManager Loads", + messageFormat: "'{0}' uses the {1} type, but {2} is in use instead. See https://smapi.io/package/avoid-contentmanager-type for details.", + category: "SMAPI.CommonErrors", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + helpLinkUri: "https://smapi.io/package/avoid-contentmanager-type" + ); + + public ContentManagerAnalyzer() + { + using (Stream stream = this.GetType().Assembly.GetManifestResourceStream("StardewModdingAPI.ModBuildConfig.Analyzer.1.6.0.23268.json")) + using (StreamReader reader = new StreamReader(stream)) + { + this.OneSixRules = JsonConvert.DeserializeObject(reader.ReadToEnd()); + } + this.SupportedDiagnostics = ImmutableArray.CreateRange(new[] { this.AvoidBadTypeRule }); + } + + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); + context.EnableConcurrentExecution(); + + context.RegisterSyntaxNodeAction( + this.AnalyzeContentManagerLoads, + SyntaxKind.InvocationExpression + ); + } + + private void AnalyzeContentManagerLoads(SyntaxNodeAnalysisContext context) + { + var invocation = (InvocationExpressionSyntax)context.Node; + var memberAccess = invocation.Expression as MemberAccessExpressionSyntax; + if (memberAccess == null || memberAccess.Name.Identifier.ValueText != "Load") + return; + // "Data\\Fish" -> Data\Fish + string assetName = invocation.ArgumentList.Arguments[0].ToString().Replace("\"", "").Replace("\\\\", "\\"); + + var formatter = new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters); + string genericArgument = context.SemanticModel.GetTypeInfo((memberAccess.Name as GenericNameSyntax).TypeArgumentList.Arguments[0]).Type.ToDisplayString(formatter); + + if (this.OneSixRules.AssetMap.TryGetValue(assetName, out string expectedType)) + { + expectedType = Regex.Replace(expectedType, "`\\d+", ""); + if (genericArgument != expectedType) + { + context.ReportDiagnostic(Diagnostic.Create(this.AvoidBadTypeRule, context.Node.GetLocation(), assetName, expectedType, genericArgument)); + } + } + } + } +} diff --git a/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj b/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj index 7ac3277ec..367fd2a39 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj +++ b/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj @@ -10,12 +10,17 @@ + + + + + diff --git a/src/SMAPI.sln b/src/SMAPI.sln index 4ed075106..97f309236 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31912.275 @@ -100,6 +100,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiProvider" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiConsumer", "SMAPI.Tests.ModApiConsumer\SMAPI.Tests.ModApiConsumer.csproj", "{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMAPI.ModBuildConfig.Analyzer.DataGeneration", "SMAPI.ModBuildConfig.Analyzer.DataGeneration\SMAPI.ModBuildConfig.Analyzer.DataGeneration.csproj", "{5AC3086F-9471-4369-AA64-66F01104B2E6}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5 @@ -166,6 +168,10 @@ Global {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Release|Any CPU.Build.0 = Release|Any CPU + {5AC3086F-9471-4369-AA64-66F01104B2E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5AC3086F-9471-4369-AA64-66F01104B2E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5AC3086F-9471-4369-AA64-66F01104B2E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5AC3086F-9471-4369-AA64-66F01104B2E6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -186,6 +192,7 @@ Global {3B5BF14D-F612-4C83-9EF6-E3EBFCD08766} = {4D661178-38FB-43E4-AA5F-9B0406919344} {239AEEAC-07D1-4A3F-AA99-8C74F5038F50} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} + {5AC3086F-9471-4369-AA64-66F01104B2E6} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {70143042-A862-47A8-A677-7C819DDC90DC} From 79c52b4625df29bcd36492352ab453aee0dd09f8 Mon Sep 17 00:00:00 2001 From: SinZ Date: Mon, 16 Oct 2023 12:07:26 +1100 Subject: [PATCH 2/8] Fix this always failing as Roslyn adds spaces between generics which cecil doesn't --- .../ContentManagerAnalyzerTests.cs | 31 +++++++++++++++++++ .../ContentManagerAnalyzer.cs | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs index c87a4eb84..743c3fb41 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs @@ -33,6 +33,28 @@ public void Entry() } "; + const string SampleUnrelatedGoodProgram = @" + using System; + using System.Collections.Generic; + + namespace Sample; + class Loader + { + public T Load(string arg) + { + return default(T); + } + } + class ModEntry + { + public void Entry() + { + var loader = new Loader(); + var test = loader.Load>(""Data\Fish""); + } + } + "; + /// The line number where the unit tested code is injected into . private const int SampleCodeLine = 14; @@ -77,6 +99,15 @@ public void BadType_RaisesDiagnostic(string codeText, int column, string assetNa this.VerifyCSharpDiagnostic(code, expected); } + [TestCase("Game1.content.Load>(\"Data\\\\Fish\");", true)] + [TestCase(SampleUnrelatedGoodProgram, false)] + + public void ValidCode_HasNoDiagnostics(string codeText, bool useWrapper) + { + string code = useWrapper ? SampleProgram.Replace("{{test-code}}", codeText) : codeText; + this.VerifyCSharpDiagnostic(code); + } + /********* ** Helpers diff --git a/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs index a5124554d..7a1403310 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs @@ -74,7 +74,7 @@ private void AnalyzeContentManagerLoads(SyntaxNodeAnalysisContext context) string assetName = invocation.ArgumentList.Arguments[0].ToString().Replace("\"", "").Replace("\\\\", "\\"); var formatter = new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters); - string genericArgument = context.SemanticModel.GetTypeInfo((memberAccess.Name as GenericNameSyntax).TypeArgumentList.Arguments[0]).Type.ToDisplayString(formatter); + string genericArgument = context.SemanticModel.GetTypeInfo((memberAccess.Name as GenericNameSyntax).TypeArgumentList.Arguments[0]).Type.ToDisplayString(formatter).Replace(" ", ""); if (this.OneSixRules.AssetMap.TryGetValue(assetName, out string expectedType)) { From 9a32240a70219c1acf50f43d8e49aef0823551f4 Mon Sep 17 00:00:00 2001 From: SinZ Date: Sun, 12 Nov 2023 13:41:50 +1100 Subject: [PATCH 3/8] Fix unit tests --- .../ContentManagerAnalyzerTests.cs | 2 +- .../Mock/StardewValley/Game1.cs | 7 +++++++ .../Mock/StardewValley/LocalizedContentManager.cs | 13 +++++++++++++ .../ContentManagerAnalyzer.cs | 5 +++++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/Game1.cs create mode 100644 src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/LocalizedContentManager.cs diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs index 743c3fb41..0717e4ec3 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs @@ -82,7 +82,7 @@ public void EmptyCode_HasNoDiagnostics() /// The expression which should be reported. /// The net type name which should be reported. /// The suggested property name which should be reported. - [TestCase("Game1.content.Load>(\"Data\\\\Fish\");", 0, "Data\\Fish", "System.Collections.Generic.Dictionary", "System.Collections.Generic.Dictionary")] + [TestCase("Game1.content.Load>(\"Data\\\\Fish\");", 0, "Data\\Fish", "System.Collections.Generic.Dictionary", "System.Collections.Generic.Dictionary")] public void BadType_RaisesDiagnostic(string codeText, int column, string assetName, string expectedType, string suggestedType) { // arrange diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/Game1.cs b/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/Game1.cs new file mode 100644 index 000000000..b5849eaf0 --- /dev/null +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/Game1.cs @@ -0,0 +1,7 @@ +namespace StardewValley +{ + public class Game1 + { + public static LocalizedContentManager content = new(); + } +} diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/LocalizedContentManager.cs b/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/LocalizedContentManager.cs new file mode 100644 index 000000000..3b88a8c56 --- /dev/null +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/LocalizedContentManager.cs @@ -0,0 +1,13 @@ +// ReSharper disable CheckNamespace, InconsistentNaming -- matches Stardew Valley's code +// ReSharper disable UnusedMember.Global -- used dynamically for unit tests +namespace StardewValley +{ + /// A simplified version of Stardew Valley's StardewValley.LocalizedContentManager class for unit testing. + public class LocalizedContentManager + { + public T Load(string assetName) + { + return default!; + } + } +} diff --git a/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs index 7a1403310..f894d4972 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs @@ -70,6 +70,9 @@ private void AnalyzeContentManagerLoads(SyntaxNodeAnalysisContext context) var memberAccess = invocation.Expression as MemberAccessExpressionSyntax; if (memberAccess == null || memberAccess.Name.Identifier.ValueText != "Load") return; + string? loadNamespace = context.SemanticModel.GetSymbolInfo(memberAccess).Symbol?.ContainingNamespace.Name; + if (!(loadNamespace == "StardewValley" || loadNamespace == "StardewModdingAPI")) + return; // "Data\\Fish" -> Data\Fish string assetName = invocation.ArgumentList.Arguments[0].ToString().Replace("\"", "").Replace("\\\\", "\\"); @@ -78,6 +81,8 @@ private void AnalyzeContentManagerLoads(SyntaxNodeAnalysisContext context) if (this.OneSixRules.AssetMap.TryGetValue(assetName, out string expectedType)) { + // delete `3 as I can't convince Roslyn and Cecil to agree + // TODO: Move into DataGeneration expectedType = Regex.Replace(expectedType, "`\\d+", ""); if (genericArgument != expectedType) { From 94cb26cc284ee5409ab7aa9eee4bec0ef8215140 Mon Sep 17 00:00:00 2001 From: SinZ Date: Sat, 17 Feb 2024 15:27:40 +1100 Subject: [PATCH 4/8] Switch AvoidContentManagerBadType to rely on DataLoader --- .../Program.cs | 107 ------- ...BuildConfig.Analyzer.DataGeneration.csproj | 25 -- .../ContentManagerAnalyzerTests.cs | 2 +- .../Mock/StardewValley/DataLoader.cs | 15 + .../1.5.6.22018.json | 233 ---------------- .../1.6.0.23268.json | 262 ------------------ .../ContentManagerAnalyzer.cs | 41 +-- .../SMAPI.ModBuildConfig.Analyzer.csproj | 5 - src/SMAPI.sln | 24 +- 9 files changed, 35 insertions(+), 679 deletions(-) delete mode 100644 src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/Program.cs delete mode 100644 src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/SMAPI.ModBuildConfig.Analyzer.DataGeneration.csproj create mode 100644 src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/DataLoader.cs delete mode 100644 src/SMAPI.ModBuildConfig.Analyzer/1.5.6.22018.json delete mode 100644 src/SMAPI.ModBuildConfig.Analyzer/1.6.0.23268.json diff --git a/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/Program.cs b/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/Program.cs deleted file mode 100644 index f7d3fb3b7..000000000 --- a/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/Program.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System.Text.Json; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Collections.Generic; -using StardewModdingAPI.ModBuildConfig.Analyzer; -using StardewModdingAPI.Toolkit; - -Console.WriteLine("Hello, World!"); - -var stardew = AssemblyDefinition.ReadAssembly("Stardew Valley.dll"); - -Dictionary AssetMap = new Dictionary(); - -List messagesForLater = new(); -foreach (var module in stardew.Modules) -{ - var types = module.GetTypes().Where(type => type.BaseType != null); - - foreach (var type in types) - { - foreach (var method in type.Methods) - { - if (method.HasBody) - { - - ILProcessor cil = method.Body.GetILProcessor(); - Collection instructions = cil.Body.Instructions; - - Instruction prevInstruction = Instruction.Create(OpCodes.Nop); - foreach (var instruction in instructions) - { - if (instruction.OpCode.Code == Code.Nop) - continue; - if (instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Callvirt || instruction.OpCode == OpCodes.Newobj) - { - var methodInstruction = (MethodReference)instruction.Operand; - if (methodInstruction.Name == "Load") { - if (methodInstruction.DeclaringType.FullName != "StardewValley.LocalizedContentManager") - { - Console.WriteLine("Found a Load that was not StardewValley.LocalizedContentManager " + method.DeclaringType.FullName); - continue; - } - var genericMethod = (GenericInstanceMethod)methodInstruction; - string genericParameter = genericMethod.GenericArguments[0]?.FullName ?? ""; - string? assetName = null; - if (prevInstruction.OpCode == OpCodes.Ldstr) - { - assetName = (string)prevInstruction.Operand; - } - else - { - messagesForLater.Add($"{method.FullName} is calling Load {methodInstruction} (prev instruction: {prevInstruction})"); - } - if (assetName != null) - { - if (AssetMap.TryGetValue(assetName, out string existingType)) - { - if (genericParameter != existingType) - { - Console.WriteLine($"Found a new use of {assetName}: Previously {existingType} now {genericParameter}"); - } - } - else - { - AssetMap[assetName] = genericParameter; - } - } - } - } - prevInstruction = instruction; - } - } - } - } -} - - -Directory.CreateDirectory("outputs"); -var currentVersion = new SemanticVersion(stardew.Name.Version); -HashSet missingAssets = new(); -foreach (string file in Directory.GetFiles("outputs")) -{ - if (file.EndsWith(stardew.Name.Version + ".json")) continue; - var otherVersion = new SemanticVersion(Path.GetFileNameWithoutExtension(file), true); - if (otherVersion.IsNewerThan(currentVersion)) continue; - try - { - var versionInfo = JsonSerializer.Deserialize(File.ReadAllText(file)); - foreach (var (asset, type) in versionInfo.AssetMap) - { - if (!AssetMap.ContainsKey(asset)) - { - missingAssets.Add(asset); - } - } - } - catch { } -} -string jsonOutput = JsonSerializer.Serialize(new VersionModel(AssetMap, missingAssets), new JsonSerializerOptions -{ - WriteIndented = true, -}); -File.WriteAllText($"outputs/{stardew.Name.Version}.json", jsonOutput); - - - - diff --git a/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/SMAPI.ModBuildConfig.Analyzer.DataGeneration.csproj b/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/SMAPI.ModBuildConfig.Analyzer.DataGeneration.csproj deleted file mode 100644 index c53790785..000000000 --- a/src/SMAPI.ModBuildConfig.Analyzer.DataGeneration/SMAPI.ModBuildConfig.Analyzer.DataGeneration.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - Exe - net6.0 - enable - enable - - - - - - - - - - - - - - - - - - diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs index 0717e4ec3..73573d789 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs @@ -82,7 +82,7 @@ public void EmptyCode_HasNoDiagnostics() /// The expression which should be reported. /// The net type name which should be reported. /// The suggested property name which should be reported. - [TestCase("Game1.content.Load>(\"Data\\\\Fish\");", 0, "Data\\Fish", "System.Collections.Generic.Dictionary", "System.Collections.Generic.Dictionary")] + [TestCase("Game1.content.Load>(\"Data\\\\Fish\");", 0, "Data\\Fish", "System.Collections.Generic.Dictionary", "System.Collections.Generic.Dictionary")] public void BadType_RaisesDiagnostic(string codeText, int column, string assetName, string expectedType, string suggestedType) { // arrange diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/DataLoader.cs b/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/DataLoader.cs new file mode 100644 index 000000000..646b8c7e7 --- /dev/null +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/Mock/StardewValley/DataLoader.cs @@ -0,0 +1,15 @@ +// ReSharper disable CheckNamespace, InconsistentNaming -- matches Stardew Valley's code +// ReSharper disable UnusedMember.Global -- used dynamically for unit tests +using System.Collections.Generic; + +namespace StardewValley +{ + /// A simplified version of Stardew Valley's StardewValley.DataLoader class for unit testing. + public static class DataLoader + { + public static Dictionary Fish(LocalizedContentManager content) + { + return default!; + } + } +} diff --git a/src/SMAPI.ModBuildConfig.Analyzer/1.5.6.22018.json b/src/SMAPI.ModBuildConfig.Analyzer/1.5.6.22018.json deleted file mode 100644 index f2f933062..000000000 --- a/src/SMAPI.ModBuildConfig.Analyzer/1.5.6.22018.json +++ /dev/null @@ -1,233 +0,0 @@ -{ - "AssetMap": { - "TileSheets\\tools": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\springobjects": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Fonts\\SpriteFont1": "Microsoft.Xna.Framework.Graphics.SpriteFont", - "Fonts\\SmallFont": "Microsoft.Xna.Framework.Graphics.SpriteFont", - "Fonts\\tinyFont": "Microsoft.Xna.Framework.Graphics.SpriteFont", - "Fonts\\tinyFontBorder": "Microsoft.Xna.Framework.Graphics.SpriteFont", - "Data\\ObjectInformation": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\ClothingInformation": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\BigCraftablesInformation": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\Achievements": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\CraftingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\CookingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "LooseSprites\\Cursors": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Cursors2": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Giftbox": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\ControllerMaps": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\NPCGiftTastes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\SecretNotes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "LooseSprites\\Concessions": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\birds": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\daybg": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\nightbg": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\MenuTiles": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\MenuTilesUncolored": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\lantern": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\windowLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\sconceLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\greenLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\indoorWindowLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\shadow": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\animations": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\crops": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\emotes": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\debris": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\Craftables": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\rain": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\BuffsIcons": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\ObjectContextTags": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Characters\\Farmer\\hairstyles": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\shirts": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\pants": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\hats": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\accessories": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\furniture": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\furnitureFront": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\ChairTiles": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\font_bold": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\font_colored": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\weapons": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\Projectiles": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\George": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Evelyn": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Alex": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Emily": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Haley": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Jodi": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Sam": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Vincent": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Clint": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Lewis": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Caroline": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Abigail": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Pierre": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Gus": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Pam": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Penny": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Harvey": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Elliott": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Maru": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Robin": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Demetrius": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Sebastian": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Linus": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Wizard": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Marnie": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Shane": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Jas": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Leah": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Dwarf": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Krobus": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\MrQi": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Sandy": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Bouncer": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Gunther": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Marlon": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Henchman": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Willy": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\ParrotBoy": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Birdie": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Kent": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\NPCDispositions": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "BuildingUpgrades\\Greenhouse": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\Quests": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\weapons": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\furniture": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\mail": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\Monsters": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Maps\\Festivals": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Movies": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\temporary_sprites_1": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\critters": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\bushes": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\MovieTheaterScreen_TileSheet": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Wilderness Golem": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\HomeRenovations": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.HomeRenovations.HomeRenovation\u003E", - "LooseSprites\\GemBird": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\SpecialOrders": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.SpecialOrderData\u003E", - "Minigames\\Clouds": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\Blueprints": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "LooseSprites\\robinAtWork": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\shoeColors": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\skinColors": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\SpousePatios": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Buildings\\houses": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\FarmAnimals": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\Fish": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "LooseSprites\\Lighting\\projectorLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\fishTankLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\SeaMonster": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\Crops": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\HairData": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\ChairTiles": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Portraits\\AnsweringMachine": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\Locations": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\Events\\FarmHouse": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\Events\\Trailer": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\EngagementDialogue": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Characters\\Dialogue\\MarriageDialogue": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Characters\\Dialogue\\rainy": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\animationDescriptions": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\AdditionalFarms": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModFarmType\u003E", - "Data\\AdditionalLanguages": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModLanguage\u003E", - "Data\\Festivals\\FestivalDates": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\Furniture": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\Boots": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\hats": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data//CookingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\achievements": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\AdditionalWallpaperFlooring": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModWallpaperOrFlooring\u003E", - "TerrainFeatures\\Flooring": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TerrainFeatures\\Flooring_winter": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\fruitTrees": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "TileSheets\\fruitTrees": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TerrainFeatures\\hoeDirt": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TerrainFeatures\\hoeDirtDark": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TerrainFeatures\\hoeDirtSnow": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TerrainFeatures\\Quartz": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TerrainFeatures\\mushroom_tree": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TerrainFeatures\\tree_palm2": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TerrainFeatures\\tree_palm": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\AquariumFish": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\AquariumFish": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Portraits\\Bear": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\TV\\TipChannel": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\TV\\CookingChannel": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Maps\\walls_and_floors": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\Bundles": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Minigames\\Darts": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Minigames\\boatJourneyMap": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Effects\\ShadowRemoveMG3.8.0": "Microsoft.Xna.Framework.Graphics.Effect", - "LooseSprites\\CraneGame": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Minigames\\MineCart": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Minigames\\MaruComet": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Minigames\\jojacorps": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\boardGame": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\boardGameBorder": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\cowPhotos": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\cowPhotosWinter": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Minigames\\Intro": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\spring_outdoorsTileSheet": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\nightSceneMaru": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\nightSceneMaruTrees": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\SpecialOrdersBoard": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\PaintData": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "LooseSprites\\dye_bench": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\FieldOfficeDonationMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\ForgeMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\EmoteMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\letterBG": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\tailoring": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\TailoringRecipes": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Crafting.TailorItemRecipe\u003E", - "Strings\\credits": "System.Collections.Generic.List\u00601\u003CSystem.String\u003E", - "LooseSprites\\Billboard": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\buildingPlacementTiles": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\textBox": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\chatBox": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\emojis": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\SecretNotesImages": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\farmMap": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites//temporary_sprites_1": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\JunimoNote": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\LanguageButtons": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\map": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Minigames\\TitleButtons": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\TutorialImages\\FarmTut": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\Events\\AbandonedJojaMart": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "LooseSprites\\WillysBoat": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\parrots": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\SafariGuy": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\LightRays": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Cloudy_Ocean_BG": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Cloudy_Ocean_BG_Night": "Microsoft.Xna.Framework.Graphics.Texture2D", - "VolcanoLayouts\\Layouts": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\MoviesReactions": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.MovieCharacterReaction\u003E", - "Data\\ConcessionTastes": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.ConcessionTaste\u003E", - "Data\\Movies": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Movies.MovieData\u003E", - "Data\\Concessions": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.ConcessionItemData\u003E", - "Portraits\\Gil": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Dobson": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\steamAnimation": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\swimShadow": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\CommunityCenter_Refurbished": "xTile.Map", - "Data\\SpouseRooms": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "LooseSprites\\JojaCDForm": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Morris": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\Mountain-BridgeFixed": "xTile.Map", - "Characters\\Monsters\\Shadow Brute": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Shadow Shaman": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Shadow Sniper": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Frost Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Lava Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Iridium Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Green Slime": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\FishPondData": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.FishPond.FishPondData\u003E", - "LooseSprites\\ParrotPlatform": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\SandDuggy": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\SuspensionBridge": "Microsoft.Xna.Framework.Graphics.Texture2D" - }, - "FormerAssets": [] -} \ No newline at end of file diff --git a/src/SMAPI.ModBuildConfig.Analyzer/1.6.0.23268.json b/src/SMAPI.ModBuildConfig.Analyzer/1.6.0.23268.json deleted file mode 100644 index 1f1cb2982..000000000 --- a/src/SMAPI.ModBuildConfig.Analyzer/1.6.0.23268.json +++ /dev/null @@ -1,262 +0,0 @@ -{ - "AssetMap": { - "TileSheets\\tools": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\springobjects": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Fonts\\SpriteFont1": "Microsoft.Xna.Framework.Graphics.SpriteFont", - "Fonts\\SmallFont": "Microsoft.Xna.Framework.Graphics.SpriteFont", - "Fonts\\tinyFont": "Microsoft.Xna.Framework.Graphics.SpriteFont", - "Data\\Objects": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Objects.ObjectData\u003E", - "Data\\BigCraftables": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.BigCraftables.BigCraftableData\u003E", - "Data\\Achievements": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\CraftingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\CookingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "LooseSprites\\Cursors": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Cursors2": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Giftbox": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\ControllerMaps": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\NPCGiftTastes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "LooseSprites\\Concessions": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\birds": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\daybg": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\nightbg": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\MenuTiles": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\MenuTilesUncolored": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\lantern": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\windowLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\sconceLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\greenLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\indoorWindowLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\shadow": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\animations": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\Buildings": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Buildings.BuildingData\u003E", - "Data\\Characters": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Characters.CharacterData\u003E", - "Data\\Crops": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Crops.CropData\u003E", - "Data\\FarmAnimals": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.FarmAnimals.FarmAnimalData\u003E", - "Data\\FloorsAndPaths": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.FloorsAndPaths.FloorPathData\u003E", - "Data\\FruitTrees": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.FruitTrees.FruitTreeData\u003E", - "Data\\LocationContexts": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.LocationContexts.LocationContextData\u003E", - "Data\\Pants": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Pants.PantsData\u003E", - "Data\\Pets": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Pets.PetData\u003E", - "Data\\Shirts": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Shirts.ShirtData\u003E", - "Data\\Tools": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Tools.ToolData\u003E", - "Data\\Weapons": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Weapons.WeaponData\u003E", - "TileSheets\\crops": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\emotes": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\debris": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\Craftables": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\rain": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\BuffsIcons": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\hairstyles": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\shirts": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\pants": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\hats": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\accessories": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\ChairTiles": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\font_bold": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\font_colored": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\weapons": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\Projectiles": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\Bundles": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\PassiveFestivals": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.PassiveFestivalData\u003E", - "Data\\Locations": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Locations.LocationData\u003E", - "Portraits\\MrQi": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\AnsweringMachine": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\mail": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Minigames\\Clouds": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\Quests": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\Shops": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Shops.ShopData\u003E", - "Data\\Monsters": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Maps\\Festivals": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Movies": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\temporary_sprites_1": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\critters": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\bushes": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\MovieTheaterScreen_TileSheet": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Wilderness Golem": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\HairData": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Characters\\Farmer\\shoeColors": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Farmer\\skinColors": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\HomeRenovations": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.HomeRenovations.HomeRenovation\u003E", - "LooseSprites\\GemBird": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\Machines": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Machines.MachineData\u003E", - "Data\\Fish": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "LooseSprites\\Lighting\\projectorLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Lighting\\fishTankLight": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Buildings\\houses": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\ChairTiles": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\GarbageCans": "StardewValley.GameData.GarbageCans.GarbageCanData", - "Data\\Minecarts": "StardewValley.GameData.Minecarts.MinecartData", - "Data\\Events\\FarmHouse": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\Events\\Trailer": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\SecretNotes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.Int32,System.String\u003E", - "Data\\EngagementDialogue": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\animationDescriptions": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\Fences": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Fences.FenceData\u003E", - "Data\\AdditionalFarms": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModFarmType\u003E", - "LooseSprites\\SeaMonster": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\AdditionalLanguages": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModLanguage\u003E", - "Data\\Festivals\\FestivalDates": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\Weddings": "StardewValley.GameData.Weddings.WeddingData", - "Data//CookingRecipes": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "LooseSprites\\Map": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\WorldMap": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.WorldMaps.WorldMapRegionData\u003E", - "Data\\GiantCrops": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.GiantCrops.GiantCropData\u003E", - "TerrainFeatures\\hoeDirt": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TerrainFeatures\\hoeDirtDark": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TerrainFeatures\\hoeDirtSnow": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\WildTrees": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.WildTrees.WildTreeData\u003E", - "Data\\SpecialOrders": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.SpecialOrders.SpecialOrderData\u003E", - "Data\\Boots": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "LooseSprites\\AquariumFish": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\AquariumFish": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\Furniture": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\hats": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\TV\\TipChannel": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\TV\\CookingChannel": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Data\\AdditionalWallpaperFlooring": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.ModWallpaperOrFlooring\u003E", - "Maps\\walls_and_floors": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\IncomingPhoneCalls": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.IncomingPhoneCallData\u003E", - "Minigames\\boatJourneyMap": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Effects\\ShadowRemoveMG3.8.0": "Microsoft.Xna.Framework.Graphics.Effect", - "LooseSprites\\CraneGame": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Minigames\\Darts": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\boardGame": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\boardGameBorder": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Minigames\\jojacorps": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\cowPhotos": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\cowPhotosWinter": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Minigames\\Intro": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\spring_outdoorsTileSheet": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Minigames\\MaruComet": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Minigames\\MineCart": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\nightSceneMaru": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\nightSceneMaruTrees": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Strings\\credits": "System.Collections.Generic.List\u00601\u003CSystem.String\u003E", - "LooseSprites\\Billboard": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\PaintData": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "LooseSprites\\textBox": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\chatBox": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\emojis": "Microsoft.Xna.Framework.Graphics.Texture2D", - "TileSheets\\SecretNotesImages": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\dye_bench": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\EmoteMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\FieldOfficeDonationMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\ForgeMenu": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites//temporary_sprites_1": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\JunimoNote": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\LanguageButtons": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\letterBG": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\SpecialOrdersBoard": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\tailoring": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\TailoringRecipes": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Crafting.TailorItemRecipe\u003E", - "Minigames\\TitleButtons": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\TutorialImages\\FarmTut": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\Events\\AbandonedJojaMart": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,System.String\u003E", - "Portraits\\Gil": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\MonsterSlayerQuests": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.MonsterSlayerQuestData\u003E", - "LooseSprites\\steamAnimation": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\swimShadow": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\WillysBoat": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Dobson": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\CommunityCenter_Refurbished": "xTile.Map", - "LooseSprites\\parrots": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\SafariGuy": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\LightRays": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Cloudy_Ocean_BG": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\Cloudy_Ocean_BG_Night": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\JojaCDForm": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Portraits\\Morris": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\MuseumRewards": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Museum.MuseumRewards\u003E", - "Portraits\\Abigail": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Maps\\Mountain-BridgeFixed": "xTile.Map", - "Data\\MoviesReactions": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.MovieCharacterReaction\u003E", - "Data\\ConcessionTastes": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.ConcessionTaste\u003E", - "Data\\Movies": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.Movies.MovieData\u003E", - "Data\\Concessions": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.Movies.ConcessionItemData\u003E", - "Characters\\Monsters\\Shadow Brute": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Shadow Shaman": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Shadow Sniper": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Frost Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Lava Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Iridium Bat": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Characters\\Monsters\\Green Slime": "Microsoft.Xna.Framework.Graphics.Texture2D", - "VolcanoLayouts\\Layouts": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Buildings\\Error": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\FishPondData": "System.Collections.Generic.List\u00601\u003CStardewValley.GameData.FishPonds.FishPondData\u003E", - "LooseSprites\\ParrotPlatform": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\SandDuggy": "Microsoft.Xna.Framework.Graphics.Texture2D", - "LooseSprites\\SuspensionBridge": "Microsoft.Xna.Framework.Graphics.Texture2D", - "Data\\AudioChanges": "System.Collections.Generic.Dictionary\u00602\u003CSystem.String,StardewValley.GameData.AudioCueData\u003E" - }, - "FormerAssets": [ - "Fonts\\tinyFontBorder", - "Data\\ObjectInformation", - "Data\\ClothingInformation", - "Data\\BigCraftablesInformation", - "Data\\ObjectContextTags", - "TileSheets\\furniture", - "TileSheets\\furnitureFront", - "Portraits\\George", - "Portraits\\Evelyn", - "Portraits\\Alex", - "Portraits\\Emily", - "Portraits\\Haley", - "Portraits\\Jodi", - "Portraits\\Sam", - "Portraits\\Vincent", - "Portraits\\Clint", - "Portraits\\Lewis", - "Portraits\\Caroline", - "Portraits\\Pierre", - "Portraits\\Gus", - "Portraits\\Pam", - "Portraits\\Penny", - "Portraits\\Harvey", - "Portraits\\Elliott", - "Portraits\\Maru", - "Portraits\\Robin", - "Portraits\\Demetrius", - "Portraits\\Sebastian", - "Portraits\\Linus", - "Portraits\\Wizard", - "Portraits\\Marnie", - "Portraits\\Shane", - "Portraits\\Jas", - "Portraits\\Leah", - "Portraits\\Dwarf", - "Portraits\\Krobus", - "Portraits\\Sandy", - "Portraits\\Bouncer", - "Portraits\\Gunther", - "Portraits\\Marlon", - "Portraits\\Henchman", - "Portraits\\Willy", - "Portraits\\ParrotBoy", - "Portraits\\Birdie", - "Portraits\\Kent", - "Data\\NPCDispositions", - "BuildingUpgrades\\Greenhouse", - "Data\\weapons", - "Data\\furniture", - "Data\\Blueprints", - "LooseSprites\\robinAtWork", - "Data\\SpousePatios", - "Characters\\Dialogue\\MarriageDialogue", - "Characters\\Dialogue\\rainy", - "Data\\achievements", - "TerrainFeatures\\Flooring", - "TerrainFeatures\\Flooring_winter", - "Data\\fruitTrees", - "TileSheets\\fruitTrees", - "TerrainFeatures\\Quartz", - "TerrainFeatures\\mushroom_tree", - "TerrainFeatures\\tree_palm2", - "TerrainFeatures\\tree_palm", - "Portraits\\Bear", - "LooseSprites\\buildingPlacementTiles", - "LooseSprites\\farmMap", - "LooseSprites\\map", - "Data\\SpouseRooms" - ] -} \ No newline at end of file diff --git a/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs index f894d4972..345d697e2 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs @@ -1,35 +1,19 @@ using System; using System.Collections.Generic; -using System.Text; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis; using System.Collections.Immutable; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using System.Reflection; -using System.IO; -using Newtonsoft.Json; -using System.Text.RegularExpressions; +using System.Linq; namespace StardewModdingAPI.ModBuildConfig.Analyzer { - public class VersionModel - { - public VersionModel(Dictionary assetMap, HashSet missingAssets) - { - this.AssetMap = assetMap; - this.FormerAssets = missingAssets; - } - - public Dictionary AssetMap { get; set; } - public HashSet FormerAssets { get; set; } - } - [DiagnosticAnalyzer(LanguageNames.CSharp)] public class ContentManagerAnalyzer : DiagnosticAnalyzer { public override ImmutableArray SupportedDiagnostics { get; } - public VersionModel OneSixRules { get; } /// The diagnostic info for an avoidable net field access. @@ -45,11 +29,6 @@ public class ContentManagerAnalyzer : DiagnosticAnalyzer public ContentManagerAnalyzer() { - using (Stream stream = this.GetType().Assembly.GetManifestResourceStream("StardewModdingAPI.ModBuildConfig.Analyzer.1.6.0.23268.json")) - using (StreamReader reader = new StreamReader(stream)) - { - this.OneSixRules = JsonConvert.DeserializeObject(reader.ReadToEnd()); - } this.SupportedDiagnostics = ImmutableArray.CreateRange(new[] { this.AvoidBadTypeRule }); } @@ -76,17 +55,19 @@ private void AnalyzeContentManagerLoads(SyntaxNodeAnalysisContext context) // "Data\\Fish" -> Data\Fish string assetName = invocation.ArgumentList.Arguments[0].ToString().Replace("\"", "").Replace("\\\\", "\\"); - var formatter = new SymbolDisplayFormat(typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters); - string genericArgument = context.SemanticModel.GetTypeInfo((memberAccess.Name as GenericNameSyntax).TypeArgumentList.Arguments[0]).Type.ToDisplayString(formatter).Replace(" ", ""); + if (!assetName.StartsWith("Data", StringComparison.InvariantCultureIgnoreCase)) return; + string dataAsset = assetName.Substring(5); - if (this.OneSixRules.AssetMap.TryGetValue(assetName, out string expectedType)) + var dataLoader = context.Compilation.GetTypeByMetadataName("StardewValley.DataLoader"); + var dataMatch = dataLoader.GetMembers().FirstOrDefault(m => m.Name == dataAsset); + if (dataMatch == null) return; + if (dataMatch is IMethodSymbol method) { - // delete `3 as I can't convince Roslyn and Cecil to agree - // TODO: Move into DataGeneration - expectedType = Regex.Replace(expectedType, "`\\d+", ""); - if (genericArgument != expectedType) + var genericArgument = context.SemanticModel.GetTypeInfo((memberAccess.Name as GenericNameSyntax).TypeArgumentList.Arguments[0]).Type; + // Can't use the proper way of using SymbolEquityComparer due to System.Collections overlapping with CoreLib. + if (method.ReturnType.ToString() != genericArgument.ToString()) { - context.ReportDiagnostic(Diagnostic.Create(this.AvoidBadTypeRule, context.Node.GetLocation(), assetName, expectedType, genericArgument)); + context.ReportDiagnostic(Diagnostic.Create(this.AvoidBadTypeRule, context.Node.GetLocation(), assetName, method.ReturnType.ToString(), genericArgument.ToString())); } } } diff --git a/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj b/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj index 367fd2a39..7ac3277ec 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj +++ b/src/SMAPI.ModBuildConfig.Analyzer/SMAPI.ModBuildConfig.Analyzer.csproj @@ -10,17 +10,12 @@ - - - - - diff --git a/src/SMAPI.sln b/src/SMAPI.sln index 97f309236..5e9ecf250 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31912.275 @@ -100,17 +99,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiProvider" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiConsumer", "SMAPI.Tests.ModApiConsumer\SMAPI.Tests.ModApiConsumer.csproj", "{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMAPI.ModBuildConfig.Analyzer.DataGeneration", "SMAPI.ModBuildConfig.Analyzer.DataGeneration\SMAPI.ModBuildConfig.Analyzer.DataGeneration.csproj", "{5AC3086F-9471-4369-AA64-66F01104B2E6}" -EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5 - SMAPI.Internal\SMAPI.Internal.projitems*{0a9bb24f-15ff-4c26-b1a2-81f7ae316518}*SharedItemsImports = 5 - SMAPI.Internal\SMAPI.Internal.projitems*{80efd92f-728f-41e0-8a5b-9f6f49a91899}*SharedItemsImports = 5 - SMAPI.Internal\SMAPI.Internal.projitems*{85208f8d-6fd1-4531-be05-7142490f59fe}*SharedItemsImports = 13 - SMAPI.Internal\SMAPI.Internal.projitems*{cd53ad6f-97f4-4872-a212-50c2a0fd3601}*SharedItemsImports = 5 - SMAPI.Internal\SMAPI.Internal.projitems*{e6da2198-7686-4f1d-b312-4a4dc70884c0}*SharedItemsImports = 5 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU @@ -168,10 +157,6 @@ Global {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Release|Any CPU.Build.0 = Release|Any CPU - {5AC3086F-9471-4369-AA64-66F01104B2E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5AC3086F-9471-4369-AA64-66F01104B2E6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5AC3086F-9471-4369-AA64-66F01104B2E6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5AC3086F-9471-4369-AA64-66F01104B2E6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -192,9 +177,16 @@ Global {3B5BF14D-F612-4C83-9EF6-E3EBFCD08766} = {4D661178-38FB-43E4-AA5F-9B0406919344} {239AEEAC-07D1-4A3F-AA99-8C74F5038F50} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} - {5AC3086F-9471-4369-AA64-66F01104B2E6} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {70143042-A862-47A8-A677-7C819DDC90DC} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{0a9bb24f-15ff-4c26-b1a2-81f7ae316518}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{80efd92f-728f-41e0-8a5b-9f6f49a91899}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{85208f8d-6fd1-4531-be05-7142490f59fe}*SharedItemsImports = 13 + SMAPI.Internal\SMAPI.Internal.projitems*{cd53ad6f-97f4-4872-a212-50c2a0fd3601}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{e6da2198-7686-4f1d-b312-4a4dc70884c0}*SharedItemsImports = 5 + EndGlobalSection EndGlobal From b169de83539a96b4b207b7f4c78a542b32df89dc Mon Sep 17 00:00:00 2001 From: SinZ Date: Sat, 17 Feb 2024 15:55:14 +1100 Subject: [PATCH 5/8] Add PreferDataLoader to suggest using DataLoader where possible --- .../ContentManagerAnalyzerTests.cs | 38 +++++++++++++++++-- ...SMAPI.ModBuildConfig.Analyzer.Tests.csproj | 4 ++ .../ContentManagerAnalyzer.cs | 15 +++++++- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs index 73573d789..917060c16 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs @@ -92,14 +92,46 @@ public void BadType_RaisesDiagnostic(string codeText, int column, string assetNa Id = "AvoidContentManagerBadType", Message = $"'{assetName}' uses the {suggestedType} type, but {expectedType} is in use instead. See https://smapi.io/package/avoid-contentmanager-type for details.", Severity = DiagnosticSeverity.Error, - Locations = new[] { new DiagnosticResultLocation("Test0.cs", SampleCodeLine, SampleCodeColumn + column) } + Locations = [new DiagnosticResultLocation("Test0.cs", SampleCodeLine, SampleCodeColumn + column)] + }; + DiagnosticResult preferDataLoader = new() + { + Id = "PreferContentManagerDataLoader", + Message = $"'{assetName[5..]}' can be accessed using 'DataLoader.{assetName[5..]}(LocalizedContentManager content)' instead. See https://smapi.io/package/prefer-contentmanager-dataloader for details.", + Severity = DiagnosticSeverity.Info, + Locations = [new DiagnosticResultLocation("Test0.cs", SampleCodeLine, SampleCodeColumn + column)] + }; + + // assert + this.VerifyCSharpDiagnostic(code, expected, preferDataLoader); + } + + + + /// Test that the expected diagnostic message is raised for avoidable net field references. + /// The code line to test. + /// The column within the code line where the diagnostic message should be reported. + /// The expression which should be reported. + /// The net type name which should be reported. + /// The suggested property name which should be reported. + [TestCase("Game1.content.Load>(\"Data\\\\Fish\");", 0, "Fish")] + public void PreferDataLoader_RaisesDiagnostic(string codeText, int column, string assetName) + { + // arrange + string code = SampleProgram.Replace("{{test-code}}", codeText); + DiagnosticResult preferDataLoader = new() + { + Id = "PreferContentManagerDataLoader", + Message = $"'{assetName}' can be accessed using 'DataLoader.{assetName}(LocalizedContentManager content)' instead. See https://smapi.io/package/prefer-contentmanager-dataloader for details.", + Severity = DiagnosticSeverity.Info, + Locations = [new DiagnosticResultLocation("Test0.cs", SampleCodeLine, SampleCodeColumn + column)] }; // assert - this.VerifyCSharpDiagnostic(code, expected); + this.VerifyCSharpDiagnostic(code, preferDataLoader); } - [TestCase("Game1.content.Load>(\"Data\\\\Fish\");", true)] + [TestCase("Game1.content.Load>(\"Data\\\\Custom_Asset\");", true)] [TestCase(SampleUnrelatedGoodProgram, false)] public void ValidCode_HasNoDiagnostics(string codeText, bool useWrapper) diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj index c63935c25..fb2a90ba4 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj @@ -15,5 +15,9 @@ + + + + diff --git a/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs index 345d697e2..1ff4b337f 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs @@ -16,7 +16,7 @@ public class ContentManagerAnalyzer : DiagnosticAnalyzer public override ImmutableArray SupportedDiagnostics { get; } - /// The diagnostic info for an avoidable net field access. + /// The diagnostic info for an avoidable runtime casting error. private readonly DiagnosticDescriptor AvoidBadTypeRule = new( id: "AvoidContentManagerBadType", title: "Avoid incorrectly typing ContentManager Loads", @@ -26,10 +26,20 @@ public class ContentManagerAnalyzer : DiagnosticAnalyzer isEnabledByDefault: true, helpLinkUri: "https://smapi.io/package/avoid-contentmanager-type" ); + /// The diagnostic info for best practices using DataLoader + private readonly DiagnosticDescriptor PreferDataLoader = new( + id: "PreferContentManagerDataLoader", + title: "Prefer using DataLoader to ContentManager Loads", + messageFormat: "'{0}' can be accessed using 'DataLoader.{0}(LocalizedContentManager content)' instead. See https://smapi.io/package/prefer-contentmanager-dataloader for details.", + category: "SMAPI.CommonErrors", + defaultSeverity: DiagnosticSeverity.Info, + isEnabledByDefault: true, + helpLinkUri: "https://smapi.io/package/prefer-contentmanager-dataloader" + ); public ContentManagerAnalyzer() { - this.SupportedDiagnostics = ImmutableArray.CreateRange(new[] { this.AvoidBadTypeRule }); + this.SupportedDiagnostics = ImmutableArray.CreateRange(new[] { this.AvoidBadTypeRule, this.PreferDataLoader }); } public override void Initialize(AnalysisContext context) @@ -69,6 +79,7 @@ private void AnalyzeContentManagerLoads(SyntaxNodeAnalysisContext context) { context.ReportDiagnostic(Diagnostic.Create(this.AvoidBadTypeRule, context.Node.GetLocation(), assetName, method.ReturnType.ToString(), genericArgument.ToString())); } + context.ReportDiagnostic(Diagnostic.Create(this.PreferDataLoader, context.Node.GetLocation(), dataAsset)); } } } From 0c2dd7f52d7ee84991df2ce2e140e080d8211af7 Mon Sep 17 00:00:00 2001 From: SinZ Date: Sat, 17 Feb 2024 15:59:01 +1100 Subject: [PATCH 6/8] Switch PreferContentManagerDataLoader to refer to full asset name --- .../ContentManagerAnalyzerTests.cs | 6 +++--- src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs index 917060c16..6a7e6ccf0 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/ContentManagerAnalyzerTests.cs @@ -97,7 +97,7 @@ public void BadType_RaisesDiagnostic(string codeText, int column, string assetNa DiagnosticResult preferDataLoader = new() { Id = "PreferContentManagerDataLoader", - Message = $"'{assetName[5..]}' can be accessed using 'DataLoader.{assetName[5..]}(LocalizedContentManager content)' instead. See https://smapi.io/package/prefer-contentmanager-dataloader for details.", + Message = $"'{assetName}' can be accessed using 'DataLoader.{assetName[5..]}(LocalizedContentManager content)' instead. See https://smapi.io/package/prefer-contentmanager-dataloader for details.", Severity = DiagnosticSeverity.Info, Locations = [new DiagnosticResultLocation("Test0.cs", SampleCodeLine, SampleCodeColumn + column)] }; @@ -114,7 +114,7 @@ public void BadType_RaisesDiagnostic(string codeText, int column, string assetNa /// The expression which should be reported. /// The net type name which should be reported. /// The suggested property name which should be reported. - [TestCase("Game1.content.Load>(\"Data\\\\Fish\");", 0, "Fish")] + [TestCase("Game1.content.Load>(\"Data\\\\Fish\");", 0, "Data\\Fish")] public void PreferDataLoader_RaisesDiagnostic(string codeText, int column, string assetName) { // arrange @@ -122,7 +122,7 @@ public void PreferDataLoader_RaisesDiagnostic(string codeText, int column, strin DiagnosticResult preferDataLoader = new() { Id = "PreferContentManagerDataLoader", - Message = $"'{assetName}' can be accessed using 'DataLoader.{assetName}(LocalizedContentManager content)' instead. See https://smapi.io/package/prefer-contentmanager-dataloader for details.", + Message = $"'{assetName}' can be accessed using 'DataLoader.{assetName[5..]}(LocalizedContentManager content)' instead. See https://smapi.io/package/prefer-contentmanager-dataloader for details.", Severity = DiagnosticSeverity.Info, Locations = [new DiagnosticResultLocation("Test0.cs", SampleCodeLine, SampleCodeColumn + column)] }; diff --git a/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs index 1ff4b337f..3330af31e 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs +++ b/src/SMAPI.ModBuildConfig.Analyzer/ContentManagerAnalyzer.cs @@ -30,7 +30,7 @@ public class ContentManagerAnalyzer : DiagnosticAnalyzer private readonly DiagnosticDescriptor PreferDataLoader = new( id: "PreferContentManagerDataLoader", title: "Prefer using DataLoader to ContentManager Loads", - messageFormat: "'{0}' can be accessed using 'DataLoader.{0}(LocalizedContentManager content)' instead. See https://smapi.io/package/prefer-contentmanager-dataloader for details.", + messageFormat: "'{0}' can be accessed using 'DataLoader.{1}(LocalizedContentManager content)' instead. See https://smapi.io/package/prefer-contentmanager-dataloader for details.", category: "SMAPI.CommonErrors", defaultSeverity: DiagnosticSeverity.Info, isEnabledByDefault: true, @@ -79,7 +79,7 @@ private void AnalyzeContentManagerLoads(SyntaxNodeAnalysisContext context) { context.ReportDiagnostic(Diagnostic.Create(this.AvoidBadTypeRule, context.Node.GetLocation(), assetName, method.ReturnType.ToString(), genericArgument.ToString())); } - context.ReportDiagnostic(Diagnostic.Create(this.PreferDataLoader, context.Node.GetLocation(), dataAsset)); + context.ReportDiagnostic(Diagnostic.Create(this.PreferDataLoader, context.Node.GetLocation(), assetName, dataAsset)); } } } From 516035a5e44cd0d7de41ea516c79a2f8ee1b305c Mon Sep 17 00:00:00 2001 From: SinZ Date: Sat, 17 Feb 2024 16:02:37 +1100 Subject: [PATCH 7/8] Remove redundant folder include --- .../SMAPI.ModBuildConfig.Analyzer.Tests.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj index fb2a90ba4..c63935c25 100644 --- a/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj +++ b/src/SMAPI.ModBuildConfig.Analyzer.Tests/SMAPI.ModBuildConfig.Analyzer.Tests.csproj @@ -15,9 +15,5 @@ - - - - From 9dcc0e727dad2bc979f30da38f1adb4c780f399a Mon Sep 17 00:00:00 2001 From: SinZ Date: Sat, 17 Feb 2024 16:09:07 +1100 Subject: [PATCH 8/8] Revert changes to SMAPI.sln --- src/SMAPI.sln | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/SMAPI.sln b/src/SMAPI.sln index 5e9ecf250..4ed075106 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -1,3 +1,4 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31912.275 @@ -100,6 +101,14 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiConsumer", "SMAPI.Tests.ModApiConsumer\SMAPI.Tests.ModApiConsumer.csproj", "{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}" EndProject Global + GlobalSection(SharedMSBuildProjectFiles) = preSolution + SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{0a9bb24f-15ff-4c26-b1a2-81f7ae316518}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{80efd92f-728f-41e0-8a5b-9f6f49a91899}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{85208f8d-6fd1-4531-be05-7142490f59fe}*SharedItemsImports = 13 + SMAPI.Internal\SMAPI.Internal.projitems*{cd53ad6f-97f4-4872-a212-50c2a0fd3601}*SharedItemsImports = 5 + SMAPI.Internal\SMAPI.Internal.projitems*{e6da2198-7686-4f1d-b312-4a4dc70884c0}*SharedItemsImports = 5 + EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU @@ -181,12 +190,4 @@ Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {70143042-A862-47A8-A677-7C819DDC90DC} EndGlobalSection - GlobalSection(SharedMSBuildProjectFiles) = preSolution - SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5 - SMAPI.Internal\SMAPI.Internal.projitems*{0a9bb24f-15ff-4c26-b1a2-81f7ae316518}*SharedItemsImports = 5 - SMAPI.Internal\SMAPI.Internal.projitems*{80efd92f-728f-41e0-8a5b-9f6f49a91899}*SharedItemsImports = 5 - SMAPI.Internal\SMAPI.Internal.projitems*{85208f8d-6fd1-4531-be05-7142490f59fe}*SharedItemsImports = 13 - SMAPI.Internal\SMAPI.Internal.projitems*{cd53ad6f-97f4-4872-a212-50c2a0fd3601}*SharedItemsImports = 5 - SMAPI.Internal\SMAPI.Internal.projitems*{e6da2198-7686-4f1d-b312-4a4dc70884c0}*SharedItemsImports = 5 - EndGlobalSection EndGlobal