Modloader 1.5

1.Settings page
2.Mod compatibility improvement
This commit is contained in:
yangzhi 2019-06-13 15:29:02 +08:00
parent e511ad28a8
commit 1df4408da0
42 changed files with 587 additions and 271 deletions

View File

@ -128,6 +128,7 @@ namespace ModLoader
private readonly Mutex _working = new Mutex(false);
public static Activity1 Instance { get; private set; }
private readonly HttpClient _httpClient = new HttpClient();
private static readonly Dictionary<int, Action> MessageHandler = new Dictionary<int, Action>();
@ -150,10 +151,29 @@ namespace ModLoader
protected override void OnCreate(Bundle bundle)
{
Instance = this;
Type[] services = { typeof(Analytics), typeof(Crashes) };
AppCenter.Start("b8eaba94-d276-4c97-9953-0c91e7357e21", services);
base.OnCreate(bundle);
this.RequestWindowFeature(WindowFeatures.NoTitle);
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.N)
{
StrictMode.SetVmPolicy(new StrictMode.VmPolicy.Builder().Build());
}
try {
File errorLog = this.FilesDir.ListFiles().FirstOrDefault(f => f.IsDirectory && f.Name == "error")?.ListFiles().FirstOrDefault(f => f.Name.EndsWith(".dat"));
if (errorLog != null)
{
string errorLogPath = Path.Combine(this.ExternalCacheDir.AbsolutePath, "error.dat");
StreamToFile(new FileStream(errorLog.AbsolutePath, FileMode.Open), errorLogPath);
ShowConfirmDialog(this, Resource.String.Error, Resource.String.CrashReportMessage, Resource.String.View, Resource.String.Dismiss, () => { OpenTextFile(this, errorLogPath); });
}
Type[] services = { typeof(Analytics), typeof(Crashes) };
AppCenter.Start("b8eaba94-d276-4c97-9953-0c91e7357e21", services);
IEnumerable<File> errorLogs = this.FilesDir.ListFiles().FirstOrDefault(f => f.IsDirectory && f.Name == "error")?.ListFiles().ToList().FindAll(f => f.Name.EndsWith(".dat") || f.Name.EndsWith(".throwable"));
if (errorLogs != null) foreach (var file in errorLogs) file.Delete();
}
catch (Exception)
{
// ignored
}
if (Build.VERSION.SdkInt >= BuildVersionCodes.P)
{
this.Window.Attributes.LayoutInDisplayCutoutMode = LayoutInDisplayCutoutMode.ShortEdges;
@ -169,13 +189,18 @@ namespace ModLoader
private void OnCreatePartTwo()
{
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.N)
{
StrictMode.SetVmPolicy(new StrictMode.VmPolicy.Builder().Build());
}
if (GetConfig(this, "compatCheck", "true") == "false")
Constants.CompatCheck = false;
if (GetConfig(this, "upgradeCheck", "true") == "false")
Constants.UpgradeCheck = false;
else
new PgyUpdateManager.Builder().SetForced(false).SetUserCanRetry(true).SetDeleteHistroyApk(true).Register();
this.InitEnvironment();
this.FindViewById<Button>(Resource.Id.buttonSetting).Click += (sender, args) =>
{
this.StartActivity(typeof(ActivitySetting));
};
this.FindViewById<Button>(Resource.Id.buttonExtract).Click += (sender, args) =>
{
new Thread(() =>
@ -251,6 +276,8 @@ namespace ModLoader
FileAccess.Write, FileShare.Read);
monoFramework.Write(stream);
stream.Close();
Stream stream2 = this.Resources.OpenRawResource(Resource.Raw.SMDroidFiles);
ZipHelper.UnZip(stream2, Constants.GamePath);
dialog.Dismiss();
MakeToast(this, this.Resources.GetText(Resource.String.GeneratedMessage),
ToastLength.Long);
@ -406,16 +433,7 @@ namespace ModLoader
}
internal void ConfigMod(string configPath)
{
Intent intent = new Intent(Intent.ActionView);
intent.AddCategory(Intent.CategoryDefault);
File configFile = new File(configPath);
intent.SetDataAndType(Android.Net.Uri.FromFile(configFile), "text/plain");
intent.AddFlags(ActivityFlags.NewTask);
try
{
this.StartActivity(intent);
}
catch (ActivityNotFoundException) { }
OpenTextFile(this, configPath);
}
internal void RemoveMod(ModInfo mod)
@ -439,6 +457,10 @@ namespace ModLoader
private void PrepareModList()
{
if (!new File(Constants.ModPath).Exists())
{
Directory.CreateDirectory(Constants.ModPath);
}
string modListFileName = Path.Combine(Constants.GameInternalPath, "ModList.json");
new JsonHelper().ReadJsonFileIfExists(modListFileName, out ModInfo[] modInfos);
Dictionary<string, ModInfo> modInfoDictionary = modInfos.ToDictionary(info => info.UniqueID, info => info);

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using ModLoader.Common;
using static ModLoader.Common.Utils;
namespace ModLoader
{
[Activity(Label = "ActivitySetting")]
public class ActivitySetting : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
this.SetContentView(Resource.Layout.layout_setting);
CheckBox checkBoxCompat = this.FindViewById<CheckBox>(Resource.Id.checkBoxCompat);
this.WireConfig(checkBoxCompat, "compatCheck", b => Constants.CompatCheck = b);
CheckBox checkBoxUpgrade = this.FindViewById<CheckBox>(Resource.Id.checkBoxUpgrade);
this.WireConfig(checkBoxUpgrade, "upgradeCheck", b => Constants.UpgradeCheck = b);
}
private void WireConfig(CheckBox checkBox, string configSection, Action<bool> onChecked)
{
if (GetConfig(this, configSection, "true") == "false")
{
onChecked(false);
checkBox.Checked = false;
}
else
{
onChecked(true);
checkBox.Checked = true;
}
checkBox.Click += (sender, args) =>
{
onChecked(checkBox.Checked);
SetConfig(this, configSection, checkBox.Checked ? "true" : "false");
};
}
}
}

View File

@ -21,5 +21,7 @@ namespace ModLoader.Common
public static string ModPath { get; } = Path.Combine(GamePath, "Mods");
public static string ContentPath { get; } = Path.Combine(Constants.GamePath, "Game/assets/Content".Replace('/', Path.DirectorySeparatorChar));
public static string GameInternalPath { get; } = Path.Combine(Constants.GamePath, "smapi-internal");
}
public static bool CompatCheck { get; set; } = true;
public static bool UpgradeCheck { get; set; } = true;
};
}

View File

@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using Android.Graphics;
using ModLoader.Common;
using Mono.Cecil;
using Mono.Cecil.Cil;
using OpCodes = Mono.Cecil.Cil.OpCodes;
namespace DllRewrite
{
@ -15,6 +17,7 @@ namespace DllRewrite
private AssemblyDefinition MonoGame_Framework;
private readonly AssemblyDefinition mscorlib;
private readonly AssemblyDefinition Mono_Android;
private readonly AssemblyDefinition System_Xml;
private readonly DefaultAssemblyResolver resolver;
private readonly AssemblyDefinition StardewValley;
private readonly Dictionary<string, TypeReference> typeDict = new Dictionary<string, TypeReference>();
@ -25,6 +28,8 @@ namespace DllRewrite
this.resolver.AddSearchDirectory(Constants.AssemblyPath);
this.mscorlib = this.resolver.Resolve(new AssemblyNameReference("mscorlib", new Version("0.0.0.0")));
this.Mono_Android = this.resolver.Resolve(new AssemblyNameReference("Mono.Android", new Version("0.0.0.0")));
this.System_Xml =
this.resolver.Resolve(new AssemblyNameReference("System.Xml", new Version("0.0.0.0")));
this.MonoGame_Framework =
this.resolver.Resolve(new AssemblyNameReference("MonoGame.Framework", new Version("0.0.0.0")));
this.StardewValley =
@ -197,6 +202,26 @@ namespace DllRewrite
typeGame1.Methods.Add(propertyDefinition.SetMethod);
typeGame1.Properties.Add(propertyDefinition);
// GameLocation.hook
var typeGameLocation = this.StardewValley.MainModule.GetType("StardewValley.GameLocation");
var typeDebrisManager = this.StardewValley.MainModule.GetType("StardewValley.DebrisManager");
var getDebrisNetCollection = typeDebrisManager.Methods.First(m => m.Name == "get_debrisNetCollection");
var typeDebrisCollection = getDebrisNetCollection.ReturnType;
propertyDefinition = new PropertyDefinition("debrisCollection", PropertyAttributes.None, typeDebrisCollection);
propertyDefinition.CustomAttributes.Add(new CustomAttribute(this.GetMethodReference(".ctor", "System.Xml.Serialization.XmlIgnoreAttribute", this.System_Xml)));
propertyDefinition.GetMethod = new MethodDefinition("get_debrisCollection",
MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.SpecialName |
MethodAttributes.HideBySig, typeDebrisCollection);
propertyDefinition.GetMethod.SemanticsAttributes = MethodSemanticsAttributes.Getter;
processor = propertyDefinition.GetMethod.Body.GetILProcessor();
processor.Emit(OpCodes.Ldarg_0);
getMethod = typeGameLocation.Methods.FirstOrDefault(m => m.Name == "get_debris");
processor.Emit(OpCodes.Callvirt, getMethod);
processor.Emit(OpCodes.Callvirt, getDebrisNetCollection);
processor.Emit(OpCodes.Ret);
typeGameLocation.Methods.Add(propertyDefinition.GetMethod);
typeGameLocation.Properties.Add(propertyDefinition);
//HUDMessage..ctor

View File

@ -146,5 +146,32 @@ namespace ModLoader.Common
Microsoft.AppCenter.Crashes.Crashes.TrackError(ex);
}
}
public static void OpenTextFile(Context context, string filename)
{
Intent intent = new Intent(Intent.ActionView);
intent.AddCategory(Intent.CategoryDefault);
Java.IO.File configFile = new Java.IO.File(filename);
intent.SetDataAndType(Android.Net.Uri.FromFile(configFile), "text/plain");
intent.AddFlags(ActivityFlags.NewTask);
try
{
context.StartActivity(intent);
}
catch (ActivityNotFoundException) { }
}
public static string GetConfig(Context context, string key, string defValue)
{
ISharedPreferences sp = context.GetSharedPreferences("main_prefs", FileCreationMode.Private);
return sp.GetString(key, defValue);
}
public static void SetConfig(Context context, string key, string value)
{
ISharedPreferences sp = context.GetSharedPreferences("main_prefs", FileCreationMode.Private);
ISharedPreferencesEditor editor = sp.Edit();
editor.PutString(key, value);
editor.Apply();
}
}
}

View File

@ -46,6 +46,7 @@
<AndroidHttpClientHandlerType>
</AndroidHttpClientHandlerType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -172,6 +173,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Activity1.cs" />
<Compile Include="ActivitySetting.cs" />
<Compile Include="Common\Constants.cs" />
<Compile Include="Common\ModInfo.cs" />
<Compile Include="Common\ModListAdapter.cs" />
@ -894,7 +896,11 @@
<Compile Include="SMAPI\Framework\RewriteFacades\FarmerMethods.cs" />
<Compile Include="SMAPI\Framework\RewriteFacades\Game1Methods.cs" />
<Compile Include="SMAPI\Framework\RewriteFacades\IClickableMenuMethods.cs" />
<Compile Include="SMAPI\Framework\RewriteFacades\MapPageMethods.cs" />
<Compile Include="SMAPI\Framework\RewriteFacades\SpriteBatchMethods.cs" />
<Compile Include="SMAPI\Framework\RewriteFacades\SpriteTextMethods.cs" />
<Compile Include="SMAPI\Framework\RewriteFacades\ItemGrabMenuMethods.cs" />
<Compile Include="SMAPI\Framework\RewriteFacades\TextBoxMethods.cs" />
<Compile Include="SMAPI\Framework\SCore.cs" />
<Compile Include="SMAPI\Framework\Serialisation\ColorConverter.cs" />
<Compile Include="SMAPI\Framework\Serialisation\PointConverter.cs" />
@ -1067,6 +1073,11 @@
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\Layout\layout_setting.axml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\MonoGame\v3.0\MonoGame.Content.Builder.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@ -332,10 +332,11 @@ namespace Mono.Cecil {
static string GetCurrentMonoGac ()
{
if (Path.GetDirectoryName(typeof(object).Module.FullyQualifiedName) != "")
return Path.Combine(
Directory.GetParent (
Path.GetDirectoryName (typeof (object).Module.FullyQualifiedName)).FullName,
Directory.GetParent(Path.GetDirectoryName(typeof(object).Module.FullyQualifiedName)).FullName,
"gac");
return null;
}
AssemblyDefinition GetAssemblyInGac (AssemblyNameReference reference, ReaderParameters parameters)

View File

@ -18,6 +18,10 @@ using static System.Reflection.IntrospectionExtensions;
using static System.Reflection.TypeExtensions;
#endif
#if CECIL0_9
using InterfaceImplementation = Mono.Cecil.TypeReference;
#endif
namespace MonoMod {
public delegate bool MethodParser(MonoModder modder, MethodBody body, Instruction instr, ref int instri);

View File

@ -317,13 +317,24 @@ namespace MonoMod.RuntimeDetour {
return _SharedStateASM;
string name = (string) GetHarmonyType("HarmonySharedState").GetField("name", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
using (ModuleDefinition module = ModuleDefinition.CreateModule(
#if !CECIL0_9
using (
#endif
ModuleDefinition module = ModuleDefinition.CreateModule(
$"MonoMod.RuntimeDetour.{name}",
new ModuleParameters() {
Kind = ModuleKind.Dll,
#if !CECIL0_9
ReflectionImporterProvider = MMReflectionImporter.Provider
#endif
}
)) {
)
#if CECIL0_9
;
#else
)
#endif
{
TypeDefinition type = new TypeDefinition(
"", name,
Mono.Cecil.TypeAttributes.Public | Mono.Cecil.TypeAttributes.Abstract | Mono.Cecil.TypeAttributes.Sealed | Mono.Cecil.TypeAttributes.Class

View File

@ -32,7 +32,9 @@ namespace MonoMod.Utils {
module = ModuleDefinition.CreateModule(name, new ModuleParameters() {
Kind = ModuleKind.Dll,
AssemblyResolver = new AssemblyCecilDefinitionResolver(_ModuleGen, new DefaultAssemblyResolver()),
#if !CECIL0_9
ReflectionImporterProvider = new ReflectionCecilImporterProvider(null)
#endif
});
#if !NETSTANDARD1_X
@ -158,8 +160,10 @@ namespace MonoMod.Utils {
return _Postbuild(asm.GetType(typeDef.FullName.Replace("+", "\\+"), false, false).GetMethod(clone.Name));
} finally {
#if !CECIL0_9
if (moduleIsPrivate)
module.Dispose();
#endif
}
}

View File

@ -368,10 +368,13 @@ namespace MonoMod.Utils {
operand = param.Index + paramOffs;
} else if (operand is MemberReference mref) {
#if !CECIL0_9
if (mref is DynamicMethodReference dmref) {
operand = dmref.DynamicMethod;
} else {
} else
#endif
{
MemberInfo member = mref.ResolveReflection();
operand = member;
#if !NETSTANDARD

View File

@ -152,7 +152,9 @@ namespace MonoMod.Utils {
ModuleDefinition module = _DynModuleDefinition = ModuleDefinition.CreateModule($"DMD:DynModule<{name}>?{GetHashCode()}", new ModuleParameters() {
Kind = ModuleKind.Dll,
AssemblyResolver = new AssemblyCecilDefinitionResolver(_ModuleGen, new DefaultAssemblyResolver()),
#if !CECIL0_9
ReflectionImporterProvider = new ReflectionCecilImporterProvider(null)
#endif
});
_DynModuleIsPrivate = true;
@ -205,7 +207,9 @@ namespace MonoMod.Utils {
ReaderParameters rp = new ReaderParameters();
if (_ModuleGen != null) {
rp.AssemblyResolver = new AssemblyCecilDefinitionResolver(_ModuleGen, rp.AssemblyResolver ?? new DefaultAssemblyResolver());
#if !CECIL0_9
rp.ReflectionImporterProvider = new ReflectionCecilImporterProvider(rp.ReflectionImporterProvider);
#endif
}
try {
module = moduleTmp = ModuleDefinition.ReadModule(location, rp);
@ -466,6 +470,7 @@ namespace MonoMod.Utils {
#endif
}
#if !CECIL0_9
class ReflectionCecilImporterProvider : IReflectionImporterProvider {
private readonly IReflectionImporterProvider Fallback;
@ -511,6 +516,7 @@ namespace MonoMod.Utils {
return Fallback.ImportReference(method, context);
}
}
#endif
class DynamicMethodReference : MethodReference {
public DynamicMethod DynamicMethod;

View File

@ -102,8 +102,13 @@ namespace MonoMod.Utils {
public static void Emit(this ILProcessor il, OpCode opcode, FieldInfo field)
=> il.Emit(opcode, il.Import(field));
public static void Emit(this ILProcessor il, OpCode opcode, MethodBase method)
=> il.Emit(opcode, il.Import(method));
public static void Emit(this ILProcessor il, OpCode opcode, MethodBase method) {
if (method is System.Reflection.Emit.DynamicMethod) {
il.Emit(opcode, (object) method);
return;
}
il.Emit(opcode, il.Import(method));
}
public static void Emit(this ILProcessor il, OpCode opcode, Type type)
=> il.Emit(opcode, il.Import(type));
public static void Emit(this ILProcessor il, OpCode opcode, MemberInfo member) {

View File

@ -1,4 +1,5 @@
using System;
#if !CECIL0_9
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Linq.Expressions;
@ -99,3 +100,4 @@ namespace MonoMod.Utils {
}
}
#endif

View File

@ -41,13 +41,24 @@ namespace MonoMod.Utils.Cil {
Type t_ILGenerator = typeof(System.Reflection.Emit.ILGenerator);
Type t_ILGeneratorProxyTarget = typeof(ILGeneratorShim);
using (ModuleDefinition module = ModuleDefinition.CreateModule(
#if !CECIL0_9
using (
#endif
ModuleDefinition module = ModuleDefinition.CreateModule(
FullName,
new ModuleParameters() {
Kind = ModuleKind.Dll,
#if !CECIL0_9
ReflectionImporterProvider = MMReflectionImporter.Provider
#endif
}
)) {
)
#if CECIL0_9
;
#else
)
#endif
{
TypeDefinition type = new TypeDefinition(
Namespace,

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="16" android:versionName="1.4" android:installLocation="auto" package="com.zane.smdroid" platformBuildVersionCode="28" platformBuildVersionName="9">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="20" android:versionName="1.5" android:installLocation="auto" package="com.zane.smdroid" platformBuildVersionCode="28" platformBuildVersionName="9">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

View File

@ -39,6 +39,12 @@
android:layout_height="wrap_content"
android:minWidth="96sp"
android:id="@+id/buttonWiki" />
<Button
android:text="@string/Setting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="96sp"
android:id="@+id/buttonSetting" />
</LinearLayout>
<LinearLayout
android:layout_marginLeft="@dimen/compat_button_padding_vertical_material"

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="@android:color/background_light"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox
android:textColor="@android:color/black"
android:text="@string/CompatCheck"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:minHeight="25px"
android:id="@+id/checkBoxCompat" />
<CheckBox
android:textColor="@android:color/black"
android:text="@string/UpgradeCheck"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:minHeight="25px"
android:id="@+id/checkBoxUpgrade" />
</LinearLayout>

View File

@ -219,5 +219,12 @@
"UniqueID": "Pathoschild.ContentPatcher"
}
]
},{
"UniqueID": "SgtPickles.MTN",
"Name": "MTN",
"Description": "Greatly Customizes farms, along with managing multitude amount of custom farm types.",
"DownloadUrl": "http://smd.zaneyork.cn/bin/download/Main/%E7%A7%BB%E6%A4%8DMOD/WebHome/mtn-2.0.0-alpha8.zip",
"Version": "2.0.0-alpha8",
"Dependencies": []
}
]

View File

@ -255,26 +255,26 @@ namespace ModLoader
public partial class Id
{
// aapt resource value: 0x7f0b001d
public const int action0 = 2131427357;
// aapt resource value: 0x7f0b001a
public const int action0 = 2131427354;
public const int action_container = 2131427354;
// aapt resource value: 0x7f0b0017
public const int action_container = 2131427351;
// aapt resource value: 0x7f0b0021
public const int action_divider = 2131427361;
// aapt resource value: 0x7f0b001e
public const int action_divider = 2131427358;
// aapt resource value: 0x7f0b001b
public const int action_image = 2131427355;
// aapt resource value: 0x7f0b0018
public const int action_image = 2131427352;
// aapt resource value: 0x7f0b001c
public const int action_text = 2131427356;
// aapt resource value: 0x7f0b0019
public const int action_text = 2131427353;
// aapt resource value: 0x7f0b002b
public const int actions = 2131427371;
// aapt resource value: 0x7f0b0028
public const int actions = 2131427368;
// aapt resource value: 0x7f0b002c
public const int appIcon = 2131427372;
// aapt resource value: 0x7f0b002f
public const int appIcon = 2131427375;
// aapt resource value: 0x7f0b0006
public const int async = 2131427334;
@ -282,11 +282,11 @@ namespace ModLoader
// aapt resource value: 0x7f0b0007
public const int blocking = 2131427335;
// aapt resource value: 0x7f0b0013
public const int buttonAddOrRemove = 2131427347;
// aapt resource value: 0x7f0b0014
public const int buttonConfig = 2131427348;
public const int buttonAddOrRemove = 2131427348;
// aapt resource value: 0x7f0b0015
public const int buttonConfig = 2131427349;
// aapt resource value: 0x7f0b000d
public const int buttonExtract = 2131427341;
@ -297,20 +297,29 @@ namespace ModLoader
// aapt resource value: 0x7f0b000f
public const int buttonLaunch = 2131427343;
// aapt resource value: 0x7f0b0011
public const int buttonSetting = 2131427345;
// aapt resource value: 0x7f0b0010
public const int buttonWiki = 2131427344;
// aapt resource value: 0x7f0b001b
public const int cancel_action = 2131427355;
// aapt resource value: 0x7f0b001e
public const int cancel_action = 2131427358;
// aapt resource value: 0x7f0b0023
public const int chronometer = 2131427363;
// aapt resource value: 0x7f0b0018
public const int checkBoxCompat = 2131427352;
// aapt resource value: 0x7f0b0031
public const int description = 2131427377;
// aapt resource value: 0x7f0b0019
public const int checkBoxUpgrade = 2131427353;
// aapt resource value: 0x7f0b002a
public const int end_padder = 2131427370;
// aapt resource value: 0x7f0b0026
public const int chronometer = 2131427366;
// aapt resource value: 0x7f0b0034
public const int description = 2131427380;
// aapt resource value: 0x7f0b002d
public const int end_padder = 2131427373;
// aapt resource value: 0x7f0b0008
public const int forever = 2131427336;
@ -318,14 +327,14 @@ namespace ModLoader
// aapt resource value: 0x7f0b000b
public const int gridLayout1 = 2131427339;
// aapt resource value: 0x7f0b0025
public const int icon = 2131427365;
// aapt resource value: 0x7f0b0028
public const int icon = 2131427368;
// aapt resource value: 0x7f0b0029
public const int icon_group = 2131427369;
// aapt resource value: 0x7f0b002c
public const int icon_group = 2131427372;
// aapt resource value: 0x7f0b0024
public const int info = 2131427364;
// aapt resource value: 0x7f0b0027
public const int info = 2131427367;
// aapt resource value: 0x7f0b0009
public const int italic = 2131427337;
@ -339,50 +348,50 @@ namespace ModLoader
// aapt resource value: 0x7f0b000c
public const int linearLayout1 = 2131427340;
// aapt resource value: 0x7f0b0011
public const int listView1 = 2131427345;
// aapt resource value: 0x7f0b0012
public const int ll_view = 2131427346;
public const int listView1 = 2131427346;
// aapt resource value: 0x7f0b001d
public const int media_actions = 2131427357;
// aapt resource value: 0x7f0b0013
public const int ll_view = 2131427347;
// aapt resource value: 0x7f0b0020
public const int media_actions = 2131427360;
// aapt resource value: 0x7f0b000a
public const int normal = 2131427338;
// aapt resource value: 0x7f0b002b
public const int notificationLayout = 2131427371;
// aapt resource value: 0x7f0b002e
public const int notificationLayout = 2131427374;
// aapt resource value: 0x7f0b0027
public const int notification_background = 2131427367;
// aapt resource value: 0x7f0b002a
public const int notification_background = 2131427370;
// aapt resource value: 0x7f0b0020
public const int notification_main_column = 2131427360;
// aapt resource value: 0x7f0b0023
public const int notification_main_column = 2131427363;
// aapt resource value: 0x7f0b001f
public const int notification_main_column_container = 2131427359;
// aapt resource value: 0x7f0b0022
public const int notification_main_column_container = 2131427362;
// aapt resource value: 0x7f0b0030
public const int progress_bar = 2131427376;
// aapt resource value: 0x7f0b002f
public const int progress_bar_frame = 2131427375;
// aapt resource value: 0x7f0b002d
public const int progress_text = 2131427373;
// aapt resource value: 0x7f0b0026
public const int right_icon = 2131427366;
// aapt resource value: 0x7f0b0021
public const int right_side = 2131427361;
// aapt resource value: 0x7f0b0033
public const int progress_bar = 2131427379;
// aapt resource value: 0x7f0b0032
public const int spacer = 2131427378;
public const int progress_bar_frame = 2131427378;
// aapt resource value: 0x7f0b001c
public const int status_bar_latest_event_content = 2131427356;
// aapt resource value: 0x7f0b0030
public const int progress_text = 2131427376;
// aapt resource value: 0x7f0b0029
public const int right_icon = 2131427369;
// aapt resource value: 0x7f0b0024
public const int right_side = 2131427364;
// aapt resource value: 0x7f0b0035
public const int spacer = 2131427381;
// aapt resource value: 0x7f0b001f
public const int status_bar_latest_event_content = 2131427359;
// aapt resource value: 0x7f0b0002
public const int tag_transition_group = 2131427330;
@ -393,17 +402,17 @@ namespace ModLoader
// aapt resource value: 0x7f0b0004
public const int text2 = 2131427332;
// aapt resource value: 0x7f0b0017
public const int textDescription = 2131427351;
// aapt resource value: 0x7f0b0016
public const int textDescription = 2131427350;
public const int textModName = 2131427350;
// aapt resource value: 0x7f0b0015
public const int textModName = 2131427349;
// aapt resource value: 0x7f0b0025
public const int time = 2131427365;
// aapt resource value: 0x7f0b0022
public const int time = 2131427362;
// aapt resource value: 0x7f0b002e
public const int time_remaining = 2131427374;
// aapt resource value: 0x7f0b0031
public const int time_remaining = 2131427377;
// aapt resource value: 0x7f0b0005
public const int title = 2131427333;
@ -447,52 +456,55 @@ namespace ModLoader
public const int layout_mod_list = 2130903041;
// aapt resource value: 0x7f030002
public const int notification_action = 2130903042;
public const int layout_setting = 2130903042;
// aapt resource value: 0x7f030003
public const int notification_action_tombstone = 2130903043;
public const int notification_action = 2130903043;
// aapt resource value: 0x7f030004
public const int notification_media_action = 2130903044;
public const int notification_action_tombstone = 2130903044;
// aapt resource value: 0x7f030005
public const int notification_media_cancel_action = 2130903045;
public const int notification_media_action = 2130903045;
// aapt resource value: 0x7f030006
public const int notification_template_big_media = 2130903046;
public const int notification_media_cancel_action = 2130903046;
// aapt resource value: 0x7f030007
public const int notification_template_big_media_custom = 2130903047;
public const int notification_template_big_media = 2130903047;
// aapt resource value: 0x7f030008
public const int notification_template_big_media_narrow = 2130903048;
public const int notification_template_big_media_custom = 2130903048;
// aapt resource value: 0x7f030009
public const int notification_template_big_media_narrow_custom = 2130903049;
public const int notification_template_big_media_narrow = 2130903049;
// aapt resource value: 0x7f03000a
public const int notification_template_custom_big = 2130903050;
public const int notification_template_big_media_narrow_custom = 2130903050;
// aapt resource value: 0x7f03000b
public const int notification_template_icon_group = 2130903051;
public const int notification_template_custom_big = 2130903051;
// aapt resource value: 0x7f03000c
public const int notification_template_lines_media = 2130903052;
public const int notification_template_icon_group = 2130903052;
// aapt resource value: 0x7f03000d
public const int notification_template_media = 2130903053;
public const int notification_template_lines_media = 2130903053;
// aapt resource value: 0x7f03000e
public const int notification_template_media_custom = 2130903054;
public const int notification_template_media = 2130903054;
// aapt resource value: 0x7f03000f
public const int notification_template_part_chronometer = 2130903055;
public const int notification_template_media_custom = 2130903055;
// aapt resource value: 0x7f030010
public const int notification_template_part_time = 2130903056;
public const int notification_template_part_chronometer = 2130903056;
// aapt resource value: 0x7f030011
public const int status_bar_ongoing_event_progress_bar = 2130903057;
public const int notification_template_part_time = 2130903057;
// aapt resource value: 0x7f030012
public const int status_bar_ongoing_event_progress_bar = 2130903058;
static Layout()
{
@ -529,41 +541,50 @@ namespace ModLoader
// aapt resource value: 0x7f080018
public const int ApplicationName = 2131230744;
// aapt resource value: 0x7f080028
public const int Cancel = 2131230760;
// aapt resource value: 0x7f08002b
public const int Cancel = 2131230763;
// aapt resource value: 0x7f080026
public const int Config = 2131230758;
public const int CompatCheck = 2131230758;
// aapt resource value: 0x7f080029
public const int Config = 2131230761;
// aapt resource value: 0x7f080024
public const int Confirm = 2131230756;
// aapt resource value: 0x7f080038
public const int CrashReportMessage = 2131230776;
// aapt resource value: 0x7f08001c
public const int Disable = 2131230748;
// aapt resource value: 0x7f08003a
public const int Dismiss = 2131230778;
// aapt resource value: 0x7f08001d
public const int Enable = 2131230749;
// aapt resource value: 0x7f080025
public const int Error = 2131230757;
// aapt resource value: 0x7f080028
public const int Error = 2131230760;
// aapt resource value: 0x7f080019
public const int Extract = 2131230745;
// aapt resource value: 0x7f08002b
public const int ExtractedMessage = 2131230763;
// aapt resource value: 0x7f08002e
public const int ExtractedMessage = 2131230766;
// aapt resource value: 0x7f08002a
public const int ExtractingMessage = 2131230762;
// aapt resource value: 0x7f08002d
public const int ExtractingMessage = 2131230765;
// aapt resource value: 0x7f08001a
public const int Generate = 2131230746;
// aapt resource value: 0x7f08002d
public const int GeneratedMessage = 2131230765;
// aapt resource value: 0x7f080030
public const int GeneratedMessage = 2131230768;
// aapt resource value: 0x7f08002c
public const int GeneratingMessage = 2131230764;
// aapt resource value: 0x7f08002f
public const int GeneratingMessage = 2131230767;
// aapt resource value: 0x7f080023
public const int Ignore = 2131230755;
@ -571,38 +592,41 @@ namespace ModLoader
// aapt resource value: 0x7f08001b
public const int Launch = 2131230747;
// aapt resource value: 0x7f08002e
public const int ModDownloadingMessage = 2131230766;
// aapt resource value: 0x7f080031
public const int ModDownloadingMessage = 2131230769;
// aapt resource value: 0x7f08001e
public const int ModInstall = 2131230750;
// aapt resource value: 0x7f080030
public const int ModInstalledMessage = 2131230768;
// aapt resource value: 0x7f080033
public const int ModInstalledMessage = 2131230771;
// aapt resource value: 0x7f08001f
public const int ModRemove = 2131230751;
// aapt resource value: 0x7f080031
public const int ModRemovedMessage = 2131230769;
// aapt resource value: 0x7f08002f
public const int NetworkErrorMessage = 2131230767;
// aapt resource value: 0x7f080033
public const int NotExtractedMessage = 2131230771;
// aapt resource value: 0x7f080034
public const int NotGeneratedMessage = 2131230772;
public const int ModRemovedMessage = 2131230772;
// aapt resource value: 0x7f080032
public const int NotInstalledMessage = 2131230770;
public const int NetworkErrorMessage = 2131230770;
// aapt resource value: 0x7f080027
public const int RemoveConfirmMessage = 2131230759;
// aapt resource value: 0x7f080037
public const int NotExtractedMessage = 2131230775;
// aapt resource value: 0x7f080029
public const int StorageIsFullMessage = 2131230761;
// aapt resource value: 0x7f080036
public const int NotGeneratedMessage = 2131230774;
// aapt resource value: 0x7f080035
public const int NotInstalledMessage = 2131230773;
// aapt resource value: 0x7f08002a
public const int RemoveConfirmMessage = 2131230762;
// aapt resource value: 0x7f080025
public const int Setting = 2131230757;
// aapt resource value: 0x7f08002c
public const int StorageIsFullMessage = 2131230764;
// aapt resource value: 0x7f080022
public const int Update = 2131230754;
@ -610,6 +634,12 @@ namespace ModLoader
// aapt resource value: 0x7f080021
public const int UpdateTip = 2131230753;
// aapt resource value: 0x7f080027
public const int UpgradeCheck = 2131230759;
// aapt resource value: 0x7f080039
public const int View = 2131230777;
// aapt resource value: 0x7f080020
public const int Wiki = 2131230752;

View File

@ -13,6 +13,9 @@
<string name="Update">更新</string>
<string name="Ignore">忽略</string>
<string name="Confirm">确认</string>
<string name="Setting">设置</string>
<string name="CompatCheck">Mod兼容性检查</string>
<string name="UpgradeCheck">检查更新</string>
<string name="Error">错误</string>
<string name="Config">配置</string>
<string name="RemoveConfirmMessage">确认移除这个插件?</string>
@ -29,4 +32,7 @@
<string name="NotInstalledMessage">请先安装游戏本体</string>
<string name="NotExtractedMessage">请先点击解压按钮</string>
<string name="NotGeneratedMessage">请先点击生成按钮</string>
<string name="CrashReportMessage">检测到崩溃日志</string>
<string name="View">查看</string>
<string name="Dismiss">关闭</string>
</resources>

View File

@ -13,6 +13,9 @@
<string name="Update">Upgrade</string>
<string name="Ignore">Ignore</string>
<string name="Confirm">Confirm</string>
<string name="Setting">Setting</string>
<string name="CompatCheck">Mod Compatibility Check</string>
<string name="UpgradeCheck">Upgrade Check</string>
<string name="Error">Error</string>
<string name="Config">Config</string>
<string name="RemoveConfirmMessage">Are you sure to remove this mod?</string>
@ -27,6 +30,9 @@
<string name="ModInstalledMessage">Mod Installed Successfully</string>
<string name="ModRemovedMessage">Mod Removed Successfully</string>
<string name="NotInstalledMessage">Install the Stardew Valley First</string>
<string name="NotExtractedMessage">Press Extract First</string>
<string name="NotGeneratedMessage">Press Generate First</string>
<string name="NotExtractedMessage">Press Extract First</string>
<string name="CrashReportMessage">Crash report detected</string>
<string name="View">View</string>
<string name="Dismiss">Dismiss</string>
</resources>

View File

@ -22,7 +22,7 @@ namespace StardewModdingAPI
****/
/// <summary>SMAPI's current semantic version.</summary>
public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.0.0");
public static ISemanticVersion CoreVersion { get; } = new Toolkit.SemanticVersion("1.4.2");
public static ISemanticVersion CoreVersion { get; } = new Toolkit.SemanticVersion("1.4.3");
/// <summary>The minimum supported version of Stardew Valley.</summary>
public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.3.36");
@ -182,7 +182,6 @@ namespace StardewModdingAPI
"Microsoft.Xna.Framework.Graphics",
"Microsoft.Xna.Framework.Xact",
"0Harmony",
"Newtonsoft.Json",
"StardewModdingAPI.Toolkit",
"StardewModdingAPI.Toolkit.CoreInterfaces"
};

View File

@ -60,7 +60,6 @@ namespace StardewModdingAPI.Framework.ContentManagers
/// <summary>Assert that the given key has a valid format and return a normalised form consistent with the underlying cache.</summary>
/// <param name="assetName">The asset key to check.</param>
/// <exception cref="SContentLoadException">The asset key is empty or contains invalid characters.</exception>
[SuppressMessage("ReSharper", "ParameterOnlyUsedForPreconditionCheck.Local", Justification = "Parameter is only used for assertion checks by design.")]
string AssertAndNormaliseAssetName(string assetName);
/// <summary>Get the current content locale.</summary>

View File

@ -108,7 +108,7 @@ namespace StardewModdingAPI.Framework.ContentManagers
{
// XNB file
case ".xnb":
return this.ModedLoad<T>(relativePath, language);
return base.Load<T>(relativePath, language);
// unpacked data
case ".json":
@ -189,96 +189,5 @@ namespace StardewModdingAPI.Framework.ContentManagers
texture.SetData(data);
return texture;
}
public T ModedLoad<T>(string assetName, LanguageCode language){
if (language != LanguageCode.en)
{
string key = assetName + "." + this.LanguageCodeString(language);
Dictionary<string, bool> _localizedAsset = this.Reflector.GetField<Dictionary<string, bool>>(this, "_localizedAsset").GetValue();
if (!_localizedAsset.TryGetValue(key, out bool flag) | flag)
{
try
{
_localizedAsset[key] = true;
return this.ModedLoad<T>(key);
}
catch (ContentLoadException)
{
_localizedAsset[key] = false;
}
}
}
return this.ModedLoad<T>(assetName);
}
public T ModedLoad<T>(string assetName)
{
if (string.IsNullOrEmpty(assetName))
{
throw new ArgumentNullException("assetName");
}
T local = default(T);
string key = assetName.Replace('\\', '/');
Dictionary<string, object> loadedAssets = this.Reflector.GetField<Dictionary<string, object>>(this, "loadedAssets").GetValue();
if (loadedAssets.TryGetValue(key, out object obj2) && (obj2 is T))
{
return (T)obj2;
}
local = this.ReadAsset<T>(assetName, null);
loadedAssets[key] = local;
return local;
}
protected override Stream OpenStream(string assetName)
{
Stream stream;
try
{
stream = new FileStream(Path.Combine(this.RootDirectory, assetName) + ".xnb", FileMode.Open, FileAccess.Read);
MemoryStream destination = new MemoryStream();
stream.CopyTo(destination);
destination.Seek(0L, SeekOrigin.Begin);
stream.Close();
stream = destination;
}
catch (Exception exception3)
{
throw new ContentLoadException("Opening stream error.", exception3);
}
return stream;
}
protected new T ReadAsset<T>(string assetName, Action<IDisposable> recordDisposableObject)
{
if (string.IsNullOrEmpty(assetName))
{
throw new ArgumentNullException("assetName");
}
;
string str = assetName;
object obj2 = null;
if (this.Reflector.GetField<IGraphicsDeviceService>(this, "graphicsDeviceService").GetValue() == null)
{
this.Reflector.GetField<IGraphicsDeviceService>(this, "graphicsDeviceService").SetValue(this.ServiceProvider.GetService(typeof(IGraphicsDeviceService)) as IGraphicsDeviceService);
}
Stream input = this.OpenStream(assetName);
using (BinaryReader reader = new BinaryReader(input))
{
using (ContentReader reader2 = this.Reflector.GetMethod(this, "GetContentReaderFromXnb").Invoke<ContentReader>(assetName, input, reader, recordDisposableObject))
{
MethodInfo method = reader2.GetType().GetMethod("ReadAsset", BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic, null, new Type[] { }, new ParameterModifier[] { });
obj2 = method.MakeGenericMethod(new Type[] { typeof(T) }).Invoke(reader2, null);
if (obj2 is GraphicsResource graphics)
{
graphics.Name = str;
}
}
}
if (obj2 == null)
{
throw new Exception("Could not load " + str + " asset!");
}
return (T)obj2;
}
}
}

View File

@ -13,6 +13,7 @@ using StardewModdingAPI.Toolkit.Utilities;
using StardewValley;
using xTile;
using xTile.Format;
using xTile.ObjectModel;
using xTile.Tiles;
namespace StardewModdingAPI.Framework.ModHelpers
@ -247,7 +248,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
return;
relativeMapPath = this.ModContentManager.AssertAndNormaliseAssetName(relativeMapPath); // Mono's Path.GetDirectoryName doesn't handle Windows dir separators
string relativeMapFolder = Path.GetDirectoryName(relativeMapPath) ?? ""; // folder path containing the map, relative to the mod folder
bool isOutdoors = map.Properties.TryGetValue("Outdoors", out PropertyValue outdoorsProperty) && outdoorsProperty != null;
// fix tilesheets
foreach (TileSheet tilesheet in map.TileSheets)
{
@ -259,7 +260,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
// get seasonal name (if applicable)
string seasonalImageSource = null;
if (Context.IsSaveLoaded && Game1.currentSeason != null)
if (isOutdoors && Context.IsSaveLoaded && Game1.currentSeason != null)
{
string filename = Path.GetFileName(imageSource) ?? throw new InvalidOperationException($"The '{imageSource}' tilesheet couldn't be loaded: filename is unexpectedly null.");
bool hasSeasonalPrefix =

View File

@ -318,6 +318,7 @@ namespace StardewModdingAPI.Framework.ModLoading
// rewrite type scopes to use target assemblies
IEnumerable<TypeReference> typeReferences = module.GetTypeReferences().OrderBy(p => p.FullName);
typeReferences = typeReferences.Concat(module.Types.SelectMany(t => this.GetAttributeTypes(t.CustomAttributes)));
typeReferences = typeReferences.Concat(module.Types.SelectMany(t => this.GetAttributeTypes(t.Methods.SelectMany(p => p.CustomAttributes))));
typeReferences = typeReferences.Concat(module.Types.SelectMany(t => this.GetAttributeTypes(t.Properties.SelectMany(p => p.CustomAttributes))));
typeReferences = typeReferences.Concat(module.Types.SelectMany(t => this.GetAttributeTypes(t.Fields.SelectMany(p => p.CustomAttributes))));
foreach (TypeReference type in typeReferences)

View File

@ -43,7 +43,7 @@ namespace StardewModdingAPI.Framework.ModLoading
public static bool IsSameType(Type type, TypeReference reference)
{
// same namespace & name
if (type.Namespace != reference.Namespace || type.Name != reference.Name)
if ((type.Namespace != reference.Namespace && reference.Namespace == "" && type.Namespace != reference.DeclaringType.Namespace)|| type.Name != reference.Name)
return false;
// same generic parameters
@ -96,12 +96,35 @@ namespace StardewModdingAPI.Framework.ModLoading
}
return true;
}
public static bool HasMatchingSignature(ConstructorInfo definition, MethodReference reference)
{
// same name
if (definition.Name != reference.Name)
return false;
// same arguments
ParameterInfo[] definitionParameters = definition.GetParameters();
ParameterDefinition[] referenceParameters = reference.Parameters.ToArray();
if (referenceParameters.Length != definitionParameters.Length)
return false;
for (int i = 0; i < referenceParameters.Length; i++)
{
if (!RewriteHelper.IsSameType(definitionParameters[i].ParameterType, referenceParameters[i].ParameterType))
return false;
}
return true;
}
/// <summary>Get whether a type has a method whose signature matches the one expected by a method reference.</summary>
/// <param name="type">The type to check.</param>
/// <param name="reference">The method reference.</param>
public static bool HasMatchingSignature(Type type, MethodReference reference)
{
if (reference.Name == ".ctor")
{
return type.GetConstructors(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public)
.Any(method => RewriteHelper.HasMatchingSignature(method, reference));
}
return type
.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.Public)
.Any(method => RewriteHelper.HasMatchingSignature(method, reference));

View File

@ -14,5 +14,11 @@ namespace StardewModdingAPI.Framework.RewriteFacades
{
return base.couldInventoryAcceptThisItem(item, true);
}
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public new bool addItemToInventoryBool(Item item)
{
return base.addItemToInventoryBool(item, false);
}
}
}

View File

@ -31,5 +31,10 @@ namespace StardewModdingAPI.Framework.RewriteFacades
{
warpFarmer(locationName, tileX, tileY, facingDirectionAfterWarp, false, true, false);
}
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public static new void panScreen(int x, int y)
{
panScreen(x, y, 0);
}
}
}

View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StardewValley;
using StardewValley.Menus;
#pragma warning disable 1591 // missing documentation
namespace StardewModdingAPI.Framework.RewriteFacades
{
public class ItemGrabMenuMethods : ItemGrabMenu
{
public ItemGrabMenuMethods(IList<Item> inventory, bool reverseGrab, bool showReceivingMenu,
InventoryMenu.highlightThisItem highlightFunction, behaviorOnItemSelect behaviorOnItemSelectFunction,
string message, behaviorOnItemSelect behaviorOnItemGrab = null, bool snapToBottom = false,
bool canBeExitedWithKey = false, bool playRightClickSound = true, bool allowRightClick = true,
bool showOrganizeButton = false, int source = 0, Item sourceItem = null, int whichSpecialButton = -1,
object context = null) : base(inventory, reverseGrab, showReceivingMenu, highlightFunction, behaviorOnItemSelectFunction, message,
behaviorOnItemGrab, snapToBottom, canBeExitedWithKey, playRightClickSound, allowRightClick, showOrganizeButton, source, sourceItem,
whichSpecialButton)
{
}
}
}

View File

@ -0,0 +1,13 @@
using StardewValley.Menus;
namespace StardewModdingAPI.Framework.RewriteFacades
{
public class MapPageMethods : MapPage
{
public MapPageMethods(int x, int y, int width, int height)
: base(x, y, width, height, 1f, 1f)
{
}
}
}

View File

@ -0,0 +1,30 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StardewValley.BellsAndWhistles;
#pragma warning disable 1591 // missing documentation
namespace StardewModdingAPI.Framework.RewriteFacades
{
public class SpriteTextMethods : SpriteText
{
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public new static void drawStringHorizontallyCenteredAt(SpriteBatch b, string s, int x, int y, int characterPosition = 0xf423f, int width = -1, int height = 0xf423f, float alpha = 1f, float layerDepth = 0.088f, bool junimoText = false, int color = -1, int maxWidth = 0x1869f)
{
drawString(b, s, x - (getWidthOfString(s) / 2), y, characterPosition, width, height, alpha, layerDepth, junimoText, -1, "", color);
}
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public new static int getWidthOfString(string s, int widthConstraint = 999999)
{
return getWidthOfString(s);
}
[SuppressMessage("ReSharper", "CS0109", Justification = "The 'new' modifier applies when compiled on Windows.")]
public new static void drawStringWithScrollBackground(SpriteBatch b, string s, int x, int y,
string placeHolderWidthText = "", float alpha = 1f, int color = -1)
{
drawStringWithScrollBackground(b, s, x, y, placeHolderWidthText, alpha, color, 0.088f);
}
}
}

View File

@ -0,0 +1,17 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StardewValley.Menus;
#pragma warning disable 1591 // missing documentation
namespace StardewModdingAPI.Framework.RewriteFacades
{
public class TextBoxMethods : TextBox
{
public TextBoxMethods(Texture2D textboxTexture, Texture2D caretTexture, SpriteFont font, Color textColor)
: base(textboxTexture, caretTexture, font, textColor, true, false)
{
}
}
}

View File

@ -258,9 +258,17 @@ namespace StardewModdingAPI.Framework
// override game
SGame.ConstructorHack = new SGameConstructorHack(this.Monitor, this.Reflection, this.Toolkit.JsonHelper, this.InitialiseBeforeFirstAssetLoaded);
if(!this.HarmonyDetourBridgeFailed)
{
try
{
HarmonyDetourBridge.Init();
}
catch (Exception)
{
this.HarmonyDetourBridgeFailed = true;
this.Monitor.Log("HarmonyDetourBridge Init Failed", LogLevel.Warn);
}
}
// override game
this.GameInstance = new SGame(
@ -999,7 +1007,7 @@ namespace StardewModdingAPI.Framework
Assembly modAssembly;
try
{
modAssembly = assemblyLoader.Load(mod, assemblyPath, assumeCompatible: mod.DataRecord?.Status == ModStatus.AssumeCompatible);
modAssembly = assemblyLoader.Load(mod, assemblyPath, assumeCompatible:!ModLoader.Common.Constants.CompatCheck || mod.DataRecord?.Status == ModStatus.AssumeCompatible);
this.ModRegistry.TrackAssemblies(mod, modAssembly);
}
catch (IncompatibleInstructionException) // details already in trace logs

View File

@ -261,6 +261,7 @@ namespace StardewModdingAPI.Framework
throw new InvalidOperationException($"The game didn't initialise its first content manager before SMAPI's {nameof(SGame)} constructor. This indicates an incompatible lifecycle change.");
// init XNA
if(GraphicsAdapter.DefaultAdapter.IsProfileSupported(GraphicsProfile.HiDef))
Game1.graphics.GraphicsProfile = GraphicsProfile.HiDef;
// init SMAPI
@ -884,8 +885,8 @@ namespace StardewModdingAPI.Framework
if (this.Monitor.IsVerbose)
{
string addedText = this.Watchers.LocationsWatcher.Added.Any() ? string.Join(", ", added.Select(p => p.Name)) : "none";
string removedText = this.Watchers.LocationsWatcher.Removed.Any() ? string.Join(", ", removed.Select(p => p.Name)) : "none";
string addedText = added.Any() ? string.Join(", ", added.Select(p => p.Name)) : "none";
string removedText = removed.Any() ? string.Join(", ", removed.Select(p => p.Name)) : "none";
this.Monitor.Log($"Context: location list changed (added {addedText}; removed {removedText}).", LogLevel.Trace);
}
@ -1110,6 +1111,7 @@ namespace StardewModdingAPI.Framework
#endif
base.Update(gameTime);
events.UpdateTicked.RaiseEmpty();
events.UnvalidatedUpdateTicked.RaiseEmpty();
this.UpdateCrashTimer.Reset();
}
catch (Exception ex)
@ -1605,6 +1607,7 @@ namespace StardewModdingAPI.Framework
{
if (((!npc.swimming) && !npc.HideShadow) && (!npc.IsInvisible && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(npc.getTileLocation())))
{
if (npc.Sprite != null)
Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, npc.Position + new Vector2(((float)(npc.Sprite.SpriteWidth * 4)) / 2f, (float)(npc.GetBoundingBox().Height + (npc.IsMonster ? 0 : 12)))), new Rectangle?(Game1.shadowTexture.Bounds), Color.White, 0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)((4f + (((float)npc.yJumpOffset) / 40f)) * npc.scale), SpriteEffects.None, Math.Max((float)0f, (float)(((float)npc.getStandingY()) / 10000f)) - 1E-06f);
}
}
@ -1615,6 +1618,7 @@ namespace StardewModdingAPI.Framework
{
if (((!npc2.swimming) && !npc2.HideShadow) && !Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(npc2.getTileLocation()))
{
if (npc2.Sprite != null)
Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, npc2.Position + new Vector2(((float)(npc2.Sprite.SpriteWidth * 4)) / 2f, (float)(npc2.GetBoundingBox().Height + (npc2.IsMonster ? 0 : ((npc2.Sprite.SpriteHeight <= 0x10) ? -4 : 12))))), new Rectangle?(Game1.shadowTexture.Bounds), Color.White, 0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)((4f + (((float)npc2.yJumpOffset) / 40f)) * npc2.scale), SpriteEffects.None, Math.Max((float)0f, (float)(((float)npc2.getStandingY()) / 10000f)) - 1E-06f);
}
}
@ -1651,6 +1655,7 @@ namespace StardewModdingAPI.Framework
{
if (((!npc3.swimming) && !npc3.HideShadow) && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(npc3.getTileLocation()))
{
if (npc3.Sprite != null)
Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, npc3.Position + new Vector2(((float)(npc3.Sprite.SpriteWidth * 4)) / 2f, (float)(npc3.GetBoundingBox().Height + (npc3.IsMonster ? 0 : 12)))), new Rectangle?(Game1.shadowTexture.Bounds), Color.White, 0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)((4f + (((float)npc3.yJumpOffset) / 40f)) * npc3.scale), SpriteEffects.None, Math.Max((float)0f, (float)(((float)npc3.getStandingY()) / 10000f)) - 1E-06f);
}
}
@ -1661,6 +1666,7 @@ namespace StardewModdingAPI.Framework
{
if (((!npc4.swimming) && !npc4.HideShadow) && Game1.currentLocation.shouldShadowBeDrawnAboveBuildingsLayer(npc4.getTileLocation()))
{
if (npc4.Sprite != null)
Game1.spriteBatch.Draw(Game1.shadowTexture, Game1.GlobalToLocal(Game1.viewport, npc4.Position + new Vector2(((float)(npc4.Sprite.SpriteWidth * 4)) / 2f, (float)(npc4.GetBoundingBox().Height + (npc4.IsMonster ? 0 : 12)))), new Rectangle?(Game1.shadowTexture.Bounds), Color.White, 0f, new Vector2((float)Game1.shadowTexture.Bounds.Center.X, (float)Game1.shadowTexture.Bounds.Center.Y), (float)((4f + (((float)npc4.yJumpOffset) / 40f)) * npc4.scale), SpriteEffects.None, Math.Max((float)0f, (float)(((float)npc4.getStandingY()) / 10000f)) - 1E-06f);
}
}

View File

@ -6,6 +6,7 @@ using StardewModdingAPI.Framework.ModLoading.Finders;
using StardewModdingAPI.Framework.ModLoading.Rewriters;
using StardewModdingAPI.Framework.RewriteFacades;
using StardewValley;
using StardewValley.BellsAndWhistles;
using StardewValley.Menus;
namespace StardewModdingAPI.Metadata
@ -59,12 +60,24 @@ namespace StardewModdingAPI.Metadata
yield return new FieldToPropertyRewriter(typeof(Game1), "isDebrisWeather");
yield return new FieldToPropertyRewriter(typeof(GameLocation), "debris", "debrisCollection");
yield return new FieldReplaceRewriter(typeof(Farmer), "daysUntilHouseUpgrade", "daysUntilHouseUpgrade");
yield return new MethodParentRewriter(typeof(IClickableMenu), typeof(IClickableMenuMethods));
yield return new MethodParentRewriter(typeof(Game1), typeof(Game1Methods));
yield return new MethodParentRewriter(typeof(Farmer), typeof(FarmerMethods));
yield return new MethodParentRewriter(typeof(TextBox), typeof(TextBoxMethods));
yield return new MethodParentRewriter(typeof(SpriteText), typeof(SpriteTextMethods));
yield return new MethodParentRewriter(typeof(ItemGrabMenu), typeof(ItemGrabMenuMethods));
yield return new MethodParentRewriter(typeof(MapPage), typeof(MapPageMethods));
/****
** detect mod issues
****/

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Harmony;
using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Patching;
using StardewModdingAPI.Framework.Reflection;
using StardewValley;
@ -14,7 +13,7 @@ namespace StardewModdingAPI.Patches
internal class DialogueErrorPatch : IHarmonyPatch
{
/*********
** Private methods
** Fields
*********/
/// <summary>Writes messages to the console and log file on behalf of the game.</summary>
private static IMonitor MonitorForGame;
@ -47,10 +46,10 @@ namespace StardewModdingAPI.Patches
/// <param name="harmony">The Harmony instance.</param>
public void Apply(HarmonyInstance harmony)
{
ConstructorInfo constructor = AccessTools.Constructor(typeof(Dialogue), new[] { typeof(string), typeof(NPC) });
MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(DialogueErrorPatch.Prefix));
harmony.Patch(constructor, new HarmonyMethod(prefix), null);
harmony.Patch(
original: AccessTools.Constructor(typeof(Dialogue), new[] { typeof(string), typeof(NPC) }),
prefix: new HarmonyMethod(this.GetType(), nameof(DialogueErrorPatch.Prefix))
);
}
@ -72,6 +71,7 @@ namespace StardewModdingAPI.Patches
IReflectedMethod parseDialogueString = DialogueErrorPatch.Reflection.GetMethod(__instance, "parseDialogueString");
IReflectedMethod checkForSpecialDialogueAttributes = DialogueErrorPatch.Reflection.GetMethod(__instance, "checkForSpecialDialogueAttributes");
IReflectedField<List<string>> dialogues = DialogueErrorPatch.Reflection.GetField<List<string>>(__instance, "dialogues");
// replicate base constructor
if (dialogues.GetValue() == null)
dialogues.SetValue(new List<string>());

View File

@ -1,7 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using Harmony;
using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Patching;
using StardewValley;

View File

@ -1,7 +1,6 @@
using System;
using Harmony;
using StardewModdingAPI.Enums;
using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Patching;
using StardewModdingAPI.Framework.Reflection;
using StardewValley;

View File

@ -28,13 +28,13 @@ namespace StardewModdingAPI.Patches
// object.getDescription
harmony.Patch(
original: AccessTools.Method(typeof(SObject), nameof(SObject.getDescription)),
prefix: new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(ObjectErrorPatch.Object_GetDescription_Prefix)))
prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.Object_GetDescription_Prefix))
);
// IClickableMenu.drawToolTip
harmony.Patch(
original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.drawToolTip)),
prefix: new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(ObjectErrorPatch.IClickableMenu_DrawTooltip_Prefix)))
prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.IClickableMenu_DrawTooltip_Prefix))
);
}