Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

测试地图相关 #10

Merged
merged 11 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
site/**
.VSCodeCounter/**
.vs/**
.idea/
.idea/
**/Source/bin/**
**/Source/obj/**
**/Source/.vs/**
**/Source/CelesteModTutorial.sln
58 changes: 53 additions & 5 deletions docs/advanced/cross_mod_interactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ public static bool GravityHelperLoaded;
public override void Load()
{
// 获取 GravityHelperModule 的元数据
EverestModuleMetadata gravityHelper = new()
EverestModuleMetadata gravityHelperMetadata = new()
{
Name = "GravityHelper",
Version = new Version(1, 2, 20)
};

// 判断 GravityHelper 是否成功加载
GravityHelperLoaded = Everest.Loader.DependencyLoaded(gravityHelper);
GravityHelperLoaded = Everest.Loader.DependencyLoaded(gravityHelperMetadata);
}
```

Expand Down Expand Up @@ -148,13 +148,61 @@ if (MyCelesteModAPI.MultiplyByTwo(myNumber) > 400)
通过这种方式, 我们可以在自己的 Mod 中访问并调用其他 Mod 提供的功能, 而不需要直接依赖该 Mod 的程序集.


<!--

## 直接程序集引用

有时候我们需要直接使用目标Mod中的类型和方法, 但目标 Mod 并没有实现 `ModInterop` API.
这种情况下, 我们可以直接引用其他 Mod 的程序集.

下面我们介绍两种方法:

### Cache

Everest 会将所有 Code Mod 的程序集使用 MonoMod 进行 patch 处理后放置到 `Celeste/Mods/Cache/<mod名>.<程序集名>.dll` 中.
我们可以通过配置模板的 `.csporj` 文件以直接引用它们:
Saplonily marked this conversation as resolved.
Show resolved Hide resolved

```xml title="MyCelesteMod.csproj" hl_lines="19 20 21 22"
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="CelesteMod.props" />

<PropertyGroup>
<RootNamespace>Celeste.Mod.MyCelesteMod</RootNamespace>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<None Include="CelesteMod.props">
<Visible>false</Visible>
</None>
<None Include="CelesteMod.targets">
<Visible>false</Visible>
</None>
</ItemGroup>

<ItemGroup>
<CelesteModReference Include="GravityHelper" />
<CelesteModReference Include="ExtendedVariantMode" />
<CelesteModReference Include="FrostHelper" AssemblyName="FrostTempleHelper" />
</ItemGroup>

<Import Project="CelesteMod.targets" />
</Project>
```

!!! info
在引用之前我们需要确认目标 Mod 在 `Cache` 中的是否存在, 以上面引用的 Mod 为例. `Cache` 中应该存在:

- GravityHelper.GravityHelper.dll
- ExtendedVariantMode.ExtendedVariantMode.dll

我们填写目标 Mod 在 `Cache` 中名称的前半段就行.
Saplonily marked this conversation as resolved.
Show resolved Hide resolved

### lib-stripped
-->

`lib-stripped` 是指剥离了所有方法实现的程序集, 仅保留类型和方法签名.
我们可以通过 [`NStrip`](https://github.com/bbepis/NStrip) 或 [`BepInEx.AssemblyPublicizer `](https://github.com/BepInEx/BepInEx.AssemblyPublicizer) 的 `strip-only` 模式等工具对目标程序集进行剥离.
完成后我们可以直接引用被剥离的程序集.



Expand Down Expand Up @@ -192,7 +240,7 @@ public override void Load()
PlayerGravityComponentProperty = gravityHelperModuleType?.GetProperty("PlayerComponent", BindingFlags.NonPublic | BindingFlags.Static);

// 反射获取 GravityHelper.Components.SetPlayerGravity 方法
SetPlayerGravityMethod = playerComponent?.GetValue(null)?.GetType().GetMethod("SetGravity", BindingFlags.Public | BindingFlags.Instance);
SetPlayerGravityMethod = PlayerGravityComponentProperty?.GetValue(null)?.GetType().GetMethod("SetGravity", BindingFlags.Public | BindingFlags.Instance);

// 反射获取 GravityHelper.GravityHelperModule.ShouldInvertPlayer 属性
IsPlayerInvertedProperty = gravityHelperModuleType?.GetProperty("ShouldInvertPlayer", BindingFlags.Public | BindingFlags.Static);
Expand Down
87 changes: 87 additions & 0 deletions docs/arc/project_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
!!! info
在蔚蓝国外社区流行着另一个 mod 项目模板, 不过我个人不太喜欢它, 不过你需要的话[这是 Github 主页](https://github.com/EverestAPI/CelesteModTemplate)
所以这里主要使用我个人制作也是个人最常用的一个.

\_(:з」∠)\_
根据一些反馈我们发现旧的手动配置环境的方式非常的复杂难操作(
所以呢这里就推荐一种新的配置环境的方式 - **使用模板**
考虑到 nuget 安装模板也需要一定的命令行基础...
所以这里考虑[提供直接的下载链接](https://hongshitieli.lanzouj.com/iJfRz1l0iffg),
或者你也可以选择使用 `dotnet cli` 从 nuget 上的模板安装:

!!! note
你可能还需要安装 `.NET 8 SDK` 来使用该模板, 你可以[在这里](https://get.dot.net)找到它

??? info "使用 dotnet cli 从模板新建项目"
首先在一个你喜欢的位置放置你的项目文件夹, 名字即为你的项目名, 例如 `MyCelesteMod`:
```bat
mkdir MyCelesteMod
cd MyCelesteMod
```
然后在此位置安装 nuget 上我的 mod 模板(如果你没有安装的话):
```bat
dotnet new install Saladim.CelesteModTemplate
```
然后你就能使用这条指令直接创建项目了:
```bat
dotnet new sapcelestemode
```
名字即为上层文件夹名, 或者你可以使用 `-n` 参数重写项目名字:
```bat
dotnet new sapcelestemod -n MySuperCelesteMod
```
模板目前默认不会创建针对 Everest Core 的 Code Mod, 如果你需要的话你可以传入 `--core-only true` 参数:
```bat
dotnet new sapcelestemod --core-only true
```

完成后使用你喜欢的编辑器打开项目(对于 vs 直接打开 .csproj 文件), 那么按理来说你会看到这几个文件:

- CelesteMod.props
- CelesteMod.targets
- Common.props
- MyCelesteModModule.cs
- MyCelesteMod.csproj

以及你的项目, 它的名字是 `MyCelesteMod`, 不同于旧的方法, 在这里你的配置过程很简单:

- 首先打开 `Common.props`, **将里面的 `CelesteRootPath` 内的内容改成你的蔚蓝安装位置**

```xml hl_lines="3"
<Project>
<PropertyGroup>
<CelesteRootPath>C:\Program Files (x86)\Steam\steamapps\common\Celeste</CelesteRootPath>
<CommonCelesteUsings>true</CommonCelesteUsings>
<CommonCelesteReferences>true</CommonCelesteReferences>
<ModAssetsFolderName>ModFolder</ModAssetsFolderName>
</PropertyGroup>
</Project>
```

现在你可以按下 `Ctrl+B` 或者手动点击 `生成->生成解决方案`,
如果你在你的 vs 输出里面看到了类似这两句:

```
1>MyCelesteMod -> D:\User\temp\cm\bin\x86\Debug\net452\MyCelesteMod.dll
1>MyCelesteMod -> C:/Program Files (x86)/Steam/steamapps/common/Celeste/Mods/MyCelesteMod_copy/MyCelesteMod.dll
```

并且你在你的蔚蓝 Mod 目录下找到了这个被创建的目录,
那么你的环境就算是配完了, 如果你很感兴趣这之中发生了什么, 要引用哪些程序集, 这个模板背后干了什么, 你可以去看那复杂的旧的配置方法.
!!! note
这个模板使用 `msbuild` 帮助了你很多事!
比如当你编译完项目之后它会复制编译结果到项目目录的 `ModFolder` 目录下,
然后将整个 `ModFolder` 复制到蔚蓝的 `Mods\{你的mod名}_copy` 文件夹下!
所以当我们需要更改一些比如说 loenn 的配置文件, `everest.yaml` 的内容, 你的测试地图等时,
你只需要简单地重新编译一遍项目, 然后等待模板来帮你做剩下的活!


## 更改细节

通过模板的话依然有些东西需要自行更改, 比如这个 Mod 的名字.
更改 Mod 的名字很简单, 你只需要简单地在 vs 里重命名项目的名字
比如我想叫做 `MyAwesomeMod`, 那么你可以通过这样:
![awesome mod!](rename_proj.png)

顺便别忘了把类似 `MyCelesteModModule.cs` 的文件名也改成类似 `MyAwesomeModModule.cs`,
以及改名后清理一下 ModFolder 下面可能有的一些以过去名字命名的 .dll 和 .pdb 文件!
22 changes: 12 additions & 10 deletions docs/coding_challenges/simple_texturing.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,12 @@ ok 那么现在我们该在代码这边来点贴图了, 这里我们会用到之
- Graphics
- Atlases
- Gameplay
- `MyCelesteMod`
- pass_by_refill.png
- objects
- PassByRefill
- pass_by_refill.png

`pass_by_refill.png` 即我们的贴图, 如果你同时也是一位 mapper 的话你一定很熟悉这个文件夹套套乐!
在代码这边, 我们使用 `GFX.Game["MyCelesteMod/pass_by_refill"]` 来获取这个贴图, 它是一个 `MTexture` 类型的实例, 在获取到这个贴图后,
在代码这边, 我们使用 `GFX.Game["objects/PassByRefill/pass_by_refill"]` 来获取这个贴图, 它是一个 `MTexture` 类型的实例, 在获取到这个贴图后,
我们 `new` 一个 `Monocle.Image`, 然后在构造函数中传入它, 然后使用 `this.Add` 函数挂载到我们的这个实体上, 总的代码应该是这样的:
```cs title="PassByRefill.cs"
public PassByRefill(Vector2 position, int dashes)
Expand All @@ -73,16 +74,17 @@ public PassByRefill(Vector2 position, int dashes)
Hitbox hitbox = new(64, 64);
Collider = hitbox;

MTexture tex = GFX.Game["MyCelesteMod/pass_by_refill"];
MTexture tex = GFX.Game["objects/PassByRefill/pass_by_refill"];
Image image = new(tex);
this.Add(image);
}
```

!!! info
`GFX` 是蔚蓝中的一个管理贴图的类, 我们用它获取到一个贴图组 `Game`, 然后向它检索一个名为 `MyCelesteMod/pass_by_refill` 的贴图, 你可能会疑惑为什么这里的路径只需要后半部分,
这是因为 `GFX.Game` 只会检索 `Atlases/Graphics/Gameplay` 中的内容.
同样的, `GFX.Portraits` 只会检索 `Atlases/Graphics/Portraits` 中的内容.
`GFX` 是蔚蓝中的一个管理贴图的类, 我们用它获取到一个贴图组 `Game`, 然后向它检索一个名为 `objects/PassByRefill/pass_by_refill` 的贴图, 你可能会疑惑为什么这里的路径只需要后半部分,

这是因为 `GFX.Game` 只会检索 `Graphics/Atlases/Gameplay` 中的内容.
同样的, `GFX.Portraits` 只会检索 `Graphics/Atlases/Portraits` 中的内容.

顺便记得删掉我们重写的 `Render` 函数, 我们不再需要它了. 总的类应该是这样的:
```cs title="PassByRefill.cs"
Expand All @@ -99,7 +101,7 @@ public class PassByRefill : Entity
Hitbox hitbox = new(64, 64);
Collider = hitbox;

MTexture tex = GFX.Game["MyCelesteMod/pass_by_refill"];
MTexture tex = GFX.Game["objects/PassByRefill/pass_by_refill"];
Image image = new(tex);
this.Add(image);
}
Expand Down Expand Up @@ -171,7 +173,7 @@ public class PassByRefill : Entity

然后设置 entity 的 `texture` 属性, 这会让 Loenn 为其设置贴图:
```lua
entity.texture = "MyCelesteMod/pass_by_refill"
entity.texture = "objects/PassByRefill/pass_by_refill"
```
顺便设置贴图原点为左上角, 否则 Loenn 中的显示可能会与实际游戏中的不同:
```lua
Expand All @@ -197,7 +199,7 @@ entity.fieldInformation =
}
}

entity.texture = "MyCelesteMod/pass_by_refill"
entity.texture = "objects/PassByRefill/pass_by_refill"
entity.justification = { 0.0, 0.0 }

return entity
Expand Down
8 changes: 8 additions & 0 deletions docs/coding_challenges/test_map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# 测试地图

实战部分附带一张测试地图供读者下载下来<del>乱弄</del>研究与测试,
你可以在[这里](../resources/CelesteModTutorial.zip)进行下载.
代码你可以在 `Source` 目录下找到.

!!! info
下载并解压后别忘了生成 Mod 的 `dll` 文件!
Loading