Skip to content

Commit 6efaa65

Browse files
committed
drop support for XNA Framework
Stardew Valley 1.5.5 migrates to MonoGame on all platforms.
1 parent c8c6b38 commit 6efaa65

15 files changed

Lines changed: 60 additions & 195 deletions

File tree

docs/technical/smapi.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ SMAPI uses a small number of conditional compilation constants, which you can se
5757
flag | purpose
5858
---- | -------
5959
`SMAPI_FOR_WINDOWS` | Whether SMAPI is being compiled for Windows; if not set, the code assumes Linux/macOS. Set automatically in `common.targets`.
60-
`SMAPI_FOR_XNA` | Whether SMAPI is being compiled for XNA Framework; if not set, the code assumes MonoGame. Set automatically in `common.targets` with the same value as `SMAPI_FOR_WINDOWS`.
6160

6261
## For SMAPI developers
6362
### Compiling from source

src/SMAPI.ModBuildConfig/build/smapi.targets

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -43,38 +43,24 @@
4343
<!--*********************************************
4444
** Add assembly references
4545
**********************************************-->
46-
<!-- common -->
4746
<ItemGroup>
47+
<!-- game -->
4848
<Reference Include="$(GameExecutableName)" HintPath="$(GamePath)\$(GameExecutableName).exe" Private="$(CopyModReferencesToBuildOutput)" />
4949
<Reference Include="StardewValley.GameData" HintPath="$(GamePath)\StardewValley.GameData.dll" Private="$(CopyModReferencesToBuildOutput)" />
50+
<Reference Include="MonoGame.Framework" HintPath="$(GamePath)\MonoGame.Framework.dll" Private="$(CopyModReferencesToBuildOutput)" />
51+
<Reference Include="xTile" HintPath="$(GamePath)\xTile.dll" Private="$(CopyModReferencesToBuildOutput)" />
52+
53+
<!-- SMAPI -->
5054
<Reference Include="StardewModdingAPI" HintPath="$(GamePath)\StardewModdingAPI.exe" Private="$(CopyModReferencesToBuildOutput)" />
5155
<Reference Include="SMAPI.Toolkit.CoreInterfaces" HintPath="$(GamePath)\smapi-internal\SMAPI.Toolkit.CoreInterfaces.dll" Private="$(CopyModReferencesToBuildOutput)" />
52-
<Reference Include="xTile" HintPath="$(GamePath)\xTile.dll" Private="$(CopyModReferencesToBuildOutput)" />
56+
57+
<!-- Harmony -->
5358
<Reference Include="0Harmony" Condition="'$(EnableHarmony)' == 'true'" HintPath="$(GamePath)\smapi-internal\0Harmony.dll" Private="$(CopyModReferencesToBuildOutput)" />
54-
</ItemGroup>
5559

56-
<!-- Windows only -->
57-
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
58-
<Reference Include="Netcode" HintPath="$(GamePath)\Netcode.dll" Private="$(CopyModReferencesToBuildOutput)" />
60+
<!-- Windows only -->
61+
<Reference Include="Netcode" HintPath="$(GamePath)\Netcode.dll" Private="$(CopyModReferencesToBuildOutput)" Condition="'$(OS)' == 'Windows_NT'" />
5962
</ItemGroup>
6063

61-
<!-- Game framework -->
62-
<Choose>
63-
<When Condition="'$(GameFramework)' == 'Xna'">
64-
<ItemGroup>
65-
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="$(CopyModReferencesToBuildOutput)" />
66-
<Reference Include="Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="$(CopyModReferencesToBuildOutput)" />
67-
<Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="$(CopyModReferencesToBuildOutput)" />
68-
<Reference Include="Microsoft.Xna.Framework.Xact, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="$(CopyModReferencesToBuildOutput)" />
69-
</ItemGroup>
70-
</When>
71-
<Otherwise>
72-
<ItemGroup>
73-
<Reference Include="MonoGame.Framework" HintPath="$(GamePath)\MonoGame.Framework.dll" Private="$(CopyModReferencesToBuildOutput)" />
74-
</ItemGroup>
75-
</Otherwise>
76-
</Choose>
77-
7864

7965
<!--*********************************************
8066
** Show validation messages

src/SMAPI.Mods.ConsoleCommands/SMAPI.Mods.ConsoleCommands.csproj

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
<ItemGroup>
1616
<Reference Include="$(GameExecutableName)" HintPath="$(GamePath)\$(GameExecutableName).exe" Private="False" />
17+
<Reference Include="MonoGame.Framework" HintPath="$(GamePath)\MonoGame.Framework.dll" Private="False" />
1718
<Reference Include="StardewValley.GameData" HintPath="$(GamePath)\StardewValley.GameData.dll" Private="False" />
1819
</ItemGroup>
1920

@@ -22,23 +23,6 @@
2223
<Reference Include="Netcode" HintPath="$(GamePath)\Netcode.dll" Private="False" />
2324
</ItemGroup>
2425

25-
<!-- Game framework -->
26-
<Choose>
27-
<When Condition="$(DefineConstants.Contains(SMAPI_FOR_XNA))">
28-
<ItemGroup>
29-
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
30-
<Reference Include="Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
31-
<Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
32-
<Reference Include="Microsoft.Xna.Framework.Xact, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
33-
</ItemGroup>
34-
</When>
35-
<Otherwise>
36-
<ItemGroup>
37-
<Reference Include="MonoGame.Framework" HintPath="$(GamePath)\MonoGame.Framework.dll" Private="False" />
38-
</ItemGroup>
39-
</Otherwise>
40-
</Choose>
41-
4226
<ItemGroup>
4327
<None Update="manifest.json" CopyToOutputDirectory="PreserveNewest" />
4428
</ItemGroup>

src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchPatcher.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ internal class SpriteBatchPatcher : BasePatcher
1919
public override void Apply(Harmony harmony, IMonitor monitor)
2020
{
2121
harmony.Patch(
22-
original: Constants.GameFramework == GameFramework.Xna
23-
? this.RequireMethod<SpriteBatch>("InternalDraw")
24-
: this.RequireMethod<SpriteBatch>("CheckValid", new[] { typeof(Texture2D) }),
22+
original: this.RequireMethod<SpriteBatch>("CheckValid", new[] { typeof(Texture2D) }),
2523
postfix: this.GetHarmonyMethod(nameof(SpriteBatchPatcher.After_CheckValid))
2624
);
2725
}
@@ -30,13 +28,8 @@ public override void Apply(Harmony harmony, IMonitor monitor)
3028
/*********
3129
** Private methods
3230
*********/
33-
#if SMAPI_FOR_XNA
34-
/// <summary>The method to call after <see cref="SpriteBatch.InternalDraw"/>.</summary>
35-
/// <param name="texture">The texture to validate.</param>
36-
#else
3731
/// <summary>The method to call after <see cref="SpriteBatch.CheckValid"/>.</summary>
3832
/// <param name="texture">The texture to validate.</param>
39-
#endif
4033
private static void After_CheckValid(Texture2D texture)
4134
{
4235
if (texture?.IsDisposed == true)

src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
<ItemGroup>
1717
<Reference Include="$(GameExecutableName)" HintPath="$(GamePath)\$(GameExecutableName).exe" Private="False" />
18+
<Reference Include="MonoGame.Framework" HintPath="$(GamePath)\MonoGame.Framework.dll" Private="False" />
1819
<Reference Include="StardewValley.GameData" HintPath="$(GamePath)\StardewValley.GameData.dll" Private="False" />
1920
<Reference Include="xTile" HintPath="$(GamePath)\xTile.dll" Private="False" />
2021
</ItemGroup>
@@ -24,23 +25,6 @@
2425
<Reference Include="Netcode" HintPath="$(GamePath)\Netcode.dll" Private="False" />
2526
</ItemGroup>
2627

27-
<!-- Game framework -->
28-
<Choose>
29-
<When Condition="$(DefineConstants.Contains(SMAPI_FOR_XNA))">
30-
<ItemGroup>
31-
<Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
32-
<Reference Include="Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
33-
<Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
34-
<Reference Include="Microsoft.Xna.Framework.Xact, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86" Private="False" />
35-
</ItemGroup>
36-
</When>
37-
<Otherwise>
38-
<ItemGroup>
39-
<Reference Include="MonoGame.Framework" HintPath="$(GamePath)\MonoGame.Framework.dll" Private="False" />
40-
</ItemGroup>
41-
</Otherwise>
42-
</Choose>
43-
4428
<ItemGroup>
4529
<None Update="i18n\*.json" CopyToOutputDirectory="PreserveNewest" />
4630
<None Update="manifest.json" CopyToOutputDirectory="PreserveNewest" />

src/SMAPI/Constants.cs

Lines changed: 24 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,7 @@ internal static class EarlyConstants
4040
internal static GamePlatform Platform { get; } = (GamePlatform)Enum.Parse(typeof(GamePlatform), LowLevelEnvironmentUtility.DetectPlatform());
4141

4242
/// <summary>The game framework running the game.</summary>
43-
internal static GameFramework GameFramework { get; } =
44-
#if SMAPI_FOR_XNA
45-
GameFramework.Xna;
46-
#else
47-
GameFramework.MonoGame;
48-
#endif
43+
internal static GameFramework GameFramework { get; } = GameFramework.MonoGame;
4944

5045
/// <summary>The game's assembly name.</summary>
5146
internal static string GameAssemblyName => EarlyConstants.Platform == GamePlatform.Windows ? "Stardew Valley" : "StardewValley";
@@ -260,61 +255,32 @@ internal static PlatformAssemblyMap GetAssemblyMap(Platform targetPlatform, Game
260255
removeAssemblyReferences.Add("StardewModdingAPI.Toolkit.CoreInterfaces");
261256
targetAssemblies.Add(typeof(StardewModdingAPI.IManifest).Assembly);
262257

263-
// get changes for platform
264-
if (Constants.Platform != Platform.Windows)
258+
// XNA Framework before Stardew Valley 1.5.5
259+
removeAssemblyReferences.AddRange(new[]
265260
{
266-
removeAssemblyReferences.AddRange(new[]
267-
{
268-
"Netcode",
269-
"Stardew Valley"
270-
});
271-
targetAssemblies.Add(
272-
typeof(StardewValley.Game1).Assembly // note: includes Netcode types on Linux/macOS
273-
);
274-
}
275-
else
276-
{
277-
removeAssemblyReferences.Add(
278-
"StardewValley"
279-
);
280-
targetAssemblies.AddRange(new[]
281-
{
282-
typeof(Netcode.NetBool).Assembly,
283-
typeof(StardewValley.Game1).Assembly
284-
});
285-
}
261+
"Microsoft.Xna.Framework",
262+
"Microsoft.Xna.Framework.Game",
263+
"Microsoft.Xna.Framework.Graphics",
264+
"Microsoft.Xna.Framework.Xact"
265+
});
266+
targetAssemblies.Add(
267+
typeof(Microsoft.Xna.Framework.Vector2).Assembly
268+
);
286269

287-
// get changes for game framework
288-
switch (framework)
289-
{
290-
case GameFramework.MonoGame:
291-
removeAssemblyReferences.AddRange(new[]
292-
{
293-
"Microsoft.Xna.Framework",
294-
"Microsoft.Xna.Framework.Game",
295-
"Microsoft.Xna.Framework.Graphics",
296-
"Microsoft.Xna.Framework.Xact"
297-
});
298-
targetAssemblies.Add(
299-
typeof(Microsoft.Xna.Framework.Vector2).Assembly
300-
);
301-
break;
302-
303-
case GameFramework.Xna:
304-
removeAssemblyReferences.Add(
305-
"MonoGame.Framework"
306-
);
307-
targetAssemblies.AddRange(new[]
308-
{
309-
typeof(Microsoft.Xna.Framework.Vector2).Assembly,
310-
typeof(Microsoft.Xna.Framework.Game).Assembly,
311-
typeof(Microsoft.Xna.Framework.Graphics.SpriteBatch).Assembly
312-
});
313-
break;
270+
// `Netcode.dll` merged into the game assembly in Stardew Valley 1.5.5
271+
removeAssemblyReferences.Add(
272+
"Netcode"
273+
);
314274

315-
default:
316-
throw new InvalidOperationException($"Unknown game framework '{framework}'.");
317-
}
275+
// Stardew Valley reference
276+
removeAssemblyReferences.Add(
277+
Constants.Platform == Platform.Windows
278+
? "StardewValley"
279+
: "Stardew Valley"
280+
);
281+
targetAssemblies.Add(
282+
typeof(StardewValley.Game1).Assembly
283+
);
318284

319285
return new PlatformAssemblyMap(targetPlatform, removeAssemblyReferences.ToArray(), targetAssemblies.ToArray());
320286
}

src/SMAPI/Framework/Content/ContentCache.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using System.Collections.Generic;
33
using System.Diagnostics.Contracts;
44
using System.Linq;
5-
using Microsoft.Xna.Framework;
65
using StardewModdingAPI.Framework.Reflection;
76
using StardewModdingAPI.Toolkit.Utilities;
87
using StardewValley;
@@ -52,13 +51,7 @@ public ContentCache(LocalizedContentManager contentManager, Reflector reflection
5251
this.Cache = reflection.GetField<Dictionary<string, object>>(contentManager, "loadedAssets").GetValue();
5352

5453
// get key normalization logic
55-
if (Constants.GameFramework == GameFramework.Xna)
56-
{
57-
IReflectedMethod method = reflection.GetMethod(typeof(TitleContainer), "GetCleanPath");
58-
this.NormalizeAssetNameForPlatform = path => method.Invoke<string>(path);
59-
}
60-
else
61-
this.NormalizeAssetNameForPlatform = key => key.Replace('\\', '/'); // based on MonoGame's ContentManager.Load<T> logic
54+
this.NormalizeAssetNameForPlatform = PathUtilities.NormalizePath; //this.NormalizeAssetNameForPlatform = key => key.Replace('\\', '/'); // based on MonoGame's ContentManager.Load<T> logic
6255
}
6356

6457
/****

src/SMAPI/Framework/Input/GamePadStateBuilder.cs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.Linq;
23
using Microsoft.Xna.Framework;
34
using Microsoft.Xna.Framework.Input;
45

@@ -157,11 +158,8 @@ public IEnumerable<SButton> GetPressedButtons()
157158
yield break;
158159

159160
// buttons
160-
foreach (var pair in this.ButtonStates)
161-
{
162-
if (pair.Value == ButtonState.Pressed && pair.Key.TryGetController(out Buttons button))
163-
yield return button.ToSButton();
164-
}
161+
foreach (Buttons button in this.GetPressedGamePadButtons())
162+
yield return button.ToSButton();
165163

166164
// triggers
167165
if (this.LeftTrigger > 0.2f)
@@ -201,7 +199,7 @@ public GamePadState GetState()
201199
rightThumbStick: this.RightStickPos,
202200
leftTrigger: this.LeftTrigger,
203201
rightTrigger: this.RightTrigger,
204-
buttons: this.GetButtonBitmask() // MonoGame requires one bitmask here; don't specify multiple values
202+
buttons: this.GetPressedGamePadButtons().ToArray()
205203
);
206204

207205
return this.State.Value;
@@ -211,17 +209,14 @@ public GamePadState GetState()
211209
/*********
212210
** Private methods
213211
*********/
214-
/// <summary>Get a bitmask representing the pressed buttons.</summary>
215-
private Buttons GetButtonBitmask()
212+
/// <summary>Get the pressed gamepad buttons.</summary>
213+
private IEnumerable<Buttons> GetPressedGamePadButtons()
216214
{
217-
Buttons flag = 0;
218215
foreach (var pair in this.ButtonStates)
219216
{
220217
if (pair.Value == ButtonState.Pressed && pair.Key.TryGetController(out Buttons button))
221-
flag |= button;
218+
yield return button;
222219
}
223-
224-
return flag;
225220
}
226221
}
227222
}

src/SMAPI/Framework/InternalExtensions.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using Microsoft.Xna.Framework.Graphics;
77
using StardewModdingAPI.Framework.Events;
88
using StardewModdingAPI.Framework.Reflection;
9-
using StardewValley;
109
using StardewValley.Menus;
1110

1211
namespace StardewModdingAPI.Framework
@@ -150,11 +149,7 @@ static IEnumerable<IClickableMenu> GetAncestors(IClickableMenu menu)
150149
/// <param name="reflection">The reflection helper with which to access private fields.</param>
151150
public static bool IsOpen(this SpriteBatch spriteBatch, Reflector reflection)
152151
{
153-
string fieldName = Constants.GameFramework == GameFramework.Xna
154-
? "inBeginEndPair"
155-
: "_beginCalled";
156-
157-
return reflection.GetField<bool>(Game1.spriteBatch, fieldName).GetValue();
152+
return reflection.GetField<bool>(spriteBatch, "_beginCalled").GetValue();
158153
}
159154
}
160155
}

src/SMAPI/Framework/Logging/LogManager.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,10 @@ public void LogFatalLaunchError(Exception exception)
253253
switch (exception)
254254
{
255255
// audio crash
256-
case InvalidOperationException ex when ex.Source == "Microsoft.Xna.Framework.Xact" && ex.StackTrace.Contains("Microsoft.Xna.Framework.Audio.AudioEngine..ctor"):
257-
this.Monitor.Log("The game couldn't load audio. Do you have speakers or headphones plugged in?", LogLevel.Error);
258-
this.Monitor.Log($"Technical details: {ex.GetLogSummary()}");
259-
break;
256+
//case InvalidOperationException ex when ex.Source == "Microsoft.Xna.Framework.Xact" && ex.StackTrace.Contains("Microsoft.Xna.Framework.Audio.AudioEngine..ctor"):
257+
// this.Monitor.Log("The game couldn't load audio. Do you have speakers or headphones plugged in?", LogLevel.Error);
258+
// this.Monitor.Log($"Technical details: {ex.GetLogSummary()}");
259+
// break;
260260

261261
// missing content folder exception
262262
case FileNotFoundException ex when ex.Message == "Couldn't find file 'C:\\Program Files (x86)\\Steam\\SteamApps\\common\\Stardew Valley\\Content\\XACT\\FarmerSounds.xgs'.": // path in error is hardcoded regardless of install path

0 commit comments

Comments
 (0)