“模组:创建 SMAPI 模组”的版本间的差异

来自Stardew Valley Wiki
跳到导航 跳到搜索
 
(未显示3个用户的25个中间版本)
第1行: 第1行:
 
{{模组:制作指南/header}}
 
{{模组:制作指南/header}}
  
{{翻译}}
+
'''如果您是第一次制作模组''' 请参阅 [[模组:目录#创建模组]] 来了解 C# 模组和内容包模组之间差异的简短描述。
  
  要为游戏 创建 SMAPI 模组? 教程就在这儿。要使用模组,请参阅 [[模组:使用 指南/入门|使用指南]]。要创建内容包模组,请参阅 [[模组:Content Patcher]]。
+
  您想使用 C#  创建 “SMAPI 模组 ”吗 ”本 指南 适合您!
  
 
==介绍==
 
==介绍==
 
===什么是 SMAPI 模组?===
 
===什么是 SMAPI 模组?===
SMAPI 模组 使用 改装 接口来扩展游戏逻辑。 可以在 游戏中发生某些情 做出响应 (例如 ,将 对象放置在世界中),定期运行代码(例如每个更新周期一次),更改游戏的资源和数据等。SMAPI 模组使用 C 编写,使用 .NET Framework 和 Stardew Valley 将 XNA / MonoGame  用于游戏 逻辑(绘制到屏幕 用户输入等)。
+
SMAPI 模组使用 [https://smapi.io/ SMAPI] 编辑 接口来扩展游戏逻辑。 游戏中发生某些 情时(例如 当一个 对象 放置在世界中 ,该模组可以做出响应 ,定期运行代码(例如每个更新周期 运行 一次),更改游戏的资源和数据等。SMAPI 模组 使用 .NET 的 C# 编写 游戏 使用 MonoGame  运行 逻辑(绘制到屏幕 用户输入等)
 +
 
 +
.NET 的另一种语言 Visual Basic 也可以用于编写模组,如果您了解该语言的对应语法即可使用它。得益于 .NET 新版本的特性,从游戏版本 1.5.5 开始使用该语言编写模组也可以直接跨平台运行,社区中已经存在使用该语言的模组并且运行正常,也许您正在运行它们。本文中会提及一些代码示例
  
 
===为什么模组使用 SMAPI?===
 
===为什么模组使用 SMAPI?===
 
SMAPI 可以做许多事情,例如:
 
SMAPI 可以做许多事情,例如:
 
+
# 将 你的 模组加载到游戏中。 如果 没有 SMAPI  加载代码模组 ,则不可能实现它们
# 将模组加载到游戏中。没有 SMAPI  就无法 加载代码模组。
+
# 提供接口和事件,以 原本无法实现的 方式与游戏 进行交 互。 例如 游戏资源 数据 更改、 玩家配置 、翻译、 的简化接口 。这些内容将在指南后面介绍。
# 提供接口和事件, 能够 其他 方式与游戏互 有一些简化的接口,可用于更改 游戏资源/ 数据 玩家配置 ,转换, 等。这些内容将在 指南 后面 部分 介绍。
+
加载时重写模组以实现 跨平台兼容 性。 让您而 不必担心游戏在 Linux/Mac/Windows 版本之间的差异。
跨平台兼容 时进行重构, 样一来就 不必担心游戏在 Linux/Mac/Windows 版本之间的差异。
+
# 重 模组 更新它 。SMAPI 检测并修复 常见情况下因 游戏更新 而损 坏的模组代码。
# 重 模组 更新它 。在常见情况下,SMAPI 检测并修复游戏更新 所破 坏的模组代码。
+
# 拦截错误。如果模组崩溃或 导致 错误,SMAPI 将拦截错误,在控制台窗口中显示错误详细信息,并在大多数情况下自动恢复游戏。这意味着 模组不会意外导致 游戏崩溃,并且可以更轻松地 排除 错误。
# 拦截错误。如果模组崩溃或 发生 错误,SMAPI 将拦截 错误,在控制台窗口中显示错误详细信息,并 在大多数情况下自动恢复游戏。这意味着 减少 游戏 意外 崩溃,并且可以更轻松地 解决 错误。
+
# 提供更新检查。当 模组 有新版本可用时,SMAPI 会自动提醒玩家。
# 提供更新检查。当有新版本可用时,SMAPI 会自动提醒玩家。
+
# 提供兼容性检查。SMAPI 会自动检测模组何时不兼容,并在导致问题之前将其禁用, 这样玩家就不会遇到损坏的 游戏。
# 提供兼容性检查。SMAPI 会自动检测模组何时不兼容,并在 导致问题之前将其禁用, 以防止 游戏 爆炸
 
  
 
===我能制作一个模组吗?===
 
===我能制作一个模组吗?===
 
 是的!本指南将帮助你逐步创建一个简单的模组。然后你可以继续学习,让它做您想做的事即可。
 
 是的!本指南将帮助你逐步创建一个简单的模组。然后你可以继续学习,让它做您想做的事即可。
 +
 
 如果你是编程新手,许多模组开发人员开始时几乎没有或完全没有编程经验。如果你下定决心,当然可以沿途学习,但是您应该为陡峭的学习曲线做好准备。刚开始时不要太过于自信,弄清楚它的时候,最好从一个小的模组开始。一开始很容易变得不知所措并放弃。模组社区非常热情,所以不要害怕问问题!
 
 如果你是编程新手,许多模组开发人员开始时几乎没有或完全没有编程经验。如果你下定决心,当然可以沿途学习,但是您应该为陡峭的学习曲线做好准备。刚开始时不要太过于自信,弄清楚它的时候,最好从一个小的模组开始。一开始很容易变得不知所措并放弃。模组社区非常热情,所以不要害怕问问题!
  
第27行: 第29行:
  
 
===我可以不使用 SMAPI 来制作模组吗?===
 
===我可以不使用 SMAPI 来制作模组吗?===
 当然。许多的 SMAPI 模组支持 [[模组:内容包|内容包]],可以让你提供它们所使用的 JSON 文本文件、图像等。例如,你可以 [[模组:Content Patcher|使用 Content Patcher]] 来编辑游戏的贴图并且不需要任何编程技术。本指南的其余部分是关于创建新的 SMAPI 模组的。有关内容包,请参阅 [[模组:Content Patcher]] (或模组的文档(如果为其 他mod 创建内容包)).
+
 当然。许多的 SMAPI 模组支持 [[模组:内容包|内容包]],可以让你提供它们所使用的 JSON 文本文件、图像等。例如,你可以 [[模组:Content Patcher|使用 Content Patcher]] 来编辑游戏的贴图并且不需要任何编程技术。本指南的其余部分是关于创建新的 SMAPI 模组的。有关内容包,请参阅 [[模组:Content Patcher]] (或模组的文档(如果为其 他模组 创建内容包)).
  
 
===我在哪里可以得到帮助?===
 
===我在哪里可以得到帮助?===
<span id="help"></span>星露谷 模组社区 欢迎你的到来. Feel free to ask for help in [[Modding:Community#Discord|#making-mods on the Stardew Valley Discord]].
+
<span id="help"></span>星露谷 官方聊天室 欢迎你的到来 :[https://stardewvalleywiki.com/Modding:Community#Discord Stardew Valley Discord]
  
 
==开始==
 
==开始==
第36行: 第38行:
 
 由于模组是用 C# 编写的,因此最好先熟悉它。无需记住所有内容,但是掌握基础知识(例如字段、方法、变量和类)将使其他所有内容都变得更加容易。
 
 由于模组是用 C# 编写的,因此最好先熟悉它。无需记住所有内容,但是掌握基础知识(例如字段、方法、变量和类)将使其他所有内容都变得更加容易。
  
 一些有用的资源:
+
 一些有用的资源
* [https://docs.microsoft.com/en-us/dotnet/csharp/quick-starts/ ''C# 快速 学习''] 通过交互式 示例讲解C#的 基础知识。
+
* [https://docs.microsoft.com/en-us/dotnet/csharp/quick-starts/ ''C# 快速 开始''] 通过交互式 学习 C#  基础知识。
* [https://mva.microsoft.com/en-us/training-courses/c-fundamentals-for-absolute-beginners-16169 ''C# 绝对初学者的基础知识''] 视频指南将引导您完成 C #  从基本概念到事件驱动 编程(这是 SMAPI 模组经常使用的 内容)。
+
* [https://mva.microsoft.com/en-us/training-courses/c-fundamentals-for-absolute-beginners-16169 ''C# Fundamentals for Absolute Beginners'']  是一个 视频指南 将引导您完成 C#, 从基本概念到事件驱动编程(这是 SMAPI 模组 最常用的)。
 +
* 已经知道如何编程? 请访问 [https://learnxinyminutes.com/docs/csharp/ LearnXinYMinutes] 快速了解 C# 语法和概念。
 +
 
 +
SMAPI  经常使用的 几个概念
 +
* [https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/types/generics ''泛型'']
 +
* [https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/events/''基于事件的编程'']
 +
* 对于序列化,SMAPI 通常使用 [https://www.newtonsoft.com/json ''NewtonSoft'']
  
 
===要求===
 
===要求===
 在你开始之前:
+
 在你开始之前
# 熟悉 [[模组: 玩家 指南| 玩家指南]],本指南的其余部分假定你已经熟悉使用模组。
+
# 熟悉 [[模组: 使用 指南/入门| 模组的使用]],本指南的其余部分假定你已经熟悉使用模组。
 
# 安装游戏
 
# 安装游戏
# 安装 [[模组: 玩家 指南#安 装 SMAPI|SMAPI]]
+
# 安装 [[模组: 使用 指南/入门#安 装SMAPI|SMAPI]]
 
# 安装开发环境
 
# 安装开发环境
#* 在 Linux 上:安装 [http://www.monodevelop.com/ MonoDevelop]
+
#* 在 Linux 上:安装 [http://www.monodevelop.com/ MonoDevelop] 或 [https://www.jetbrains.com/rider/ Rider]
#* 在 Mac 上:安装 [https://visualstudio.microsoft.com/vs/mac/ Visual Studio for Mac]. (This is a rebranded MonoDevelop.)
+
#* 在 Mac 上:安装 [https://visualstudio.microsoft.com/vs/mac/ Visual Studio for Mac] (这是一个重新命名的 MonoDevelop
#* 在 Windows 上:安装 [https://visualstudio.microsoft.com/vs/community/ Visual Studio Community]. 在 安装程序 中的 工作负载 选择 .NET 桌面开发
+
#* 在 Windows 上:安装 [https://visualstudio.microsoft.com/vs/community/ Visual Studio Community] ,当 安装程序 询问 工作负载 时, 选择 .NET 桌面开发
 +
# 安装 [https://dotnet.microsoft.com/en-us/download/dotnet/6.0 NET 6.0 SDK](x64版本,也可以直接在 Visual Studio Community 单个组件中选择)
  
 如果 不熟悉 Visual Studio (on Windows/Mac或者 MonoDevelop (on Linux), [[模组:IDE 参考]] 解释了如何完成本指南所需的重要工作
+
 如果不熟悉 Visual Studio (Windows/Mac 或者 MonoDevelop (Linux),在 [[模组:IDE 参考]]  页面 解释了如何完成本指南所需的重要工作
  
==创建一个基 础的 模组==
+
==创建一个基 模组==
===快速 开始===
+
===快速 启动===
 如果 有足够的经验 跳过本教程, 则此部分 概述如下
+
 如果 有足够的经验 可以 跳过本教程, 以下是本节 要:
{{collapse|快速开始|content=&#32;
+
{{collapse| 展开以查看 快速开始|content=&#32;
# 创建一个 空的 C#类库 项目
+
# 创建一个 C#类库 项目 (注意不要选择成 .NET Framework 的那个,或者你可以使用另一种语言)
# 目标框架选择 .NET Framework 4.5 或者 4.5.1, 建议使用 4.5.2
+
# 目标框架选择 .NET 6.0
参考 [https://smapi.io/package/readme <tt>Pathoschild.Stardew.ModBuildConfig</tt> NuGet package] 根据要在其上编译模组的平台自动添加正确的引用。
+
添加 [https://smapi.io/package/readme <samp>Pathoschild.Stardew.ModBuildConfig</samp>] NuGet 
# 创建一个 <tt>ModEntry</tt> 类, 该类 将 <tt>StardewModdingAPI.Mod</tt> 子类化
+
# 创建一个 <samp>ModEntry</samp> 类,将 它继承自 <samp>StardewModdingAPI.Mod</samp>
# 覆写 <tt>Entry</tt> 方法,并使用 [[#Mod APIs|SMAPI events and APIs]] 编写代码
+
# 覆写 <samp>Entry</samp> 方法,并使用 [[#Mod APIs|SMAPI 事件和 API]] 编写代码
# 创建一个 [[# 添加你的清单|<tt>manifest.json</tt> 文件]]  来描述 你的 SMAPI  模组
+
# 创建一个 [[#Add your manifest|<samp>manifest.json</samp>]] 文件来描述你的模组
 
# 创建 [[#发布你的模组|一个包含模组文件的zip压缩包]] 来发布
 
# 创建 [[#发布你的模组|一个包含模组文件的zip压缩包]] 来发布
 
}}
 
}}
  
 
===创建解决方案===
 
===创建解决方案===
一个 SMAPI 模组是具有 SMAPI 调用入口方法的动态链接库(DLL),因此要对其进行设置
 
  
# 打开 Visual Studio 或 MonoDevelop.
+
SMAPI 模组是一个动态链接库(DLL),具有由 SMAPI 调用的入口方法
创建  类库 项目 ,选择 .NET Framework 框架 ( 参阅 [[模组:IDE 参考#创建项目|如何创建 一个 项目]])。确保你 选择 的是 .NET Framework 而不 是 .NET Core 或者 .NET Standard
+
 
选择 目标框架 版本 为 .NET Framework 4.5 或 4.5.1,使用 4.5.2 最佳 ( 参阅 [[模组:IDE 参考#选择目标框架|如何改 目标框架]])
+
# 打开 Visual Studio 或 MonoDevelop
# 添加 [https://www.nuget.org/packages/Pathoschild.Stardew.ModBuildConfig <tt>Pathoschild.Stardew.ModBuildConfig</tt> NuGet 包] ( 参阅 [[模组:IDE 参考#添加 NuGet 包|如何添加 NuGet 包]]).
+
使用“ 类库 项目 创建解决方案(请 参阅[[模组:IDE 参考#创建项目|如何创建项目]] )(不要 选择 “类库(.NET Framework )”!那 在游戏 1.5.4 以及之前版本中所使用的)
安装完包 之后重新启动 Visual Studio 或者 MonoDevelop
+
# 目标框架 设置 为 .NET 6(请 参阅 [[模组:IDE 参考#选择目标框架|如何 改目标框架]] )您可能需要 [https://dotnet.microsoft.com/en-us/download/dotnet/6.0 安装 SDK]。这是游戏安装和使用的版本
 +
# 添加 [https://www.nuget.org/packages/Pathoschild.Stardew.ModBuildConfig <samp>Pathoschild.Stardew.ModBuildConfig</samp> NuGet 包] (请 参阅 [[模组:IDE 参考#添加 NuGet 包| 如何添加 NuGet 包]]
 +
#* 如果报错“找不到类型或命名空间名称“StardewModdingAPI””,则可能没有检测到游戏路径,需要将 GamePath 属性设置为游戏的目录。这可以通过将“GamePath”属性添加到项目文件(“.csproj”或“.vbproj”)中的“PropertyGroup”节点下来完成
 +
# 之后重新启动 Visual Studio 或者 MonoDevelop
  
 
===添加代码===
 
===添加代码===
 接下来 让我们 添加 一些将运行的 SMAPI  代码
+
 接下来添加代码
  
 
<ol>
 
<ol>
<li>删除 <tt>Class1.cs</tt> 或者 <tt>MyClass.cs</tt> 文件 (参阅 [[模组:IDE 参考#删除文件|如何删除文件]]).</li>
+
<li>删除 <samp>Class1.cs</samp> 或者 <samp>MyClass.cs</samp> 文件 (参阅 [[模组:IDE 参考#删除文件|如何删除文件]]).</li>
<li>在项目中添加一个 C# 类文件,取名为 <tt>ModEntry.cs</tt> (参阅 [[模组:IDE 参考#添加文件|如何添加]]).</li>
+
<li>在项目中添加一个 C# 类文件,取名为 <samp>ModEntry.cs</samp> (参阅 [[模组:IDE 参考#添加文件|如何添加 文件]]).</li>
<li>在此文件中输入代码 (把 <tt>YourProjectName</tt> 换成你的解决方案的名字):
+
<li>在此文件中输入代码 (把 <samp>YourProjectName</samp> 换成你的解决方案的名字):
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
 
using System;
 
using System;
第98行: 第109行:
 
      *********/
 
      *********/
 
      /// <summary>模组的入口点,在首次加载模组后自动调用</summary>
 
      /// <summary>模组的入口点,在首次加载模组后自动调用</summary>
      /// <param name="helper">对象 名:helper 提供用于编写模组的简化接口</param>
+
      /// <param name="helper">对象 helper 提供用于编写模组的简化接口</param>
 
      public override void Entry(IModHelper helper)
 
      public override void Entry(IModHelper helper)
 
      {
 
      {
第105行: 第116行:
 
        //this 表示本对象,也就是当前的 ModEntry 类
 
        //this 表示本对象,也就是当前的 ModEntry 类
 
      }
 
      }
 
  
 
      /*********
 
      /*********
第120行: 第130行:
  
 
        // 向控制台输出按下了什么按钮
 
        // 向控制台输出按下了什么按钮
        this.Monitor.Log($"{Game1.player.Name} pressed {e.Button}.", LogLevel.Debug);
+
        this.Monitor.Log($"{Game1.player.Name} 按下了 {e.Button}.", LogLevel.Debug);
 
      }
 
      }
 
    }
 
    }
第127行: 第137行:
 
</ol>
 
</ol>
  
Here's a breakdown of what that code is doing:
+
以下是该代码的功能细分:
  
# <code>using X;</code> (see [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive using directive]) makes classes in that namespace available in your code.
+
# <code>using X</code> ( 参阅 [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive using directive]) 使该命名空间中的类在你的代码中可用
# <code>namespace YourProjectName</code> (see [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/namespace namespace keyword]) defines the scope for your mod code. Don't worry about this when you're starting out, Visual Studio or MonoDevelop will add it automatically when you add a file.
+
# <code>namespace YourProjectName</code> (参阅 [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/namespace namespace keyword] )定义命名空间,入门时不必担心,因为在新建类文件时 Visual Studio MonoDevelop 会自动添加它
# <code>public class ModEntry : Mod</code> (see [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/class class keyword]) creates your mod's main class, and subclasses SMAPI's <tt>Mod</tt> class. SMAPI will detect your <tt>Mod</tt> subclass automatically, and <tt>Mod</tt> gives you access to SMAPI's APIs.
+
# <code>public class ModEntry : Mod</code> ( 参阅 [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/class class keyword]) 创建你的模组的主类文件,并继承 SMAPI <samp>Mod</samp> 类。SMAPI 将自动检测你的 <samp>Mod</samp> 子类,而 <samp>Mod</samp> 对象使你可访问 SMAPI 的接口
# <code>public override void Entry(IModHelper helper)</code> is the method SMAPI will call when your mod is loaded into the game. The <code>helper</code> provides convenient access to many of SMAPI's APIs.
+
# <code>public override void Entry(IModHelper helper)</code> 是将模组加载到游戏中时 SMAPI 将调用的方法。这里的 <code>helper</code> 对象提供了对许多 SMAPI 接口的便捷访问
# <code>helper.Events.Input.ButtonPressed += this.OnButtonPressed;</code> adds an 'event handler' (i.e. a method to call) when the button-pressed event happens. In other words, when a button is pressed (the <tt>helper.Events.Input.ButtonPressed</tt> event), SMAPI will call your <tt>this.OnButtonPressed</tt> method. See [[Modding:Modder Guide/APIs/Events|events in the SMAPI reference]] for more info.
+
# <code>helper.Events.Input.ButtonPressed += this.OnButtonPressed</code> 添加了一个事件绑定到当按下按钮的事件发生时。换句话说,当一个按钮被按下 ( 也就是 <samp>helper.Events.Input.ButtonPressed</samp> 事件触发了), SMAPI 会调用你的 <samp>this.OnButtonPressed</samp> 方法。参阅 [[ 模组: 使用指南/APIs/ 事件|SMAPI 中的事件]] 获取更多信息
  
===Add your manifest===
+
如果您使用的是 Visual Basic 语言,以下是使用该语言的 Entry 示例,实现了和上面的 C# 代码相同的步骤和功能
The mod manifest tells SMAPI about your mod.
+
<ol><syntaxhighlight lang="vb">
 +
Imports StardewModdingAPI
 +
Imports StardewModdingAPI.Events
 +
Imports StardewValley
 +
 
 +
Namespace YourProjectName
 +
Public Class ModEntry
 +
   Inherits [Mod]
 +
 
 +
   Public Overrides Sub Entry(helper As IModHelper)
 +
     AddHandler helper.Events.Input.ButtonPressed, AddressOf OnButtonPressed
 +
   End Sub
 +
 
 +
   Public Sub OnButtonPressed(sender As Object, e As ButtonPressedEventArgs)
 +
     If Not Context.IsWorldReady Then Exit Sub
 +
     Monitor.Log($"{Game1.player.Name} 按下了 {e.Button}.", LogLevel.Debug)
 +
   End Sub
 +
End Class
 +
End Namespace
 +
</syntaxhighlight></ol>
 +
 
 +
=== 添加你的清单===
 +
模组的清单为 SMAPI 提供模组的信息
  
 
<ol>
 
<ol>
<li>Add a file named <tt>manifest.json</tt> to your project.</li>
+
<li> 向你的解决方案添加一个名为 <samp>manifest.json</samp> 的文本文件</li>
<li>Paste this code into the file:
+
<li> 将这些代码复制到文件中:(注意要区分键值的大小写,避免出现意外情况)
 
<syntaxhighlight lang="json">
 
<syntaxhighlight lang="json">
 
{
 
{
   "Name": "<your project name>",
+
   "Name": "< 模组的名字>",
   "Author": "<your name>",
+
   "Author": "< 你的名字>",
 
   "Version": "1.0.0",
 
   "Version": "1.0.0",
   "Description": "<One or two sentences about the mod>",
+
   "Description": "< 一句话简单描述你的模组是干什么的>", //(可选)
   "UniqueID": "<your name>.<your project name>",
+
   "UniqueID": "< 你的名字>.< 模组的名字>",
   "EntryDll": "<your project name>.dll",
+
   "EntryDll": "< 你的解决方案的名字>.dll",
   "MinimumApiVersion": "3.0.0",
+
   "MinimumApiVersion": "4.0.0",
   "UpdateKeys": []
+
   "UpdateKeys": [] //(可选)常用的更新键:"Nexus:???", "Gtihub:user/repository", "Moddrop:???"
 
}
 
}
 
</syntaxhighlight></li>
 
</syntaxhighlight></li>
<li>Replace the <tt>&lt;...&gt;</tt> placeholders with the correct info. Don't leave any <tt>&lt;&gt;</tt> symbols!</li>
+
<li> 正确填写其中的信息,不要留着空信息</li>
 
</ol>
 
</ol>
  
This will be listed in the console output when the game is launching. For more info, see the [[Modding:Modder Guide/APIs/Manifest|manifest docs]].
+
当游戏启动时,它将在控制台中输出。更多信息请参阅 [[ 模组: 使用指南/APIs/ 清单|清单文档]]
 +
 
 +
===试试你的模组===
 +
# 构建项目。<br /><small>如果正确执行了“[[#创建项目| 创建项目]] ”步骤,这会自动将模组添加到游戏的 <samp>Mods</ samp> 文件夹。</small>
 +
# 通过 SMAPI 运行游戏。
 +
 
 +
到目前为止,只要您在游戏中按下某个键时该模组就会向控制台窗口发送一条消息。
 +
 
 +
'''更改控制台文本颜色'''
 +
 
 +
控制台中默认文本颜色的设置方式可能会导致它们不可读。 要更改文本颜色:
 +
 
 +
*'''Steam''':打开 Steam 并右键单击库中的游戏。单击“管理”下的“浏览本地文件”,然后打开“/Stardew Valley/smapi-internal/”文件夹中的 <samp>config.json</samp> 文件,搜索“ConsoleColors”,然后编辑“Trace”和“Debug”颜色,以便它们在控制台中可见。
 +
 
 +
*'''Linux''':linux上的默认路径是 <samp>~/.local/share/Steam/steamapps/common/Stardew Valley/smapi-internal/config.json</samp>,除非你已经安装 您的游戏位于不同的驱动器或者标准 Steam 库文件夹之外。
  
===Try your mod===
+
*'''Windows''' :Windows 上的默认路径应为“C:\Program files (x86)\Steam\steamapps\common\Stardew Valley\smapi-internal\config.json”,除非游戏在不同的驱动器或 Steam 库文件夹之外。
# Build the project.<br /><small>If you did the ''[[#Create the project|create the project]]'' steps correctly, this will automatically add your mod to the game's <tt>Mods</tt> folder.</small>
 
# Run the game through SMAPI.
 
  
The mod so far will just send a message to the console window whenever you press a key in the game.
+
===疑难解答===
 +
如果上述教程创建的模组不能正常运行:
  
===Troubleshoot===
+
# 重复查看以上步骤,以确保你没有跳过任何内容
If the tutorial mod doesn't work...
+
# 检查是否有任何的错误消息,也许可以解释为什么它不起作用:
 +
#* 在 Visual Studio 中尝试重新构建解决方案,查看 '''输出''' 面板 或者 '''错误列表'''
 +
#* 在 MonoDevelop 中点击 ''Build > Rebuild All'' 等待处理完毕。然后点击 "Build: XX errors, XX warnings" 在顶部的条,点击 ''XX Errors'' 和 ''Build Output'' 选项卡
 +
# 参阅 [[模组:使用指南/疑难解答|疑难解答]].
 +
# 如果其他所有方法均失败,请到 Stardew Valley Discord 寻求帮助 :)
  
# Review the above steps to make sure you didn't skip something.
+
==常见问题==
# Check for error messages which may explain why it's not working:
+
===SMAPI 的文档在哪里?===
#* In Visual Studio, click ''Build > Rebuild Solution'' and check the ''Output'' pane or ''Error'' list.
+
这只是“入门”教程。更多信息请参阅 [[ 模组: 制作指南/APIs|SMAPI 接口说明]]
#* In MonoDevelop, click ''Build > Rebuild All'' and wait until it's done. Then click the "Build: XX errors, XX warnings" bar at the top, and check the ''XX Errors'' and ''Build Output'' tabs.
 
# See the [[Modding:Modder Guide/Test and Troubleshoot|troubleshooting guide]].
 
# If all else fails, come ask for help in the [[Modding:Community#Discord|#modding in the Stardew Valley Discord]]. :)
 
  
==FAQs==
+
=== 我可以看看其他模组的代码吗?===
===Where's the SMAPI documentation?===
+
是的,近 70% 的 SMAPI 模组都是开源的。要找到他们的代码:
This is just the 'getting started' tutorial. For more documentation, see the [[Modding:Modder Guide/APIs|SMAPI reference]] and the [[Modding:Index|topics listed on the index page]].
 
  
===How do I make my mod work crossplatform?===
+
# 打开 [https://smapi.io/mods/ 模组兼容性页面]
SMAPI will automatically adjust your mod so it works on Linux, MacOS, and Windows. However, there are a few things you should do to avoid problems:
+
# 单击搜索框下方的“show advanced info”
 +
# 在“code”列中查找链接
 +
 
 +
=== 我如何使我的模组跨平台工作?===
 +
SMAPI 将自动调整模组使其可以在 Linux 、MacOS 和 Windows 上运行。但是你也应该采取一些措施来避免出现问题:
  
 
<ol>
 
<ol>
<li>Use the [https://smapi.io/package/readme crossplatform build config] package to automatically set up your project references. This makes crossplatform compatibility easier and lets your code compile on any platform. (If you followed the above guide, you already have this.)</li>
+
<li> 使用 [https://smapi.io/package/readme 跨平台构建配置] 包以自动设置您的项目引用,这使跨平台兼容性变得更容易,并使代码可以在任何平台上进行编译。(如果遵循上述指南,那么就没问题了)</li>
  
<li>Use <tt>Path.Combine</tt> to build file paths, don't hardcode path separators since they won't work on all platforms.
+
<li> 使用 <samp>Path.Combine</samp> 方法来拼接路径,而不是使用斜杠或者除号,因为不同的操作系统所使用的分隔符是不一样的
  
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
// ✘ Don't do this! It won't work on Linux/Mac.
+
// ✘ 不要这样做!这在 Linux Mac 上不会起作用
 
string path = this.Helper.DirectoryPath + "\assets\image.png";
 
string path = this.Helper.DirectoryPath + "\assets\image.png";
  
// ✓ This is OK
+
// ✓ 这样才是对的
 
string path = Path.Combine(this.Helper.DirectoryPath, "assets", "image.png");
 
string path = Path.Combine(this.Helper.DirectoryPath, "assets", "image.png");
 
</syntaxhighlight></li>
 
</syntaxhighlight></li>
  
<li>Use <tt>this.Helper.DirectoryPath</tt>, don't try to determine the mod path yourself.
+
<li> 使用 <samp>this.Helper.DirectoryPath</samp> 来获取当前模组文件夹路径,请勿尝试自行确定模组路径
  
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
// ✘ Don't do this! It will crash if SMAPI rewrites the assembly (e.g. to update or crossplatform it).
+
// ✘ 不要这样做!如果 SMAPI 重写了程序集(例如对其进行了更新或跨平台),它将崩溃
 
string modFolder = Assembly.GetCallingAssembly().Location;
 
string modFolder = Assembly.GetCallingAssembly().Location;
  
// ✓ This is OK
+
// ✓ 这样就没问题
 
string modFolder = this.Helper.DirectoryPath;
 
string modFolder = this.Helper.DirectoryPath;
 
</syntaxhighlight></li>
 
</syntaxhighlight></li>
 +
 +
<li>“资源名称”标识可以通过 <code><nowiki>Game1.content.Load<T>("asset name")</nowiki></code> 等内容 API 加载的资产。这“不是”文件路径,并且资源名称并不总是与文件路径匹配。比较资源名称时,请确保使用 <code>PathUtilities.NormalizeAssetName("some/path")</code> 而不是 path helpers
 +
 +
<syntaxhighlight lang="c#">
 +
// ✘ 不要这样做! 它不适用于 Windows。
 +
bool isAbigail = (asset.Name == Path.Combine("Characters", "Abigail"));
 +
bool isAbigail2 = (asset.Name == PathUtilities.NormalizePath("Characters", "Abigail"));
 +
 +
// ✓ 这样就可以了
 +
bool isAbigail = (asset.Name == PathUtilities.NormalizeAssetName("Characters", "Abigail"));
 +
</syntaxhighlight>
 +
 +
请注意,无需标准化传递给 SMAPI API 的资源名称,SMAPI API 会自动标准化它们(尽管这样做也没什么坏处):
 +
<syntaxhighlight lang="c#">
 +
// ✓ 这样就可以了
 +
helper.Content.Load<Texture2D>("Characters/Abigail");
 +
helper.Content.Load<Texture2D>(@"Characters\Abigail");
 +
</syntaxhighlight>
 +
</li>
 
</ol>
 
</ol>
  
===How do I decompile the game code?===
+
=== 如何反编译游戏代码?===
It's often useful to see how the game code works. The game code is compiled into <tt>StardewValley.exe</tt> (i.e. converted to a machine-readable format), but you can decompile it get a mostly-readable approximation of the original code. (This might not be fully functional due to decompiler limitations, but you'll be able to see what it's doing.)
+
观察游戏代码的工作方式通常对开发很有用。游戏的代码都编译在 <samp>StardewValley.dll</samp> 文件中,可以对其进行反编译以获得原始代码的近似可读性。(由于反编译和生成优化的问题,可能无法准确还原逻辑,但已经足够看到它在做什么。)
 +
 
 +
要反编译游戏代码:
 +
 
 +
:# 首次步骤:
 +
:## 在 Windows 上安装 {{github|icsharpcode/ILSpy/releases|ILSpy}}(在 Release 的 Assets 下获取“ILSpy_binaries”文件),或在 Linux 和 macOS 上安装 [https://github.com/icsharpcode/AvaloniaILSpy/releases Avalonia ILSpy]
 +
:## 打开 ILSpy
 +
:## 单击“View > Options”,滚动到底部的“Other”部分,然后启用“Always qualify member references”
 +
:# 在 ILSpy 中打开 <samp>Stardew Valley.dll</samp>
 +
:# 确保在语言下拉列表中选择“C#”(不是 IL、IL with C# 或 ReadyToRun)
 +
:# 右键单击“Stardew Valley”并选择“Save Code”以创建可以在 Visual Studio 中打开的反编译项目
 +
:## 如果您使用 Avalonia ILSpy,请确保将 <samp>.csproj</samp> 文件扩展名添加到保存对话框中的文件名中,如下所示:<samp>Stardew-Valley.csproj</samp> (否则该项目将无法正确反编译)
 +
 
 +
另外有一个很不错的反编译工具但已经不再维护了:{{github|dnSpy/dnSpy/releases|dnSpy}}
  
To decompile the game code...
+
要解包 XNB 数据或图像文件,请参阅 [[模组:编辑 XNB 文件]]
  
; On Windows&#58;
+
===“目标 .NET 6.0”是什么意思?===
:# First-time setup:
 
:## Install the latest {{github|icsharpcode/ILSpy/releases|ILSpy}} release (get the "ILSpy_binaries" file under assets).
 
:## Open ILSpy.
 
:## Click ''View > Options'', scroll to the "Other" section at the bottom, and enable "Always qualify member references".
 
:# Open <tt>StardewValley.exe</tt> in ILSpy.
 
:# Right-click on ''Stardew Valley'' and choose ''Save Code'' to create a decompiled project you can open in Visual Studio.
 
  
; On Linux/MacOS&#58;
+
这里有多种不同的东西
:# Install [https://code.visualstudio.com/download Visual Studio Code].
 
:# Get the [https://marketplace.visualstudio.com/items?itemName=icsharpcode.ilspy-vscode ILSpy .NET Decompiler] plugin for VSCode.
 
:# Open the Visual Studio Code Command Palette (<code>Command+Shift+P</code>), then type <code>ilspy</code> to show the two commands.
 
:# Choose ''Decompile IL Assembly (pick file)'', then choose the <tt>StardewValley.exe</tt> in your [[Modding:Player Guide/Getting Started#Find your game folder|game folder]].
 
:# A tree view named <tt>ILSPY DECOMPILED MEMBERS</tt> should appear in the Explorer view. This lets you expand and select various nodes to see the decompiled C# code in the editor.
 
  
To unpack the XNB data/image files, see [[Modding:Editing XNB files]].
+
* 目标版本:这是编译二进制文件所针对的 .NET 版本,最新版本的游戏必须以 .NET 6.0 为目标
 +
* SDK 版本:这是安装的 .NET 版本,可以定位低于 SDK 版本的任何版本。如果在 VS 2022 中安装了 .NET 7.0,仍然可以使用 .NET 6.0
 +
* C# 版本:语言的版本与 .NET 版本分开(尽管存在对应关系),可以在项目中使用 <code><langversion></code> 属性来指定语言版本
  
 
[[Category:模组]]
 
[[Category:模组]]
第233行: 第305行:
 
[[fr:Modding:Guide du Moddeur/Commencer]]
 
[[fr:Modding:Guide du Moddeur/Commencer]]
 
[[pt:Modificações:Guia do Modder/Começando]]
 
[[pt:Modificações:Guia do Modder/Começando]]
 +
[[ru:Модификации:Моддер гайд/Приступая к работе]]

2024年4月3日 (三) 09:52的最新版本

制作SMAPI模组 SMAPI mascot.png


模组:目录

如果您是第一次制作模组 请参阅 模组:目录#创建模组 来了解 C# 模组和内容包模组之间差异的简短描述。

您想使用 C# 创建“SMAPI 模组”吗?”本指南适合您!

介绍

什么是 SMAPI 模组?

SMAPI 模组使用 SMAPI 编辑接口来扩展游戏逻辑。当游戏中发生某些事情时(例如当一个对象被放置在世界中时),该模组可以做出响应,定期运行代码(例如每个更新周期运行一次),更改游戏的资源和数据等。SMAPI 模组是使用 .NET 的 C# 编写的,游戏使用 MonoGame 运行逻辑(绘制到屏幕、用户输入等)。

.NET 的另一种语言 Visual Basic 也可以用于编写模组,如果您了解该语言的对应语法即可使用它。得益于 .NET 新版本的特性,从游戏版本 1.5.5 开始使用该语言编写模组也可以直接跨平台运行,社区中已经存在使用该语言的模组并且运行正常,也许您正在运行它们。本文中会提及一些代码示例。

为什么模组使用 SMAPI?

SMAPI 可以做许多事情,例如:

  1. 将你的模组加载到游戏中。如果没有 SMAPI 来加载代码模组,则不可能实现它们。
  2. 提供接口和事件,以原本无法实现的方式与游戏进行交互。例如游戏资源或数据更改、玩家配置、翻译、反射等的简化接口。这些内容将在指南后面介绍。
  3. 加载时重写模组以实现跨平台兼容性。这让您而不必担心游戏在 Linux/Mac/Windows 版本之间的差异。
  4. 重写模组来更新它。SMAPI 可检测并修复常见情况下因游戏更新而损坏的模组代码。
  5. 拦截错误。如果模组崩溃或导致错误,SMAPI 将拦截错误,在控制台窗口中显示错误详细信息,并在大多数情况下自动恢复游戏。这意味着模组不会意外导致游戏崩溃,并且可以更轻松地排除错误。
  6. 提供更新检查。当模组有新版本可用时,SMAPI 会自动提醒玩家。
  7. 提供兼容性检查。SMAPI 会自动检测模组何时不兼容,并在导致问题之前将其禁用,这样玩家就不会遇到损坏的游戏。

我能制作一个模组吗?

是的!本指南将帮助你逐步创建一个简单的模组。然后你可以继续学习,让它做您想做的事即可。

如果你是编程新手,许多模组开发人员开始时几乎没有或完全没有编程经验。如果你下定决心,当然可以沿途学习,但是您应该为陡峭的学习曲线做好准备。刚开始时不要太过于自信,弄清楚它的时候,最好从一个小的模组开始。一开始很容易变得不知所措并放弃。模组社区非常热情,所以不要害怕问问题!

如果你已经具备编程经验,那应该没问题。具有 C# 或 Java 的编程经验将使事情变得容易,但这并不重要。如果不熟悉 C#,则可以浏览下面的“学习C#”参考资料以填补所有空白。

我可以不使用 SMAPI 来制作模组吗?

当然。许多的 SMAPI 模组支持 内容包,可以让你提供它们所使用的 JSON 文本文件、图像等。例如,你可以 使用 Content Patcher 来编辑游戏的贴图并且不需要任何编程技术。本指南的其余部分是关于创建新的 SMAPI 模组的。有关内容包,请参阅 模组:Content Patcher (或模组的文档(如果为其他模组创建内容包)).

我在哪里可以得到帮助?

星露谷官方聊天室欢迎你的到来:Stardew Valley Discord

开始

学习 C#

由于模组是用 C# 编写的,因此最好先熟悉它。无需记住所有内容,但是掌握基础知识(例如字段、方法、变量和类)将使其他所有内容都变得更加容易。

一些有用的资源:

SMAPI 经常使用的几个概念

要求

在你开始之前:

  1. 熟悉 模组的使用,本指南的其余部分假定你已经熟悉使用模组。
  2. 安装游戏
  3. 安装 SMAPI
  4. 安装开发环境
  5. 安装 NET 6.0 SDK(x64版本,也可以直接在 Visual Studio Community 单个组件中选择)

如果不熟悉 Visual Studio(Windows/Mac)或者 MonoDevelop(Linux),在 模组:IDE 参考 页面解释了如何完成本指南所需的重要工作

创建一个基本模组

快速启动

如果您有足够的经验可以跳过本教程,以下是本节的摘要:

展开以查看快速开始 
  1. 创建一个 C#类库 项目(注意不要选择成 .NET Framework 的那个,或者你可以使用另一种语言)
  2. 目标框架选择 .NET 6.0
  3. 添加 Pathoschild.Stardew.ModBuildConfig NuGet 包
  4. 创建一个 ModEntry 类,将它继承自 StardewModdingAPI.Mod
  5. 覆写 Entry 方法,并使用 SMAPI 事件和 API 编写代码
  6. 创建一个 manifest.json 文件来描述你的模组
  7. 创建 一个包含模组文件的zip压缩包 来发布

创建解决方案

SMAPI 模组是一个动态链接库(DLL),具有由 SMAPI 调用的入口方法

  1. 打开 Visual Studio 或 MonoDevelop
  2. 使用“类库”项目创建解决方案(请参阅如何创建项目)(不要选择“类库(.NET Framework)”!那是在游戏 1.5.4 以及之前版本中所使用的)
  3. 目标框架设置为 .NET 6(请参阅 如何更改目标框架)您可能需要 安装 SDK。这是游戏安装和使用的版本
  4. 添加 Pathoschild.Stardew.ModBuildConfig NuGet 包(请参阅 如何添加 NuGet 包
    • 如果报错“找不到类型或命名空间名称“StardewModdingAPI””,则可能没有检测到游戏路径,需要将 GamePath 属性设置为游戏的目录。这可以通过将“GamePath”属性添加到项目文件(“.csproj”或“.vbproj”)中的“PropertyGroup”节点下来完成
  5. 之后重新启动 Visual Studio 或者 MonoDevelop

添加代码

接下来添加代码

  1. 删除 Class1.cs 或者 MyClass.cs 文件 (参阅 如何删除文件).
  2. 在项目中添加一个 C# 类文件,取名为 ModEntry.cs (参阅 如何添加文件).
  3. 在此文件中输入代码 (把 YourProjectName 换成你的解决方案的名字):
    using System;
    using Microsoft.Xna.Framework;
    using StardewModdingAPI;
    using StardewModdingAPI.Events;
    using StardewModdingAPI.Utilities;
    using StardewValley;
    
    namespace YourProjectName
    {
        /// <summary>模组入口点</summary>
        public class ModEntry : Mod
        {
            /*********
            ** 公共方法
            *********/
            /// <summary>模组的入口点,在首次加载模组后自动调用</summary>
            /// <param name="helper">对象 helper 提供用于编写模组的简化接口</param>
            public override void Entry(IModHelper helper)
            {
                helper.Events.Input.ButtonPressed += this.OnButtonPressed;
                //意思是将 OnButtonPressed 方法绑定到 SMAPI 的 ButtonPressed 按钮按下事件
                //this 表示本对象,也就是当前的 ModEntry 类
            }
    
            /*********
            ** 私有方法
            *********/
            /// <summary>在玩家按下键盘、控制器或鼠标上的按钮后引发</summary>
            /// <param name="sender">对象 sender 表示调用此方法的对象</param>
            /// <param name="e">对象 e 表示事件数据</param>
            private void OnButtonPressed(object sender, ButtonPressedEventArgs e)
            {
                // 如果玩家还没有进入存档,则取消执行
                if (!Context.IsWorldReady)
                    return;
    
                // 向控制台输出按下了什么按钮
                this.Monitor.Log($"{Game1.player.Name} 按下了 {e.Button}.", LogLevel.Debug);
            }
        }
    }
    

以下是该代码的功能细分:

  1. using X (参阅 using directive) 使该命名空间中的类在你的代码中可用
  2. namespace YourProjectName(参阅 namespace keyword)定义命名空间,入门时不必担心,因为在新建类文件时 Visual Studio 或 MonoDevelop 会自动添加它
  3. public class ModEntry : Mod (参阅 class keyword) 创建你的模组的主类文件,并继承 SMAPI 的 Mod 类。SMAPI 将自动检测你的 Mod 子类,而 Mod 对象使你可访问 SMAPI 的接口
  4. public override void Entry(IModHelper helper) 是将模组加载到游戏中时 SMAPI 将调用的方法。这里的 helper 对象提供了对许多 SMAPI 接口的便捷访问
  5. helper.Events.Input.ButtonPressed += this.OnButtonPressed 添加了一个事件绑定到当按下按钮的事件发生时。换句话说,当一个按钮被按下 (也就是 helper.Events.Input.ButtonPressed 事件触发了), SMAPI 会调用你的 this.OnButtonPressed 方法。参阅 SMAPI 中的事件 获取更多信息

如果您使用的是 Visual Basic 语言,以下是使用该语言的 Entry 示例,实现了和上面的 C# 代码相同的步骤和功能

    Imports StardewModdingAPI
    Imports StardewModdingAPI.Events
    Imports StardewValley
    
    Namespace YourProjectName
    Public Class ModEntry
        Inherits [Mod]
    
        Public Overrides Sub Entry(helper As IModHelper)
            AddHandler helper.Events.Input.ButtonPressed, AddressOf OnButtonPressed
        End Sub
    
        Public Sub OnButtonPressed(sender As Object, e As ButtonPressedEventArgs)
            If Not Context.IsWorldReady Then Exit Sub
            Monitor.Log($"{Game1.player.Name} 按下了 {e.Button}.", LogLevel.Debug)
        End Sub
    End Class
    End Namespace
    

添加你的清单

模组的清单为 SMAPI 提供模组的信息

  1. 向你的解决方案添加一个名为 manifest.json 的文本文件
  2. 将这些代码复制到文件中:(注意要区分键值的大小写,避免出现意外情况)
    {
      "Name": "<模组的名字>",
      "Author": "<你的名字>",
      "Version": "1.0.0",
      "Description": "<一句话简单描述你的模组是干什么的>", //(可选)
      "UniqueID": "<你的名字>.<模组的名字>",
      "EntryDll": "<你的解决方案的名字>.dll",
      "MinimumApiVersion": "4.0.0",
      "UpdateKeys": [] //(可选)常用的更新键:"Nexus:???", "Gtihub:user/repository", "Moddrop:???"
    }
    
  3. 正确填写其中的信息,不要留着空信息

当游戏启动时,它将在控制台中输出。更多信息请参阅 清单文档

试试你的模组

  1. 构建项目。
    如果正确执行了“创建项目”步骤,这会自动将模组添加到游戏的 Mods</ samp> 文件夹。
  2. 通过 SMAPI 运行游戏。

到目前为止,只要您在游戏中按下某个键时该模组就会向控制台窗口发送一条消息。

更改控制台文本颜色

控制台中默认文本颜色的设置方式可能会导致它们不可读。 要更改文本颜色:

  • Steam:打开 Steam 并右键单击库中的游戏。单击“管理”下的“浏览本地文件”,然后打开“/Stardew Valley/smapi-internal/”文件夹中的 config.json 文件,搜索“ConsoleColors”,然后编辑“Trace”和“Debug”颜色,以便它们在控制台中可见。
  • Linux:linux上的默认路径是 ~/.local/share/Steam/steamapps/common/Stardew Valley/smapi-internal/config.json,除非你已经安装 您的游戏位于不同的驱动器或者标准 Steam 库文件夹之外。
  • Windows:Windows 上的默认路径应为“C:\Program files (x86)\Steam\steamapps\common\Stardew Valley\smapi-internal\config.json”,除非游戏在不同的驱动器或 Steam 库文件夹之外。

疑难解答

如果上述教程创建的模组不能正常运行:

  1. 重复查看以上步骤,以确保你没有跳过任何内容
  2. 检查是否有任何的错误消息,也许可以解释为什么它不起作用:
    • 在 Visual Studio 中尝试重新构建解决方案,查看 输出 面板 或者 错误列表
    • 在 MonoDevelop 中点击 Build > Rebuild All 等待处理完毕。然后点击 "Build: XX errors, XX warnings" 在顶部的条,点击 XX ErrorsBuild Output 选项卡
  3. 参阅 疑难解答.
  4. 如果其他所有方法均失败,请到 Stardew Valley Discord 寻求帮助 :)

常见问题

SMAPI 的文档在哪里?

这只是“入门”教程。更多信息请参阅 SMAPI 接口说明

我可以看看其他模组的代码吗?

是的,近 70% 的 SMAPI 模组都是开源的。要找到他们的代码:

  1. 打开 模组兼容性页面
  2. 单击搜索框下方的“show advanced info”
  3. 在“code”列中查找链接

我如何使我的模组跨平台工作?

SMAPI 将自动调整模组使其可以在 Linux、MacOS 和 Windows 上运行。但是你也应该采取一些措施来避免出现问题:

  1. 使用 跨平台构建配置 包以自动设置您的项目引用,这使跨平台兼容性变得更容易,并使代码可以在任何平台上进行编译。(如果遵循上述指南,那么就没问题了)
  2. 使用 Path.Combine 方法来拼接路径,而不是使用斜杠或者除号,因为不同的操作系统所使用的分隔符是不一样的
    // ✘ 不要这样做!这在 Linux 和 Mac 上不会起作用
    string path = this.Helper.DirectoryPath + "\assets\image.png";
    
    // ✓ 这样才是对的
    string path = Path.Combine(this.Helper.DirectoryPath, "assets", "image.png");
    
  3. 使用 this.Helper.DirectoryPath 来获取当前模组文件夹路径,请勿尝试自行确定模组路径
    // ✘ 不要这样做!如果 SMAPI 重写了程序集(例如对其进行了更新或跨平台),它将崩溃
    string modFolder = Assembly.GetCallingAssembly().Location;
    
    // ✓ 这样就没问题
    string modFolder = this.Helper.DirectoryPath;
    
  4. “资源名称”标识可以通过 Game1.content.Load<T>("asset name") 等内容 API 加载的资产。这“不是”文件路径,并且资源名称并不总是与文件路径匹配。比较资源名称时,请确保使用 PathUtilities.NormalizeAssetName("some/path") 而不是 path helpers
    // ✘ 不要这样做! 它不适用于 Windows。
    bool isAbigail = (asset.Name == Path.Combine("Characters", "Abigail"));
    bool isAbigail2 = (asset.Name == PathUtilities.NormalizePath("Characters", "Abigail"));
    
    // ✓ 这样就可以了
    bool isAbigail = (asset.Name == PathUtilities.NormalizeAssetName("Characters", "Abigail"));
    

    请注意,无需标准化传递给 SMAPI API 的资源名称,SMAPI API 会自动标准化它们(尽管这样做也没什么坏处):

    // ✓ 这样就可以了
    helper.Content.Load<Texture2D>("Characters/Abigail");
    helper.Content.Load<Texture2D>(@"Characters\Abigail");
    

如何反编译游戏代码?

观察游戏代码的工作方式通常对开发很有用。游戏的代码都编译在 StardewValley.dll 文件中,可以对其进行反编译以获得原始代码的近似可读性。(由于反编译和生成优化的问题,可能无法准确还原逻辑,但已经足够看到它在做什么。)

要反编译游戏代码:

  1. 首次步骤:
    1. 在 Windows 上安装 ILSpy(在 Release 的 Assets 下获取“ILSpy_binaries”文件),或在 Linux 和 macOS 上安装 Avalonia ILSpy
    2. 打开 ILSpy
    3. 单击“View > Options”,滚动到底部的“Other”部分,然后启用“Always qualify member references”
  2. 在 ILSpy 中打开 Stardew Valley.dll
  3. 确保在语言下拉列表中选择“C#”(不是 IL、IL with C# 或 ReadyToRun)
  4. 右键单击“Stardew Valley”并选择“Save Code”以创建可以在 Visual Studio 中打开的反编译项目
    1. 如果您使用 Avalonia ILSpy,请确保将 .csproj 文件扩展名添加到保存对话框中的文件名中,如下所示:Stardew-Valley.csproj (否则该项目将无法正确反编译)

另外有一个很不错的反编译工具但已经不再维护了:dnSpy

要解包 XNB 数据或图像文件,请参阅 模组:编辑 XNB 文件

“目标 .NET 6.0”是什么意思?

这里有多种不同的东西

  • 目标版本:这是编译二进制文件所针对的 .NET 版本,最新版本的游戏必须以 .NET 6.0 为目标
  • SDK 版本:这是安装的 .NET 版本,可以定位低于 SDK 版本的任何版本。如果在 VS 2022 中安装了 .NET 7.0,仍然可以使用 .NET 6.0
  • C# 版本:语言的版本与 .NET 版本分开(尽管存在对应关系),可以在项目中使用 <langversion> 属性来指定语言版本