From 5d41648de5b7588eb6e73e2324870308a07617d5 Mon Sep 17 00:00:00 2001
From: Saplonily
Date: Sun, 11 Aug 2024 00:09:05 +0800
Subject: [PATCH] Deployed 52ce1e7 with MkDocs version: 1.6.0
---
404.html | 63 +
arc/basic_env/index.html | 63 +
arc/sdk-styled-proj/index.html | 63 +
begin/basic_env/index.html | 63 +
begin/celeste_everest_monomod/index.html | 63 +
begin/hook,reading_1/index.html | 63 +
begin/preference/index.html | 63 +
begin/reading_2/index.html | 63 +
begin/simple_entity/index.html | 63 +
begin/simple_texturing/index.html | 63 +
begin/simple_trigger/index.html | 63 +
extra_cmcc/cmcc/ReadMe/index.html | 63 +
extra_cmcc/cmcc/todo/index.html | 63 +
extra_cmcc/index.html | 63 +
extra_luacs/begin/index.html | 63 +
extra_luacs/cs_access/index.html | 63 +
extra_luacs/examples/index.html | 63 +
extra_luacs/reference/index.html | 63 +
index.html | 65 +-
other/xml-speedrun/index.html | 65 +-
search/search_index.json | 2 +-
sitemap.xml.gz | Bin 127 -> 127 bytes
trans/adv_hooks/index.html | 268 +++-
trans/adv_hooks2/index.html | 63 +
trans/common1/index.html | 69 +-
trans/common2/index.html | 1583 ++++++++++++++++++++
trans/common3/index.html | 1433 ++++++++++++++++++
trans/debug/index.html | 1173 +++++++++++++++
trans/ec_common/index.html | 69 +-
trans/il/index.html | 117 +-
trans/imgs/code_dependency.jpg | Bin 0 -> 11890 bytes
trans/imgs/code_joke.jpg | Bin 0 -> 39949 bytes
trans/imgs/debug_p1_0.jpg | Bin 0 -> 13781 bytes
trans/imgs/debug_p1_1.png | Bin 0 -> 39490 bytes
trans/imgs/debug_p2.jpg | Bin 0 -> 19736 bytes
trans/imgs/img00.png | Bin 0 -> 749 bytes
trans/imgs/img01.png | Bin 0 -> 736 bytes
trans/session_settings_savedata/index.html | 65 +-
38 files changed, 6052 insertions(+), 54 deletions(-)
create mode 100755 trans/common2/index.html
create mode 100755 trans/common3/index.html
create mode 100755 trans/debug/index.html
create mode 100755 trans/imgs/code_dependency.jpg
create mode 100755 trans/imgs/code_joke.jpg
create mode 100755 trans/imgs/debug_p1_0.jpg
create mode 100755 trans/imgs/debug_p1_1.png
create mode 100755 trans/imgs/debug_p2.jpg
create mode 100755 trans/imgs/img00.png
create mode 100755 trans/imgs/img01.png
diff --git a/404.html b/404.html
index efe90f3..32e0ea3 100755
--- a/404.html
+++ b/404.html
@@ -516,6 +516,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -594,6 +636,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/arc/basic_env/index.html b/arc/basic_env/index.html
index 7d43348..b5673d8 100755
--- a/arc/basic_env/index.html
+++ b/arc/basic_env/index.html
@@ -525,6 +525,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -603,6 +645,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/arc/sdk-styled-proj/index.html b/arc/sdk-styled-proj/index.html
index 9a6a653..2b06f40 100755
--- a/arc/sdk-styled-proj/index.html
+++ b/arc/sdk-styled-proj/index.html
@@ -523,6 +523,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -601,6 +643,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/begin/basic_env/index.html b/begin/basic_env/index.html
index 55fa6a9..3b2c66a 100755
--- a/begin/basic_env/index.html
+++ b/begin/basic_env/index.html
@@ -648,6 +648,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -726,6 +768,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/begin/celeste_everest_monomod/index.html b/begin/celeste_everest_monomod/index.html
index d67c8a6..44d1016 100755
--- a/begin/celeste_everest_monomod/index.html
+++ b/begin/celeste_everest_monomod/index.html
@@ -594,6 +594,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -672,6 +714,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/begin/hook,reading_1/index.html b/begin/hook,reading_1/index.html
index 8a86211..008ddf3 100755
--- a/begin/hook,reading_1/index.html
+++ b/begin/hook,reading_1/index.html
@@ -627,6 +627,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -705,6 +747,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/begin/preference/index.html b/begin/preference/index.html
index 4dbc721..7947f1a 100755
--- a/begin/preference/index.html
+++ b/begin/preference/index.html
@@ -603,6 +603,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -681,6 +723,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/begin/reading_2/index.html b/begin/reading_2/index.html
index 1df0d2a..80bd2dd 100755
--- a/begin/reading_2/index.html
+++ b/begin/reading_2/index.html
@@ -624,6 +624,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -702,6 +744,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/begin/simple_entity/index.html b/begin/simple_entity/index.html
index e676816..e488063 100755
--- a/begin/simple_entity/index.html
+++ b/begin/simple_entity/index.html
@@ -717,6 +717,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -795,6 +837,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/begin/simple_texturing/index.html b/begin/simple_texturing/index.html
index e4011b7..64b6d26 100755
--- a/begin/simple_texturing/index.html
+++ b/begin/simple_texturing/index.html
@@ -618,6 +618,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -696,6 +738,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/begin/simple_trigger/index.html b/begin/simple_trigger/index.html
index b06df58..3748317 100755
--- a/begin/simple_trigger/index.html
+++ b/begin/simple_trigger/index.html
@@ -612,6 +612,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -690,6 +732,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/extra_cmcc/cmcc/ReadMe/index.html b/extra_cmcc/cmcc/ReadMe/index.html
index 4997459..3b6db09 100755
--- a/extra_cmcc/cmcc/ReadMe/index.html
+++ b/extra_cmcc/cmcc/ReadMe/index.html
@@ -525,6 +525,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -603,6 +645,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/extra_cmcc/cmcc/todo/index.html b/extra_cmcc/cmcc/todo/index.html
index c0442a5..d5e3e53 100755
--- a/extra_cmcc/cmcc/todo/index.html
+++ b/extra_cmcc/cmcc/todo/index.html
@@ -525,6 +525,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -603,6 +645,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/extra_cmcc/index.html b/extra_cmcc/index.html
index 470deda..a9b7481 100755
--- a/extra_cmcc/index.html
+++ b/extra_cmcc/index.html
@@ -525,6 +525,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -603,6 +645,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/extra_luacs/begin/index.html b/extra_luacs/begin/index.html
index 7a796cc..aa3a41c 100755
--- a/extra_luacs/begin/index.html
+++ b/extra_luacs/begin/index.html
@@ -525,6 +525,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -603,6 +645,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/extra_luacs/cs_access/index.html b/extra_luacs/cs_access/index.html
index f260c63..f2f89e6 100755
--- a/extra_luacs/cs_access/index.html
+++ b/extra_luacs/cs_access/index.html
@@ -525,6 +525,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -603,6 +645,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/extra_luacs/examples/index.html b/extra_luacs/examples/index.html
index 9b0591b..9219487 100755
--- a/extra_luacs/examples/index.html
+++ b/extra_luacs/examples/index.html
@@ -525,6 +525,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -603,6 +645,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/extra_luacs/reference/index.html b/extra_luacs/reference/index.html
index 1c7699e..0e68db2 100755
--- a/extra_luacs/reference/index.html
+++ b/extra_luacs/reference/index.html
@@ -525,6 +525,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -603,6 +645,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
diff --git a/index.html b/index.html
index 6887420..55d8f68 100755
--- a/index.html
+++ b/index.html
@@ -533,6 +533,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -611,6 +653,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
@@ -1044,7 +1107,7 @@ 首页
Apple Sheep - 在写作初期提供了大量修改建议 (Bilibili )
夜谷紫幽 - 为配置环境节提供了使用模板的建议 (Bilibili )
电箱 - 制作了包含基础 Loenn 使用教程的作图教程 (Bilibili )
-Lucky boy - Session, Settings, SaveData 节的一些补充 (GitHub )
+Lucky boy - Session, Settings, SaveData 节的一些补充, 以及钩取 Helper 方法, debug, tracker, flag, tag 节的作者 (GitHub )
以及我自己 :D
diff --git a/search/search_index.json b/search/search_index.json
index f36ea73..7a6606c 100755
--- a/search/search_index.json
+++ b/search/search_index.json
@@ -1 +1 @@
-{"config":{"lang":["en"],"separator":"[\\s\\u200b\\u3000\\-\u3001\u3002\uff0c\uff0e\uff1f\uff01\uff1b]+","pipeline":["stemmer"]},"docs":[{"location":"","title":"\u9996\u9875","text":"\u672c\u7cfb\u5217\u6559\u7a0b\u4e3b\u8981\u5199\u81ea\u4e8e\u4e2a\u4eba\u5728\u5236\u4f5c\u851a\u84dd CodeMod \u7684\u4e00\u4e9b\u7ecf\u9a8c \u672c\u7f51\u7ad9\u5185\u5bb9\u5f00\u6e90\u5728: github.com/Saplonily/CelesteModTutorial \u5341\u5206\u6b22\u8fce\u6765\u63d0 pr \u548c issue \u4ee5\u4fee\u590d\u5404\u79cd\u8bed\u6cd5\u9519\u8bef, \u7528\u8bcd\u9519\u8bef\u548c\u5185\u5bb9\u9519\u8bef\u4ee5\u53ca\u5efa\u8bae_(:\u0437\u300d\u2220)_
\u5927\u90e8\u5206\u6587\u7ae0\u53ef\u80fd\u4f1a\u5199\u7684\u4e0d\u660e\u4e0d\u767d\u4ee5\u81f3\u4e8e\u9700\u8981\u9891\u7e41\u4fee\u6539, \u5982\u679c\u4f60\u6709\u66f4\u597d\u7684\u4fee\u6539\u5efa\u8bae\u7684\u8bdd\u6b22\u8fce\u6765\u63d0 issue.
\u90a3\u4e48\u4e00\u5207\u5c31\u7eea, \u53ef\u4ee5\u5f00\u59cb\u9605\u8bfb \u5165\u95e8-\u7b2c\u4e00\u8282 \u4e86:
\u5f00\u59cb - Celeste Everest MonoMod
\u987a\u4fbf\u611f\u8c22\u4e00\u4e9b\u4e3a\u672c\u6559\u7a0b\u8d21\u732e\u7684\u4eba:
Apple Sheep - \u5728\u5199\u4f5c\u521d\u671f\u63d0\u4f9b\u4e86\u5927\u91cf\u4fee\u6539\u5efa\u8bae (Bilibili) \u591c\u8c37\u7d2b\u5e7d - \u4e3a\u914d\u7f6e\u73af\u5883\u8282\u63d0\u4f9b\u4e86\u4f7f\u7528\u6a21\u677f\u7684\u5efa\u8bae (Bilibili) \u7535\u7bb1 - \u5236\u4f5c\u4e86\u5305\u542b\u57fa\u7840 Loenn \u4f7f\u7528\u6559\u7a0b\u7684\u4f5c\u56fe\u6559\u7a0b (Bilibili) Lucky boy - Session, Settings, SaveData \u8282\u7684\u4e00\u4e9b\u8865\u5145 (GitHub) \u4ee5\u53ca\u6211\u81ea\u5df1 :D
Saplonily (Bilibili, Outlook) \u4ee5\u53ca\u6559\u7a0b\u5927\u90e8\u5206\u5185\u5bb9\u7684\u6765\u6e90:
\u548c\u4e00\u5207\u7684\u57fa\u7840:
\u5728\u7f51\u7ad9\u4e2d\u7684\u4ee3\u7801\u5757\u4e2d\u7684\u4e00\u4e9b\u9ad8\u4eae\u5728\u6a2a\u5411\u6eda\u52a8\u65f6\u4f1a\u53d1\u751f\u622a\u65ad, \u5373\u9ad8\u4eae\u5e76\u6ca1\u6709\u8986\u76d6\u6574\u884c, \u8fd9\u4e2a\u662f mkdocs-material
\u81ea\u8eab\u7684 bug, \u800c\u4e14\u770b\u4e0a\u53bb\u8bf4\u662f\u4fee\u590d\u8d77\u6765\u5f88\u56f0\u96be, issue \u94fe\u63a5: mkdocs-material issue #452.
bug \u4e8e\u4e0b:
t11ntpj808mbc1gu4lx7n9d8tj5q3ck3t1c0aclc Liquorice oat cake carrot cake. Halvah lemon drops bear claw fruitcake. Marshmallow danish jelly-o toffee.\njqlksiohper0brg9x2ajcm7ajjf8ptjxprqstvda Apple pie cake jelly-o sugar plum.\nx3mjly0wn48wy7lgf2bfymbykommv8dbyp7an1n8 Toffee candy brownie carrot cake jujubes sweet roll chocolate gingerbread.\nq0b5pj6eacuwj3t1i4jv7yxf00mi6osc0h5etcfz Cupcake tiramisu danish brownie danish jujubes gingerbread toffee gummi bears.\nu25qzla31ahqxd2x6b2wgpbxvw88h5w6mujoqtuq Fruitcake jelly beans candy canes icing pastry liquorice. Bear claw tart chocolate sweet souffl\u00e9 sweet roll marshmallow ice cream liquorice.\n9xcjy4nvh1jinka64lkdr1nhagm8odp0frr56nks Bear claw tootsie roll toffee biscuit cotton candy macaroon. \n5rmcwguz3jzws8w1hh2jbfdau74jip3f8rbu10oy Pudding caramels carrot cake sweet roll danish oat cake.\ns50wqctf9059ets5ezp4oeq7p6pfr24ntww2d15v Oat cake macaroon pastry cheesecake. Dessert topping chocolate bar. \nvue3y73jcwsg5um4pw8aqhuv3njgtg9iq0ortx5p Sesame snaps candy canes muffin lollipop wafer. \n1o6edje4xcb7vtcvct4ghawafdvmvgkx4r0scny5 Macaroon pudding gingerbread. \n
\u672c\u7cfb\u5217\u5185\u5bb9\u4f9d\u636eCC BY-SA 4.0\u8bb8\u53ef\u8bc1\u8fdb\u884c\u6388\u6743
"},{"location":"arc/basic_env/","title":"\u57fa\u7840\u73af\u5883\u914d\u7f6e - \u65e7","text":""},{"location":"arc/basic_env/#_1","title":"\u9879\u76ee\u521b\u5efa","text":"\u5728vs\u521b\u5efa\u9879\u76ee\u9875\u9762\u4e2d\u6211\u4eec\u9700\u8981\u9009\u62e9\u8fd9\u4e2a:
\u6ce8\u610f\u8981\u9009\u5e26 .NET Framework
\u5b57\u6837\u7684, \u851a\u84dd\u7684\u5e95\u5c42\u6846\u67b6\u76f8\u5bf9\u4e8e\u76ee\u524d\u7684 .NET
\u5df2\u7ecf\u5f88\u53e4\u8001\u4e86, \u6240\u4ee5\u53ef\u80fd\u4f1a\u88ab\u7a0d\u5fae\u7279\u6b8a\u70b9\u5bf9\u5f85(, \u4e4b\u540e\u5728\u4e3a\u9879\u76ee\u547d\u540d\u7684\u7a97\u53e3\u4e2d\u7684\u9879\u76ee\u6846\u67b6\u8bb0\u5f97\u7cbe\u786e\u9009\u62e9 .NET Framework 4.5.2
.
\u5982\u679c\u4f60\u6ca1\u6709 .NET Framework 4.5.2
\u7684\u9009\u9879\u8bf7\u68c0\u67e5\u662f\u5426\u5b89\u88c5\u4e86\u6b64\u6846\u67b6, \u5e76\u4e14\u4f60\u9009\u62e9\u7684\u662f\u5e26 .NET Framework
\u5b57\u6837\u7684\u7c7b\u5e93\u9879\u76ee.
\u5f53\u4f60\u521b\u5efa\u5b8c\u9879\u76ee\u540e, \u4f60\u4f1a\u5f97\u5230\u4e00\u4e2a\u4ee3\u7801\u6587\u4ef6 Class1.cs
, \u5b83\u770b\u8d77\u6765\u50cf: Class1.cs
using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace MyCelesteMod\n{\n public class Class1\n {\n\n }\n}\n
"},{"location":"arc/basic_env/#_2","title":"\u6dfb\u52a0\u5bf9\u851a\u84dd\u7684\u5f15\u7528","text":"\u56e0\u4e3a\u6211\u4eec\u662f\u851a\u84dd mod \u561b, \u6240\u4ee5\u80af\u5b9a\u5f97\u4f9d\u8d56\u4e00\u4e9b\u851a\u84dd\u7684\u4e1c\u897f, \u5373\u4f9d\u8d56\u4e8e\u851a\u84dd\u7684\u7a0b\u5e8f\u96c6. \u5177\u4f53\u64cd\u4f5c\u6765\u8bf4:
\u5728\u89e3\u51b3\u65b9\u6848\u89c6\u56fe\u7a97\u53e3\u4f60\u7684\u9879\u76ee\u4e0b\u7684\u5f15\u7528
\u4e0a\u53f3\u51fb \u9009\u62e9\u6dfb\u52a0\u5f15\u7528
\u5728\u65b0\u7684\u7a97\u53e3\u9009\u62e9\u5de6\u4fa7\u7684\u6d4f\u89c8
\u70b9\u51fb\u7a97\u53e3\u53f3\u4e0b\u89d2\u7684\u6d4f\u89c8
\u5b8c\u6210\u540e\u5728\u5f39\u51fa\u7684\u6587\u4ef6\u9009\u62e9\u6846\u4e2d\u9009\u62e9\u4ee5\u4e0b\u51e0\u4e2a\u5728\u851a\u84dd\u6839\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6: Celeste.exe
FNA.dll
MMHOOK_Celeste.dll
YamlDotNet.dll
\u5bf9\u4e8e steam \u7248\u851a\u84dd\u7684\u76ee\u5f55\u901a\u5e38\u4f1a\u5728 C:\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste
\u53e6\u5916\u4e3a\u4e86\u4fdd\u8bc1\u4f60\u7684 mod \u7684\u8de8\u5e73\u53f0\u6027, \u4f60\u7684\u5f15\u7528\u5217\u8868\u91cc System
\u5f00\u5934\u7684\u53ea\u80fd\u5305\u542b:
System
System.Configuration
System.Core
System.Data
System.Drawing
System.Runtime.Serialization
System.Security
System.Xml
System.Xml.Linq
\u5982\u679c\u4f60\u7684\u9879\u76ee\u5f15\u7528\u6709\u5176\u4ed6 System
\u5f00\u5934\u7cfb\u5217\u7684\u5f15\u7528, \u5e76\u4e14\u5b83\u4eec\u4e0d\u5728\u4e0a\u8ff0\u5217\u8868\u4e0a, \u4f60\u9700\u8981\u5c06\u5176\u79fb\u9664(\u53f3\u952e->\u79fb\u9664).
"},{"location":"arc/basic_env/#module","title":"\u6dfb\u52a0 Module \u7c7b","text":"ok\u5728\u6211\u4eec\u4e00\u756a\u6298\u817e\u4e0b\u6211\u4eec\u7ec8\u4e8e\u53ef\u4ee5\u5f00\u59cb\u6765\u5199\u4ee3\u7801\u4e86, \u90a3\u4e48\u9996\u5148\u628a\u4f60\u7684 Class1.cs
\u91cd\u547d\u540d\u6210 (\u4f60\u7684mod\u540d)Module.cs
, \u6bd4\u5982\u8fd9\u91cc\u6211\u7684 mod \u540d\u53eb MyCelesteMod
, \u90a3\u4e48\u8fd9\u4e2a\u6587\u4ef6\u6700\u597d\u53eb\u505a MyCelesteModModule.cs
, \u8fd9\u662f\u4e3a\u4e86\u65b9\u4fbf\u65e5\u540e\u5f00\u53d1\u80fd\u4e00\u773c\u8bc6\u522b\u51fa\u8fd9\u662f\u6211\u4eec\u6700\u65e9\u671f\u521b\u5efa\u7684\u90a3\u4e2a\u5173\u952e\u7c7b.
\u5982\u679c\u4f60\u7684 vs \u63d0\u793a\u4f60\u662f\u5426\u91cd\u547d\u540d\u6807\u8bc6\u7b26, \u4f60\u53ef\u4ee5\u9009\u662f, \u8fd9\u6837\u90a3\u4e2a\u6587\u4ef6\u91cc\u7684 Class1
\u7c7b\u540d\u4e5f\u4f1a\u5e2e\u4f60\u91cd\u547d\u540d
\u90a3\u4e48\u540c\u6837\u5730\u5bf9\u8fd9\u4e2a\u6587\u4ef6\u91cc\u7684\u7c7b\u7684\u540d\u5b57\u4e5f\u91cd\u547d\u540d, \u7136\u540e\u6211\u4eec\u8ba9\u8fd9\u4e2a\u7c7b\u7ee7\u627f\u4e8e EverestModule
.
\u5982\u679c\u51fa\u73b0\u4e86\u672a\u547d\u540d\u6807\u8bc6\u7b26\u7684\u9519\u8bef, \u8bf7\u68c0\u67e5\u4f60\u662f\u5426\u6b63\u786e\u5f15\u7528\u4e86 Celeste.exe
\u5e76\u4e14 using \u4e86 Celeste.Mod
\u547d\u540d\u7a7a\u95f4
EverestModule
\u662f\u4e00\u4e2a\u62bd\u8c61\u7c7b ,\u90a3\u4e48\u73b0\u5728\u6211\u4eec\u9700\u8981\u52a0\u5165\u4e24\u4e2a\u65b9\u6cd5\u4ee5\u5b9e\u73b0\u5b83, \u540c\u65f6\u8ba9vs\u95ed\u5634. MyCelesteMod.cs
public override void Load()\n{\n}\n\npublic override void Unload()\n{\n}\n
Load
\u65b9\u6cd5\u4f1a\u5728 Everest \u52a0\u8f7d\u4f60\u7684 Mod \u65f6\u88ab\u8c03\u7528 Unload
\u65b9\u6cd5\u4f1a\u5728 Everest \u5378\u8f7d\u4f60\u7684 Mod \u65f6\u88ab\u8c03\u7528 \u5728\u8fd9\u91cc\u6211\u4eec\u4f1a\u5199\u4e2a\u7c7b\u4f3c Hello world \u7684\u4e1c\u897f, \u5373\u5728 Load
\u91cc\u6253\u5370\u4e9b\u8bdd. em, \u53ef\u80fd\u4e0d\u662f\u4f60\u671f\u671b\u7684 Console.WriteLine
\u800c\u662f Logger.Log
, \u5c31\u50cf\u8fd9\u6837:
Logger.Log(LogLevel.Info, \"MyCelesteMod\", \"Hello World! Hello Everest!\");\n
\u8fd9\u662f\u4e00\u4e2a\u851a\u84dd\u5e95\u5c42\u6846\u67b6 Monocle
\u5f15\u64ce\u91cc\u7684\u4e00\u4e2a\u9759\u6001\u7c7b, \u5728\u4e4b\u540e\u6211\u4eec\u4f1a\u4ecb\u7ecd\u851a\u84dd\u4e2d\u5e38\u89c1\u7c7b\u7684\u4f7f\u7528. \u4e0b\u9762\u662f\u8fd9\u4e2a\u65b9\u6cd5\u7684\u53c2\u6570\u5217\u8868:
\u7b2c\u4e00\u4e2a\u53c2\u6570: \u8fd9\u53e5\u65e5\u5fd7\u7684\u7b49\u7ea7, \u8fd9\u91cc\u6211\u4eec\u5148\u9009 Info
. \u7b2c\u4e8c\u4e2a\u53c2\u6570: \u8fd9\u53e5\u65e5\u5fd7\u7684 Tag
, \u901a\u5e38\u5b83\u662f\u4f60\u7684 Mod \u540d\u5b57 \u7b2c\u4e09\u4e2a\u53c2\u6570: \u6211\u4eec\u5e0c\u671b\u8f93\u51fa\u7684\u8bdd \u90a3\u4e48\u4f60\u73b0\u5728\u7684\u4ee3\u7801\u5e94\u8be5\u662f\u5927\u6982\u8fd9\u6837\u5b50\u7684: MyCelesteMod.cs
using Celeste.Mod;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace MyCelesteMod\n{\n public class MyModModule : EverestModule\n {\n public override void Load()\n {\n Logger.Log(LogLevel.Info, \"MyCelesteMod\", \"Hello World! Hello Everest!\");\n }\n\n public override void Unload()\n {\n\n }\n }\n}\n
\u73b0\u5728, \u6309\u4e0b Ctrl + B
, vs \u5e94\u8be5\u4f1a\u542f\u52a8\u7f16\u8bd1.
\u4f60\u4f1a\u9047\u5230\u4e00\u4e2a\u5173\u4e8e x86
\u4e0e AnyCpu
\u67b6\u6784\u4e0d\u7b26\u7684\u8b66\u544a, \u8fd9\u91cc\u6211\u4eec\u5148\u5ffd\u7565\u5b83\u5e76\u5728\u540e\u9762\u89e3\u51b3.
\u7f16\u8bd1\u5b8c\u6210, \u6211\u4eec\u5c31\u53ef\u4ee5\u627e\u5230\u6211\u4eec\u7f16\u8bd1\u51fa\u6765\u7684\u65b0\u9c9c\u7684\u7a0b\u5e8f\u96c6: <\u4f60\u7684\u9879\u76ee\u540d>/<\u4f60\u7684\u9879\u76ee\u540d>/bin/Debug/<\u4f60\u7684\u9879\u76ee\u540d>.dll
, \u4f60\u7684 vs \u7684\u8f93\u51fa\u7a97\u53e3\u4e5f\u5e94\u8be5\u4f1a\u5199\u4e0a\u8fd9\u4e2a dll \u7684\u5b8c\u6574\u8def\u5f84.
"},{"location":"arc/basic_env/#everest","title":"\u8ba9 Everest \u52a0\u8f7d","text":"\u4ee5\u4e0a\u4e00\u987f\u64cd\u4f5c\u8fc7\u540e\u4f60\u4f1a\u53d1\u73b0\u4f60\u7684\u851a\u84dd\u4ec0\u4e48\u4e5f\u6ca1\u53d1\u751f(\u4e50). \u56e0\u4e3a\u6211\u4eec\u8fd8\u6ca1\u544a\u8bc9\u5b83\u8ba9\u5b83\u52a0\u8f7d\u6211\u4eec\u7684 mod! \u4e3a\u4e86\u8ba9 Everest \u52a0\u8f7d\u6211\u4eec\u7684 mod, \u5176\u4e2d\u4e00\u4e2a\u65b9\u6cd5\u5c31\u662f\u5728\u851a\u84dd\u7684 Mods \u6587\u4ef6\u5939\u91cc\u9762\u65b0\u5efa\u4e00\u4e2a\u6587\u4ef6\u5939, \u5e76\u653e\u5165\u6211\u4eec\u7684 mod \u6587\u4ef6, \u5b83\u7684\u540d\u5b57\u6211\u4eec\u6700\u597d\u5c31\u662f\u9879\u76ee\u540d\u5b57, \u6bd4\u5982 MyCelesteMod
, \u7136\u540e\u5728\u8fd9\u91cc\u5199\u4e00\u4efd everest.yaml
\u6587\u4ef6, \u5b83\u5305\u542b\u6211\u4eec mod \u7684\u4e00\u4e9b\u57fa\u672c\u4fe1\u606f: everest.yaml
- Name: <mod\u540d\u5b57>\nVersion: <\u7248\u672c>\nDLL: <dll\u4f4d\u7f6e>\nDependencies:\n - Name: Everest\n Version: <\u4f9d\u8d56\u7684 everest \u7248\u672c>\n
ok, \u6211\u4eec\u6765\u6162\u6162\u586b\u8fd9\u4e9b\u4e1c\u897f - mod\u540d\u5b57
: \u63a8\u8350\u4e3a\u9879\u76ee\u540d\u6bd4\u5982 MyCelesteMod
- \u7248\u672c
: \u7531\u4e8e\u662f\u5f00\u53d1\u65e9\u671f, \u6240\u4ee5\u7248\u672c\u63a8\u8350\u6307\u5b9a\u4e3a0\u5f00\u5934\u7684 0.1.0
- \u4f9d\u8d56\u7684 everest \u7248\u672c
: \u8fd9\u91cc\u586b\u4f60\u7684 everest \u7248\u672c\u5c31\u884c\u4e86, \u6bd4\u5982\u8bf4\u5982\u679c\u4f60\u662f 3876 \u90a3\u4e48\u8fd9\u91cc\u5e94\u8be5\u5199 1.3876.0
- Dll \u4f4d\u7f6e
: \u6211\u4eec\u5148\u628a\u4e4b\u524d\u7f16\u8bd1\u7684\u65b0\u9c9c(\u53ef\u80fd\u73b0\u5728\u4e0d\u548b\u65b0\u9c9c\u4e86)\u7684 dll \u590d\u5236\u5230\u8fd9\u4e2a\u6587\u4ef6\u5939\u6765, \u6ca1\u8bb0\u9519\u7684\u8bdd\u5728\u8fd9\u91cc\u53eb MyCelesteMod.dll
, ok, everest.yaml
\u91cc\u8981\u5199\u7684 dll \u4f4d\u7f6e\u662f\u76f8\u5bf9\u4e8e\u8fd9\u4e2a\u6587\u4ef6\u5939\u7684, \u6211\u4eec\u5c31\u653e\u5728\u5b83\u91cc\u9762\u7b2c\u4e00\u5c42, \u6240\u4ee5\u6211\u4eec\u76f4\u63a5\u5199 MyCelesteMod.dll
\u5c31\u884c\u4e86. \u73b0\u5728\u4f60\u7684\u90a3\u4e2a\u6587\u4ef6\u5939\u73b0\u5728\u53ef\u80fd\u957f\u8fd9\u4e2a\u6837\u5b50:
MyCelesteMod MyCelesteMod.dll everest.yaml everest.yaml\u53ef\u80fd\u957f\u8fd9\u4e2a\u6837\u5b50: everest.yaml
- Name: MyCelesteMod\nVersion: 0.1.0\nDLL: MyCelesteMod.dll\nDependencies:\n - Name: Everest\n Version: 1.3876.0\n
ok, \u5728\u542f\u52a8\u4e4b\u524d\u6211\u4eec\u8fd8\u8981\u5e72\u6700\u540e\u4e00\u4ef6\u5c0f\u4e8b, \u5c31\u662f\u6211\u4eec\u7684\u65e5\u5fd7, \u5b83\u6253\u5370\u5728\u6587\u4ef6\u91cc\u540c\u65f6\u4e5f\u6253\u5370\u5728\u63a7\u5236\u53f0\u91cc, \u65e5\u5fd7\u6587\u4ef6\u7ffb\u9605\u6bd4\u8f83\u9ebb\u70e6, \u6240\u4ee5\u4e3a\u4e86\u65e5\u540e\u65b9\u4fbf\u8c03\u8bd5, \u6211\u4eec\u8fd8\u662f\u5148\u8ba9\u851a\u84dd\u542f\u52a8\u7684\u540c\u65f6\u542f\u52a8\u4e00\u4e2a\u63a7\u5236\u53f0\u597d\u4e00\u70b9. Everest \u5df2\u7ecf\u4e3a\u6211\u4eec\u505a\u4e86\u8fd9\u4ef6\u4e8b\u4e86, \u6211\u4eec\u8981\u505a\u7684\u53ea\u662f\u5728\u851a\u84ddexe\u540c\u76ee\u5f55\u4e0b\u627e\u5230everest-launch.txt
, \u6ca1\u627e\u5230\u4e5f\u6ca1\u5173\u7cfb, \u65b0\u5efa\u4e00\u4e2a\u5c31\u53ef\u4ee5\u4e86, \u7136\u540e\u5728\u91cc\u9762\u5199\u4e0a--console
, \u662f\u7684\u5c31\u8fd9\u4e00\u5c0f\u70b9\u4e1c\u897f, \u7136\u540e\u6211\u4eec\u4fdd\u5b58, \u542f\u52a8\u851a\u84dd!
\u542f\u52a8\u540e\u4f60\u5e94\u8be5\u4f1a\u540c\u65f6\u770b\u5230\u4e00\u4e2a\u63a7\u5236\u53f0\u7a97\u53e3, \u626b\u89c6\u4e00\u4e0b: console output
[MonoMod] [AutoPatch] Patch pass\n[MonoMod] [AutoPatch] PatchRefs pass\n[MonoMod] [PostProcessor] PostProcessor pass #1\n[MonoMod] [Write] Writing modded module into output file.\n(07/05/2023 23:22:16) [Everest] [Info] [MyCelesteMod] Hello World! Hello Everest!\n(07/05/2023 23:22:16) [Everest] [Info] [core] Module MyCelesteMod 0.1.0 registered.\n(07/05/2023 23:22:16) [Everest] [Info] [loader] Loading mods with unsatisfied optional dependencies (if any)\nFNA3D Driver: D3D11\nD3D11 Adapter: Intel(R) UHD Graphics 630\nBEGIN LOAD\n- GFX LOAD: 139ms\n- MTN LOAD: 9ms\nWINDOW-1600x900\nGAME DISPLAYED (in 291ms)\n- AUDIO LOAD: 454ms\n- GFX DATA LOAD: 75ms\n
\u5927\u6982\u5728\u5982\u4e0a\u7684\u4f4d\u7f6e\u9644\u8fd1(\u5728\u8fd9\u91cc\u662f\u7b2c5\u884c)\u4f60\u5c31\u80fd\u627e\u5230\u4f60\u7684 Hello world \u4e86, \u81f3\u6b64\u57fa\u672c\u73af\u5883\u914d\u7f6e\u7ed3\u675f."},{"location":"arc/sdk-styled-proj/","title":"\u504f\u597d - sdk-styled csproj","text":""},{"location":"arc/sdk-styled-proj/#sdk-style-csproj","title":"Sdk-style csproj","text":"\u73b0\u5728\u6253\u5f00\u4f60\u7684\u9879\u76ee\u76ee\u5f55\u4e2d\u7684 .csproj
\u6587\u4ef6(\u901a\u5e38\u4e5f\u4f1a\u88ab\u53eb\u4f5c*\u9879\u76ee\u6587\u4ef6*), \u5b83\u7528\u4e8e\u7ec4\u7ec7\u63cf\u8ff0\u4f60\u7684\u9879\u76ee\u662f\u4ec0\u4e48\u6837\u5b50\u7684, \u4f60\u53ef\u80fd\u4f1a\u53d1\u73b0\u975e\u5e38\u7684\u6742\u4e71\u4e0d\u53ef\u8bfb, \u5c31\u50cf:
.csproj<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n <PropertyGroup>\n <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n <ProjectGuid>{100E625E-04C6-434F-865C-3E6E50A379B5}</ProjectGuid>\n <OutputType>Library</OutputType>\n <AppDesignerFolder>Properties</AppDesignerFolder>\n <RootNamespace>MyCelesteMod</RootNamespace>\n <AssemblyName>MyCelesteMod</AssemblyName>\n <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>\n <FileAlignment>512</FileAlignment>\n <Deterministic>true</Deterministic>\n </PropertyGroup>\n <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n <DebugSymbols>true</DebugSymbols>\n <DebugType>full</DebugType>\n <Optimize>false</Optimize>\n <OutputPath>bin\\Debug\\</OutputPath>\n <DefineConstants>DEBUG;TRACE</DefineConstants>\n <ErrorReport>prompt</ErrorReport>\n <WarningLevel>4</WarningLevel>\n </PropertyGroup>\n <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n <DebugType>pdbonly</DebugType>\n <Optimize>true</Optimize>\n <OutputPath>bin\\Release\\</OutputPath>\n <DefineConstants>TRACE</DefineConstants>\n <ErrorReport>prompt</ErrorReport>\n <WarningLevel>4</WarningLevel>\n </PropertyGroup>\n <ItemGroup>\n <Reference Include=\"Celeste\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\Celeste.exe</HintPath>\n </Reference>\n <Reference Include=\"FNA\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\FNA.dll</HintPath>\n </Reference>\n <Reference Include=\"MMHOOK_Celeste\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\MMHOOK_Celeste.dll</HintPath>\n </Reference>\n <Reference Include=\"YamlDotNet\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\YamlDotNet.dll</HintPath>\n </Reference>\n <Reference Include=\"System\" />\n <Reference Include=\"System.Core\" />\n <Reference Include=\"System.Xml.Linq\" />\n <Reference Include=\"Microsoft.CSharp\" />\n <Reference Include=\"System.Xml\" />\n </ItemGroup>\n <ItemGroup>\n <Compile Include=\"MyModModule.cs\" />\n <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n </ItemGroup>\n <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n</Project>\n
Note
\u5bf9\u4e8e\u6b64\u90e8\u5206\u7684\u5185\u5bb9\u4f60\u53ef\u80fd\u9700\u8981\u9605\u8bfb\u4e86\u89e3\u4e00\u4e0b XML
\u683c\u5f0f\u6587\u4ef6
\u5b9e\u9645\u4e0a\u5bf9\u4e8e\u6211\u4eec\u771f\u6b63\u7ecf\u5e38\u4fee\u6539\u7684\u5c5e\u6027\u53ea\u6709\u4e0a\u9762\u6807\u4eae\u7684\u884c, \u90a3\u4e48\u5982\u679c\u8fd9\u65f6\u5019\u4f7f\u7528 Sdk-style csproj
\u4f1a\u597d\u5f88\u591a, \u5b83\u770b\u4e0a\u53bb\u662f\u8fd9\u6837\u7684:
Sdk-style csproj<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <OutputType>Library</OutputType>\n <RootNamespace>MyCelesteMod</RootNamespace>\n <AssemblyName>MyCelesteMod</AssemblyName>\n <TargetFramework>net452</TargetFramework>\n </PropertyGroup>\n\n <ItemGroup>\n <Reference Include=\"Celeste\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\Celeste.exe</HintPath>\n </Reference>\n <Reference Include=\"FNA\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\FNA.dll</HintPath>\n </Reference>\n <Reference Include=\"MMHOOK_Celeste\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\MMHOOK_Celeste.dll</HintPath>\n </Reference>\n <Reference Include=\"YamlDotNet\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\YamlDotNet.dll</HintPath>\n </Reference>\n <Reference Include=\"System\" />\n <Reference Include=\"System.Core\" />\n <Reference Include=\"System.Xml.Linq\" />\n <Reference Include=\"Microsoft.CSharp\" />\n <Reference Include=\"System.Xml\" />\n </ItemGroup>\n\n</Project>\n
\u4f60\u4f1a\u53d1\u73b0\u5176\u5b9e\u8fd9\u91cc\u53ea\u7559\u4e0b\u4e86\u6211\u4eec\u4e0a\u9762\u6807\u9ec4\u7684\u4e1c\u897f, \u662f\u7684, \u8fd9\u5c31\u662f Sdk-style csproj
\u7684\u4f18\u70b9. \u8fc1\u79fb\u81f3 Sdk-style csproj
\u975e\u5e38\u7b80\u5355, \u4f60\u53ea\u9700\u8981:
\u5220\u9664 PropertyGroup
\u548c ItemGroup
\u53ca\u65c1\u8fb9\u7684\u975e\u6807\u9ec4\u8282\u70b9 \u5220\u9664 Project
\u8282\u70b9\u4e0b\u7684\u4e24\u4e2a Import
\u5220\u9664 Project
\u8282\u70b9\u7684\u6240\u6709\u5c5e\u6027 \u91cd\u65b0\u5728 Project
\u8282\u70b9\u4e0a\u52a0\u5165\u5c5e\u6027: Sdk = \"Microsoft.NET.Sdk\"
TargetFrameworkVersion
\u66f4\u6539\u4e3a\u65b0\u7248\u7684 TargetFramework
, v4.5.2
\u66f4\u6539\u4e3a net452
Note
\u4e0d\u7528\u62c5\u5fc3\u5220\u6389\u8fd9\u4e48\u591a\u4e1c\u897f\u4f1a\u51fa\u73b0\u95ee\u9898, \u5b9e\u9645\u4e0a\u6211\u4eec\u5220\u6389\u7684\u4e1c\u897f\u53ea\u662f\u5408\u5e76\u5165 Sdk = \"Microsoft.NET.Sdk\"
\u8fd9\u4e00\u53e5\u4e86\u800c\u5df2
\u8fd9\u4e2a\u65f6\u5019\u6574\u4e2a\u6587\u4ef6\u6e05\u6670\u53ef\u8bfb:
\u6839\u8282\u70b9\u7684 Project
\u4e0b\u6302\u8f7d\u7740 PropertyGroup
\u4ee5\u53ca ItemGroup
, PropertyGroup
\u63cf\u8ff0\u4e86\u6211\u4eec\u9879\u76ee\u7684\u4e00\u4e9b\u901a\u7528\u5c5e\u6027, \u6bd4\u5982\u8f93\u51fa\u7c7b\u578b, \u547d\u540d\u7a7a\u95f4, \u7a0b\u5e8f\u96c6\u6635\u79f0\u4ee5\u53ca\u9879\u76ee\u6846\u67b6\u7248\u672c, ItemGroup
\u5219\u63cf\u8ff0\u4e86\u6211\u4eec\u9879\u76ee\u4e2d\u7684\u4e00\u4e9b\u5f15\u7528\u7b49. \u5728\u8fd9\u91cc\u63d0\u53ca\u8fd9\u4e2a\u662f\u56e0\u4e3a\u5728\u540e\u9762\u90e8\u5206\u6211\u4eec\u4f1a\u9700\u8981\u4fee\u6539 .csproj
\u6587\u4ef6, \u901a\u8fc7\u5bf9\u6bd4\u4f60\u53ef\u4ee5\u53d1\u73b0\u8fd9\u4e24\u4e2a xml \u6587\u4ef6\u90fd\u6709 PropertyGroup
\u548c ItemGroup
\u8282\u70b9 (\u5982\u679c\u6709\u591a\u4e2a\u8282\u70b9\u7684\u8bdd, \u4efb\u610f\u4e00\u4e2a\u90fd\u884c), \u6240\u4ee5\u6211\u4eec\u4e4b\u540e\u5bf9\u9879\u76ee\u6587\u4ef6\u7684\u4fee\u6539\u7684\u63cf\u8ff0\u90fd\u4f1a\u57fa\u4e8e\u8fd9\u4e24\u4e2a\u8282\u70b9.
Warning
\u8bb0\u5f97\u5220\u9664 Properties
\u6587\u4ef6\u5939\u91cc\u7684 cs \u6587\u4ef6, \u5b83\u53ef\u80fd\u4f1a\u4e0e sdk-styled csproj \u81ea\u52a8\u751f\u6210\u7684\u6587\u4ef6\u76f8\u51b2\u7a81
"},{"location":"begin/basic_env/","title":"\u57fa\u7840\u73af\u5883\u914d\u7f6e","text":"Note
\u672c\u8282\u5185\u5bb9\u7531\u624b\u52a8\u914d\u7f6e\u91cd\u5199\u4e3a\u901a\u8fc7\u6a21\u677f\u914d\u7f6e, \u65e7\u7248\u4f60\u53ef\u4ee5\u5230\u5f52\u6863-\u57fa\u7840\u73af\u5883\u914d\u7f6e\u4e2d\u627e\u5230(\u4e0d\u63a8\u8350)
"},{"location":"begin/basic_env/#celeste","title":"Celeste","text":"Note
\u5982\u679c\u4f60\u4e0d\u662f Windows \u7528\u6237\u7684\u8bdd\u8fd9\u4e00\u6b65\u4f60\u53ef\u4ee5\u76f4\u63a5\u8df3\u8fc7.
Info
\u5728 Everest Core \u7248\u672c\u540e(Stable \u7248\u672c\u53f7\u5927\u4e8e 4465)\u5f3a\u5236\u5207\u6362\u4e3a\u4e86 FNA \u7248\u672c, \u5982\u679c\u4f60\u5df2\u662f Core \u7248\u672c\u4f60\u53ef\u4ee5\u8df3\u8fc7\u8fd9\u4e00\u6b65.
Everest \u9700\u6c42\u6211\u4eec\u4f7f\u7528 FNA \u7248\u672c\u7684\u851a\u84dd, \u800c Linux \u548c MacOS \u4e0a\u7684\u851a\u84dd\u5df2\u7ecf\u5c31\u662f FNA \u7248\u672c\u4e86, \u800c\u5728 Windows \u4e0a\u5219\u662f XNA \u7248\u672c, \u6240\u4ee5\u6211\u4eec\u9700\u8981\u4e00\u4e9b\u65b9\u6cd5\u5207\u6362\u5230 FNA \u7248\u672c:
\u5728 Steam \u4e0a: \u5e93->Celeste, \u53f3\u952e\u83dc\u5355\u5c5e\u6027->\u6d4b\u8bd5\u7248->Opengl \u5728 itch \u4e0a: \u91cd\u65b0\u4e0b\u8f7d\u4e00\u4e2a Celeste Windows OpenGL
\u7248\u672c \u5728 Epic \u4e0a: \u5df2\u7ecf\u662f FNA \u7248\u672c\u4e86 Note
Everest \u4f1a\u5728\u8fd0\u884c\u65f6\u5c06\u4f60\u4ee5 FNA \u7248\u672c\u5236\u4f5c\u7684 mod \u91cd\u94fe\u63a5\u4e3a XNA, \u6240\u4ee5\u4f60\u4e0d\u662f\u5f88\u9700\u8981\u5728\u610f\u8fd9\u4fe9\u7684\u5dee\u8ddd \u6ce8\u610f\u66f4\u6362\u7248\u672c\u540e\u4f1a\u53d8\u56de\u539f\u7248, \u4f60\u9700\u8981\u91cd\u65b0\u5b89\u88c5 Everest
"},{"location":"begin/basic_env/#c","title":"C# \u7f16\u7a0b\u80fd\u529b \u4e0e \u5f00\u53d1\u73af\u5883","text":"\u56e0\u4e3a\u6211\u4eec\u662f Code Mod, \u55ef, \u90a3\u4e48\u5199\u4e00\u4e9b\u4ee3\u7801\u662f\u5fc5\u4e0d\u53ef\u5c11\u7684, \u851a\u84dd\u662f\u4f7f\u7528 C#
\u57fa\u4e8e .NET Framework 4.5.2
\u6765\u5236\u4f5c\u7684, \u90a3\u4e48\u5b66\u4e60 C#
\u5f53\u7136\u662f\u5fc5\u4e0d\u53ef\u5c11\u7684.
Info
\u5728 Everest Core \u7248\u672c\u4e0a\u851a\u84dd\u88ab\u8fc1\u79fb\u5230\u4e86 .NET 7
\u4e0a, \u4e0d\u8fc7\u57fa\u4e8e\u65e7\u6846\u67b6\u7684 mod \u4f1a\u5c3d\u53ef\u80fd\u5730\u88ab Everest \u81ea\u52a8\u8f6c\u6362\u4e3a\u57fa\u4e8e\u65b0\u6846\u67b6\u7684 mod.
Info
\u7406\u8bba\u4e0a\u6240\u6709 .NET \u7cfb\u8bed\u8a00\u6bd4\u5982 VB.NET
F#
\u90fd\u53ef\u4ee5, \u4e0d\u8fc7\u4e3a\u4e86\u65b9\u4fbf\u8d77\u89c1\u6211\u4eec\u8fd8\u662f\u4f7f\u7528 C#.
\u597d\u5427\u8fd9\u53e5\u8bdd\u53ef\u80fd\u8bf4\u7684\u592a\u5e73\u6de1\u4e86(, \u6bd5\u7adf\u5927\u90e8\u5206\u851a\u6279\u851a\u84dd mod \u7231\u597d\u8005\u5c31\u662f\u88ab\u8fd9\u4e00\u6b65\u5361\u4f4f\u7684, \u90a3\u4e48\u8fd9\u91cc...\u53ea\u80fd\u7ed9\u4f60\u63a8\u8350\u51e0\u4e2a\u5b66\u4e60\u6e20\u9053\u4e86, \u6bd5\u7adf\u5728\u8fd9\u91cc\u6ca1\u5fc5\u8981\u8ba9\u8fd9\u4e2a\u6559\u7a0b\u8fc7\u4e8e\u5168\u80fd.
\u89c6\u9891: Bilibili - \u4e11\u840c\u6c14\u8d28\u72d7 - \u3010C#\u96f6\u57fa\u7840\u5165\u95e8\u6559\u7a0b Visual Studio 2022\u3011\u4eba\u751f\u4f4e\u8c37\u6765\u5b66C# (\u5168p, \u7a0d\u5fae\u4e0d\u5168) \u89c6\u9891: Bilibili - C#\u4ece\u5165\u95e8\u5230\u7cbe\u901a\uff08\u7b2c5\u7248\uff09 (1-71p, 109-132p) \u89c6\u9891: Bilibili - \u5218\u94c1\u731b - C#\u8bed\u8a00\u5165\u95e8\u8be6\u89e3-\u7b2c1\u5b63-\u526a\u8f91\u7248-\u516833\u8bfe-\u5206154\u96c6 (1-152p) \u7f51\u7ad9: Runnob - C# \u6559\u7a0b \u7f51\u7ad9: w3schools - C# \u6559\u7a0b (\u82f1\u6587) \u4e66\u7c4d: C#\u5165\u95e8\u7ecf\u5178-\u7b2c7\u7248-C# 6.0 Info
\u5982\u679c\u4f60\u6ca1\u6709\u80fd\u529b\u652f\u6301\u6b63\u7248\u4e66\u7c4d\u7684\u8bdd, \u4f60\u53ef\u4ee5\u5230\u4e00\u4e9b C# \u5f00\u53d1\u8005\u7fa4\u5185\u5bfb\u627e\u5b83\u7684\u7535\u5b50\u975e\u6b63\u7248(\u6bd4\u5982\u89c6\u9891 1.
up \u7684\u7fa4\u5185) \u4e0a\u9762\u51e0\u4e2a\u6211\u66f4\u52a0\u63a8\u8350\u7684\u662f 1.
\u548c 3.
\u501f\u7528 4.
\u7684\u76ee\u5f55, \u786e\u4fdd\u4f60\u5bf9\u4e0b\u9762\u8fd9\u4e9b\u6982\u5ff5(\u753b \u00d7 \u7684\u6682\u65f6\u5728\u851a\u84dd Code Mod \u4e2d\u7528\u4e0d\u5230)\u6709\u8db3\u591f\u6e05\u6670\u7684\u4e86\u89e3\u5728\u5f00\u59cb\u4f60\u7684\u851a\u84dd Code Mod \u4e4b\u65c5\u4e4b\u524d:
\u76f8\u4fe1\u5728\u4e0a\u9762\u7684\u6559\u7a0b\u4e2d\u4f60\u5e94\u8be5\u5df2\u7ecf\u88ab\u63a8\u8350\u4e86\u4e00\u4e9b\u7f16\u8f91\u5668 / IDE, \u90a3\u4e48\u5728\u672c\u6559\u7a0b\u4e2d\u6211\u4e2a\u4eba\u4f1a\u4e3a\u4e86\u65b9\u4fbf\u4ec5\u5728 Windows
\u4e0a\u4f7f\u7528 Visual Studio
, \u5f53\u7136\u4e0d\u4fdd\u8bc1\u5728\u5176\u4ed6\u5730\u65b9\u4f1a\u9047\u5230\u5947\u5947\u602a\u602a\u7684\u95ee\u9898. _(:\u0437\u300d\u2220)_
"},{"location":"begin/basic_env/#_2","title":"\u901a\u8fc7\u6a21\u677f\u521b\u5efa\u9879\u76ee","text":"Info
\u5728\u851a\u84dd\u56fd\u5916\u793e\u533a\u6d41\u884c\u7740\u53e6\u4e00\u4e2a mod \u9879\u76ee\u6a21\u677f, \u4e0d\u8fc7\u6211\u4e2a\u4eba\u4e0d\u592a\u559c\u6b22\u5b83, \u4e0d\u8fc7\u4f60\u9700\u8981\u7684\u8bdd\u8fd9\u662f Github \u4e3b\u9875 \u6240\u4ee5\u8fd9\u91cc\u4e3b\u8981\u4f7f\u7528\u6211\u4e2a\u4eba\u5236\u4f5c\u4e5f\u662f\u4e2a\u4eba\u6700\u5e38\u7528\u7684\u4e00\u4e2a.
_(:\u0437\u300d\u2220)_ \u6839\u636e\u4e00\u4e9b\u53cd\u9988\u6211\u4eec\u53d1\u73b0\u65e7\u7684\u624b\u52a8\u914d\u7f6e\u73af\u5883\u7684\u65b9\u5f0f\u975e\u5e38\u7684\u590d\u6742\u96be\u64cd\u4f5c( \u6240\u4ee5\u5462\u8fd9\u91cc\u5c31\u63a8\u8350\u4e00\u79cd\u65b0\u7684\u914d\u7f6e\u73af\u5883\u7684\u65b9\u5f0f - \u4f7f\u7528\u6a21\u677f \u8003\u8651\u5230 nuget \u5b89\u88c5\u6a21\u677f\u4e5f\u9700\u8981\u4e00\u5b9a\u7684\u547d\u4ee4\u884c\u57fa\u7840... \u6240\u4ee5\u8fd9\u91cc\u8003\u8651\u63d0\u4f9b\u76f4\u63a5\u7684\u4e0b\u8f7d\u94fe\u63a5, \u6216\u8005\u4f60\u4e5f\u53ef\u4ee5\u9009\u62e9\u4f7f\u7528 dotnet cli
\u4ece nuget \u4e0a\u7684\u6a21\u677f\u5b89\u88c5:
Note
\u4f60\u53ef\u80fd\u8fd8\u9700\u8981\u5b89\u88c5 .NET 8 SDK
\u6765\u4f7f\u7528\u8be5\u6a21\u677f, \u4f60\u53ef\u4ee5\u5728\u8fd9\u91cc\u627e\u5230\u5b83
\u4f7f\u7528 dotnet cli \u4ece\u6a21\u677f\u65b0\u5efa\u9879\u76ee \u9996\u5148\u5728\u4e00\u4e2a\u4f60\u559c\u6b22\u7684\u4f4d\u7f6e\u653e\u7f6e\u4f60\u7684\u9879\u76ee\u6587\u4ef6\u5939, \u540d\u5b57\u5373\u4e3a\u4f60\u7684\u9879\u76ee\u540d, \u4f8b\u5982 MyCelesteMod
:
mkdir MyCelesteMod\ncd MyCelesteMod\n
\u7136\u540e\u5728\u6b64\u4f4d\u7f6e\u5b89\u88c5 nuget \u4e0a\u6211\u7684 mod \u6a21\u677f(\u5982\u679c\u4f60\u6ca1\u6709\u5b89\u88c5\u7684\u8bdd): dotnet new install Saladim.CelesteModTemplate\n
\u7136\u540e\u4f60\u5c31\u80fd\u4f7f\u7528\u8fd9\u6761\u6307\u4ee4\u76f4\u63a5\u521b\u5efa\u9879\u76ee\u4e86: dotnet new sapcelestemod\n
\u540d\u5b57\u5373\u4e3a\u4e0a\u5c42\u6587\u4ef6\u5939\u540d, \u6216\u8005\u4f60\u53ef\u4ee5\u4f7f\u7528 -n
\u53c2\u6570\u91cd\u5199\u9879\u76ee\u540d\u5b57: dotnet new sapcelestemod -n MySuperCelesteMod\n
\u6a21\u677f\u76ee\u524d\u9ed8\u8ba4\u4e0d\u4f1a\u521b\u5efa\u9488\u5bf9 Everest Core \u7684 Code Mod, \u5982\u679c\u4f60\u9700\u8981\u7684\u8bdd\u4f60\u53ef\u4ee5\u4f20\u5165 --core-only true
\u53c2\u6570: dotnet new sapcelestemod --core-only true\n
\u5b8c\u6210\u540e\u4f7f\u7528\u4f60\u559c\u6b22\u7684\u7f16\u8f91\u5668\u6253\u5f00\u9879\u76ee(\u5bf9\u4e8e vs \u76f4\u63a5\u6253\u5f00 .csproj \u6587\u4ef6), \u90a3\u4e48\u6309\u7406\u6765\u8bf4\u4f60\u4f1a\u770b\u5230\u8fd9\u51e0\u4e2a\u6587\u4ef6:
CelesteMod.props CelesteMod.targets Common.props MyCelesteModModule.cs MyCelesteMod.csproj \u4ee5\u53ca\u4f60\u7684\u9879\u76ee, \u5b83\u7684\u540d\u5b57\u662f MyCelesteMod
, \u4e0d\u540c\u4e8e\u65e7\u7684\u65b9\u6cd5, \u5728\u8fd9\u91cc\u4f60\u7684\u914d\u7f6e\u8fc7\u7a0b\u5f88\u7b80\u5355:
\u9996\u5148\u6253\u5f00 Common.props
, \u5c06\u91cc\u9762\u7684 CelesteRootPath
\u5185\u7684\u5185\u5bb9\u6539\u6210\u4f60\u7684\u851a\u84dd\u5b89\u88c5\u4f4d\u7f6e <Project>\n <PropertyGroup>\n <CelesteRootPath>C:\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste</CelesteRootPath>\n <CommonCelesteUsings>true</CommonCelesteUsings>\n <CommonCelesteReferences>true</CommonCelesteReferences>\n <ModAssetsFolderName>ModFolder</ModAssetsFolderName>\n </PropertyGroup>\n</Project>\n
\u73b0\u5728\u4f60\u53ef\u4ee5\u6309\u4e0b Ctrl+B
\u6216\u8005\u624b\u52a8\u70b9\u51fb \u751f\u6210->\u751f\u6210\u89e3\u51b3\u65b9\u6848
, \u5982\u679c\u4f60\u5728\u4f60\u7684 vs \u8f93\u51fa\u91cc\u9762\u770b\u5230\u4e86\u7c7b\u4f3c\u8fd9\u4e24\u53e5:
1>MyCelesteMod -> D:\\User\\temp\\cm\\bin\\x86\\Debug\\net452\\MyCelesteMod.dll\n1>MyCelesteMod -> C:/Program Files (x86)/Steam/steamapps/common/Celeste/Mods/MyCelesteMod_copy/MyCelesteMod.dll\n
\u5e76\u4e14\u4f60\u5728\u4f60\u7684\u851a\u84dd Mod \u76ee\u5f55\u4e0b\u627e\u5230\u4e86\u8fd9\u4e2a\u88ab\u521b\u5efa\u7684\u76ee\u5f55, \u90a3\u4e48\u4f60\u7684\u73af\u5883\u5c31\u7b97\u662f\u914d\u5b8c\u4e86, \u5982\u679c\u4f60\u5f88\u611f\u5174\u8da3\u8fd9\u4e4b\u4e2d\u53d1\u751f\u4e86\u4ec0\u4e48, \u8981\u5f15\u7528\u54ea\u4e9b\u7a0b\u5e8f\u96c6, \u8fd9\u4e2a\u6a21\u677f\u80cc\u540e\u5e72\u4e86\u4ec0\u4e48, \u4f60\u53ef\u4ee5\u53bb\u770b\u90a3\u590d\u6742\u7684\u65e7\u7684\u914d\u7f6e\u65b9\u6cd5.
Note
\u8fd9\u4e2a\u6a21\u677f\u4f7f\u7528 msbuild
\u5e2e\u52a9\u4e86\u4f60\u5f88\u591a\u4e8b! \u6bd4\u5982\u5f53\u4f60\u7f16\u8bd1\u5b8c\u9879\u76ee\u4e4b\u540e\u5b83\u4f1a\u590d\u5236\u7f16\u8bd1\u7ed3\u679c\u5230\u9879\u76ee\u76ee\u5f55\u7684 ModFolder
\u76ee\u5f55\u4e0b, \u7136\u540e\u5c06\u6574\u4e2a ModFolder
\u590d\u5236\u5230\u851a\u84dd\u7684 Mods\\{\u4f60\u7684mod\u540d}_copy
\u6587\u4ef6\u5939\u4e0b! \u6240\u4ee5\u5f53\u6211\u4eec\u9700\u8981\u66f4\u6539\u4e00\u4e9b\u6bd4\u5982\u8bf4 loenn \u7684\u914d\u7f6e\u6587\u4ef6, everest.yaml
\u7684\u5185\u5bb9, \u4f60\u7684\u6d4b\u8bd5\u5730\u56fe\u7b49\u65f6, \u4f60\u53ea\u9700\u8981\u7b80\u5355\u5730\u91cd\u65b0\u7f16\u8bd1\u4e00\u904d\u9879\u76ee, \u7136\u540e\u7b49\u5f85\u6a21\u677f\u6765\u5e2e\u4f60\u505a\u5269\u4e0b\u7684\u6d3b!
"},{"location":"begin/basic_env/#_3","title":"\u66f4\u6539\u7ec6\u8282","text":"\u901a\u8fc7\u6a21\u677f\u7684\u8bdd\u4f9d\u7136\u6709\u4e9b\u4e1c\u897f\u9700\u8981\u81ea\u884c\u66f4\u6539, \u6bd4\u5982\u8fd9\u4e2a Mod \u7684\u540d\u5b57. \u66f4\u6539 Mod \u7684\u540d\u5b57\u5f88\u7b80\u5355, \u4f60\u53ea\u9700\u8981\u7b80\u5355\u5730\u5728 vs \u91cc\u91cd\u547d\u540d\u9879\u76ee\u7684\u540d\u5b57 \u6bd4\u5982\u6211\u60f3\u53eb\u505a MyAwesomeMod
, \u90a3\u4e48\u4f60\u53ef\u4ee5\u901a\u8fc7\u8fd9\u6837: \u987a\u4fbf\u522b\u5fd8\u4e86\u628a\u7c7b\u4f3c MyCelesteModModule.cs
\u7684\u6587\u4ef6\u540d\u4e5f\u6539\u6210\u7c7b\u4f3c MyAwesomeModModule.cs
, \u4ee5\u53ca\u6539\u540d\u540e\u6e05\u7406\u4e00\u4e0b ModFolder \u4e0b\u9762\u53ef\u80fd\u6709\u7684\u4e00\u4e9b\u4ee5\u8fc7\u53bb\u540d\u5b57\u547d\u540d\u7684 .dll \u548c .pdb \u6587\u4ef6!
"},{"location":"begin/basic_env/#module","title":"Module \u7c7b","text":"\u5c31\u50cf\u6211\u4eec\u7684\u7ecf\u5178\u7684\u63a7\u5236\u53f0 C# \u5e94\u7528\u7a0b\u5e8f\u4e00\u6837\u6709\u4e2a Main
\u65b9\u6cd5, \u6211\u4eec\u7684\u851a\u84dd Mod \u4e5f\u6709\u4e00\u4e2a\u7c7b\u4f3c\u7684\u4e1c\u897f, \u90a3\u5c31\u662f Everest \u63d0\u4f9b\u7ed9\u6211\u4eec\u7684 EverestModule
\u7c7b. \u90a3\u4e48, \u73b0\u5728\u6253\u5f00\u4f60\u7684 MyCelesteModModule.cs
\u90a3\u4e2a\u6587\u4ef6, \u4f60\u5e94\u8be5\u4f1a\u770b\u5230\u7c7b\u4f3c\u7ed3\u6784\u8fd9\u6837\u7684\u4ee3\u7801:
namespace MyCelesteMod;\n\npublic class MyCelesteModModule : EverestModule\n{\n public override void Load()\n {\n\n }\n\n public override void Unload()\n {\n }\n}\n
\u5728\u5f00\u5934\u6211\u4eec\u58f0\u660e\u4e86\u547d\u540d\u7a7a\u95f4, \u63a5\u4e0b\u6765\u6211\u4eec\u58f0\u660e\u4e86\u4e00\u4e2a\u7c7b, \u7136\u540e\u8ba9\u5b83\u7ee7\u627f\u4e8e EverestModule
, \u6ce8\u610f\u8fd9\u4e2a\u7c7b\u662f\u62bd\u8c61\u7684, \u5b83\u8981\u6c42\u6211\u4eec\u5b9e\u73b0\u7684\u4e24\u4e2a\u65b9\u6cd5\u5206\u522b\u4e3a Load
\u4e0e Unload
. \u8fd9\u4e24\u4e2a\u65b9\u6cd5\u5f88\u7b80\u5355: Load
\u65b9\u6cd5\u5728\u4f60\u7684 mod \u88ab\u52a0\u8f7d\u65f6\u8c03\u7528. Unload
\u65b9\u6cd5\u5728\u4f60\u7684 mod \u88ab\u5378\u8f7d\u65f6\u8c03\u7528. \u901a\u5e38\u6211\u4eec\u4f1a\u5728 Load
\u65b9\u6cd5\u91cc\u52a0\u8f7d\u6211\u4eec\u9700\u8981\u7684\u8d44\u6e90, \u8fdb\u884c\u9002\u5f53\u7684\u521d\u59cb\u5316, \u5728 Unload
\u65b9\u6cd5\u91cc\u91ca\u653e\u6211\u4eec\u7684\u8d44\u6e90. \u5728\u8fd9\u91cc\u4e3a\u4e86\u660e\u663e\u53ef\u89c1, \u6211\u4eec\u5728 Load
\u65b9\u6cd5\u91cc\u901a\u8fc7\u4e00\u4e2a\u851a\u84dd\u4e2d\u7684\u7c7b Logger
\u6253\u5370\u51fa\u4e86\u4e00\u53e5 \"Hello World\".
\u5982\u679c\u4f60\u597d\u5947 Logger.Log
\u8fd9\u4e2a\u65b9\u6cd5\u4f60\u53ef\u4ee5\u5c55\u5f00\u6765\u4e86\u89e3 Logger
\u662f\u4e00\u4e2a\u851a\u84dd\u5e95\u5c42\u5f15\u64ce Monocle
\u7684\u4e00\u4e2a\u5de5\u5177\u7c7b, \u5b83\u5e2e\u52a9\u4f60\u6253\u5370\u8f93\u51fa\u4e00\u4e9b\u8c03\u8bd5\u4fe1\u606f, \u901a\u5e38\u8fd9\u4e9b\u4fe1\u606f\u4f1a\u88ab\u6253\u5370\u8fdb\u63a7\u5236\u53f0\u7684\u540c\u65f6\u5199\u5165\u6e38\u620f\u7684 log.txt
\u6587\u4ef6\u4e2d, \u8fd9\u4e5f\u5c31\u89e3\u91ca\u4e86\u4e3a\u4ec0\u4e48\u4f60\u9047\u5230\u5404\u79cd\u95ee\u9898\u65f6\u522b\u4eba\u603b\u8981\u6c42\u4f60\u53d1\u9001\u4f60\u7684 log.txt
. Logger.Log
\u6709\u4e24\u4e2a\u91cd\u8f7d, \u5176\u4e2d\u4e00\u4e2a\u7684\u7b7e\u540d\u662f:
public static void Log(LogLevel logLevel, string tag, string str)\n
\u5b83\u4f1a\u4ee5 logLevel
\u7684\u65e5\u5fd7\u7b49\u7ea7\u6253\u5370\u4e00\u4e2a\u6807\u7b7e\u4e3a tag
\u7684\u6d88\u606f str
, \u53e6\u4e00\u4e2a\u91cd\u8f7d\u4e0d\u8981\u6c42\u4f60\u4f20\u5165 logLevel
\u4f46\u4f1a\u9ed8\u8ba4\u4f60\u7684 logLevel
\u4e3a LogLevel.Verbose
. LogLevel
\u679a\u4e3e\u5305\u542b Verbose, Debug, Info, Warn, Error
. \u901a\u5e38\u5bf9\u4e8e\u666e\u901a\u65e5\u5fd7\u6211\u4eec\u4f1a\u9009\u62e9 Info
, \u5bf9\u4e8e\u8f83\u591a\u7684\u8c03\u8bd5\u4fe1\u606f\u9009\u62e9 Debug
, \u5bf9\u4e8e\u5197\u4f59\u7684\u4fe1\u606f\u9009\u62e9 Verbose
, \u5bf9\u4e8e\u4e00\u4e9b\u9519\u8bef\u4f46\u4e0d\u5f71\u54cd\u6e38\u620f\u8fdb\u884c\u7684\u4fe1\u606f\u9009\u62e9 Warn
, \u5bf9\u4e8e\u4e00\u4e9b\u81f4\u547d\u6027\u9519\u8bef\u6211\u4eec\u4f1a\u9009\u62e9 Error
. \u4e00\u822c\u5730, \u6e38\u620f\u53ea\u4f1a\u6253\u5370 Info
\u7b49\u7ea7\u53ca\u4ee5\u4e0a\u7684\u65e5\u5fd7, \u4f60\u53ef\u4ee5\u901a\u8fc7\u5728\u851a\u84dd\u542f\u52a8\u7684\u547d\u4ee4\u884c\u4e2d\u52a0\u5165--loglevel {\u7b49\u7ea7}
\u6765\u6307\u5b9a\u8fc7\u6ee4\u7b49\u7ea7."},{"location":"begin/basic_env/#everestyaml","title":"everest.yaml","text":"ok, \u6211\u4eec\u524d\u9762\u51e0\u4e4e\u5df4\u62c9\u5df4\u62c9\u8bb2\u4e86\u51e0\u4e4e\u4e09\u5343\u591a\u4e2a\u5b57, \u4f46\u662f\u4f9d\u7136\u6ca1\u6709\u8ba9\u851a\u84dd\u52a0\u8f7d\u5230\u6211\u4eec\u7684mod, \u4e0d\u8fc7\u522b\u6025, \u8fd9\u662f\u5012\u6570\u7b2c\u4e8c\u6b65\u4e86. \u5b9e\u9645\u4e0a\u6709\u5173 code mod \u7684\u6240\u6709\u4ee3\u7801\u76f8\u5173\u7684\u4e1c\u897f\u6211\u4eec\u90fd\u5df2\u7ecf\u505a\u5b8c\u4e86, \u5269\u4f59\u7684\u5176\u5b9e\u53ea\u662f\u4e00\u4e2a\u666e\u901a mod \u8981\u505a\u7684 ---- \u5199 everest.yaml
. \u5728\u8fd9\u91cc\u6211\u4eec\u9700\u8981\u5728 ModFolder
\u8fd9\u4e2a\u6587\u4ef6\u5939\u91cc\u505a\u8fd9\u4ef6\u4e8b, \u90a3\u4e48, \u5728\u4f60\u7684\u8fd9\u4e2a\u6587\u4ef6\u5939\u4e0b\u521b\u5efa everest.yaml
\u7a7a\u6587\u4ef6, \u4f60\u7684\u76ee\u5f55\u7ed3\u6784\u53ef\u80fd\u50cf\u662f:
Note
.dll
\u6587\u4ef6\u548c .pdb
\u6587\u4ef6\u4ec5\u4f1a\u5728\u4f60\u6784\u5efa\u8fc7\u9879\u76ee\u540e\u51fa\u73b0, \u6709\u65f6\u5019\u751a\u81f3 ModFolder \u76ee\u5f55\u4e5f\u4f1a\u5728\u6784\u5efa\u8fc7\u540e\u51fa\u73b0
ModFolder everest.yaml MyCelesteMod.dll MyCelesteMod.pdb \u597d\u7684, \u73b0\u5728\u6211\u4eec\u6253\u5f00 everest.yaml
, \u7136\u540e\u50cf\u4e00\u4e2a\u666e\u901a\u7684 mapper \u4e00\u6837\u586b\u5199\u4fe1\u606f:
- Name: MyCelesteMod\n Version: 0.1.0\n DLL: MyCelesteMod.dll\n Dependencies:\n - Name: Everest\n Version: 1.3971.0\n
\u8fd9\u4e9b\u53c2\u6570\u5206\u522b\u662f: Name
: \u4f60\u7684 mod \u540d\u5b57 Version
: \u4f60\u7684 mod \u7684\u7248\u672c DLL
: \u5982\u679c\u4f60\u662f code mod \u7684\u8bdd, \u8fd9\u91cc\u586b\u5165\u4f60\u7684 code (\u4e5f\u5c31\u662f dll \u6587\u4ef6) \u7684\u4f4d\u7f6e, \u8fd9\u91cc\u6211\u4eec\u662f\u76f4\u63a5\u628a .dll \u6587\u4ef6\u653e\u5230\u8fd9\u4e2a yaml \u7684\u65c1\u8fb9\u4e86, \u6240\u4ee5\u76f4\u63a5\u5199\u540d\u5b57\u5c31\u597d \u6700\u540e\u662f\u6700\u5e95\u4e0b\u7684\u90a3\u4e2a\u4f9d\u8d56, \u8fd9\u91cc\u6211\u4eec\u53ea\u4f9d\u8d56\u6700\u57fa\u7840\u7684 Everest, \u7248\u672c\u586b\u4e0a\u4f60\u76ee\u524d\u4f7f\u7528\u7684 Everest \u7248\u672c, \u8fd9\u91cc\u6211\u5c31\u586b\u5199 3971 \u4e86. \u5982\u679c\u4f60\u7684 mod \u4f9d\u8d56 Everest Core, \u4f60\u9700\u8981\u5728\u8fd9\u91cc\u5c06 Everest
\u66f4\u6539\u4e3a EverestCore
, \u5e76\u5c06\u7248\u672c\u53f7\u586b\u5199\u5927\u4e8e 4465 \u7684\u503c.
"},{"location":"begin/basic_env/#_4","title":"\u6700\u540e\u4e00\u6b65!","text":"\u4e3a\u4e86\u65b9\u4fbf\u6211\u4eec\u7684\u8c03\u8bd5, \u6211\u4eec\u9700\u8981\u8ba9\u851a\u84dd\u6253\u5f00\u7684\u540c\u65f6\u6253\u5f00\u63a7\u5236\u53f0, \u8fd9\u4e00\u6b65\u5f88\u7b80\u5355:
\u627e\u5230\u851a\u84dd\u6839\u76ee\u5f55\u4e0b\u7684 everest-launch.txt
, \u6ca1\u6709\u7684\u8bdd\u65b0\u5efa\u4e00\u4e2a\u7a7a\u7684\u5c31\u884c\u4e86 \u5411\u91cc\u9762\u5199\u5165 --console
\u641e\u5b9a, \u8d70\u4f60! \u73b0\u5728, \u91cd\u65b0\u7f16\u8bd1\u9879\u76ee, \u8ba9 msbuild
\u5e26\u7740\u4f60\u7684 ModFolder
\u7684\u5185\u5bb9\u524d\u5f80\u851a\u84dd Mods \u6587\u4ef6\u5939\u4e0b, \u542f\u52a8\u851a\u84dd. \u5728\u540c\u65f6\u542f\u52a8\u7684\u9ed1\u4e4e\u4e4e\u7684\u547d\u4ee4\u884c\u7a97\u53e3\u4e0a\u4f60\u5e94\u8be5\u80fd\u5728\u8fd9\u9644\u8fd1\u770b\u5230\u90a3\u53e5\u719f\u6089\u7684 Hello world:
(07/08/2023 21:18:59) [Everest] [Info] [core] Module DialogCutscene 1.0.0 registered.\n(07/08/2023 21:18:59) [Everest] [Info] [core] Module UpdateChecker 1.0.2 registered.\n(07/08/2023 21:18:59) [Everest] [Info] [core] Module InfiniteSaves 1.0.0 registered.\n(07/08/2023 21:18:59) [Everest] [Info] [core] Module DebugRebind 1.0.0 registered.\n(07/08/2023 21:18:59) [Everest] [Info] [core] Module RebindPeriod 1.0.0 registered.\n(07/08/2023 21:19:00) [Everest] [Info] [Everest.LuaBoot] Lua ready.\n(07/08/2023 21:19:00) [Everest] [Info] [MyCelesteMod] Hello World!\n(07/08/2023 21:19:00) [Everest] [Info] [core] Module MyAwesomeMod 0.1.0 registered.\n(07/08/2023 21:19:00) [Everest] [Info] [loader] Loading mods with unsatisfied optional dependencies (if any)\nFNA3D Driver: D3D11\nD3D11 Adapter: Intel(R) UHD Graphics 630\n
"},{"location":"begin/basic_env/#_5","title":"\u8fd8\u6ca1\u5b8c","text":"\u5728\u7ecf\u8fc7\u5982\u4e0a\u7684\u914d\u7f6e\u540e, \u4f60\u4f1a\u53d1\u73b0\u5728\u851a\u84dd\u542f\u52a8\u7684\u65f6\u5019, \u8fdb\u884c\u7f16\u8bd1\u5e76\u590d\u5236\u8d44\u6e90\u65f6\u4f1a\u62a5\u9519, \u8fd9\u662f\u56e0\u4e3a Everest \u9501\u5b9a\u5360\u7528\u4e86\u5b83\u4eec, \u5bfc\u81f4\u4f60\u4e0d\u5f97\u4e0d\u8ba9\u8fd9\u4e00\u5207\u5728\u851a\u84dd\u5173\u95ed\u65f6\u8fdb\u884c, \u540c\u65f6\u7531\u4e8e\u851a\u84dd\u7684\u91cd\u542f\u901f\u5ea6\u4e0d\u662f\u5f88\u7406\u60f3, \u8fd9\u5927\u5927\u7684\u62c9\u4f4e\u4e86 mod \u5f00\u53d1\u6548\u7387. \u4e0d\u8fc7\u597d\u5728 Everest \u63d0\u4f9b\u4e86\u4e00\u4e2a\u6280\u672f\u53eb\u505a code hot reload
, \u5373\u70ed\u91cd\u8f7d, \u5b83\u5141\u8bb8\u4f60\u5728\u6e38\u620f\u8fd0\u884c\u671f\u95f4\u66ff\u6362\u4f60\u7684\u4ee3\u7801\u5e76\u91cd\u8f7d\u8d44\u6e90, \u5b83\u76ee\u524d\u8fd8\u5728 wip \u72b6\u6001. \u8981\u5f00\u542f\u8fd9\u9879\u529f\u80fd, \u9996\u5148\u5230\u4f60\u7684\u851a\u84dd\u6839\u76ee\u5f55\u4e0b\u7684 Saves \u76ee\u5f55, \u627e\u5230\u5e76\u6253\u5f00 modsettings-Everest.celeste
\u8fd9\u4e2a\u6587\u4ef6, \u7ffb\u5230\u5927\u6982\u4e2d\u95f4\u7684\u4f4d\u7f6e, \u627e\u5230\u5c5e\u6027 CodeReload_WIP
, \u5c06\u5176\u66f4\u6539\u4e3a true
, \u6b64\u65f6\u91cd\u65b0\u7f16\u8bd1\u4f60\u7684\u9879\u76ee, \u4f60\u5e94\u8be5\u5c31\u4e0d\u4f1a\u518d\u5f97\u5230\u4efb\u4f55\u9519\u8bef, \u5e76\u4e14 Everest \u4e5f\u6b63\u786e\u5730\u70ed\u91cd\u8f7d\u4e86\u4f60\u7684 mod \u548c\u4f60\u7684 mod \u8d44\u6e90.
"},{"location":"begin/basic_env/#_6","title":"\u6700\u540e\u4e00\u4e9b\u788e\u788e\u5ff5","text":"\u8fd9\u4e00\u8282\u5b8c\u6210\u540e\u4f60\u7684\u76ee\u5f55\u7ed3\u6784\u5927\u6982\u4f1a\u50cf\u662f:
MyCelesteMod (\u4f60\u7684\u6839\u76ee\u5f55) ModFolder everest.yaml MyCelesteMod.dll MyCelesteMod.pdb CelesteMod.props CelesteMod.targets Common.props MyCelesteMod.csproj MyCelesteModModule.cs \u5176\u4e2d\u6b63\u5982\u4e4b\u524d\u6240\u4ecb\u7ecd\u7684, \u6211\u63a8\u8350\u5982\u679c\u4f60\u4f7f\u7528\u8be5\u6a21\u677f\u7684\u8bdd, mod \u7684\u8d44\u6e90\u6587\u4ef6\u5e94\u8be5\u653e\u5728 ModFolder
\u4e2d, \u7136\u540e\u5c31\u50cf\u5f80\u5e38\u4e00\u6837\u653e\u7f6e\u4f60\u7684 mod \u8d44\u6e90, \u5f53\u4f60\u7684\u9879\u76ee\u5728\u6784\u5efa\u65f6\u5b83\u4eec\u4f1a\u81ea\u52a8\u88ab\u590d\u5236. \u5e76\u4e14\u5c06\u4ee3\u7801\u6587\u4ef6\u653e\u7f6e\u5728 .csproj \u540c\u76ee\u5f55\u4e0b\u6216\u5d4c\u5957\u6587\u4ef6\u5939\u4e0b, \u5982\u679c\u4f60\u6ca1\u6709\u66f4\u6539\u4f60\u7684\u9879\u76ee\u800c\u53ea\u66f4\u6539\u4e86\u8d44\u6e90\u6587\u4ef6\u65f6\u4f60\u4f1a\u53d1\u73b0\u7f16\u8bd1\u9879\u76ee\u4f1a\u56e0\u4e3a \"\u6240\u6709\u6587\u4ef6\u90fd\u662f\u6700\u65b0\u7684\" \u800c\u8df3\u8fc7\u7f16\u8bd1, \u800c\u540c\u65f6\u4e5f\u4f1a\u8df3\u8fc7\u6211\u4eec\u7684\u8d44\u6e90\u590d\u5236, \u5bf9\u6b64\u7684\u8bdd\u6211\u4eec\u6709\u4e24\u79cd\u89e3\u51b3\u65b9\u6848:
\u76f4\u63a5\u5f3a\u5236\u91cd\u65b0\u6784\u5efa\u9879\u76ee (vs \u4e2d \"\u751f\u6210\" -> \"\u91cd\u65b0\u751f\u6210\u9879\u76ee\") \u5728\u9879\u76ee\u6839\u76ee\u5f55\u6267\u884c msbuild -target:PostModBuild
\u547d\u4ee4\u884c \u597d\u50cf\u662f\u6709\u66f4\u597d\u7684\u89e3\u51b3\u65b9\u6cd5, \u4e0d\u8fc7\u9274\u4e8e\u672c\u4eba MSBuild \u77e5\u8bc6\u4e0d\u8db3\u53ea\u80fd\u505a\u6210\u8fd9\u6837\u4e86(x
"},{"location":"begin/celeste_everest_monomod/","title":"Celeste Everest MonoMod","text":""},{"location":"begin/celeste_everest_monomod/#celeste","title":"Celeste","text":"\u989d, \u6765\u8fd9\u91cc\u7684\u5e94\u8be5\u90fd\u77e5\u9053 Celeste \u662f\u4ec0\u4e48\u5427(( \u540e\u6587\u4e2d\u63d0\u5230\u7684 Celeste
, \u851a\u84dd
\u90fd\u4f1a\u53ea\u6307 Celeste \u8fd9\u4e2a\u6e38\u620f, \u4e5f\u5c31\u662f\u6211\u4eec\u6b63\u5728\u5b66\u4e60\u7684\u4e3a\u5176\u5236\u4f5c mod \u7684\u5bf9\u8c61.
"},{"location":"begin/celeste_everest_monomod/#everest","title":"Everest","text":"\u4f5c\u4e3a\u4e00\u4e2a\u851a\u84dd\u7684 mod \u73a9\u5bb6, \u5b89\u88c5 Everest \u662f\u5fc5\u4e0d\u53ef\u5c11\u7684\u6b65\u9aa4, \u56e0\u4e3a\u6211\u4eec\u7684 mod \u4f9d\u8d56\u4e8e\u5b83\u6240\u63d0\u4f9b\u7684\u5236\u4f5c mod \u4e2d\u6240\u5fc5\u987b\u7684\u4e1c\u897f. \u5b83\u5f00\u6e90\u5728 Github \u4e0a. \u53ef\u80fd\u4f60\u8fd8\u542c\u8fc7 Olympus, \u5b83\u662f\u4e00\u4e2a Everest \u7684\u5b89\u88c5\u5668, \u4e5f\u662f\u4e00\u4e2a mod \u7ba1\u7406\u5668.
\u5982\u679c\u4f60\u8fd8\u73a9\u8fc7 Minecraft \u7684\u8bdd\u6211\u4eec\u53ef\u4ee5\u5efa\u7acb\u4e00\u4e2a\u8fd9\u6837\u7684\u5947\u5999\u5173\u7cfb:
\u851a\u84dd\u4fa7 MC\u4fa7 Celeste Minecraft Everest Forge/Fabric Olympus PCL2/HCML \u989d\u5916\u5730, Everest, Forge, Fabric \u8fd9\u4e00\u7c7b\u4e1c\u897f\u6211\u4eec\u5bf9\u5176\u6709\u4e2a\u7edf\u79f0, \u53eb\u505a ModApi
. \u5c31\u50cf Celeste \u548c Minecraft \u88ab\u7edf\u79f0\u4e3a\u6e38\u620f\u672c\u4f53/\u539f\u7248.
"},{"location":"begin/celeste_everest_monomod/#monomod","title":"MonoMod","text":"Everest \u5e95\u5c42\u57fa\u4e8e MonoMod, \u5728\u8fd9\u91cc\u4f60\u53ea\u9700\u8981\u77e5\u9053 Everest \u4f9d\u8d56\u4e86 MonoMod, \u540c\u6837\u5730\u5b83\u4e5f\u662f\u4e00\u4e2a\u5f00\u6e90\u9879\u76ee(Github). \u6709\u8da3\u7684\u662f, Everest \u7684\u4e3b\u8981\u7ef4\u62a4\u8005\u4e4b\u4e00\u4e5f\u662f MonoMod \u7684\u4e3b\u8981\u7ef4\u62a4\u8005, \u540c\u65f6 MonoMod \u4e5f\u662f\u4e00\u4e9b\u5176\u4ed6\u6e38\u620f\u7684 mod \u5e95\u5c42, \u6bd4\u5982 Terraria \u7684 tModLoader, Fez \u7684 FEZMod \u7b49\u7b49.
\u90a3\u4e48\u5728\u8fd9\u4e09\u4e2a\u57fa\u7840\u6982\u5ff5\u4e86\u89e3\u4e4b\u540e\u4f60\u5c31\u53ef\u4ee5\u5f00\u59cb\u5236\u4f5c\u4f60\u7684\u7b2c\u4e00\u4e2a mod\u4e86: \u57fa\u7840\u73af\u5883\u914d\u7f6e
"},{"location":"begin/hook%2Creading_1/","title":"\u94a9\u5b50, \u9605\u8bfb\u4ee3\u7801, demo1","text":""},{"location":"begin/hook%2Creading_1/#_1","title":"\u524d\u8a00","text":"\u5728\u8fd9\u4e00\u8282, \u6211\u4eec\u4f1a\u4ecb\u7ecd\u5728\u5236\u4f5c mod \u4e2d\u7684\u4e00\u4e2a\u5f88\u91cd\u8981\u7684\u6280\u672f: \u94a9\u5b50(Hook), \u6211\u4eec\u4e3b\u8981\u4ecb\u7ecd On \u94a9\u5b50, \u5728\u4e4b\u540e\u6211\u4eec\u4f1a\u9605\u8bfb\u851a\u84dd\u7684\u4ee3\u7801, \u6700\u540e\u6211\u4eec\u4f1a\u5236\u4f5c\u4e00\u4e2a\u4fee\u6539\u73a9\u5bb6\u51b2\u523a\u6570\u7684\u5c0f demo.
"},{"location":"begin/hook%2Creading_1/#on","title":"\u94a9\u5b50 (\u7279\u6307 On \u94a9\u5b50)","text":"\u5bf9\u4e8e C# \u7684\u4e00\u4e2a\u666e\u901a\u7684\u51fd\u6570\u6765\u8bf4, \u5b83\u88ab\u8c03\u7528\u65f6\u770b\u8d77\u6765\u662f\u8fd9\u6837\u7684:
graph LR\n A[\u8c03\u7528\u65b9] --> B[\u5373\u5c06\u8c03\u7528\u8be5\u51fd\u6570];\n subgraph \u8be5\u51fd\u6570\n B --> C[\u8be5\u51fd\u6570\u4e3b\u4f53];\n C --> D[\u7ed3\u675f\u8c03\u7528\u8be5\u51fd\u6570];\n end\n D --> E[\u8c03\u7528\u65b9];
\u5f53\u6211\u4eec\u5f15\u5165\u94a9\u5b50\u6280\u672f\u540e, \u8fd9\u4e2a\u51fd\u6570\u8c03\u7528\u65f6\u4f1a\u50cf\u88ab\"\u94a9\"\u4f4f\u4e00\u6837\u8f6c\u8eab\u53bb\u8c03\u7528\u6211\u4eec\u7684\u51fd\u6570:
graph LR\n A[\u8c03\u7528\u65b9]; B[\u5373\u5c06\u8c03\u7528\u8be5\u51fd\u6570];\n F[\u94a9\u5b50]; G[\u6211\u4eec\u7684\u51fd\u6570];\n H[\u8be5\u51fd\u6570\u4e3b\u4f53];\n D[\u7ed3\u675f\u8c03\u7528\u8be5\u51fd\u6570];\n E[\u8c03\u7528\u65b9];\n subgraph \u8be5\u51fd\u6570\n B; H; D;\n end\n A --> B;\n B --> F;\n F --> G;\n H --> D;\n G --> H;\n G -.\u6216\u8005.-> D;\n D --> E;
\u5982\u56fe\u6240\u89c1, \u8be5\u94a9\u5b50\u5141\u8bb8\u4f60\u5728\u8c03\u7528\u67d0\u4e2a\u51fd\u6570\u65f6\u8f6c\u8eab\u53bb\u8c03\u7528\u6211\u4eec\u7684\u51fd\u6570, \u540c\u65f6\u4f60\u80fd\u9009\u62e9\u6211\u4eec\u7684\u51fd\u6570\u6267\u884c\u5b8c\u540e\u662f\u5426\u518d\u6267\u884c\u56de\u539f\u51fd\u6570.
\u5728 Everest \u4e2d, \u501f\u52a9\u4e8e MonoMod \u7684\u6280\u672f, \u521b\u5efa\u4e00\u4e2a On \u94a9\u5b50\u7b80\u5355\u7684\u5c31\u50cf:
\u7b80\u5355\u7684\u94a9\u53d6...public override void Load()\n{\n On.Celeste.Player.Update += Player_Update;\n}\n\nprivate void Player_Update(On.Celeste.Player.orig_Update orig, Player self)\n{\n orig(self);\n}\n\npublic override void Unload()\n{\n On.Celeste.Player.Update -= Player_Update;\n}\n
\u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\u6211\u4eec\u4f7f\u7528\u7c7b\u4f3c\u8ba2\u9605\u4e8b\u4ef6\u7684\u8bed\u6cd5\u53bb\u94a9\u4f4f\u4e86 Player
\u7c7b\u7684 Update
\u65b9\u6cd5(\u8be5\u65b9\u6cd5\u6bcf\u5e27\u90fd\u4f1a\u8c03\u7528\u4e00\u904d), Everest \u4e3a\u6211\u4eec\u628a\u51e0\u4e4e\u6240\u6709\u53ef\u80fd\u94a9\u53d6\u7684\u51fd\u6570\u653e\u5230\u4e86\u547d\u540d\u7a7a\u95f4 On
\u4e2d, \u5f53\u4f60\u60f3\u94a9\u53d6\u67d0\u4e2a\u65b9\u6cd5\u65f6\u53ea\u9700\u901a\u8fc7 On
\u547d\u540d\u7a7a\u95f4\u4e00\u8def\"\u70b9\"\u5230\u4f60\u60f3\u8981\u7684\u65b9\u6cd5\u4e0a, \u7136\u540e\u4f7f\u7528\u4e00\u4e2a\u94a9\u5b50\u51fd\u6570\u4ee5\u50cf\u4e8b\u4ef6\u4e00\u6837\u7684\u8bed\u6cd5\"\u8ba2\u9605\"\u5c31\u80fd\u94a9\u4f4f\u5b83! \u5728\u8fd9\u91cc\u6211\u4eec\u7684\u94a9\u5b50\u51fd\u6570\u5c31\u662fPlayer_Update
, \u4f60\u53ef\u80fd\u6ce8\u610f\u5230\u53c2\u6570\u5f88\u590d\u6742, \u662f\u7684, \u6240\u4ee5\u4e00\u822c\u6765\u8bf4\u6211\u90fd\u662f\u4f9d\u8d56 IDE \u5e2e\u6211\u81ea\u52a8\u586b\u5199\u8fd9\u4e9b\u53c2\u6570\u5c31\u50cf:
Note
\u6ce8\u610f IDE \u751f\u6210\u7684\u51fd\u6570\u9ed8\u8ba4\u5305\u542b\u4e00\u53e5\u629b\u51fa\u5f02\u5e38\u8bed\u53e5, \u8bb0\u5f97\u628a\u5b83\u6539\u6389
orig
\u53c2\u6570\u662f\u4e00\u4e2a\u59d4\u6258, \u8c03\u7528\u5b83\u5c31\u76f8\u5f53\u4e8e\u8c03\u7528\u8fd9\u4e2a\u94a9\u5b50\u94a9\u4f4f\u7684\u539f\u51fd\u6570, \u4e5f\u5c31\u662f\u8bf4\u4f60\u53ef\u4ee5\u5728\u8be5\u51fd\u6570\u8c03\u7528\u524d\u505a\u4e9b\u4e8b, \u4e5f\u53ef\u4ee5\u5728\u8be5\u51fd\u6570\u8c03\u7528\u540e\u505a\u4e9b\u4e8b, \u6216\u8005\u5e72\u8106\u4e0d\u8c03\u7528\u8fd9\u4e2a\u51fd\u6570, \u751a\u81f3\u8c03\u7528\u8fd9\u4e2a\u51fd\u6570\u591a\u6b21. \u901a\u5e38\u6765\u8bf4\u6211\u4eec\u90fd\u4f1a\u5728\u672b\u5c3e\u7b80\u5355\u7684\u8c03\u7528\u56de\u53bb\u907f\u514d\u9020\u6210\u4e0d\u5fc5\u8981\u7684\u9ebb\u70e6.
\u4e00\u4e9b\u94a9\u5b50\u672c\u8eab...private void Player_Update(On.Celeste.Player.orig_Update orig, Player self)\n{\n // \u5728\u8fd9\u4e4b\u524d\u505a\u4e00\u4e9b\u4e8b...\n\n // \u5f53\u67d0\u4e9b\u5947\u602a\u7684\u6761\u4ef6\u4e0d\u6210\u7acb\u65f6\u6211\u4eec\u624d\u8c03\u7528\u56de\u53bb\u539f\u6765\u7684\u51fd\u6570...\n if (!xxx)\n orig(self);\n\n // \u5728\u8fd9\u4e4b\u540e\u505a\u4e00\u4e9b\u4e8b...\n}\n
\u5982\u679c\u4f60\u94a9\u53d6\u5230\u7684\u662f\u4e00\u4e2a\u6210\u5458\u51fd\u6570(\u4e5f\u53eb\u6210\u5458\u65b9\u6cd5), \u90a3\u4e48\u53c2\u6570\u901a\u5e38\u4f1a\u5e26\u6709\u4e00\u4e2a self
, \u5b83\u8868\u793a\u6267\u884c\u8fd9\u4e2a\u6210\u5458\u51fd\u6570\u65f6 this
\u7684\u503c, \u90a3\u4e48\u81ea\u7136\u5730\u5982\u679c\u4f60\u94a9\u53d6\u7684\u662f\u4e00\u4e2a\u9759\u6001\u51fd\u6570\u90a3\u4e48\u662f\u6ca1\u6709\u8fd9\u4e2a\u53c2\u6570\u7684. \u5982\u679c\u4f60\u94a9\u53d6\u7684\u51fd\u6570\u662f\u5e26\u53c2\u6570\u7684, \u90a3\u4e48\u53c2\u6570\u5217\u8868\u4f1a\u539f\u5c01\u4e0d\u52a8\u7684\u6392\u5217\u5728\u524d\u9762\u63d0\u5230\u7684\u53c2\u6570\u7684\u540e\u9762.
\u6bd4\u5982\u4f60\u5c1d\u8bd5\u94a9\u53d6 Player.Jump
\u51fd\u6570\u65f6, \u5b83\u7684\u4e09\u4e2a\u53c2\u6570\u4f1a\u8fd9\u6837\u4f20\u9012\u7ed9\u4f60:
private void Player_Jump(On.Celeste.Player.orig_Jump orig, Player self, bool particles, bool playSfx)\n
\u6700\u540e, \u4e0d\u8981\u5fd8\u8bb0\u5728 Unload
\u65b9\u6cd5\u91cc\u53d6\u6d88\u6389\u6211\u4eec\u7684\u94a9\u5b50(\u901a\u8fc7-=
), \u9632\u6b62\u6211\u4eec\u7684\u94a9\u5b50\u5728\u4e0d\u5fc5\u8981\u7684\u5730\u65b9\u4ea7\u751f\u4e0d\u597d\u7684\u5f71\u54cd: \u53d6\u6d88\u94a9\u5b50
public override void Unload()\n{\n On.Celeste.Player.Update -= Player_Update;\n}\n
"},{"location":"begin/hook%2Creading_1/#i","title":"\u9605\u8bfb\u4ee3\u7801 I","text":"\u5230\u8fd9\u91cc\u76f8\u4fe1\u4f60\u80af\u5b9a\u6709\u5f88\u591a\u95ee\u53f7, \u6bd4\u5982\u8fd9\u4e9b\u51fd\u6570\u90fd\u662f\u5e72\u4ec0\u4e48\u7684?
Player
\u662f\u4ec0\u4e48? Player.Update
\u662f\u4ec0\u4e48? Player.Jump
\u53c8\u662f\u4ec0\u4e48?? \u6240\u4ee5\u8fd9\u65f6\u6211\u4eec\u5c31\u9700\u8981\u9605\u8bfb\u851a\u84dd\u7684\u4ee3\u7801\u6765\u4e86\u89e3\u8fd9\u4e9b\u4e1c\u897f. \u5f53\u7136, \u851a\u84dd\u662f\u4e2a\u5546\u4e1a\u6e38\u620f, \u60f3\u6307\u671b\u5b83\u5f00\u6e90\u6240\u6709\u4ee3\u7801\u662f\u4e0d\u53ef\u80fd\u7684, \u90a3\u6211\u4eec\u5c31\u5fc5\u987b\u5f97\u501f\u52a9\u4e00\u4e9b\u53cd\u7f16\u8bd1\u5de5\u5177. \u5728\u8fd9\u91cc\u6211\u4f1a\u63a8\u8350 dnSpy
\u4f7f\u7528\u8be5\u8f6f\u4ef6\u5f88\u7b80\u5355:
\u6253\u5f00\u5b83 \u70b9\u51fb\u5de6\u4e0a\u89d2\u7684\u6587\u4ef6
, \u6253\u5f00
\u9009\u62e9 Celeste.exe
(\u5982\u679c\u4f60\u4f7f\u7528 core \u7248\u672c\u7684 everest, \u4f60\u9700\u8981\u9009\u62e9 Celeste.dll
) \u5c55\u5f00\u851a\u84dd\u7684\u7a0b\u5e8f\u96c6 \u4f60\u73b0\u5728\u53ef\u4ee5\u770b\u5230\u851a\u84dd\u90fd\u6709\u54ea\u4e9b\u7c7b\u4e86 \u4f60\u73b0\u5728\u4e5f\u53ef\u4ee5\u770b\u5230\u851a\u84dd\u90fd\u6709\u54ea\u4e9b\u51fd\u6570\u4e86 Warning
\u4e0d\u8981\u4e0a\u4f20\u53cd\u7f16\u8bd1\u540e\u7684\u4ee3\u7801\u5230\u4efb\u4f55\u5730\u65b9, \u8fd9\u53ef\u80fd\u4f1a\u4e0d\u907f\u514d\u7684\u9020\u6210\u4e00\u4e9b\u4e89\u8bae.
\u73b0\u5728\u6211\u4eec\u6d4f\u89c8\u851a\u84dd\u7684\u4ee3\u7801\u5c31\u50cf\u4f60\u5728 IDE \u91cc\u6d4f\u89c8\u4f60\u7684\u9879\u76ee\u4e00\u6837, \u867d\u7136\u8fd9\u4e0d\u662f\u6211\u4eec\u7684\u9879\u76ee. \u5728\u6d4f\u89c8\u8fc7\u7a0b\u4e2d, \u901a\u5e38\u53ef\u80fd\u4f60\u4f1a\u5bf9\u7740\u4e00\u4e2a\u5b57\u6bb5\u3001\u4e00\u4e2a\u51fd\u6570\u53d1\u5446, \u5927\u6982\u662f\u56e0\u4e3a\u4f60\u6839\u672c\u4e0d\u77e5\u9053\u5b83\u662f\u505a\u4ec0\u4e48\u7684! \u597d\u5728 dnSpy
\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5f88\u597d\u7528\u7684\"\u5206\u6790\"\u529f\u80fd\u6765\u7f13\u89e3\u8fd9\u4e2a : \u5728\u8fd9\u91cc\u4f60\u53ef\u4ee5\u770b\u5230\u54ea\u4e9b\u5b57\u6bb5\u3001\u54ea\u4e9b\u51fd\u6570\u88ab\u8c01\u8c03\u7528\u4e86\u3001\u88ab\u8c01\u5f15\u7528\u4e86\u3001\u88ab\u8c01\u66f4\u6539\u4e86:
"},{"location":"begin/hook%2Creading_1/#monocle-ec","title":"Monocle, EC \u67b6\u6784","text":"\u5728\u8fd9\u91cc\u6211\u4f1a\u7b80\u5355\u4ecb\u7ecd\u4e00\u4e0b\u6574\u4e2a\u851a\u84dd\u662f\u600e\u4e48\u7ec4\u7ec7\u8d77\u6765\u7684. \u9996\u5148\u851a\u84dd\u57fa\u4e8e Monocle
\u5f15\u64ce, \u8fd9\u662f matt
\u81ea\u5df1\u5f00\u53d1\u7684\u4e00\u4e2a\u5f15\u64ce, \u6240\u4ee5\u522b\u6307\u671b\u4f60\u80fd\u5728\u7f51\u4e0a\u627e\u5230\u5b83\u7684\u6559\u7a0b(, \u5176\u6b21 Monocle
\u518d\u6b21\u4f9d\u8d56 XNA
(\u5df2\u505c\u6b62\u7ef4\u62a4) \u6216\u8005 FNA
(XNA
\u6846\u67b6\u7684\u91cd\u65b0\u5b9e\u73b0), XNA
\u63d0\u4f9b\u7684 api \u90fd\u975e\u5e38\u539f\u59cb, \u751a\u81f3\u8fde\u6700\u57fa\u672c\u7684\u573a\u666f\u7ec4\u7ec7\u4e4b\u7c7b\u7684\u90fd\u6ca1\u6709, \u90a3\u4e48 Monocle
\u5c31\u662f\u6765\u5b9e\u73b0\u8fd9\u4e9b\u7684.
\u901a\u5e38\u6765\u8bf4\u4e00\u4e2a\u6b63\u5728\u8fd0\u884c\u7684 Monocle
\u6e38\u620f\u7684\u7ed3\u6784\u5c31\u50cf:
graph LR\nR[Engine] --- A;\n\nA[Scene] --- B[Entity A];\nA --- C[Entity B];\nA --- E[Entity ...];\nB --- F[Component A];\nB --- G[Component B];\nC --- H[Component A];\nC --- I[Component C];\nC --- J[Component ...];
Scene
\u8868\u793a\u4e00\u4e2a\u573a\u666f, \u6bd4\u5982\u4e3b\u754c\u9762\u573a\u666f, pico8 \u573a\u666f, \u4ee5\u53ca\u6700\u5e38\u89c1\u7684 gameplay \u573a\u666f. Entity
\u8868\u793a\u4e00\u4e2a\u5b9e\u4f53, \u6bd4\u5982\u8bf4\u739b\u5fb7\u7433\u5c31\u662f\u4e00\u4e2a\u5b9e\u4f53, \u4e00\u4e2a\u5f39\u7403\u662f\u4e00\u4e2a\u5b9e\u4f53, \u4e00\u4e2a\u6ce1\u6ce1\u662f\u4e00\u4e2a\u5b9e\u4f53. Component
\u8868\u793a\u4e00\u4e2a\u7ec4\u4ef6, \u5b83\u9644\u52a0\u4e0e\u5b9e\u4f53\u4e4b\u4e0a, \u901a\u5e38\u6211\u4eec\u80fd\u76f4\u63a5\u770b\u5230\u7684\u53ea\u6709\u56fe\u7247\u7ec4\u4ef6, \u6bd4\u5982\u5ca9\u6d46\u5757\u7684\u8d34\u56fe\u5c31\u662f\u7531 Image
\u7ec4\u4ef6\u6765\u5c55\u73b0\u7684, \u73a9\u5bb6\u7684\u52a8\u753b\u7531 Sprite
\u7ec4\u4ef6\u5c55\u73b0. Info
\u4ee5\u4e0a\u8fd9\u4e2a\u67b6\u6784\u6211\u4eec\u5c31\u79f0\u4e3a EC
\u67b6\u6784, \u5b83\u662f\u6e38\u620f\u7684\u4e00\u79cd\u7ec4\u7ec7\u65b9\u5f0f\u7684\u5b9e\u73b0.
\u901a\u5e38\u5730, \u6bcf\u8fc7 1/60
\u79d2, Engine
\u5c31\u4f1a\u88ab\u8c03\u7528\u5b83\u7684 Update()
\u51fd\u6570\u7528\u6765\u66f4\u65b0\u6e38\u620f\u903b\u8f91, Engine.Update()
\u5185\u90e8\u4f1a\u518d\u6b21\u8c03\u7528 Scene
\u7684 Update()
\u51fd\u6570, Scene.Update()
\u5185\u90e8\u4f1a\u904d\u5386\u5b83\u6240\u6709\u7684 Entity
\u5e76\u8c03\u7528\u5b83\u4eec\u7684 Update()
\u51fd\u6570, Entity.Update()
\u5185\u90e8\u8fd8\u4f1a\u904d\u5386\u5b83\u6240\u6709\u7684 Component
\u5e76\u8c03\u7528\u5b83\u4eec\u7684 Update()
\u51fd\u6570.
\u90a3\u4e48\u81ea\u7136, Player.Update()
\u5c31\u662f\u739b\u5fb7\u7433\u6bcf\u5e27\u7684\u66f4\u65b0\u903b\u8f91\u6240\u5728\u7684\u5730\u65b9\u4e86. \u73b0\u5728\u6211\u4eec\u505a\u4e00\u4e2a\u5c0f demo, \u5c06\u73a9\u5bb6\u7684\u51b2\u523a\u6570\u91cf\u9501\u6b7b\u4e3a\u5355\u51b2.
"},{"location":"begin/hook%2Creading_1/#_2","title":"\u9501\u5b9a\u5355\u51b2","text":"\u901a\u8fc7\u7b80\u5355\u7684\u6d4f\u89c8\u851a\u84dd\u7684\u4ee3\u7801, \u4f60\u4e86\u89e3\u5230(\u6ca1\u4e86\u89e3\u5230\u4e5f\u6b63\u5e38, \u540e\u9762\u4f1a\u8bf4\u4e00\u4e9b\u5e38\u89c1\u7c7b\u548c\u7ed3\u6784\u5e2e\u52a9\u4f60\u7406\u89e3) Player.Dashes
\u8fd9\u4e2a\u5b57\u6bb5\u50a8\u5b58\u4e86\u73a9\u5bb6\u7684\u51b2\u523a\u6570\u91cf, \u90a3\u4e48\u73b0\u5728\u6211\u4eec\u5c06\u5b83\u9501\u5b9a\u4e3a 1, \u4e5f\u5c31\u662f\u5355\u51b2. \u9996\u5148\u6211\u4eec\u94a9\u53d6 Player.Update()
, \u7136\u540e\u5728\u786e\u4fdd\u8c03\u7528\u56de\u539f\u6765\u7684\u51fd\u6570\u540e\u76f4\u63a5\u5c06 Dashes
\u5f3a\u5236\u4fee\u6539\u4e3a 1.
\u9501\u5b9a\u51b2\u523a\u4e3a1!public override void Load()\n{\n On.Celeste.Player.Update += Player_Update;\n}\n\nprivate void Player_Update(On.Celeste.Player.orig_Update orig, Player self)\n{\n self.Dashes = 1;\n orig(self);\n}\n\npublic override void Unload()\n{\n On.Celeste.Player.Update -= Player_Update;\n}\n
\u90a3\u4e48\u73b0\u5728\u7f16\u8bd1, \u6309\u4e4b\u524d\u7684\u5185\u5bb9\u64cd\u4f5c, \u5e76\u91cd\u542f\u851a\u84dd, \u4f60\u5e94\u8be5\u5c31\u4f1a\u770b\u5230\u4f60\u7684\u739b\u5fb7\u7433\u6c38\u8fdc\u90fd\u4f1a\u6709\u5355\u51b2\u4e86(\u5373\u4f7f\u662f\u5728\u7a7a\u4e2d!).
"},{"location":"begin/hook%2Creading_1/#_3","title":"\u94a9\u5b50\u7684\u6700\u4f73\u5b9e\u8df5","text":"\u6211\u4eec\u5e94\u8be5\u5c3d\u53ef\u80fd\u4e00\u6b21\u6027\u5730\u5c31\u5c06\u6211\u4eec\u6240\u9700\u8981\u7684\u6240\u6709\u94a9\u5b50\u5728 Load
\u91cc\u52a0\u8f7d\u5b8c, \u56e0\u4e3a\u521b\u5efa\u94a9\u5b50\u5b9e\u9645\u4e0a\u7684\u5f00\u9500\u5e76\u4e0d\u5c0f, \u5982\u679c\u4f60\u9700\u8981\u67d0\u4e9b \"\u67d0\u4e9b\u6761\u4ef6\u4e0d\u6210\u7acb\u4e0d\u542f\u52a8\u94a9\u5b50, \u6761\u4ef6\u6210\u7acb\u518d\u542f\u52a8\u94a9\u5b50\" \u7684\u903b\u8f91\u7684\u8bdd, \u6211\u5efa\u8bae\u4f60\u5e94\u8be5\u59cb\u7ec8\u4fdd\u6301\u94a9\u5b50, \u7136\u540e\u5728\u94a9\u5b50\u5185\u90e8\u5224\u65ad\u4f60\u7684\u6761\u4ef6, \u4e0d\u6210\u7acb\u65f6\u4f60\u5e94\u8be5\u76f4\u63a5\u56de\u8c03\u539f\u6765\u7684\u65b9\u6cd5\u5e76\u4e0d\u505a\u4efb\u4f55\u5176\u4ed6\u4e8b\u60c5.
"},{"location":"begin/preference/","title":"\u504f\u597d","text":"\u5728\u672c\u7cfb\u5217\u6559\u7a0b\u4e2d\u672c\u4eba\u53ef\u80fd\u4f1a\u5076\u5c14\u4e60\u60ef\u6027\u7684\u4f7f\u7528\u4e00\u4e9b\u6bd4\u8f83\u65b0\u7684 C# \u8bed\u6cd5\u6216\u8005\u662f\u7279\u6027, \u901a\u5e38\u8fd9\u662f\u5927\u90e8\u5206 C# \u6559\u7a0b\u4e2d\u5f88\u5c11\u63d0\u53ca\u7684, \u6240\u4ee5\u4e3a\u4e86\u907f\u514d\u56f0\u60d1\u6211\u4f1a\u5728\u8fd9\u91cc\u63d0\u53ca\u4ed6\u4eec.
Note
\u4e3a\u4e86\u4f7f\u7528\u8fd9\u4e9b\u8bed\u6cd5\u4f60\u53ef\u80fd\u9700\u8981\u5b89\u88c5 .NET 8 SDK
, \u5982\u679c\u4f60\u65e0\u6cd5\u7406\u89e3\u67d0\u4e9b\u4e1c\u897f, \u6ca1\u5173\u7cfb, \u4f60\u4f9d\u7136\u53ef\u4ee5\u4f7f\u7528\u540c\u65f6\u63d0\u53ca\u5230\u7684\u7b49\u6548\u65b9\u6cd5
"},{"location":"begin/preference/#_2","title":"\u7b80\u5355\u4e86\u89e3\u9879\u76ee\u6587\u4ef6","text":"\u5728\u89e3\u51b3\u65b9\u6848\u8d44\u6e90\u7ba1\u7406\u5668\u4e2d, \u53cc\u51fb\u4f60\u7684\u9879\u76ee, \u6309\u7406\u6765\u8bf4\u4f60\u5e94\u8be5\u4f1a\u6253\u5f00\u8be5\u9879\u76ee\u7684 .csproj
\u6587\u4ef6, \u901a\u5e38\u4e5f\u53eb\u505a\u9879\u76ee\u6587\u4ef6, \u5b83\u63cf\u8ff0\u4e86\u8fd9\u4e2a\u9879\u76ee\u7684\u5404\u65b9\u9762\u7684\u4fe1\u606f, \u5e76\u4e14\u4ee5\u4e0b\u51e0\u5c0f\u8282\u7684\u5185\u5bb9\u4e5f\u4f9d\u8d56\u4e8e\u6b64. \u5982\u679c\u4f60\u4f7f\u7528\u7684\u662f\u4ece\u6a21\u677f\u914d\u7f6e\u7684\u73af\u5883, \u90a3\u4e48\u4f60\u5e94\u8be5\u4f1a\u770b\u5230\u5982\u4e0b\u5185\u5bb9:
.csproj<Project Sdk=\"Microsoft.NET.Sdk\">\n <Import Project=\"CelesteMod.props\" />\n <Import Project=\"Common.props\" />\n <PropertyGroup>\n <RootNamespace>$(AssemblyName)</RootNamespace>\n <LangVersion>preview</LangVersion>\n </PropertyGroup>\n\n <ItemGroup>\n <Reference Include=\"System\" />\n <Reference Include=\"System.Core\" />\n <Reference Include=\"System.Xml.Linq\" />\n <Reference Include=\"System.Xml\" />\n </ItemGroup>\n\n <Import Project=\"CelesteMod.targets\" />\n</Project>\n
Note
\u8fd9\u4e2a\u6587\u4ef6\u662f XML \u683c\u5f0f\u7684, \u5982\u679c\u4f60\u4e0d\u719f\u6089 XML \u7684\u8bdd\u4f60\u53ef\u4ee5\u5230\u8fd9\u91cc\u7b80\u5355\u770b\u4e00\u4e0b, \u514d\u5f97\u4f60\u4e0d\u77e5\u9053\u6211\u4eec\u8ba8\u8bba\u7684\u4e1c\u897f\u90fd\u662f\u4ec0\u4e48
\u5176\u4e2d\u6211\u4eec\u53ea\u9700\u8981\u5173\u6ce8\u91cc\u9762\u7684 PropertyGroup
\u4ee5\u53ca ItemGroup
\u8282\u70b9 PropertyGroup
\u8282\u70b9\u5b9a\u4e49\u4e86\u8fd9\u4e2a\u9879\u76ee\u6709\u54ea\u4e9b\u5c5e\u6027, \u6bd4\u5982\u9879\u76ee\u6846\u67b6\u7248\u672c, \u8bed\u8a00\u7248\u672c, \u7a0b\u5e8f\u96c6\u6635\u79f0\u7b49 ItemGroup
\u5219\u5b9a\u4e49\u4e86\u8fd9\u4e2a\u9879\u76ee\u5305\u542b\u4ec0\u4e48, \u6bd4\u5982\u5f15\u7528\u4e86\u54ea\u4e9b\u7a0b\u5e8f\u96c6\u3001\u54ea\u4e9b nuget \u5305\u7b49.
"},{"location":"begin/preference/#implicit-usings-using","title":"Implicit Usings (\u9690\u5f0f Using)","text":"Note
\u5bf9\u4e8e\u901a\u8fc7\u6a21\u677f\u6784\u5efa\u7684\u9879\u76ee\u6765\u8bf4\u8fd9\u4e00\u6b65\u5df2\u7ecf\u5b8c\u6210, \u4f60\u53ef\u4ee5\u5c1d\u8bd5\u5c06 Common.props
\u4e2d\u7684 CommonCelesteUsings
\u66f4\u6539\u4e3a false
\u6765\u611f\u53d7\u6ca1\u6709\u542f\u7528\u7684\u6548\u679c
\u73b0\u5728\u770b\u770b\u4f60\u7684\u6e90\u6587\u4ef6\u5934\u9876\u662f\u4e0d\u662f\u5145\u6ee1\u4e86\u4e00\u5927\u5806 using xxx
? \u90a3\u5c31\u5bf9\u4e86, \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e2a\u7279\u6027\u6765\u8ba9\u5b83\u770b\u8d77\u6765\u66f4\u7b80\u4ecb\u4e9b. \u90a3\u4e48\u6253\u5f00\u4f60\u7684\u9879\u76ee\u6587\u4ef6, \u5411\u4f60\u7684 ItemGroup
\u4e2d\u52a0\u5165\u8fd9\u4e9b:
<Using Include=\"System\"/>\n<Using Include=\"System.Collections.Generic\"/>\n<Using Include=\"System.IO\"/>\n<Using Include=\"System.Linq\"/>\n<Using Include=\"System.Threading\"/>\n<Using Include=\"System.Threading.Tasks\"/>\n
\u8fd9\u4e2a\u65f6\u5019\u4f60\u5c31\u53ef\u4ee5\u79fb\u9664\u4f60\u7684\u5927\u90e8\u5206 System
\u5f00\u5934\u7684 Using \u8bed\u53e5\u5566, \u8fd9\u88ab\u79f0\u4e3a \u9690\u5f0f Using
, \u56e0\u4e3a\u6211\u4eec\u662f\u851a\u84dd mod, \u6240\u4ee5\u6211\u4eec\u7ecf\u5e38\u4e5f\u4f1a Using \u4ee5\u4e0b\u51e0\u4e2a\u547d\u540d\u7a7a\u95f4:
Celeste.Mod
: \u5305\u542b\u5f88\u591a Everest \u76f8\u5173\u4e1c\u897f Celeste
: \u851a\u84dd\u672c\u4f53\u6240\u5728\u547d\u540d\u7a7a\u95f4 Monocle
: \u851a\u84dd\u81ea\u5df1\u7684\u6e38\u620f\u5f15\u64ce Microsoft.Xna.Framework
: \u851a\u84dd\u81ea\u5df1\u7684\u6e38\u620f\u5f15\u64ce\u7684\u5e95\u5c42\u6846\u67b6 \u5bf9\u8fd9\u4e9b\u9690\u5f0f Using \u6211\u4eec\u4e5f\u5411 ItemGroup
\u52a0\u5165:
<Using Include=\"Celeste.Mod\"/>\n<Using Include=\"Celeste\"/>\n<Using Include=\"Monocle\"/>\n<Using Include=\"Microsoft.Xna.Framework\"/>\n
\u73b0\u5728\u6253\u5f00\u4f60\u7684\u4ee3\u7801\u6587\u4ef6, \u4f60\u53ef\u4ee5\u5c06\u5934\u9876\u4e0a\u7684\u5927\u90e8\u5206 Using \u90fd\u5220\u9664\u4e86, \u8fd9\u6837, \u4f60\u7684\u4ee3\u7801\u6587\u4ef6\u53d8\u7684\u66f4\u52a0\u7684\u5e72\u51c0\u6574\u6d01: MyModModule.cs
namespace MyCelesteMod\n{\n public class MyModModule : EverestModule\n {\n public override void Load()\n {\n\n Logger.Log(LogLevel.Info, \"MyCelesteMod\", \"Hello World! Hello Everest!\");\n }\n\n public override void Unload()\n {\n\n }\n }\n}\n
"},{"location":"begin/preference/#file-scoped-namespaces","title":"File Scoped Namespaces","text":"\u5bf9\u4e8e namespace \u547d\u540d\u7a7a\u95f4\u6765\u8bf4\u6211\u4eec\u901a\u5e38\u4e00\u4e2a\u6587\u4ef6\u53ea\u6709\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4, \u90a3\u4e48\u6700\u5916\u5c42\u7684 namespace \u7684\u7f29\u8fdb\u5c31\u6709\u4e9b\u6d6a\u8d39\u6a2a\u5411\u7a7a\u95f4, \u6240\u4ee5\u6211\u4eec\u9009\u62e9\u4f7f\u7528 File Scoped Namespaces
, \u8fd9\u5f88\u7b80\u5355:
\u5728 namespace MyCelesteMod
\u540e\u52a0\u4e0a\u4e00\u4e2a\u5206\u53f7 \u5220\u9664 namespace \u7684\u4e24\u4e2a\u5927\u62ec\u53f7 \u56de\u9000 namespace \u4e0b\u7684\u6240\u6709\u7f29\u8fdb \u641e\u5b9a\u4e86, \u8d70\u4f60! MyModModule.csnamespace MyCelesteMod;\n\npublic class MyModModule : EverestModule\n{\n public override void Load()\n {\n Logger.Log(LogLevel.Info, \"MyCelesteMod\", \"Hello World! Hello Everest!\");\n }\n\n public override void Unload()\n {\n\n }\n}\n
Info
\u5982\u679c\u4f60\u6536\u5230\u9519\u8bef CS8370
, \u90a3\u4f60\u53ef\u80fd\u9700\u8981\u5728 PropertyGroup
\u4e0b\u6dfb\u52a0\u8fd9\u4e00\u884c:
<LangVersion>preview</LangVersion>\n
"},{"location":"begin/preference/#_3","title":"\u65b9\u6cd5? \u51fd\u6570?","text":"\u55ef\u8fd9\u4e2a\u662f\u540e\u6765\u52a0\u7684, \u56e0\u4e3a\u6211\u53d1\u73b0\u6211\u5728\u6574\u4e2a\u6587\u6863\u91cc\u90fd\u5728\u6df7\u7528 \"\u65b9\u6cd5\" \u548c \"\u51fd\u6570\" \u8fd9\u4e24\u4e2a\u540d\u5b57, \u4f46\u662f\u4fee\u6539\u8d77\u6765\u6bd4\u8f83\u9ebb\u70e6\u6240\u4ee5\u6211\u8fd8\u662f\u9009\u62e9\u5728\u8fd9\u91cc\u8bf4\u51e0\u53e5: \"\u51fd\u6570\" \u662f\u6e90\u81ea\u53e4\u65e9\u7684\u9762\u5411\u8fc7\u7a0b\u8bed\u8a00\u7684\u6982\u5ff5, \u540e\u6765\u968f\u7740 OOP \u9762\u5411\u5bf9\u8c61\u601d\u60f3\u7684\u6d41\u884c, \u51fd\u6570\u9010\u6e10\u88ab\u5c01\u88c5\u5230\u7c7b\u91cc, \u800c\u7c7b\u91cc\u7684\u8fd9\u4e9b\u51fd\u6570\u5728\u4e60\u60ef\u4e0a\u6211\u4eec\u624d\u4f1a\u79f0\u4e4b\u4e3a \"\u65b9\u6cd5\", \u4f46\u662f\u4e5f\u6709\u4eba\u4ecd\u7136\u5c06\u8fd9\u4e9b\u4e1c\u897f\u79f0\u4e4b\u4e3a \"\u51fd\u6570\", \u6240\u4ee5\u5b9e\u9645\u4e0a\u5728\u9762\u5411\u5bf9\u8c61\u7684\u8bed\u8a00\u91cc\u4f60\u53ef\u4ee5\u5c06 \"\u65b9\u6cd5\" \u548c \"\u51fd\u6570\" \u770b\u4e3a\u4e00\u4e2a\u4e1c\u897f, \u6216\u8005\u4ec5\u5728\u672c\u6587\u6863\u4e2d\u8fd9\u4e48\u770b.
"},{"location":"begin/reading_2/","title":"\u9605\u8bfb\u4ee3\u7801 II","text":"\u4e00\u4e9b\u60c5\u51b5\u4e0b, \u9605\u8bfb\u7531\u53cd\u7f16\u8bd1\u5668\u751f\u6210\u7684\u4ee3\u7801\u65f6\u53ef\u80fd\u4e0d\u662f\u90a3\u4e48\u987a\u5229, \u90a3\u4e48\u8fd9\u4e00\u8282\u4f1a\u7b80\u5355\u8bf4\u4e00\u4e9b\u53cd\u7f16\u8bd1\u5668\u751f\u6210\u7684\u4ee3\u7801\u4e0e\u901a\u5e38\u7684 C# \u4ee3\u7801\u4e0d\u4e00\u6837\u7684\u5730\u65b9.
"},{"location":"begin/reading_2/#_1","title":"\u5947\u5947\u602a\u602a\u7684\u6635\u79f0\u4e0e\u4ee3\u7801","text":"\u5728\u53cd\u7f16\u8bd1\u5668\u4e2d\u53ef\u80fd\u4f1a\u51fa\u73b0\u8fd9\u79cd\u5947\u602a\u7684\u8bed\u6cd5: Celeste.FinalBoss (\u5373 6a \u540e\u534a\u6bb5 Badeline Boss \u5b9e\u4f53)
public void orig_ctor(EntityData e, Vector2 offset)\n{\n this..ctor(e.Position + offset, e.NodesOffset(offset), e.Int(\"patternIndex\", 0), e.Float(\"cameraPastY\", 120f), e.Bool(\"dialog\", false), e.Bool(\"startHit\", false), e.Bool(\"cameraLockY\", true));\n}\n
\u55ef...\u597d\u7684, \u9996\u5148 orig_ctor
\u8fd9\u4e2a\u540d\u5b57\u6709\u70b9\u602a\u4f46\u662f\u80fd\u63a5\u53d7, \u4f46\u662f\u63a5\u4e0b\u6765\u7684 this..ctor
\u662f\u4ec0\u4e48? \u5b83\u751a\u81f3\u5728 C#
\u4e2d\u662f\u4e2a\u975e\u6cd5\u8bed\u6cd5! \u5176\u5b9e\u8fd9\u5e76\u4e0d\u7f55\u89c1, \u7531\u4e8e Everest \u5bf9\u851a\u84dd\u7a0b\u5e8f\u7684\u4fee\u6539\u5e76\u4e0d\u53ea\u662f\u505c\u7559\u5728\u8868\u9762, \u800c\u66f4\u662f\u6df1\u5165\u5230\u4e86 IL \u4ee3\u7801\u5c42, \u8fd9\u662f\u4e00\u79cd\u76f8\u5bf9\u5e95\u5c42\u7684\u4ee3\u7801, \u4f60\u7684 C#
\u4ee3\u7801\u6700\u7ec8\u90fd\u4f1a\u88ab\u7f16\u8bd1\u4e3a IL
\u7136\u540e\u6254\u7ed9\u8fd0\u884c\u65f6(runtime)\u6765\u6267\u884c, \u540c\u6837\u5730, \u6240\u6709\u5176\u4ed6\u7684 .NET
\u7cfb\u8bed\u8a00\u6bd4\u5982 VB.NET
\u548c F#
\u4e5f\u90fd\u4f1a\u88ab\u7f16\u8bd1\u4e3a IL. \u90a3\u4e48\u65e2\u7136\u8fd9\u91cc\u7684 IL \u662f\u7531 C#
\u7f16\u8bd1\u800c\u6765\u7684, \u90a3\u4e48\u8fd9\u6837\u7684 IL \u591a\u591a\u5c11\u5c11\u4f1a\u6709\u4e00\u79cd \"C# \u5473\", \u53cd\u7f16\u8bd1\u5668\u5c31\u662f\u9760\u8fd9\u79cd\u4e00\u5b9a\u7684 \"C# \u5473\" \u6765\u9006\u63a8\u51fa\u53ef\u80fd\u7684 C#
\u6e90\u7801. \u4f46\u662f\u65e2\u7136\u8fd9\u91cc Everest \u76f4\u63a5\u5728 IL \u4ee3\u7801\u5c42\u8fdb\u884c\u4e86\u4fee\u6539, \u7834\u574f\u4e86\u8fd9\u79cd \"C# \u5473\", \u90a3\u81ea\u7136\u53cd\u7f16\u8bd1\u5668\u5c31\u4f1a\u751f\u6210\u5947\u5947\u602a\u602a\u751a\u81f3\u975e\u6cd5\u7684\u4ee3\u7801.
\u90a3\u4e48\u8fd9\u91cc\u751f\u6210\u7684\u5947\u602a\u975e\u6cd5\u7684\u4ee3\u7801\u662f\u4ec0\u4e48?
"},{"location":"begin/reading_2/#ctor-cctor","title":".ctor / .cctor","text":".ctor
\u662f\u4e00\u4e2a\u7279\u6b8a\u7684\u51fd\u6570\u540d\u79f0, \u8868\u793a\u8be5\u7c7b\u7684\u6784\u9020\u51fd\u6570, \u6bd4\u5982 Player..ctor(a, b)
\u5373\u8868\u793a\u8c03\u7528 Player
\u7c7b\u7684 .ctor
\u51fd\u6570, \u867d\u7136\u4f60\u81ea\u5df1\u662f\u505a\u4e0d\u5230\u7684.
.cctor
\u4e5f\u662f\u4e00\u4e2a\u7279\u6b8a\u7684\u51fd\u6570\u540d\u79f0, \u8868\u793a\u8be5\u7c7b\u7684\u9759\u6001\u6784\u9020\u51fd\u6570, \u6bd4\u5982 Input..cctor()
\u5373\u8868\u793a\u8c03\u7528 Input
\u7c7b\u7684\u65e0\u53c2\u9759\u6001\u6784\u9020\u51fd\u6570.
\u8fd9\u4e00\u7c7b\u51fd\u6570\u5728 IL
\u5c42\u6709\u4e2a\u6807\u8bb0\u53eb special name
, \u5f53\u53cd\u7f16\u8bd1\u5668\u53d1\u73b0\u4e00\u4e2a\u65b9\u6cd5\u540d\u4e3a .ctor
\u4e14\u5e26\u6709 special name
\u6807\u8bb0\u7684\u65b9\u6cd5\u65f6, \u53cd\u7f16\u8bd1\u5668\u5c31\u4f1a\u8ba4\u4e3a\u5b83\u662f\u4e00\u4e2a\u6784\u9020\u51fd\u6570, \u5982\u679c\u53cd\u7f16\u8bd1\u5668\u53d1\u73b0\u8fd9\u4e2a\u65b9\u6cd5\u5728\u4e00\u4e2a\u6784\u9020\u51fd\u6570\u5f00\u5934\u8c03\u7528\u4e86, \u90a3\u4e48\u53cd\u7f16\u8bd1\u5668\u5c31\u4f1a\u8ba4\u4e3a\u8fd9\u4e2a\u6784\u9020\u51fd\u6570\u5e26\u4e00\u4e2a\u6784\u9020\u51fd\u6570\u94fe, \u4f46\u662f\u5982\u679c\u5b83\u7684\u8c03\u7528\u4f4d\u7f6e\u5728\u5176\u4ed6\u4f4d\u7f6e, \u540c\u65f6\u53c8\u56e0\u4e3a C#
\u7f16\u8bd1\u5668\u662f\u4e0d\u53ef\u80fd\u8fd9\u4e48\u7f16\u8bd1\u7684, \u90a3\u4e48\u53cd\u7f16\u8bd1\u5668\u5c31\u4f1a\u4e0d\u77e5\u6240\u63aa, \u53ea\u80fd\u65e0\u5948\u7684\u751f\u6210 xxx..ctor()
\u8fd9\u79cd\u9519\u8bef\u7684\u8bed\u6cd5. \u8fd9\u4e5f\u662f\u6211\u4eec\u4e0a\u9762\u770b\u5230\u7684 this..ctor
\u8fd9\u79cd\u8bed\u6cd5\u88ab\u751f\u6210\u7684\u539f\u56e0, \u56e0\u4e3a\u8fd9\u4e2a\u6784\u9020\u51fd\u6570\u8c03\u7528\u4e0d\u5728\u6784\u9020\u51fd\u6570\u91cc\u51fa\u73b0, \u800c\u662f\u5728\u4e00\u4e2a\u6b63\u5e38\u7684 orig_ctor
\u65b9\u6cd5\u91cc\u9762!
Info
ctor
\u8fd9\u4e2a\u5947\u602a\u7684\u7f29\u5199\u6765\u81ea\u5355\u8bcd constructor
, \u76f4\u8bd1\u5373 \u6784\u9020\u5668
.
\u6240\u4ee5\u6211\u4eec\u901a\u5e38\u4e5f\u4f1a\u7528 .ctor
ctor
\u6765\u6307\u4ee3\u6784\u9020\u51fd\u6570, .cctor
cctor
\u6307\u4ee3\u9759\u6001\u6784\u9020\u51fd\u6570. \u6b64\u5916, Visual Studio \u4e2d\u6709\u4e2a\u81ea\u5e26\u7684\u4ee3\u7801\u7247\u6bb5\u5c31\u662f ctor
, \u5728\u7c7b\u4e2d\u6253\u51fa ctor \u5e76\u53cc\u51fb Tab \u952e, vs \u5c31\u4f1a\u81ea\u52a8\u751f\u6210\u8be5\u7c7b\u7684\u6784\u9020\u51fd\u6570, \u8fd9\u91cc\u7684 ctor
\u6765\u6e90\u4e5f\u5c31\u5728\u6b64.
Info
\u5728\u524d\u9762\u7684\u94a9\u5b50\u8282\u6211\u4eec\u6ca1\u6709\u63a2\u8ba8\u8fc7\u6784\u9020\u51fd\u6570\u5982\u4f55\u94a9\u53d6, \u5728\u8fd9\u91cc\u4f60\u53ef\u80fd\u5c31\u4f1a\u660e\u767d, \u94a9\u53d6\u540d\u5b57\u4e3a ctor
\u7684\u51fd\u6570\u5c31\u662f\u94a9\u53d6\u4e86\u6784\u9020\u51fd\u6570, \u9759\u6001\u6784\u9020\u51fd\u6570\u540c\u7406.
"},{"location":"begin/reading_2/#orig_","title":"orig_*","text":"\u8fd8\u6709\u4e00\u4e9b\u51fd\u6570\u4ee5 orig_
\u5f00\u5934, \u8fd9\u5176\u5b9e\u662f everest \u81ea\u5df1\"\u94a9\u53d6\"\u7684\u51fd\u6570. \u5728\u8fd9\u91cc, \u6bd4\u5982 Player.Update
\u65b9\u6cd5\u5c31\u88ab everest \u8fdb\u884c\u4e86\"\u94a9\u53d6\", \u800c\u94a9\u5b50\u51fd\u6570\u672c\u4f53\u5c31\u662f Player.Update
, \u800c\u5bf9\u5e94\u6211\u4eec\u94a9\u5b50\u7684 orig
\u59d4\u6258\u5728\u5c31\u4f53\u73b0\u4e3a orig_Update
\u65b9\u6cd5.
Player.Update (\u50cf\u94a9\u5b50\u672c\u4f53\u4e00\u6837!)public override void Update()\n{\n this.orig_Update(); // \u5c31\u50cf\u5728\u6211\u4eec\u7684\u94a9\u5b50\u91cc\u8c03\u7528 orig \u59d4\u6258\u4e00\u6837\n // \u5c31\u50cf\u5728\u6211\u4eec\u7684\u94a9\u5b50\u91cc\u5728\u51fd\u6570\u6267\u884c\u5b8c\u540e\u505a\u4e9b\u4e8b\u60c5\u4e00\u6837\n Level level = base.Scene as Level;\n if (level == null)\n ......\n}\n// Player.orig_Update() \u5c31\u50cf\u6211\u4eec\u7684\u94a9\u5b50\u94a9\u53d6\u7684\u539f\u51fd\u6570!\n
Info
\u5982\u679c\u4f60\u81ea\u884c\u94a9\u53d6 Player.Update
\u51fd\u6570\u8fd9\u79cd\u5df2\u88ab everest \"\u94a9\u53d6\" \u7684\u51fd\u6570\u5b9e\u9645\u4e0a\u4f60\u94a9\u53d6\u7684\u662f everest \u7684\u94a9\u5b50, \u8fd9\u5bf9\u4e8e On
\u94a9\u5b50\u53ef\u80fd\u6ca1\u6709\u5927\u5f71\u54cd, \u4f46\u662f\u5bf9\u4e8e\u540e\u9762\u6211\u4eec\u4f1a\u8bf4\u7684 IL
\u94a9\u5b50\u6709\u5f88\u5927\u5f71\u54cd, \u4e0d\u8fc7\u8fd9\u4e9b\u6211\u4eec\u7b49\u5230\u540e\u9762\u518d\u8bf4.
"},{"location":"begin/reading_2/#statemachine","title":"StateMachine","text":"\u8fd9\u662f Monocle \u4e2d\u7684\u4e00\u4e2a Component \u7c7b, \u662f\u4e00\u4e2a\u72b6\u6001\u673a\u7684\u5b9e\u73b0, \u5177\u4f53\u7684\u7528\u6cd5\u6211\u4f1a\u5728 \u5e38\u89c1 Celeste, Monocle \u7c7b\u5728\u5199\u4e86.jpg \u8282\u8bf4, \u8fd9\u91cc\u4ec5\u662f\u65b9\u4fbf\u4f60\u9605\u8bfb\u4e00\u4e0b\u76f8\u5173\u7684\u4ee3\u7801:
"},{"location":"begin/reading_2/#st","title":"St*
\u7c7b\u5b57\u6bb5","text":"\u5728\u9605\u8bfb Player
\u7c7b\u7684\u4ee3\u7801\u65f6, \u4f60\u4f1a\u770b\u5230\u8fd9\u4e9bSt
\u5f00\u5934\u540d\u5b57\u7684\u5e38\u91cf\u4f46\u662f\u4f60\u627e\u4e0d\u5230\"\u88ab\u4f7f\u7528\"\u7684\u5730\u65b9:
const int StNormal = 0; const int StClimb = 1; const int StDash = 2; const int StSwim = 3; const int StBoost = 4; ...... \u8fd9\u4e9b\u662f\u73a9\u5bb6\u72b6\u6001\u673a\u7684\u72b6\u6001\u7f16\u53f7, \u81f3\u4e8e\u4f60\u627e\u4e0d\u5230\"\u88ab\u4f7f\u7528\"\u662f\u56e0\u4e3a\u5bf9\u4e8e const \u5e38\u91cf\u6210\u5458, c# \u7f16\u8bd1\u5668\u5728\u7f16\u8bd1\u671f\u5c31\u628a\u5f15\u7528\u7684\u8fd9\u4e9b\u4e1c\u897f\u76f4\u63a5\u66ff\u6362\u4e3a\u4e86\u6570\u5b57, \u4f60\u80fd\u770b\u5230\u7684\u53ea\u6709\u4fdd\u7559\u4e0b\u6765\u7684\u8fd9\u4e9b\u5e38\u91cf\u7684\u503c\u548c\u540d\u5b57. \u90a3\u8fd9\u6837\u4ee3\u7801\u4e2d\u5c31\u4e0d\u907f\u514d\u7684\u51fa\u73b0\u4e86\u5947\u602a\u7684\u9b54\u6570, \u6bd4\u5982\u8fd9\u91cc\u7684 24: int Player.FlingBirdUpdate()
private int FlingBirdUpdate()\n{\n base.MoveTowardsX(this.flingBird.X, 250f * Engine.DeltaTime, null);\n base.MoveTowardsY(this.flingBird.Y + 8f + base.Collider.Height, 250f * Engine.DeltaTime, null);\n return 24;\n}\n
Info
FlingBirdUpdate \u662f\u4e00\u4e2a\u72b6\u6001\u673a\u7684 Update \u51fd\u6570, \u6240\u6709\u8be5\u7c7b\u51fd\u6570\u7684\u8fd4\u56de\u503c\u8868\u793a\u4e0b\u4e00\u5e27\u73a9\u5bb6\u7684\u72b6\u6001\u5e94\u8be5\u662f\u4ec0\u4e48.
\u4f60\u80af\u5b9a\u5f88\u7591\u60d1\u8fd9\u4e2a\u5947\u602a\u7684 24 \u662f\u4ec0\u4e48, \u8fd9\u91cc\u6211\u4eec\u5df2\u7ecf\u77e5\u9053\u5b83\u662f\u4e2a\u72b6\u6001\u673a\u7f16\u53f7\u4e86, \u6211\u4eec\u53ea\u9700\u8981\u4e00\u4e0b\u8fd9\u4e2a\u7f16\u53f7\u5bf9\u5e94\u7684\u72b6\u6001. \u7ecf\u8fc7\u67e5\u8be2, \u4f60\u4f1a\u77e5\u9053\u7f16\u53f7\u4e3a 24 \u7684\u72b6\u6001\u662f StFlingBird
, \u5373\u88ab\u9e1f\u6254\u72b6\u6001(\u7b26\u5408\u8fd9\u91cc\u7684\u51fd\u6570\u540d!):
const int StFlingBird = 24;\n
\u5728\u8fd9\u91cc\u4f1a\u7b80\u5355\u5217\u51fa\u4e00\u4e0b Player
\u7684\u6240\u6709\u72b6\u6001\u4fbf\u4e8e\u67e5\u8be2:
const int StNormal = 0; // \u6b63\u5e38\nconst int StClimb = 1; // \u6500\u722c\nconst int StDash = 2; // \u51b2\u523a\nconst int StSwim = 3; // \u6c34\u4e2d\nconst int StBoost = 4; // \u7eff\u6ce1\u6ce1\u4e2d\nconst int StRedDash = 5; // \u7ea2\u6ce1\u6ce1\u4e2d\nconst int StHitSquash = 6; // \u7ea2\u6ce1\u6ce1\u649e\u5899\u6216\u649e\u5730\nconst int StLaunch = 7; // \u88ab \u5f39\u7403, \u9c7c \u5f39\u5f00\nconst int StPickup = 8; // \u6361\u8d77\u6293\u53d6\u7269\nconst int StDreamDash = 9; // \u7a7f\u679c\u51bb\nconst int StSummitLaunch = 10; // badeline\u6700\u540e\u4e00\u6b21\u4e0a\u629b\nconst int StDummy = 11; // \u5267\u60c5\u8fc7\u573a\u72b6\u6001\nconst int StIntroWalk = 12; // Walk \u7c7b\u578b\u7684 Intro (Intro \u5373\u73a9\u5bb6\u8fdb\u5165\u5173\u5361\u7684\u8868\u73b0\u65b9\u5f0f)\nconst int StIntroJump = 13; // Jump \u7c7b\u578b\u7684 Intro (1a)\nconst int StIntroRespawn = 14; // Respawn \u7c7b\u578b\u7684 Intro (\u91cd\u751f)\nconst int StIntroWakeUp = 15; // WakeUp \u7c7b\u578b\u7684 Intro (2a awake)\nconst int StBirdDashTutorial = 16; // \u5e8f\u7ae0\u6559\u51b2\u523a\u65f6\u51b2\u523a\u7ed3\u675f\u540e\u8fdb\u5165\u7684\u72b6\u6001\nconst int StFrozen = 17; // \u672a\u77e5\nconst int StReflectionFall = 18; // 6a-2 \u6389\u843d\u5267\u60c5\u6bb5\nconst int StStarFly = 19; // \u7fbd\u6bdb\u98de\u884c\nconst int StTempleFall = 20; // 5a \u955c\u5b50\u540e\u7684\u6389\u843d\u6bb5\nconst int StCassetteFly = 21; // \u6361\u5230\u78c1\u5e26\u540e\u7684\u6ce1\u6ce1\u5305\u88f9\u6bb5\nconst int StAttract = 22; // 6a badeline boss \u9760\u8fd1\u65f6\u7684\u5438\u5f15\u6bb5\nconst int StIntroMoonJump = 23; // 9a \u5f00\u573a\u4e0a\u5347\u5267\u60c5\u6bb5\nconst int StFlingBird = 24; // 9a \u9e1f\u6254\u72b6\u6001\nconst int StIntroThinkForABit = 25; // 9a Intro\n
"},{"location":"begin/simple_entity/","title":"\u7b80\u5355\u81ea\u5b9a\u4e49\u5b9e\u4f53","text":"\u5728\u77e5\u9053\u4e00\u4e9b mod \u5236\u4f5c\u4e2d\u6700\u4e3a\u57fa\u7840\u7684\u4e1c\u897f\u540e, \u6211\u4eec\u9996\u5148\u628a\u5174\u8da3\u70b9\u8f6c\u5411\u81ea\u5b9a\u4e49\u5b9e\u4f53, \u76f8\u4fe1\u76f8\u5bf9\u4e8e\u4fee\u6539\u5df2\u6709\u7684\u4e1c\u897f\u5e76\u4f34\u968f\u7740\u4e00\u5b9a\u7684\u70e7\u8111(\u6211\u8be5\u600e\u4e48\u6539? \u8fd9\u4e48\u6539\u4f1a\u4e0d\u4f1a\u7834\u574f\u5b98\u56fe\u5143\u7d20?), \u4f60\u53ef\u80fd\u66f4\u559c\u6b22\u81ea\u5df1\u5236\u4f5c\u4e00\u4e2a\u5b9e\u4f53, \u90a3\u5c31\u5bf9\u4e86! \u5728\u8fd9\u4e00\u8282, \u6211\u4eec\u4f1a\u4e86\u89e3 loenn \u7684\u57fa\u7840\u4f7f\u7528\u3001\u6dfb\u52a0\u4e00\u4e2a\u81ea\u5b9a\u4e49\u5b9e\u4f53\u7684\u901a\u7528\u6b65\u9aa4, \u4ee5\u53ca\u4e00\u4e9b\u6e38\u620f\u5e38\u7528\u7684\u65b9\u6cd5!
"},{"location":"begin/simple_entity/#_2","title":"\u6211\u4eec\u7684\u81ea\u5b9a\u4e49\u5b9e\u4f53\u7c7b","text":""},{"location":"begin/simple_entity/#_3","title":"\u5b83\u80fd\u5e72\u4ec0\u4e48","text":"\u5728\u5f00\u59cb\u5236\u4f5c\u8fd9\u4e2a\u81ea\u5b9a\u4e49\u5b9e\u4f53\u4e4b\u524d, \u6211\u4eec\u5148\u660e\u767d\u4e00\u4e0b\u8fd9\u4e2a\u5b9e\u4f53\u505a\u51fa\u6765\u662f\u4ec0\u4e48\u6548\u679c\u7684. \u90a3\u4e48, \u4e3a\u4e86\u7b80\u5355\u8d77\u89c1, \u8fd9\u91cc\u5c31\u505a\u4e00\u4e2a\u7b80\u5355\u7684\u529f\u80fd, \u5b83\u5927\u6982\u662f:
\u5b83\u53eb\u505a PassByRefill
\u957f\u5ea6\u548c\u5bbd\u5ea6\u662f\u968f\u610f\u7684 \u5b83\u770b\u8d77\u6765\u662f\u4e2a\u900f\u660e\u7684\u7ea2\u8272\u7269\u4f53 \u73a9\u5bb6\u4e0e\u5176\u78b0\u649e\u65f6\u4f1a\u9501\u5b9a\u4e3a\u67d0\u4e2a\u51b2\u523a\u6570 \u8fd9\u4e2a\u51b2\u523a\u6570\u53ef\u4ee5\u5728\u4f5c\u56fe\u8f6f\u4ef6\u4e2d\u8bbe\u7f6e \u662f\u7684\u5c31\u8fd9\u6837\u7b80\u5355, \u90a3\u4e48\u6211\u4eec\u5f00\u59cb\u5427.
"},{"location":"begin/simple_entity/#_4","title":"\u58f0\u660e\u8fd9\u4e2a\u7c7b","text":"Warning
\u5728\u524d\u9762\u6211\u4eec\u94a9\u53d6\u4e86 Player.Update()
\u5e76\u4e14\u5728\u4e00\u76f4\u4fee\u6539\u51b2\u523a\u6570\u4e3a 1! \u4e0d\u8981\u5fd8\u8bb0\u628a\u94a9\u5b50\u51fd\u6570\u4ee5\u53ca\u94a9\u53d6\u548c\u53d6\u6d88\u94a9\u53d6\u7684\u90a3\u4e9b\u4ee3\u7801\u5220\u6389, \u6700\u540e\u4f60\u7684 Module \u7c7b\u5e94\u8be5\u53ea\u5305\u542b\u4e24\u4e2a\u7a7a\u7684 Load
\u548c Unload
\u65b9\u6cd5!
\u9996\u5148\u5728\u4ee3\u7801\u4e2d, \u6211\u4eec\u9700\u8981\u58f0\u660e\u8fd9\u4e2a\u7c7b, \u4e5f\u5c31\u662f\u521b\u5efa\u4e00\u4e2a .cs \u6587\u4ef6, \u7136\u540e\u547d\u4e2a\u540d. \u5728\u8fd9\u91cc\u4f60\u8fd8\u9700\u8981\u7ee7\u627f\u4e00\u4e0b Entity
, \u5728\u524d\u9762\u6211\u4eec\u5df2\u7ecf\u4e86\u89e3\u8fc7\u4e86\u5b83\u662f Monocle
\u7684\u4e00\u4e2a\u7c7b, \u8868\u793a\u573a\u666f\u4e2d\u7684\u5b9e\u4f53. \u90a3\u4e48\u4f60\u5e94\u8be5\u4f1a\u5199\u51fa\u5982\u4e0b\u7684\u4ee3\u7801:
PassByRefill.csnamespace MyCelesteMod;\n\npublic class PassByRefill : Entity\n{\n\n}\n
ok, \u63a5\u4e0b\u6765, \u6211\u4eec\u52a0\u4e00\u4e2a\u8868\u793a\u51b2\u523a\u6570\u7684\u5b57\u6bb5, \u7136\u540e\u641e\u4e00\u4e2a\u6784\u9020\u51fd\u6570\u63a5\u6536\u5e76\u8d4b\u503c\u5b83: PassByRefill.cs
public int Dashes = 0;\n\npublic PassByRefill(Vector2 position, Vector2 size, int dashes)\n{\n Position = position;\n Dashes = dashes;\n}\n
\u8fd9\u91cc\u7684 position
\u53c2\u6570\u4f1a\u88ab\u7528\u4e8e\u8bbe\u7f6e\u5b83\u7684 Position
\u5b57\u6bb5, \u8fd9\u4e2a\u5b57\u6bb5\u4ece Monocle.Entity
\u7ee7\u627f\u800c\u6765, \u5b83\u8868\u793a\u8fd9\u4e2a Entity
\u5728\u573a\u666f\u4e2d\u6240\u5728\u7684\u4f4d\u7f6e(\u4e16\u754c\u5750\u6807). Vector2
\u662f\u4e00\u4e2a XNA \u4e2d\u7684\u7ed3\u6784\u4f53, \u5305\u542b\u4e00\u4e2a X
\u548c\u4e00\u4e2a Y
\u7684 float
\u5b57\u6bb5, \u5b83\u7528\u4e8e\u63cf\u8ff0\u4e00\u4e2a\u5e73\u9762\u5411\u91cf, \u5c31\u50cf\u4f60\u5728\u5e73\u9762\u76f4\u89d2\u5750\u6807\u7cfb\u4e2d\u6240\u505a\u7684\u4e00\u6837! \u4e0d\u8fc7\u8fd9\u91cc\u9700\u8981\u6ce8\u610f, \u6e38\u620f\u4e2d\u7684\u5750\u6807\u7cfb\u548c\u6211\u4eec\u901a\u5e38\u6570\u5b66\u4e2d\u7684\u5750\u6807\u7cfb\u4e0d\u540c, \u5b83\u7684\u539f\u70b9\u5728\u5de6\u4e0a\u89d2, X \u8f74\u6c34\u5e73\u5411\u53f3\u4f46\u662f Y \u8f74\u7ad6\u76f4\u5411\u4e0b! \u8bb0\u4f4f\u4e0d\u8981\u641e\u6df7\u4e86. \u4f60\u53ef\u80fd\u6ce8\u610f\u5230\u6211\u4eec\u5e76\u6ca1\u6709\u7406 size
\u8fd9\u4e2a\u8868\u793a\u5927\u5c0f\u53c2\u6570, \u7a0d\u7b49\u4e00\u4e0b, \u6211\u4eec\u7b49\u4f1a\u5c31\u4f1a\u4f7f\u7528\u5b83\u4e86.
\u63a5\u4e0b\u6765, \u6211\u4eec\u9700\u8981\u58f0\u660e\u4e00\u4e2a\u7279\u6b8a\u7684\u6784\u9020\u51fd\u6570, \u4ee5\u8ba9 Everest \u53cd\u5c04\u8c03\u7528\u5e76\u4f7f\u5f97\u6211\u4eec\u7684\u5b9e\u4f53\u53ef\u4ee5\u6b63\u5e38\u83b7\u53d6\u5730\u56fe\u7684\u6570\u636e: PassByRefill.cs
public PassByRefill(EntityData data, Vector2 offset) \n : this(data.Position + offset, new Vector2(data.Width, data.Height), data.Int(\"dashes\"))\n { }\n
\u5728\u8fd9\u91cc, EntityData data
\u50a8\u5b58\u4e86\u4f5c\u56fe\u8f6f\u4ef6\u4fdd\u5b58\u7684\u76f8\u5173\u6570\u636e, \u6211\u4eec\u8981\u63d0\u53d6\u5b83\u4eec\u5f88\u7b80\u5355. \u6bd4\u5982\u8bf4\u6211\u4eec\u8981\u63d0\u53d6\u4e00\u4e2a\u540d\u4e3a dashes
\u7684 int
\u7c7b\u578b\u7684\u6570\u636e, \u6211\u4eec\u5c31\u7b80\u5355\u5730\u8c03\u7528\u5b83\u7684\u65b9\u6cd5 Int(string name)
, \u7136\u540e\u662f\u5b83\u7684\u5927\u5c0f\u6570\u636e, \u5927\u5c0f\u5728\u8fd9\u662f\u4e2a\u7279\u6b8a\u7684\u4e1c\u897f, \u5f97\u9700\u8981\u901a\u8fc7 Width
\u548c Height
\u5b57\u6bb5\u6765\u63d0\u53d6, \u7136\u540e\u6211\u4eec\u6254\u8fdb Vector2
\u91cc\u5e76\u4f20\u9012\u7ed9\u6211\u4eec\u4e0a\u9762\u7684\u6784\u9020\u51fd\u6570. \u5bf9\u4e8e\u66f4\u591a\u65b9\u6cd5\u4ee5\u53ca\u8fd9\u90e8\u5206\u6570\u636e\u8be5\u5982\u4f55\u81ea\u5b9a\u4e49\u6211\u4eec\u4f1a\u5728\u672c\u8282\u540e\u534a\u90e8\u5206\u8bf4\u660e. Vector2 offset
\u53c2\u6570\u8868\u793a\u8fd9\u4e00\u9762\u7684\u6700\u5de6\u4e0a\u89d2\u7684\u4e16\u754c\u5750\u6807, EntityData
\u7684 Position
\u5b57\u6bb5\u8868\u793a\u7269\u4f53\u76f8\u5bf9\u4e8e\u8fd9\u4e00\u9762\u6700\u5de6\u4e0a\u89d2\u7684\u4f4d\u7f6e, \u6240\u4ee5\u6211\u4eec\u9700\u8981\u628a\u5b83\u76f8\u52a0\u6765\u5f97\u5230\u4e16\u754c\u5750\u6807. (\u56e0\u4e3a Entity.Position
\u901a\u5e38\u53ea\u5141\u8bb8\u4e16\u754c\u5750\u6807!)
Info
\u8fd9\u4e2a\u6784\u9020\u51fd\u6570\u7684\u7b7e\u540d\u4e5f\u80fd\u4e3a\u5176\u4ed6\u7684\u6837\u5b50, \u4f46\u662f\u6211\u4eec\u6700\u6700\u6700\u5e38\u7528\u7684\u4e00\u4e2a\u7248\u672c\u5c31\u662f\u4e0a\u9762\u8fd9\u4e2a
"},{"location":"begin/simple_entity/#everest","title":"\u8ba9 Everest \u627e\u5230\u5b83","text":"\u73b0\u5728\u6211\u4eec\u53ea\u5b9a\u4e49\u4e86\u4e00\u4e2a\u7c7b Everest \u90a3\u8fb9\u662f\u5565\u4e5f\u4e0d\u77e5\u9053\u7684, \u6240\u4ee5\u6211\u4eec\u5f97\u544a\u8bc9\u5b83, \u800c\u8fd9\u4e2a\u8fc7\u7a0b\u6211\u4eec\u4e00\u822c\u5c31\u53eb \u6ce8\u518c
. \u8981\u6ce8\u518c\u4e00\u4e2a\u81ea\u5b9a\u4e49\u5b9e\u4f53\u975e\u5e38\u7b80\u5355, \u6211\u4eec\u53ea\u9700\u8981\u5c06 CustomEntity
(\u5728\u547d\u540d\u7a7a\u95f4 Celeste.Mod.Entities
\u4e2d) \u88c5\u9970\u5230\u6211\u4eec\u7684\u7c7b\u4e0a\u5e76\u4f20\u5165\u6211\u4eec\u5b9e\u4f53\u7684 \"\u540d\u79f0 ID\". \u5c31\u50cf: PassByRefill.cs
[CustomEntity(\"MyCelesteMod/PassByRefill\")]\npublic class PassByRefill : Entity\n{\n......\n
\u5728\u8fd9\u91cc \"\u540d\u79f0 ID\" \u6211\u4eec\u4e00\u822c\u63a8\u8350\u4ee5 \"{Mod\u540d}/\u8be5\u5b9e\u4f53\u7c7b\u540d\" \u8fdb\u884c\u547d\u540d, \u5c31\u50cf\u8fd9\u91cc\u4e00\u6837, Mod \u540d\u4e3a MyCelesteMod
, \u7c7b\u540d\u4e3a PassByRefill
, \u5b9e\u4f53 \"\u540d\u79f0 ID\" \u5c31\u662f MyCelesteMod/PassByRefill
. \u8fd9\u91cc\u6211\u5efa\u8bae\u4f60\u8bb0\u4f4f\u5b83, \u5f85\u4f1a\u6211\u4eec\u4f1a\u5728\u4f5c\u56fe\u8f6f\u4ef6\u914d\u7f6e\u7684\u65f6\u5019\u7528\u5230."},{"location":"begin/simple_entity/#loenn","title":"Loenn","text":"\u4f5c\u56fe\u8f6f\u4ef6
\u851a\u84dd\u7684\u4f5c\u56fe\u8f6f\u4ef6\u6700\u6d41\u884c\u7684\u76ee\u524d\u6709 ahorn
\u4e0e loenn
, \u4e0d\u8fc7\u6211\u66f4\u63a8\u8350 loenn
, \u56e0\u4e3a ahorn
\u5b9e\u5728\u662f \u592a!!\u5361!!\u4e86!!
"},{"location":"begin/simple_entity/#_5","title":"\u57fa\u7840\u4f7f\u7528","text":"Loenn \u662f\u4e00\u4e2a\u851a\u84dd\u7684\u4f5c\u56fe\u8f6f\u4ef6, \u5f53\u7136\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528\u5b83\u4e0d\u662f\u5236\u4f5c\u51fa\u7cbe\u7f8e\u7684\u5730\u56fe, \u800c\u662f\u4ec5\u4ec5\u653e\u7f6e\u4e00\u4e0b\u6211\u4eec\u7684\u81ea\u5b9a\u4e49\u5b9e\u4f53! _(:\u0437\u300d\u2220)_, \u8fd9\u91cc\u6211\u4e0d\u600e\u4e48\u60f3\u91cd\u590d\u5b83\u7684\u57fa\u7840\u4f7f\u7528, \u6240\u4ee5\u6211\u63a8\u8350\u4f60\u53bb\u4ee5\u4e0b\u51e0\u4e2a\u89c6\u9891\u4e2d\u4e86\u89e3:
Bilibili \u3010Celeste\u851a\u84dd\u3011\u7535\u7bb1\u4f5c\u56fe\u6559\u7a0b\u91cd\u7f6e\u7248 0-1 Loenn\u7684\u5b89\u88c5 Bilibili \u3010Celeste\u851a\u84dd\u3011\u7535\u7bb1\u4f5c\u56fe\u6559\u7a0b\u91cd\u7f6e\u7248 1-1 Loenn\u7684\u4f7f\u7528 \u7248\u672c
\u5982\u679c\u4f60\u4e4b\u524d\u5df2\u7ecf\u4e0b\u8f7d\u4e86 Loenn, \u6211\u5efa\u8bae\u4f60\u786e\u4fdd\u5b83\u5347\u7ea7\u5230\u6700\u65b0\u7248\u4e86, \u56e0\u4e3a\u63a5\u4e0b\u6765\u7684\u67d0\u4e9b\u4e1c\u897f\u6211\u53ef\u80fd\u4e0d\u592a\u8bb0\u5f97\u662f\u54ea\u4e2a\u7248\u672c\u5f15\u5165\u7684\u4e86.
"},{"location":"begin/simple_entity/#loenn_1","title":"\u8ba9 Loenn \u627e\u5230\u6211\u4eec\u7684\u5b9e\u4f53","text":"\u76f8\u4fe1\u4f60\u73b0\u5728\u5df2\u7ecf\u61c2\u7684 Loenn \u57fa\u672c\u7684\u4f7f\u7528\u7528\u6cd5\u4e86, \u90a3\u4e48\u73b0\u5728, \u6211\u4eec\u8981\u7ed9 Loenn \u5199\u4e00\u4e9b\u4e1c\u897f\u8ba9\u5b83\u77e5\u9053\u6211\u4eec\u8fd9\u4e2a\u5b9e\u4f53 mapper \u4eec\u80fd\u7528\u4e86. \u9996\u5148\u6211\u4eec\u5728 ModFolder \u4e0b\u65b0\u5efa\u4e00\u4e2a\u53eb Loenn
\u7684\u6587\u4ef6\u5939, \u518d\u5728\u91cc\u9762\u65b0\u5efa\u4e00\u4e2a\u53eb entities
\u7684\u6587\u4ef6\u5939, \u518d\u5728\u91cc\u9762\u65b0\u5efa\u4e00\u4e2a\u53eb PassByRefill.lua
(\u4e5f\u5c31\u662f{\u5b9e\u4f53\u7c7b\u540d}.lua
) \u7684\u6587\u672c\u6587\u4ef6. \u73b0\u5728\u4f60\u7684\u76ee\u5f55\u7ed3\u6784\u5e94\u8be5\u662f\u8fd9\u6837\u7684:
ok, \u7136\u540e\u6211\u4eec\u6253\u5f00 PassByRefill.lua
, \u8fd9\u662f\u4e00\u4e2a lua
\u8bed\u8a00\u7684\u6e90\u6587\u4ef6, \u8fd9\u91cc\u6211\u4eec\u4e0d\u9700\u8981\u5f88\u591a lua
\u77e5\u8bc6, \u76f4\u63a5\u7167\u7740\u6284\u5c31\u597d\u4e86:
PassByRefill.lualocal entity = {}\n\nentity.name = \"MyCelesteMod/PassByRefill\"\nentity.placements = {\n name = \"normal\",\n data = {\n width = 16,\n height = 16,\n dashes = 1\n }\n}\n\nreturn entity\n
\u8fd8\u8bb0\u5f97\u6211\u4eec\u4e4b\u524d\u8bb0\u4f4f\u7684\u5b9e\u4f53 \"\u540d\u79f0 ID\" \u5417? \u5728\u8fd9\u91cc\u4f60\u5c31\u9700\u8981\u5c06\u5176\u8d4b\u503c\u7ed9 entity.name
.
\u7136\u540e\u662f entity
\u7684 placements
, \u5b83\u8868\u793a\u8fd9\u4e2a\u5b9e\u4f53\u7684\u653e\u7f6e\u9009\u9879, \u5728\u8fd9\u91cc\u6211\u4eec\u5148\u4e0d\u7ba1, \u4f60\u5c31\u7406\u89e3\u4e3a\u4f60\u5e0c\u671b Loenn \u600e\u4e48\u628a\u4f60\u8fd9\u4e2a\u5b9e\u4f53\u62c6\u5206\u4e3a\u591a\u4e2a\u653e\u7f6e\u9009\u9879, \u8fd9\u91cc\u6211\u4eec\u7684\u5199\u6cd5\u8868\u793a\u4e0d\u5e0c\u671b Loenn \u62c6\u5206\u5b83, \u5982\u679c\u8fd9\u91cc\u7684 placements
\u662f\u4e2a\u6570\u7ec4\u7684\u8bdd\u90a3\u4e48 Loenn \u5c31\u4f1a\u62c6\u5206\u5b83\u4e86. \u7ee7\u7eed\u5230 name
\u5c5e\u6027, \u5b83\u8868\u793a\u8fd9\u4e2a\u653e\u7f6e\u9009\u9879\u7684\u540d\u79f0, \u8fd9\u4e2a\u540d\u79f0\u662f\u4efb\u610f\u7684, \u5b83\u53ea\u88ab\u7528\u6765\u4f5c\u4e3a\u672c\u5730\u5316\u952e\u540d(\u672c\u5730\u5316\u5c31\u5305\u62ec\u6211\u4eec\u5e38\u8bf4\u7684\"\u6c49\u5316\"). \u7136\u540e\u662f data
\u5c5e\u6027, \u5b83\u8868\u793a\u8fd9\u4e2a\u5b9e\u4f53\u7684\u6570\u636e. \u5728\u8fd9\u91cc\u6211\u4eec\u58f0\u660e\u4e86\u4e09\u4e2a\u6570\u5b57\u7c7b\u578b\u7684\u5c5e\u6027: width
, height
, dashes
, \u524d\u4e24\u4e2a\u5c5e\u6027\u662f\u7279\u6b8a\u7684, \u5728\u4ee3\u7801\u4e2d\u63d0\u53d6\u53ea\u9700\u8981\u5bf9 EntityData
\u83b7\u53d6 Width
/Height
\u5b57\u6bb5\u5373\u53ef. \u7b2c\u4e09\u4e2a dashes
\u5c5e\u6027\u5c31\u662f\u6211\u4eec\u7684\u81ea\u5b9a\u4e49\u5c5e\u6027 \u5728 data
\u5bf9\u8c61\u91cc\u7684\u5c5e\u6027, \u540e\u9762\u7684\u7b49\u53f7\u5c31\u8868\u793a\u5b83\u7684\u9ed8\u8ba4\u503c, \u6bd4\u5982 width
\u9ed8\u8ba4\u4e3a 16, dashes
\u9ed8\u8ba4\u4e3a 1.
Note
\u5982\u679c\u4f60\u4e0d\u58f0\u660e width
\u548c height
\u5c5e\u6027\u5e76\u4e14\u4e0d\u52a0\u8d34\u56fe\u7684\u8bdd Loenn \u4f3c\u4e4e\u4f1a\u76f4\u63a5\u7981\u6b62\u4f60\u653e\u7f6e\u8fd9\u4e2a\u5b9e\u4f53.
\u597d\u5427\u770b\u8d77\u6765\u4e0a\u9762\u8fd9\u4e00\u5768*\u975e\u5e38\u96be\u61c2*, \u4e0d\u8fc7\u6ca1\u5173\u7cfb, \u53ea\u8981\u4f60\u4f1a\u76f4\u63a5\u590d\u5236\u4e0a\u9762\u7684\u4e1c\u897f, \u6539\u4e00\u4e0b entity.name
, \u5411 data
\u91cc\u52a0\u4e00\u4e9b\u5c5e\u6027\u5c31\u884c\u4e86. \u5b9e\u9645\u4e0a\u6211\u4e5f\u662f\u8fd9\u4e48\u505a\u7684.
\u90a3\u4e48, \u91cd\u65b0\u7f16\u8bd1\u6211\u4eec\u7684\u9879\u76ee, \u8ba9 msbuild
\u628a\u6211\u4eec\u7684\u4e1c\u897f\u590d\u5236\u8fc7\u53bb, \u8fd9\u65f6\u6253\u5f00\u6211\u4eec\u7684 Loenn (\u6216\u8005\u91cd\u542f Loenn), \u641c\u7d22\u4e00\u4e0b @MyCelesteMod
. \u90a3\u4e48\u5217\u8868\u4e0a\u5e94\u8be5\u53ea\u4f1a\u51fa\u73b0\u4e00\u4e2a\u540d\u5b57\u5f88\u5947\u602a\u7684\u9009\u9879(\u56e0\u4e3a\u6211\u4eec\u8fd8\u6ca1\u914d\u7f6e\u672c\u5730\u5316\u76f8\u5173\u7684\u4e1c\u897f!), \u73b0\u5728\u628a\u5b83\u653e\u5230\u4efb\u4f55\u4f60\u559c\u6b22\u7684\u5730\u65b9, \u6253\u5f00\u5b83\u7684\u5c5e\u6027\u6846, \u6211\u4eec\u5c31\u80fd\u770b\u5230\u4e00\u4e2a\u5927\u5927\u7684 dashes
\u5c5e\u6027\u5728\u4e0a\u9762\u5141\u8bb8\u6211\u4eec\u6539\u5566. \u4f60\u53ef\u80fd\u6ce8\u610f\u5230\u5b83\u662f\u5168\u767d\u7684! \u56e0\u4e3a\u6211\u4eec\u8fd8\u6ca1\u544a\u8bc9 Loenn \u5b83\u957f\u4ec0\u4e48\u6837! \u4e0d\u8fc7\u8fd9\u4e2a\u7b49\u4ee5\u540e\u6211\u4eec\u518d\u6765\u641e.
"},{"location":"begin/simple_entity/#_6","title":"\u56de\u5230\u4ee3\u7801","text":"\u73b0\u5728\u5728\u6e38\u620f\u4e2d\u8fdb\u5165\u653e\u4e86\u6211\u4eec\u90a3\u4e2a\u5b9e\u4f53\u7684\u90a3\u5f20\u56fe, \u7136\u540e\u5230\u4e4b\u524d\u4f60\u559c\u6b22\u7684\u90a3\u4e2a\u5730\u65b9, \u7136\u540e... \u662f\u7684, \u4f60\u5565\u4e5f\u4e0d\u4f1a\u770b\u89c1, \u56e0\u4e3a\u6211\u4eec\u4e5f\u6ca1\u544a\u8bc9\u6e38\u620f\u5b83\u957f\u4ec0\u4e48\u6837! \u540c\u65f6\u4f60\u8d70\u5230\u5b83\u9644\u8fd1, \u4e5f\u4e0d\u4f1a\u53d1\u751f\u4efb\u4f55\u4e8b, \u56e0\u4e3a\u6211\u4eec\u4e5f\u6ca1\u544a\u8bc9\u6e38\u620f\u8fd9\u4e2a\u5b9e\u4f53\u5e94\u8be5\u5e72\u4ec0\u4e48!
"},{"location":"begin/simple_entity/#_7","title":"\u544a\u8bc9\u6e38\u620f\u5b83\u8be5\u505a\u4ec0\u4e48","text":"\u90a3\u4e48, \u5c31\u50cf\u524d\u9762\u63cf\u8ff0\u7684\u4e00\u6837, \"\u73a9\u5bb6\u4e0e\u5176\u78b0\u649e\u65f6\u4f1a\u9501\u5b9a\u4e3a\u67d0\u4e2a\u51b2\u523a\u6570\", \u90a3\u4e48\u6211\u4eec\u9700\u8981\u505a\u4e00\u4e9b\u78b0\u649e. \u5728 Monocle
\u91cc\u8fd9\u9879\u5de5\u4f5c\u5f88\u7b80\u5355, \u6211\u4eec\u9996\u5148\u5728\u6784\u9020\u51fd\u6570\u91cc\u53bb new
\u4e00\u4e2a\u957f\u65b9\u5f62\u7684\u78b0\u649e\u7bb1: PassByRefill.PassByRefill
public PassByRefill(Vector2 position, Vector2 size, int dashes)\n{\n Hitbox hitbox = new(size.X, size.Y);\n}\n
Info
\u6211\u4eec\u5728\u8fd9\u91cc\u7528\u5230\u4e86\u4e4b\u524d\u7684 size
\u53c2\u6570
Hitbox
\u5c31\u662f\u6211\u4eec\u60f3\u8981\u7684\u957f\u65b9\u5f62\u78b0\u649e\u7bb1, \u5b83\u7684\u552f\u4e00\u7684\u6784\u9020\u5668\u63a5\u6536\u56db\u4e2a\u53c2\u6570, \u524d\u4e24\u4e2a\u53c2\u6570\u4e3a\u5b83\u7684\u5bbd\u9ad8, \u540e\u4e24\u4e2a\u53c2\u6570\u4e3a\u8fd9\u4e2a\u78b0\u649e\u7bb1\u7684\u504f\u79fb(\u56e0\u4e3a\u78b0\u649e\u7bb1\u6211\u4eec\u8981\u9644\u52a0\u5230 Entity
\u8eab\u4e0a, \u6240\u4ee5\u4f1a\u6709\u504f\u79fb\u8fd9\u4e2a\u4e1c\u897f), \u8fd9\u4e24\u4e2a\u53c2\u6570\u9ed8\u8ba4\u90fd\u4e3a 0. \u7136\u540e\u8bbe\u7f6e\u5230 Entity
\u8eab\u4e0a: PassByRefill.PassByRefill
Collider = hitbox;\n
Collider
\u662f Entity
\u7684\u4e00\u4e2a\u5c5e\u6027, \u5b83\u8868\u793a\u8fd9\u4e2a Entity
\u81ea\u8eab\u7684\u78b0\u649e\u7bb1. Collider
\u5c5e\u6027\u662f Collider
\u7c7b\u578b\u7684, \u5b83\u662f\u4e00\u4e2a\u62bd\u8c61\u7c7b\u8868\u793a\u4e00\u4e2a\u78b0\u649e\u4f53, \u8fd9\u91cc\u6211\u4eec\u7684 Hitbox
\u5c31\u662f\u5b83\u7684\u4e00\u4e2a\u5b9e\u73b0, \u4e5f\u5c31\u662f\u4e00\u79cd\u957f\u65b9\u5f62\u7684\u5b9e\u73b0. \u78b0\u649e\u7bb1\u8bbe\u7f6e\u5b8c\u540e, \u6211\u4eec\u5c31\u8be5\u5728 Update()
\u68c0\u6d4b\u78b0\u649e\u4e86, \u8fd9\u5f88\u7b80\u5355~ PassByRefill.Update()
public override void Update()\n{\n base.Update();\n // \u83b7\u53d6 Player \u5b9e\u4f8b (\u522b\u5bb3\u6015!)\n var player = Scene.Tracker.GetEntity<Player>();\n\n // \u68c0\u6d4b\u662f\u5426\u4e0e\u73a9\u5bb6\u78b0\u649e\n if (player is not null && this.CollideCheck(player))\n {\n // \u5982\u679c\u78b0\u649e\u4e86, \u90a3\u4e48\u8bbe\u7f6e\u5b83\u7684\u51b2\u523a\u6570\n player.Dashes = this.Dashes;\n }\n}\n
\u76f8\u4fe1\u4f60\u770b\u5230\u7b2c\u4e94\u884c\u4e00\u5b9a\u4f1a\u88ab\u5413\u4e00\u8df3! \u76f8\u4fe1\u90a3\u4e00\u4e32\u4e1c\u897f\u5bf9\u4e8e\u65b0\u4eba\u6765\u8bf4\u4e00\u5b9a\u5f88\u590d\u6742, \u4e0d\u8fc7\u6ca1\u5173\u7cfb, \u4f60\u53ea\u9700\u8981\u77e5\u9053\u90a3\u4e00\u4e32\u4f1a\u8fd4\u56de\u5728\u573a\u7684\u90a3\u4e2a\u73a9\u5bb6\u5c31\u884c(\u4e0d\u5728\u573a\u65f6\u4e3a null). \u7136\u540e\u6211\u4eec\u7528 Entity
\u7684 CollideCheck
\u68c0\u67e5\u6211\u4eec\u6709\u6ca1\u6709\u4e0e\u73a9\u5bb6\u53d1\u751f\u78b0\u649e, \u5982\u679c\u6709\u5219\u5f3a\u5236\u8bbe\u7f6e\u5b83\u7684\u51b2\u523a\u6570. \u7531\u4e8e\u6211\u4eec\u6bcf\u4e00\u5e27\u90fd\u5728\u68c0\u67e5, \u90fd\u5728\u8bbe\u7f6e, \u6240\u4ee5\u6700\u7ec8\u7684\u6548\u679c\u5c31\u662f\u73a9\u5bb6\u4e00\u65e6\u8fdb\u5165\u8fd9\u4e2a\u533a\u57df, \u51b2\u523a\u6570\u88ab\u9501\u5b9a\u4e3a Dashes
.
Info
\u5b9e\u9645\u4e0a\u8fd9\u91cc\u6709\u66f4\u597d\u7684\u65b9\u6cd5\u6765\u5355\u72ec\u68c0\u6d4b\u4e0e\u73a9\u5bb6\u7684\u78b0\u649e, \u4e3a\u4e86\u7b80\u5355\u8d77\u89c1\u8fd9\u91cc\u6ca1\u6709\u91c7\u7528. \u4e0d\u8fc7\u6211\u4eec\u4f9d\u7136\u4f1a\u5728\u540e\u9762\u63d0\u5230(\"\u5e38\u89c1 Celeste, Monocle \u7c7b\"\u8282). \u7b2c\u4e00\u884c\u7684 base.Update()
\u4f1a\u904d\u5386\u8c03\u7528\u8be5 Entity
\u7684\u6240\u6709 Component
\u7684 Update()
, \u901a\u5e38\u6211\u4eec\u9700\u8981\u5728\u5f00\u5934\u5c31\u8c03\u7528\u5b83. \u540e\u9762\u7684 Render()
\u4e5f\u662f.
Info
\u5728\u73a9\u5bb6\u6b7b\u4ea1\u540e\u7684\"\u70df\u82b1\"\u5e76\u4e0d\u662f Player
\u5b9e\u4f8b, \u6240\u4ee5\u6b64\u65f6\u6211\u4eec\u4f1a\u5f97\u5230\u4e00\u4e2a null
\u7684\u7ed3\u679c, \u5982\u679c\u4f60\u4e0d\u60f3\u8ba9\u4f60\u7684\u6e38\u620f\u5d29\u6e83\u7684\u8bdd\u8bb0\u5f97\u68c0\u67e5\u5b83\u662f\u5426\u4e3a null
.
"},{"location":"begin/simple_entity/#_8","title":"\u544a\u8bc9\u6e38\u620f\u5b83\u957f\u4ec0\u4e48\u6837","text":"\u90a3\u4e48, \u529f\u80fd\u505a\u597d\u540e, \u5f97\u8ba9\u73a9\u5bb6\u770b\u89c1, \u4e3a\u4e86\u7b80\u5355\u8d77\u89c1\u8fd9\u91cc\u6211\u4eec\u4e0d\u6253\u7b97\u4f7f\u7528\u56fe\u7247, \u53ea\u662f\u50cf\u524d\u9762\u63cf\u8ff0\u7684\u4e00\u6837, \u5b83\u662f\u4e2a\"\u900f\u660e\u7684\u7ea2\u8272\u7269\u4f53\", \u5728\u8fd9\u91cc\u6211\u4eec\u9700\u8981\u91cd\u5199 Entity
\u7684 Render()
\u65b9\u6cd5\u6765\u7ed8\u5236\u4e00\u4e2a\u7eaf\u8272\u957f\u65b9\u5f62, \u5b83\u4f1a\u5728\u6e38\u620f\u4e2d\u6bcf\u5e27\u90fd\u4f1a\u88ab\u8c03\u7528, \u5c31\u50cf Update()
\u4e00\u6837, \u4e0d\u8fc7\u5207\u8bb0\u4e0d\u8981\u5728\u8fd9\u4e24\u4e2a\u65b9\u6cd5\u91cc\u5e72\u4e0d\u76f8\u5173\u7684\u4e8b! \u4f60\u5e94\u8be5\u5728 Update()
\u91cc\u53ea\u66f4\u65b0\u4f60\u7684\u903b\u8f91, \u800c\u5728 Render()
\u91cc\u53ea\u505a\u7ed8\u5236. \u8fd9\u91cc\u6211\u4eec\u9009\u62e9\u7ed8\u5236\u4e00\u4e2a\u900f\u660e\u7684\u7ea2\u8272\u957f\u65b9\u5f62, \u6211\u4eec\u9700\u8981\u501f\u52a9\u8fd9\u4e2a\u51fd\u6570:
Monocle.Draw.RectDraw.Rect(Vector2 position, float width, float height, Color color)\n
\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u6211\u4eec\u5e0c\u671b\u7ed8\u5236\u7684\u4f4d\u7f6e(\u4e16\u754c\u5750\u6807) \u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u6211\u4eec\u5e0c\u671b\u7ed8\u5236\u7684\u5bbd\u5ea6 \u7b2c\u4e09\u4e2a\u53c2\u6570\u662f\u6211\u4eec\u5e0c\u671b\u7ed8\u5236\u7684\u9ad8\u5ea6 \u7b2c\u56db\u4e2a\u53c2\u6570\u662f\u6211\u4eec\u5e0c\u671b\u7ed8\u5236\u7684\u989c\u8272 \u6211\u4eec\u5728\u8fd9\u91cc\u4f1a\u8fd9\u6837\u7528\u5b83:
PassByRefill.Render()base.Render();\nColor c = Color.Red;\nc.A = 127;\nDraw.Rect(Position, Width, Height, c);\n
\u9996\u5148\u6211\u4eec\u83b7\u53d6\u4e00\u4e2a\u7ea2\u8272\u7684 Color
, \u7136\u540e\u8bbe\u7f6e\u900f\u660e\u5ea6\u4e3a 127
, \u7136\u540e\u8c03\u7528\u8fd9\u4e2a\u65b9\u6cd5\u7ed8\u5236. \u4f60\u53ef\u80fd\u6ce8\u610f\u5230 Width
\u548c Height
\u8fd9\u4e24\u4e2a\u4e1c\u897f, \u5b83\u662f Entity
\u7684\u4e24\u4e2a\u5c5e\u6027, \u9ed8\u8ba4\u5b83\u4eec\u90fd\u662f 0, \u5728\u4f60\u52a0\u5165\u78b0\u649e\u7bb1\u7684\u77ac\u95f4\u4ed6\u4eec\u4f1a\u53d8\u6210\u78b0\u649e\u7bb1\u7684\u5bbd\u548c\u9ad8, \u5728\u8fd9\u91cc\u5b83\u4eec\u7684\u503c\u5c31\u662f\u6211\u4eec\u4e4b\u524d\u8bbe\u7f6e\u7684 Hitbox
\u7684\u5bbd\u9ad8.
"},{"location":"begin/simple_entity/#_9","title":"\u51c6\u5907\u5c31\u7eea","text":"\u90a3\u4e48, \u4e00\u5207\u5c31\u7eea, \u7f16\u8bd1\u4f60\u7684\u9879\u76ee, \u5230\u90a3\u4e2a\u5730\u65b9, \u5728\u534a\u900f\u660e\u7ea2\u8272\u7684\u533a\u57df\u91cc\u4eab\u53d7\u9501\u5b9a\u51b2\u523a\u6570\u7684\u5feb\u4e50\u5427!
\u5982\u679c\u4f60\u9047\u5230\u4e86\u56f0\u96be, \u4f60\u53ef\u4ee5\u5bf9\u6bd4\u4e00\u4e0b\u6700\u7ec8\u7684\u4ee3\u7801: PassByRefill.cs
using Celeste.Mod.Entities;\n\nnamespace MyCelesteMod;\n\n[CustomEntity(\"MyCelesteMod/PassByRefill\")]\npublic class PassByRefill : Entity\n{\n public int Dashes = 0;\n\n public PassByRefill(Vector2 position, Vector2 size, int dashes)\n {\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(size.X, size.Y);\n Collider = hitbox;\n }\n\n public PassByRefill(EntityData data, Vector2 offset)\n : this(data.Position + offset, new Vector2(data.Width, data.Height), data.Int(\"dashes\"))\n { }\n\n public override void Update()\n {\n base.Update();\n var player = Scene.Tracker.GetEntity<Player>();\n if (player is not null && this.CollideCheck(player))\n {\n player.Dashes = this.Dashes;\n }\n }\n\n public override void Render()\n {\n base.Render();\n Color c = Color.Red;\n c.A = 127;\n Draw.Rect(Position, Width, Height, c);\n }\n}\n
"},{"location":"begin/simple_entity/#_10","title":"\u66f4\u591a","text":""},{"location":"begin/simple_entity/#loenn-dashes","title":"\u5728 Loenn \u4e2d\u7981\u6b62\u8bbe\u7f6e dashes \u4e3a\u5c0f\u6570","text":"\u5728 Loenn \u4e2d\u5982\u679c\u4f60\u6ca1\u6709\u663e\u5f0f\u6307\u5b9a\u67d0\u4e2a\u6570\u5b57 data \u7684\u7c7b\u578b\u7684\u8bdd\u5b83\u9ed8\u8ba4\u4f1a\u662f\u6d6e\u70b9\u6570, \u4e5f\u5c31\u662f\u4f60\u80fd\u8f93\u5165\u5c0f\u6570, \u4e0d\u8fc7\u8fd9\u4e0d\u4f1a\u5f88\u5f71\u54cd(\u8fd8\u662f\u6709\u7684!)\u4ee3\u7801\u90a3\u8fb9, \u6240\u4ee5\u6211\u4eec\u5f97\u8ddf Loenn \u8bf4\u4e00\u4e0b\u5b83\u662f\u4e2a\u6574\u6570! \u90a3\u4e48\u6211\u4eec\u5728\u4ee3\u7801\u7684 return \u4e4b\u524d\u8fd9\u6837\u8bbe\u7f6e\u4e00\u4e0b: PassByRefill.lua
entity.fieldInformation = \n{\n dashes = {\n fieldType = \"integer\"\n }\n}\n
\u5728\u8fd9\u91cc\u6211\u4eec\u8bbe\u7f6e\u4e86\u4e00\u4e2a\u65b0\u7684\u5c5e\u6027 fieldInformation
, \u7136\u540e\u5728\u91cc\u9762\u544a\u8bc9 Loenn \u6211\u4eec\u7684 dashes
\u8fd9\u4e2a\u5c5e\u6027\u7684 fieldType
\u662f integer
, \u4e5f\u5c31\u662f\u6574\u6570. \u90a3\u4e48\u73b0\u5728\u518d\u91cd\u65b0\u7f16\u8bd1, \u91cd\u542f Loenn, \u4f60\u5e94\u8be5\u4f1a\u770b\u5230 Loenn \u53ea\u5141\u8bb8\u4f60\u8f93\u5165\u6574\u6570\u4e86."},{"location":"begin/simple_entity/#loenn_2","title":"\u4e3a Loenn \u4fa7\u914d\u7f6e\u672c\u5730\u5316","text":"\u73b0\u5728\u6211\u4eec\u5728 Loenn \u4fa7\u6211\u4eec\u7684\u5b9e\u4f53\u653e\u7f6e\u9009\u62e9\u7684\u540d\u79f0\u975e\u5e38\u5947\u602a! \u8fd9\u80af\u5b9a\u4e0d\u662f\u4f60\u60f3\u8981\u7684\u7ed3\u679c, \u6240\u4ee5\u8fd9\u91cc\u6211\u4eec\u5c06\u4e3a\u5176\u914d\u7f6e\u672c\u5730\u5316. \u90a3\u4e48, \u5e38\u89c4\u5730, \u6211\u4eec\u9700\u8981\u5728 ModFolder/Loenn
\u8fd9\u4e2a\u6587\u4ef6\u5939\u4e0b\u518d\u65b0\u5efa\u4e00\u4e2a\u53eb lang
\u6587\u4ef6\u5939, \u7136\u540e\u5728\u91cc\u9762\u521b\u5efa\u4e00\u4e2a\u53eb en_gb.lang
\u7684\u7a7a\u6587\u4ef6, \u5b83\u662f Loenn \u9ed8\u8ba4\u8bfb\u53d6\u7684\u672c\u5730\u5316\u6587\u4ef6. \u73b0\u5728\u4f60\u7684\u76ee\u5f55\u7ed3\u6784\u5e94\u8be5\u50cf:
\u5728 en_gb.lang
\u6587\u4ef6\u91cc, \u6211\u4eec\u5199\u4e0b:
entities.MyCelesteMod/PassByRefill.placements.name.normal=PassByRefill\n
\u554a, \u8fd9\u4e00\u4e32\u53ef\u80fd\u6709\u4ebf\u70b9\u957f, \u6211\u4eec\u6162\u6162\u6765\u89e3\u91ca\u4e00\u4e0b: \u9996\u5148\u8fd9\u662f\u4e00\u4e2a\u5b9e\u4f53, \u6240\u4ee5\u4ee5 entities
\u5f00\u5934, \u7136\u540e\u6211\u4eec\u9700\u8981\u952e\u5165\u5b9e\u4f53\u7684\"\u540d\u79f0 ID\", \u7136\u540e\u518d\u4f9d\u6b21\u952e\u5165 placements
\u548c name
, \u8fd9\u8868\u793a\u6211\u4eec\u60f3\u672c\u5730\u5316\u7684\u5185\u5bb9\u662f\u90a3\u4e2a\u5b9e\u4f53\u7684\u653e\u7f6e\u9009\u9879\u7684\u540d\u79f0, \u6700\u540e\u952e\u5165\u653e\u7f6e\u9009\u9879\u7684\u540d\u5b57 \"normal\"(\u5b83\u5e94\u8be5\u4f1a\u5728\u4f60\u7684 lua \u7684\u7b2c\u4e94\u884c\u9644\u8fd1). ok \u73b0\u5728\u6211\u4eec\u5df2\u7ecf\u6307\u5b9a\u4e86\u6211\u4eec\u60f3\u672c\u5730\u5316\u4ec0\u4e48\u4e1c\u897f\u4e86, \u90a3\u4e48\u63a5\u4e0b\u6765\u7b80\u5355\u7684 ={\u5185\u5bb9}
, \u5728\u8fd9\u91cc\u662f PassByRefill
. \u6700\u540e, \u7f16\u8bd1\u590d\u5236, \u91cd\u542f Loenn, \u4f60\u5e94\u8be5\u5c31\u4f1a\u770b\u5230\u6211\u4eec\u7684\u5b9e\u4f53\u7ec8\u4e8e\u6709\u4e2a\u6b63\u5e38\u540d\u5b57\u4e86:
Info
\u5bf9\u4e8e\u5b83\u7684\u8d34\u56fe\u6211\u4eec\u4e4b\u540e\u518d\u8bf4, \u6211\u77e5\u9053\u4f60\u5f88\u6025\u4f46\u662f\u4f60\u5148\u522b\u6025.
"},{"location":"begin/simple_texturing/","title":"\u7b80\u5355\u8d34\u56fe","text":"\u55ef... \u90a3\u4e48\u5230\u8fd9\u4e00\u7ae0\u6211\u4eec\u8be5\u7ed9\u6211\u4eec\u5b9e\u4f53\u4e0a\u70b9\u8d34\u56fe\u4e86, \u4ee5\u53ca\u8fd8\u6709 Loenn \u4fa7\u7684\u8d34\u56fe, \u90a3\u4e48\u7ed3\u675f\u8fd9\u4e00\u7ae0\u540e\u4f60\u5e94\u8be5\u4f1a\u89c9\u5f97\u6211\u4eec\u7684\u5b9e\u4f53\u662f\u4e2a\"\u50cf\u6837\"\u7684\u5b9e\u4f53\u4e86. \u8fd9\u91cc\u6211\u4eec\u4f1a\u4f7f\u7528\u8fd9\u4e2a 64x64 \u7684\u8d85\u7ea7\u4e11\u964b\u7684\u8d34\u56fe:
\u554a\u5b83\u771f\u7684\u592a\u4e11\u964b\u4e86 \u4f60\u53ef\u4ee5\u5728\u8fd9\u91cc\u4e0b\u8f7d\u5b83: fucking_ugly_texture.png
"},{"location":"begin/simple_texturing/#_2","title":"\u7981\u6b62\u6211\u4eec\u7684\u5b9e\u4f53\u7f29\u653e","text":"\u5728\u8fd9\u91cc\u6211\u4eec\u7684\u8d34\u56fe\u662f\u6b63\u65b9\u5f62\u7684, \u6240\u4ee5\u8fd9\u91cc\u4e3a\u4e86\u65b9\u4fbf\u8d77\u89c1\u6682\u65f6\u8ba9\u6211\u4eec\u7684\u5b9e\u4f53\u4e0d\u80fd\u7f29\u653e, \u90a3\u4e48\u5728\u4ee3\u7801\u8fd9\u8fb9\u7684\u8868\u73b0\u5c31\u662f\u76f4\u63a5\u5220\u53bb\u4e0e Size \u6709\u5173\u7684\u4e1c\u897f\u5e76\u5c06\u78b0\u649e\u7bb1\u786c\u7f16\u7801\u6210 64x64 \u5927\u5c0f:
AfterBefore PassByRefill.cspublic PassByRefill(Vector2 position, int dashes)\n{\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(64, 64);\n Collider = hitbox;\n}\n\npublic PassByRefill(EntityData data, Vector2 offset)\n : this(data.Position + offset, data.Int(\"dashes\"))\n{ }\n
PassByRefill.cspublic PassByRefill(Vector2 position, Vector2 size, int dashes)\n{\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(size.X, size.Y);\n Collider = hitbox;\n}\n\npublic PassByRefill(EntityData data, Vector2 offset)\n : this(data.Position + offset, new Vector2(data.Width, data.Height), data.Int(\"dashes\"))\n{ }\n
Info
\u5728 Loenn \u90a3\u8fb9\u6211\u4eec\u5f85\u4f1a\u518d\u8bf4, \u5982\u679c\u4f60\u73b0\u5728\u5c31\u5220\u9664 width \u548c height \u5c5e\u6027\u7684\u8bdd\u4f60\u4f1a\u53d1\u73b0\u4f60\u653e\u7f6e\u4e0d\u4e86\u8fd9\u4e2a\u5b9e\u4f53
"},{"location":"begin/simple_texturing/#monocleimage","title":"\u8d34\u56fe\u4ee5\u53ca Monocle.Image","text":""},{"location":"begin/simple_texturing/#_3","title":"\u851a\u84dd\u4fa7","text":"ok \u90a3\u4e48\u73b0\u5728\u6211\u4eec\u8be5\u5728\u4ee3\u7801\u8fd9\u8fb9\u6765\u70b9\u8d34\u56fe\u4e86, \u8fd9\u91cc\u6211\u4eec\u4f1a\u7528\u5230\u4e4b\u524d\u63d0\u5230\u7684 Component
\u7684\u6982\u5ff5\u53ca\u5bf9\u5e94\u7684\u4e00\u4e2a\u65b0\u7684\u7c7b Monocle.Image
, \u5b83\u7684\u4f5c\u7528\u5c31\u662f\u7ed8\u5236\u8d34\u56fe. \u9996\u5148\u6211\u4eec\u5f97\u8ba9\u6e38\u620f\u627e\u5230\u5e76\u52a0\u8f7d\u5230\u6211\u4eec\u7684\u8d34\u56fe, \u8fd9\u4e00\u6b65\u5f88\u7b80\u5355\u5e76\u7c7b\u4f3c, \u53ea\u9700\u8981\u5957\u51e0\u5c42\u6587\u4ef6\u5939:
pass_by_refill.png
\u5373\u6211\u4eec\u7684\u8d34\u56fe, \u5982\u679c\u4f60\u540c\u65f6\u4e5f\u662f\u4e00\u4f4d mapper \u7684\u8bdd\u4f60\u4e00\u5b9a\u5f88\u719f\u6089\u8fd9\u4e2a\u6587\u4ef6\u5939\u5957\u5957\u4e50! \u5728\u4ee3\u7801\u8fd9\u8fb9, \u6211\u4eec\u4f7f\u7528 GFX.Game[\"MyCelesteMod/pass_by_refill\"]
\u6765\u83b7\u53d6\u8fd9\u4e2a\u8d34\u56fe, \u5b83\u662f\u4e00\u4e2a MTexture
\u7c7b\u578b\u7684\u5b9e\u4f8b, \u5728\u83b7\u53d6\u5230\u8fd9\u4e2a\u8d34\u56fe\u540e, \u6211\u4eec new
\u4e00\u4e2a Monocle.Image
, \u7136\u540e\u5728\u6784\u9020\u51fd\u6570\u4e2d\u4f20\u5165\u5b83, \u7136\u540e\u4f7f\u7528 this.Add
\u51fd\u6570\u6302\u8f7d\u5230\u6211\u4eec\u7684\u8fd9\u4e2a\u5b9e\u4f53\u4e0a, \u603b\u7684\u4ee3\u7801\u5e94\u8be5\u662f\u8fd9\u6837\u7684: PassByRefill.cs
public PassByRefill(Vector2 position, int dashes)\n{\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(64, 64);\n Collider = hitbox;\n\n MTexture tex = GFX.Game[\"MyCelesteMod/pass_by_refill\"];\n Image image = new(tex);\n this.Add(image);\n}\n
Info
GFX
\u662f\u851a\u84dd\u4e2d\u7684\u4e00\u4e2a\u7ba1\u7406\u8d34\u56fe\u7684\u7c7b, \u6211\u4eec\u7528\u5b83\u83b7\u53d6\u5230\u4e00\u4e2a\u8d34\u56fe\u7ec4 Game
, \u7136\u540e\u5411\u5b83\u68c0\u7d22\u4e00\u4e2a\u540d\u4e3a MyCelesteMod/pass_by_refill
\u7684\u8d34\u56fe, \u4f60\u53ef\u80fd\u4f1a\u7591\u60d1\u4e3a\u4ec0\u4e48\u8fd9\u91cc\u7684\u8def\u5f84\u53ea\u9700\u8981\u540e\u534a\u90e8\u5206, \u8fd9\u662f\u56e0\u4e3a GFX.Game
\u53ea\u4f1a\u68c0\u7d22 Atlases/Graphics/Gameplay
\u4e2d\u7684\u5185\u5bb9. \u540c\u6837\u7684, GFX.Portraits
\u53ea\u4f1a\u68c0\u7d22 Atlases/Graphics/Portraits
\u4e2d\u7684\u5185\u5bb9.
\u987a\u4fbf\u8bb0\u5f97\u5220\u6389\u6211\u4eec\u91cd\u5199\u7684 Render
\u51fd\u6570, \u6211\u4eec\u4e0d\u518d\u9700\u8981\u5b83\u4e86. \u603b\u7684\u7c7b\u5e94\u8be5\u662f\u8fd9\u6837\u7684: PassByRefill.cs
[CustomEntity(\"MyCelesteMod/PassByRefill\")]\n[Tracked]\npublic class PassByRefill : Entity\n{\n public int Dashes = 0;\n\n public PassByRefill(Vector2 position, int dashes)\n {\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(64, 64);\n Collider = hitbox;\n\n MTexture tex = GFX.Game[\"MyCelesteMod/pass_by_refill\"];\n Image image = new(tex);\n this.Add(image);\n }\n\n public PassByRefill(EntityData data, Vector2 offset)\n : this(data.Position + offset, data.Int(\"dashes\"))\n { }\n\n public override void Update()\n {\n base.Update();\n var player = Scene.Tracker.GetEntity<Player>();\n if (player is not null && this.CollideCheck(player))\n {\n player.Dashes = this.Dashes;\n }\n }\n}\n
"},{"location":"begin/simple_texturing/#loenn","title":"Loenn \u4fa7","text":"\u5728 Loenn \u4fa7\u8fd9\u8fb9\u4e5f\u975e\u5e38\u7b80\u5355, \u9996\u5148\u6211\u4eec\u5148\u5927\u80c6\u7684\u5220\u6389 width \u548c height \u5c5e\u6027:
AfterBefore PassByRefill.lualocal entity = {}\n\nentity.name = \"MyCelesteMod/PassByRefill\"\nentity.placements = {\n name = \"normal\",\n data = {\n dashes = 2\n }\n}\n\nentity.fieldInformation = \n{\n dashes = {\n fieldType = \"integer\"\n }\n}\n\nreturn entity\n
PassByRefill.lualocal entity = {}\n\nentity.name = \"MyCelesteMod/PassByRefill\"\nentity.placements = {\n name = \"normal\",\n data = {\n width = 16,\n height = 16,\n dashes = 2\n }\n}\n\nentity.fieldInformation = \n{\n dashes = {\n fieldType = \"integer\"\n }\n}\n\nreturn entity\n
\u7136\u540e\u8bbe\u7f6e entity \u7684 texture
\u5c5e\u6027, \u8fd9\u4f1a\u8ba9 Loenn \u4e3a\u5176\u8bbe\u7f6e\u8d34\u56fe:
entity.texture = \"MyCelesteMod/pass_by_refill\"\n
\u987a\u4fbf\u8bbe\u7f6e\u8d34\u56fe\u539f\u70b9\u4e3a\u5de6\u4e0a\u89d2, \u5426\u5219 Loenn \u4e2d\u7684\u663e\u793a\u53ef\u80fd\u4f1a\u4e0e\u5b9e\u9645\u6e38\u620f\u4e2d\u7684\u4e0d\u540c: entity.justification = { 0.0, 0.0 }\n
\u8fd9\u91cc\u7684\u8def\u5f84\u4e0e\u6211\u4eec\u4e4b\u524d\u5728\u4ee3\u7801\u4e2d\u7684\u7c7b\u4f3c. \u90a3\u4e48\u73b0\u5728\u603b\u4f53\u4e0a\u770b\u4e0a\u53bb\u5e94\u8be5\u662f\u8fd9\u6837\u7684: local entity = {}\n\nentity.name = \"MyCelesteMod/PassByRefill\"\nentity.placements = {\n name = \"normal\",\n data = {\n dashes = 2\n }\n}\n\nentity.fieldInformation = \n{\n dashes = {\n fieldType = \"integer\"\n }\n}\n\nentity.texture = \"MyCelesteMod/pass_by_refill\"\nentity.justification = { 0.0, 0.0 }\n\nreturn entity\n
"},{"location":"begin/simple_texturing/#_4","title":"\u6700\u540e","text":"\u6700\u540e\u7f16\u8bd1\u6211\u4eec\u7684\u9879\u76ee, \u6253\u5f00\u6216\u8005\u91cd\u542f Loenn, \u4f60\u5c31\u4f1a\u770b\u5230\u6211\u4eec\u7684\u5b9e\u4f53\u6709\u7740\u4e00\u4e2a\u4e0d\u600e\u4e48\u597d\u770b\u7684\u8d34\u56fe\u4e86! \u73b0\u5728\u8fdb\u5165\u5230\u6e38\u620f\u4e2d\u4f60\u4e5f\u4f1a\u770b\u5230\u8fd9\u4e2a\u4e0d\u600e\u4e48\u597d\u770b\u7684\u8d34\u56fe\u4e86!
"},{"location":"begin/simple_trigger/","title":"\u7b80\u5355\u81ea\u5b9a\u4e49 Trigger","text":"\u5982\u679c\u4f60\u662f\u4e00\u4f4d Mapper \u7684\u8bdd\u90a3\u4f60\u4e00\u5b9a\u77e5\u9053 Trigger \u662f\u591a\u4e48\u91cd\u8981\u7684\u5b58\u5728. \u5728\u8fd9\u91cc\u53ef\u80fd\u4e0d\u662f\u5f88\u80fd\u5728\u77ed\u7bc7\u5e45\u5185\u8bf4\u660e Trigger \u7684\u91cd\u8981\u6027, \u8fd9\u91cc\u53ea\u7b80\u5355\u4e3e\u51e0\u4e2a\u4f8b\u5b50:
\u7edd\u5927\u90e8\u5206\u955c\u5934\u7684\u79fb\u52a8\u4e0e\u504f\u79fb \u5267\u60c5\u7684\u89e6\u53d1, \u65e0\u5355\u53cc\u51b2\u7684\u5207\u6362 \u98ce\u7684\u6539\u53d8 \u91cd\u751f\u70b9\u7684\u8bbe\u7f6e \u97f3\u4e50\u53c2\u6570\u7684\u8bbe\u7f6e \u80cc\u666f\u7684\u6e10\u53d8, \u524d\u666f\u7684\u5404\u79cd\u53d8\u6362 \u4ee5\u4e0a\u51e0\u4e2a\u4f8b\u5b50\u4e0d\u8bf4\u7edd\u5927\u90e8\u5206, \u4e5f\u6709\u5f88\u5927\u7684\u5360\u6bd4\u90fd\u662f\u7531 Trigger \u5b8c\u6210\u7684. Trigger \u662f Entity \u7684\u5b50\u7c7b, \u5b83\u5e26\u6709\u4e00\u4e2a\u957f\u65b9\u5f62\u7684\u78b0\u649e\u7bb1, \u901a\u5e38\u5b83\u662f\u5bf9\u73a9\u5bb6\u4e0d\u53ef\u89c1\u7684, \u5f53\u73a9\u5bb6 \u8fdb\u5165(OnEnter)
, \u4fdd\u6301(OnStay)
, \u79bb\u5f00(OnLeave)
\u4f1a\u5206\u522b\u6267\u884c\u4e0d\u540c\u7684\u52a8\u4f5c, \u6bd4\u5982\u8bf4\u5f53\u73a9\u5bb6 \u8fdb\u5165
\u6539\u53d8\u98ce\u7684 Trigger \u65f6\u4f1a\u6539\u53d8\u573a\u4e0a\u7684\u98ce\u7684\u60c5\u51b5, \u5f53\u73a9\u5bb6 \u4fdd\u6301
\u5728\u955c\u5934\u504f\u79fb\u6539\u53d8 Trigger \u91cc\u65f6\u4f1a\u4fdd\u6301\u955c\u5934\u76f8\u5bf9\u4e8e\u73a9\u5bb6\u7684\u504f\u79fb\u4e8e\u4e00\u4e2a\u503c.
Info
\u5728\u5b98\u56fe\u7b2c\u4e5d\u7ae0\u5047\u5fc3\u9644\u8fd1\u7684 Trigger \u770b\u4e0a\u53bb\u5c31\u50cf: \u5728\u8fd9\u91cc, \u5de6\u8fb9\u6709\u4e2a\u8bbe\u7f6e\u91cd\u751f\u70b9\u7684 Trigger, \u4e2d\u95f4\u6709\u4e2a\u4fdd\u6301\u955c\u5934\u4f4d\u7f6e\u7684 Trigger, \u800c\u5728\u53f3\u8fb9\u6709\u4e2a\u66f4\u6539\u80cc\u666f\u7684 Trigger.
\u90a3\u4e48, \u662f\u65f6\u5019\u5236\u4f5c\u4e00\u4e2a\u5c5e\u4e8e\u6211\u4eec\u81ea\u5df1\u7684 Trigger \u4e86, \u7b80\u5355\u8d77\u89c1\u8fd9\u91cc\u6211\u4eec\u53ea\u505a\u51e0\u4e2a\u6700\u7b80\u5355\u7684\u529f\u80fd:
\u5b83\u53eb SetPassByRefillDashesTrigger
\u73a9\u5bb6\u8fdb\u5165\u540e\u4fee\u6539\u573a\u4e0a\u6240\u6709\u6211\u4eec\u4e4b\u524d\u7684 PassByRefill
\u5b9e\u4f53\u7684\u51b2\u523a\u6570 \u6ca1\u4e86, \u662f\u7684, \u5c31\u662f\u8fd9\u4e48\u7b80\u5355! "},{"location":"begin/simple_trigger/#entity","title":"\u50cf\u5bf9 Entity \u4e00\u6837\u5730\u505a\u51c6\u5907\u5de5\u4f5c","text":"\u9996\u5148\u5728\u4ee3\u7801\u4e2d\u51c6\u5907\u6211\u4eec\u7684\u7c7b, \u4e0d\u8fc7\u8fd9\u6b21\u6211\u4eec\u7ee7\u627f\u7684\u662f Trigger
. \u54e6\u5bf9\u4e86, \u5b83\u8fd8\u4f1a\u8981\u6c42\u58f0\u660e\u4e00\u4e2a\u5e26\u53c2\u7684\u6784\u9020\u51fd\u6570, \u56e0\u4e3a Trigger
\u57fa\u7c7b\u6ca1\u6709\u65e0\u53c2\u6784\u9020\u5668, \u6240\u4ee5\u4f60\u53ef\u80fd\u9700\u8981\u50cf\u5982\u4e0b\u4e00\u6837\u58f0\u660e\u4e00\u4e0b: SetPassByRefillDashesTrigger.cs
[CustomEntity(\"MyCelesteMod/SetPassByRefillDashesTrigger\")]\npublic class SetPassByRefillDashesTrigger : Trigger\n{\n public SetPassByRefillDashesTrigger(EntityData data, Vector2 offset)\n : base(data, offset)\n {\n\n }\n}\n
\u4f60\u53ef\u80fd\u4f1a\u53d1\u73b0\u5176\u5b9e\u5b83\u8981\u6c42\u7684\u5c31\u662f Everest \u8981\u6c42\u6211\u4eec\u5b9a\u4e49\u7684\u90a3\u4e2a! \u90a3\u521a\u597d\u6211\u4eec\u5c31\u4e0d\u7528\u518d\u989d\u5916\u5b9a\u4e49\u4e00\u4e2a\u4e86. \u7136\u540e\u6211\u4eec\u7a0d\u4f5c\u66f4\u6539, \u4ee5\u8ba9\u5b83\u4e5f\u80fd\u63d0\u53d6\u5230\u4e00\u4e2a\u53eb dashes
\u7684\u6570\u636e: SetPassByRefillDashesTrigger.cspublic int Dashes;\n\npublic SetPassByRefillDashesTrigger(EntityData data, Vector2 offset)\n : base(data, offset)\n{\n Dashes = data.Int(\"dashes\");\n}\n
\u6784\u9020\u51fd\u6570\u94fe
\u5f62\u5982 : base(data, offset)
: this(position)
\u7684\u8fd9\u79cd\u8bed\u6cd5\u53eb\u505a\u6784\u9020\u51fd\u6570\u94fe, \u8fd9\u4e00\u90e8\u5206\u4f3c\u4e4e\u5f88\u591a C# \u6559\u7a0b\u6ca1\u6709\u7279\u522b\u63d0\u53ca, \u5982\u679c\u4f60\u5bf9\u6b64\u4e0d\u662f\u5f88\u4e86\u89e3\u7684\u8bdd\u6211\u63a8\u8350\u4f60\u53bb\u67e5\u9605\u4e86\u89e3\u8be5\u8bed\u6cd5.
\u4f60\u53ef\u80fd\u6ce8\u610f\u5230 Trigger \u4e00\u822c\u90fd\u662f\u6709\u5bbd\u5ea6\u548c\u9ad8\u5ea6\u7684, \u5728\u8fd9\u91cc\u6211\u4eec\u5e76\u6ca1\u6709\u7528 EntityData data
\u53bb\u83b7\u53d6, \u800c\u4e14\u6211\u4eec\u4e5f\u6ca1\u8bbe\u7f6e\u5b83\u7684 Position
! \u5b9e\u9645\u4e0a\u5f53\u4f60 : base(data, offset)
\u65f6\u8fd9\u4e9b\u4e8b\u60c5\u5df2\u7ecf\u7531\u7236\u7c7b Trigger \u7684\u6784\u9020\u51fd\u6570\u505a\u4e86, \u5982\u679c\u4f60\u597d\u5947\u53ef\u4ee5\u7ffb\u9605 Trigger
\u6784\u9020\u51fd\u6570\u9644\u8fd1\u7684\u4ee3\u7801.
Trigger.Trigger(EntityData data, Vector2 offset) /// .......\npublic Trigger(EntityData data, Vector2 offset)\n : base(data.Position + offset)\n{\n base.Collider = new Hitbox(data.Width, data.Height);\n Visible = false;\n}\n/// .......\n
"},{"location":"begin/simple_trigger/#trigger_1","title":"Trigger \u7684\u5b9e\u9645\u529f\u80fd","text":"ok \u73b0\u5728\u8ba9\u6211\u4eec\u60f3\u60f3\u6211\u4eec\u7684 Trigger \u7684\u529f\u80fd\u5982\u4f55\u5b9e\u73b0. \u5b83\u5927\u6982\u5c31\u662f:
\u68c0\u6d4b\u73a9\u5bb6\u662f\u5426\u8fdb\u5165 \u8bbe\u7f6e\u573a\u4e0a\u6240\u6709 PassByRefill
\u7684 Dashes
\u5b57\u6bb5 \u6ca1\u4e86 \u5728\u8fd9\u91cc\u6211\u4eec\u4f1a\u4f7f\u7528 Trigger \u7684 OnEnter
\u865a\u51fd\u6570, \u5b83\u4f1a\u5728\u73a9\u5bb6\u9996\u6b21\u8fdb\u5165\u76841\u5e27\u88ab\u8c03\u75281\u6b21. SetPassByRefillDashesTrigger.cs
public override void OnEnter(Player player)\n{\n base.OnEnter(player);\n}\n
Note
\u851a\u84dd\u5185\u90e8\u5927\u90e8\u5206\u865a\u51fd\u6570\u91cd\u5199\u65f6\u6700\u597d\u5728\u5f00\u5934\u8c03\u7528\u4e00\u904d\u57fa\u7c7b\u7684\u5b9e\u73b0, \u9664\u975e\u4f60\u771f\u7684\u77e5\u9053\u5b83\u505a\u4e86\u4ec0\u4e48\u5e76\u4e14\u4f60\u771f\u7684\u4e0d\u9700\u8981\u5b83.
\u7136\u540e\u662f\u83b7\u53d6\u573a\u4e0a\u6240\u6709\u7684 PassByRefill
, \u4ee5\u4fbf\u6211\u4eec\u80fd\u8bbe\u7f6e\u5b83\u4eec\u7684 Dashes
. \u8fd9\u91cc\u6211\u4eec\u4f1a\u642c\u51fa\u4e00\u4e2a\u4f60\u53ef\u80fd\u773c\u719f\u7684\u4e00\u4e32: SetPassByRefillDashesTrigger.OnEnter(Player player)
// \u83b7\u53d6\u6240\u6709\u7684 PassByRefill\nvar refills = Scene.Tracker.GetEntities<PassByRefill>();\n
\u5728\u8fd9\u91cc\u6216\u8bb8\u8be5\u4ecb\u7ecd\u4ecb\u7ecd\u8fd9\u4e00\u4e32\u662f\u4ec0\u4e48\u4e86, \u9996\u5148\u6211\u4eec\u901a\u8fc7 Scene
\u5c5e\u6027\u83b7\u53d6\u81ea\u8eab\u6240\u5728\u7684\u573a\u666f, \u7136\u540e\u83b7\u53d6\u5b83\u7684 Tracker
. Tracker \u662f\u851a\u84dd\u573a\u666f\u5185\u7684\u4e00\u4e2a\u8f85\u52a9\u7c7b, \u5b83\u53ef\u4ee5\u5f88\u5feb\u7684\u5e2e\u4f60\u7b5b\u9009\u51fa\u573a\u4e0a\u7684\u5b9e\u4f53, \u5728\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528\u5b83\u7684 GetEntities<T>
\u6765\u7b5b\u9009\u51fa\u6240\u6709\u7c7b\u578b\u4e3a T
, \u4e5f\u5c31\u662f PassByRefill
\u7684\u5b9e\u4f53. \u90e8\u5206\u5b9e\u4f53\u5728\u573a\u4e0a\u53ef\u80fd\u6c38\u8fdc\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u65f6, \u6bd4\u5982\u8bf4\u6211\u4eec\u7684 Player
, \u9664\u975e\u4f60\u5b89\u88c5\u4e86\u5947\u5947\u602a\u602a\u7684 mod, \u5426\u5219\u5b83\u6c38\u8fdc\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b, \u8fd9\u79cd\u60c5\u51b5\u4e0b\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 GetEntity
, \u5b83\u53ea\u4f1a\u8fd4\u56de\u4e00\u4e2a\u5b9e\u4f8b. \u90a3\u4e48\u4f60\u73b0\u5728\u5e94\u8be5\u61c2\u5f97\u4e4b\u524d\u6211\u4eec\u5199\u4e0b\u7684 Scene.Tracker.GetEntity<Player>()
\u662f\u4ec0\u4e48\u610f\u601d\u4e86: \"\u4f7f\u7528\u573a\u666f\u7684 Tracker \u83b7\u53d6\u573a\u4e0a\u552f\u4e00\u7684\u90a3\u4e2a Player \u5b9e\u4f8b\".
\u54e6\u5bf9\u4e86, \u6211\u4eec\u8fd8\u5f97\u5728\u6211\u4eec\u60f3\u8981 Tracker \u83b7\u53d6\u7684\u5b9e\u4f53\u7684\u7c7b\u4e0a\u52a0\u4e00\u4e2a Tracked
\u7279\u6027, \u5c31\u50cf: PassByRefill.cs
[CustomEntity(\"MyCelesteMod/PassByRefill\")]\n[Tracked]\npublic class PassByRefill : Entity\n{\n
\u8fd9\u4e00\u6b65\u5176\u5b9e\u5f88\u5bb9\u6613\u88ab\u5fd8\u8bb0, \u5c31\u50cf\u6211\u5199\u5b8c\u521d\u7a3f\u5e76\u505a\u5230\u6700\u540e\u4e00\u6b65\u6e38\u620f\u5d29\u6e83\u65f6\u624d\u60f3\u8d77\u6765(\u4e50). \u597d\u7684\u7136\u540e\u6211\u4eec\u8be5\u8bbe\u7f6e PassByRefill
\u4eec\u7684 Dashes
... \u989d\u7b49\u7b49! \u4f60\u53ef\u80fd\u4f1a\u53d1\u73b0\u8fd9\u91cc\u7684 refills
\u5c40\u90e8\u53d8\u91cf\u5176\u5b9e\u662f\u4e2a List<Entity>
\u7c7b\u578b, \u8fd9\u4e2a\u6211\u4e0d\u592a\u6e05\u695a\u4e3a\u4ec0\u4e48, \u4f30\u8ba1\u662f\u4e00\u4e2a Monocle
\u5728\u5b9e\u73b0\u4e2d\u7684\u4e00\u4e2a\u5c0f\u9519\u8bef, \u4e3a\u4e86\u7ea0\u6b63\u5b83\u8fd9\u91cc\u6211\u4f1a\u4f7f\u7528 Linq
\u7684 Cast
\u6765\u8f6c\u6362\u4e00\u4e0b\u7c7b\u578b:
SetPassByRefillDashesTrigger.OnEnter(Player player)var refills = Scene.Tracker.GetEntities<PassByRefill>().Cast<PassByRefill>();\n
ok, \u73b0\u5728\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u904d\u5386\u5e76\u8bbe\u7f6e\u4e86: SetPassByRefillDashesTrigger.OnEnter(Player player)
foreach(var refill in refills)\n{\n refill.Dashes = this.Dashes;\n}\n
\u6700\u540e, \u4f60\u7684\u4ee3\u7801\u5e94\u8be5\u603b\u4f53\u4e0a\u662f\u8fd9\u4e2a\u6837\u5b50: SetPassByRefillDashesTrigger.cs
using Celeste.Mod.Entities;\n\nnamespace MyCelesteMod;\n\n[CustomEntity(\"MyCelesteMod/SetPassByRefillDashesTrigger\")]\npublic class SetPassByRefillDashesTrigger : Trigger\n{\n public int Dashes;\n\n public SetPassByRefillDashesTrigger(EntityData data, Vector2 offset)\n : base(data, offset)\n {\n Dashes = data.Int(\"dashes\");\n }\n\n public override void OnEnter(Player player)\n {\n base.OnEnter(player);\n var refills = Scene.Tracker.GetEntities<PassByRefill>().Cast<PassByRefill>();\n foreach(var refill in refills)\n {\n refill.Dashes = this.Dashes;\n }\n }\n}\n
"},{"location":"begin/simple_trigger/#loenn","title":"Loenn \u914d\u7f6e","text":"ok \u6211\u4eec\u7684 Trigger \u7684\u4ee3\u7801\u5df2\u7ecf\u5199\u597d\u4e86, \u63a5\u4e0b\u6765\u5199\u4e00\u4e2a Loenn \u914d\u7f6e\u5c31\u597d\u4e86, \u8fd9\u4e00\u6b65\u4e0e Entity \u7684\u5f88\u50cf, \u4e0d\u8fc7\u4f60\u9700\u8981\u628a\u5b83\u653e\u5230 triggers \u6587\u4ef6\u5939\u5185:
ModFolder Loenn entities triggers SetPassByRefillDashesTrigger.lua \u5185\u5bb9\u5927\u540c\u5c0f\u5f02:
SetPassByRefillDashesTrigger.lualocal trigger = {}\n\ntrigger.name = \"MyCelesteMod/SetPassByRefillDashesTrigger\"\ntrigger.placements = {\n name = \"normal\",\n data = {\n width = 16,\n height = 16,\n dashes = 2\n }\n}\n\ntrigger.fieldInformation = \n{\n dashes = {\n fieldType = \"integer\"\n }\n}\n\nreturn trigger\n
\u6700\u540e\u8bb0\u5f97\u5199\u4e2a\u672c\u5730\u5316\u4fe1\u606f, \u4e0d\u7136\u5b83\u7684\u540d\u5b57\u80af\u5b9a\u4f1a\u5f88\u4e11! \u8fd9\u4e00\u6b65\u4e5f\u662f\u5f88\u7c7b\u4f3c\u7684:
entities.MyCelesteMod/PassByRefill.placements.name.normal=PassByRefill\ntriggers.MyCelesteMod/SetPassByRefillDashesTrigger.placements.name.normal=SetPassByRefillDashesTrigger\n
Note
\u522b\u5fd8\u4e86\u7f16\u8bd1, \u4e0d\u8981\u50cf\u6211\u4e00\u6837\u5bf9\u7740 Loenn \u7591\u60d1\u6211\u7684 trigger/\u5b9e\u4f53 \u600e\u4e48\u4e0d\u89c1\u4e86(
"},{"location":"begin/simple_trigger/#_1","title":"\u6548\u679c","text":"\u73b0\u5728\u5728\u4f60\u7684\u5730\u56fe\u4e0a\u6446\u653e\u8fd9\u4e2a trigger \u4ee5\u53ca\u51e0\u4e2a PassByRefill
. \u6211\u5728\u8fd9\u91cc\u4f1a\u6446\u51e0\u4e2a\u80cc\u666f\u7816\u6765\u5e2e\u6211\u4eec\u8fa8\u8bc6\u8fd9\u4e2a trigger \u5728\u54ea, \u56e0\u4e3a trigger \u901a\u5e38\u90fd\u662f\u4e0d\u53ef\u89c1\u7684 (\u4f60\u53ef\u4ee5\u901a\u8fc7 ~
\u952e\u6216\u8005\u4e0b\u8f7d CelesteTAS
\u8fd9\u4e2a mod \u6765\u67e5\u770b\u78b0\u649e\u7bb1). \u90a3\u4e48\u89c1\u8bc1\u4f60\u7684\u6770\u4f5c\u5427!
\u8fdb\u5165 trigger \u524d (PassByRefill \u7684 Dashes \u8bbe\u7f6e\u4e3a 2): \u8fdb\u5165 trigger \u540e (\u88ab\u8bbe\u7f6e\u4e3a 1 \u4e86):
"},{"location":"begin/simple_trigger/#_2","title":"\u6700\u540e","text":"\u6211\u4eec\u76ee\u524d\u5b9e\u73b0\u7684\u90a3\u4e2a Entity \u4e0e\u8fd9\u4e2a Trigger \u7684\u642d\u914d\u5176\u5b9e\u95ee\u9898\u7e41\u591a, \u6bd4\u5982 Entity \u5982\u679c\u5728 Trigger \u89e6\u53d1\u540e\u624d\u88ab\u653e\u7f6e\u5230\u573a\u4e0a, \u90a3\u4e48\u51b2\u523a\u6570\u4f1a\u4fdd\u6301\u5b83\u7684\u9ed8\u8ba4, \u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u6700\u4f73\u7684\u65b9\u6848\u662f\u4f7f\u7528\u851a\u84dd\u4e2d\u7684 Session
, \u6211\u4eec\u4f1a\u5728\u540e\u9762\u63d0\u5230\u5b83.
"},{"location":"extra_cmcc/","title":"\u989d\u5916 - CMCC","text":"\u6b22\u8fce\u6765\u5230\u53c8\u4e00\u4e2a\u989d\u5916\u7ae0\u8282, \u4e0d\u8fc7\u8fd9\u91cc\u4e0d\u662f\u4e00\u4e2a\u65b0\u4e3b\u9898, \u53ea\u662f\u4e00\u4e2a\u7531 ForkKILLET \u5efa\u7acb\u7684\u4ed3\u5e93 CelesteMapperCooperationInChina (CMCC) \u7684\u4e00\u4e2a\u7f51\u9875\u5448\u73b0.
\u6e90 github \u4ed3\u5e93: https://github.com/ForkKILLET/CelesteMapperCooperationInChina
"},{"location":"extra_cmcc/cmcc/ReadMe/","title":"\u851a\u84dd\u5236\u56fe\u4e92\u52a9\uff08\u4e2d\u56fd\uff09 | CMCC","text":""},{"location":"extra_cmcc/cmcc/ReadMe/#_1","title":"\u80cc\u666f","text":"\u4e00\u4f4d\u5236\u56fe\u7fa4\u7fa4\u53cb\uff1a
\u8bdd\u8bf4\u6211\u6709\u4e00\u4e2a\u5c0f\u63d0\u8bae\uff0c\u4e0d\u77e5\u9053\u884c\u4e0d\u884c\uff0c\u5728\u672c\u7fa4\u53ef\u4ee5\u5efa\u7acb\u4e00\u4e2a\u53ef\u7f16\u8f91\u7684 FAQ \u6587\u6863\uff0c\u5927\u5bb6\u53ef\u4ee5\u628a\u505amod\u65f6\u5019\u9047\u5230\u7684\u4e00\u4e9b\u5c0f\u95ee\u9898\u548c\u89e3\u51b3\u65b9\u6848\u653e\u8fdb\u53bb\u2026\u2026
\u4e3a\u4e86\u65b9\u4fbf\u56fd\u5185\u851a\u84dd\uff08Celeste\uff09\u73a9\u5bb6\u5206\u4eab\u5236\u56fe\u7ecf\u9a8c\uff0c\u6211\u4eec\u5f00\u4e86\u4e00\u4e2a\u4ed3\u5e93\u5b58\u653e\u8fd9\u4e9b\u4fe1\u606f\u3002
\u4e24\u4e2a\u6ce8\u610f\u70b9\uff1a
\u4f18\u5148\u4f7f\u7528\u4e2d\u6587 \u4fdd\u8bc1\u56fd\u5185\u53ef\u8bbf\u95ee\u6027 "},{"location":"extra_cmcc/cmcc/ReadMe/#_2","title":"\u8bbf\u95ee","text":" GitHub Gitee \u955c\u50cf "},{"location":"extra_cmcc/cmcc/ReadMe/#_3","title":"\u5185\u5bb9\u7d22\u5f15","text":" FAQ\uff08\u65bd\u5de5\u4e2d\uff09 "},{"location":"extra_cmcc/cmcc/todo/","title":"FAQ","text":""},{"location":"extra_cmcc/cmcc/todo/#q1-loenn","title":"Q1 \u600e\u4e48\u62d6\u52a8 Loenn \u7684\u89c6\u89d2","text":"\u9f20\u6807\u957f\u6309\u53f3\u952e
\u9664\u6b64\u4e4b\u5916, \u5e38\u89c1\u7684 L\u00f6nn \u6309\u952e/\u5feb\u6377\u952e\u6709:
\u901a\u7528\u6309\u952e Ctrl + N: \u65b0\u5730\u56fe Ctrl + O: \u6253\u5f00\u5730\u56fe \u5c06 .bin \u62d6\u5230\u7a97\u53e3\u4e0a: \u6253\u5f00\u5730\u56fe Ctrl + S: \u4fdd\u5b58\u5730\u56fe Ctrl + Shift + S: \u53e6\u5b58\u4e3a Ctrl + T: \u65b0\u623f\u95f4(\u9762) Ctrl + Shift + T: \u6253\u5f00\u5f53\u524d\u623f\u95f4\u5c5e\u6027\u9762\u677f Alt + \u65b9\u5411\u952e: \u79fb\u52a8\u623f\u95f4(\u6b65\u957f 8px) Alt + Delete: \u5220\u9664\u623f\u95f4 Ctrl + Z: \u64a4\u56de Ctrl + Shift + Z: \u91cd\u505a \u9f20\u6807\u6eda\u8f6e: \u7f29\u653e Ctrl + \u2795 (\u52a0\u53f7): \u653e\u5927 Ctrl + \u2796 (\u51cf\u53f7): \u7f29\u5c0f \u53cc\u51fb\u9f20\u6807\u4e2d\u952e: \u7f29\u653e\u81f3\u53ef\u4ee5\u770b\u89c1\u6574\u4e2a\u5730\u56fe F11: \u5207\u6362\u5168\u5c4f \u65b9\u5411\u952e: \u5217\u8868\u4e2d\u5bfc\u822a \u7269\u4f53\u653e\u7f6e \u5de6\u952e: \u653e\u7f6e\u7269\u4f53 (8px \u5bf9\u9f50) \u6309\u4f4f Ctrl \u65f6\u5de6\u952e: \u653e\u7f6e\u7269\u4f53 (1px \u5bf9\u9f50) \u53f3\u952e: \u6253\u5f00\u5149\u6807\u6240\u6307\u7269\u4f53\u7684\u5c5e\u6027\u9762\u677f \u5de6\u952e\u5e76\u62d6\u52a8: \u5728\u653e\u7f6e\u53ef\u8c03\u6574\u5927\u5c0f\u7684\u7269\u4f53\u65f6\u8c03\u6574\u7269\u4f53\u7684\u5927\u5c0f \u4e2d\u952e: \u590d\u5236\u5149\u6807\u6240\u6307\u7269\u4f53 Q, E: \u51cf\u5c0f\u5bbd\u5ea6 / \u589e\u5927\u5bbd\u5ea6 A, D: \u51cf\u5c0f\u9ad8\u5ea6 / \u589e\u5927\u9ad8\u5ea6 L, R: \u9006\u65f6\u9488/\u987a\u65f6\u9488 \u65cb\u8f6c\u7269\u4f53 V, H: \u7eb5\u5411/\u6a2a\u5411 \u7ffb\u8f6c\u7269\u4f53 \u7269\u4f53\u9009\u62e9 \u5de6\u952e: \u9009\u62e9\u7269\u4f53 \u5df2\u9009\u62e9\u67d0\u7269\u4f53\u65f6\u5de6\u952e: \u5faa\u73af\u9009\u62e9\u5149\u6807\u5e95\u4e0b\u7684\u7269\u4f53 (\u4ece\u5c0f\u5230\u5927) \u5de6\u952e\u62d6\u52a8: \u9009\u62e9\u591a\u4e2a\u7269\u4f53 Shift + \u5de6\u952e\u5e76\u62d6\u52a8: \u52a0\u5165\u7269\u4f53\u5230\u5f53\u524d\u5df2\u9009\u62e9\u7269\u4f53\u5217\u8868\u4e2d Ctrl + A: \u5168\u9009\u7269\u4f53 \u5df2\u9009\u62e9\u67d0\u7269\u4f53\u65f6\u53f3\u952e: \u6253\u5f00\u7269\u4f53\u7684\u5c5e\u6027\u9762\u677f \u5df2\u9009\u62e9\u67d0\u7269\u4f53\u65f6\u5de6\u952e\u5e76\u62d6\u52a8: \u62d6\u52a8\u6240\u9009\u7269\u4f53 Shift + \u5df2\u9009\u62e9\u67d0\u7269\u4f53\u65f6\u5de6\u952e\u5e76\u62d6\u52a8: \u8f74\u5411\u62d6\u52a8\u7269\u4f53, \u5373\u4ec5\u5141\u8bb8\u7269\u4f53\u4e0a\u4e0b\u6216\u5de6\u53f3\u79fb\u52a8 \u5df2\u9009\u62e9\u67d0\u7269\u4f53\u65f6\u65b9\u5411\u952e: \u79fb\u52a8\u6240\u9009\u7269\u4f53 Q, E: \u51cf\u5c0f\u5bbd\u5ea6 / \u589e\u5927\u5bbd\u5ea6 A, D: \u51cf\u5c0f\u9ad8\u5ea6 / \u589e\u5927\u9ad8\u5ea6 Ctrl + \u4e0a\u9762\u7684\u6309\u952e: \u4f7f\u7528 1px \u5bf9\u9f50\u800c\u4e0d\u662f 8px L, R: \u9006\u65f6\u9488/\u987a\u65f6\u9488 \u65cb\u8f6c\u7269\u4f53 V, H: \u7eb5\u5411/\u6a2a\u5411 \u7ffb\u8f6c\u7269\u4f53 Shift + V / Shift + H: \u7ad6\u76f4/\u7eb5\u5411 \u7ffb\u8f6c\u9009\u5b9a\u533a\u57df \u5bf9 \u5b9e\u4f53/Trigger \u6309 N: \u5411 \u5b9e\u4f53/Trigger \u52a0\u5165\u7b2c\u4e00\u4e2a\u8282\u70b9 \u5bf9\u8282\u70b9\u6309 N: \u5728\u5df2\u9009\u62e9\u7684\u8282\u70b9\u540e\u52a0\u5165\u4e00\u4e2a\u8282\u70b9 Delete: \u5220\u9664\u6240\u9009\u7269\u4f53 Ctrl + C: \u590d\u5236\u7269\u4f53\u5230\u526a\u5207\u677f Ctrl + X: \u526a\u5207\u7269\u4f53\u5230\u526a\u5207\u677f Ctrl + V: \u4ece\u526a\u5207\u677f\u7c98\u8d34\u7269\u4f53 Brushes \u5de6\u952e: \u653e\u7f6e tile \u5de6\u952e\u5e76\u62d6\u52a8: \u5237 tile \u4e2d\u952e: \u8bbe\u7f6e\u5f53\u524d tile \u7c7b\u578b\u4e3a\u5149\u6807\u4e0b\u7684 tile \u7c7b\u578b Stylegrounds \u65b9\u5411\u952e: \u5728\u5217\u8868\u4e2d\u5bfc\u822a Alt + \u65b9\u5411\u952e: \u66f4\u6539\u987a\u5e8f Debug \u6309\u952e F5: \u91cd\u8f7d\u6240\u6709\u5b9e\u4f53\u548c trigger F6: \u6e05\u9664\u7ed8\u56fe\u7f13\u5b58\u5e76\u91cd\u7ed8\u5730\u56fe F7: \u91cd\u8f7d\u5de5\u5177 Ctrl + F5: \u91cd\u8f7d\u6574\u4e2a L\u00f6nn Ctrl + Shift + F5: \u91cd\u542f L\u00f6nn "},{"location":"extra_cmcc/cmcc/todo/#q2-loenn","title":"Q2 Loenn \u600e\u4e48\u79fb\u52a8\u623f\u95f4","text":"Alt + \u65b9\u5411\u952e \u5176\u4ed6\u6309\u952e/\u5feb\u6377\u952e\u89c1 Q1 \u4e2d\u7684\u5217\u8868
"},{"location":"extra_cmcc/cmcc/todo/#q3-loenn","title":"Q3 Loenn \u600e\u4e48\u653e\u5b9e\u4f53","text":"\u5728\u53f3\u8fb9\u7684\u83dc\u5355\u7684\u5de6\u8fb9\u4e00\u5217\u4e2d\u9009\u62e9 Placements, \u518d\u5728\u4e0b\u9762\u9009\u62e9 Entities, \u5728\u53f3\u8fb9\u9009\u62e9\u4e00\u6761\u7136\u540e\u5728\u623f\u95f4\u91cc\u5de6\u952e\u5c31\u80fd\u653e\u7f6e\u4e86. \u6b64\u5916\u5728\u53f3\u8fb9\u90a3\u4e00\u5217\u7684\u5e95\u4e0b\u6709\u4e2a\u767d\u8272\u7684\u641c\u7d22\u6846, \u53ef\u4ee5\u641c\u7d20\u7269\u4f53. \u5bf9\u4e8e\u641c\u7d22\u7279\u5b9a helper \u7684\u7269\u4f53, \u53ef\u4ee5\u5728\u524d\u9762\u52a0\u4e0a @helper\u540d
, \u4f8b\u5982\u641c\u7d22\u91cd\u529b helper \u4e2d\u7684\u5f39\u7403\u53ef\u4ee5\u952e\u5165 @gravityhelper bumper
, \u53ef\u4ee5\u53ea\u6253\u8bcd\u5934: @gra bu
.
"},{"location":"extra_cmcc/cmcc/todo/#q4-tile","title":"Q4 \u5982\u4f55\u81ea\u5b9a\u4e49 tile","text":"\u53ef\u4ee5\u53c2\u8003:
Bilibili - \u7535\u7bb1 - \u5236\u56fe\u6559\u7a0b\u7b2c\u4e94\u7ae0 \u81ea\u5b9a\u4e49 Tiles Bilibili - UnderDragon - tiles \u5e94\u7528\u6559\u7a0b "},{"location":"extra_luacs/begin/","title":"\u989d\u5916 - LuaCutscene","text":""},{"location":"extra_luacs/begin/#_1","title":"\u524d\u8a00","text":"\u6b22\u8fce\u6765\u5230\u8fd9\u4e2a\u989d\u5916\u7ae0\u8282, \u867d\u7136\u5b83\u88ab\u6211\u6254\u5230\u4e86 code mod \u6559\u7a0b\u4e4b\u4e2d, \u4f46\u662f\u5b83\u5b9e\u9645\u4e0a\u4e0d\u9700\u8981\u592a\u591a\u7684 C# \u80fd\u529b. \u5728\u8fd9\u91cc\u4f1a\u4e3b\u8981\u5305\u542b\u4e00\u4e9b LuaCutscene \u672c\u8eab\u4ee5\u53ca\u4f7f\u7528\u5176\u8c03\u7528 C# \u4ee3\u7801\u5b9e\u73b0\u7684\u6709\u8da3\u7684\u6548\u679c, \u5982\u679c\u4f60\u60f3\u8981\u4f60\u7684\u5267\u60c5\u62e5\u6709\u66f4\u591a\u7684\u70ab\u9177\u6548\u679c, \u800c\u4e0d\u662f\u5c40\u9650\u4e8e\u53ea\u6709\u5bf9\u8bdd\u6846\u548c Madeline \u65e0\u804a\u7684\u8d70\u52a8, \u6bd4\u5982\u70ab\u9177\u7684\u955c\u5934\u7f13\u52a8, \u5468\u8fb9\u5b9e\u4f53\u7684\u82b1\u6837\u8868\u6f14, \u751a\u81f3\u662f\u62e5\u6709\u6539\u53d8 gp \u80fd\u529b\u7684\u5267\u60c5! \u90a3\u4e48\u6216\u8bb8\u8fd9\u91cc\u521a\u597d\u5c31\u9002\u5408\u4f60. \u90a3\u4e48\u73b0\u5728\u5c31\u5f00\u59cb\u5427.
"},{"location":"extra_luacs/begin/#_2","title":"\u914d\u7f6e\u73af\u5883","text":"\u8fd9\u4e00\u6b65\u4e8b\u5b9e\u4e0a\u662f\u53ef\u9009\u7684, \u4e0d\u8fc7\u4e3a\u4e86\u66f4\u6109\u5feb\u7684 lua \u4ee3\u7801\u7684\u4e66\u5199, \u6211\u4e2a\u4eba\u8fd8\u662f\u89c9\u5f97\u633a\u6709\u5fc5\u8981\u7684. \u5728\u8fd9\u91cc\u6211\u4f1a\u63a8\u8350\u4f7f\u7528 VSCode \u914d\u4e0a Lua (sumneko.lua) \u63d2\u4ef6.
Note
\u6211\u4e2a\u4eba\u4e0d\u592a\u4f1a\u914d\u7f6e\u8fd9\u79cd lua \u73af\u5883, \u6240\u4ee5\u5982\u679c\u4f60\u9047\u5230\u4e86\u5927\u91cf\u7684\u672a\u5b9a\u4e49\u8b66\u544a\u4f60\u53ef\u4ee5\u9009\u62e9\u5728\u8bbe\u7f6e\u4e2d\u641c\u7d22 Lua.diagnostics.enable
\u5e76\u5c06\u5176\u5173\u95ed.
"},{"location":"extra_luacs/begin/#hello-world","title":"Hello World","text":"\u90a3\u4e48, \u8001\u4f20\u7edf. \u73b0\u5728, \u5728\u4f60\u7684\u5730\u56fe\u4e2d\u653e\u7f6e\u4e00\u4e2a LuaCutscene
\u7684 LuaCutscene/LuaCutsceneTrigger
, \u7136\u540e\u8bbe\u7f6e\u5176 Filename
\u53c2\u6570\u4e3a\u4e00\u4e2a lua \u6587\u4ef6\u7684\u8def\u5f84\u6bd4\u5982 Luas/testlua
(\u6ce8\u610f\u6ca1\u6709\u540e\u7f00.lua), \u7136\u540e Save Changes. \u7136\u540e\u6211\u4eec\u6839\u636e\u521a\u624d\u8bbe\u7f6e\u7684\u8def\u5f84\u6b63\u786e\u653e\u7f6e\u6211\u4eec\u7684 lua \u6587\u4ef6:
<\u4f60\u7684 mod \u540d\u5b57> \u7136\u540e\u5199\u4e0a\u6211\u4eec\u7684 Hello World:
function onBegin()\n print(\"[Cutscene] Hello from the Cutscene!\")\nend\n
\u4fdd\u5b58\u540e\u6309\u4e0b F3 \u952e\u91cd\u8f7d\u4f60\u7684\u5730\u56fe, \u7136\u540e\u8d70\u8fdb\u4f60\u6446\u653e\u7684 trigger \u5185, \u4e4b\u540e, \u68c0\u67e5\u4f60\u7684\u63a7\u5236\u53f0, \u6216\u8005\u68c0\u67e5\u4f60\u6700\u65b0\u7684 log.txt, \u4f60\u5e94\u8be5\u4f1a\u5728\u832b\u832b\u65e5\u5fd7\u6d77\u4e2d\u770b\u5230\u8fd9\u4e00\u884c\u8f93\u51fa:
(12/03/2023 10:36:35) [Everest] [Info] [LevelLoader] Loading Saplonily/FunnyButFuckingMaps/MaybeAFunnyMap\n(12/03/2023 10:36:35) [Everest] [Warn] [Content] CONFLICT in C:\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\Mods\\MaxHelpingHand v1.28.3.zip\\Graphics\\Sprites.xml: Overriding element player_playback.\n[Cutscene] Hello from the Cutscene!\n(12/03/2023 10:36:45) [Everest] [Info] [LevelLoader] Loading Saplonily/FunnyButFuckingMaps/MaybeAFunnyMapOverriding element player_playback.\n
\u9ad8\u4eae\u884c\u4fbf\u662f\u6211\u4eec\u7684 lua \u4ee3\u7801\u6253\u5370\u51fa\u6765\u7684.
Info
\u5728\u4e4b\u540e\u7684\u8fc7\u7a0b\u4e2d\u867d\u7136\u4f60\u53ef\u4ee5\u53cd\u590d\u7ffb\u770b log.txt \u6765\u77e5\u6653\u4f60\u7684 lua \u4ee3\u7801\u7684\u8fd0\u884c\u60c5\u51b5, \u4e0d\u8fc7\u8fd9\u663e\u7136\u4e0d\u5982\u4f60\u6709\u4e00\u4e2a\u63a7\u5236\u53f0\u7a97\u53e3\u76f4\u63a5\u80fd\u770b\u5230\u8f93\u51fa. \u5bf9\u4e8e\u5728 windows \u4e0a, \u4f60\u53ef\u4ee5\u5411\u851a\u84dd\u6839\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6 everest-launch.txt
\u65b0\u52a0\u5165\u4e00\u884c --console
\u6765\u5728\u851a\u84dd\u6bcf\u6b21\u542f\u52a8\u65f6\u9644\u5e26\u4e00\u4e2a\u63a7\u5236\u53f0\u7a97\u53e3.
"},{"location":"extra_luacs/begin/#hello-world_1","title":"\u5bf9\u8bdd Hello World","text":"\u5f53\u7136, \u5728\u63a7\u5236\u53f0\u91cc\u770b\u65e0\u804a\u7684\u65e5\u5fd7\u6253\u5370\u662f\u6ca1\u610f\u601d\u7684, \u6240\u4ee5\u73b0\u5728\u6211\u4eec\u5411\u5b83\u52a0\u5165\u51e0\u6761\u5bf9\u8bdd. \u9996\u5148\u4e3a\u4f60\u8fd9\u4e00\u6bb5\u5bf9\u8bdd\u8d77\u4e00\u6bb5\u540d\u5b57, \u6bd4\u5982 TESTDIALOG_HELLO
, \u901a\u5e38\u6211\u4eec\u5efa\u8bae\u524d\u7f00\u662f\u4f60\u7684\u5730\u56fe\u540d\u4ee5\u9632\u547d\u540d\u51b2\u7a81, \u540e\u7f00\u4f60\u53ef\u4ee5\u6839\u636e\u4f60\u7684\u7231\u597d\u6765\u53d6, \u6bd4\u5982\u52a0\u4e0a\u5267\u60c5\u6240\u5728\u9762\u540d, \u6216\u8005\u5e72\u8106\u662f\u5267\u60c5\u7684\u81ea\u589e\u5e8f\u53f7. \u7136\u540e\u65b0\u5efa\u4e00\u4e2a Simplified Chinese.txt
, \u4e5f\u5c31\u662f\u5bf9\u8bdd\u6587\u4ef6:
<\u4f60\u7684 mod \u540d\u5b57> \u4ee5\u53ca\u5b83\u7684\u5185\u5bb9:
TESTDIALOG_HELLO=\n [MADELINE left normal]\n \u6211\u662f {+MADELINE}.\n
\u7136\u540e\u66f4\u6539 lua \u4ee3\u7801:
function onBegin()\n say(\"TESTDIALOG_HELLO\")\nend\n
\u73b0\u5728\u91cd\u8f7d\u8d44\u6e90, \u8fdb\u5165 trigger, \u4f60\u5c31\u80fd\u770b\u5230 Madeline \u5fae\u7b11\u200b\u7740\u8bf4 \"\u6211\u662f <\u4f60\u7684\u5b58\u6863\u540d>.\" \u4e86. \u5728\u8fd9\u91cc\u5bf9\u8bdd\u72b6\u6001\u65f6\u73a9\u5bb6\u4f9d\u7136\u80fd\u52a8, \u53ef\u4ee5\u901a\u8fc7\u5c06 lua \u4ee3\u7801\u6539\u6210\u8fd9\u6837\u6765\u5728\u5bf9\u8bdd\u8fdb\u884c\u65f6\u7981\u6b62\u79fb\u52a8:
function onBegin()\n disableMovement()\n say(\"TESTDIALOG_HELLO\")\n enableMovement()\nend\n
\u5bf9\u8bdd dialog \u6587\u4ef6\u7684\u76f8\u5173\u5185\u5bb9\u8fd9\u91cc\u5c31\u4e0d\u7ec6\u5199\u4e86, \u63a8\u8350\u53c2\u8003\u851a\u84dd\u5236\u56fe\u6559\u7a0b\u7684\u51ac\u83dc\u6559\u7a0b, \u4f60\u53ef\u4ee5\u5230\u851a\u84dd\u7684\u5236\u56fe\u7fa4 (633125440) \u4e2d\u53d6\u5f97, \u6216\u8005\u4e5f\u53ef\u4ee5\u5728\u8fd9\u4e2a\u7f51\u76d8\u94fe\u63a5\u4e2d\u53d6\u5f97.
"},{"location":"extra_luacs/begin/#_3","title":"\u57fa\u7840\u6982\u5ff5","text":"\u76f8\u4fe1\u5728\u524d\u9762\u7684\u9605\u8bfb\u4e2d\u4f60\u80af\u5b9a\u662f\u4e00\u5934\u96fe\u6c34\u7684, \u56e0\u4e3a\u4f60\u5bf9 lua \u4ee3\u7801\u901a\u5e38\u4f9d\u7136\u662f\u4e00\u65e0\u6240\u77e5\u7684, \u90a3\u5c31\u5bf9\u4e86, \u73b0\u5728\u6211\u4eec\u5c31\u6765\u4ecb\u7ecd\u51e0\u4e2a\u7b80\u5355\u7684\u6982\u5ff5.
"},{"location":"extra_luacs/begin/#_4","title":"\u51fd\u6570","text":"\u5728\u6211\u4eec\u521a\u521a\u7684 lua \u4ee3\u7801\u4e2d, \u6700\u5916\u56f4\u7684\u7531 function
\u5230 end
\u56f4\u8d77\u6765\u7684\u4e1c\u897f\u6211\u4eec\u5c31\u53eb\u4e00\u4e2a\u51fd\u6570:
function onBegin()\n disableMovement()\n say(\"TESTDIALOG_HELLO\")\n enableMovement()\nend\n
function
\u548c end
\u8fd9\u79cd\u5173\u7cfb\u5230\u4ee3\u7801\u7ed3\u6784\u7684\u4e1c\u897f\u6211\u4eec\u5c31\u53eb\u5b83 '\u5173\u952e\u5b57', function
\u5173\u952e\u5b57\u540e\u9762\u5230\u5de6\u62ec\u53f7\u4e4b\u5185\u7684\u5185\u5bb9\u5c31\u662f\u8fd9\u4e2a\u51fd\u6570\u7684\u51fd\u6570\u540d, \u5728\u8fd9\u91cc\u5373 onBegin
, \u5728\u8fd9\u91cc\u8fd9\u4e2a\u51fd\u6570\u540d\u662f\u7279\u6b8a\u7684, \u5b83\u4f1a\u88ab LuaCutscene \u5728\u73a9\u5bb6\u8fdb\u5165 trigger \u65f6\u4e14\u5267\u60c5\u53ef\u4ee5\u64ad\u653e\u65f6 '\u8c03\u7528'. \u62ec\u53f7\u5185\u7684\u5185\u5bb9\u6211\u4eec\u53eb\u53c2\u6570, \u8fd9\u91cc LuaCutscene \u8981\u6c42\u6211\u4eec onBegin
\u8fd9\u4e2a\u7279\u6b8a\u51fd\u6570\u4e0d\u80fd\u5e26\u53c2\u6570\u6216\u8005\u5e26\u4e00\u4e2a\u53c2\u6570, \u8fd9\u91cc\u6211\u4eec\u6682\u65f6\u7f6e\u7a7a, \u4e5f\u5c31\u662f\u53ea\u6709\u4e00\u5bf9\u62ec\u53f7, \u4e0d\u5e26\u53c2\u6570. \u800c\u8fd9\u4e4b\u4e2d\u7684\u5185\u5bb9\u4fbf\u662f\u51fd\u6570\u7684\u5185\u5bb9\u7269, \u4e5f\u5373\u4e3b\u4f53, \u5b83\u4f1a\u4ece\u4e0a\u5230\u4e0b\u987a\u5e8f\u6267\u884c\u6211\u4eec\u7684\u4ee3\u7801.
\u901a\u5e38\u4e3b\u4f53\u662f\u6211\u4eec\u6240\u805a\u7126\u7684\u4e1c\u897f, \u5728\u8fd9\u91cc, \u6211\u4eec\u7684\u4e3b\u4f53\u5305\u542b\u4e09\u884c\u4ee3\u7801. \u7b2c\u4e00\u884c\u4ee3\u7801\u662f disableMovement()
, \u4e5f\u5c31\u662f\u4e00\u4e2a\u540d\u79f0\u52a0\u4e0a\u4e00\u5bf9\u62ec\u53f7, \u5b83\u8868\u793a\u8c03\u7528\u4e00\u4e2a\u540d\u4e3a disableMovement
\u7684\u51fd\u6570, \u5e76\u4e14\u4e0d\u5e26\u53c2\u6570, \u8fd9\u548c\u521a\u624d\u51fd\u6570\u7684\u58f0\u660e\u6709\u70b9\u76f8\u50cf, disableMovement
\u662f\u4e00\u4e2a LuaCutscene \u4e3a\u6211\u4eec\u63d0\u524d\u51c6\u5907\u597d\u7684, \u4e5f\u5373 '\u5b9a\u4e49' \u597d\u7684\u51fd\u6570, \u5b83\u7684\u4f5c\u7528\u662f\u7981\u6b62\u73a9\u5bb6\u7684\u79fb\u52a8, \u4e0e\u4e4b\u76f8\u5bf9\u7684\u5c31\u662f enableMovement
\u51fd\u6570, \u5b83\u4f1a\u5141\u8bb8\u73a9\u5bb6\u79fb\u52a8. \u4e2d\u95f4\u7684\u7b2c\u4e8c\u884c\u4ee3\u7801\u8c03\u7528\u4e86 say
\u8fd9\u4e2a\u51fd\u6570, \u5b83\u8868\u793a\u64ad\u653e\u4e00\u4e2a\u5bf9\u8bdd, \u90a3\u4e48\u8fd9\u91cc\u5bf9\u8bdd\u540d\u5c31\u9700\u8981\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u4e86, \u6240\u4ee5\u6211\u4eec\u5728\u62ec\u53f7\u4e2d\u5199\u5165\u521a\u624d\u6211\u4eec\u7684\u5bf9\u8bdd\u540d TESTDIALOG_HELLO
, \u8bb0\u4f4f\u8981\u5e26\u53cc\u5f15\u53f7, \u56e0\u4e3a\u5b83\u662f\u4e00\u4e2a '\u5b57\u7b26\u4e32'.
Info
disableMovement
\u4e0e enableMovement
\u51fd\u6570\u90fd\u662f\u77ac\u95f4\u6267\u884c\u5b8c\u6bd5\u7684, \u51fd\u6570\u4f1a\u9a6c\u4e0a\u7ee7\u7eed\u6267\u884c\u4e0b\u9762\u7684\u4ee3\u7801, \u800c say
\u51fd\u6570\u8c03\u7528\u540e\u76f4\u5230\u73a9\u5bb6\u770b\u5b8c\u5bf9\u8bdd\u624d\u4f1a\u7ee7\u7eed\u6267\u884c\u4e0b\u9762\u7684\u4ee3\u7801. \u5bf9\u4e8e\u540e\u8005\u6211\u4eec\u7279\u522b\u5730\u79f0\u4e3a \u534f\u7a0b\u51fd\u6570
.
"},{"location":"extra_luacs/begin/#if","title":"\u53d8\u91cf, \u8fd4\u56de\u503c, if","text":"\u73b0\u5728, \u6211\u4eec\u89c2\u5bdf\u4e0b\u9762\u4ee3\u7801:
function onBegin()\n local hasFlag = getFlag(\"MY_AWESOME_FLAG\")\n if hasFlag then\n disableMovement()\n say(\"TESTDIALOG_HELLO\")\n enableMovement()\n end\nend\n
\u5728\u51fd\u6570\u5f00\u5934\u6211\u4eec\u4f7f\u7528\u4e86 local a = b()
\u8fd9\u79cd\u8bed\u6cd5, \u5f00\u5934\u7684 local
\u5173\u952e\u5b57\u8868\u793a\u6211\u4eec\u8981\u58f0\u660e\u4e00\u4e2a\u53d8\u91cf, \u7d27\u8ddf\u7684 hasFlag
\u8868\u793a\u8fd9\u4e2a\u53d8\u91cf\u7684\u540d\u79f0, \u968f\u540e\u518d\u6b21\u8ddf\u4e0a\u4e00\u4e2a =
\u53f7, \u8fd9\u8868\u793a\u6211\u4eec\u60f3\u4ee5 =
\u53f7\u540e\u8fb9\u7684\u503c\u4f5c\u4e3a\u8fd9\u4e2a\u53d8\u91cf\u7684\u503c, \u5728\u8fd9\u91cc\u5b83\u662f getFlag
\u8fd9\u4e2a\u9884\u5148\u5b9a\u4e49\u7684\u51fd\u6570\u7684\u8fd4\u56de\u503c, \u51fd\u6570\u901a\u5e38\u7528\u4e8e\u505a\u4e00\u4e9b\u4e8b\u60c5, \u800c\u5b83\u7684\u8fd4\u56de\u503c\u5c31\u8868\u793a\u8fd9\u4ef6\u4e8b\u505a\u7684\u5982\u4f55, \u5728\u8fd9\u91cc getFlag
\u51fd\u6570\u7528\u4e8e\u68c0\u6d4b\u5b83\u7684\u53c2\u6570\u6307\u4ee3\u7684\u90a3\u4e2a flag \u662f\u5426\u5b58\u5728, \u5f53\u68c0\u6d4b\u5230 flag \u5b58\u5728\u65f6\u5b83\u4f1a\u8fd4\u56de true
, \u5426\u4e4b\u5219\u8fd4\u56de false
. \u8fd9\u91cc\u8fd9\u4e2a\u8fd4\u56de\u503c\u7684 '\u7c7b\u578b' \u662f bool
, \u5b83\u53ea\u6709\u521a\u624d\u63d0\u5230\u7684\u4e24\u4e2a\u503c, \u6240\u4ee5\u540c\u6837\u5730 hasFlag
\u8fd9\u4e2a\u53d8\u91cf\u7684\u7c7b\u578b\u662f bool
.
\u5f53\u6211\u4eec\u4ece getFlag
\u5f97\u5230\u4e86\u5bf9\u5e94 flag \u662f\u5426\u5b58\u5728\u7684\u4fe1\u606f\u540e, \u6211\u4eec\u4f7f\u7528 if \u8bed\u53e5\u6765\u68c0\u6d4b\u5b83, \u9996\u5148\u6211\u4eec\u4ee5 if
\u5f00\u5934, \u7136\u540e\u7d27\u8ddf\u4e00\u4e2a bool
\u7c7b\u578b\u7684\u503c, \u4e5f\u5c31\u662f\u8fd9\u91cc\u7684 hasFlag
\u53d8\u91cf, \u7136\u540e\u518d\u8ddf\u4e0a\u4e00\u4e2a then
\u5173\u952e\u5b57, \u968f\u540e\u518d\u6b21\u8ddf\u4e0a\u4e00\u5c0f\u6bb5\u4ee3\u7801, \u968f\u540e\u4ee5 end
\u7ed3\u675f, \u8fd9\u91cc\u7684\u610f\u601d\u5c31\u662f\u6211\u4eec\u5e0c\u671b then
\u5230 end
\u6240\u5305\u56f4\u8d77\u6765 '\u4ee3\u7801\u5757' \u4ec5\u5728 hasFlag
\u4e3a true
, \u4e5f\u5373 getFlag
\u8fd4\u56de true
, \u4e5f\u5373 flag MY_AWESOME_FLAG
\u5b58\u5728\u65f6\u6267\u884c. \u73b0\u5728\u4f60\u53ef\u4ee5\u8bd5\u8bd5\u590d\u5236\u4e0a\u8ff0\u7684\u4ee3\u7801, \u7136\u540e\u5728\u4f60\u7684\u5730\u56fe\u4e2d\u653e\u7f6e\u4e24\u4e2a flag Trigger, \u4e00\u4e2a\u5f00\u542f MY_AWESOME_FLAG
\u8fd9\u4e2a flag, \u4e00\u4e2a\u5173\u95ed flag, \u7136\u540e\u5206\u522b\u5c1d\u8bd5\u8d70\u8fdb\u5267\u60c5 trigger, \u4f60\u5f88\u5bb9\u6613\u4f1a\u53d1\u73b0\u4ec5\u5728 MY_AWESOME_FLAG
flag \u5f00\u542f\u65f6\u5267\u60c5\u624d\u4f1a\u88ab\u64ad\u653e, \u4e5f\u5c31\u662f\u64ad\u653e\u5267\u60c5\u7684\u90a3\u4e09\u884c\u4ee3\u7801\u624d\u4f1a\u88ab\u6267\u884c.
\u5b9e\u9645\u4e0a\u65e2\u7136 if
\u5230 then
\u4e4b\u95f4\u53ea\u9700\u8981\u4e00\u4e2a\u7c7b\u578b\u4e3a bool
\u7684\u503c, \u90a3\u4e48\u8fd9\u91cc\u5176\u5b9e\u4e0d\u9700\u8981 hasFlag
\u8fd9\u4e2a\u53d8\u91cf\u4f5c\u4e3a\u8fc7\u6e21:
function onBegin()\n if getFlag(\"MY_AWESOME_FLAG\") then\n disableMovement()\n say(\"TESTDIALOG_HELLO\")\n enableMovement()\n end\nend\n
\u8fd9\u884c\u4ee3\u7801\u4e0e\u4e0a\u9762\u662f\u7b49\u6548\u7684.
\u901a\u5e38\u6709\u65f6\u5019\u6211\u4eec\u5e0c\u671b flag \u62e5\u6709\u60c5\u51b5\u4e0d\u4e00\u7684\u65f6\u5019\u64ad\u653e\u4e0d\u540c\u7684\u5267\u60c5, \u6bd4\u5982\u4e0a\u9762\u62e5\u6709 MY_AWESOME_FLAG
flag \u65f6\u64ad\u653e\u5267\u60c5 A, \u800c\u6ca1\u6709\u65f6\u64ad\u653e\u5267\u60c5 B. \u9996\u5148\u6211\u4eec\u5148\u66f4\u65b0\u6211\u4eec\u7684\u5bf9\u8bdd\u6587\u4ef6:
TESTDIALOG_HELLO=\n [MADELINE left normal]\n \u62e5\u6709 flag\n\nTESTDIALOG_HELLO_NOFLAG=\n [MADELINE left normal]\n \u6ca1\u6709 flag\n
\u7136\u540e\u66f4\u65b0 lua \u4ee3\u7801:
function onBegin()\n if getFlag(\"MY_AWESOME_FLAG\") then\n disableMovement()\n say(\"TESTDIALOG_HELLO\")\n enableMovement()\n else\n disableMovement()\n say(\"TESTDIALOG_HELLO_NOFLAG\")\n enableMovement()\n end\nend\n
\u73b0\u5728\u5728\u6e38\u620f\u4e2d\u5c1d\u8bd5\u4e00\u4e0b, \u7b26\u5408\u6211\u4eec\u7684\u671f\u671b: \u6ca1\u6709 flag \u65f6\u64ad\u653e TESTDIALOG_HELLO_NOFLAG
\u8fd9\u4e2a\u5bf9\u8bdd, \u62e5\u6709 flag \u65f6\u64ad\u653e TESTDIALOG_HELLO
\u8fd9\u4e2a\u5bf9\u8bdd.
\u89c2\u5bdf\u4e0a\u8ff0\u4ee3\u7801, \u6211\u4eec\u53d1\u73b0\u7981\u6b62\u548c\u5141\u8bb8\u79fb\u52a8\u7684\u90a3\u4e00\u5bf9\u51fd\u6570\u8c03\u7528\u6ca1\u5fc5\u8981\u91cd\u590d\u4e24\u904d\u5199\u5728 if \u91cc, \u56e0\u4e3a\u65e0\u8bba if \u7684\u6761\u4ef6\u662f\u5426\u6210\u7acb\u5b83\u4eec\u90fd\u662f\u5148\u7981\u6b62\u79fb\u52a8, \u7136\u540e\u518d\u5141\u8bb8\u79fb\u52a8, \u6240\u4ee5\u6211\u4eec\u5c06\u90a3\u4e00\u5bf9\u4ee3\u7801\u62bd\u79bb\u5e76\u653e\u7f6e\u5728\u6700\u4e0a\u4e0b:
function onBegin()\n disableMovement()\n if getFlag(\"MY_AWESOME_FLAG\") then\n say(\"TESTDIALOG_HELLO\")\n else\n say(\"TESTDIALOG_HELLO_NOFLAG\")\n end\n enableMovement()\nend\n
\u5f53\u7136, \u6548\u679c\u662f\u4e00\u6837\u7684, \u4f46\u662f\u6211\u4eec\u7684\u4ee3\u7801\u7b80\u6d01\u4e86\u4e0d\u5c11.
"},{"location":"extra_luacs/begin/#_5","title":"\u66f4\u591a\u51fd\u6570","text":"\u73b0\u5728, \u56de\u5fc6\u4e00\u4e0b\u6211\u4eec\u5df2\u7ecf\u4e86\u89e3\u5230\u4e86\u54ea\u4e9b\u51fd\u6570:
\u4e00\u4e2a\u6700\u4e0a\u9762\u4f7f\u7528\u8fc7\u7684\u51fd\u6570 print
, \u4f5c\u7528\u4e3a\u5c06\u5b83\u7684\u53c2\u6570\u5185\u5bb9\u8f93\u51fa\u51fa\u6765 disableMovement
, \u6ca1\u6709\u53c2\u6570, \u4f5c\u7528\u4e3a\u7981\u6b62\u73a9\u5bb6\u7684\u79fb\u52a8 enableMovement
, \u6ca1\u6709\u53c2\u6570, \u4f5c\u7528\u4e3a\u5141\u8bb8\u73a9\u5bb6\u7684\u79fb\u52a8 say
, \u4f5c\u7528\u4e3a\u64ad\u653e\u53c2\u6570\u6240\u6307\u7684\u5bf9\u8bdd getFlag
, \u4f5c\u7528\u4e3a\u68c0\u6d4b\u53c2\u6570\u6240\u6307\u7684 flag \u662f\u5426\u5b58\u5728, \u5e76\u4e14\u8fd4\u56de\u8be5\u503c \u5f53\u7136, \u51fd\u6570\u7684\u53c2\u6570\u4e0d\u53ef\u80fd\u53ea\u6709\u4e00\u4e2a, \u6bd4\u5982 cassetteFly
\u51fd\u6570:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\n -- cassetteFly \u8c03\u7528\u5b8c\u540e\u5e76\u4e0d\u4f1a\u7b49\u5f85...\n enableMovement()\nend\n
Info
-- \u5e76\u52a0\u4e0a\u7a7a\u683c\u8d77\u5934\u7684\u4e00\u884c\u8868\u793a\u4e00\u884c\u6ce8\u91ca, \u5f53\u4ee3\u7801\u6267\u884c\u5230\u8fd9\u65f6\u4f1a\u76f4\u63a5\u5ffd\u7565\u8fd9\u4e00\u884c, \u6b64\u5916\u8fd8\u6709\u5757\u6ce8\u91ca, \u5373\u5ffd\u7565\u5757\u6240\u5305\u56f4\u7684\u4e00\u6574\u5757\u4ee3\u7801:
function onBegin()\n --[[\n \u5728\u8fd9\u91cc\n \u5199\n \u4efb\u610f\n \u591a\n \u7684\u6ce8\u91ca!\n ]]--\n say(\"SOMETHING_INTERESTING\")\nend\n
cassetteFly
\u51fd\u6570\u4f5c\u7528\u4e3a\u4e58\u5750\u6ce1\u6ce1\u98de\u884c\u4e00\u6bb5\u8ddd\u79bb(\u6536\u96c6\u78c1\u5e26\u540e\u7684\u52a8\u4f5c), \u5b83\u9700\u8981\u63a5\u6536\u4e24\u4e2a\u53c2\u6570, \u5b83\u4eec\u5747\u4e3a number
\u7c7b\u578b, \u8868\u793a\u4e00\u4e2a\u6570\u5b57, \u591a\u4e2a\u53c2\u6570\u4e4b\u95f4\u4f7f\u7528 ,
\u9017\u53f7\u5206\u9694\u5f00\u6765, \u6ce8\u610f\u8fd9\u91cc\u53c2\u6570\u7c7b\u578b\u662f\u6570\u5b57, \u6240\u4ee5\u4e0d\u9700\u8981\u52a0\u4e0a\u53cc\u5f15\u53f7\u8868\u793a\u4e3a\u5b57\u7b26\u4e32. \u7b2c\u4e00\u4e2a\u53c2\u6570\u8868\u793a\u6a2a\u5411\u7684\u76f8\u5bf9\u98de\u884c\u8ddd\u79bb, \u5355\u4f4d px, \u6b63\u503c\u5411\u53f3, \u8d1f\u503c\u5411\u5de6, \u7b2c\u4e8c\u4e2a\u53c2\u6570\u8868\u793a\u7eb5\u5411\u7684\u76f8\u5bf9\u98de\u884c\u8ddd\u79bb, \u6b63\u503c\u5411\u4e0b, \u8d1f\u503c\u5411\u4e0a.
\u4e0d\u8fc7\u4e0d\u592a\u597d\u7684\u662f cassetteFly
\u4e0d\u662f\u534f\u7a0b\u51fd\u6570, \u8fd9\u4f1a\u9020\u6210\u8c03\u7528\u4e86\u8be5\u51fd\u6570\u540e\u9a6c\u4e0a\u8c03\u7528 enableMovement
\u51fd\u6570, \u8fd9\u4f1a\u6253\u65ad\u6ce1\u6ce1\u98de\u884c\u7684\u8fc7\u7a0b, \u6240\u4ee5\u6211\u4eec\u5148\u6682\u65f6\u5220\u6389 enableMovement
\u7684\u8c03\u7528, \u4e0d\u8fc7\u4e0d\u8981\u62c5\u5fc3, \u6ce1\u6ce1\u98de\u884c\u7ed3\u675f\u540e\u4f1a\u81ea\u52a8\u5e2e\u6211\u4eec\u5141\u8bb8\u79fb\u52a8:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\nend\n
\u7136\u540e\u5230\u6e38\u620f\u4e2d\u89c2\u5bdf\u8fd9\u4e2a\u6ce1\u6ce1\u98de\u884c\u8fdb\u884c\u6240\u9700\u7684\u5927\u6982\u65f6\u95f4, \u53d1\u73b0\u5927\u6982\u662f 1.5 \u79d2, \u6240\u4ee5\u6211\u4eec\u5728\u6ce1\u6ce1\u98de\u884c\u7684\u8c03\u7528\u540e\u9762\u7d27\u8ddf\u4e00\u4e2a wait
\u7684\u8c03\u7528:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\n wait(1.5)\nend\n
\u987a\u4fbf, \u6ce1\u6ce1\u98de\u884c\u7ed3\u675f\u540e\u4f1a\u81ea\u52a8\u5141\u8bb8\u79fb\u52a8, \u6240\u4ee5\u6211\u4eec\u8fd8\u5f97\u518d\u6b21\u7981\u6389\u79fb\u52a8:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\n wait(1.5)\n disableMovement()\nend\n
\u4ee5\u53ca, \u6211\u4eec\u8fd8\u5e0c\u671b\u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e4b\u540e\u518d\u64ad\u653e\u4e00\u6bb5\u5bf9\u8bdd:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\n wait(1.5)\n disableMovement()\n say(\"TESTDIALOG_FLY\")\nend\n
\u8fd9\u662f\u5bf9\u5e94\u7684 dialog:
TESTDIALOG_FLY=\n [MADELINE left normal]\n \u563f\u6211\u521a\u624d\u5b8c\u6210\u4e86\u4e00\u6b21\u6ce1\u6ce1\u98de\u884c\u54ce\n
\u987a\u4fbf\u4e0d\u8981\u5fd8\u4e86\u518d\u5141\u8bb8\u79fb\u52a8:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\n wait(1.5)\n disableMovement()\n say(\"TESTDIALOG_FLY\")\n enableMovement()\nend\n
\u73b0\u5728\u5728\u6e38\u620f\u91cc\u8bd5\u4e00\u4e0b, \u662f\u4e0d\u662f\u5148\u5411\u5de6\u4e0a\u89d2\u8fdb\u884c\u4e00\u4e2a (-100, -100) \u7684\u6ce1\u6ce1\u98de\u884c, \u7136\u540e\u8fc7\u4e86 1.5 \u79d2\u540e\u51c6\u65f6\u64ad\u653e TESTDIALOG_FLY
\u8fd9\u4e2a\u5bf9\u8bdd, \u7136\u540e\u4ec5\u5728\u5bf9\u8bdd\u7ed3\u675f\u540e\u624d\u80fd\u79fb\u52a8?
\u9664\u4e86\u4f7f\u7528 flag trigger \u8bbe\u7f6e flag \u4ee5\u5916, \u8fd8\u53ef\u4ee5\u5728 lua \u4e2d\u8bbe\u7f6e flag:
function onBegin()\n setFlag(\"FLAG_FROM_LUA\", true)\nend\n
setFlag
\u51fd\u6570\u63a5\u6536\u4e24\u4e2a\u53c2\u6570, \u7b2c\u4e00\u4e2a\u53c2\u6570\u4e3a string \u7c7b\u578b, \u6307\u4ee3\u4e00\u4e2a flag, \u7b2c\u4e8c\u4e2a\u53c2\u6570\u4e3a bool \u7c7b\u578b, \u8868\u793a\u8981\u8bbe\u7f6e\u4e3a\u5f00\u542f\u8fd8\u662f\u5173\u95ed. \u90a3\u4e48\u663e\u800c\u6613\u89c1, \u6548\u679c\u5c31\u662f\u7ecf\u8fc7\u8fd9\u4e2a \"\u5267\u60c5\" trigger \u65f6 FLAG_FROM_LUA
\u8fd9\u4e2a flag \u4f1a\u88ab\u5f00\u542f. \u4f60\u53ef\u4ee5\u627e\u4e00\u4e9b\u5176\u4ed6\u7684 flag \u9a71\u52a8\u7684\u5b9e\u4f53\u6765\u9a8c\u8bc1\u4e00\u4e0b.
\u987a\u4fbf\u6211\u4eec\u8fd8\u53ef\u4ee5\u505a\u4e00\u4e2a\u6709\u8da3\u7684\u6548\u679c, \u7ecf\u8fc7 trigger \u65f6\u53cd\u8f6c\u5f00\u542f\u72b6\u6001:
function onBegin()\n setFlag(\"FLAG_FROM_LUA\", not getFlag(\"FLAG_FROM_LUA\"))\nend\n
getFlag
\u8fd4\u56de\u4e86\u4e00\u4e2a bool \u7c7b\u578b\u7684\u503c, \u7136\u540e\u6211\u4eec\u5728\u8fd9\u4e2a\u503c, \u5728\u8fd9\u91cc\u662f\u51fd\u6570\u8c03\u7528\u7684\u8fd4\u56de\u503c\u5de6\u4fa7\u5199\u4e00\u4e2a not, \u5b83\u8868\u793a\u7ffb\u8f6c bool \u7684\u503c, \u5373 true -> false, false -> true, \u90a3\u4e48\u5728\u8fd9\u91cc\u5c31\u662f\u6bcf\u6b21\u89e6\u53d1 trigger \u65f6 FLAG_FROM_LUA
\u7684\u5f00\u542f\u72b6\u6001\u88ab\u53cd\u8f6c.
"},{"location":"extra_luacs/begin/#_6","title":"\u903b\u8f91\u8fd0\u7b97\u7b26","text":"\u5bf9\u4e8e\u8fd9\u4e9b lua \u901a\u7528\u5185\u5bb9\u5c31\u76f4\u63a5\u4e22\u4e2a w3c \u7684\u94fe\u63a5\u4e86: Lua \u8fd0\u7b97\u7b26 w3cschool - https://www.w3cschool.cn/...
\u8fd0\u7528\u4e0a\u9762\u7684\u77e5\u8bc6\u4f60\u53ef\u4ee5\u5199\u4e00\u4e2a if \u4f7f\u5f97\u4ec5\u5728\u4e24\u4e2a flag \u540c\u65f6\u6210\u7acb\u65f6\u624d\u6267\u884c\u5185\u90e8\u7684\u4ee3\u7801:
function onBegin()\n local flagA = getFlag(\"MY_FLAG_A\")\n local flagB = getFlag(\"MY_FLAG_B\")\n\n if flagA and flagB then\n print(\"\u540c\u65f6\u6210\u7acb!\")\n end\nend\n
"},{"location":"extra_luacs/begin/#_7","title":"\u5176\u4ed6\u7279\u6b8a\u51fd\u6570","text":"\u9664\u4e86\u4e0a\u6587\u63d0\u5230\u7684 onBegin
\u8fd9\u4e2a\u7279\u6b8a\u51fd\u6570\u5916, \u8fd8\u6709\u53e6\u5916\u4e00\u4e2a\u7ecf\u5e38\u7528\u5230\u7684 onEnd
\u51fd\u6570, \u987e\u540d\u601d\u4e49, \u5c31\u662f\u5267\u60c5\u7ed3\u675f\u65f6\u88ab\u8c03\u7528\u7684\u51fd\u6570, \u5b83\u901a\u5e38\u4f1a\u5e26\u4e24\u4e2a\u53c2\u6570:
function onEnd(room, wasSkipped)\n -- \u505a\u4e00\u4e9b\u6e05\u7406\u5de5\u4f5c...\nend\n
\u901a\u5e38\u6211\u4eec\u53ea\u4f1a\u5728 onEnd
\u8c03\u7528\u4e2d\u505a\u6e05\u7406\u5de5\u4f5c, \u6bd4\u5982\u8bf4\u5220\u6389\u5267\u60c5\u4e2d\u51fa\u73b0\u7684\u989d\u5916\u5b9e\u4f53, \u8bbe\u7f6e\u73a9\u5bb6\u7684\u4f4d\u7f6e\u5230\u6700\u7ec8\u4f4d\u7f6e\u7b49\u7b49, \u6ce8\u610f\u7684\u662f, \u8df3\u8fc7\u5267\u60c5\u8fd9\u4e2a\u52a8\u4f5c\u5b9e\u9645\u4e0a\u4f1a\u76f4\u63a5\u6253\u65ad onBegin
\u7684\u6267\u884c, \u5e76\u4e14\u4e5f\u4f1a\u8c03\u7528 onEnd
, \u8fd9\u4e2a\u6253\u65ad\u4f4d\u7f6e\u662f\u4e0d\u53ef\u9884\u77e5. \u5176\u4e2d\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f Level
\u7c7b\u578b\u7684\u503c, \u5b83\u662f\u4e00\u4e2a\u851a\u84dd\u4ee3\u7801\u4e2d\u7684\u7c7b\u578b, \u8fd9\u91cc\u6211\u4eec\u6682\u65f6\u5ffd\u7565, \u6765\u5173\u6ce8\u7b2c\u4e8c\u4e2a\u53c2\u6570, \u5b83\u662f\u4e00\u4e2a bool
\u7c7b\u578b\u7684\u503c, \u5b83\u8868\u793a\u8fd9\u4e2a\u5267\u60c5\u662f\u81ea\u7136\u7ed3\u675f\u7684\u8fd8\u662f\u88ab\u8df3\u8fc7\u7684, \u6bd4\u5982\u5728\u4e00\u4e9b\u79fb\u52a8\u8f83\u591a\u7684\u5267\u60c5\u4e2d~(\u591a\u52a8\u75c7) ~, \u5176 onEnd
\u5c31\u4f1a\u901a\u5e38\u662f\u8bbe\u7f6e\u73a9\u5bb6\u7684\u4f4d\u7f6e\u5230\u6700\u7ec8\u4f4d\u7f6e, \u987a\u5e26\u4e00\u63d0, \u5b98\u56fe\u4e2d\u6709\u4e9b\u5267\u60c5\u7684\u4f4d\u7f6e\u8bbe\u7f6e\u53ea\u8bbe\u7f6e\u4e86\u6a2a\u5750\u6807, \u6240\u4ee5\u6bd4\u5982 5a \u8fdb\u5165\u5185\u90e8\u90a3\u6bb5\u8def\u7684\u5728\u534a\u7a7a\u4e2d\u8df3\u8fc7\u5267\u60c5\u6765\u76f4\u63a5\u6a2a\u5411\u79fb\u52a8\u5230\u6309\u94ae\u4e0a\u7684\u901f\u901a\u6280\u5de7\u624d\u5f97\u4ee5\u5b9e\u73b0.
\u6ce8\u610f\u7684\u662f, onEnd
\u51fd\u6570\u4e2d\u4e0d\u80fd\u4f7f\u7528\u534f\u7a0b\u51fd\u6570, \u5982\u679c\u4f60\u8fd9\u4e48\u505a\u4e86\u4f60\u4f1a\u5f97\u5230\u4e00\u4e2a attempt to yield from outside a coroutine
\u7684\u62a5\u9519, \u8fd9\u662f\u56e0\u4e3a onBegin
\u51fd\u6570\u672c\u8eab\u4e5f\u662f\u4e00\u4e2a\u534f\u7a0b\u51fd\u6570, \u8fd9\u624d\u5141\u8bb8\u4f60\u5728\u5185\u90e8\u4f7f\u7528\u534f\u7a0b\u51fd\u6570.
"},{"location":"extra_luacs/begin/#_8","title":"\u5176\u4ed6\u51fd\u6570","text":"\u9664\u4e86\u4e0a\u8ff0\u63d0\u5230\u7684 say
, getFlag
, setFlag
\u7b49\u5916, \u8fd8\u6709\u975e\u5e38\u591a\u9884\u5148\u5b9a\u4e49\u597d\u7684\u51fd\u6570, \u4f60\u53ef\u4ee5\u5728\u4e0b\u9762\u8fd9\u4e2a\u94fe\u63a5\u4e2d\u627e\u5230: Lua Cutscenes Documentaion - https://maddie480.ovh/...
\u5728\u4e0a\u9762\u8fd9\u4e2a\u6587\u6863\u4e2d\u6bd4\u5982\u8fd9\u4e2a\u51fd\u6570:
Function Description helpers.die([direction={0, 0}[, evenIfInvincible=false[, registerDeathInStats=true]]]) Kills the player. \u5176\u4e2d helpers.die
\u8bf4\u660e\u8fd9\u4e2a\u51fd\u6570\u540d\u662f die, \u540e\u9762\u5706\u62ec\u53f7\u56f4\u8d77\u6765\u7684\u8868\u793a\u5b83\u7684\u53c2\u6570, \u4e00\u5c42\u5c42\u4e2d\u62ec\u53f7\u56f4\u8d77\u6765\u7684\u8868\u793a\u53ef\u9009\u53c2\u6570, \u53c2\u6570\u540d\u540e\u9762\u52a0\u7b49\u4e8e\u53f7\u8868\u793a\u8be5\u53ef\u9009\u53c2\u6570\u7684\u9ed8\u8ba4\u503c, \u6bd4\u5982\u4e0a\u8ff0\u51fd\u6570\u7684\u8c03\u7528\u53ef\u4ee5\u6709:
\u8c03\u7528\u65b9\u5f0f \u7b49\u6548\u8c03\u7528\u65b9\u5f0f die() die(vector2(0, 0), false, true) die(vector2(1, 1)) die(vector2(1, 1), false, true) die(vector2(1, 1), true) die(vector2(1, 1), true, true) die(vector2(1, 1), true, false) die(vector2(1, 1), true, false) \u987a\u4fbf, \u5176\u4e2d\u7b2c\u4e00\u4e2a\u53c2\u6570\u7684\u7c7b\u578b\u662f\u4e2a Vector2
, \u8868\u793a\u4e00\u4e2a\u4e8c\u7ef4\u5411\u91cf, \u8fd9\u79cd\u7c7b\u578b\u7684\u503c\u4f60\u53ef\u4ee5\u8c03\u7528 vector2(1, 1)
\u51fd\u6570\u6765\u4ece\u8fd4\u56de\u503c\u5f97\u5230, \u987e\u540d\u601d\u4e49\u5b83\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f x \u5750\u6807, y \u5750\u6807. \u8fd9\u91cc\u5b83\u7684\u542b\u4e49\u662f\u73a9\u5bb6\u6b7b\u4ea1\u65f6\u7684\u7279\u6548\u65b9\u5411.
"},{"location":"extra_luacs/begin/#_9","title":"\u6700\u540e","text":"\u76f8\u4fe1\u5230\u8fd9\u91cc\u4f60\u5df2\u7ecf\u4f53\u4f1a\u5230\u4e86 luacutscene, \u6216\u8005\u8bf4\u6e38\u620f\u4e2d\u5185\u5d4c lua \u4ee3\u7801\u7684\u5f3a\u5927. \u5728\u4e4b\u540e\u7684\u6587\u7ae0\u4e2d\u5c31\u4e0d\u518d\u4f1a\u63d0\u53ca\u4e0e lua \u76f8\u5173\u7684\u95ee\u9898\u4e86, \u6240\u4ee5\u5728\u4e4b\u540e\u67e5\u627e\u5916\u90e8\u7684 lua \u6559\u7a0b\u662f\u5fc5\u8981\u7684, \u6bd4\u5982 w3cschool \u7684 lua \u6559\u7a0b.
"},{"location":"extra_luacs/cs_access/","title":"C# \u4ea4\u4e92","text":"\u4ece\u8fd9\u4e00\u5c0f\u8282\u5f00\u59cb\u5c31\u9700\u8981\u4f7f\u7528\u4e00\u5c0f\u4e9b C# \u77e5\u8bc6\u4e86, \u4e0d\u8fc7\u4e0d\u9700\u8981\u592a\u591a, \u4f60\u53ea\u9700\u8981\u80fd\u770b\u61c2 C# \u4fa7\u7684\u51fd\u6570, \u5b57\u6bb5, \u5c5e\u6027\u7b49\u7684\u5b9a\u4e49\u5c31\u884c.
"},{"location":"extra_luacs/cs_access/#c_1","title":"\u5f15\u5165 C# \u7c7b","text":"\u8981\u5f15\u7528\u4e00\u4e2a C# \u7c7b, \u9996\u5148\u9700\u8981\u5728\u6587\u4ef6\u9876\u90e8\u4f7f\u7528 require \u51fd\u6570:
local celeste = require(\"#Celeste.Celeste\")\n\nfunction onBegin()\n -- ...\nend\n
\u53c2\u6570\u9700\u8981\u4ee5 \"#<\u5b8c\u6574\u7c7b\u540d>\" \u683c\u5f0f\u4f20\u5165, \u6bd4\u5982\u4e0a\u8ff0\u4ee3\u7801\u5c31\u4f1a\u5f97\u5230\u4e00\u4e2a C# \u7c7b Celeste
, \u8fd9\u6837\u6211\u4eec\u53ef\u4ee5\u6765\u8c03\u7528\u4e00\u4e0b\u4ea7\u751f\u51bb\u7ed3\u5e27\u7684\u9759\u6001\u65b9\u6cd5:
local celeste = require(\"#Celeste.Celeste\")\n\nfunction onBegin()\n celeste.Freeze(0.5)\nend\n
\u5c31\u50cf\u4f60\u5728 C# \u4e2d\u6240\u505a\u7684\u4e00\u6837, \u4e0d\u8fc7\u8fd9\u91cc\u4f7f\u7528\u4e0a\u9762\u83b7\u53d6\u5230\u7684 celeste
\u4f5c\u4e3a\u4f60\u5728 C# \u4e2d\u4e66\u5199\u7684\u7c7b\u540d. \u4e0a\u8ff0\u4ee3\u7801\u5e94\u8be5\u4f1a\u5bfc\u81f4\u4f60\u8fdb\u5165 trigger \u65f6\u51bb\u7ed3 0.5 \u79d2.
"},{"location":"extra_luacs/cs_access/#_1","title":"\u65b9\u6cd5\u8c03\u7528, \u5b57\u6bb5, \u5c5e\u6027\u8bbf\u95ee","text":"\u901a\u5e38, \u5982\u679c\u4f60\u9700\u8981\u8bbf\u95ee C# \u4ee3\u7801\u5bf9\u73a9\u5bb6\u505a\u4e00\u4e9b\u6709\u8da3\u7684\u53d8\u52a8, \u83b7\u53d6\u73a9\u5bb6\u7c7b\u7684\u5b9e\u4f8b\u4ee5\u53ca\u5728\u5b9e\u4f8b\u4e0a\u8c03\u7528\u65b9\u6cd5\u662f\u5fc5\u4e0d\u53ef\u5c11\u7684.
\u5728 LuaCutscene \u4e2d\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u9884\u5b9a\u4e49\u548c\u8d4b\u503c\u7684 player
\u5168\u5c40\u53d8\u91cf, \u4e5f\u5c31\u662f\u5728\u4efb\u4f55\u65b9\u6cd5\u5185\u90fd\u80fd\u4f7f\u7528\u7684\u53d8\u91cf, \u4f8b\u5982, \u5728\u8fdb\u5165 trigger \u65f6\u5c06\u73a9\u5bb6\u7684\u51b2\u523a\u8bbe\u4e3a 2:
function onBegin()\n player.Dashes = 2\nend\n
\u4e0a\u8ff0\u4ee3\u7801\u8bbf\u95ee\u4e86 player \u5168\u5c40\u53d8\u91cf, \u5e76\u4e14\u8bbe\u7f6e\u5176 Dashes
\u5b57\u6bb5\u4e3a 2, \u4e5f\u5c31\u662f\u8bbe\u7f6e\u51b2\u523a\u6570\u4e3a2, \u4e0d\u8fc7\u8fd9\u6837\u4f1a\u5bfc\u81f4\u5728\u7a7a\u4e2d\u4e5f\u6062\u590d\u4e3a 2, \u6240\u4ee5\u6211\u4eec\u52a0\u5165\u5728\u662f\u5426\u5728\u5b89\u5168\u5730\u9762(\u8349\u8393\u80fd\u7ed3\u7b97\u7684\u90a3\u79cd)\u4e0a\u7684\u68c0\u6d4b:
function onBegin()\n if player.OnSafeGround then\n player.Dashes = 2\n end\nend\n
\u4e0a\u8ff0\u4ee3\u7801\u4e2d OnSafeGround
\u5c31\u662f\u4e00\u4e2a\u5c5e\u6027. \u4e0d\u8fc7\u4e0a\u9762\u8fd9\u6bb5\u4ee3\u7801\u6709\u4e00\u4e9b\u95ee\u9898, \u5f53\u4f60\u4ece\u4e0a\u5f80\u4e0b\u6389\u5165 trigger \u65f6, \u53ea\u6709\u8fdb\u5165\u7684\u90a3\u4e00\u5e27\u624d\u4f1a\u68c0\u6d4b\u5e76\u6062\u590d\u51b2\u523a, \u8fd9\u6709\u65f6\u5019\u5c31\u4e0d\u662f\u6211\u4eec\u60f3\u8981\u7684\u7ed3\u679c, \u6240\u4ee5\u6211\u4eec\u4f7f\u7528\u4e00\u4e2a\u65b0\u7684\u7279\u6b8a\u51fd\u6570 onStay
:
function onStay()\n if player.OnSafeGround then\n player.Dashes = 2\n end\nend\n
\u8fd9\u4f1a\u8ba9\u8fd9\u6bb5\u4ee3\u7801\u5728\u73a9\u5bb6\u63a5\u89e6\u5230 trigger \u7684\u6bcf\u4e00\u5e27\u90fd\u6267\u884c\u4ee3\u7801, \u7b26\u5408\u6211\u4eec\u76ee\u524d\u7684\u9700\u6c42. \u9664\u6b64\u4e4b\u5916\u8fd8\u6709\u53e6\u5916\u4e24\u4e2a: onEnter
\u548c onLeave
, \u5b83\u4eec\u90fd\u4e0d\u662f\u534f\u7a0b\u51fd\u6570, \u524d\u8005\u5728\u73a9\u5bb6\u8fdb\u5165 trigger \u65f6\u89e6\u53d1(\u8fd9\u4e0e onBegin
\u4e0d\u540c, \u6bd4\u5982\u5728\u5267\u60c5\u8fdb\u884c\u65f6\u4f60\u4f9d\u7136\u53ef\u4ee5\u63a7\u5236\u8fdb\u51fa trigger), \u540e\u8005\u5728\u73a9\u5bb6\u79bb\u5f00 trigger \u65f6\u6267\u884c.
\u5f53\u7136\u6211\u4eec\u8fd8\u53ef\u4ee5\u8c03\u7528\u4e00\u4e9b\u65b9\u6cd5, \u6bd4\u5982\u5267\u60c5\u5f00\u59cb\u65f6\u5f3a\u5236\u4e22\u5f03\u6293\u53d6\u7269:
function onBegin()\n player:Throw()\nend\n
\u6ce8\u610f\u5728\u8c03\u7528\u6210\u5458\u65b9\u6cd5\u65f6\u6211\u4eec\u9700\u8981\u4f7f\u7528 : \u7b26\u53f7, \u8fd9\u662f\u5230\u76ee\u524d\u4e3a\u6b62\u7684\u4e00\u4e2a\u7279\u4f8b.
"},{"location":"extra_luacs/cs_access/#_2","title":"\u79c1\u6709\u8bbf\u95ee","text":"\u5bf9\u4e8e\u79c1\u6709\u6210\u5458\u7684\u8bbf\u95ee, \u5728 Everest Core (\u622a\u6b62 4446) \u4e0a\u4f3c\u4e4e\u662f\u6709\u4e00\u4e9b\u95ee\u9898\u5bfc\u81f4\u5b8c\u5168\u4e0d\u80fd\u8bbf\u95ee, \u7ecf\u8fc7\u8be2\u95ee\u4f3c\u4e4e\u662f Core \u7684\u4e00\u4e9b\u7f13\u5b58\u95ee\u9898, \u5728 Stable \u4e0a\u4e0d\u4f1a\u51fa\u73b0, \u6545\u8fd9\u91cc\u6682\u65f6\u8df3\u8fc7, \u76f8\u5173\u79c1\u6709\u6210\u5458\u8bbf\u95ee\u53ef\u5728 C# \u4fa7\u64cd\u4f5c\u4f5c\u4e3a\u66ff\u4ee3.
"},{"location":"extra_luacs/cs_access/#_3","title":"\u534f\u7a0b","text":"lua \u4e0e c# \u4e24\u4fa7\u90fd\u6709\u534f\u7a0b\u7684\u6982\u5ff5, \u4e0d\u8fc7\u4e0d\u80fd\u76f4\u63a5\u4f7f\u7528, \u9700\u8981\u4e00\u5b9a\u7684\u8f6c\u6362, \u4f8b\u5982\u4f7f\u7528 Level.ZoomTo
\u51fd\u6570, \u5b83\u4f1a\u8fd4\u56de\u4e00\u4e2a\u5c06\u6444\u50cf\u673a\u7f29\u653e\u81f3\u67d0\u4e00\u70b9\u7684\u534f\u7a0b:
function onBegin()\n disableMovement()\n local level = player.Scene\n local c = level:ZoomTo(vector2(160, 90), 1.5, 2.0)\n coroutine.yield(c)\nend\n
\u4e0a\u8ff0\u4ee3\u7801\u8c03\u7528\u4e86 level
\u7684 ZoomTo
\u51fd\u6570, \u5e76\u5c06\u8fd4\u56de\u503c\u50a8\u5b58\u8d77\u6765, \u7136\u540e\u4f7f\u7528 coroutine.yield
\u5c06\u5176\u8f6c\u6362\u4e3a lua \u534f\u7a0b\u5e76\u7b49\u5f85. \u6e38\u620f\u4e2d\u7684\u6548\u679c\u5219\u4e3a\u76f8\u673a\u5728 2s \u5185\u5411\u5c4f\u5e55\u4e2d\u5fc3\u653e\u5927 1.5 \u500d. \u987a\u4fbf\u8fd9\u4e2a\u51fd\u6570\u8fd8\u6709\u4e2a\u914d\u5957\u7684\u7f29\u653e\u56de\u6765\u7684\u7248\u672c:
function onBegin()\n disableMovement()\n local level = player.Scene;\n coroutine.yield(level:ZoomTo(vector2(160, 90), 1.5, 2.0))\n coroutine.yield(level:ZoomBack(2.0))\nend\n
"},{"location":"extra_luacs/cs_access/#_4","title":"\u6700\u540e","text":"\u76f8\u4fe1\u5982\u679c\u4f60\u6ca1\u6709\u592a\u591a C# \u77e5\u8bc6\u7684\u8bdd, \u8fd9\u4e00\u5c0f\u8282\u4f60\u80af\u5b9a\u662f\u5f88\u56f0\u60d1\u4e0d\u77e5\u9053\u53d1\u751f\u4e86\u4ec0\u4e48\u7684, \u4e0d\u8fc7\u6ca1\u5173\u7cfb, \u4f60\u4f9d\u7136\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528\u540e\u7eed\u7ed9\u51fa\u7684\u4ee3\u7801\u6bb5\u548c\u73b0\u6210\u7684\u51fd\u6570\u6765\u505a\u4f60\u60f3\u505a\u7684\u4e8b.
"},{"location":"extra_luacs/examples/","title":"\u4f8b\u5b50","text":"\u5728\u8fd9\u4e00\u5c0f\u8282\u4e2d\u4f1a\u66f4\u591a\u5730\u4ecb\u7ecd\u4e00\u4e9b\u9884\u5b9a\u4e49\u51fd\u6570, \u4ee5\u53ca\u4e00\u4e9b\u5de5\u5177\u51fd\u6570\u7b49\u7b49, \u5728\u540e\u9762\u7684\u8282\u4e2d\u8fd8\u4f1a\u5305\u542b\u4e00\u4e9b helper \u5728 C# \u4fa7\u534f\u52a9\u5b9e\u73b0\u7684\u51fd\u6570.
"},{"location":"extra_luacs/examples/#_2","title":"\u4e00\u4e9b\u4ecb\u7ecd","text":"\u5c31\u5982\u4e4b\u524d\u6240\u8bf4\u7684, \u79fb\u52a8\u7684\u7981\u6b62\u72b6\u6001\u5e76\u4e0d\u4f1a\u5728\u5267\u60c5\u7ed3\u675f\u65f6\u81ea\u52a8\u89e3\u9664, \u5728\u5206\u652f\u590d\u6742\u5bb9\u6613\u5728\u672b\u5c3e\u5fd8\u8bb0\u8c03\u7528 enableMovement
\u7684\u60c5\u51b5\u4e0b, \u901a\u5e38\u5efa\u8bae\u5728 onEnd
\u51fd\u6570\u4e2d\u91cd\u65b0\u5141\u8bb8\u79fb\u52a8:
function onEnd()\n enableMovement()\nend\n
\u5bf9\u4e8e\u90e8\u5206\u8981\u6c42\u7edd\u5bf9\u5750\u6807\u7684\u51fd\u6570, \u4f60\u53ef\u4ee5\u901a\u8fc7\u6309\u4e0b\u952e\u76d8\u4e0a\u7684 ~
\u952e\u6765\u6253\u5f00\u8c03\u8bd5\u9762\u677f, \u5728\u754c\u9762\u5de6\u4e0a\u89d2\u4f1a\u6709\u4e00\u680f\u7c7b\u4f3c\u5982\u4e0b\u7684\u4fe1\u606f:
Area: 04 @ 12 (SID: Celeste/Saplonily/Test)\nCursor @\n screen: 792, 407\n world: -618, 213\n level: 1142, 397\n level, /8: 142, 49\n level, snap: 1136, 392\n
\u5176\u4e2d Area: 04 @ 12
\u4e2d\u7684 04
\u4e3a\u5f53\u524d\u623f\u95f4\u540d, 12
\u4e3a\u5f53\u524d\u7ae0\u8282 ID, \u901a\u5e38\u5bf9\u4e8e B \u9762\u5b83\u8fd8\u4f1a\u4ee5 H
\u7ed3\u5c3e, C \u9762\u4ee5 HH
\u7ed3\u5c3e. screen
\u8868\u793a\u76ee\u524d\u5149\u6807\u6240\u5728\u7684\u5c4f\u5e55\u5750\u6807, (0, 0)
\u8868\u793a\u5c4f\u5e55\u5de6\u4e0a\u89d2. level
\u8868\u793a\u76ee\u524d\u5149\u6807\u6240\u5728\u7684\u4e16\u754c\u5750\u6807, \u4e5f\u5c31\u662f walkTo
\u7b49\u51fd\u6570\u8981\u6c42\u6211\u4eec\u4f20\u5165\u7684\u7edd\u5bf9\u5750\u6807. level, /8
\u8868\u793a\u5149\u6807\u6240\u5728\u7684\u4e16\u754c\u5750\u6807\u9664\u4ee5 8 \u53d6\u6574\u7684\u7ed3\u679c, \u8fd9\u901a\u5e38\u7528\u4e8e\u5b9a\u4f4d\u4ee5 8px \u4e3a\u5355\u4f4d\u7684 tile. level, snap
\u7684\u503c\u4e3a level, /8
\u7684\u503c\u4e58\u4ee5 8, \u5728\u6570\u503c\u4e0a\u8868\u73b0\u4e3a\u5149\u6807\u6240\u5728\u4e16\u754c\u5750\u6807\u4e0e 8x8 \u7f51\u683c\u8fdb\u884c\u5bf9\u9f50\u7684\u7ed3\u679c.
\u5728\u88c5\u4e86 CelesteTAS
mod \u7684\u60c5\u51b5\u4e0b, \u4f60\u8fd8\u53ef\u4ee5\u5de6\u51fb\u5730\u56fe\u4e0a\u7684\u5b9e\u4f53\u6765\u83b7\u53d6\u66f4\u591a\u4fe1\u606f:
Area: 04 @ 12 (SID: Celeste/Saplonily/Test)\nCursor @\n screen: 792, 407\n entity type: Celeste.Glider\n entity name: glider\n entity id : 04:14\n mod name : Celeste\n world: -618, 213\n level: 1142, 397\n level, /8: 142, 49\n level, snap: 1136, 392\n
\u5176\u4e2d entity type
\u4e3a\u5de6\u51fb\u5230\u7684\u5b9e\u4f53\u7684\u5b9e\u4f53\u7c7b\u540d, \u4e5f\u5373\u4ee3\u7801\u7c7b\u540d. entity name
\u4e3a\u5b9e\u4f53\u7684\u540d\u79f0, \u4e5f\u662f\u5728\u5730\u56fe\u6587\u4ef6\u4e2d\u5b9e\u9645\u4fdd\u5b58\u7684\u540d\u5b57, \u901a\u5e38\u5728\u4e0e\u4ee3\u7801\u7c7b\u540d\u76f8\u4f3c\u7684\u4f7f\u7528\u573a\u666f\u4e2d\u4f1a\u7528\u5230. entity id
\u4e3a\u5b9e\u4f53\u7684 ID, \u901a\u5e38\u7528\u4e8e\u67d0\u4e9b\u9700\u8981\u4f20\u5165\u5b9e\u4f53 ID \u53c2\u6570\u7684 helper \u5b9e\u4f53. mod name
\u4e3a\u8be5\u5b9e\u4f53\u6240\u5c5e mod \u540d, \u5bf9\u4e8e\u539f\u7248\u5b9e\u4f53\u4e3a Celeste
.
\u4ee5\u9632\u4f60\u8fd8\u4e0d\u77e5\u9053, \u6e38\u620f\u7684\u5750\u6807\u7cfb\u4e0e\u5e38\u89c4\u7684\u6570\u5b66\u5750\u6807\u7cfb\u4e0d\u540c, \u5176 y \u5750\u6807\u7ecf\u8fc7\u4e86\u7ad6\u76f4\u7ffb\u8f6c:
"},{"location":"extra_luacs/examples/#_3","title":"\u7247\u6bb5","text":""},{"location":"extra_luacs/examples/#_4","title":"\u64ad\u653e\u73a9\u5bb6\u52a8\u753b","text":"function playSprite(sprite, duration)\n player.Sprite:Play(sprite, false, false)\n if duration then\n wait(duration)\n end\nend\n
\u4e0a\u8ff0\u4ee3\u7801\u5c01\u88c5\u4e86\u4e00\u4e2a\u51fd\u6570, \u4f7f\u5f97\u4f60\u53ef\u4ee5\u5411\u73a9\u5bb6\u64ad\u653e\u4e00\u4e2a\u52a8\u753b\u5e76\u7b49\u5f85\u51e0\u79d2, \u4f8b\u5982\u8ba9\u73a9\u5bb6\u64ad\u653e swimIdle
, \u4e5f\u5c31\u662f\u5728\u6c34\u4e2d\u65f6\u64ad\u653e\u7684\u52a8\u753b:
player.DummyAutoAnimate = false\nplaySprite(\"swimIdle\", 1)\nplayer.DummyAutoAnimate = true\n
\u5728\u73a9\u5bb6\u88ab\u7981\u6b62\u79fb\u52a8\u540e\u6e38\u620f\u4f9d\u7136\u4f1a\u5904\u7406\u73a9\u5bb6\u7684\u52a8\u753b, \u6240\u4ee5\u6211\u4eec\u7684 swimIdle
\u52a8\u753b\u4f1a\u7acb\u523b\u88ab\u66ff\u6362\u4e3a\u9ed8\u8ba4\u52a8\u753b, \u8fd9\u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e DummyAutoAnimate
\u4e3a false
\u6765\u7981\u6b62\u8fd9\u4e00\u884c\u4e3a.
\u6b64\u5916\u8fd8\u53ef\u4ee5\u6709\u53cd\u5411\u64ad\u653e\u52a8\u753b:
function playSpriteReversed(sprite, duration, from)\n player.Sprite:Reverse(sprite, false)\n -- from \u8fd8\u8981\u518d +1, \u907f\u514d\u6e38\u620f\u8df3\u8fc7\u6700\u540e\u4e00\u5e27\u800c\u4ece\u5012\u6570\u7b2c\u4e8c\u5e27\u5f00\u59cb\n player.Sprite:SetAnimationFrame(from + 1)\n if duration then\n wait(duration)\n end\nend\n
\u851a\u84dd\u7684\u5f15\u64ce Monocle
\u7684 Sprite
\u6709\u4e2a\u53cd\u5411\u64ad\u653e\u7684\u65b9\u6cd5, \u4f46\u662f\u5b83\u53ea\u4f1a\u4fee\u6539\u65b9\u5411\u4e3a\u53cd\u65b9\u5411, \u4e0d\u4f1a\u8df3\u5230\u6700\u540e\u4e00\u5e27\u5f00\u59cb, \u6240\u4ee5\u8fd9\u91cc\u4f60\u53ef\u80fd\u9700\u8981\u624b\u52a8\u67e5\u8be2\u4f60\u60f3\u8981\u53cd\u5411\u64ad\u653e\u7684\u52a8\u753b\u7684\u6700\u540e\u4e00\u5e27\u7684\u4f4d\u7f6e.
\u4f8b\u5982\u8ba9\u73a9\u5bb6\u62ac\u5934, \u7ed3\u675f\u540e\u7b49\u5f85 0.5 \u79d2\u7136\u540e\u518d\u4f4e\u5934\u7136\u540e\u7ed3\u675f\u5267\u60c5:
function onBegin()\n disableMovement()\n local level = player.Scene;\n player.DummyAutoAnimate = false\n playSprite(\"lookUp\", 0.5)\n wait(0.5)\n -- <Anim id=\"lookUp\" path=\"lookUp\" delay=\"0.1\" frames=\"2-7\"/>, \u6700\u540e\u4e00\u5e27\u662f 7\n playSpriteReversed(\"lookUp\", 0.5, 7)\n player.DummyAutoAnimate = true\nend\n
\u6b64\u5916\u4f60\u8fd8\u4f1a\u53d1\u73b0\u6b64\u65f6\u4f9d\u7136\u6709\u91cd\u529b, \u4f46\u662f\u4f60\u4f9d\u7136\u60f3\u8ba9\u73a9\u5bb6\u5728\u7a7a\u4e2d\u6e38\u52a8(\u9646\u6e38), \u4f60\u53ef\u4ee5\u8fd9\u6837\u7981\u7528\u91cd\u529b:
function onBegin()\n disableMovement()\n local level = player.Scene;\n player.DummyAutoAnimate = false\n player.DummyGravity = false\n playSprite(\"swimIdle\", 0.5)\n player.DummyGravity = true\n player.DummyAutoAnimate = true\nend\n
\u4e0a\u8ff0\u4f8b\u5b50\u7684\u5b8c\u6574 lua \u6587\u4ef6:
testCutscene.luafunction playSprite(sprite, duration)\n player.Sprite:Play(sprite, false, false)\n if duration then\n wait(duration)\n end\nend\n\nfunction playSpriteReversed(sprite, duration, from)\n player.Sprite:Reverse(sprite, false)\n player.Sprite:SetAnimationFrame(from + 1)\n if duration then\n wait(duration)\n end\nend\n\nfunction onBegin()\n disableMovement()\n local level = player.Scene;\n waitUntilOnGround()\n wait(1)\n player.DummyAutoAnimate = false\n player.DummyGravity = false\n playSprite(\"swimIdle\", 0.5)\n player.DummyGravity = true\n player.DummyAutoAnimate = true\nend\n\nfunction onEnd()\n enableMovement()\nend\n
"},{"location":"extra_luacs/reference/","title":"\u53c2\u8003","text":""},{"location":"extra_luacs/reference/#luacutscene","title":"LuaCutscene \u51fd\u6570","text":"\u5728\u524d\u9762\u7684\u5c0f\u8282\u4e2d\u6211\u4eec\u5df2\u7ecf\u63d0\u5230\u8fc7 LuaCutscene \u63d0\u4f9b\u4e86\u5927\u91cf\u7684\u51fd\u6570, \u90a3\u4e48\u8fd9\u91cc\u6211\u4eec\u5c06\u4ecb\u7ecd\u5176\u4e2d\u5e38\u7528\u7684\u4e00\u90e8\u5206(\u4e4b\u524d\u5df2\u4ecb\u7ecd\u8fc7\u7684\u5c06\u4e0d\u518d\u63d0\u53ca).
"},{"location":"extra_luacs/reference/#wait","title":"wait","text":"wait(duration)
\u534f\u7a0b\u51fd\u6570, \u6682\u505c\u51fd\u6570\u6267\u884c\u51e0\u79d2
duration: \u8981\u6682\u505c\u7684\u65f6\u95f4(\u79d2) "},{"location":"extra_luacs/reference/#walkto","title":"walkTo","text":"walkTo(x, walkBackwards=false, speedMultiplier=1.0, keepWalkingIntoWalls=false)
\u534f\u7a0b\u51fd\u6570, \u8ba9\u73a9\u5bb6\u884c\u8d70\u5230\u5750\u6807 x
x: \u76ee\u6807 x \u7edd\u5bf9\u5750\u6807, \u5355\u4f4d px walkBackwards: \u662f\u5426\u64ad\u653e\u4e3a\u5012\u8d70\u52a8\u753b speedMultiplier: \u901f\u5ea6\u500d\u7387 keepWalkingIntoWalls: \u649e\u5899\u65f6\u662f\u5426\u4fdd\u6301\u72b6\u6001\u76f4\u5230\u5899\u88ab\u79fb\u9664 \u5982\u679c\u5728\u884c\u8d70\u8fc7\u7a0b\u4e2d\u78b0\u5230\u5899\u90a3\u4e48\u8be5\u51fd\u6570\u4f1a\u7acb\u5373\u7ed3\u675f\u6267\u884c, \u9664\u975e keepWalkingIntoWalls
\u88ab\u8bbe\u7f6e\u4e3a true
, \u5982\u679c\u4e0d\u5e78\u5730\u78b0\u5230\u4e86\u4e0d\u53ef\u80fd\u4f1a\u88ab\u79fb\u9664\u7684\u5899, \u4f8b\u5982\u524d\u666f\u7816, \u90a3\u4e48\u5267\u60c5\u5c31\u4f1a\u6c38\u4e45\u5361\u4f4f.
"},{"location":"extra_luacs/reference/#walk","title":"walk","text":"walkTo(x, walkBackwards=false, speedMultiplier=1.0, keepWalkingIntoWalls=false)
\u4e0e walkTo
\u76f8\u540c, \u4f46 x \u4e3a\u76f8\u5bf9\u503c, \u4f8b\u5982 100
\u4f1a\u4f7f\u5f97\u73a9\u5bb6\u5411\u53f3\u884c\u8d70 100 px
"},{"location":"extra_luacs/reference/#runto","title":"runTo","text":"runTo(x, fastAnimation=false)
\u534f\u7a0b\u51fd\u6570, \u8ba9\u73a9\u5bb6\u8dd1\u5230\u5750\u6807 x
x: \u76ee\u6807 x \u7edd\u5bf9\u5750\u6807, \u5355\u4f4d px fastAnimation: \u662f\u5426\u4f7f\u7528\u5feb\u8dd1\u7684\u52a8\u753b \u4e0e walkTo
\u7c7b\u4f3c, \u4f46\u662f\u52a8\u753b\u53d8\u4e3a\u8dd1\u6b65. \u6ce8\u610f\u6b64\u51fd\u6570\u6ca1\u6709\u540c\u7b49\u7684 keepWalkingIntoWalls
\u53c2\u6570, \u5176\u7b49\u6548\u4e8e\u4e3a true
\u7684\u60c5\u51b5, \u4e5f\u5c31\u662f\u649e\u5899\u540e\u4e0d\u4f1a\u7ed3\u675f\u8be5\u51fd\u6570\u7684\u6267\u884c.
"},{"location":"extra_luacs/reference/#run","title":"run","text":"run(x, fastAnimation=false)
\u4e0e runTo
\u76f8\u540c, \u4f46 x \u4e3a\u76f8\u5bf9\u503c.
"},{"location":"extra_luacs/reference/#postcard","title":"postcard","text":"postcard(dialog, sfxIn, sfxOut=nil)
\u534f\u7a0b\u51fd\u6570, \u5411\u73a9\u5bb6\u663e\u793a\u660e\u4fe1\u7247
dialog: \u660e\u4fe1\u7247\u6240\u4f7f\u7528\u7684 dialog id, \u4e0e say
\u7684\u662f\u540c\u4e00\u79cd id sfxIn: \u5c55\u793a\u660e\u4fe1\u7247\u65f6\u64ad\u653e\u7684\u97f3\u9891 event id. sfxOut: \u660e\u4fe1\u7247\u79fb\u5f00\u65f6\u64ad\u653e\u7684\u97f3\u9891 event id. \u5bf9\u4e8e\u97f3\u9891\u76f8\u5173\u7684\u5185\u5bb9, \u4f8b\u5982\u83b7\u53d6 event id, \u53ef\u53c2\u8003\u7535\u7bb1\u5236\u56fe\u6559\u7a0b\u4e2d\u7684:
av986769059 - \u81ea\u5b9a\u4e49\u97f3\u4e50(\u57fa\u7840\u7bc7) av604397615 - \u81ea\u5b9a\u4e49\u97f3\u4e50(\u8fdb\u9636\u7bc7) av517096099 - \u81ea\u5b9a\u4e49\u97f3\u4e50(\u62d3\u5c55\u7bc7) \u5728\u660e\u4fe1\u7247\u51fa\u73b0\u65f6\u5c1d\u8bd5\u6682\u505c\u5e76\u8df3\u8fc7\u5267\u60c5\u4f1a\u4f7f\u5173\u5361\u5904\u4e8e\u4e00\u79cd\u5f88\u5947\u602a\u7684\u72b6\u6001, \u4f60\u53ef\u4ee5\u9009\u62e9\u7981\u7528\u5173\u5361\u7684\u6682\u505c\u6765\u907f\u514d\u5b83.
\u622a\u6b62 0.2.11
, postcard
\u51fd\u6570\u5b58\u5728\u7f16\u7801\u95ee\u9898, \u4e2a\u4eba\u5df2\u5f00 pr \u4fee\u590d
"},{"location":"extra_luacs/reference/#choice","title":"choice","text":"choice(...)
\u534f\u7a0b\u51fd\u6570, \u5411\u73a9\u5bb6\u5c55\u793a\u51e0\u4e2a\u5bf9\u8bdd\u9009\u9879(\u7c7b\u4f3c 6a \u5f00\u5934\u90a3\u79cd), \u8fd4\u56de\u73a9\u5bb6\u9009\u62e9\u7684\u5bf9\u8bdd\u5e8f\u53f7(\u6ce8\u610f\u4ece 1 \u5f00\u59cb).
\u8fd9\u662f\u4e00\u4e2a\u53ef\u53d8\u53c2\u6570\u7684\u51fd\u6570, \u4f8b\u5982\u4ee5\u4e0b\u4f7f\u7528:
local chosen = choice(\"CHOICE_1\", \"CHOICE_2\", \"CHOICE_3\");\nsay(\"CHOICE_SAY_\" .. tostring(chosen));\n
\u4f1a\u5411\u73a9\u5bb6\u5c55\u793a\u4e09\u4e2a\u9009\u9879, \u5e76\u4e14\u5728\u73a9\u5bb6\u9009\u62e9\u5b8c\u540e\u5c55\u793a\u5bf9\u5e94\u5e8f\u53f7\u5bf9\u5e94\u7684\u5bf9\u8bdd:
CHOICE_1
-> CHOICE_SAY_1
CHOICE_2
-> CHOICE_SAY_2
CHOICE_3
-> CHOICE_SAY_3
"},{"location":"extra_luacs/reference/#die","title":"die","text":"die(direction={0, 0}, evenIfInvincible=false, registerDeathInStats=true)
\u975e\u534f\u7a0b\u51fd\u6570, \u6740\u6b7b\u73a9\u5bb6
direction: \u6b7b\u4ea1\u65b9\u5411, \u4f8b\u5982 {1, 0}
\u8868\u793a\u6c34\u5e73\u5411\u53f3, {-1, -1}
\u8868\u793a\u5de6\u4e0a\u65b9 evenIfInvincible: \u662f\u5426\u5728\u73a9\u5bb6\u662f\u65e0\u654c\u65f6\u4e5f\u6740\u6b7b registerDeathInStats: \u662f\u5426\u8bb0\u5f55\u672c\u6b21\u6b7b\u4ea1, \u5426\u5219\u672c\u6b21\u6b7b\u4ea1\u4e0d\u4f1a\u589e\u52a0\u5b58\u6863\u6b7b\u4ea1\u6570 \u5c31\u5982\u6b64\u51fd\u6570\u6240\u505a\u7684, \u76f4\u63a5\u6740\u6b7b\u73a9\u5bb6, \u4e0d\u8fc7\u6b64\u51fd\u6570\u8c03\u7528\u540e\u4f9d\u7136\u4f1a\u6267\u884c\u540e\u9762\u7684\u4ee3\u7801, \u867d\u7136\u540c\u65f6\u540e\u9762\u7684\u4ee3\u7801\u4f1a\u88ab\u73a9\u5bb6\u6b7b\u4ea1\u540e\u7684\u81ea\u52a8\u91cd\u5f00\u76f4\u63a5\u6253\u65ad.
"},{"location":"extra_luacs/reference/#jump","title":"jump","text":"jump(duration=2.0)
\u975e\u534f\u7a0b\u51fd\u6570, \u4f7f\u73a9\u5bb6\u8df3\u8dc3
duration: \u8df3\u8dc3\u65f6\u957f, \u7b49\u4ef7\u4e8e\u4f60\u6309\u8df3\u952e\u7684\u65f6\u957f \u6709\u8da3\u7684\u662f, \u6b64\u51fd\u6570\u5373\u4f7f\u73a9\u5bb6\u5728\u7a7a\u4e2d\u4e5f\u4f1a\u8d77\u6548, \u4e0d\u8fc7\u6b64\u51fd\u6570\u5bfc\u81f4\u7684\u8df3\u4e0d\u4f1a\u89e6\u53d1 super \u4e0e hyper \u7b49\u673a\u5236.
"},{"location":"extra_luacs/reference/#waituntilonground","title":"waitUntilOnGround","text":"waitUntilOnGround()
\u534f\u7a0b\u51fd\u6570, \u7b49\u5f85\u73a9\u5bb6\u89e6\u78b0\u5230\u5730\u677f
"},{"location":"extra_luacs/reference/#changeroom","title":"changeRoom","text":"changeRoom(name)
changeRoom(name, spawnX, spawnY)
\u975e\u534f\u7a0b\u51fd\u6570 ,\u66f4\u6539\u73a9\u5bb6\u6240\u5728\u9762
name: \u76ee\u6807\u9762\u540d\u79f0 spawnX: \u65b0\u91cd\u751f\u70b9 x \u5750\u6807 spawnY: \u65b0\u91cd\u751f\u70b9 y \u5750\u6807 \u5982\u679c\u4e0d\u4f20\u5165\u65b0\u91cd\u751f\u70b9\u5750\u6807\u5219\u9ed8\u8ba4\u4e3a\u623f\u95f4\u5de6\u4e0b\u89d2. \u4e0d\u8fc7\u7ecf\u4e2a\u4eba\u6d4b\u8bd5\u8fd9\u4e2a\u91cd\u751f\u70b9\u7684\u8bbe\u7f6e\u4f1a\u9a6c\u4e0a\u5c31\u88ab\u65b0\u9762\u7684\u8fdb\u5165\u800c\u8986\u76d6, \u4e0d\u8fc7\u6709\u8da3\u7684\u662f, \u6b64\u51fd\u6570\u5141\u8bb8\u4f20\u5165\u4e00\u4e2a filler \u9762, \u6b64\u65f6\u91cd\u751f\u70b9\u5c31\u4e0d\u4f1a\u88ab\u8986\u76d6\u4e86.
"},{"location":"extra_luacs/reference/#teleportto","title":"teleportTo","text":"teleportTo(x, y)
\u975e\u534f\u7a0b\u51fd\u6570, \u4f20\u9001\u73a9\u5bb6\u5230\u76ee\u6807\u4f4d\u7f6e
x: \u76ee\u6807 x \u5750\u6807 y: \u76ee\u6807 y \u5750\u6807 \u6b64\u5916\u8fd9\u4e2a\u51fd\u6570\u8fd8\u6709\u53e6\u5916\u4e24\u4e2a\u91cd\u8f7d, \u4e0d\u8fc7\u6211\u4e2a\u4eba\u8fd8\u6ca1\u5f04\u61c2\u5b83\u7684\u7528\u6cd5, \u6545\u8fd9\u91cc\u5c31\u4e0d\u5199\u4e86.
"},{"location":"extra_luacs/reference/#teleport","title":"teleport","text":"\u4e0e teleportTo
\u76f8\u540c, \u4f46\u662f\u5750\u6807\u662f\u76f8\u5bf9\u5750\u6807
"},{"location":"extra_luacs/reference/#instantteleportto","title":"instantTeleportTo","text":"instantTeleportTo(x, y)
\u975e\u534f\u7a0b\u51fd\u6570, \u7acb\u5373\u4f20\u9001\u73a9\u5bb6\u5230\u76ee\u6807\u4f4d\u7f6e
x: \u76ee\u6807 x \u5750\u6807 y: \u76ee\u6807 y \u5750\u6807 \u6b64\u51fd\u6570\u4e0e teleportTo
\u7c7b\u4f3c, \u4f46\u662f\u5b83\u4f1a\u5728\u4f20\u9001\u7684\u540c\u65f6\u7acb\u5373\u8c03\u6574\u89c6\u91ce, \u4e5f\u5c31\u662f\u6444\u50cf\u673a\u7684\u4f4d\u7f6e. \u6b64\u5916\u8fd9\u4e2a\u51fd\u6570\u4e5f\u6709\u53e6\u5916\u4e00\u4e2a\u6709\u5173\u9762\u7684\u91cd\u8f7d((x, y, room)
), \u4f46\u662f\u4f20\u5165\u5176\u4ed6\u9762\u540e\u73a9\u5bb6\u4f1a\u8fdb\u5165\u4e00\u79cd\u5947\u602a\u7684\u5267\u60c5\u72b6\u6001.
"},{"location":"extra_luacs/reference/#instantteleport","title":"instantTeleport","text":"\u4e0e instantTeleportTo
\u76f8\u540c, \u4f46\u662f\u5750\u6807\u662f\u76f8\u5bf9\u5750\u6807
"},{"location":"extra_luacs/reference/#completearea","title":"completeArea","text":"completeArea(spotlightWipe=false, skipScreenWipe=false, skipCompleteScreen=false)
\u975e\u534f\u7a0b\u51fd\u6570, \u7ed3\u675f\u5f53\u524d\u7ae0\u8282, \u6b64\u51fd\u6570\u8c03\u7528\u540e\u4f1a\u91cd\u65b0\u5141\u8bb8\u73a9\u5bb6\u79fb\u52a8.
spotlightWipe
: true
\u65f6\u4e3a\u805a\u5149\u706f\u578b\u5207\u6362\u5230\u9ed1\u5c4f, false
\u4e3a\u6e10\u53d8\u578b. skipScreenWipe
: \u662f\u5426\u8df3\u8fc7\u5207\u6362\u5230\u9ed1\u5c4f\u7684\u8fc7\u7a0b skipCompleteScreen
: \u662f\u5426\u8df3\u8fc7\u7ed3\u7b97\u5c4f "},{"location":"extra_luacs/reference/#givekey","title":"giveKey","text":"giveKey()
\u975e\u534f\u7a0b\u51fd\u6570, \u7ed9\u4e88\u73a9\u5bb6\u4e00\u628a\u94a5\u5319.
"},{"location":"extra_luacs/reference/#makeunskippable","title":"makeUnskippable","text":"makeUnskippable()
\u975e\u534f\u7a0b\u51fd\u6570, \u4f7f\u5f53\u524d\u5267\u60c5\u65e0\u6cd5\u8df3\u8fc7
\u6709\u4e9b\u65f6\u5019\u4f60\u7684\u5267\u60c5\u8fc7\u4e8e\u590d\u6742, \u4ee5\u81f3\u4e8e\u4f60\u65e0\u6cd5\u826f\u597d\u5730\u9884\u6d4b\u76f4\u63a5\u8df3\u8fc7\u5267\u60c5\u5e94\u8be5\u505a\u4ec0\u4e48, \u6bd4\u5982\u73a9\u5bb6\u5230\u5e95\u79fb\u52a8\u5230\u54ea\u4e86, \u90a3\u4e48\u4f7f\u5b83\u65e0\u6cd5\u8df3\u8fc7\u53ef\u80fd\u662f\u4e2a\u4e0d\u9519\u7684\u9009\u62e9.
"},{"location":"extra_luacs/reference/#disableretry-enableretry","title":"disableRetry / enableRetry","text":"enableRetry()
disableRetry()
\u975e\u534f\u7a0b\u51fd\u6570, \u7981\u7528 / \u542f\u7528 \u91cd\u8bd5\u529f\u80fd.
\u6ce8\u610f\u6b64\u51fd\u6570\u7684\u6548\u679c\u5728\u5267\u60c5\u7ed3\u675f\u540e\u4e0d\u4f1a\u6062\u590d, \u5efa\u8bae\u624b\u52a8\u5728 onEnd()
\u5904\u91cd\u65b0\u542f\u7528.
"},{"location":"extra_luacs/reference/#disablepause-enablepause","title":"disablePause / enablePause","text":"helpers.disablePause()
helpers.enablePause()
\u975e\u534f\u7a0b\u51fd\u6570, \u7981\u7528 / \u542f\u7528 \u6682\u505c\u529f\u80fd.
\u6ce8\u610f\u6b64\u51fd\u6570\u7684\u6548\u679c\u5728\u5267\u60c5\u7ed3\u675f\u540e\u4e0d\u4f1a\u6062\u590d, \u5efa\u8bae\u624b\u52a8\u5728 onEnd()
\u5904\u91cd\u65b0\u542f\u7528.
"},{"location":"extra_luacs/reference/#endcutscene","title":"endCutscene","text":"endCutscene()
\u975e\u534f\u7a0b\u51fd\u6570, \u7ed3\u675f\u5f53\u524d\u5267\u60c5.
\u6ce8\u610f\u8be5\u51fd\u6570\u8c03\u7528\u540e\u540e\u9762\u7684\u4ee3\u7801\u4f9d\u7136\u4f1a\u6267\u884c, \u76f4\u5230\u9047\u5230\u4e00\u4e2a\u534f\u7a0b\u51fd\u6570, \u6216\u8005\u51fd\u6570\u88ab\u8fd4\u56de\u6216\u5230\u8fbe\u672b\u5c3e.
"},{"location":"other/xml-speedrun/","title":"XML \u7b80\u5355\u4ecb\u7ecd","text":"\u8fd9\u91cc\u4e3a\u4e86\u65b9\u4fbf\u67d0\u4e9b\u6ca1\u542c\u8bf4\u8fc7 XML \u7684\u4eba\u5feb\u901f\u4e86\u89e3 XML \u7684\u5927\u81f4\u8bed\u6cd5\u662f\u4ec0\u4e48, \u6240\u4ee5\u5f88\u591a\u7ec6\u8282\u65b9\u9762\u7684\u95ee\u9898\u6211\u4f1a\u76f4\u63a5\u5ffd\u7565, \u90a3\u4e48, \u5c31\u6b64\u5f00\u59cb\u5427:
"},{"location":"other/xml-speedrun/#_1","title":"\u5b9a\u4e49","text":"\u8fd9\u91cc\u6458\u6284\u4e00\u4e0b:
XML \u6307\u53ef\u6269\u5c55\u6807\u8bb0\u8bed\u8a00(eXtensible Markup Language). XML \u88ab\u8bbe\u8ba1\u7528\u6765\u4f20\u8f93\u548c\u5b58\u50a8\u6570\u636e, \u4e0d\u7528\u4e8e\u8868\u73b0\u548c\u5c55\u793a\u6570\u636e, HTML \u5219\u7528\u6765\u8868\u73b0\u6570\u636e.
XML \u662f\u4e00\u79cd\u4ee5\u683c\u5f0f\u5316\u50a8\u5b58\u6570\u636e\u7684\u8bed\u8a00, \u5728 msbuild
\u4e2d\u5b83\u5c31\u88ab\u7528\u6765\u4ee5\u683c\u5f0f\u5316\u7684\u65b9\u5f0f\u63cf\u8ff0\u6574\u4e2a\u9879\u76ee\u7684\u4fe1\u606f.
"},{"location":"other/xml-speedrun/#_2","title":"\u8282\u70b9, \u7279\u6027","text":"\u4e00\u6bb5\u5f88\u57fa\u7840\u7684 XML \u53ef\u80fd\u662f\u8fd9\u4e2a\u6837\u5b50\u7684:
<books>\n <book id=\"123\">\u8fd9\u662f\u7b2c\u4e00\u672c\u4e66</book>\n <book id=\"456\">\u8fd9\u662f\u7b2c\u4e8c\u672c\u4e66</book>\n <book id=\"114\">\u8fd9\u662f\u7b2c\u4e09\u672c\u4e66</book>\n <book id=\"514\">\u8fd9\u662f\u4e0d\u77e5\u9053\u7b2c\u51e0\u672c\u4e66</book>\n</books>\n
\u8fd9\u6bb5 XML \u7528\u4e2d\u6587\u89e3\u91ca\u8d77\u6765\u662f\u8fd9\u6837\u7684:
\u9996\u5148\u6211\u4eec\u5b9a\u4e49\u4e86\u4e00\u4e2a\u8282\u70b9, \u5b83\u7684\u540d\u5b57\u53eb\u505a \"books\", \u5b83\u6709\u5f88\u591a\u5b50\u8282\u70b9, \u5206\u522b\u662f:
\u4e00\u4e2a \"book\" \u8282\u70b9, \u5b83\u7684 id \u7279\u6027\u662f 123, \u5b83\u7684\u5185\u5bb9\u662f \"\u8fd9\u662f\u7b2c\u4e00\u672c\u4e66\" \u4e00\u4e2a \"book\" \u8282\u70b9, \u5b83\u7684 id \u7279\u6027\u662f 456, \u5b83\u7684\u5185\u5bb9\u662f \"\u8fd9\u662f\u7b2c\u4e8c\u672c\u4e66\" \u4e00\u4e2a \"book\" \u8282\u70b9, \u5b83\u7684 id \u7279\u6027\u662f 114, \u5b83\u7684\u5185\u5bb9\u662f \"\u8fd9\u662f\u7b2c\u4e09\u672c\u4e66\" \u4e00\u4e2a \"book\" \u8282\u70b9, \u5b83\u7684 id \u7279\u6027\u662f 514, \u5b83\u7684\u5185\u5bb9\u662f \"\u8fd9\u662f\u4e0d\u77e5\u9053\u7b2c\u51e0\u672c\u4e66\" \u5728\u8fd9\u91cc, \u6700\u5916\u5c42\u7684 \"books\" \u4ee5\u53ca\u91cc\u9762\u7684 \"book\" \u90fd\u79f0\u4e3a\u8282\u70b9, \u5176\u4e2d \"books\" \u8282\u70b9\u5185\u90e8\u6709\u5f88\u591a \"book\" \u8282\u70b9, \u800c \"book\" \u8282\u70b9\u5185\u90e8\u53ea\u6709\u4e00\u4e32\u6587\u672c. \u6bcf\u4e2a \"book\" \u8282\u70b9\u90fd\u6709\u4e00\u4e2a\u53eb\u505a id \u7684\u7279\u6027(\u6709\u65f6\u4e5f\u53eb\u505a\u5c5e\u6027, \u4e0d\u8fc7\u6ce8\u610f\u522b\u4e0e C# \u7684\u5c5e\u6027/\u7279\u6027\u76f8\u6df7\u6dc6).
\u5728\u8bed\u6cd5\u5c42\u9762\u4e0a, \u4e00\u4e2a\u8282\u70b9\u4ee5 <\u540d\u5b57> \u5f00\u59cb\u58f0\u660e, \u5728\u53d9\u8ff0\u5b8c\u5b83\u7684\u5185\u5bb9\u540e\u4ee5 </\u540d\u5b57> \u7ed3\u675f. \u5c5e\u6027\u5219\u5728\u8282\u70b9\u540d\u79f0\u4e4b\u540e\u4ee5\u7a7a\u683c\u5206\u9694\u6392\u5217: <\u540d\u5b57 \u5c5e\u60271=\"\u503c1\" \u5c5e\u60272=\"\u503c2\">, \u5c5e\u6027\u7684\u503c\u9700\u8981\u7531 \"
\u5305\u88f9. \u5bf9\u4e8e\u4e00\u4e9b\u6ca1\u6709\u5185\u90e8\u5185\u5bb9\u7684\u8282\u70b9, \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u81ea\u7ed3\u675f\u8bed\u6cd5:
<columns>\n <column id=\"xxx\"/>\n <column qwq=\"6\" awa=\"4\"/>\n <column/>\n <column/>\n <column/>\n</columns>\n
XML \u5141\u8bb8\u4ee5\u4efb\u610f\u6df1\u5ea6\u6765\u5d4c\u5957, \u6240\u4ee5\u6211\u4eec\u53ef\u4ee5\u8fd9\u6837\u6765\u7ec4\u88c5\u4e00\u4e2a\u5f88\u590d\u6742\u7684 XML:
<books>\n <book id=\"123\">\n <bookmarks page=\"1\">114514</bookmarks>\n <bookmarks page=\"2\">2333</bookmarks>\n <bookmarks page=\"123\">838</bookmarks>\n </book>\n <book id=\"456\">\n <bookmarks page=\"1\">\n <picture src=\"http://example.com\">\n this is alt\n </picture>\n <text content=\"text here!\"/>\n </bookmarks>\n <bookmarks page=\"2\">2333</bookmarks>\n </book>\n</books>\n
"},{"location":"trans/adv_hooks/","title":"IL \u94a9\u5b50\u4e0e\u968f\u610f\u94a9\u53d6","text":""},{"location":"trans/adv_hooks/#il_1","title":"IL \u94a9\u5b50","text":""},{"location":"trans/adv_hooks/#il_2","title":"\u63d2\u5165 IL","text":"\u73b0\u5728, \u4f60\u5df2\u7ecf\u4e86\u89e3\u4e86\u57fa\u672c\u7684 IL \u77e5\u8bc6, \u7a0d\u5fae\u4f1a\u4f7f\u7528 System.Reflection.Emit
\u5e93\u4e86, \u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u4f7f\u7528 IL \u94a9\u5b50\u4e86. IL \u94a9\u5b50\u5141\u8bb8\u4f60\u4fee\u6539\u851a\u84dd\u7684\u4ee3\u7801, \u8fd9\u662f\u4e00\u4e2a\u5f88\u5f3a\u5927\u7684\u529f\u80fd, \u90a3\u4e48\u81ea\u7136\u800c\u7136, \u5b83\u7684\u4f7f\u7528\u4e5f\u4f1a\u53d8\u5f97\u66f4\u52a0\u590d\u6742.
IL \u94a9\u5b50\u4e0e On \u94a9\u5b50\u7684\u4e8b\u4ef6\u8ba2\u9605\u65b9\u5f0f\u5f88\u76f8\u50cf, \u53ea\u4e0d\u8fc7\u662f\u6362\u6210\u4e86 IL \u547d\u540d\u7a7a\u95f4, \u4e0d\u8fc7\u8981\u6ce8\u610f\u7684\u662f, \u65b9\u6cd5\u7684\u53c2\u6570\u4e0d\u518d\u662f\u539f\u51fd\u6570\u59d4\u6258\u52a0\u4e0a\u5176\u5bf9\u5e94\u53c2\u6570\u4e86, \u800c\u662f\u4e00\u4e2a ILContext
\u7c7b\u578b\u7684\u503c, \u540c\u65f6, \u65b9\u6cd5\u4e5f\u4e0d\u662f\u6bcf\u6b21\u8c03\u7528\u88ab\u94a9\u65b9\u6cd5\u65f6\u8c03\u7528, \u800c\u662f\u4ec5\u5728\u6e38\u620f\u542f\u52a8\u65f6\u8c03\u7528. \u4f8b\u5982, \u94a9\u53d6\u73a9\u5bb6\u7684 SuperWallJump
\u65b9\u6cd5(\u5728\u73a9\u5bb6\u505a\u51fa\u4e86\u4e00\u4e2a\u8e6d\u5899\u65f6\u8c03\u7528):
public override void Load()\n{\n IL.Celeste.Player.SuperWallJump += Player_SuperWallJump;\n}\n\nprivate void Player_SuperWallJump(ILContext il)\n{\n\n}\n\npublic override void Unload()\n{\n IL.Celeste.Player.SuperWallJump -= Player_SuperWallJump;\n}\n
\u73b0\u5728, \u6211\u4eec\u83b7\u53d6\u5230\u4e86\u4e00\u4e2a ILContext
, \u5b83\u8868\u793a\u8fd9\u4e2a\u65b9\u6cd5\u7684 IL
\u4e0a\u4e0b\u6587, \u4e0d\u8fc7\u5728\u8fd9\u91cc\u4f60\u4e0d\u9700\u8981\u77e5\u9053\u8fd9\u662f\u4ec0\u4e48, \u6211\u4eec\u901a\u5e38\u8981\u7684\u53ea\u662f\u4f7f\u7528\u5176\u521b\u5efa\u4e00\u4e2a ILCursor
:
ILCursor cur = new(il);\n
\u987e\u540d\u601d\u4e49, \u8fd9\u662f\u4e00\u4e2a \"IL \u6307\u9488\", \u5b83 \"\u6307\u5411\" \u8fd9\u4e2a\u65b9\u6cd5\u7684 IL \u4ee3\u7801\u7684\u67d0\u4e00\u884c, \u5b83\u62e5\u6709\u5f88\u591a\u65b9\u6cd5\u4ee5\u5141\u8bb8\u6211\u4eec\u5728\u5b83\u6307\u5411\u7684\u4f4d\u7f6e\u4e0b\u6dfb\u52a0, \u4fee\u6539, \u5220\u9664 IL, \u81ea\u7136, \u5b83\u4e5f\u5e26\u6709\u5f88\u591a\u65b9\u6cd5\u6765\u79fb\u52a8\u5b83\u7684\u6307\u5411, \u6700\u5e38\u7528\u7684\u65b9\u6cd5\u4e4b\u4e00\u662f TryGotoNext
, \u5b83\u7684\u53c2\u6570\u5217\u8868\u5305\u542b\u4e00\u7cfb\u5217\u7684 predicates
(\u8fd9\u8bcd\u4f3c\u4e4e\u6ca1\u4e2a\u7edf\u4e00\u7684\u7ffb\u8bd1, \u4e0d\u8fc7\u7406\u89e3\u5b83\u5f88\u7b80\u5355).
\u73b0\u5728, \u5047\u8bbe\u6211\u4eec\u7684\u76ee\u7684\u662f\u4fee\u6539\u73a9\u5bb6\u8e6d\u5899\u8df3\u65f6\u7684\u7ad6\u76f4\u901f\u5ea6\u4e3a 2 \u500d, \u90a3\u4e48\u6211\u4eec\u627e\u5230 SuperWallJump
\u65b9\u6cd5, \u6ce8\u610f\u5230\u7ad6\u76f4\u901f\u5ea6\u662f\u5728\u8fd9\u91cc\u8bbe\u7f6e\u7684:
Celeste.Player.SuperWallJump()...\nthis.wallSlideTimer = 1.2f;\nthis.wallBoostTimer = 0f;\nthis.Speed.X = 170f * (float)dir;\nthis.Speed.Y = -160f;\nthis.Speed += this.LiftBoost;\nthis.varJumpSpeed = this.Speed.Y;\nthis.launched = true;\n...\n
\u90a3\u4e48\u6211\u4eec\u67e5\u770b\u5b83\u9644\u8fd1 IL, \u7136\u540e\u67e5\u627e\u8fd9\u90e8\u5206 IL \u7684\u4e00\u4e2a\u7279\u5f81\u4ee5\u65b9\u4fbf\u6211\u4eec\u8fdb\u884c\u5b9a\u4f4d:
Celeste.Player.SuperWallJump()IL_0075: ldarg.1\nIL_0076: conv.r4\nIL_0077: mul\nIL_0078: stfld float32 [FNA]Microsoft.Xna.Framework.Vector2::X\nIL_007D: ldarg.0\nIL_007E: ldflda valuetype [FNA]Microsoft.Xna.Framework.Vector2 Celeste.Player::Speed\nIL_0083: ldc.r4 -160\nIL_0088: stfld float32 [FNA]Microsoft.Xna.Framework.Vector2::Y\nIL_008D: ldarg.0\nIL_008E: ldarg.0\n
\u6211\u4eec\u53d1\u73b0\u8fd9\u91cc\u6709\u4e00\u4e2a\u5f88\u7279\u6b8a\u7684 -160 \u6d6e\u70b9\u6570\u7684\u538b\u5165, \u5e76\u4e14\u7d27\u968f\u5176\u540e\u7684\u662f\u4e00\u4e2a Vector2::Y
\u5b57\u6bb5\u7684\u5b58\u5165, \u90a3\u4e48\u8fd9\u6837\u6211\u4eec\u5c31\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e2a\u7279\u5f81\u5c06 IL \u6307\u9488\u6307\u5411\u8fd9\u91cc:
if (cur.TryGotoNext(ins => ins.MatchLdcR4(-160f), ins => ins.MatchStfld<Vector2>(\"Y\")))\n{\n // \u6307\u9488\u4f4d\u4e8e ldc.r4 \u6307\u4ee4\u4e86\n}\n
\u4e0a\u8ff0\u4ee3\u7801\u4e2d\u6211\u4eec\u8981\u6c42 IL \u6307\u9488\u5411\u4e0b\u67e5\u627e, \u76f4\u5230\u627e\u5230\u4e00\u4e2a\u4f4d\u7f6e\u4f7f\u5f97 IL \u662f ldc.r4 -160f
\u5e76\u4e14\u4e0b\u4e00\u884c\u662f\u50a8\u5b58\u5230 Vector2
Y
\u5b57\u6bb5. \u5982\u679c\u6ca1\u627e\u5230\u5219\u8fd4\u56de false
. \u73b0\u5728, \u6211\u4eec\u7684\u6307\u9488\u5df2\u7ecf\u6307\u5411 ldc.r4
\u4e86, \u4f46\u662f\u6b64\u65f6\u5728\u8fd9\u4e2a\u4f4d\u7f6e\u52a0\u5165 IL \u4ee3\u7801\u5b9e\u9645\u4e0a\u4f1a\u52a0\u5230\u8fd9\u4e00\u884c\u4e0a\u9762\u53bb, \u6240\u6709\u6211\u4eec\u5f97\u5148\u8ba9\u5b83\u518d\u5411\u4e0b\u79fb\u52a8\u4e00\u884c, \u7136\u540e\u4f7f\u7528\u6211\u4eec\u7684 IL \u77e5\u8bc6, \u5c06\u5b83\u4e58\u4ee5\u4e2a 2:
if (cur.TryGotoNext(ins => ins.MatchLdcR4(-160f), ins => ins.MatchStfld<Vector2>(\"Y\")))\n{\n cur.Index++;\n cur.Emit(OpCodes.Ldc_R4, 2.0f);\n cur.Emit(OpCodes.Mul);\n}\n
Warning
\u6ce8\u610f OpCodes \u4f4d\u4e8e Mono.Cecil.Cil
\u800c\u4e0d\u662f System.Reflection.Emit
\u547d\u540d\u7a7a\u95f4\u4e0b.
\u73b0\u5728\u7f16\u8bd1\u8fd0\u884c, \u4f60\u5e94\u8be5\u80fd\u89c2\u5bdf\u5230\u8e6d\u5899\u8df3\u7684\u7ad6\u76f4\u901f\u5ea6\u53d8\u7684\u5f88\u5927!
\u6ce8\u610f\u7684\u662f, IL \u94a9\u5b50\u5f88\u5f3a\u5927, \u4f46\u4f7f\u7528\u5b83\u7684\u98ce\u9669\u4e5f\u5f88\u5927, \u7a0d\u6709\u4e0d\u614e\u5c31\u4f1a\u4f7f\u6574\u4e2a\u6e38\u620f\u76f4\u63a5\u5d29\u6e83. \u4f8b\u5982, \u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d, \u5982\u679c\u4f60\u5fd8\u8bb0\u4e86\u5411\u4e0b\u79fb\u52a8\u4e00\u884c, \u6211\u4eec\u5e0c\u671b\u63d2\u5165\u7684 IL \u4ee3\u7801\u5c31\u4f1a\u9519\u8bef\u5730\u88ab\u63d2\u5165\u81f3 ldc.r4 \u7684\u4e0a\u4e00\u884c, \u901a\u5e38\u8fd9\u4f1a\u5bfc\u81f4\u975e\u6cd5\u7684 IL \u4ee5\u5bfc\u81f4 JIT \u7f16\u8bd1\u5f02\u5e38, \u6216\u8005\u5176\u4ed6\u4e0d\u53ef\u9884\u77e5\u7684\u884c\u4e3a, \u4e0d\u8fc7\u5728\u8fd9\u91cc\u5b83\u4f1a\u5bfc\u81f4\u4e00\u4e2a\u66f4\u52a0\u4e25\u91cd\u7684\u95ee\u9898, \u5b83\u4f1a\u76f4\u63a5\u5d29\u6e83\u6389\u4f60\u7684\u6e38\u620f\u5e76\u4e14\u4e0d\u52a0\u4efb\u4f55 log.txt \u7684\u8f93\u51fa\u548c error_log.txt \u7684\u5f39\u51fa! \u4f60\u53ef\u4ee5\u81ea\u5df1\u5c1d\u8bd5\u4e00\u4e0b\u6765\u611f\u53d7\u5982\u679c IL \u94a9\u5b50\u4f7f\u7528\u5931\u8bef\u7684\u60c5\u51b5.
\u901a\u5e38\u66f4\u5e38\u89c1\u5730, \u6211\u4eec\u5e0c\u671b\u8fd9\u4e2a\u7cfb\u6570\u662f\u53ef\u4ee5\u968f\u65f6\u4fee\u6539\u7684, \u76f8\u4fe1\u4f60\u5f88\u5feb\u5c31\u80fd\u60f3\u5230\u6bd4\u5982\u50a8\u5b58\u5230\u5b57\u6bb5\u91cc, \u7136\u540e\u63d2\u5165\u4e00\u4e9b\u590d\u6742\u7684\u5b57\u6bb5\u8bfb\u53d6\u4ee3\u7801\u6216\u8005\u590d\u6742\u7684\u65b9\u6cd5\u8c03\u7528\u4ee3\u7801, \u4e0d\u8fc7 MonoMod \u4e3a\u6211\u4eec\u63d0\u4f9b\u4e86\u4e00\u4e2a\u66f4\u7b80\u5355\u7684\u65b9\u6cd5: EmitDelegate
, \u5b83\u80fd\u4e00\u952e\u751f\u6210\u8fd9\u4e9b\u590d\u6742\u7684\u65b9\u6cd5\u83b7\u53d6\u548c\u8c03\u7528.
\u4f8b\u5982\u4f60\u6709\u4e00\u4e2a\u9759\u6001\u65b9\u6cd5 GetFactorOfWallJumpYSpeed
, \u5b83\u4f1a\u6839\u636e\u4e00\u4e9b\u60c5\u51b5\u8fd4\u56de\u4e0d\u540c\u7684\u503c, \u4f8b\u5982\u5728\u8fd9\u91cc\u68c0\u6d4b\u6309\u8df3\u65f6\u662f\u5426\u540c\u65f6\u6309\u4e0b\u6293\u952e, \u662f\u5219\u7ffb\u500d\u7ad6\u76f4\u901f\u5ea6, \u5426\u5219\u4e0d\u53d8:
public static float GetFactorOfWallJumpYSpeed()\n{\n if (Input.Grab.Pressed)\n return 2.0f;\n else\n return 1.0f;\n}\n
\u4e0a\u9762\u5bf9\u5e94\u7684\u4ee3\u7801:
if (cur.TryGotoNext(ins => ins.MatchLdcR4(-160f), ins => ins.MatchStfld<Vector2>(\"Y\")))\n{\n cur.Index++;\n // as easy as pi!\n cur.EmitDelegate(GetFactorOfWallJumpYSpeed);\n cur.Emit(OpCodes.Mul);\n}\n
"},{"location":"trans/adv_hooks/#il_3","title":"\u79fb\u9664 IL","text":"\u901a\u5e38\u9664\u4e86\u63d2\u5165, \u6211\u4eec\u8fd8\u9700\u8981\u79fb\u9664 IL, \u5bf9\u4e8e\u4fee\u6539 IL \u7684\u60c5\u51b5\u6211\u4eec\u53ea\u9700\u8981\u5148\u79fb\u9664\u518d\u63d2\u5165\u5373\u53ef. \u8981\u79fb\u9664\u4e00\u884c IL, \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 Remove
\u65b9\u6cd5, Remove
\u65b9\u6cd5\u4f1a\u79fb\u9664\u6307\u9488\u6240\u6307\u7684 IL \u884c, \u4f8b\u5982\u6211\u4eec\u4f9d\u7136\u4fee\u6539\u73a9\u5bb6\u7684\u8e6d\u5899\u8df3\u7ad6\u76f4\u901f\u5ea6, \u4f46\u662f\u5728\u8fd9\u91cc\u6211\u4eec\u76f4\u63a5\u8986\u76d6\u6211\u4eec\u7684\u65b0\u503c:
if (cur.TryGotoNext(ins => ins.MatchLdcR4(-160f), ins => ins.MatchStfld<Vector2>(\"Y\")))\n{\n // \u6ce8\u610f\u6ca1\u6709 cur.Index++ \u4e86, \u8bb0\u4f4f Emit \u65f6\u65b0\u4ee3\u7801\u88ab\u6dfb\u52a0\u5230\u4e0a\u4e00\u884c, \u800c Remove \u65f6\u5219\u79fb\u9664\u5f53\u524d\u884c\n cur.Remove();\n // \u5f53\u524d\u4e00\u884c\u7684 IL \u5df2\u7ecf\u88ab\u79fb\u9664\u4e86, \u73b0\u5728\u6307\u9488\u5b9e\u9645\u4e0a\u6307\u5411\u4e4b\u524d\u7684\u4e0b\u4e00\u884c, \u6240\u4ee5\u6211\u4eec\u53ef\u4ee5\u76f4\u63a5 Emit\n cur.Emit(OpCodes.Ldc_R4, -300.0f);\n}\n
Note
\u5728\u63d2\u5165 IL, \u4fee\u6539 IL, \u66f4\u6539 IL \u6307\u9488\u6307\u5411\u65f6\u52a1\u5fc5\u6e05\u695a\u63d2\u5165\u4f4d\u7f6e, \u5220\u9664\u76ee\u6807, \u4ee5\u53ca\u64cd\u4f5c\u5b8c\u6210\u540e\u7684\u6307\u9488\u6307\u5411.
"},{"location":"trans/adv_hooks/#_1","title":"\u4efb\u610f\u94a9\u53d6","text":"\u76f8\u4fe1\u4f60\u5df2\u7ecf\u53d1\u73b0\u4e86, \u6709\u4e9b\u65b9\u6cd5\u6bd4\u5982\u53eb\u505a orig_xxx
\u7684\u65b9\u6cd5, \u4ee5\u53ca\u5c5e\u6027\u7684 getter \u548c setter \u4f60\u90fd\u65e0\u6cd5\u5728 On. \u548c IL. \u8fd9\u4e24\u4e2a\u547d\u540d\u7a7a\u95f4\u4e2d\u627e\u5230, \u540c\u65f6, \u94a9\u53d6\u522b\u7684 helper \u7684\u65b9\u6cd5\u4f3c\u4e4e\u4e5f\u65e0\u6cd5\u5b8c\u6210.
\u8fd9\u91cc\u6211\u4eec\u5f15\u5165\u4e24\u4e2a\u65b0\u7c7b: Hook
\u4e0e ILHook
, \u524d\u8005\u8868\u793a\u4e00\u4e2a On \u94a9\u5b50, \u540e\u8005\u8868\u793a\u4e00\u4e2a IL \u94a9\u5b50.
Info
Hook
\u4e0e ILHook
\u4f4d\u4e8e MonoMod.RuntimeDetour
\u7a0b\u5e8f\u96c6\u4e2d, \u5728\u65e7\u6a21\u677f\u91cc\u5b83\u6ca1\u6709\u88ab\u9ed8\u8ba4\u5f15\u7528\u8fdb\u6765, \u8fd9\u662f\u4e00\u4e2a\u6211\u4e2a\u4eba\u7684\u5931\u8bef, \u5982\u679c\u4f60\u786e\u5b9e\u65e0\u6cd5\u5f15\u7528\u8fd9\u4e24\u4e2a\u7c7b\u7684\u8bdd\u4f60\u53ef\u4ee5\u5728 CelesteMod.props
\u91cc\u7684\u6700\u5e95\u4e0b\u7684\u90a3\u4e2a ItemGroup
\u4e2d\u52a0\u5165\u8fd9\u4e00\u6761:
<Reference Include=\"MonoMod.RuntimeDetour\">\n <HintPath>$(CelesteAssemblyPath)/MonoMod.RuntimeDetour.dll</HintPath>\n <Private>False</Private>\n</Reference>\n
Hook
\u7684\u6784\u9020\u51fd\u6570\u62e5\u6709\u975e\u5e38\u591a\u91cd\u8f7d, \u5728\u8fd9\u91cc\u6211\u4eec\u53ea\u9700\u8981\u90a3\u4e2a (MethodBase method, Delegate to)
\u7684\u91cd\u8f7d, \u5b83\u8868\u793a\u6211\u4eec\u5e0c\u671b\u94a9\u53d6\u7b2c\u4e00\u4e2a\u53c2\u6570\u6307\u5b9a\u7684\u65b9\u6cd5, \u94a9\u5b50\u65b9\u6cd5\u662f\u7b2c\u4e8c\u4e2a\u53c2\u6570\u6307\u5b9a\u7684\u59d4\u6258.
\u4f8b\u5982, \u6211\u4eec\u5e0c\u671b\u94a9\u53d6 Player.Inventory
\u8fd9\u4e2a\u5c5e\u6027\u7684 get
\u65b9\u6cd5, \u4f7f\u5176\u603b\u662f\u8fd4\u56de PlayerInventory.TheSummit
, \u4e5f\u5c31\u662f\u603b\u662f\u5177\u6709\u80cc\u5305, \u53cc\u51b2\u7b49:
// \u50a8\u5b58\u6211\u4eec\u7684 hook, \u4ee5\u4fbf\u6211\u4eec\u5728 Unload \u4e2d\u91ca\u653e\u5b83\nprivate Hook playerInventory_get_hook;\n\npublic override void Load()\n{\n // \u5148\u4f7f\u7528\u53cd\u5c04\u627e\u5230 Player.Inventory \u5c5e\u6027\u7684 getter\n var playerInventory_get = typeof(Player).GetProperty(\"Inventory\").GetGetMethod();\n // \u4f7f\u7528\u5176\u521b\u5efa\u4e00\u4e2a On \u94a9\u5b50\n playerInventory_get_hook = new(playerInventory_get, PlayerInventoryHook);\n}\n\n// \u6211\u4eec\u9700\u8981\u624b\u52a8\u58f0\u660e orig \u65b9\u6cd5\u7684\u59d4\u6258, \u56e0\u4e3a\u8fd9\u91cc\u4e0d\u518d\u662f\u65b9\u4fbf\u7684\u4e8b\u4ef6\u8ba2\u9605\u4e86\npublic delegate PlayerInventory PlayerInventory_get_orig(Player self);\npublic static PlayerInventory PlayerInventoryHook(PlayerInventory_get_orig orig, Player self)\n{\n // \u76f4\u63a5\u5ffd\u7565 orig \u65b9\u6cd5\u7684\u8c03\u7528, \u5f3a\u5236\u8fd4\u56de 7a/b/c \u7684 Inventory\n return PlayerInventory.TheSummit;\n}\n\npublic override void Unload()\n{\n // \u8bb0\u5f97\u9500\u6bc1\u94a9\u5b50\n playerInventory_get_hook.Dispose();\n}\n
\u56e0\u4e3a\u4e0d\u518d\u662f\u4e4b\u524d\u65b9\u4fbf\u7684\u4e8b\u4ef6\u8ba2\u9605, \u6240\u4ee5\u94a9\u5b50\u7684 orig \u53c2\u6570\u7684\u59d4\u6258\u539f\u578b\u4f60\u5fc5\u987b\u5f97\u81ea\u5df1\u58f0\u660e, \u6ce8\u610f\u94a9\u5b50\u65b9\u6cd5\u548c\u94a9\u5b50 orig \u53c2\u6570\u7684\u53c2\u6570\u5217\u8868\u4e00\u5b9a\u8981\u5c0f\u5fc3\u51c6\u786e\u7684\u586b\u5199, \u5426\u5219\u4f1a\u76f4\u63a5\u9020\u6210\u6e38\u620f\u5d29\u6e83. \u4e0a\u8ff0\u4ee3\u7801\u7684\u6548\u679c\u5e94\u8be5\u662f\u4f60\u65e0\u8bba\u5982\u4f55\u90fd\u4f1a\u62e5\u6709 7a/b/c \u7684 Inventory, \u4e5f\u5927\u6982\u5373\u53cc\u51b2, \u5e26\u80cc\u5305.
\u73b0\u5728, \u62e5\u6709\u4e86\u94a9\u5b50\u51fd\u6570, \u4f60\u53ef\u4ee5\u505a\u4efb\u4f55\u4f60\u4e4b\u524d\u4f7f\u7528\u8ba2\u9605\u4e8b\u4ef6\u6765\u521b\u5efa\u94a9\u5b50\u4e00\u6837\u7684\u4e8b. \u987a\u4fbf, \u4f7f\u7528\u8fd9\u79cd\u65b9\u6cd5\u4e5f\u5141\u8bb8\u4f60\u94a9\u53d6\u522b\u7684 helper \u7684\u65b9\u6cd5, \u751a\u81f3\u662f\u94a9\u53d6\u522b\u7684 helper \u7684\u94a9\u5b50\u65b9\u6cd5. \u4e0d\u8fc7\u5728\u6b64\u4e4b\u524d\u4f60\u9700\u8981\u4e3a\u4f60\u7684 mod \u58f0\u660e\u4f9d\u8d56\u6216\u8005\u53ef\u9009\u4f9d\u8d56, \u58f0\u660e\u53ef\u9009\u4f9d\u8d56\u540e\u53c8\u9700\u8981\u68c0\u6d4b\u5bf9\u5e94 mod \u662f\u5426\u52a0\u8f7d\u7b49\u7b49, \u8fd9\u90e8\u5206\u5185\u5bb9\u6211\u4eec\u4e4b\u540e\u518d\u8bf4.
\u540c\u6837\u5730, IL \u94a9\u5b50\u7684\u521b\u5efa\u4e5f\u4e0e On \u94a9\u5b50\u76f8\u540c:
private ILHook playerInventory_get_ilhook;\n\npublic override void Load()\n{\n var playerInventory_get = typeof(Player).GetProperty(\"Inventory\").GetGetMethod();\n playerInventory_get_ilhook = new(playerInventory_get, PlayerInventoryILHook);\n}\n\npublic static void PlayerInventoryILHook(ILContext context)\n{\n // \u50cf\u4e4b\u524d\u4e00\u6837\u505a\u4f60\u5728 IL \u94a9\u5b50\u4e2d\u505a\u7684\u4e8b...\n}\n\npublic override void Unload()\n{\n playerInventory_get_ilhook.Dispose();\n}\n
\u4e0d\u8fc7\u4e0d\u518d\u9700\u8981\u624b\u52a8\u58f0\u660e orig \u59d4\u6258, \u56e0\u4e3a IL \u94a9\u5b50\u7684\u94a9\u5b50\u65b9\u6cd5\u53c2\u6570\u5217\u8868\u662f\u56fa\u5b9a\u7684.
Note
\u5173\u4e8e\u534f\u7a0b\u51fd\u6570\u7684\u94a9\u53d6\u4e0e\u4e0a\u8ff0\u6b65\u9aa4\u622a\u7136\u4e0d\u540c, \u8fd9\u4e00\u70b9\u6211\u4eec\u4f1a\u5728\u4e0b\u4e00\u8282\u63a2\u8ba8.
"},{"location":"trans/adv_hooks2/","title":"\u534f\u7a0b\u7684\u94a9\u53d6\u4e0e\u79c1\u6709\u8bbf\u95ee","text":""},{"location":"trans/adv_hooks2/#_2","title":"\u534f\u7a0b\u7684\u94a9\u53d6","text":""},{"location":"trans/adv_hooks2/#_3","title":"\u8fed\u4ee3\u5668\u51fd\u6570","text":"\u8fed\u4ee3\u5668\u51fd\u6570, \u4e5f\u5373\u65b9\u6cd5\u4f53\u5e26 yield return
\u6216 yield break
\u8bed\u53e5\u5e76\u8fd4\u56de IEnumerable
\u6216 IEnumerator
\u7684\u51fd\u6570, \u5b83\u5141\u8bb8\u4f60 \"\u4e2d\u65ad\" \u51fd\u6570\u7684\u8fd0\u884c\u5e76\u4e2d\u9014 \"\u8fd4\u56de\" \u4e00\u4e2a\u503c. \u7ecf\u8fc7\u524d\u9762 Alarm, Tween, Coroutine \u8282\u7684\u4ecb\u7ecd\u76f8\u4fe1\u4f60\u4e5f\u77e5\u9053\u5230\u4e86\u534f\u7a0b\u4e4b\u4e8e\u8fed\u4ee3\u5668\u51fd\u6570\u7684\u5f3a\u5927. \u4e0d\u8fc7\u5bf9\u4e8e\u534f\u7a0b\u51fd\u6570\u7684\u94a9\u53d6\u5e76\u4e0d\u662f\u90a3\u4e48\u7b80\u5355, \u9700\u8981\u4e00\u4e9b\u989d\u5916\u6b65\u9aa4.
\u5982\u679c\u4f60\u76f8\u5bf9\u4e86\u89e3\u4e00\u70b9 C# \u7684\u5e95\u5c42\u7684\u8bdd, \u4f60\u5e94\u8be5\u4f1a\u77e5\u9053\u8fed\u4ee3\u5668\u51fd\u6570\u6700\u7ec8\u4f1a\u88ab\u7f16\u8bd1\u4e3a\u4e00\u4e2a\u72b6\u6001\u673a\u7c7b, \u800c\u539f\u51fd\u6570\u53ea\u662f\u505a\u4e86\u4e00\u4e2a new \u5e76\u8fd4\u56de\u7684\u5de5\u4f5c. \u4e3a\u4e86\u5728\u53cd\u7f16\u8bd1\u5668\u6bd4\u5982 dnspy \u4e2d\u6d4f\u89c8\u8fd9\u4e2a\u72b6\u6001\u673a\u7c7b, \u4f60\u9700\u8981\u5173\u95ed\u7c7b\u4f3c\u7684 \u89c6\u56fe -> \u9009\u9879 -> \u53cd\u7f16\u8bd1\u5668 -> \u53cd\u7f16\u8bd1\u679a\u4e3e\u5668 \u8fd9\u4e2a\u529f\u80fd, \u8fd9\u6837\u53cd\u7f16\u8bd1\u5668\u624d\u4f1a\u5c55\u793a\u9690\u85cf\u7684\u72b6\u6001\u673a\u7c7b.
\u6bd4\u5982 FinalBoss.Attack01Sequence
\u65b9\u6cd5:
\u539f\u65b9\u6cd5:
private IEnumerator Attack01Sequence()\n{\n this.StartShootCharge();\n for (;;)\n {\n yield return 0.5f;\n this.Shoot(0f);\n yield return 1f;\n this.StartShootCharge();\n yield return 0.15f;\n yield return 0.3f;\n }\n yield break;\n}\n
\u5173\u95ed \u53cd\u7f16\u8bd1\u679a\u4e3e\u5668 \u9009\u9879\u540e:
private IEnumerator Attack01Sequence()\n{\n FinalBoss.<Attack01Sequence>d__49 <Attack01Sequence>d__ = new FinalBoss.<Attack01Sequence>d__49(0);\n <Attack01Sequence>d__.<>4__this = this;\n return <Attack01Sequence>d__;\n}\n
\u5176\u4e2d <Attack01Sequence>d__49
\u8fd9\u4e2a\u53e4\u602a\u7684\u7c7b\u540d\u5c31\u662f\u80cc\u540e\u751f\u6210\u7684\u72b6\u6001\u673a\u7c7b, \u800c\u65b9\u6cd5\u4f53\u7684\u5b9e\u9645\u5185\u5bb9\u5219\u5728\u8be5\u7c7b\u7684 MoveNext
\u65b9\u6cd5\u4e2d:
bool IEnumerator.MoveNext()\n{\n int num = this.<>1__state;\n FinalBoss finalBoss = this.<>4__this;\n switch (num)\n {\n case 0:\n this.<>1__state = -1;\n finalBoss.StartShootCharge();\n break;\n case 1:\n this.<>1__state = -1;\n finalBoss.Shoot(0f);\n this.<>2__current = 1f;\n this.<>1__state = 2;\n return true;\n case 2:\n this.<>1__state = -1;\n finalBoss.StartShootCharge();\n this.<>2__current = 0.15f;\n this.<>1__state = 3;\n return true;\n case 3:\n this.<>1__state = -1;\n this.<>2__current = 0.3f;\n this.<>1__state = 4;\n return true;\n case 4:\n this.<>1__state = -1;\n break;\n default:\n return false;\n }\n this.<>2__current = 0.5f;\n this.<>1__state = 1;\n return true;\n}\n
\u4e0a\u8ff0\u4ee3\u7801\u4e2d <>2__current
\u8fd9\u4e2a\u53e4\u602a\u7684\u5b57\u6bb5\u7528\u6765\u50a8\u5b58\u8fd4\u56de\u503c, <>1__state
\u5219\u7528\u6765\u50a8\u5b58\u534f\u7a0b\u8fd0\u884c\u7684\u8fdb\u5ea6.
"},{"location":"trans/adv_hooks2/#on","title":"On \u534f\u7a0b\u94a9\u5b50","text":"\u5bf9\u534f\u7a0b\u4f7f\u7528 On \u94a9\u5b50\u76f8\u5bf9\u7b80\u5355\u4e00\u70b9 ,\u4f8b\u5982\u94a9\u53d6 Celeste.NPC01_Theo.Talk
\u8fd9\u4e2a\u534f\u7a0b\u51fd\u6570, \u4e5f\u5c31\u662f 1a 6zb \u9762\u7684 theo \u7684\u5bf9\u8bdd\u7684\u534f\u7a0b, \u5982\u679c\u4f60\u76f4\u63a5\u4f7f\u7528\u5982\u4e0b\u4ee3\u7801(\u65b9\u6cd5 1):
public override void Load()\n{\n On.Celeste.NPC01_Theo.Talk += NPC01_Theo_Talk;\n}\n\nprivate IEnumerator NPC01_Theo_Talk(On.Celeste.NPC01_Theo.orig_Talk orig, NPC01_Theo self, Player player)\n{\n var it = orig(self, player);\n Logger.Log(LogLevel.Info, \"Test\", \"not the right time.\");\n return it;\n}\n\npublic override void Unload()\n{\n On.Celeste.NPC01_Theo.Talk -= NPC01_Theo_Talk;\n}\n
\u4f60\u4f1a\u53d1\u73b0\u5b83\u5b9e\u9645\u4e0a\u662f\u5728\u5bf9\u8bdd\u5f00\u59cb\u524d\u8f93\u51fa\u7684, \u8fd9\u5e76\u4e0d\u662f\u6211\u4eec\u60f3\u8981\u7684\u65f6\u673a, \u540c\u6837\u8fd9\u4e5f\u5f88\u597d\u7406\u89e3\u4e3a\u4ec0\u4e48\u4f1a\u8fd9\u6837, \u56e0\u4e3a\u539f\u51fd\u6570\u53ea\u662f\u8fd4\u56de\u4e86\u4e00\u4e2a\u80cc\u540e\u72b6\u6001\u673a\u7c7b\u7684\u65b0\u5b9e\u4f8b. \u4e3a\u4e86\u8fbe\u6210\u8fd9\u4e2a\u76ee\u7684, \u6211\u4eec\u9700\u8981\u8fd9\u4e48\u505a(\u65b9\u6cd5 2):
private IEnumerator NPC01_Theo_Talk(On.Celeste.NPC01_Theo.orig_Talk orig, NPC01_Theo self, Player player)\n{\n IEnumerator origEnum = orig(self, player);\n while (origEnum.MoveNext()) yield return origEnum.Current;\n Logger.Log(LogLevel.Info, \"Test\", \"the right time.\");\n}\n
\u4e5f\u5c31\u662f\u5c06\u5bf9\u5e94\u7684\u534f\u7a0b\u5305\u88c5\u8d77\u6765\u5e76\u5728\u6700\u540e\u9644\u52a0\u6211\u4eec\u7684\u4ee3\u7801. \u8bf4\u5230\u8fd9\u4e2a, \u4f60\u53ef\u80fd\u4f1a\u60f3\u5230\u8fd9\u6bb5\u4ee3\u7801\u53ef\u4ee5\u7b80\u5316\u6210\u8fd9\u6837(\u65b9\u6cd5 3):
private IEnumerator NPC01_Theo_Talk(On.Celeste.NPC01_Theo.orig_Talk orig, NPC01_Theo self, Player player)\n{\n yield return orig(self, player);\n Logger.Log(LogLevel.Info, \"Test\", \"does not execute.\");\n}\n
\u76f4\u63a5\u5c06\u534f\u7a0b\u8fd4\u56de\u5e76\u5728\u5176\u6267\u884c\u5b8c\u540e\u505a\u4e00\u4e9b\u4e8b, \u770b\u8d77\u6765\u4f3c\u4e4e\u6ca1\u4ec0\u4e48\u95ee\u9898? \u4f46\u662f! \u5982\u679c\u4f60\u770b\u8fc7 Coroutine
\u7684\u5b9e\u73b0\u7684\u8bdd, \u4f60\u4f1a\u53d1\u73b0\u534f\u7a0b\u8fd4\u56de\u53e6\u4e00\u4e2a\u534f\u7a0b\u65f6, \u53e6\u4e00\u4e2a\u534f\u7a0b\u5e76\u4e0d\u662f\u9a6c\u4e0a\u6267\u884c\u7684, \u800c\u662f\u7b49\u5230\u4e86\u4e0b\u4e00\u5e27, \u4e3a\u4e86\u66f4\u597d\u7684\u517c\u5bb9 tas, \u6211\u4eec\u8981\u4e48\u4f7f\u7528\u65b9\u6cd5 2, \u8981\u4e48\u4f7f\u7528\u5982\u4e0b\u7c7b\u4f3c\u7684\u4ee3\u7801(\u65b9\u6cd5 4):
private IEnumerator OuiFileSelect_Leave(On.Celeste.OuiFileSelect.orig_Leave orig, OuiFileSelect self, Oui next) \n{\n yield return new SwapImmediately(orig(self, next));\n Logger.Log(\"TestMod\", \"I left file select!\");\n}\n
\u4e5f\u5c31\u662f\u5728\u83b7\u53d6\u534f\u7a0b\u540e\u518d\u7528 everest \u4e3a\u6211\u4eec\u63d0\u4f9b\u7684 SwapImmediately
\u5305\u8d77\u6765, \u8fd9\u4f1a\u8ba9\u5185\u90e8\u7684\u534f\u7a0b\u7acb\u523b\u524d\u8fdb\u4e00\u6b21. \u800c\u4e0d\u4f1a\u7b49\u5f85\u591a\u4f59\u7684 1 \u5e27.
Info
\u5177\u4f53\u4e0a\u8ff0\u65b9\u6cd5\u7684\u884c\u4e3a\u63cf\u8ff0\u7684\u53ef\u80fd\u5e76\u4e0d\u662f\u5f88\u51c6\u786e, \u56e0\u4e3a\u6211\u4e2a\u4eba\u5f88\u5c11\u4f1a\u51fa\u73b0\u9700\u8981\u94a9\u53d6\u534f\u7a0b\u7684\u6848\u4f8b, \u5f88\u611f\u8c22\u5982\u679c\u4f60\u80fd\u5b8c\u5584\u5b83\u7684\u8bdd!
"},{"location":"trans/adv_hooks2/#il","title":"IL \u534f\u7a0b\u94a9\u5b50","text":"\u5bf9\u534f\u7a0b\u4f7f\u7528 IL \u94a9\u5b50\u76f8\u5bf9\u4f1a\u590d\u6742\u5f88\u591a, \u56e0\u4e3a\u5bf9\u539f\u51fd\u6570\u4f7f\u7528 IL \u94a9\u5b50\u901a\u5e38\u662f\u6ca1\u6709\u610f\u4e49\u7684, \u4e3a\u6b64, \u6211\u4eec\u9700\u8981\u83b7\u53d6\u5230\u80cc\u540e\u5b9e\u9645\u50a8\u5b58\u65b9\u6cd5\u4f53\u7684\u72b6\u6001\u673a\u7684 MoveNext
\u65b9\u6cd5:
var methodInfo = typeof(Player).GetMethod(\"DashCoroutine\", BindingFlags.NonPublic | BindingFlags.Instance).GetStateMachineTarget();\nILHook dashCoroutineHook = new ILHook(methodInfo, ILHookDashCoroutine);\n
\u5728\u8fd9\u91cc, MonoMod \u4e3a\u6211\u4eec\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5f88\u65b9\u4fbf\u7684\u62d3\u5c55\u65b9\u6cd5 GetStateMachineTarget
, \u5b83\u4f1a\u83b7\u53d6\u8fd9\u4e2a\u65b9\u6cd5\u5bf9\u5e94\u7684\u72b6\u6001\u673a\u7684 MoveNext
\u65b9\u6cd5, \u968f\u540e\u6211\u4eec\u624b\u52a8\u6784\u9020\u4e00\u4e2a IL \u94a9\u5b50, \u7136\u540e\u5c31\u50cf\u5f80\u5e38\u4e00\u6837\u5b9e\u73b0\u6211\u4eec\u7684\u94a9\u5b50. \u4e0d\u8fc7\u5f53\u7136, \u96be\u5ea6\u4f1a\u975e\u5e38\u5927, \u56e0\u4e3a\u901a\u5e38\u8fd9\u4e2a\u65b9\u6cd5\u662f\u975e\u5e38\u6df7\u4e71\u7684.
"},{"location":"trans/adv_hooks2/#_4","title":"\u79c1\u6709\u8bbf\u95ee","text":"\u901a\u5e38, \u4f60\u53ef\u80fd\u9700\u8981\u8bbf\u95ee\u4e00\u4e2a\u79c1\u6709\u65b9\u6cd5\u6216\u8005\u79c1\u6709\u5b57\u6bb5, \u9996\u5148\u6700\u5bb9\u6613\u60f3\u5230\u7684\u5f53\u7136\u662f\u53cd\u5c04, \u4e0d\u8fc7 MonoMod \u4e3a\u6211\u4eec\u63d0\u4f9b\u4e86\u4e00\u4e2a\u66f4\u597d\u7684\u4e1c\u897f: DynamicData
\u7c7b, \u4f8b\u5982\u8bbf\u95ee\u73a9\u5bb6\u7684\u79c1\u6709\u5b57\u6bb5 onGround
:
DynamicData playerData = DynamicData.For(player);\nbool onGround = playerData.Get<bool>(\"onGround\");\n
\u4fee\u6539\u4e5f\u5341\u5206\u7b80\u5355, \u4f8b\u5982\u4fee\u6539\u73a9\u5bb6\u7684\u6700\u5927\u4e0b\u843d\u901f\u5ea6:
playerData.Set(\"maxFall\", 660f);\n
\u8c03\u7528\u79c1\u6709\u65b9\u6cd5\u540c\u7406, \u53c2\u6570\u4e5f\u53ea\u9700\u4f5c\u4e3a params \u53c2\u6570\u4f20\u9012:
playerData.Invoke(\"Duck\");\n\nbool checkResult = (bool)playerData.Invoke(\"DreamDashCheck\", Vector2.UnitX);\n
\u5bf9\u4e8e\u9759\u6001\u7c7b, \u53ea\u9700\u8981\u7b80\u5355\u7684\u66f4\u6539\u83b7\u53d6 DynamicData
\u7684\u65b9\u5f0f:
DynamicData inputData = new DynamicData(typeof(Input));\n
\u968f\u540e\u9759\u6001\u65b9\u6cd5, \u5b57\u6bb5, \u5c5e\u6027\u7684\u8bbf\u95ee\u4e5f\u4e0e\u5b9e\u4f8b\u7684\u76f8\u540c.
\u5f53\u5b57\u7b26\u4e32\u6307\u5b9a\u7684\u6210\u5458\u4e0d\u5b58\u5728\u65f6, \u6ce8\u610f\u5e76\u4e0d\u4f1a\u62a5\u9519, \u5bf9\u4e8e\u5176\u7684\u975e\u6cdb\u578b Get
\u65b9\u6cd5\u4f1a\u7b80\u5355\u5730\u8fd4\u56de null \u503c, \u5bf9\u4e8e\u503c\u7c7b\u578b\u6cdb\u578b Get
\u65b9\u6cd5\u4f1a\u5f15\u53d1\u7a7a\u5f15\u7528\u5f02\u5e38, \u5bf9\u4e8e\u5f15\u7528\u7c7b\u578b\u6cdb\u578b Get
\u65b9\u6cd5\u8fd4\u56de null. \u4e0d\u8fc7\u5bf9\u4e8e Set
\u65b9\u6cd5, \u5982\u679c\u6307\u5b9a\u7684\u6210\u5458\u4e0d\u5b58\u5728\u65f6\u5b83\u4f1a\u5c06\u8fd9\u4e2a\u6210\u5458 \"\u7c98\u9644\" \u5230\u5bf9\u8c61\u4e0a, \u5c31\u50cf\u7ed9\u5bf9\u8c61\u52a8\u6001\u52a0\u4e86\u4e00\u6761\u5b57\u6bb5\u4e00\u6837, \u968f\u540e\u4f7f\u7528 Get
\u65b9\u6cd5\u4e5f\u80fd\u83b7\u53d6\u5230\u8fd9\u4e2a\u503c, \u4f60\u53ef\u4ee5\u4f7f\u7528\u5c06\u8fd9\u4e2a\u884c\u4e3a\u5f53 \"\u52a8\u6001\u6dfb\u52a0\u5b57\u6bb5\" \u4e00\u6837\u4f7f\u7528. \u4f8b\u5982:
DynamicData dd = DynamicData.For(player);\ndd.Set(\"mcm_attached\", \"some attached data...\");\n\n\n// ...\u4e00\u4e9b\u5176\u4ed6\u5730\u65b9\nstring data = dd.Get<string>(\"mcm_attached\");\nLogger.Log(LogLevel.Info, \"MyCelesteMod\", $\"data is {data}\");\n
\u4e0d\u8fc7\u8bb0\u5f97\u6dfb\u52a0\u81ea\u5df1 mod \u72ec\u7279\u7684\u547d\u540d\u524d\u7f00\u4ee5\u9632\u91cd\u540d, DynamicData
\u5728\u4e0d\u540c mod \u95f4\u662f\u5171\u4eab\u7684.
"},{"location":"trans/common1/","title":"Alarm, Tween, Coroutine","text":""},{"location":"trans/common1/#tween","title":"Tween","text":"Tween \u662f\u4e00\u4e2a\u5728 Monocle \u4e2d\u7528\u6765\u5b9e\u73b0\u7f13\u52a8\u7684 Component
, \u5728\u8fd9\u91cc\u4f60\u53ef\u4ee5\u8fdb\u884c\u6240\u6709 easings.net \u4e0a\u7684\u7f13\u52a8, \u5b83\u7684\u4f7f\u7528\u65b9\u6cd5\u5f88\u7b80\u5355: \u4f7f\u7528 Tween
// \u9996\u5148\u4f7f\u7528\u9759\u6001\u65b9\u6cd5 Tween.Create \u6765\u521b\u5efa\nTween tw = Tween.Create(Tween.TweenMode.Oneshot, Ease.BackIn, 1f, false);\n
\u8fd9\u91cc\u53c2\u6570\u53ef\u80fd\u76f8\u5bf9\u8f83\u591a:
\u7b2c\u4e00\u4e2a\u53c2\u6570 mode
: \u5b83\u8868\u793a\u7f13\u52a8\u7684\u7c7b\u578b, \u53ef\u7528\u7684\u6709: Persist
: \u7f13\u52a8\u7ed3\u675f\u540e\u8be5\u7ec4\u4ef6\u4f1a\u5931\u6d3b, \u76f4\u5230\u518d\u6b21\u88ab\u8c03\u7528 Start
Oneshot
: \u7f13\u52a8\u7ed3\u675f\u540e\u8be5\u7ec4\u4ef6\u4f1a\u79fb\u9664\u81ea\u8eab Looping
: \u7f13\u52a8\u7ed3\u675f\u4e00\u6b21\u540e\u4f1a\u7acb\u523b\u518d\u6b21\u5f00\u59cb\u540c\u4e00\u4e2a\u7f13\u52a8, \u5e76\u5faa\u73af YoyoOneshot
: \u7f13\u52a8\u7ed3\u675f\u540e\u4f1a\u7acb\u523b\u8fdb\u884c\u4e00\u6b21\u53cd\u5411\u7684\u7f13\u52a8, \u7ed3\u675f\u540e\u79fb\u9664\u81ea\u8eab YoyoLooping
: \u540c YoyoOneshot
, \u4f46\u662f\u4f1a\u5faa\u73af\u800c\u4e0d\u662f\u79fb\u9664\u81ea\u8eab \u7b2c\u4e8c\u4e2a\u53c2\u6570 easer
: \u5b83\u8868\u793a\u8be5\u7f13\u52a8\u7684 Easer
, \u901a\u5e38\u6211\u4eec\u4f7f\u7528 Ease
\u7c7b\u4e2d\u7684\u5df2\u6709\u9759\u6001\u5b57\u6bb5\u4e2d\u63d0\u4f9b\u7684\u5c31\u884c\u4e86, \u540c\u6837\u5730\u4f60\u53ef\u4ee5\u5728 easings.net \u611f\u53d7\u5e76\u68c0\u7d22\u4f60\u6240\u9700\u8981\u7684\u7f13\u52a8\u7c7b\u578b. \u7b2c\u4e09\u4e2a\u53c2\u6570 duration
: \u8868\u793a\u8be5\u7f13\u52a8\u8fdb\u884c\u7684\u65f6\u95f4(\u5355\u4f4d\u79d2), \u5bf9\u4e8e\u7279\u6b8a\u7684\u7f13\u52a8\u7c7b\u578b\u6765\u8bf4\u5b83\u6307\u4e00\u6b21\u6b63\u5411\u7f13\u52a8\u6216\u8005\u4e00\u6b21\u53cd\u5411\u7f13\u52a8\u6240\u9700\u65f6\u95f4. \u7b2c\u56db\u4e2a\u53c2\u6570 start
: \u662f\u5426\u7acb\u5373\u5f00\u59cb\u8fd9\u4e2a Tween
, \u5426\u5219\u6211\u4eec\u5f97\u9700\u8981\u624b\u52a8\u8c03\u7528 Start
\u65b9\u6cd5 \u5728\u521b\u5efa\u5b8c\u6211\u4eec\u7684 tw
\u5b9e\u4f8b\u540e, \u6211\u4eec\u5148\u5236\u70b9\u5c0f\u76ee\u6807:
\u5728\u7f13\u52a8\u5f00\u59cb\u65f6\u8f93\u51fa \"Tween start!\" \u5728\u7f13\u52a8\u8fc7\u7a0b\u65f6\u8f93\u51fa \"Tweening... Eased: <\u6b64\u65f6\u7684\u7f13\u52a8\u503c>, Percent: <\u7f13\u52a8\u5df2\u8fdb\u884c\u7684\u65f6\u95f4\u5360\u6bd4>\" \u5728\u7f13\u52a8\u7ed3\u675f\u540e\u8f93\u51fa \"Tween complete!\" \u5bf9\u4e8e\u5f00\u59cb\u548c\u7ed3\u675f\u5f88\u7b80\u5355, \u6211\u4eec\u53ea\u9700\u8981\u8d4b\u503c\u4e00\u4e9b\u5b57\u6bb5:
\u8d4b\u503c Tween \u7684\u4e00\u4e9b\u5b57\u6bb5tw.OnStart = t => Logger.Log(LogLevel.Info, \"test\", \"Tween start!\");\ntw.OnComplete = t => Logger.Log(LogLevel.Info, \"test\", \"Tween complete!\");\n
\u5728\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528 lambda \u8868\u8fbe\u5f0f\u4e3a\u5176\u8d4b\u503c, \u5176\u4e2d\u8be5 lambda \u88ab\u4f20\u5165\u7684\u53c2\u6570\u5c31\u662f\u8fd9\u4e2a Tween
\u5b9e\u4f8b, \u8fd9\u53ef\u4ee5\u5e2e\u52a9\u6211\u4eec\u907f\u514d lambda \u6355\u83b7\u4ee5\u53ca\u590d\u7528\u6211\u4eec\u7684 Tween
\u5904\u7406\u51fd\u6570.
\u5bf9\u4e8e\u7f13\u52a8\u8fc7\u7a0b, \u6211\u4eec\u9996\u5148\u4ecb\u7ecd\u4e24\u4e2a\u5c5e\u6027:
Eased
: \u8868\u793a\u8be5\u7f13\u52a8\u5f53\u524d\u7684 \"\u7f13\u52a8\u503c\" Percent
: \u8868\u793a\u8be5\u7f13\u52a8\u5df2\u8fdb\u884c\u65f6\u95f4\u5360\u6bd4, \u5373 \u5df2\u8fdb\u884c\u65f6\u95f4/\u603b\u65f6\u95f4 \u4e00\u4e2a\u66f4\u6e05\u695a\u7684\u4f8b\u5b50\u662f\u89c2\u5bdf easings.net \u7684\u56fe\u50cf, Eased
\u5373\u7eb5\u5750\u6807\u503c, Percent
\u5373\u6a2a\u5750\u6807\u503c.
\u90a3\u4e48\u8fd9\u91cc\u5c31\u5f88\u7b80\u5355\u5b9e\u73b0\u4e86:
tw.OnUpdate = t => Logger.Log(LogLevel.Info, \"test\", $\"Tweening... Eased: {t.Eased}, Percent: {t.Percent}\");\n
\u6700\u540e\u8bb0\u5f97 Start
\u5b83\u5e76\u4e14\u8bb0\u5f97\u628a\u5b83\u6302\u8f7d\u5230\u5b9e\u4f53\u4e0a, \u56e0\u4e3a\u5b83\u7684\u66f4\u65b0\u662f\u4f9d\u8d56\u5b9e\u4f53\u7684:
\u5f00\u59cb\u5e76\u6302\u8f7d// \u5982\u679c\u4f60\u5bf9 `start` \u53c2\u6570\u4f20\u5165 `true` \u90a3\u4e48\u4f60\u53ef\u4ee5\u4e0d\u7528\u505a\u8fd9\u4e00\u6b65\ntw.Start();\n// \u8fd9\u91cc\u5047\u8bbe\u6211\u4eec\u7684\u6240\u6709\u4ee3\u7801\u90fd\u8fdb\u884c\u5728\u4e00\u4e2a\u5b9e\u4f53\u5185\u90e8\nthis.Add(tw);\n
\u6216\u8005, \u6211\u4eec\u4f7f\u7528 Tween.Set
\u65b9\u6cd5, \u5b83\u662f\u4e00\u4e2a\u5de5\u5177\u65b9\u6cd5\u5141\u8bb8\u6211\u4eec\u7b80\u5316\u5bf9 Tween \u7684\u4f7f\u7528, \u4e0a\u9762\u7684\u4f8b\u5b50\u7528\u8fd9\u4e2a\u65b9\u6cd5\u53ef\u4ee5\u5199\u6210\u8fd9\u6837:
Tween tw = Tween.Set(this, Tween.TweenMode.Oneshot, 1f, Ease.BackIn,\n t => Logger.Log(LogLevel.Info, \"test\", $\"Tweening... Eased: {t.Eased}, Percent: {t.Percent}\"),\n t => Logger.Log(LogLevel.Info, \"test\", \"Tween complete!\"));\n// OnStart \u8fd8\u5f97\u624b\u52a8\u8bbe\u7f6e\u5450\ntw.OnStart = t => Logger.Log(LogLevel.Info, \"test\", \"Tween start!\");\ntw.Start();\n
\u5b83\u4f1a\u81ea\u52a8\u5e2e\u6211\u4eec\u6302\u8f7d\u5230\u5b9e\u4f53\u4e0a, \u4e0d\u8fc7\u4f9d\u7136\u9700\u8981\u6211\u4eec\u624b\u52a8 Start
, \u8fd9\u91cc\u65b9\u4fbf\u4e4b\u5904\u5c31\u5728\u4e8e\u4f60\u53ef\u4ee5\u76f4\u63a5\u628a\u4e00\u4e2a\u7b80\u5355\u7684\u51fd\u6570\u76f4\u63a5\u5728\u53c2\u6570\u4e2d\u4f20\u5165, \u800c\u4e0d\u662f Create
\u540e\u518d\u8bbe\u7f6e\u5b57\u6bb5. \u4e0d\u8fc7\u8fd9\u91cc\u53c2\u6570\u5217\u8868\u4e2d\u5e76\u6ca1\u6709 Start
\u76f8\u5173\u7684\u53c2\u6570, \u5982\u679c\u4f60\u8fd8\u9700\u8981\u8bbe\u7f6e Start
\u7684\u56de\u8c03\u7684\u8bdd\u4f60\u53ef\u4ee5\u56de\u9000\u5230\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\u7684\u65b9\u6cd5, \u5c31\u50cf\u4e0a\u9762\u7684\u4ee3\u7801\u4e00\u6837\u624b\u52a8\u8bbe\u7f6e OnStart
.
"},{"location":"trans/common1/#alarm","title":"Alarm","text":"\u987e\u540d\u601d\u4e49, \u5b83\u5c31\u662f\u4e2a'\u95f9\u949f', \u5b83\u5141\u8bb8\u4f60\u8bbe\u5b9a\u4e00\u4e2a\u65f6\u95f4\u5e76\u5728\u65f6\u95f4\u7ed3\u675f\u540e\u505a\u4e00\u4e9b\u4e8b\u60c5, \u5176\u4f7f\u7528\u8d77\u6765\u5f88\u7b80\u5355:
Alarm alarm = Alarm.Create(Alarm.AlarmMode.Oneshot, OnAlarm, 2f, false);\nAdd(alarm);\nalarm.Start();\n\nstatic void OnAlarm()\n{\n Logger.Log(LogLevel.Info, \"Test\", \"123\");\n}\n
\u7b2c\u4e00\u4e2a\u53c2\u6570 AlarmMode
\u4e0e Tween.TweenMode
\u7684\u57fa\u672c\u4e00\u81f4, \u8fd9\u91cc\u5c31\u4e0d\u8d58\u8ff0\u4e86 \u7b2c\u4e8c\u4e2a\u53c2\u6570\u8868\u793a\u65f6\u95f4\u5230\u540e\u7684\u56de\u8c03\u51fd\u6570 \u7b2c\u4e09\u4e2a\u53c2\u6570\u8868\u793a\u65f6\u95f4\u6709\u591a\u957f \u7b2c\u56db\u4e2a\u53c2\u6570\u4e5f\u4e0e tween \u7c7b\u4f3c, \u8868\u793a\u662f\u5426\u5e0c\u671b\u81ea\u52a8\u8c03\u7528 Start
\u65b9\u6cd5 \u9664\u4e86\u5728\u7b2c\u4e09\u4e2a\u53c2\u6570\u5904\u8bbe\u7f6e\u65f6\u95f4\u957f\u5ea6\u5916, Start
\u65b9\u6cd5\u4e5f\u5141\u8bb8\u6211\u4eec\u4f20\u5165\u4e00\u4e2a\u65f6\u95f4\u957f\u5ea6, \u8fd9\u4f1a\u5728\u4f60\u9700\u8981\u4e00\u4e2a\u4e0d\u5b9a\u957f\u7684\u95f9\u949f\u7684\u65f6\u5019\u5f88\u6709\u7528. \u9664\u6b64\u4e4b\u5916, Alarm
\u4e5f\u6709\u7c7b\u4f3c\u4e8e Tween.Set
\u7684\u65b9\u6cd5\u76f4\u63a5\u4f5c\u7528\u4e0e Entity
\u4e0a, \u53c2\u6570\u4e5f\u4e0e\u5176\u6784\u9020\u51fd\u6570\u76f8\u540c:
// \u4e0d\u8fc7\u8fd9\u91cc AlarmMode \u53cd\u800c\u88ab matt \u653e\u5230\u6700\u540e\u53bb\u4e86\nAlarm.Set(this, 2f, OnAlarm, Alarm.AlarmMode.Oneshot).Start();\n
"},{"location":"trans/common1/#coroutine","title":"Coroutine","text":"Coroutine
\u5e38\u89c1\u7684\u4e2d\u6587\u7ffb\u8bd1\u53eb\u505a '\u534f\u7a0b', \u5b83\u662f\u4e00\u4e2a\u975e\u5e38\u5f3a\u5927\u7684\u4e1c\u897f, async/await \u5f02\u6b65\u5141\u8bb8\u6211\u4eec\u50cf\u5199\u540c\u6b65\u4ee3\u7801\u4e00\u6837\u5199\u5f02\u6b65\u4ee3\u7801, \u5927\u6982\u7c7b\u4f3c\u5730, \u534f\u7a0b\u5c31\u5141\u8bb8\u6211\u4eec\u50cf\u5199\u4e00\u4e2a\u5728\u540c\u4e00\u5e27\u5185\u5141\u8bb8\u7684\u4ee3\u7801\u4e00\u6837\u5199\u5728\u4e0d\u540c\u5e27\u5185\u8fd0\u884c\u7684\u4ee3\u7801. \u597d\u5427\u4e0a\u9762\u8fd9\u53e5\u8bdd\u6709\u70b9\u4e71, \u4e0d\u8fc7\u6211\u4eec\u770b\u4e00\u4e0b\u4f8b\u5b50\u5c31\u4f1a\u7406\u89e3\u4e86:
var coroutine = new Coroutine(MakeRoutine());\nAdd(coroutine);\n\nstatic IEnumerator MakeRoutine()\n{\n Logger.Log(LogLevel.Info, \"tag\", \"\u5f00\u59cb!\");\n yield return 1f;\n Logger.Log(LogLevel.Info, \"tag\", \"\u8fc7\u4e861s!\");\n yield return 2f;\n Logger.Log(LogLevel.Info, \"tag\", \"\u53c8\u8fc7\u4e862s!\");\n yield break;\n}\n
Info
\u4e0a\u8ff0\u4ee3\u7801\u4e2d\u7684 yield return
\u7b49\u8bed\u6cd5\u5c5e\u4e8e \"\u8fed\u4ee3\u5668\u51fd\u6570\", \u5982\u679c\u4f60\u4e0d\u4e86\u89e3\u5b83\u7684\u8bdd\u4f60\u53ef\u4ee5\u5230 msdn \u4e0a\u6216\u8005 bing \u641c\u7d22 \u4e0a\u67e5\u627e\u5b83.
\u4e0a\u8ff0\u4ee3\u7801\u4f1a\u7acb\u523b\u6253\u5370\u4e00\u53e5 \"\u5f00\u59cb!\" \u7136\u540e\u7b49\u5f851s, \u7136\u540e\u6253\u5370 \"\u8fc7\u4e861s!\", \u518d\u8fc7\u4e862s\u540e\u518d\u6b21\u6253\u5370\"\u53c8\u8fc7\u4e862s!\". \u4e5f\u5c31\u662f\u8bf4\u4f60\u6bcf yield return
\u4e00\u4e2a\u6d6e\u70b9\u6570, \u6e38\u620f\u4f1a\u7b49\u5f85\u8be5\u79d2\u6570, \u7136\u540e\u7ee7\u7eed\u6267\u884c\u4e0b\u9762\u7684\u4ee3\u7801. \u4f60\u53ef\u80fd\u89c9\u5f97\u8fd9\u4e0d\u5c31\u662f\u4e2a\u9ad8\u7ea7\u70b9\u7684 Alarm
\u5417, \u786e\u5b9e, \u4f60\u4ecd\u7136\u53ef\u4ee5\u7528 Alarm
\u6765\u91cd\u5199\u8fd9\u90e8\u5206\u529f\u80fd, \u4e0d\u8fc7\u5f88\u5feb\u4f60\u5c31\u4f1a\u9677\u5165\u56de\u8c03\u5730\u72f1\u5e76\u4e14\u4ee3\u7801\u4e5f\u53d8\u7684\u5341\u5206\u96be\u8bfb:
Logger.Log(LogLevel.Info, \"tag\", \"\u5f00\u59cb!\");\nAlarm.Set(this, 1f, () =>\n{\n Logger.Log(LogLevel.Info, \"tag\", \"\u8fc7\u4e861s!\");\n Alarm.Set(this, 2f, () =>\n {\n Logger.Log(LogLevel.Info, \"tag\", \"\u53c8\u8fc7\u4e862s!\");\n\n }, Alarm.AlarmMode.Oneshot);\n\n}, Alarm.AlarmMode.Oneshot);\n
\u9664\u4e86\u8fd4\u56de\u4e00\u4e9b\u6d6e\u70b9\u6570, \u6211\u4eec\u8fd8\u53ef\u4ee5\u8fd4\u56de\u4e00\u4e2a null
, \u8fd9\u6837\u4f1a\u8ba9\u6e38\u620f\u4ec5\u7b49\u5f85\u4e00\u5e27, \u4e5f\u5c31\u662f\u5728\u8fd9\u6b21\u8fd4\u56de\u540e, \u6e38\u620f\u5728\u4e0b\u4e00\u5e27\u7acb\u523b\u7ee7\u7eed\u6267\u884c\u800c\u4e0d\u662f\u7b49\u5f85\u79d2\u6570. \u6bd4\u5982\u5728\u5b98\u56fe\u4e2d FallingBlock
\u5bf9\u5176\u7684\u4e00\u4e2a\u5e94\u7528(\u5df2\u7b80\u5316, \u5220\u9664\u4e86 BadelineBoss \u76f8\u5173\u7684\u4ee3\u7801): Celeste.FallingBlock.Sequence()
// \u6301\u7eed\u68c0\u6d4b\u662f\u5426\u73a9\u5bb6\u5728\u4e0a\u9762\u6293/\u7ad9\u7740\nwhile (!PlayerFallCheck())\n yield return null;\n// \u73a9\u5bb6\u6293/\u7ad9\u7740, \u8fdb\u5165\u6389\u843d\u72b6\u6001\nHasStartedFalling = true;\nwhile (true)\n{\n // \u5728\u771f\u6b63\u8fdb\u884c\u5411\u4e0b\u79fb\u52a8\u65f6\u5148\u7b49\u5f85 0.2s \n yield return 0.2f;\n\n // \u7136\u540e\u7b49\u5f85 0.4s, \u4f46\u662f\u73a9\u5bb6\u79bb\u5f00\u6389\u843d\u5757\u540e\u4f1a\u53d6\u6d88\u8fd9\u4e2a\u7b49\u5f85\n float waitTimer = 0.4f;\n while (waitTimer > 0f && PlayerWaitCheck())\n {\n yield return null;\n waitTimer -= Engine.DeltaTime;\n }\n\n // ......, \u6267\u884c\u6301\u7eed\u6389\u843d\u7684\u903b\u8f91, \u76f4\u5230\u78b0\u5230\u4e86\u5e73\u53f0(\u6cdb\u6307\u6240\u6709\u4e0a\u9762\u80fd\u7ad9\u7684\u4e1c\u897f, \u975e\u6307\u6728\u5e73\u53f0, \u4e0b\u540c)\u7136\u540e\u505c\u4e0b\n\n // \u6bcf\u9694 0.1s \u68c0\u6d4b\u662f\u5426\u5e95\u4e0b\u4f9d\u7136\u8fd8\u5b58\u5728\u5e73\u53f0, \u5426\u5219\u8fdb\u5165\u4e0b\u4e00\u6b21 while \u5faa\u73af\n while (CollideCheck<Platform>(Position + new Vector2(0f, 1f)))\n yield return 0.1f;\n}\n......\n
\u73b0\u5728\u56de\u5fc6\u4e00\u4e0b\u5b98\u56fe\u7684\u6389\u843d\u5757\u7684\u903b\u8f91, \u662f\u4e0d\u662f\u548c\u4e0a\u9762\u4ee3\u7801\u63cf\u8ff0\u7684\u4e00\u81f4? \u5982\u679c\u6ca1\u6709\u4e86\u534f\u7a0b, \u6211\u4eec\u5c31\u5f97\u7528\u4e00\u4e2a\u72b6\u6001\u53d8\u91cf\u6765\u50a8\u5b58\u6389\u843d\u5757\u8fdb\u884c\u5230\u54ea\u4e00\u6b65, \u5e76\u4e14\u65f6\u65f6\u523b\u523b\u7ef4\u62a4\u8fd9\u4e2a\u53d8\u91cf, \u65e5\u76ca\u53d8\u7684\u8d8a\u6765\u8d8a\u9ebb\u70e6. \u534f\u7a0b\u8fd8\u80fd\u8fd4\u56de\u53e6\u4e00\u4e2a\u534f\u7a0b, \u53ea\u9700\u8981\u8fd4\u56de\u4e00\u4e2a IEnumerator
:
var coroutine = new Coroutine(MakeRoutine());\nAdd(coroutine);\n\nstatic IEnumerator MakeRoutine()\n{\n Logger.Log(LogLevel.Info, \"tag\", \"\u5f00\u59cb!\");\n yield return 1f;\n Logger.Log(LogLevel.Info, \"tag\", \"\u8fc7\u4e861s!\");\n yield return MakeRoutineInner();\n Logger.Log(LogLevel.Info, \"tag\", \"\u5185\u90e8\u7684\u534f\u7a0b\u7ed3\u675f\u4e86!\");\n yield return MakeRoutineInner();\n Logger.Log(LogLevel.Info, \"tag\", \"\u5185\u90e8\u7684\u534f\u7a0b\u53c8\u4e00\u6b21\u7ed3\u675f\u4e86!\");\n yield break;\n}\n\nstatic IEnumerator MakeRoutineInner()\n{\n yield return 1f;\n Logger.Log(LogLevel.Info, \"tag\", \"\u5185\u90e8\u7b49\u4e861s!\");\n yield return 1f;\n Logger.Log(LogLevel.Info, \"tag\", \"\u5185\u90e8\u53c8\u7b49\u4e861s!\");\n yield break;\n}\n
\u5b83\u7684\u8f93\u51fa\u4f1a\u50cf\u662f: (09/30/2023 13:39:28) [Everest] [Info] [tag] \u5f00\u59cb!\n(09/30/2023 13:39:29) [Everest] [Info] [tag] \u8fc7\u4e861s!\n(09/30/2023 13:39:30) [Everest] [Info] [tag] \u5185\u90e8\u7b49\u4e861s!\n(09/30/2023 13:39:31) [Everest] [Info] [tag] \u5185\u90e8\u53c8\u7b49\u4e861s!\n(09/30/2023 13:39:31) [Everest] [Info] [tag] \u5185\u90e8\u7684\u534f\u7a0b\u7ed3\u675f\u4e86!\n(09/30/2023 13:39:32) [Everest] [Info] [tag] \u5185\u90e8\u7b49\u4e861s!\n(09/30/2023 13:39:33) [Everest] [Info] [tag] \u5185\u90e8\u53c8\u7b49\u4e861s!\n(09/30/2023 13:39:33) [Everest] [Info] [tag] \u5185\u90e8\u7684\u534f\u7a0b\u53c8\u4e00\u6b21\u7ed3\u675f\u4e86!\n
\u4f7f\u7528\u534f\u7a0b, \u6211\u4eec\u53ef\u4ee5\u5f88\u8f7b\u677e\u7684\u5c31\u50cf\u81ea\u7136\u63cf\u8ff0\u4e00\u4e2a\u8fc7\u7a0b\u4e00\u6837 \"\u81ea\u7136\" \u5730\u5199\u5b9e\u73b0\u7684\u4ee3\u7801, \u5b98\u56fe\u4e2d\u5267\u60c5\u7684\u5b9e\u73b0\u5c31\u662f\u4e00\u4e2a\u5f88\u597d\u7684\u4f8b\u5b50(\u6b64\u5904\u4e3a\u5e8f\u7ae0\u9e1f\u6559\u51b2\u523a\u7684\u5267\u60c5, \u5df2\u5927\u91cf\u7b80\u5316): Celeste.CS00_Ending
private IEnumerator Cutscene(Level level)\n{\n // \u6162\u6162\u51cf\u6162\u6e38\u620f\u901f\u5ea6\u76f4\u5230 0.0x, \u5e76\u4e14\u5728\u51cf\u6162\u5230 0.5x \u65f6\u505c\u6b62\u6865\u5d29\u584c\u97f3\u4e50\n while (Engine.TimeRate > 0f)\n {\n yield return null;\n if (Engine.TimeRate < 0.5f && bridge != null)\n bridge.StopCollapseLoop();\n level.StopShake();\n Engine.TimeRate -= Engine.RawDeltaTime * 2f;\n }\n // \u6b64\u65f6\u6e38\u620f\u901f\u5ea6\u4f1a\u88ab\u8bef\u51cf\u5230\u8d1f\u6570, \u8bbe\u7f6e\u56de 0 \u9632\u6b62\u6e38\u620f\u884c\u4e3a\u5f02\u5e38\n Engine.TimeRate = 0f;\n // \u5207\u6362\u73a9\u5bb6\u72b6\u6001\u5230 StDummy, \u5373\u7981\u6b62\u6240\u6709\u8f93\u5165\u548c\u4ea4\u4e92\n player.StateMachine.State = Player.StDummy;\n // \u9501\u5b9a\u73a9\u5bb6\u671d\u5411\u4e3a\u53f3\n player.Facing = Facings.Right;\n // \u65e0\u89c6\u6e38\u620f\u901f\u5ea6\u5730\u7b49\u5f85 1s, \u9ed8\u8ba4\u8fd4\u56de\u6d6e\u70b9\u6570\u7684\u7b49\u5f85\u4f1a\u53d7\u6e38\u620f\u901f\u5ea6\u5f71\u54cd,\n // \u8fd9\u91cc\u5982\u679c\u7528\u8fd4\u56de\u6d6e\u70b9\u6570\u7684\u7b49\u5f85\u4f1a\u9020\u6210\u534f\u7a0b\u505c\u6b62, \u56e0\u4e3a\u6e38\u620f\u901f\u5ea6\u4e3a 0x, \u5373\u7b49\u5f85\u6c38\u8fdc\u4e0d\u4f1a\u7ed3\u675f\n yield return WaitFor(1f);\n // \u64ad\u653e\u9e1f\u98de\u5165\u7684\u58f0\u97f3\n Audio.Play(\"event:/game/general/bird_in\", bird.Position);\n // \u8bbe\u7f6e\u9e1f\u7684\u671d\u5411\u548c\u52a8\u753b\n bird.Facing = Facings.Left;\n bird.Sprite.Play(\"fall\", false, false);\n // \u7f13\u52a8\u9e1f\u7684\u4f4d\u7f6e, \u5e76\u5728\u9e1f\u98de\u5230\u4e00\u534a\u65f6\u64ad\u653e\u98de\u884c\u7684\u52a8\u753b\n float percent = 0f;\n Vector2 from = bird.Position;\n Vector2 to = bird.StartPosition;\n while (percent < 1f)\n {\n bird.Position = from + (to - from) * Ease.QuadOut(percent);\n if (percent > 0.5f)\n bird.Sprite.Play(\"fly\", false, false);\n percent += Engine.RawDeltaTime * 0.5f;\n yield return null;\n }\n bird.Position = to;\n from = default(Vector2);\n to = default(Vector2);\n // \u64ad\u653e\u9e1f\u78b0\u5730\u7684\u97f3\u6548\n Audio.Play(\"event:/game/general/bird_land_dirt\", bird.Position);\n // \u5411\u5de6\u91ca\u653e\u5c18\u57c3\u7c92\u5b50\u6548\u679c\n Dust.Burst(bird.Position, - MathHelper.PI / 2, 12);\n // \u64ad\u653e\u95f2\u7f6e\u52a8\u753b, \u7136\u540e\u7b49\u5f85 0.5s \u540e\u518d\u6b21\u64ad\u653e\u5544\u5730\u7684\u52a8\u753b\n bird.Sprite.Play(\"idle\", false, false);\n yield return WaitFor(0.5f);\n bird.Sprite.Play(\"peck\", false, false);\n // \u7b49\u5f85 1.1s, \u4e5f\u5c31\u662f\u5dee\u4e0d\u591a\u5544\u5730\u52a8\u753b\u7684\u957f\u5ea6\n yield return WaitFor(1.1f);\n // \u64ad\u653e\u51b2\u523a\u6559\u5b66\n yield return bird.ShowTutorial(new BirdTutorialGui(\n bird, new Vector2(0f, -16f), Dialog.Clean(\"tutorial_dash\", null), \n new Vector2(1f, -1f), \"+\", BirdTutorialGui.ButtonPrompt.Dash\n ), caw: true);\n\n // \u6301\u7eed\u7b49\u5f85, \u76f4\u5230\u73a9\u5bb6\u6309\u4e0b\u4e86\u53f3\u4e0a\u51b2\n for (;;)\n {\n Vector2 aimVector = Input.GetAimVector(Facings.Right);\n if (aimVector.X > 0f && aimVector.Y < 0f && Input.Dash.Pressed)\n break;\n yield return null;\n }\n // \u8bbe\u7f6e\u73a9\u5bb6\u7684\u72b6\u6001\u4e3a \"\u9e1f\u51b2\u523a\u6559\u7a0b\" \u72b6\u6001, \u8fd9\u4e2a\u72b6\u6001\u5373\u51b2\u523a\u5f00\u59cb\u5230\u4e0a\u5cb8\u5e76\u5f3a\u5236\u79fb\u52a8\u5230\u53f3\u4fa7\u7684\u72b6\u6001\n player.StateMachine.State = Player.StBirdDashTutorial;\n player.Dashes = 0;\n level.Session.Inventory.Dashes = 1;\n // \u6062\u590d\u6e38\u620f\u901f\u7387\n Engine.TimeRate = 1f;\n // \u6536\u56de\u9e1f\u7684\u6559\u7a0b\u6846\u6846\n bird.Add(new Coroutine(bird.HideTutorial()));\n // \u7b49\u5f85 0.25s\n yield return 0.25f;\n // \u64ad\u653e\u9e1f\u88ab\u73a9\u5bb6\u5413\u8d70\u98de\u8d70\u7684\u52a8\u753b (\u6b64\u65f6\u5927\u7ea6\u662f\u73a9\u5bb6\u51b2\u523a\u7ed3\u675f\u7684\u65f6\u95f4)\n bird.Add(new Coroutine(bird.StartleAndFlyAway()));\n // \u7b49\u5f85\u76f4\u5230\u73a9\u5bb6\u843d\u5730, \u6216\u8005\u76f4\u5230\u73a9\u5bb6\u5bc4\u4e86\n while (!player.Dead && !player.OnGround(1))\n yield return null;\n // \u7b49\u5f85 2s\n yield return 2f;\n // \u64ad\u653e title_ping \u97f3\u6548, \u5982\u679c\u4f60\u60f3\u4e0d\u8d77\u6765\u7684\u8bdd\u4f60\u53ef\u4ee5\u53bb\u4ed4\u7ec6\u542c\u542c\n // \u5728\u851a\u84dd\u6e90 fmod \u5de5\u7a0b\u6587\u4ef6\u91cc\u5b83\u7684\u97f3\u9891\u6587\u4ef6\u4f4d\u4e8e music/kuraine/mus_lvl0_titleping_oneshot.ogg\n Audio.SetMusic(\"event:/music/lvl0/title_ping\");\n // \u7ee7\u7eed\u7b49\u5f85 2s\n yield return 2f;\n // \u5411\u573a\u666f\u4e2d\u52a0\u5165\u663e\u793a \"\u4f60\u80fd\u505a\u5230\u3002\" \u8fd9\u53e5\u8bdd\u7684\u5b9e\u4f53\n endingText = new PrologueEndingText(false);\n Scene.Add(endingText);\n\n // \u83b7\u53d6\u5173\u5361\u4e2d\u63a7\u5236\u524d\u666f\u96ea\u548c\u80cc\u666f\u96ea\u7684\u5b9e\u4f53\n Snow bgSnow = level.Background.Get<Snow>();\n Snow fgSnow = level.Foreground.Get<Snow>();\n // \u987a\u4fbf\u52a0\u5165\u9ad8\u5206\u8fa8\u7387\u7684\u96ea, \u4e5f\u5373 ui \u5c42\u4e0a\u7684\u96ea (HiresSnow = High resolution snow)\n level.Add(level.HiresSnow = new HiresSnow(0.45f));\n // \u4f46\u662f\u5148\u628a\u900f\u660e\u5ea6\u8c03\u6210 0, \u7528\u6765\u7b49\u4f1a\u6e10\u53d8\n level.HiresSnow.Alpha = 0f;\n\n // \u5f00\u59cb\u6e10\u53d8\u4e09\u5c42\u96ea\u7684\u900f\u660e\u5ea6\n float ease = 0f;\n while (ease < 1f)\n {\n ease += Engine.DeltaTime * 0.25f;\n float eased = Ease.CubeInOut(ease);\n if (fgSnow != null)\n fgSnow.Alpha -= Engine.DeltaTime * 0.5f;\n if (bgSnow != null)\n bgSnow.Alpha -= Engine.DeltaTime * 0.5f;\n level.HiresSnow.Alpha = Calc.Approach(level.HiresSnow.Alpha, 1f, Engine.DeltaTime * 0.5f);\n // \u4e8e\u6b64\u540c\u65f6 \"\u4f60\u80fd\u505a\u5230\u3002\" \u8fd9\u53e5\u8bdd\u4e5f\u6162\u6162\u964d\u4e0b\u6765\n endingText.Position = new Vector2(960f, 540f - 1080f * (1f - eased));\n // \u6444\u50cf\u673a\u4e5f\u6162\u6162\u5411\u4e0a\u79fb\u52a8\n level.Camera.Y = level.Bounds.Top - 3900f * eased;\n yield return null;\n }\n // \u7ed3\u675f\u8fd9\u4e2a\u5267\u60c5\n EndCutscene(level);\n yield break;\n}\n
"},{"location":"trans/ec_common/","title":"\u66f4\u591a EC","text":"\u90a3\u4e48\u7ecf\u8fc7\u524d\u9762\u7684\u9605\u8bfb, \u76f8\u4fe1\u4f60\u5df2\u7ecf\u4e86\u89e3\u5230\u4e86\u4e00\u4e9b\u5f88\u5f88\u5f88\u57fa\u672c\u7684\u77e5\u8bc6, \u90a3\u4e48\u4ece\u8fd9\u4e00\u7ae0\u5f00\u59cb\u5c31\u662f\u4e00\u4e9b\u96f6\u788e\u4e14\u6742\u4e71\u7684\u4e1c\u897f\u4e86. \u987a\u4fbf\u6240\u4ee5, \u6211\u8fd8\u662f\u5f88\u5efa\u8bae\u4f60\u53bb\u591a\u9605\u8bfb\u4e00\u4e0b\u539f\u7248\u7684\u4ee3\u7801\u4ee5\u53ca\u4e00\u4e9b\u5e38\u89c1\u7b80\u5355Helper\u7684\u6e90\u7801, \u6bd5\u7adf\u6211\u81ea\u5df1\u90fd\u4e0d\u77e5\u9053\u6211\u9700\u8981\u5728\u8fd9\u91cc\u8bf4\u4e9b\u4ec0\u4e48(
_(:\u0437\u300d\u2220)_
_(:\u0437\u300d\u2220)_ \u6446\u70c2\u4e86\u8fd9\u8282\u53ef\u80fd\u4f1a\u5f88\u4e0d\u660e\u6240\u4ee5(
"},{"location":"trans/ec_common/#_1","title":"\u751f\u547d\u5468\u671f","text":"\u5728\u524d\u9762\u6211\u4eec\u5df2\u7ecf\u4e86\u89e3\u5230\u4e86 Update
\u51fd\u6570\u548c Render
\u51fd\u6570, Update
\u4e0e Render
\u6bcf\u5e27\u90fd\u4f1a\u88ab\u8c03\u7528, \u5bf9\u4e8e\u903b\u8f91\u7684\u66f4\u65b0\u6211\u4eec\u5e94\u5728 Update
\u4e2d\u505a, \u800c\u6709\u5173\u7ed8\u5236\u7684\u4efb\u52a1\u6211\u4eec\u5e94\u8be5\u5728 Render
\u4e2d\u505a, \u8fd9\u662f\u56e0\u4e3a\u5373\u4f7f\u4f60\u5728 Update
\u4e2d\u8fdb\u884c\u4e86\u7ed8\u5236\u7684\u8c03\u7528, \u5728 Render
\u5f00\u59cb\u4e4b\u524d\u4e5f\u4f1a\u88ab\u851a\u84dd\u6e05\u7a7a. \u7c7b\u4f3c\u5730, \u6e38\u620f\u4e2d\u7684\u6682\u505c\u7684\u5b9e\u73b0\u539f\u7406\u662f\u505c\u6b62\u6bcf\u5e27 Update
\u7684\u8c03\u7528\u800c\u4fdd\u7559 Render
\u7684\u8c03\u7528, \u90a3\u4e48\u81ea\u7136\u5982\u679c\u4f60\u5728 Render
\u91cc\u8fdb\u884c\u903b\u8f91\u66f4\u65b0\u4f60\u4f1a\u7834\u574f\u6389\u6e38\u620f\u539f\u6709\u7684\u6682\u505c.
ok\u90a3\u4e48\u6211\u4eec balabala \u8bf4\u4e86\u4e00\u5927\u5806, \u63a5\u4e0b\u6765\u4ecb\u7ecd\u51e0\u4e2a\u4f1a\u88ab\u851a\u84dd\u8c03\u7528\u7684\u51fd\u6570, \u8fd9\u4e9b\u51fd\u6570\u4e5f\u53eb\u505a\u751f\u547d\u5468\u671f
\u51fd\u6570.
"},{"location":"trans/ec_common/#entity","title":"\u5bf9\u4e8e Entity","text":" Update
Render
DebugRender
: \u8be5\u51fd\u6570\u4f1a\u5728\u851a\u84dd\u8c03\u8bd5\u63a7\u5236\u53f0\u88ab\u6253\u5f00\u65f6\u88ab\u6bcf\u5e27\u88ab\u8c03\u7528\u4f5c\u4e3a debug \u6e32\u67d3, \u5373 everest \u9ed8\u8ba4 ~ \u952e\u6253\u5f00\u7684\u90a3\u4e2a, \u5b83\u7684\u9ed8\u8ba4\u884c\u4e3a\u662f\u7ed8\u5236\u8be5\u5b9e\u4f53\u7684\u78b0\u649e\u7bb1, \u5728\u8fd9\u91cc\u4f60\u53ef\u4ee5\u505a\u4e00\u4e9b\u8c03\u8bd5\u7528\u7684\u6807\u8bc6\u7684\u7ed8\u5236, \u5c31\u6bd4\u5982\u8bf4\u4f60\u7684\u5b9e\u4f53\u7684\u4f5c\u7528\u8303\u56f4\u4ec0\u4e48\u7684. Added
: \u5f53\u8be5\u5b9e\u4f53\u88ab\u4ee5 Scene.Add
\u51fd\u6570\u8c03\u7528\u52a0\u5165\u5230\u573a\u666f\u4e0a\u65f6\u8c03\u7528, \u5728\u8fd9\u91cc\u4f60\u53ef\u4ee5\u8bfb\u53d6\u573a\u666f\u7684\u4e00\u4e9b\u72b6\u6001\u6216\u8005 flag \u4e4b\u7c7b\u7684\u5e76\u66f4\u6539\u5b83\u7684\u884c\u4e3a. Awake
: \u8be5\u51fd\u6570\u4e0e Added
\u884c\u4e3a\u76f8\u540c, \u4f46\u662f\u5f53\u4e00\u5e27\u4e4b\u5185\u6709\u591a\u4e2a\u5b9e\u4f53\u88ab\u52a0\u5165\u573a\u666f\u65f6\u5b83\u4eec\u7684 Awake
\u4f1a\u5728\u8fd9\u4e9b\u5b9e\u4f53\u90fd\u88ab\u52a0\u5165\u540e\u518d\u6279\u91cf\u8c03\u7528, \u800c Added
\u5219\u662f\u52a0\u5165\u4e00\u4e2a\u5c31\u8c03\u7528\u4e00\u4e2a. \u4e00\u4e2a\u5f88\u597d\u7684\u5728\u5b98\u56fe\u4e2d\u8fd0\u7528\u7684\u4f8b\u5b50\u662f\u6d6e\u52a8\u5757\u7684\u8fde\u63a5, \u8fd9\u662f\u5728\u573a\u666f\u5f00\u59cb\u65f6\u505a\u7684, \u4e3a\u4e86\u9632\u6b62\u9057\u6f0f\u67d0\u4e9b\u6d6e\u52a8\u5757\u95f4\u7684\u8fde\u63a5\u5c31\u9700\u8981\u5728\u5b9e\u4f53\u90fd\u88ab\u52a0\u5165\u540e\u518d\u8c03\u7528. Removed
: \u5f53\u8be5\u5b9e\u4f53\u88ab\u4ee5 Scene.Remove
\u51fd\u6570\u8c03\u7528\u79fb\u9664\u573a\u666f\u65f6\u8c03\u7528, \u4f60\u53ef\u4ee5\u5728\u8fd9\u91cc\u53d6\u6d88\u4e00\u4e9b\u5b9e\u4f53\u5bf9\u573a\u666f\u7684\u4e00\u4e9b\u4f5c\u7528, \u6bd4\u5982\u8bf4\u80cc\u666f\u7684\u53d8\u5316. SceneBegin
: \u5f53\u573a\u666f\u88ab\u8c03\u7528 Scene.Begin
\u7684\u540c\u65f6\u8c03\u7528 SceneEnd
: \u5f53\u573a\u666f\u88ab\u8c03\u7528 Scene.End
\u7684\u540c\u65f6\u8c03\u7528 "},{"location":"trans/ec_common/#component","title":"\u5bf9\u4e8e Component","text":"\u5bf9\u4e8e Component \u6765\u8bf4\u5927\u90e8\u5206\u51fd\u6570\u4e0e Entity \u7684\u7c7b\u4f3c, \u53ea\u4e0d\u8fc7\u540d\u5b57\u524d\u52a0\u4e2a\u4e86 Entity. \u6bd4\u5982\u5b9e\u4f53\u7684 Awake
\u5bf9\u5e94 Component \u7684 EntityAwake
, \u901a\u5e38\u8fd9\u4e9b\u51fd\u6570\u88ab\u8c03\u7528\u7684\u5730\u65b9\u662f\u5bf9\u5e94\u7684 Entity \u7684\u751f\u547d\u5468\u671f\u51fd\u6570\u7684\u9ed8\u8ba4\u5b9e\u73b0, \u6240\u4ee5\u9664\u975e\u6709\u610f\u800c\u4e3a\u4e4b\u8bb0\u5f97\u5728\u5f00\u5934\u8c03\u7528\u57fa\u7c7b\u7684\u751f\u547d\u5468\u671f\u5b9e\u73b0: MyInterestingEntity.cs
public override void Awake()\n{\n // ensure `Awake`s of its components has been called\n base.Awake();\n // do other thing...\n}\n
"},{"location":"trans/ec_common/#scene","title":"\u5bf9\u4e8e Scene","text":"\u55ef... \u5bf9\u5e94 Scene \u7684\u4e00\u4e9b\u751f\u547d\u5468\u671f\u51fd\u6570\u6211\u4e2a\u4eba\u4e5f\u4e0d\u662f\u5f88\u4e86\u89e3\u6bd5\u7adf\u6211\u4eec\u5927\u90e8\u5206\u7684\u65f6\u95f4\u90fd\u5728 gameplay \u7684\u573a\u666f\u4e0a, \u6240\u4ee5\u8fd9\u8282\u5c31\u6682\u65f6\u5495\u4e86(\u3002_\u3002)
"},{"location":"trans/ec_common/#_2","title":"\u5e38\u89c1\u7684\u65b9\u6cd5\u4e0e\u5c5e\u6027","text":" Scene.Add
: \u5c06\u4e00\u4e2a\u5b9e\u4f53\u52a0\u5165\u5230\u573a\u666f\u4e2d Entity.Add
: \u5c06\u4e00\u4e2a Component \u6302\u8f7d\u5230\u5b9e\u4f53\u4e0a Scene.Remove
: \u5c06\u4e00\u4e2a\u5b9e\u4f53\u79fb\u51fa\u573a\u666f Entity.Remove
: \u5c06\u4e00\u4e2a Component \u79fb\u51fa\u5b9e\u4f53 Entity.RemoveSelf
: \u5c06 Entity \u81ea\u8eab\u79fb\u51fa\u81ea\u8eab\u6240\u5728\u573a\u666f Component.RemoveSelf
: \u5c06 Component \u81ea\u8eab\u79fb\u51fa\u6240\u5728\u5b9e\u4f53 Scene.Entities
: \u83b7\u53d6\u5f53\u524d\u573a\u666f\u4e0a\u7684\u5b9e\u4f53\u5217\u8868 Entity.Components
: \u83b7\u53d6\u5f53\u524d\u5b9e\u4f53\u7684 Component \u5217\u8868 "},{"location":"trans/ec_common/#entity_1","title":"Entity","text":"Entity
\u672c\u8eab\u6709\u56db\u4e2a\u516c\u5f00\u7684\u5b57\u6bb5:
Active
, \u8be5 bool
\u5b57\u6bb5\u8868\u793a\u8be5 Entity
\u662f\u5426 \"\u5b58\u6d3b\", \u5426\u5219\u4e3a \"\u5931\u6d3b\", \"\u5931\u6d3b\" \u7684 Entity
\u5c06\u4e0d\u4f1a\u88ab\u8c03\u7528 Update
\u65b9\u6cd5\u76f4\u5230 Active
\u4e3a true
Collidable
, \u8be5 bool
\u5b57\u6bb5\u8868\u793a\u8be5 Entity
\u662f\u5426 \"\u53ef\u78b0\u649e\", \u4e0d\u53ef\u78b0\u649e\u7684\u5b9e\u4f53\u4e0e\u4efb\u4f55\u5b9e\u4f53\u8fdb\u884c\u78b0\u649e\u68c0\u6d4b\u65f6\u90fd\u4f1a\u8fd4\u56de false
, \u6240\u4ee5\u4f60\u53ef\u4ee5\u4f7f\u7528\u8be5\u81ea\u52a8\u7981\u7528\u5b83\u7684\u78b0\u649e\u7bb1 Visible
, \u8be5 bool
\u5b57\u6bb5\u8868\u793a\u8be5 Entity
\u662f\u5426 \"\u53ef\u89c1\", \u4e0d\u53ef\u89c1\u7684\u5b9e\u4f53\u4e0d\u4f1a\u88ab\u8c03\u7528 Render
\u65b9\u6cd5, \u6ce8\u610f\u5373\u4f7f\u4e0d\u53ef\u89c1\u5b83\u7684\u78b0\u649e\u7bb1\u4f9d\u7136\u5b58\u5728. Position
, \u8be5 Vector2
\u5b57\u6bb5\u8868\u793a\u8be5 Entity
\u7684\u4f4d\u7f6e, \u6ce8\u610f\u8fd9\u4e2a\u4f4d\u7f6e\u76f8\u5bf9\u7684\u5750\u6807\u7cfb\u662f\u4e0d\u540c\u7684, \u5bf9\u4e8e HUD \u5b9e\u4f53\u6765\u8bf4\u5b83\u7684\u5750\u6807\u7cfb\u662f\u4e00\u4e2a 1922 x 1092 \u7684\u539f\u70b9\u5de6\u4e0a\u89d2\u7684\u5c4f\u5e55\u5750\u6807, \u5bf9\u4e8e gameplay \u5b9e\u4f53\u6765\u8bf4\u5b83\u662f\u76f8\u5bf9\u4e8e\u4e16\u754c\u539f\u70b9\u7684\u5206\u5ea6\u503c\u4e3a 1px \u7684\u5750\u6807. \u8fd9\u4e2a\u884c\u4e3a\u53ef\u4ee5\u901a\u8fc7\u540e\u9762\u6240\u8bf4\u7684 Tag
\u6765\u914d\u7f6e. "},{"location":"trans/ec_common/#tag","title":"Tag","text":":thinking: \u9664\u6b64\u4e4b\u5916\u5462\u8fd8\u6709\u4e00\u4e2a\u5c0f\u4e1c\u897f\u53eb Tag
, \u8bed\u4e49\u4e0a\u6765\u8bf4\u5b83\u8868\u793a\u8fd9\u4e2a\u5b9e\u4f53\u7684\u4e00\u4e9b\u6807\u7b7e\u5c5e\u6027, \u4f60\u53ef\u4ee5\u901a\u8fc7 Entity.Tag
\u5c5e\u6027\u6765\u8bbf\u95ee\u5b83, \u5b83\u662f\u4e00\u4e2a 32 \u4f4d\u6574\u6570, \u5b83\u7684\u6bcf\u4e00\u4f4d\u8868\u793a\u4e00\u4e2a\u8be5\u5b9e\u4f53\u7684\"\u5c5e\u6027\", \u6211\u4eec\u901a\u5e38\u4f1a\u4f7f\u7528 AddTag
\u4ee5\u53ca RemoveTag
\u6765\u64cd\u4f5c\u5b83. \u8981\u83b7\u53d6\u573a\u666f\u4e2d\u6240\u6709\u62e5\u6709\u67d0\u4e00 Tag
\u7684\u5b9e\u4f53, \u6211\u4eec\u9700\u8981\u8bbf\u95ee Scene
\u7684 TagLists
\u800c\u4e0d\u662f Tracker
, \u7136\u540e\u4f7f\u7528\u5b83\u7684\u7d22\u5f15\u5668(\u5f62\u5982 tagList[yourtag]
\u7684\u8fd0\u7b97\u7b26)\u6765\u68c0\u7d22, \u6216\u8005\u4f60\u4e5f\u53ef\u4ee5\u4f7f\u7528\u7b80\u4fbf\u7684\u65b9\u6cd5---\u76f4\u63a5\u8bbf\u95ee Scene
\u7684\u7d22\u5f15\u5668. \u4e00\u822c\u7684\u8bdd, \u6211\u5bf9\u4e8e Tag
\u7684\u5e94\u7528\u5f88\u5c11, \u6700\u8fd1\u4e00\u6b21\u662f\u5c06\u4e00\u4e2a Entity
\u6807\u8bb0\u4e3a ui \u5c42, \u5b83\u7684\u4ee3\u7801\u770b\u8d77\u6765\u662f\u8fd9\u6837\u7684:
this.AddTag(Tags.HUD);\n
\u5f53\u4f60\u7684\u5b9e\u4f53\u62e5\u6709\u8fd9\u4e2a Tag \u540e, \u851a\u84dd\u4f1a\u5c06\u4f60\u7684\u5b9e\u4f53\u7ed8\u5236\u5728 ui \u5c42, \u6bd4\u8f83\u5e38\u89c1\u7684\u4f8b\u5b50\u5c31\u662f\u5de6\u4e0a\u89d2\u7684\u8ba1\u65f6\u5668, \u5b83\u5728\u6784\u9020\u5668\u5185\u5c31\u7ed9\u81ea\u5df1\u6253\u4e0a\u4e86 Tags.HUD
\u7684\u6807\u7b7e. \u4e5f\u5982\u4e0a\u9762\u6240\u8bf4\u7684, \u4e00\u4e9b\u851a\u84dd\u5e38\u89c1\u7684\u6240\u6709 Tag \u4f60\u90fd\u53ef\u4ee5\u5728 Celeste.Tags
\u7c7b\u5185\u627e\u5230. \u4ee5\u4e0b\u662f\u4e00\u4e9b\u53ef\u80fd\u5730\u5e38\u89c1\u7684 Tag:
PauseUpdate
: \u662f\u5426\u5728\u6682\u505c\u671f\u95f4\u4f9d\u7136\u88ab\u8c03\u7528 Update
, \u901a\u5e38\u7528\u4e8e ui \u5c42\u7684\u5b9e\u4f53\u4e0a FrozenUpdate
: \u662f\u5426\u5728 Frozen
\u72b6\u6001\u4e0b\u4f9d\u7136\u88ab\u8c03\u7528 Update
(\u6bd4\u5982\u8349\u8393\u7c7d\u52a8\u753b\u8fc7\u7a0b, 1a\u84dd\u5fc3\u89e3\u5bc6\u6210\u529f\u8fc7\u7a0b, \u6ce8\u610f\u6b64\u72b6\u6001\u4e0e\u51bb\u7ed3\u5e27\u65e0\u5173) TransitionUpdate
: \u662f\u5426\u5728\u5173\u5361\u5207\u677f\u65f6\u4f9d\u7136\u88ab\u8c03\u7528 Update
, \u901a\u5e38\u7528\u4e8e\u5728\u5207\u677f\u65f6\u66f4\u65b0\u4e00\u4e9b\u89c6\u89c9\u4e0a\u7684\u4e1c\u897f(\u6bd4\u5982\u7535\u7f51\u7684 \"\u653e\u7535\" \u52a8\u753b\u4e0d\u4f1a\u5728\u5207\u677f\u65f6\u9759\u6b62) HUD
: \u5373\u662f\u5426\u662f ui \u5c42, \u6b64\u9879\u5c31\u4f1a\u66f4\u6539 Entity
\u7684 Position
\u7684\u76f8\u5bf9\u5750\u6807\u7cfb Global
: \u8be5 Entity \u662f\u5426\u662f\u5168\u5c40\u7684, \u4e00\u4e2a\u975e\u5168\u5c40\u5b9e\u4f53\u5728\u5173\u5361\u91cd\u8bd5\u540e\u4f1a\u6d88\u5931, \u5168\u5c40 Tag \u53ef\u4ee5\u907f\u514d\u8fd9\u4ef6\u4e8b, \u901a\u5e38\u5168\u5c40 Tag \u6700\u5e38\u89c1\u7684\u7528\u6cd5\u662f\u548c HUD \u7ed3\u5408\u5728\u4e00\u8d77, \u8fd9\u6837\u4f60\u5c31\u62e5\u6709\u4e86\u4e00\u4e2a\u5728\u6e38\u620f\u5185\u6301\u4e45\u7684 ui \u90e8\u4ef6\u4e86. "},{"location":"trans/il/","title":"IL","text":"Info
\u5982\u679c\u4f60\u5728\u4e4b\u524d\u5df2\u7ecf\u5b66\u4e60\u8fc7 IL
\u5e76\u4e14\u4f7f\u7528\u8fc7\u7c7b\u4f3c\u7684 System.Reflection.Emit
\u8fd9\u4e9b api \u7684\u8bdd\u4f60\u53ef\u4ee5\u8df3\u8fc7\u8fd9\u4e00\u8282.
"},{"location":"trans/il/#_1","title":"\u7b80\u4ecb","text":"IL
\u5168\u79f0 Intermediate Language
, \u5373\u4e2d\u95f4\u8bed\u8a00, \u5728\u4e00\u4e9b\u8f83\u8001\u7684\u6587\u6863\u91cc\u9762\u5b83\u53ef\u80fd\u4e5f\u4f1a\u88ab\u53eb\u505a MSIL
, \u5373 Microsoft Intermediate Language
, \u5076\u5c14\u8fd8\u4f1a\u6709\u4e00\u4e9b\u5730\u65b9\u53eb\u505a CIL
, \u5373 Common Intermediate Language
, \u8fd9\u4e09\u79cd\u53eb\u6cd5\u901a\u5e38\u610f\u4e49\u4e0a\u90fd\u662f\u6307\u4e00\u4e2a\u4e1c\u897f. \u5728\u524d\u9762\u6211\u4eec\u5c31\u5df2\u7ecf\u63d0\u5230\u8fc7 IL
\u4e86(\u9605\u8bfb\u4ee3\u78012), \u4f46\u662f\u5e76\u6ca1\u6709\u6df1\u5165\u7684\u8bb2\u89e3\u5b83\u5230\u5e95\u662f\u4ec0\u4e48\u6837\u7684. IL
\u901a\u5e38\u6765\u8bf4\u53ef\u4ee5\u7406\u89e3\u6210\u4e24\u4e2a\u90e8\u5206, \u4e00\u4e2a \"\u6267\u884c\" \u90e8\u5206, \u4e00\u4e2a \"\u58f0\u660e\" \u90e8\u5206, \"\u6267\u884c\" \u90e8\u5206\u89c4\u5b9a\u4e86\u4e00\u4e2a\u51fd\u6570\u5185\u90e8\u7684\u4ee3\u7801\u5e94\u8be5\u600e\u4e48\u64cd\u63a7\u6211\u4eec\u7684\u7a0b\u5e8f, \u800c \"\u58f0\u660e\" \u90e8\u5206\u5219\u89c4\u5b9a\u4e86\u4e00\u4e2a\u51fd\u6570\u7684\u8fd4\u56de\u503c, \u53c2\u6570\u5217\u8868, \u8bbf\u95ee\u4fee\u9970\u7b26, \u6240\u5728\u7c7b, \u7c7b\u7684\u8bbf\u95ee\u4fee\u9970\u7b26, \u540d\u79f0\u7b49\u8fd9\u4e9b\u5143\u6570\u636e, \u83b7\u53d6\u8fd9\u4e9b\u5143\u6570\u636e\u5176\u5b9e\u4f60\u65e9\u5728\u5b66\u4e60\u53cd\u5c04\u7684\u65f6\u5019\u5c31\u8fdb\u884c\u8fc7. \u540c\u65f6\u4fee\u6539\u6216\u751f\u6210\u8fd9\u4e9b\u5143\u6570\u636e\u4e5f\u4e0d\u56f0\u96be, \u4f46\u662f\u5728\u8fdb\u884c\u851a\u84dd modding \u65f6\u4fee\u6539\u6216\u751f\u6210\u8fd9\u4e9b\u5143\u6570\u636e\u7684\u64cd\u4f5c\u51e0\u4e4e\u4e0d\u4f1a\u88ab\u4f7f\u7528\u5230, \u6240\u4ee5\u8fd9\u4e00\u8282\u6211\u4eec\u805a\u7126\u4e8e IL
\u7684 \"\u6267\u884c\" \u90e8\u5206, \u8bb2\u8ff0\u5176\u57fa\u672c\u7ed3\u6784, \u57fa\u7840\u8bed\u6cd5\u7b49\u5185\u5bb9.
"},{"location":"trans/il/#_2","title":"\u521d\u5370\u8c61","text":"HelloWorld!
namespace DynamicAssemblyTest;\n\npublic static class Program\n{\n public static void Main()\n {\n Console.WriteLine(\"Hello world!\");\n }\n}\n
\u73b0\u5728, \u8bd5\u7740\u7f16\u8bd1\u4e0a\u8ff0\u5f88\u7b80\u5355\u7684 HelloWorld \u7a0b\u5e8f, \u627e\u5230\u5176\u7a0b\u5e8f\u96c6, \u7136\u540e\u7528 dnSpy
(\u6216\u8005 ILSpy
\u4e5f\u884c) \u6253\u5f00\u5b83. \u4e0d\u8fc7\u8fd9\u6b21\u6211\u4eec\u4e0d\u662f\u5728\u770b C#
\u4ee3\u7801\u4e86, \u6211\u4eec\u9700\u8981\u770b IL
\u4ee3\u7801, \u6240\u4ee5\u6211\u4eec\u5728\u5982\u4e0b\u56fe\u7684\u8fd9\u4e2a\u4e0b\u62c9\u6846\u4e2d\u9009\u62e9 IL
:
\u5728\u56fe\u4e2d\u7684\u90a3\u4e00\u5768\u4f60\u53ef\u80fd\u4e0d\u77e5\u6240\u63aa\u7684\u4ee3\u7801\u5c31\u662f IL
\u4ee3\u7801\u4e86, \u5728\u4e0a\u8ff0 IL
\u4ee3\u7801\u4e2d .method
.class
\u8fd9\u4e00\u7c7b\u5b57\u6837\u5c31\u8868\u793a\u58f0\u660e\u4e00\u4e2a \u65b9\u6cd5/\u7c7b, \u800c\u5176\u540e\u9762\u6240\u8ddf\u7684\u4e00\u5927\u957f\u4e32\u5173\u952e\u5b57\u5c31\u662f\u4e00\u4e9b\u5143\u6570\u636e, \u6bd4\u5982\u7c7b\u540d, \u8bbf\u95ee\u4fee\u9970\u7b26\u7b49\u6211\u4eec\u4e4b\u524d\u8c08\u8bba\u8fc7\u7684\u4e1c\u897f, \u540e\u9762\u7684\u5927\u62ec\u53f7\u5c31\u8868\u793a\u8fd9\u4e2a\u58f0\u660e\u7684 \"\u5185\u5bb9\u7269\", \u901a\u5e38\u7c7b\u7684 \"\u5185\u5bb9\u7269\" \u6709\u5185\u90e8\u7c7b, \u65b9\u6cd5, \u6784\u9020\u5668, \u5b57\u6bb5, \u5c5e\u6027\u7b49, \u90a3\u4e48\u663e\u800c\u6613\u89c1\u8fd9\u91cc\u5c31\u6beb\u65e0\u7591\u95ee\u5c31\u662f IL
\u7684\u58f0\u660e\u90e8\u5206\u4e86. \u73b0\u5728\u6211\u4eec\u5173\u6ce8 .method
\u58f0\u660e, \u5176\u7684 \"\u5185\u5bb9\u7269\" \u5c31\u662f\u6211\u4eec\u63a5\u4e0b\u6765\u8981\u805a\u7126\u7684, \u5373 IL
\u7684 \"\u6267\u884c\" \u90e8\u5206. \u5728\u4e0a\u56fe\u4e2d dnSpy \u5e2e\u6211\u4eec\u5c06\u524d\u9762\u52a0\u4e0a\u4e86\u5b57\u8282\u5185\u5b58\u504f\u79fb\u7684\u90a3\u6bcf\u4e00\u884c\u5c31\u662f\u6211\u4eec\u7684 IL
\u4ee3\u7801\u4e86, \u4e0d\u8fc7\u8fd9\u91cc\u6211\u4eec\u4e0d\u592a\u4f1a\u9700\u8981\u8fd9\u4e2a\u504f\u79fb\u91cf, \u56e0\u4e3a\u5927\u591a\u6570\u6d89\u53ca\u64cd\u4f5c IL
\u7684\u5e93\u90fd\u4f1a\u4e3a\u6211\u4eec\u81ea\u52a8\u5b8c\u6210\u8fd9\u4e2a\u504f\u79fb\u7684\u8ba1\u7b97.
"},{"location":"trans/il/#_3","title":"\u5207\u6362\u73af\u5883 & \u52a8\u6001\u7a0b\u5e8f\u96c6","text":"\u73b0\u5728\u6211\u4eec\u9700\u8981\u4e00\u4e2a\u73af\u5883\u6765\u4e66\u5199\u6211\u4eec\u7684 IL
\u4ee3\u7801, \u5f53\u7136\u4f60\u867d\u7136\u5b8c\u5168\u53ef\u4ee5\u5c31\u5728 dnSpy \u5bf9\u7740\u90a3\u4e00\u5927\u5806 C#
\u7f16\u8bd1\u540e\u7684 IL
\u8fdb\u884c\u4fee\u6539, \u5e76\u9891\u7e41\u4fdd\u5b58\u4fee\u6539\u7136\u540e\u8fd0\u884c\u6765\u67e5\u770b\u6548\u679c, \u4f46\u662f\u8fd9\u603b\u5f52\u6ca1\u6709\u6211\u4eec\u76f4\u63a5\u5728 C#
\u4ee3\u7801\u91cc\u5199 IL
\u4ee3\u7801\u91cc\u65b9\u4fbf!
\u9996\u5148, \u6211\u4eec\u73b0\u5728\u53ef\u4ee5\u4e0d\u518d\u5728 mod \u5de5\u7a0b\u91cc\u5de5\u4f5c\u4e86, \u8fd9\u90e8\u5206\u5185\u5bb9\u662f\u72ec\u7acb\u5f00\u6765\u7684, \u6240\u4ee5\u6211\u4f1a\u63a8\u8350\u4f60\u65b0\u5efa\u4e00\u4e2a\u9879\u76ee\u6765\u505a\u8fd9\u4e9b. \u8fd9\u91cc\u6211\u7ed9\u9879\u76ee\u53d6\u7684\u540d\u662f DynamicAssemblyTest
, \u76ee\u6807\u6846\u67b6\u662f .net 8
. \u5b8c\u6210\u540e, \u590d\u5236\u7c98\u8d34\u4ee5\u4e0b\u4ee3\u7801(\u4e4b\u540e\u6211\u4eec\u4f1a\u6162\u6162\u89e3\u91ca\u7684):
using System.Reflection;\nusing System.Reflection.Emit;\n\nnamespace DynamicAssemblyTest;\n\npublic static class Program\n{\n public static MethodInfo GenerateMethod(Action<ILGenerator> generateAction)\n {\n AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new(\"MyAssembly\"), AssemblyBuilderAccess.RunAndCollect);\n ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule(\"MyTestModule\");\n TypeBuilder typeBuilder = moduleBuilder.DefineType(\"MyType\");\n MethodBuilder methodBuilder = typeBuilder.DefineMethod(\"MyMethod\", MethodAttributes.Public | MethodAttributes.Static);\n generateAction(methodBuilder.GetILGenerator());\n return typeBuilder.CreateType().GetMethod(\"MyMethod\")!;\n }\n\n public static void Main()\n {\n MethodInfo methodInfo = GenerateMethod(il =>\n {\n il.Emit(OpCodes.Ldstr, \"Hello Dynamic Method!\");\n il.Emit(OpCodes.Call, typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!);\n il.Emit(OpCodes.Ret);\n });\n Action action = methodInfo.CreateDelegate<Action>();\n action();\n }\n}\n
Note
\u6211\u9ed8\u8ba4\u542f\u7528\u4e86\u9690\u5f0f\u547d\u540d\u7a7a\u95f4, \u5982\u679c\u4f60\u9047\u5230\u4e86\u7c7b\u578b\u672a\u627e\u5230\u7684\u62a5\u9519\u90a3\u4f60\u5c31\u5f97\u624b\u52a8 using \u4e00\u4e0b\u5269\u4f59\u7684\u90a3\u4e9b\u547d\u540d\u7a7a\u95f4\u4e86.
\u73b0\u5728\u8fd0\u884c\u4f60\u7684\u7a0b\u5e8f, \u4f60\u5e94\u8be5\u4f1a\u5f97\u5230\u4e00\u53e5\u8f93\u51fa: Hello Dynamic Method!
. \u4e0a\u8ff0\u4ee3\u7801\u5176\u5b9e\u662f\u5728\u5728\u4ee3\u7801\u4e2d\u52a8\u6001\u5b9a\u4e49\u4e86\u4e00\u4e2a\u7a0b\u5e8f\u96c6, \u7136\u540e\u52a8\u6001\u5b9a\u4e49\u4e86\u4e00\u4e2a\u7c7b, \u5e76\u5411\u91cc\u9762\u52a8\u6001\u5b9a\u4e49\u4e86\u4e00\u4e2a MyMethod
\u65b9\u6cd5, \u4e4b\u540e\u6211\u4eec\u52a8\u6001\u5730 \"\u7f16\u8bd1\" \u4e86\u8fd9\u4e2a\u7a0b\u5e8f\u96c6\u5e76\u5c06\u5176\u88c5\u8f7d\u5230\u6211\u4eec\u7684\u7a0b\u5e8f\u96c6\u57df\u4e2d, \u5176\u4e2d, MyMethod
\u65b9\u6cd5\u7684 IL
\u7684\u5185\u5bb9\u5c31\u662f\u5728\u6211\u4eec\u7684 Main
\u65b9\u6cd5\u4e2d GenerateMethod
\u53c2\u6570\u4e2d\u7684\u59d4\u6258\u5b9a\u4e49\u7684. \u5f80\u7b80\u5355\u6765\u8bf4\u5c31\u662f\u6211\u4eec\u5728\u4ee3\u7801\u4e2d\u53cd\u5c04\u521b\u5efa\u4e86\u4e00\u6bb5\u65b0\u7684\u4ee3\u7801\u5e76\u6267\u884c, \u8fd9\u542c\u8d77\u6765\u662f\u4e0d\u662f\u9177\u6781\u4e86? \u4e0a\u9762\u8fd9\u4e2a\u52a8\u6001\u5b9a\u4e49\u7a0b\u5e8f\u96c6\u7684\u5e93\u53eb\u505a System.Reflection.Emit
, \u5728\u8fd9\u91cc\u6211\u4eec\u53ea\u662f\u4e3a\u4e86\u5b66\u4e60\u4e00\u70b9 IL
\u77e5\u8bc6\u800c\u4f7f\u7528, \u5230\u540e\u9762\u4fee\u6539\u851a\u84dd\u7684\u7a0b\u5e8f\u96c6\u65f6\u6211\u4eec\u9700\u8981\u4f7f\u7528 Everest \u5e26\u7684 Mono.Cecil
\u5e93, \u4e0d\u8fc7\u4ed6\u4eec\u5927\u540c\u5c0f\u5f02.
"},{"location":"trans/il/#il_1","title":"\u57fa\u672c IL
","text":"IL_0000: nop\nIL_0001: ldstr \"Hello world!\"\nIL_0006: call void [System.Console]System.Console::WriteLine(string)\nIL_000B: nop\nIL_000C: ret\n
\u901a\u5e38\u6765\u8bf4, \u4e00\u6bb5 IL
\u5305\u542b\u591a\u884c IL
, \u6bcf\u4e00\u884c IL
(\u6211\u5076\u5c14\u4e5f\u4f1a\u79f0\u4e3a\u4e00\u53e5 IL
) \u90fd\u5305\u542b\u4e00\u4e2a\u64cd\u4f5c\u7801(OpCode)\u4ee5\u53ca\u53ef\u4ee5\u6ca1\u6709\u7684\u53c2\u6570. \u6bd4\u5982\u4e0a\u8ff0\u6bb5 IL
, \u5176\u5305\u542b\u4e94\u884c IL
:
\u7b2c\u4e00\u884c IL
\u7684\u64cd\u4f5c\u7801\u662f nop
, \u6ca1\u6709\u53c2\u6570 \u7b2c\u4e8c\u884c IL
\u7684\u64cd\u4f5c\u7801\u662f ldstr
, \u53c2\u6570\u662f\u4e00\u4e32\u5b57\u7b26\u4e32, \u6216\u8005\u4e25\u8c28\u7684\u8bf4, \u662f\u4e00\u4e2a\u5b57\u7b26\u4e32\u7684 token
, \u5b83\u5f15\u7528\u4e86\u7a0b\u5e8f\u96c6\u5143\u6570\u636e\u4e2d\u5b58\u653e\u5b57\u7b26\u4e32\u672c\u4f53\u7684\u4f4d\u7f6e, \u4e0d\u8fc7\u6211\u4eec\u53ef\u4ee5\u5ffd\u7565\u8fd9\u4e2a\u7ec6\u8282, \u56e0\u4e3a\u6211\u4eec\u4e0d\u4f1a\u6d89\u53ca\u5230 IL
\u7684\u5177\u4f53\u5b57\u8282\u5c42\u9762\u7684\u4e1c\u897f. \u7b2c\u4e09\u884c IL
\u7684\u64cd\u4f5c\u7801\u662f call
, \u53c2\u6570\u662f\u4e00\u4e2a\u65b9\u6cd5, \u5b83\u4e5f\u662f\u4e00\u4e2a token
, \u5176\u4e5f\u662f\u5f15\u7528\u4e86\u5143\u6570\u636e\u4e2d\u5b58\u653e\u65b9\u6cd5\u672c\u4f53\u7684\u4f4d\u7f6e \u7b2c\u56db\u884c IL
\u7684\u64cd\u4f5c\u7801\u662f nop
, \u6ca1\u6709\u53c2\u6570 \u7b2c\u4e94\u884c IL
\u7684\u64cd\u4f5c\u7801\u662f ret
, \u6ca1\u6709\u53c2\u6570 \u90a3\u4e48, \u5728\u77e5\u9053 IL
\u7684\u57fa\u672c\u7ed3\u6784\u540e, \u6211\u4eec\u5c31\u53ef\u4ee5\u5177\u4f53\u5b66\u4e60 IL
\u8fd9\u4e9b\u64cd\u4f5c\u7801\u5230\u5e95\u5e72\u4e86\u4ec0\u4e48\u4e86.
"},{"location":"trans/il/#_4","title":"\u8bc4\u4f30\u6808","text":"Note
\u5982\u679c\u4f60\u5728\u8fd9\u91cc\u4e0d\u77e5\u9053\u6808\u662f\u4ec0\u4e48\u7684\u8bdd, \u4f60\u5c31\u8be5\u53bb\u590d\u4e60\u4e00\u4e0b\u4f60\u4e4b\u524d\u5b66\u4e60\u7684\u6570\u636e\u7ed3\u6784\u4e4b\u6808\u4e86.
\u5728 IL
\u4ee3\u7801\u4e2d, \u5927\u91cf\u64cd\u4f5c\u7b26\u672c\u8d28\u4e0a\u90fd\u662f\u5728\u64cd\u4f5c\u4e00\u4e2a\u53eb\u505a \u8bc4\u4f30\u6808
\u7684\u4e1c\u897f, \u4ece\u5b57\u9762\u4e0a\u6211\u4eec\u5c31\u53ef\u4ee5\u77e5\u9053\u5b83\u662f\u4e00\u4e2a\u6808, \u90a3\u4e48\u65e2\u7136\u662f\u6808, \u90a3\u4e48\u901a\u5e38\u5c31\u6709 \u538b\u5165
\u548c \u5f39\u51fa
\u4e24\u79cd\u64cd\u4f5c, \u8bc4\u4f30\u6808
\u4e5f\u662f\u5982\u6b64. \u6bd4\u5982\u5982\u4e0b C#
\u65b9\u6cd5:
static int Add(int a, int b, int c) \n{\n return a + b + c;\n}\n
\u5b83\u5728\u7f16\u8bd1\u5668\u7684 Release
\u4f18\u5316\u4e0b\u4f1a\u7f16\u8bd1\u6210\u5982\u4e0b IL
:
Info
\u7f16\u8bd1\u5668\u7684 Debug
\u7f16\u8bd1\u4e0b\u4f1a\u4ea7\u751f\u5f88\u591a\u7528\u4e8e\u8c03\u8bd5\u4ee3\u7801\u7684 IL
, \u76f8\u5bf9\u6765\u8bf4\u4f1a\u590d\u6742\u5f88\u591a, \u6240\u4ee5\u6211\u4eec\u4f7f\u7528 Release
\u7f16\u8bd1\u6765\u5c3d\u53ef\u80fd\u7b80\u5316
.method private hidebysig static \n int32 Add (\n int32 a,\n int32 b,\n int32 c\n ) cil managed \n {\n .maxstack 8\n\n IL_0000: ldarg.0\n IL_0001: ldarg.1\n IL_0002: add\n IL_0003: ldarg.2\n IL_0004: add\n IL_0005: ret\n } // end of method Program::Add\n
\u8fd9\u91cc\u6211\u4eec\u628a\u4e00\u90e8\u5206\u58f0\u660e\u90e8\u5206\u653e\u51fa\u6765\u4e86, \u4e0d\u8fc7\u6211\u4eec\u53ea\u9700\u8981\u5173\u5fc3\u8fd9\u4e00\u884c: .maxstack 8
, \u5b83\u8868\u793a\u8bf7\u6c42\u5728\u8fd9\u4e2a\u65b9\u6cd5\u6267\u884c\u8fc7\u7a0b\u4e2d\u8bc4\u4f30\u6808\u6709\u786e\u4fdd 8 \u4e2a\u5927\u5c0f\u7684\u7a7a\u95f4\u53ef\u4ee5\u4f7f\u7528. \u7528\u56fe\u8868\u7684\u65b9\u6cd5\u5927\u6982\u662f(\u6700\u5de6\u4fa7\u6808\u9ad8\u5ea6\u6700\u4f4e, \u5411\u53f3\u6808\u9ad8\u5ea6\u9010\u6e10\u589e\u52a0, \u7ea2\u8272\u8868\u793a\u76ee\u524d\u4f7f\u7528\u4e86\u7684\u6808\u4f4d, \u4e4b\u540e\u7684\u56fe\u8868\u540c):
flowchart LR\n S1 --- S2 --- S3 --- S4 --- S5 --- S6 --- S7 --- S8\n style S1 stroke:red
\u9996\u5148\u6211\u4eec\u4f1a\u4ecb\u7ecd\u4e00\u4e2a\u7cfb\u5217\u7684\u64cd\u4f5c\u7b26 ldarg.*
, \u5b83\u8868\u793a\u5c06\u65b9\u6cd5\u53c2\u6570\u5217\u8868\u4e2d\u7684\u7b2c *-1 \u4e2a\u53c2\u6570\u538b\u5165\u8bc4\u4f30\u6808\u4e2d, \u4e0d\u5e26\u53c2\u6570(ldarg.0
\u4e0e ldarg.1
\u91cc\u7684\u6570\u5b57\u662f\u64cd\u4f5c\u7b26\u672c\u8eab, \u4e0d\u8981\u8ba4\u4e3a\u5b83\u662f\u4e00\u4e2a\u53c2\u6570\u4e86), \u6ce8\u610f\u8fd9\u662f\u5728\u9759\u6001\u65b9\u6cd5\u4e2d\u800c\u8a00\u7684, \u5982\u679c\u8be5\u65b9\u6cd5\u662f\u6210\u5458\u65b9\u6cd5, \u90a3\u4e48 ldarg.0
\u5b9e\u9645\u4e0a\u538b\u5165\u7684\u662f this
\u7684\u503c, \u800c ldarg.1
\u624d\u662f\u7b2c\u4e00\u4e2a\u53c2\u6570.
\u5728\u4e0a\u8ff0\u6bb5 IL
\u4e2d, \u8be5\u65b9\u6cd5\u662f\u4e2a\u9759\u6001\u65b9\u6cd5, \u6240\u4ee5\u524d\u4e24\u884c ldarg.0
\u4e0e ldarg.1
\u4f1a\u5c06\u7b2c\u4e00\u4e2a\u53c2\u6570\u548c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u538b\u5165\u8bc4\u4f30\u6808\u4e2d. \u73b0\u5728\u5047\u8bbe\u6211\u4eec\u8c03\u7528\u4f20\u5165\u7684\u53c2\u6570\u5206\u522b\u662f 1, 2, 3
(Sn\u8868\u793a\u672a\u4f7f\u7528\u7684\u6808\u4f4d, a:b \u8868\u793a\u8be5\u4f4d\u7f6e\u5b58\u5165\u4e86\u4e00\u4e2aa\u7c7b\u578b\u7684b\u503c, \u540e\u540c):
flowchart \n subgraph start\n direction LR\n S1_3[\"S1\"] --- S2_3[\"S2\"] --- S3_3[\"S3\"] --- S4_3[\"S4\"]\n end\n\n subgraph ldarg.0\n direction LR\n S1[\"int32: 1\"] --- S2 --- S3 --- S4\n style S1 stroke:red\n end\n\n subgraph ldarg.1\n direction LR\n S1_2[\"int32: 1\"] --- S2_2[\"int32: 2\"] --- S3_2[\"S3\"] --- S4_2[\"S4\"]\n style S1_2 stroke:red\n style S2_2 stroke:red\n end\n\n start --> ldarg.0 --> ldarg.1
\u7136\u540e\u8981\u4ecb\u7ecd\u7684\u662f add
\u64cd\u4f5c\u7b26, add
\u64cd\u4f5c\u7b26\u4f1a\u5f39\u51fa\u8bc4\u4f30\u6808\u4e0a\u7684\u4e24\u4e2a\u5143\u7d20, \u7136\u540e\u5c06\u5b83\u4eec\u76f8\u52a0, \u7136\u540e\u5c06\u7ed3\u679c\u538b\u5165\u8bc4\u4f30\u6808. \u5f53\u8fd9\u4e24\u4e2a\u5143\u7d20\u4efb\u610f\u4e00\u4e2a\u4e0d\u662f\u57fa\u672c\u6570\u5b57\u7c7b\u578b\u65f6 jit \u5c31\u4f1a\u629b\u51fa InvalidProgramException
\u5f02\u5e38. \u540c\u65f6\u6ce8\u610f\u4e00\u4e2a\u7ec6\u8282, \u4f60\u4e3a\u7c7b\u91cd\u8f7d\u7684\u52a0\u53f7\u8fd0\u7b97\u7b26\u5e76\u4e0d\u662f\u4f7f\u7528\u7684\u8fd9\u4e2a\u64cd\u4f5c\u7b26, \u800c\u662f\u8c03\u7528\u7684\u4e00\u4e2a\u7279\u6b8a\u7684\u540d\u4e3a op_Add
\u7684\u5e26\u6709 special name
\u6807\u8bb0\u7684\u65b9\u6cd5. \u6700\u540e\u662f ret
\u64cd\u4f5c\u7b26, \u5f53\u65b9\u6cd5\u6ca1\u6709\u8fd4\u56de\u503c\u65f6\u5b83\u4f1a\u5c06\u63a7\u5236\u6743\u4ea4\u56de\u7ed9\u8c03\u7528\u8005, \u540c\u65f6 jit \u4f1a\u4e3a\u6211\u4eec\u68c0\u67e5\u8bc4\u4f30\u6808\u662f\u5426\u6e05\u7a7a, \u5982\u679c\u8bc4\u4f30\u6808\u4e0a\u8fd8\u6709\u4e1c\u897f\u90a3\u4e48\u540c\u6837 jit \u4f1a\u629b\u51fa\u5f02\u5e38. \u5f53\u65b9\u6cd5\u62e5\u6709\u8fd4\u56de\u503c\u65f6\u5b83\u4f1a\u786e\u4fdd\u8bc4\u4f30\u6808\u4e0a\u6709\u4e14\u53ea\u5269\u4e00\u4e2a\u5143\u7d20, \u7136\u540e\u5c06\u8fd9\u4e2a\u503c\u5f39\u51fa\u5e76\u538b\u5165\u8c03\u7528\u8005\u7684\u8bc4\u4f30\u6808\u4e0a(\u8bc4\u4f30\u6808\u662f\u65b9\u6cd5\u72ec\u7acb\u5730). \u90a3\u4e48\u81ea\u7136\u800c\u7136, \u6211\u4eec\u6700\u521d\u7684\u90a3 6 \u53e5 IL
\u5927\u6982\u4f1a\u662f\u8fd9\u4e2a\u5de5\u4f5c\u6d41\u7a0b:
flowchart \n subgraph start\n direction LR\n S1 --- S2 --- S3 --- S4\n end\n\n subgraph ldarg.0\n direction LR\n S1_2[\"int32: 1\"] --- S2_2[\"S2\"] --- S3_2[\"S3\"] --- S4_2[\"S4\"]\n style S1_2 stroke:red\n end\n\n subgraph ldarg.1\n direction LR\n S1_3[\"int32: 1\"] --- S2_3[\"int32: 2\"] --- S3_3[\"S3\"] --- S4_3[\"S4\"]\n style S1_3 stroke:red\n style S2_3 stroke:red\n end\n\n subgraph add\n direction LR\n S1_4[\"int32: 3\"] --- S2_4[\"S2\"] --- S3_4[\"S3\"] --- S4_4[\"S4\"]\n style S1_4 stroke:red\n end\n\n subgraph ldarg.2\n direction LR\n S1_5[\"int32: 3\"] --- S2_5[\"int32: 3\"] --- S3_5[\"S3\"] --- S4_5[\"S4\"]\n style S1_5 stroke:red\n style S2_5 stroke:red\n end\n\n subgraph 2ndadd [\"2nd add\"]\n direction LR\n S1_6[\"int32: 6\"] --- S2_6[\"S2\"] --- S3_6[\"S3\"] --- S4_6[\"S4\"]\n style S1_6 stroke:red\n end\n\n start --> ldarg.0 --> ldarg.1 --> add --> ldarg.2 --> 2ndadd --> ret
\u8fd9\u56fe\u505a\u5b8c\u540e\u770b\u4e0a\u53bb\u597d\u50cf\u4e0d\u662f\u60f3\u8c61\u4e2d\u7684\u90a3\u4e48\u76f4\u89c2...
"},{"location":"trans/il/#il_2","title":"\u4e66\u5199 IL
","text":"\u73b0\u5728\u6211\u4eec\u5df2\u7ecf\u4e86\u89e3\u4e86\u4e00\u5c0f\u4e9b IL
\u7684\u77e5\u8bc6, \u73b0\u5728\u6211\u4eec\u56de\u5230\u4e4b\u524d\u7684\u5de5\u7a0b\u4e2d, \u66f4\u6539\u4e3a\u4ee5\u4e0b\u4ee3\u7801:
using System.Reflection;\nusing System.Reflection.Emit;\n\nnamespace DynamicAssemblyTest;\n\npublic static class Program\n{\n public static MethodInfo GenerateMethod(Action<ILGenerator> generateAction)\n {\n AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new(\"MyAssembly\"), AssemblyBuilderAccess.RunAndCollect);\n ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule(\"MyTestModule\");\n TypeBuilder typeBuilder = moduleBuilder.DefineType(\"MyType\");\n MethodBuilder methodBuilder = typeBuilder.DefineMethod(\"MyMethod\", MethodAttributes.Public | MethodAttributes.Static\n , typeof(int), new Type[] { typeof(int), typeof(int), typeof(int) });\n generateAction(methodBuilder.GetILGenerator());\n return typeBuilder.CreateType().GetMethod(\"MyMethod\")!;\n }\n\n public static void Main()\n {\n MethodInfo methodInfo = GenerateMethod(il =>\n {\n il.Emit(OpCodes.Ldarg_0);\n il.Emit(OpCodes.Ldarg_1);\n il.Emit(OpCodes.Add);\n il.Emit(OpCodes.Ldarg_2);\n il.Emit(OpCodes.Add);\n il.Emit(OpCodes.Ret);\n });\n var func = methodInfo.CreateDelegate<Func<int, int, int, int>>();\n var result = func(1, 2, 3);\n Console.WriteLine($\"result is {result}\");\n }\n}\n
\u8fd9\u91cc\u6211\u4eec\u5728\u4e0a\u9762\u66f4\u6539\u4e86\u65b9\u6cd5\u7684\u5b9a\u4e49, \u4f7f\u5b83\u53d8\u4e3a\u5e26\u6709 int
\u8fd4\u56de\u503c\u4e14\u63a5\u6536 3 \u4e2a\u53c2\u6570\u7684\u65b9\u6cd5, \u7136\u540e\u9002\u5f53\u4fee\u6539\u6211\u4eec\u8c03\u7528\u8fd9\u4e2a\u65b9\u6cd5\u7684\u5730\u65b9, \u7136\u540e\u8fd0\u7528\u6211\u4eec\u521a\u624d\u7684 IL
\u77e5\u8bc6\u5b9e\u73b0\u8fd9\u4e2a\u65b9\u6cd5. \u73b0\u5728, \u8fd0\u884c\u5b83, \u4f60\u5e94\u8be5\u4f1a\u5f97\u5230 result is 6
\u7684\u8f93\u51fa, \u4f46\u662f\u6211\u4eec\u5168\u7a0b\u90fd\u6ca1\u6709\u5728 C#
\u4ee3\u7801\u4e2d\u4f7f\u7528 +
\u8fd0\u7b97\u7b26, \u800c\u662f\u76f4\u63a5\u5728 IL
\u4e2d\u8c03\u7528 add
\u64cd\u4f5c\u7b26, \u4ece\u67d0\u4e9b\u65b9\u9762\u6765\u8bf4\u8fd9\u633a\u6709\u8da3\u7684.
\u73b0\u5728, \u8bd5\u7740\u5b8c\u6210\u4e00\u4e2a\u5c0f\u7ec3\u4e60, \u5c06\u4e0a\u9762 GenerateMethod
\u65b9\u6cd5\u91cc\u5bf9 MyMethod
\u7684\u5b9e\u73b0\u4ece a + b + c
\u66f4\u6539\u4e3a a + b * c
.
\u63d0\u793a\u7b54\u6848 \u4e58\u6cd5\u7684\u64cd\u4f5c\u7b26\u4e3a mul
, \u5176\u4f7f\u7528\u65b9\u6cd5\u4e0e add
\u4e00\u81f4.
\u65b9\u6cd5\u4e00\u65b9\u6cd5\u4e8c\u89e3\u91ca il.Emit(OpCodes.Ldarg_1);\nil.Emit(OpCodes.Ldarg_2);\nil.Emit(OpCodes.Mul);\nil.Emit(OpCodes.Ldarg_0);\nil.Emit(OpCodes.Add);\nil.Emit(OpCodes.Ret);\n
il.Emit(OpCodes.Ldarg_0);\nil.Emit(OpCodes.Ldarg_1);\nil.Emit(OpCodes.Ldarg_2);\nil.Emit(OpCodes.Mul);\nil.Emit(OpCodes.Add);\nil.Emit(OpCodes.Ret);\n
\u5728\u65b9\u6cd5\u4e00\u4e2d\u6211\u4eec\u7684\u601d\u8def\u5f88\u81ea\u7136, \u5148\u538b\u5165\u540e\u4e24\u4e2a\u53c2\u6570\u4f7f\u5176\u76f8\u4e58\u540e\u518d\u4e0e\u7b2c\u4e00\u4e2a\u53c2\u6570\u76f8\u52a0. \u4e5f\u5c31\u662f\u5b9e\u73b0\u7684\u662f (b * c) + a
. \u5728\u65b9\u6cd5\u4e8c\u4e2d\u5c31\u9700\u8981\u52a8\u70b9\u8111\u5b50, \u6211\u4eec\u4e00\u6b21\u6027\u5c06\u4e09\u4e2a\u53c2\u6570\u538b\u5165\u4e86\u6808\u4e2d, \u7136\u540e\u6267\u884c\u4e00\u4e2a mul
\u64cd\u4f5c, \u5b83\u4f1a\u628a\u6700\u540e\u538b\u5165\u7684\u4e24\u4e2a\u5143\u7d20\u5f39\u51fa\u76f8\u4e58\u540e\u538b\u5165, \u7136\u540e\u6211\u4eec\u9a6c\u4e0a\u518d\u6267\u884c\u4e00\u4e2a add
\u64cd\u4f5c, \u5c06\u521a\u521a\u88ab\u538b\u5165\u7684\u5143\u7d20\u4e0e\u6700\u5f00\u59cb\u88ab\u538b\u5165\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u76f8\u52a0, \u4e5f\u5c31\u662f\u5b9e\u73b0\u7684\u662f a + (b * c)
.
\u73b0\u5728\u4f60\u53ef\u4ee5\u8bd5\u7740\u73a9\u4e00\u4e9b\u6709\u8da3\u7684\u4e1c\u897f, \u6bd4\u5982\u8bd5\u7740\u7528 ldarg.3
\u538b\u5165\u4e00\u4e2a\u4e0d\u5b58\u5728\u7684\u7b2c\u56db\u4e2a\u53c2\u6570, \u6216\u8005\u5728 ret
\u65f6\u8bc4\u4f30\u6808\u4e0a\u6ca1\u6709\u5143\u7d20\u6216\u8005\u6709\u5f88\u591a\u4e2a\u5143\u7d20. \u2003\u2014\u2014\u2014\u2014 \u5b83\u4eec\u90fd\u4f1a\u8ff7\u60d1 jit \u7136\u540e\u4e0d\u77e5\u6240\u63aa\u5730\u6254\u7ed9\u4f60\u4e00\u4e2a InvalidProgramException
.
\u90a3\u4e48\u518d\u6765\u8bd5\u8bd5 a - b + c
:
\u63d0\u793a\u7b54\u6848 \u51cf\u6cd5\u7684\u64cd\u4f5c\u7b26\u4e3a sub
, \u5b83\u4f1a\u5f39\u51fa\u4e24\u4e2a\u503c, \u5c06\u540e\u5f39\u51fa\u7684\u503c\u51cf\u53bb\u5148\u5f39\u51fa\u7684\u503c\u540e\u5c06\u7ed3\u679c\u538b\u5165\u8bc4\u4f30\u6808.
il.Emit(OpCodes.Ldarg_0);\nil.Emit(OpCodes.Ldarg_1);\nil.Emit(OpCodes.Sub);\nil.Emit(OpCodes.Ldarg_2);\nil.Emit(OpCodes.Add);\nil.Emit(OpCodes.Ret);\n
\u4f60\u53ef\u80fd\u5df2\u7ecf\u53d1\u73b0\u7684\u4e00\u4e2a\u6bd4\u8f83\u8212\u670d\u7684\u70b9\u662f, \u76f8\u51cf\u7684\u987a\u5e8f\u521a\u597d\u5c31\u662f\u538b\u5165\u7684\u987a\u5e8f, \u4e5f\u5373\u5f39\u51fa\u7684\u9006\u987a\u5e8f, \u8fd9\u70b9\u4f1a\u8ba9\u6211\u4eec\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u624b\u5199 IL
\u7684\u66f4\u7b26\u5408\u76f4\u89c9\u4e00\u70b9."},{"location":"trans/il/#_5","title":"\u65b9\u6cd5\u7684\u8c03\u7528","text":"\u73b0\u5728\u6211\u4eec\u7684 IL
\u6307\u4ee4\u53ea\u80fd\u505a\u4e9b\u52a0\u52a0\u51cf\u51cf\u662f\u4e0d\u662f\u5f88\u65e0\u804a? \u90a3\u4e48\u73b0\u5728\u6211\u4eec\u6765\u8bd5\u8bd5\u5728 IL
\u4e2d\u8c03\u7528\u65b9\u6cd5. \u5728 IL
\u4e2d\u6709\u4e09\u79cd\u8c03\u7528\u65b9\u6cd5\u6307\u4ee4:
\u64cd\u4f5c\u7b26 \u53c2\u6570 \u63cf\u8ff0 call
\u65b9\u6cd5 token \u6839\u636e\u65b9\u6cd5\u7684\u53c2\u6570\u5217\u8868(\u5305\u542b this
, \u5982\u679c\u5176\u662f\u6210\u5458\u65b9\u6cd5\u65f6)\u9006\u987a\u5e8f\u5f39\u51fa\u5bf9\u5e94\u6570\u91cf\u53c2\u6570\u5e76\u4ee5\u6b64\u8c03\u7528\u5bf9\u5e94\u65b9\u6cd5 callvirt
\u65b9\u6cd5 token \u540c call
, \u4f46\u662f\u8be5\u6307\u4ee4\u5728\u5bf9\u5e94\u65b9\u6cd5\u4e3a\u865a\u65b9\u6cd5\u65f6\u4f1a\u5411\u4e0b\u5bfb\u627e\u91cd\u5199\u540e\u7684\u65b9\u6cd5 calli
callsite \u63cf\u8ff0 \u6839\u636e callsite \u63cf\u8ff0 \u5f39\u51fa\u5bf9\u5e94\u53c2\u6570\u5e76\u518d\u6b21\u5f39\u51fa\u6240\u9700\u7684\u51fd\u6570\u6307\u9488\u5e76\u8c03\u7528 \u5176\u4e2d\u7528\u7684\u6700\u591a\u7684\u662f call
\u548c callvirt
, \u6700\u540e\u4e00\u4e2a calli
\u5728\u505a\u4e0e\u672c\u673a\u4ea4\u4e92\u65f6\u624d\u5e38\u7528, \u56e0\u4e3a\u5b83\u8981\u6c42\u6211\u4eec\u6709\u5bf9\u5e94\u7684\u51fd\u6570\u6307\u9488(\u51fd\u6570\u6307\u9488\u53ef\u80fd\u5f88\u591a\u6559\u7a0b\u4e0d\u4f1a\u63d0\u53ca, \u4f60\u53ef\u4ee5\u5728MSDN \u4e0a\u7684\u4e0d\u5b89\u5168\u4ee3\u7801\u3001\u6570\u636e\u6307\u9488\u548c\u51fd\u6570\u6307\u9488\u8fd9\u7bc7\u6587\u7ae0\u4e2d\u4e86\u89e3).
call
\u4e0e callvirt
\u6700\u4e3b\u8981\u7684\u533a\u522b\u662f, call
\u6307\u4ee4\u4e00\u65e6\u6307\u5b9a\u4e86\u5bf9\u5e94\u65b9\u6cd5, \u90a3\u4e48\u5728\u8fd0\u884c\u65f6\u8c03\u7528\u7684\u65b9\u6cd5\u662f\u4e0d\u4f1a\u53d8\u7684, \u6240\u4ee5\u5b83\u901a\u5e38\u751f\u6210\u4e8e\u9759\u6001\u65b9\u6cd5\u7684\u8c03\u7528\u4e2d, \u800c callvirt
\u5728\u8fd0\u884c\u65f6\u4f1a\u68c0\u6d4b\u76ee\u6807\u7c7b\u578b, \u5e76\u5411\u4e0b\u67e5\u627e\u53ef\u80fd\u7684\u88ab\u91cd\u5199\u540e\u7684\u65b9\u6cd5, \u6240\u4ee5\u6309\u5b57\u9762\u610f\u601d\u5b83\u7ecf\u5e38\u751f\u6210\u4e8e\u865a\u65b9\u6cd5\u7684\u8c03\u7528\u4e2d, \u4e0d\u8fc7\u4e00\u822c\u5bf9\u4e8e\u666e\u901a\u6210\u5458\u65b9\u6cd5\u7684\u8c03\u7528, C#
\u7f16\u8bd1\u5668\u4e5f\u4f1a\u751f\u6210 callvirt
\u6307\u4ee4, \u8fd9\u662f\u56e0\u4e3a callvirt
\u9700\u8981\u68c0\u67e5\u76ee\u6807\u7c7b\u578b, \u5728\u8c03\u7528\u5bf9\u8c61\u4e3a null
\u65f6\u5c31\u629b\u51fa NullReferenceException
, \u800c call
\u6307\u4ee4\u53ef\u80fd\u76f4\u5230\u65b9\u6cd5\u8c03\u7528\u4e00\u534a\u65f6\u624d\u5bdf\u89c9 this
\u4e3a null
, \u8fd9\u662f\u4e00\u4e2a\u5f88\u5371\u9669\u7684\u884c\u4e3a.
\u5728\u6211\u4eec\u5e9f\u8bdd\u5b8c\u4e4b\u540e, \u662f\u65f6\u5019\u505a\u4e00\u70b9\u5b9e\u9645\u7684\u4e86. \u73b0\u5728, \u6211\u4eec\u4e0d\u9700\u8981\u6211\u4eec\u4e4b\u524d\u6d4b\u8bd5 add
, ret
, mul
, sub
\u6307\u4ee4\u65f6\u58f0\u660e\u7684\u65b9\u6cd5\u7b7e\u540d\u4e86, \u6240\u4ee5\u6211\u4eec\u66f4\u6539\u5982\u4e0b\u4ee3\u7801, \u4f7f\u5f97\u6211\u4eec\u7684\u52a8\u6001\u65b9\u6cd5 MyMethod
\u8fd4\u56de void
\u5e76\u4e14\u4e0d\u63a5\u6536\u53c2\u6570:
public static MethodInfo GenerateMethod(Action<ILGenerator> generateAction)\n{\n AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new(\"MyAssembly\"), AssemblyBuilderAccess.RunAndCollect);\n ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule(\"MyTestModule\");\n TypeBuilder typeBuilder = moduleBuilder.DefineType(\"MyType\");\n MethodBuilder methodBuilder = typeBuilder.DefineMethod(\"MyMethod\", MethodAttributes.Public | MethodAttributes.Static\n , typeof(void), Type.EmptyTypes);\n generateAction(methodBuilder.GetILGenerator());\n return typeBuilder.CreateType().GetMethod(\"MyMethod\")!;\n}\n
\u987a\u4fbf\u628a\u4e0b\u9762\u4e5f\u6539\u6210\u8fd9\u6837, \u4ee5\u8d34\u5408\u6211\u4eec\u5728\u4e0a\u9762\u7684\u5b9a\u4e49, \u987a\u4fbf\u6e05\u7a7a\u4e00\u4e0b\u6211\u4eec\u7684\u65b9\u6cd5\u4f53:
MethodInfo methodInfo = GenerateMethod(il =>\n{\n il.Emit(OpCodes.Ret);\n});\nvar action = methodInfo.CreateDelegate<Action>();\naction();\n
\u73b0\u5728, \u6211\u4eec\u6253\u7b97\u4f7f\u7528 IL
\u5199\u4e00\u4e2a HelloWorld \u7a0b\u5e8f, \u90a3\u4e48\u5c31\u9700\u8981\u8c03\u7528 System.Console.WriteLine(string)
\u8fd9\u4e2a\u65b9\u6cd5, \u6ce8\u610f\u6b64\u65f6\u6211\u4eec\u5fc5\u987b\u6e05\u695a\u6211\u4eec\u8c03\u7528\u7684\u65b9\u6cd5\u7684\u5177\u4f53\u67d0\u4e2a\u91cd\u8f7d, \u73b0\u5728\u4f7f\u7528\u53cd\u5c04\u77e5\u8bc6, \u83b7\u53d6\u8fd9\u4e2a\u9759\u6001\u65b9\u6cd5\u7684 MethodInfo
:
var cws = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\n
\u7136\u540e\u6211\u4eec\u89c2\u5bdf\u5b83\u7684\u53c2\u6570, \u53d1\u73b0\u9700\u8981\u4e00\u4e2a string
, \u6240\u4ee5\u6211\u4eec\u5f97\u4f7f\u7528 ldstr
IL
\u6307\u4ee4, \u5b83\u4f1a\u5c06\u5b83\u53c2\u6570 token \u5bf9\u5e94\u7684\u5b57\u7b26\u4e32\u538b\u5165\u8bc4\u4f30\u6808, \u5728\u8fd9\u91cc\u6211\u4eec\u4e0d\u9700\u8981\u5173\u5fc3\u8fd9\u4e2a token \u5982\u4f55\u751f\u6210, System.Reflection.Emit
\u4f1a\u5e2e\u6211\u4eec\u505a\u597d\u8fd9\u4e9b, \u5728\u8fd9\u91cc\u53ea\u9700\u8981\u4f20\u5165 string
:
il.Emit(OpCodes.Ldstr, \"Hello World in IL!\");\n
\u4e00\u5207\u5c31\u7eea, \u8c03\u7528\u6211\u4eec\u7684\u65b9\u6cd5:
il.Emit(OpCodes.Call, cws);\n
\u603b\u7684\u4ee3\u7801\u5982\u4e0b:
var cws = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nil.Emit(OpCodes.Ldstr, \"Hello World in IL!\");\nil.Emit(OpCodes.Call, cws);\nil.Emit(OpCodes.Ret);\n
\u73b0\u5728, \u8fd0\u884c\u7a0b\u5e8f, \u4f60\u5e94\u8be5\u4f1a\u770b\u5230\u5982\u4e0b\u8f93\u51fa: \u54c7\u4f60\u592a\u5f3a\u4e86\u4f60\u505a\u5230\u4e86\u8fd9\u4e2a\u795e\u4ed9\u64cd\u4f5c\u4f60\u600e\u4e48\u53ef\u4ee5\u8fd9\u4e48\u5f3a\uff01\uff01\uff01\u2003\u5f85\u4f1a\u513f\u6211\u8bf4\u6211\u81ea\u5df1\u5462
Hello World in IL!\n
\u5bf9\u4e8e\u6709\u8fd4\u56de\u503c\u7684\u65b9\u6cd5, call
\u8c03\u7528\u5b8c\u540e\u4f1a\u5c06\u8fd4\u56de\u503c\u538b\u5165\u5806\u6808, \u6bd4\u5982\u8981\u5c06\u4ee5\u4e0b C#
\u4ee3\u7801\u8f6c\u4e3a IL
\u4ee3\u7801:
Console.WriteLine(Console.ReadLine());\n
\u53ea\u9700\u8981\u8fd9\u6837:
var cws = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar cr = typeof(Console).GetMethod(\"ReadLine\")!;\nil.Emit(OpCodes.Call, cr);\nil.Emit(OpCodes.Call, cws);\nil.Emit(OpCodes.Ret);\n
\u5f53\u6211\u4eec\u4e0d\u9700\u8981\u8fd4\u56de\u503c\u65f6, \u6211\u4eec\u5fc5\u987b\u663e\u5f0f\u4f7f\u7528 pop
\u6307\u4ee4\u820d\u5f03\u5b83, \u9632\u6b62\u5b83\"\u6c61\u67d3\"\u6211\u4eec\u7684\u8bc4\u4f30\u6808:
// \u7b49\u5f85\u7528\u6237\u7684\u4e00\u4e2a\u56de\u8f66\u8f93\u5165\nConsole.ReadLine();\nConsole.WriteLine(\"Hey, I see you pressed the Enter!\");\n
var cws = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar cr = typeof(Console).GetMethod(\"ReadLine\")!;\nil.Emit(OpCodes.Call, cr);\nil.Emit(OpCodes.Pop);\nil.Emit(OpCodes.Ldstr, \"Hey, I see you pressed the Enter!\");\nil.Emit(OpCodes.Call, cws);\nil.Emit(OpCodes.Ret);\n
\u65b9\u6cd5\u7684\u53c2\u6570\u5217\u8868\u987a\u5e8f\u548c\u538b\u6808\u987a\u5e8f\u4e00\u81f4, \u8c03\u7528\u591a\u53c2\u6570\u65b9\u6cd5\u4e5f\u4f1a\u663e\u5f97\u5f88\u81ea\u7136:
double a = Math.Pow(123, 4);\nConsole.WriteLine(a);\n
var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(double) })!;\nvar powMethod = typeof(Math).GetMethod(\"Pow\")!;\nil.Emit(OpCodes.Ldc_R8, 123.0);\nil.Emit(OpCodes.Ldc_R8, 4.0);\nil.Emit(OpCodes.Call, powMethod);\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
ldc.r8
\u6307\u4ee4\u5c06\u53c2\u6570\u4e2d\u7684 float64
, \u5373 double
\u5b57\u9762\u91cf\u538b\u5165\u8bc4\u4f30\u6808\u4e2d, \u7c7b\u4f3c\u7684\u64cd\u4f5c\u7b26\u8fd8\u6709 ldc.i4
, \u5b83\u5c06\u53c2\u6570\u4e2d\u7684 int32
\u5373 int
\u5b57\u9762\u91cf\u538b\u5165\u8bc4\u4f30\u6808\u4e2d, \u6ce8\u610f\u5728\u8fd9\u91cc\u4f20\u53c2\u6211\u4eec\u5fc5\u987b\u660e\u786e\u5199\u660e\u53c2\u6570\u7c7b\u578b, \u6bd4\u5982\u4e0a\u9762\u7684 IL
\u5982\u679c\u4f7f\u7528 123
\u800c\u4e0d\u662f 123.0
\u4f1a\u53d1\u751f jit \u5f02\u5e38\u6216\u884c\u4e3a\u975e\u671f\u671b, \u56e0\u4e3a\u53c2\u6570\u7c7b\u578b\u4e0d\u5339\u914d, 123
\u5339\u914d\u5230\u4e86 il.Emit
\u7684 int
\u91cd\u8f7d, \u800c\u6211\u4eec\u9700\u8981\u7684\u662f double
\u91cd\u8f7d, \u6240\u4ee5\u6211\u4eec\u5199\u660e 123.0
\u6216 123d
\u4ee5\u4f7f\u5176\u6210\u4e3a double
\u7c7b\u578b\u7684\u5b57\u9762\u91cf. \u5bf9\u4e8e float
long
double
\u7b49\u8fd9\u4e9b\u6709\u5bf9\u5e94\u5b57\u9762\u91cf\u540e\u7f00\u7684(f
, l
, d
) \u7c7b\u578b\u6211\u4eec\u76f4\u63a5\u52a0\u540e\u7f00\u5c31\u884c\u4e86, \u4f46\u5bf9\u4e8e short
\u548c byte
\u8fd9\u4e9b, \u6211\u4eec\u5fc5\u987b\u8fdb\u884c\u663e\u5f0f\u5f3a\u8f6c:
public static void Main()\n{\n MethodInfo methodInfo = GenerateMethod(il =>\n {\n // il \u4e2d\u6ca1\u6709\u5bf9\u5e94\u7684\u52a0\u8f7d `int16` \u548c `int8` \u7684\u6307\u4ee4, \u6211\u4eec\u5f97\u4f7f\u7528 `ldc.i4`, \n // \u867d\u7136\u5b83\u672c\u6765\u662f\u7528\u6765\u52a0\u8f7d `int32` \u7684, \u4f46 jit \u4f1a\u77e5\u9053\u6211\u4eec\u60f3\u8981\u5e72\u4ec0\u4e48\n // \u5bf9\u4e8e\u5c0f\u4e00\u70b9\u7684\u6574\u6570\u5b57\u9762\u91cf IL \u8fd8\u63d0\u4f9b\u4e86\u4e00\u4e2a `ldc.i4.s` \u6307\u4ee4\n // \u5176\u53c2\u6570\u4e3a `int8` \u5373 `byte` \u6216 `sbyte` \u7c7b\u578b\n var printByte = typeof(Program).GetMethod(\"PrintByte\")!;\n il.Emit(OpCodes.Ldc_I4_S, (byte)12);\n il.Emit(OpCodes.Call, printByte);\n il.Emit(OpCodes.Ldc_I4, (int)12);\n il.Emit(OpCodes.Call, printByte);\n il.Emit(OpCodes.Ret);\n });\n var action = methodInfo.CreateDelegate<Action>();\n action();\n\n}\n\npublic static void PrintByte(byte v)\n{\n Console.WriteLine($\"Your byte is {v}\");\n}\n
"},{"location":"trans/il/#_6","title":"\u5bf9\u8c61\u5b9e\u4f8b\u5316","text":"\u8fd9\u4e00\u6b65\u5f88\u7b80\u5355, \u4e3a\u4e86\u5b9e\u4f8b\u5316\u4e00\u4e2a\u5bf9\u8c61, \u6211\u4eec\u9700\u8981\u4f7f\u7528 newobj
\u64cd\u4f5c\u7b26, \u5176\u53c2\u6570\u4e3a\u5bf9\u5e94\u5bf9\u8c61\u7684\u4e00\u4e2a\u6784\u9020\u5668, \u8be5\u6307\u4ee4\u6267\u884c\u540e\u4f1a\u5c06\u6211\u4eec\u8981\u7684\u5bf9\u8c61\u538b\u5165\u8bc4\u4f30\u6808, \u6bd4\u5982\u5982\u4e0b C#
\u4ee3\u7801:
new StringBuilder();\n
\u6211\u4eec\u9700\u8981\u8fd9\u6837\u751f\u6210\u5b83\u7684 IL
:
var sbctor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes)!;\nil.Emit(OpCodes.Newobj, sbctor);\n
"},{"location":"trans/il/#_7","title":"\u6210\u5458\u65b9\u6cd5\u7684\u8c03\u7528","text":"\u73b0\u5728, \u6211\u4eec\u5728\u8bc4\u4f30\u6808\u4e0a\u6709\u4e86\u4e00\u4e2a\u5bf9\u8c61, \u6211\u4eec\u5c31\u53ef\u4ee5\u7528\u5b83\u8c03\u7528\u5b83\u7684\u6210\u5458\u65b9\u6cd5\u4e86. \u6210\u5458\u65b9\u6cd5\u7684\u8c03\u7528\u4e0e\u9759\u6001\u65b9\u6cd5\u8c03\u7528\u57fa\u672c\u4e00\u81f4, \u4f46\u662f\u6bcf\u6b21\u8c03\u7528\u4e4b\u524d\u6211\u4eec\u90fd\u5fc5\u987b\u8bb0\u5f97\u5c06 this
\u7684\u503c\u4f5c\u4e3a\u7b2c0\u4e2a\u53c2\u6570\u538b\u5165\u5806\u6808, \u987a\u4fbf, \u8bb0\u4f4f\u8fd9\u91cc\u7684 this
\u662f\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7684, \u6bcf\u6b21\u8c03\u7528\u90fd\u4f1a\u88ab\u5f39\u51fa\u8bc4\u4f30\u6808, \u6240\u4ee5\u5728\u8fde\u7eed\u8c03\u7528\u5b83\u7684\u6210\u5458\u65b9\u6cd5\u65f6\u8bb0\u5f97\u5c06 this
\u518d\u6b21\u538b\u5165. \u901a\u5e38\u6211\u4eec\u4f1a\u4f7f\u7528 callvirt
\u6765\u8c03\u7528\u6210\u5458\u65b9\u6cd5, \u4e00\u65b9\u9762\u4e3a\u4e86\u786e\u4fdd\u8c03\u7528\u5230\u4e86\u91cd\u5199\u540e\u7684\u865a\u51fd\u6570, \u4e00\u65b9\u9762\u4e3a\u4e86\u5c3d\u53ef\u80fd\u65e9\u7684\u68c0\u6d4b\u51fa this
\u4e3a null.
Console.WriteLine(new StringBuilder().Append(\"abc\").Append(\"def\").Append(\"ghi\").ToString());\n
var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar sbctor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes)!;\nvar appendMethod = typeof(StringBuilder).GetMethod(\"Append\", new Type[] { typeof(string) })!;\nvar toStringMethod = typeof(StringBuilder).GetMethod(\"ToString\", Type.EmptyTypes)!;\n// StringBuilder.Append \u65b9\u6cd5\u4f1a\u8fd4\u56de\u81ea\u8eab, \u6240\u4ee5\u8fd9\u91cc\u7684 `this` \u5728\u65b9\u6cd5\u88ab\u8c03\u7528\u540e\u53c8\u88ab\u5f39\u51fa\u53c8\u88ab\u538b\u5165\nil.Emit(OpCodes.Newobj, sbctor);\nil.Emit(OpCodes.Ldstr, \"abc\");\nil.Emit(OpCodes.Callvirt, appendMethod);\nil.Emit(OpCodes.Ldstr, \"def\");\nil.Emit(OpCodes.Callvirt, appendMethod);\nil.Emit(OpCodes.Ldstr, \"ghi\");\nil.Emit(OpCodes.Callvirt, appendMethod);\nil.Emit(OpCodes.Callvirt, toStringMethod);\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
\u4f46\u662f\u5b9e\u9645\u4e0a, \u6211\u4eec\u660e\u786e\u77e5\u9053 StringBuilder
\u662f\u5bc6\u5c01\u7684, \u6ca1\u4eba\u4f1a\u91cd\u5199\u5b83\u7684\u865a\u65b9\u6cd5, \u4ee5\u53ca\u8fd9\u91cc\u6211\u4eec\u660e\u786e\u77e5\u9053\u8fd9\u91cc\u7684 this
\u4e0d\u4e3a null, \u6240\u4ee5\u5b9e\u9645\u4e0a\u4e0a\u9762\u7684 callvirt
\u90fd\u80fd\u6362\u6210 call
:
var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar sbctor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes)!;\nvar appendMethod = typeof(StringBuilder).GetMethod(\"Append\", new Type[] { typeof(string) })!;\nvar toStringMethod = typeof(StringBuilder).GetMethod(\"ToString\", Type.EmptyTypes)!;\n// StringBuilder.Append \u65b9\u6cd5\u4f1a\u8fd4\u56de\u81ea\u8eab, \u6240\u4ee5\u8fd9\u91cc\u7684 `this` \u5728\u65b9\u6cd5\u88ab\u8c03\u7528\u540e\u53c8\u88ab\u5f39\u51fa\u53c8\u88ab\u538b\u5165\nil.Emit(OpCodes.Newobj, sbctor);\nil.Emit(OpCodes.Ldstr, \"abc\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Ldstr, \"def\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Ldstr, \"ghi\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Call, toStringMethod);\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
"},{"location":"trans/il/#_8","title":"\u5c40\u90e8\u53d8\u91cf","text":"\u4e5f\u8bb8\u4f60\u4e5f\u53d1\u73b0\u4e86, \u6211\u4eec\u4e0a\u9762\u7684\u4ee3\u7801\u90fd\u6709\u4e9b\"\u618b\u5c48\", \u8fd9\u662f\u56e0\u4e3a\u6211\u4eec\u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\u6ca1\u6709\u7528\u5230\u5c40\u90e8\u53d8\u91cf. \u5728 System.Reflection.Emit
\u4e2d, \u6211\u4eec\u5fc5\u987b\u663e\u5f0f\u6307\u5b9a\u6211\u4eec\u53ef\u80fd\u7528\u5230\u51e0\u4e2a\u5c40\u90e8\u53d8\u91cf\u4ee5\u53ca\u5bf9\u5e94\u7684\u7c7b\u578b, \u6bd4\u5982\u5982\u4e0b C# \u4ee3\u7801:
StringBuilder sb = new();\nsb.Append(\"abc\");\nsb.Append(\"def\");\nsb.Append(\"ghi\");\nstring str = sb.ToString();\nConsole.WriteLine(str);\n
\u6211\u4eec\u8fdb\u884c\u5206\u6790, \u53d1\u73b0\u5b83\u4f7f\u7528\u4e86\u4e24\u4e2a\u5c40\u90e8\u53d8\u91cf: sb
\u548c str
, \u6240\u4ee5\u6211\u4eec\u5728\u8c03\u7528 il.Emit
\u4e4b\u524d\u8c03\u7528 il.DeclareLocal
:
il.DeclareLocal(typeof(StringBuilder)); // 0\nil.DeclareLocal(typeof(string)); // 1\n
\u6ce8\u610f\u6211\u4eec\u8c03\u7528 DeclareLocal
\u7684\u987a\u5e8f, \u8fd9\u4e2a\u987a\u5e8f\u6211\u4eec\u5728\u4e0b\u9762\u7684 IL
\u4e2d\u5c31\u4f1a\u4f7f\u7528\u5b83:
\u54e6\u5929\u54ea\u5b83\u771f\u7684\u592a\u957f\u4e86var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar sbctor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes)!;\nvar appendMethod = typeof(StringBuilder).GetMethod(\"Append\", new Type[] { typeof(string) })!;\nvar toStringMethod = typeof(StringBuilder).GetMethod(\"ToString\", Type.EmptyTypes)!;\n\nil.DeclareLocal(typeof(StringBuilder)); // 0\nil.DeclareLocal(typeof(string)); // 1\n\nil.Emit(OpCodes.Newobj, sbctor);\n// \u5c06\u6211\u4eec\u7684 StringBuilder \u5bf9\u8c61\u5b58\u5230 0 \u53f7\u4f4d\u7684\u5c40\u90e8\u53d8\u91cf\u4e0a\nil.Emit(OpCodes.Stloc_0); \n// \u628a\u6211\u4eec\u4e4b\u524d\u5728 0 \u53f7\u4f4d\u5c40\u90e8\u53d8\u91cf\u4e0a\u5b58\u7684 StringBuilder \u5bf9\u8c61\u8bfb\u53d6\u51fa\u6765\u5e76\u538b\u5165\u8bc4\u4f30\u6808\u4e0a\nil.Emit(OpCodes.Ldloc_0); \n// \u51c6\u5907 StringBuilder.Append \u7684\u90a3\u4e2a\u53c2\u6570\u4f5c\u4e3a\u5176\u5185\u90e8 ldarg.1 \u4f1a\u8bfb\u53d6\u7684\u503c(ldarg.0 \u662f this)\nil.Emit(OpCodes.Ldstr, \"abc\");\nil.Emit(OpCodes.Call, appendMethod);\n// \u6211\u4eec\u5728\u8fd9\u91cc\u4e0d\u4f1a\u4f7f\u7528 StringBuilder.Append \u7684\u90a3\u4e2a\u7528\u4e8e\u94fe\u5f0f\u8c03\u7528\u7684\u8fd4\u56de\u503c\n// \u6240\u4ee5\u6211\u4eec\u4f7f\u7528 `pop` \u5f39\u51fa\u5b83\u907f\u514d\"\u6c61\u67d3\"\u6211\u4eec\u7684\u8bc4\u4f30\u6808.\nil.Emit(OpCodes.Pop);\nil.Emit(OpCodes.Ldloc_0);\nil.Emit(OpCodes.Ldstr, \"def\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Pop);\nil.Emit(OpCodes.Ldloc_0);\nil.Emit(OpCodes.Ldstr, \"ghi\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Pop);\nil.Emit(OpCodes.Ldloc_0);\nil.Emit(OpCodes.Call, toStringMethod);\nil.Emit(OpCodes.Stloc_1);\nil.Emit(OpCodes.Ldloc_1);\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
\u5728\u4e0a\u9762\u7684 IL
\u4e2d, stloc.0
\u5c06\u6808\u9876\u7684\u503c\u5f39\u51fa\u5e76\u5b58\u5230\u5c40\u90e8\u53d8\u91cf 0 \u53f7\u4f4d\u4e0a, ldloc.0
\u8bfb\u53d6\u5c40\u90e8\u53d8\u91cf 0 \u53f7\u4f4d\u7684\u503c\u7136\u540e\u5c06\u5176\u538b\u5165\u8bc4\u4f30\u6808\u4e0a. \u4e0d\u8fc7\u5b9e\u9645\u4e0a\u8fd9\u91cc\u7528\u4e0d\u7740\u5c40\u90e8\u53d8\u91cf, \u9664\u4e86\u4f7f\u7528 Append
\u8fd4\u56de\u7684 this
\u4e4b\u5916, \u6211\u4eec\u8fd8\u53ef\u4ee5\u4f7f\u7528 dup
\u6307\u4ee4\u6765\u7b80\u5316\u5927\u91cf\u7684 ldloc.0
\u64cd\u4f5c. \u9664\u6b64\u4e4b\u5916 string
\u90a3\u4e2a\u5c40\u90e8\u53d8\u91cf\u4e5f\u7528\u4e0d\u7740, \u6211\u4eec\u5728 ToString
\u540e\u76f4\u63a5\u8c03\u7528 Console.WriteLine
\u5373\u53ef, \u56e0\u4e3a\u8fd9\u65f6\u7684 string
\u521a\u597d\u5c31\u5728\u6808\u9876.
il.Emit(OpCodes.Newobj, sbctor);\n\nil.Emit(OpCodes.Dup);\nil.Emit(OpCodes.Ldstr, \"abc\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Pop);\n\nil.Emit(OpCodes.Dup);\nil.Emit(OpCodes.Ldstr, \"def\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Pop);\n\nil.Emit(OpCodes.Dup);\nil.Emit(OpCodes.Ldstr, \"ghi\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Pop);\n\nil.Emit(OpCodes.Dup);\nil.Emit(OpCodes.Call, toStringMethod);\nil.Emit(OpCodes.Call, cw);\n\n// \u8bb0\u5f97\u5f39\u51fa\u6700\u521d newobj \u6307\u4ee4\u538b\u5165\u7684\u90a3\u4e2a\u5143\u7d20, \u5426\u5219\u6b64\u65f6 ret \u6808\u5c31\u4e0d\u662f\u7a7a\u7684\u4e86\n// \u8fd9\u4f1a\u5bfc\u81f4 jit \u629b\u51fa InvalidProgramException\nil.Emit(OpCodes.Pop);\n\nil.Emit(OpCodes.Ret);\n
dup
\u6307\u4ee4\u5f39\u51fa\u6808\u9876\u7684\u5143\u7d20, \u7136\u540e\u538b\u5165\u4e24\u904d\u8fd9\u4e2a\u5143\u7d20, \u4e5f\u5c31\u662f\u5b83\u4f1a\u590d\u5236\u6808\u9876\u7684\u5143\u7d20\u4e00\u904d\u5e76\u538b\u5165, \u5728\u8fd9\u91cc, \u6211\u4eec\u4f7f\u7528 dup
\u6307\u4ee4\u5728\u6bcf\u6b21\u9700\u8981 this
\u5bf9\u8c61\u65f6\u590d\u5236\u6700\u521d newobj
\u6307\u4ee4\u538b\u5165\u7684\u5143\u7d20, \u8fd9\u6837\u5c31\u65e0\u9700\u4f7f\u7528\u5c40\u90e8\u53d8\u91cf\u800c\u590d\u6742\u5316\u6211\u4eec\u7684 IL
\u4e86.
"},{"location":"trans/il/#_9","title":"\u5c5e\u6027\u7684\u8bbf\u95ee","text":"\u5728 IL
\u4e2d, \u5176\u5b9e\u6ca1\u6709\u4e00\u6761\u6307\u4ee4\u662f\u5173\u4e8e\u5c5e\u6027\u7684, \u56e0\u4e3a\u6211\u4eec\u77e5\u9053\u5c5e\u6027\u5b9e\u9645\u4e0a\u5c31\u662f\u4e00\u5bf9 getter \u548c setter \u800c\u5df2. \u901a\u5e38, \u4e00\u4e2a\u540d\u4e3a MyProp
\u7684\u5c5e\u6027\u7684 getter \u65b9\u6cd5\u53eb\u505a get_MyProp
, setter \u65b9\u6cd5\u53eb\u505a set_MyProp
, \u5982\u679c\u4f60\u5728 C# \u4e2d\u5c1d\u8bd5\u7ed9\u65b9\u6cd5\u8fd9\u6837\u8d77\u540d\u4f60\u4f1a\u53d1\u73b0\u7f16\u8bd1\u5668\u4f1a\u4e3a\u4e86\u9632\u6b62\u65b9\u6cd5\u91cd\u540d\u800c\u62a5\u9519, \u987a\u4fbf, \u8fd9\u4e00\u5bf9\u65b9\u6cd5\u5b83\u4eec\u5404\u81ea\u90fd\u6709\u4e00\u4e2a special name
\u7684\u7279\u6b8a\u6807\u8bb0\u4ee5\u4fbf\u7f16\u8bd1\u5668\u77e5\u6653\u5b83\u4eec\u5f52\u5c5e\u4e8e\u4e00\u4e2a\u5c5e\u6027.
\u6bd4\u5982\u5982\u4e0b C#
\u4ee3\u7801:
Console.WriteLine(\"123\".Length);\n
var cwInt = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(int) })!;\nvar stringGetLength = typeof(string).GetMethod(\"get_Length\")!;\nil.Emit(OpCodes.Ldstr, \"123\");\nil.Emit(OpCodes.Call, stringGetLength);\nil.Emit(OpCodes.Call, cwInt);\nil.Emit(OpCodes.Ret);\n
\u5728\u8fd9\u91cc\u6211\u4eec\u8c03\u7528\u7684\u5c31\u662f string
\u7684 get_Length
\u65b9\u6cd5. \u5c31\u662f\u8fd9\u4e48\u7b80\u5355.
"},{"location":"trans/il/#_10","title":"\u5b57\u6bb5\u7684\u8bbf\u95ee","text":"\u5bf9\u4e8e\u9759\u6001\u5b57\u6bb5\u7684\u8bbf\u95ee, \u6211\u4eec\u9700\u8981\u4f7f\u7528 ldsfld
\u64cd\u4f5c\u7b26, \u6bd4\u5982 Path.DirectorySeparatorChar
\u8fd9\u4e2a\u9759\u6001\u5b57\u6bb5:
Console.WriteLine(Path.DirectorySeparatorChar);\n
// \u6ce8\u610f\u4e0b\u8fd9\u91cc WriteLine \u7684\u91cd\u8f7d\u6362\u4e86, \u56e0\u4e3a Path.DirectorySeparatorChar \u662f char \u7c7b\u578b\u7684\nvar cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(char) })!;\nvar pathStfld = typeof(Path).GetField(\"DirectorySeparatorChar\")!;\nil.Emit(OpCodes.Ldsfld, pathStfld);\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
ldsfld
\u4f1a\u5c06\u53c2\u6570\u4e2d\u7684\u9759\u6001\u5b57\u6bb5\u7684 token \u5bf9\u5e94\u7684\u9759\u6001\u5b57\u6bb5\u7684\u503c\u538b\u5165\u8bc4\u4f30\u6808\u4e0a.
\u5bf9\u4e8e\u6210\u5458\u5b57\u6bb5\u7684\u8bbf\u95ee\u4e5f\u662f\u7c7b\u4f3c\u7684, \u4e0d\u8fc7\u5b83\u4f1a\u9700\u8981\u5f39\u51fa\u4e00\u4e2a this
\u5143\u7d20, \u6bd4\u5982\u5bf9\u4e8e\u5982\u4e0b C# \u7c7b:
\u5176\u5b9e\u662f\u627e\u4e0d\u5230\u00a0bcl\u00a0\u91cc\u7ecf\u5e38\u8bbf\u95ee\u6210\u5458\u5b57\u6bb5\u7684\u4f8b\u5b50\u624d\u88ab\u8feb\u58f0\u660e\u65b0\u7c7b\u7684
public class SomeClass\n{\n public string SomeString;\n public SomeClass()\n => SomeString = \"\u8fd9\u91cc\u662f\u4e00\u4e2a\u5b57\u7b26\u4e32!\";\n}\n
var someClassCtor = typeof(SomeClass).GetConstructor(Type.EmptyTypes)!;\nvar cwString = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar someClassFld = typeof(SomeClass).GetField(\"SomeString\")!;\nil.Emit(OpCodes.Newobj, someClassCtor);\nil.Emit(OpCodes.Ldfld, someClassFld);\nil.Emit(OpCodes.Call, cwString);\nil.Emit(OpCodes.Ret);\n
"},{"location":"trans/il/#_11","title":"\u8df3\u8f6c\u6307\u4ee4","text":"\u5728\u8fd9\u91cc\u6211\u4eec\u4f1a\u4ecb\u7ecd\u8fd9\u4e00\u8282\u7684\u6700\u540e\u4e00\u4e2a\u4e1c\u897f \u2014\u2014 \u8df3\u8f6c\u6307\u4ee4. \u5b83\u662f C# \u4e2d if
switch
for
while
goto
\u7b49\u6d41\u7a0b\u63a7\u5236\u8bed\u53e5\u90fd\u5341\u5206\u4f9d\u8d56\u7684\u4e1c\u897f.
\u5728 IL
\u4e2d, \u4e3a\u4e86\u65b9\u4fbf \u5927\u4e8e, \u5c0f\u4e8e, \u5927\u4e8e\u7b49\u4e8e, \u5c0f\u4e8e\u7b49\u4e8e, \u662f\u5426 null, \u662f\u5426\u975e0 \u7b49\u4f17\u591a\u6761\u4ef6\u8868\u8fbe\u5f0f\u7684\u5224\u65ad, IL
\u5f15\u5165\u4e86\u5927\u91cf\u6709\u5173\u7684\u6307\u4ee4, \u5177\u4f53\u5982\u4e0b\u8868(\u6458\u81ea MSDN):
\u6307\u4ee4 \u63cf\u8ff0 beq\u00a0\u00a0\u00a0 \u5982\u679c\u4e24\u4e2a\u503c\u76f8\u7b49\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 beq.s\u00a0\u00a0 \u5982\u679c\u4e24\u4e2a\u503c\u76f8\u7b49\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 bge\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 bge.s\u00a0\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 bge.un\u00a0\u00a0\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6\uff0c\u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 bge.un.s\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6\uff0c\u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 bgt\u00a0\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 bgt.s\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 bgt.un\u00a0\u00a0\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6\uff0c\u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 bgt.un.s\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6\uff0c\u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 ble\u00a0\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 ble.s\u00a0\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 ble.un\u00a0\u00a0\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6\uff0c\u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 ble.un.s\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6\uff0c\u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u6743\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 blt\u00a0\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 blt.s\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 blt.un\u00a0\u00a0\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6\uff0c\u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 blt.un.s\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6\uff0c\u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u7b2c\u4e8c\u4e2a\u503c\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 bne.un\u00a0\u00a0\u00a0 \u5f53\u4e24\u4e2a\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u4e0d\u76f8\u7b49\u65f6\uff0c\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 bne.un.s\u00a0 \u5f53\u4e24\u4e2a\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u4e0d\u76f8\u7b49\u65f6\uff0c\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 br\u00a0\u00a0\u00a0\u00a0 \u65e0\u6761\u4ef6\u5730\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 br.s\u00a0\u00a0\u00a0\u00a0 \u65e0\u6761\u4ef6\u5730\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 brfalse\u00a0\u00a0 \u5982\u679c value \u4e3a false\u3001\u7a7a\u5f15\u7528\uff08Visual Basic \u4e2d\u7684 Nothing\uff09\u6216\u96f6\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 brfalse.s \u5982\u679c value \u4e3a false\u3001\u7a7a\u5f15\u7528\u6216\u96f6\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 brtrue\u00a0\u00a0\u00a0 \u5982\u679c value \u4e3a true\u3001\u975e\u7a7a\u6216\u975e\u96f6\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\u3002 brtrue.s\u00a0 \u5982\u679c value \u4e3a true\u3001\u975e\u7a7a\u6216\u975e\u96f6\uff0c\u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09\u3002 \u53ef\u4ee5\u53d1\u73b0, \u57fa\u672c\u90fd\u662f\u5404\u79cd\u5927\u4e8e\u5c0f\u4e8e\u7b49\u4e8e\u975e\u7a7a\u975e0\u7b49\u4ee5\u53ca\u6709\u7b26\u53f7\u65e0\u7b26\u53f7\u8fd9\u4e9b\u60c5\u51b5\u7684\u6392\u5217\u7ec4\u5408. \u4e0a\u8868\u4e2d\u6211\u4eec\u79f0\u9664\u4e86 br
\u4e0e br.s
\u6307\u4ee4\u5916\u7684\u6307\u4ee4\u4e3a \"\u6761\u4ef6\u8df3\u8f6c\u6307\u4ee4\", \u53cd\u4e4b\u6211\u4eec\u79f0\u4e3a \"\u65e0\u6761\u4ef6\u8df3\u8f6c\u6307\u4ee4\". \u8fd9\u91cc\u6211\u4eec\u53ea\u4f1a\u7b80\u5355\u4e3e\u4f8b br
brfalse
\u8fd9\u4e24\u4e2a\u6307\u4ee4\u7684\u4f7f\u7528. \u5176\u4ed6\u6307\u4ee4\u57fa\u672c\u53ea\u662f\u51e0\u4e2a\u6761\u4ef6\u4e0d\u540c\u7c7b\u578b\u4e0d\u540c\u7684\u5dee\u522b.
brfalse
\u6307\u4ee4\u4f1a\u4ece\u8bc4\u4f30\u6808\u4e0a\u5f39\u51fa\u4e00\u4e2a\u503c, \u7136\u540e\u67e5\u770b\u8be5\u503c\u662f\u5426\u4e3a false
\u6216\u8005 null
\u6216\u8005 0
, \u5982\u679c\u662f\u5219\u8df3\u8f6c\u5230\u53c2\u6570\u6240\u6307\u7684\u76ee\u6807\u4f4d\u7f6e, \u5426\u5219\u4e0d\u505a\u4efb\u4f55\u4e8b. \u6bd4\u5982\u5982\u4e0b C# \u4ee3\u7801:
public static void MyMethod(int value)\n{\n if (value == 0)\n {\n Console.WriteLine(\"value is 0!\");\n }\n else\n {\n Console.WriteLine(\"value is not 0.\");\n }\n}\n
\u987a\u4fbf\u8bb0\u5f97\u66f4\u6539\u6211\u4eec\u7684\u65b9\u6cd5\u5b9a\u4e49:
public static MethodInfo GenerateMethod(Action<ILGenerator> generateAction)\n{\n AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new(\"MyAssembly\"), AssemblyBuilderAccess.RunAndCollect);\n ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule(\"MyTestModule\");\n TypeBuilder typeBuilder = moduleBuilder.DefineType(\"MyType\");\n MethodBuilder methodBuilder = typeBuilder.DefineMethod(\"MyMethod\", MethodAttributes.Public | MethodAttributes.Static\n , typeof(void), new Type[] { typeof(int) });\n generateAction(methodBuilder.GetILGenerator());\n return typeBuilder.CreateType().GetMethod(\"MyMethod\")!;\n}\n\npublic static void Main()\n{\n MethodInfo methodInfo = GenerateMethod(il =>\n {\n // TODO implement the IL body\n });\n var action = methodInfo.CreateDelegate<Action<int>>();\n action(1);\n}\n
\u5176\u5bf9\u5e94 IL
\u4e3a:
var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar valueIs0Target = il.DefineLabel();\nil.Emit(OpCodes.Ldarg_0);\nil.Emit(OpCodes.Brfalse, valueIs0Target);\nil.Emit(OpCodes.Ldstr, \"value is not 0.\");\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\nil.MarkLabel(valueIs0Target);\nil.Emit(OpCodes.Ldstr, \"value is 0!\");\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
\u5728\u8fd9\u91cc, \u5728\u4f7f\u7528 System.Reflection.Emit
\u5e93\u7684\u60c5\u51b5\u4e0b, \u6211\u4eec\u5728\u4ee3\u7801\u7684\u7b2c 2 \u884c\u5b9a\u4e49\u4e86\u4e00\u4e2a Label, \u7528\u6765\u4e4b\u540e\u4f5c\u4e3a\u6761\u4ef6\u8df3\u8f6c\u6307\u4ee4\u7684\u53c2\u6570\u4f20\u5165, \u4e0d\u8fc7\u76ee\u524d\u8fd9\u4e2a Label \u6ca1\u6709\u6307\u5411\u4efb\u4f55 IL
\u6307\u4ee4\u4f4d\u7f6e, \u6240\u4ee5\u6211\u4eec\u5728\u7b2c 8 \u884c\u8c03\u7528 MarkLabel
\u65b9\u6cd5, \u8c03\u7528\u5b8c\u8be5\u65b9\u6cd5\u540e\u7684\u4e0b\u4e00\u6b21 Emit
\u7684 IL
\u6307\u4ee4\u7684\u4f4d\u7f6e\u4fe1\u606f\u5c31\u4f1a\u88ab\u8bbe\u7f6e\u5230 Label \u4e2d, \u89c2\u5bdf\u4e0a\u8ff0\u4ee3\u7801\u4e0d\u96be\u53d1\u73b0, \u6211\u4eec\u8bfb\u53d6\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570, \u5982\u679c\u4e3a 0 \u90a3\u4e48\u8df3\u8f6c\u5230\u8f93\u51fa value is 0!
\u7684 IL
\u6307\u4ee4\u6bb5\u524d, \u800c\u5f53\u975e 0 \u65f6\u4e0d\u505a\u4efb\u4f55\u4e8b\u8ba9\u5176\u81ea\u7136\u6267\u884c\u5230\u8f93\u51fa value is not 0.
\u7684 IL
\u6307\u4ee4\u6bb5\u524d, \u4f60\u53ef\u4ee5\u66f4\u6539\u8c03\u7528\u8fd9\u4e2a\u65b9\u6cd5\u7684\u4ee3\u7801\u7684\u5730\u65b9\u4f20\u5165\u7684\u53c2\u6570\u6765\u89c2\u5bdf\u5b83\u7684\u8f93\u51fa(\u6bd4\u5982\u5c06 action(1)
\u6539\u4e3a action(0)
). \u987a\u4fbf, \u5728\u8fd9\u4e2a\u6307\u4ee4\u6bb5\u540e\u9762\u7d27\u8ddf\u4e00\u4e2a ret
\u6307\u4ee4\u76f4\u63a5\u8fd4\u56de\u8be5\u65b9\u6cd5\u9632\u6b62\u8bef\u6267\u884c\u5230\u540e\u9762\u7684 IL
\u6bb5. \u4e0d\u8fc7\u8fd9\u53ea\u5728\u540e\u9762\u6ca1\u6709\u4ee3\u7801\u9700\u8981\u6267\u884c\u7684\u60c5\u51b5\u4e0b\u594f\u6548, \u5982\u679c\u540e\u9762\u4f9d\u7136\u6709\u4ee3\u7801\u7684\u8bdd\u6211\u4eec\u5c31\u5f97\u4f7f\u7528 br
\u6307\u4ee4\u4e86.
br
\u6307\u4ee4\u6267\u884c\u540e\u4f1a\u5c06\u76ee\u524d\u7684\u6267\u884c\u4f4d\u7f6e\u65e0\u6761\u4ef6\u7684\u8df3\u8f6c\u5230\u5bf9\u5e94\u4f4d\u7f6e, \u6bd4\u5982\u521a\u624d\u4ecb\u7ecd brfalse
\u6307\u4ee4\u672b\u5c3e\u7684\u4e00\u70b9\u5c0f\u95ee\u9898, \u5373\u6bd4\u5982\u5982\u4e0b C# \u4ee3\u7801:
if (value == 0)\n{\n Console.WriteLine(\"value is 0!\");\n}\nelse\n{\n Console.WriteLine(\"value is not 0.\");\n}\nConsole.WriteLine(\"always execute me!\");\n
\u5728\u672b\u5c3e\u6211\u4eec\u6709\u4e00\u4e2a\u65b9\u6cd5\u8c03\u7528\u662f\u65e0\u5173 value
\u7684\u503c\u7684, \u4e4b\u524d\u7684\u4ee3\u7801\u6211\u4eec\u4e3a\u4e86\u9632\u6b62\u8bef\u6267\u884c IL
\u6211\u4eec\u4f7f\u7528\u4e86 ret
\u6307\u4ee4\u76f4\u63a5\u8fd4\u56de\u6574\u4e2a\u65b9\u6cd5, \u4f46\u662f\u73b0\u5728\u8fd9\u91cc\u6211\u4eec\u65e0\u6cd5\u8fd9\u4e48\u5e72, \u4e0d\u8fc7\u73b0\u5728\u6709 br
\u6307\u4ee4\u53ef\u4ee5\u4f7f\u7528\u4e86:
var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar valueIs0Target = il.DefineLabel();\nvar afterIfTarget = il.DefineLabel();\nil.Emit(OpCodes.Ldarg_0);\nil.Emit(OpCodes.Brfalse, valueIs0Target);\nil.Emit(OpCodes.Ldstr, \"value is not 0.\");\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Br, afterIfTarget);\nil.MarkLabel(valueIs0Target);\nil.Emit(OpCodes.Ldstr, \"value is 0!\");\nil.Emit(OpCodes.Call, cw);\nil.MarkLabel(afterIfTarget);\nil.Emit(OpCodes.Ldstr, \"always execute me!\");\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
"},{"location":"trans/il/#s","title":".s
\u7cfb\u6307\u4ee4","text":"\u4f60\u53ef\u80fd\u53d1\u73b0\u4e86\u5c31\u662f\u4e00\u4e9b IL
\u6307\u4ee4\u540c\u65f6\u8fd8\u6709\u4e00\u4e2a\u5e26 .s
\u540e\u7f00\u7684\u7248\u672c, \u8fd9\u4e2a\u6211\u4eec\u4e00\u822c\u53eb\u5b83\u7684 \"\u77ed\u683c\u5f0f\" \u7248\u672c, \u53cd\u4e4b\u53eb \"\u957f\u683c\u5f0f\" \u7248\u672c, \u6bd4\u5982\u5c31\u521a\u624d\u7684 br
\u5bf9\u5e94\u7684 br.s
, \u901a\u5e38\u7c7b\u4f3c\u8fd9\u4e00\u5bf9 IL
\u6307\u4ee4\u7684\u533a\u522b\u5c31\u662f .s
\u7248\u672c\u7684\u53c2\u6570\u4f1a\u77ed\u4e00\u70b9, \u6bd4\u5982\u957f\u683c\u5f0f\u7248\u672c\u7684\u53c2\u6570\u957f\u5ea6\u662f 4 \u5b57\u8282, \u800c\u77ed\u683c\u5f0f\u7248\u672c\u7684\u53c2\u6570\u957f\u5ea6\u53ef\u80fd\u5c31\u662f 2 \u5b57\u8282, \u6ce8\u610f\u8fd9\u91cc\u4e0d\u662f\u8bf4\u7684\u662f\u538b\u5165\u8bc4\u4f30\u6808\u7684\u503c\u7684\u7c7b\u578b, \u957f\u77ed\u683c\u5f0f\u7248\u672c\u6240\u505a\u7684\u4e8b\u60c5\u662f\u5b8c\u5168\u4e00\u6837\u7684, \u53ea\u662f\u4f20\u53c2\u5141\u8bb8\u4f60\u7528\u77ed\u4e00\u70b9\u7684\u53c2\u6570. \u8fd9\u5176\u5b9e\u5c31\u662f\u4e00\u4e2a\u5bf9 IL
\u6307\u4ee4\u7684\u5927\u5c0f\u4f18\u5316, \u7f16\u8bd1\u5668\u901a\u5e38\u5c31\u4f1a\u80fd\u7528 .s
\u7248\u672c\u5c31\u7528 .s
\u7248\u672c, \u5f53\u53c2\u6570\u9700\u6c42\u8d85\u8fc7\u77ed\u683c\u5f0f\u53c2\u6570\u8868\u8fbe\u8303\u56f4\u65f6\u624d\u4f1a\u4f7f\u7528\u957f\u683c\u5f0f, \u5bf9\u4e8e\u6211\u4eec\u7684\u8bdd\u5982\u679c\u4f60\u60f3\u5fae\u5fae\u7684\u4f18\u5316\u4e00\u4e0b\u4f60\u7684 IL
\u7684\u5927\u5c0f\u7684\u8bdd, \u4f60\u53ef\u4ee5\u9009\u62e9\u5728\u53c2\u6570\u8303\u56f4\u591f\u7528\u7684\u60c5\u51b5\u4e0b\u4f7f\u7528 .s
\u7248\u672c.
"},{"location":"trans/il/#_12","title":"\u7ed3\u5c3e","text":"\u81f3\u6b64, \u4e00\u4e9b\u57fa\u672c\u7684 IL
\u4f60\u5df2\u4e86\u89e3, \u6211\u4eec\u5728\u8fd9\u91cc\u4ecb\u7ecd\u7684 IL
\u6307\u4ee4\u4e0d\u8fc7\u662f\u51b0\u5c71\u4e00\u89d2, \u8fd8\u6709\u5f88\u591a\u5176\u4ed6\u7684 IL
\u6307\u4ee4\u6ca1\u6709\u4ecb\u7ecd, \u4e0d\u8fc7\u5b83\u4eec\u5927\u540c\u5c0f\u5f02, \u57fa\u672c\u90fd\u662f\u5bf9\u8bc4\u4f30\u6808\u7684\u5404\u79cd\u5404\u6837\u7684\u64cd\u4f5c, \u6211\u4eec\u53ea\u9700\u8981\u5728\u7528\u5230\u65f6\u6216\u8005\u5076\u5c14\u7ffb\u9605\u4e00\u4e0b IL
\u6307\u4ee4\u8868\u5c31\u80fd\u4e86\u89e3. \u6b64\u5916, \u8fd8\u6709\u5f88\u591a\u6bd4\u5982\u65b9\u6cd5\u7684\u7b7e\u540d, fixed
, try-catch
\u7b49\u5185\u5bb9\u6211\u4eec\u8fd8\u6ca1\u6709\u6d89\u53ca\u5230, \u4e0d\u8fc7\u5230\u76ee\u524d\u4e3a\u6b62\u5bf9\u4e8e\u851a\u84dd modding \u5df2\u7ecf\u52c9\u5f3a\u591f\u7528\u4e86. \u518d\u6b64\u5916, \u5728 dnSpy \u7684 IL
\u4ee3\u7801\u7684\u89c6\u89d2\u65f6, \u70b9\u51fb IL
\u64cd\u4f5c\u7b26\u7684\u540d\u79f0\u53ef\u4ee5\u5f88\u65b9\u4fbf\u5730\u8df3\u8f6c\u5230 msdn \u4e0a\u5bf9\u8fd9\u4e2a\u6307\u4ee4\u7684\u63cf\u8ff0. \u90a3\u4e48, \u5728\u4e86\u89e3\u4f7f\u7528 System.Reflection.Emit
\u5e93\u540e, \u6211\u4eec\u5c31\u53ef\u4ee5\u4f7f\u7528 Mono.Cecil
\u5728\u851a\u84dd\u4e2d\u66f4\u6539\u851a\u84dd\u7684\u7a0b\u5e8f\u96c6\u4e86.
\u4e00\u4e9b\u53ef\u80fd\u6709\u7528\u7684\u8d44\u6e90:
OpCodes Fields - Microsoft Learn (https://learn.microsoft.com/...) \u7406\u89e3IL - Rorschach - \u77e5\u4e4e (https://zhuanlan.zhihu.com/...) IL\u6307\u4ee4\u8be6\u7ec6 - Zery - \u535a\u5ba2\u56ed (https://www.cnblogs.com/...) "},{"location":"trans/session_settings_savedata/","title":"Session, Settings, SaveData","text":"\u8fd9\u90e8\u5206\u5185\u5bb9\u5728 Everest Wiki \u91cc\u662f\u5728\u914d\u7f6e\u73af\u5883\u7684\u540c\u65f6\u8bf4\u7684, \u6211\u4e2a\u4eba\u8ba4\u4e3a\u5e94\u8be5\u63a8\u540e\u4e00\u70b9\u4f46\u662f\u4f3c\u4e4e\u73b0\u5728\u63a8\u540e\u7684\u6709\u70b9\u8fc7\u5934.
\u4f60\u5e94\u8be5\u8fd8\u8bb0\u5f97\u6211\u4eec\u6700\u5f00\u59cb\u7684\u90a3\u4e2a\u7ee7\u627f\u4e8e EverestModule
\u7684\u7c7b MyCelesteModModule
, \u5230\u76ee\u524d\u4e3a\u6b62\u6211\u4eec\u53ea\u4f7f\u7528\u4e86\u5b83\u7684 Load
\u65b9\u6cd5\u548c Unload
\u65b9\u6cd5\u7528\u4e8e\u52a0\u8f7d\u521d\u59cb\u5316\u6211\u4eec\u7684\u94a9\u5b50. \u5f53\u7136, \u8fd9\u80af\u5b9a\u662f\u4e0d\u6b62\u7684, \u90a3\u4e48\u8fd9\u4e00\u8282\u5c06\u4f1a\u805a\u7126\u4e8e EverestModule
\u7684\u66f4\u591a\u7684\u5185\u5bb9.
"},{"location":"trans/session_settings_savedata/#settings","title":"Settings","text":""},{"location":"trans/session_settings_savedata/#_1","title":"\u57fa\u672c","text":"Settings, \u987e\u540d\u601d\u4e49\u5c31\u662f\u9009\u9879\u7684\u610f\u601d. Everest \u4e3a\u6211\u4eec\u5c01\u88c5\u4e86\u4e00\u4e2a\u975e\u5e38\u4fbf\u5229\u7684\u7cfb\u7edf, \u6211\u4eec\u8981\u505a\u7684\u53ea\u662f\u7b80\u5355\u5730\u52a0\u5165\u5c5e\u6027, \u7136\u540e\u88c5\u9970\u51e0\u4e2a\u7b80\u5355\u7684\u7279\u6027, \u5c31\u80fd\u521b\u5efa\u51fa\u6613\u7528\u7684\u83dc\u5355\u9009\u9879, \u5269\u4e0b\u7684 ui \u65b9\u9762\u548c\u4fdd\u5b58\u8bfb\u53d6\u7684\u5de5\u4f5c\u90fd\u7531 Everest \u8d1f\u8d23.
\u5728\u6b64\u4e4b\u524d, \u6211\u4eec\u5148\u4fdd\u5b58\u4e00\u4e0b\u6211\u4eec\u7684 EverestModule
\u5b9e\u4f8b\u4ee5\u65b9\u4fbf\u6211\u4eec\u8bbf\u95ee\u5b83\u7684\u5b9e\u4f8b(Everest \u4f1a\u786e\u4fdd\u5b83\u662f\u5355\u4f8b\u7684):
public class MyCelesteModModule : EverestModule\n{\n public static MyCelesteModModule Instance { get; private set; }\n\n public override void Load()\n {\n Instance = this;\n }\n\n public override void Unload()\n {\n }\n}\n
\u7136\u540e\u65b0\u5efa\u4e00\u4e2a\u540d\u5b57\u6700\u597d\u4ee5 mod \u5f00\u5934, Settings
\u7ed3\u5c3e\u7684 MyCelesteModSettings
\u7c7b\u5e76\u7ee7\u627f EverestModuleSettings
:
public class MyCelesteModSettings : EverestModuleSettings\n{\n\n}\n
\u7136\u540e\u5728 module \u7c7b\u91cc\u8fd9\u6837\u6ce8\u518c\u8fd9\u4e2a\u7c7b:
public class MyCelesteModModule : EverestModule\n{\n public static MyCelesteModModule Instance { get; private set; }\n\n public override Type SettingsType => typeof(MyCelesteModSettings);\n public static MyCelesteModSettings Settings => (MyCelesteModSettings)Instance._Settings;\n\n public override void Load()\n {\n Instance = this;\n }\n\n public override void Unload()\n {\n }\n}\n
\u73b0\u5728, \u6211\u4eec\u5411\u9009\u9879\u4e2d\u65b0\u52a0\u4e00\u6761\u516c\u5f00\u7684 bool \u7c7b\u578b\u7684\u5c5e\u6027:
public class MyCelesteModSettings : EverestModuleSettings\n{\n public bool AnInterestingSwitch { get; set; }\n}\n
\u73b0\u5728\u76f4\u63a5\u7f16\u8bd1\u4f60\u7684\u9879\u76ee, \u7136\u540e\u4f60\u5e94\u8be5\u4f1a\u770b\u5230 Everest \u4e3a\u4f60\u5728 mod \u9009\u9879\u4e2d\u751f\u6210\u4e86\u8fd9\u6837\u4e00\u6761\u6709\u8da3\u7684\u8bbe\u7f6e:
\u968f\u540e\u4f60\u5c31\u80fd\u5728\u4f60 mod \u7684\u4efb\u4f55\u5730\u65b9\u7528 MyCelesteModSettings.Settings.AnInterestingSwitch
\u6765\u8bbf\u95ee\u8fd9\u4e2a\u5f00\u5173\u4e86.
\u9664\u6b64\u4e4b\u5916 Everest \u8fd8\u652f\u6301\u679a\u4e3e, \u5b57\u7b26\u4e32\u548c\u6570\u5b57, \u5b83\u4eec\u5206\u522b\u4f1a\u751f\u6210\u8fd9\u6837\u7684\u9009\u9879:
public class MyCelesteModSettings : EverestModuleSettings\n{\n public bool AnInterestingSwitch { get; set; }\n\n [SettingRange(0, 100)]\n public int AnInteger { get; set; }\n\n public string AString { get; set; }\n\n public DayOfWeek DayOfWeek { get; set; }\n}\n
Info
AString
\u90a3\u6761\u9009\u9879\u662f\u4e00\u4e2a\u6309\u94ae, \u6309\u4e0b\u540e\u4f1a\u8fdb\u5165\u6587\u5b57\u8f93\u5165\u754c\u9762, \u5192\u53f7\u540e\u9762\u4f1a\u8ddf\u73a9\u5bb6\u8f93\u5165\u4e86\u7684\u6587\u5b57. DayOfWeek
\u9009\u9879\u5141\u8bb8\u4f60\u5de6\u53f3\u9009\u62e9 DayOfWeek
\u679a\u4e3e\u4e2d\u7684\u6bcf\u4e00\u9879.
\u5176\u4e2d int \u90a3\u6761\u5c5e\u6027\u9700\u8981\u88c5\u9970 SettingRange
\u7279\u6027\u5e76\u6307\u5b9a\u6700\u5927\u6700\u5c0f\u503c, \u5426\u5219 Everest \u4f1a\u62d2\u7edd\u751f\u6210\u5b83, \u6b64\u5916\u5b83\u8fd8\u6709\u4e2a\u53c2\u6570\u53ef\u4ee5\u7528\u6765\u6307\u5b9a\u8be5\u9009\u9879\u662f\u5426\u9700\u8981 \"\u5927\u7684\u8303\u56f4\" (LargeRange
), \u5982\u679c\u6307\u5b9a\u4e3a true, \u5219\u957f\u6309\u8c03\u6574\u8be5\u503c\u65f6\u7684\u589e\u957f\u901f\u5ea6\u4f1a\u6162\u6162\u589e\u52a0\u4ee5\u4fbf\u5feb\u901f\u8c03\u6574\u81f3\u66f4\u5927/\u5c0f\u7684\u503c.
\u9664\u4e86 SettingRange
\u7279\u6027, \u8fd8\u6709\u66f4\u591a\u5176\u4ed6\u7684\u7279\u6027\u7528\u4e8e\u6307\u793a\u8be5\u9009\u9879\u7684\u4e00\u4e9b\u6027\u8d28:
SettingNeedsRelauch
: \u6307\u793a\u8be5\u9009\u9879\u9700\u8981\u91cd\u542f\u6e38\u620f\u751f\u6548. SettingNumberInput
: \u5982\u679c\u8be5\u9009\u9879\u5bf9\u5e94\u7684\u5c5e\u6027\u662f\u4e2a\u6570\u5b57(int, float), \u90a3\u4e48\u4f7f\u7528\u8f93\u5165\u6587\u5b57\u7684\u83dc\u5355\u6765\u8f93\u5165\u6570\u5b57\u800c\u4e0d\u662f\u5de6\u53f3\u5207\u6362\u6570\u5b57. allowNegatives
: \u662f\u5426\u5141\u8bb8\u8d1f\u6570 maxLength
: \u5b57\u7b26\u4e32\u6700\u5927\u957f\u5ea6 SettingMaxLength
: \u8bbe\u7f6e\u8be5\u5b57\u7b26\u4e32\u9009\u9879\u7684\u6700\u5927\u957f\u5ea6. \u5426\u5219\u9ed8\u8ba4 12 \u4e2a\u5b57\u7b26. max
: \u6700\u5927\u957f\u5ea6 SettingInGame
: \u6307\u793a\u8be5\u9009\u9879\u662f\u5426\u51fa\u73b0\u5728\u6e38\u620f\u5185(\u56fe\u5185)\u83dc\u5355\u4e2d. SettingIgnore
: \u6307\u793a\u662f\u5426\u5ffd\u7565\u8be5\u9009\u9879\u88ab\u52a0\u5165\u83dc\u5355, \u6ce8\u610f\u5ffd\u7565\u540e\u4f9d\u7136\u4f1a\u88ab Everest \u6b63\u5e38\u8bfb\u53d6\u4fdd\u5b58. YamlIgnore
: \u6307\u793a\u662f\u5426\u5ffd\u7565\u8be5\u5c5e\u6027\u7684\u4fdd\u5b58. Note
YamlIgnore
\u4f4d\u4e8e\u547d\u540d\u7a7a\u95f4 YamlDotNet.Serialization
\u5185.
"},{"location":"trans/session_settings_savedata/#_2","title":"\u672c\u5730\u5316","text":"\u4f60\u53ef\u80fd\u4f1a\u53d1\u73b0\u9ed8\u8ba4\u751f\u6210\u7684\u9009\u9879\u540d\u5b57\u5c31\u662f\u5c5e\u6027\u540d, \u5c3d\u7ba1\u6211\u4eec\u901a\u5e38\u80fd\u731c\u5230\u5b83\u7684\u610f\u601d\u4ee5\u53ca\u5b83\u4f1a\u5e72\u4ec0\u4e48, \u4f46\u662f\u73a9\u5bb6\u4eec\u901a\u5e38\u4e0d\u4f1a, \u6240\u4ee5\u6211\u4eec\u8fd8\u5f97\u4e3a\u5176\u914d\u7f6e\u672c\u5730\u5316, \u5176\u5c31\u5305\u542b\u4e86\u6211\u4eec\u901a\u5e38\u8bb2\u7684 \"\u6c49\u5316\", \"\u4e2d\u6587\u7ffb\u8bd1\".
\u5728\u8fd9\u91cc, \u6211\u4eec\u9700\u8981\u7684\u672c\u5730\u5316\u952e\u540d\u662f modoptions_{\u7c7b\u540d}_{\u5c5e\u6027\u540d}
, \u4f8b\u5982\u5982\u4e0b\u7c7b:
public class MyCelesteModSettings : EverestModuleSettings\n{\n public bool EnableFunnyThing { get; set; }\n}\n
\u5176\u4e2d\u90a3\u6761\u5c5e\u6027\u5bf9\u5e94\u7684\u672c\u5730\u5316\u952e\u540d\u5219\u662f: modoptions_mycelestemod_enablefunnything
, \u6240\u4ee5\u6211\u4eec\u5c06\u5176\u5199\u5728 Dialog \u6587\u4ef6\u91cc:
ModFolder/Dialog/Simplified Chinese.txtmodoptions_mycelestemod_enablefunnything=\u5f00\u542f\u6709\u8da3\u7684\u4e1c\u897f\n
ModFolder/Dialog/english.txtmodoptions_mycelestemod_enablefunnything=Enable funny thing\n
Note
\u5982\u679c\u4f60\u4e0d\u77e5\u9053 dialog \u6587\u4ef6\u662f\u4ec0\u4e48\u7684\u8bdd, \u4f60\u53ef\u4ee5\u8be2\u95ee mapper \u4eec, \u6216\u8005\u5728\u8fd9\u91cc\u4f60\u5c31\u5e72\u8106\u7167\u505a, \u4e5f\u5c31\u662f\u65b0\u5efa\u5982\u5176\u6807\u9898\u6240\u5c55\u793a\u7684\u6587\u4ef6\u7136\u540e\u7c98\u8d34\u5bf9\u5e94\u5185\u5bb9.
\u6b64\u5916, mod \u9009\u9879\u7684\u5927\u6807\u9898\u4e5f\u6709\u4e2a\u672c\u5730\u5316\u952e\u540d, \u76f8\u5bf9\u4e8e\u4e0a\u9762\u7684\u952e\u540d\u53ea\u662f\u5c06\u5c5e\u6027\u540d\u6362\u6210\u4e86 title
, \u4f8b\u5982\u4ee5\u4e0b dialog \u6587\u4ef6:
ModFolder/Dialog/Simplified Chinese.txtmodoptions_mycelestemod_enablefunnything=\u5f00\u542f\u6709\u8da3\u7684\u4e1c\u897f\nmodoptions_mycelestemod_title=\u6211\u7684\u6709\u8da3 mod \u7684\u8bbe\u7f6e (MyCelesteMod)\n
ModFolder/Dialog/english.txtmodoptions_mycelestemod_enablefunnything=Enable funny thing\nmodoptions_mycelestemod_title=funny MyCelesteMod\n
Note
\u65f6\u523b\u8bb0\u5f97\u586b\u5145 english.txt
, \u56e0\u4e3a\u5982\u679c\u5176\u4ed6\u8bed\u8a00\u6ca1\u627e\u5230\u8fd9\u4e2a\u952e\u540d\u4f1a\u9ed8\u8ba4\u56de\u9000\u5230 english
, \u5982\u679c\u518d\u6ca1\u6709\u7684\u8bdd\u5c31\u4f1a\u76f4\u63a5\u5c55\u793a\u4e11\u964b\u7684\u952e\u540d.
\u672c\u5730\u5316\u952e\u540d\u5e76\u4e0d\u662f\u56fa\u5b9a\u7684, \u4f60\u53ef\u4ee5\u4f7f\u7528 SettingName
\u88c5\u9970\u5230\u7c7b\u4e0a\u6216\u8005\u5c5e\u6027\u4e0a\u6765\u4fee\u6539\u5b83, \u4e0d\u8fc7\u6211\u4e2a\u4eba\u4e0d\u662f\u5f88\u5efa\u8bae\u4fee\u6539\u5b83, \u56e0\u4e3a\u9ed8\u8ba4\u7684\u503c\u4f5c\u4e3a\u952e\u540d\u5b8c\u5168\u591f\u7528, \u6b64\u5916\u8fd8\u6709\u4e00\u4e2a SettingSubText
\u7279\u6027, \u5b83\u53ef\u4ee5\u5411\u8be5\u9009\u9879\u88ab\u9009\u4e2d\u65f6\u5728\u5e95\u4e0b\u663e\u793a\u4e00\u884c\u5c0f\u5b57, \u5b83\u7684\u53c2\u6570\u540c\u6837\u662f\u4e2a\u672c\u5730\u5316\u952e\u540d, \u7c7b\u4f3c\u7684\u8fd8\u6709 SettingSubHeader
\u7279\u6027, \u5b83\u4f1a\u5411\u8be5\u9009\u9879\u4e4b\u524d\u52a0\u5165\u4e00\u4e2a\u5c0f\u6807\u9898.
\u5bf9\u4e8e\u679a\u4e3e\u6bcf\u4e00\u9879\u7684\u503c\u53ef\u4ee5\u4f7f\u7528 modoptions_{\u7c7b\u540d}_{\u5c5e\u6027\u540d}_{\u679a\u4e3e\u9879\u540d}
\u6765\u6307\u5b9a, \u4f8b\u5982\u5bf9\u4e8e DayOfWeek
\u679a\u4e3e\u7c7b\u578b\u7684 Day
\u5c5e\u6027:
ModFolder/Dialog/Simplified Chinese.txtmodoptions_mycelestemod_day_sunday=\u661f\u671f\u65e5\nmodoptions_mycelestemod_day_monday=\u661f\u671f\u4e00\nmodoptions_mycelestemod_day_tuesday=\u661f\u671f\u4e8c\nmodoptions_mycelestemod_day_wednesday=\u661f\u671f\u4e09\nmodoptions_mycelestemod_day_thursday=\u661f\u671f\u56db\nmodoptions_mycelestemod_day_friday=\u661f\u671f\u4e94\nmodoptions_mycelestemod_day_saturday=\u661f\u671f\u516d\n
Info
\u5982\u679c\u4f60\u5b9e\u9645\u6d4b\u8bd5\u7684\u8bdd\u4f60\u4f1a\u53d1\u73b0 \u4e09
\u5b57\u548c \u4e94
\u5b57\u6ca1\u6709\u6e32\u67d3\u51fa\u6765, \u8fd9\u662f\u6b63\u5e38\u7684, \u56e0\u4e3a\u851a\u84dd\u7684\u5b57\u5e93\u4e2d\u6ca1\u6709\u8fd9\u4e24\u4e2a\u5b57, \u8fd9\u91cc\u6211\u5c31\u4e0d\u8d58\u8ff0\u5982\u4f55\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u4e86, \u5177\u4f53\u53ef\u4ee5\u54a8\u8be2 mapper \u4eec. (\u65e5\u5e38\u5077\u61d2.jpg)
"},{"location":"trans/session_settings_savedata/#_3","title":"\u6700\u540e","text":"\u6216\u8bb8\u4f60\u4e5f\u5df2\u7ecf\u731c\u5230\u4e86, Everest \u6b63\u662f\u4f7f\u7528\u7684 Yaml \u6765\u5e8f\u5217\u5316/\u53cd\u5e8f\u5217\u5316\u4f60\u7684 Settings
\u7c7b, \u6240\u4ee5\u8bf7\u52a1\u5fc5\u4e0d\u8981\u5728\u4f60\u7684 Settings
\u7c7b\u4e2d\u653e\u7f6e\u5947\u602a\u7684\u7c7b\u548c\u7ed3\u6784\u4f53! \u5982\u679c\u4f60\u8981\u8fd9\u4e48\u505a\u8bf7\u786e\u4fdd Everest \u80fd\u6b63\u786e\u5730\u5e8f\u5217\u5316/\u53cd\u5e8f\u5217\u5316\u4f60\u7684 Settings
\u7c7b, \u5426\u5219\u4f60\u7684\u8bbe\u7f6e\u5c06\u4e0d\u4f1a\u88ab\u6b63\u5e38\u4fdd\u5b58, \u6c38\u8fdc\u90fd\u662f\u9ed8\u8ba4\u503c.
"},{"location":"trans/session_settings_savedata/#session","title":"Session","text":""},{"location":"trans/session_settings_savedata/#_4","title":"\u57fa\u672c","text":"Session \u662f\u4e00\u4e2a\u851a\u84dd\u4e2d\u4fdd\u5b58\u6570\u636e\u7684\u6982\u5ff5, \u5b83\u7528\u4e8e\u4fdd\u5b58 \"\u4fdd\u5b58\u5e76\u9000\u51fa\" \u6309\u94ae\u6309\u4e0b\u540e\u6240\u4fdd\u5b58\u7684\u6570\u636e, \u4f8b\u5982\u5f53\u524d\u5df2\u6fc0\u6d3b\u7684 Flag, \u91cd\u751f\u70b9, \u5df2\u62fe\u53d6\u7684\u94a5\u5319, \u8349\u8393, \u6838\u5fc3\u7684\u6a21\u5f0f\u7b49. \u5728\u81ea\u5b9a\u4e49\u4f60\u81ea\u5df1\u7684 Session
\u540e, \u4f60\u53ef\u4ee5\u5728\u8fd9\u91cc\u4fdd\u5b58\u4f60\u81ea\u5df1\u72ec\u6709\u7684\u6536\u96c6\u7269\u4fe1\u606f, \u6216\u8005\u662f\u4e00\u4e9b\u5b9e\u4f53\u9700\u8981\u4e34\u65f6\u4fdd\u5b58\u4e8e\u5173\u5361\u7684\u6570\u636e. \u4e0e Settings \u76f8\u540c, \u6211\u4eec\u9700\u8981\u5148\u521b\u5efa\u4e00\u4e2a\u7ee7\u627f\u4e8e EverestModuleSession
\u7684\u7c7b, \u7136\u540e\u5728\u6a21\u5757\u7c7b\u4e2d\u58f0\u660e\u5b83:
MyCelesteModSession.csnamespace Celeste.Mod.MyCelesteMod;\n\npublic class MyCelesteModSession : EverestModuleSession\n{\n}\n
MyCelesteModModule.csnamespace Celeste.Mod.MyCelesteMod;\n\npublic class MyCelesteModModule : EverestModule\n{\n public static MyCelesteModModule Instance { get; private set; }\n\n public override Type SettingsType => typeof(MyCelesteModSettings);\n public static MyCelesteModSettings Settings => (MyCelesteModSettings)Instance._Settings;\n\n public override Type SessionType => typeof(MyCelesteModSession);\n public static MyCelesteModSession Session => (MyCelesteModSession)Instance._Session;\n\n public override void Load()\n {\n Instance = this;\n }\n\n public override void Unload()\n {\n }\n}\n
\u7136\u540e\u6211\u4eec\u5c31\u53ef\u4ee5\u5728\u4efb\u4f55\u6e38\u620f\u5904\u4e8e\u5173\u5361\u5185\u7684\u65f6\u5019\u4f7f\u7528 MyCelesteModModule.Session
\u6765\u8bbf\u95ee\u6211\u4eec\u7684 Session \u4e86. \u5982\u679c\u4f60\u5c1d\u8bd5\u5728\u6e38\u620f\u4e0d\u5728\u5173\u5361\u5185\u65f6\u8bfb\u53d6\u5b83, \u90a3\u4e48\u4f60\u4f1a\u5f97\u5230\u4e00\u4e2a null
\u503c.
\u5047\u8bbe\u6211\u4eec\u78b0\u4e86 SetPassByRefillDashesTrigger
\u4e4b\u540e\u53c8\u78b0\u5230 ChangeRespawnTrigger
\u6539\u53d8\u4e86\u91cd\u751f\u70b9, \u7528 Save And Quit
\u9000\u51fa\u4e86\u6e38\u620f, \u518d\u6b21\u8fdb\u5165\u65f6\u4f60\u4f1a\u53d1\u73b0\u91cd\u751f\u70b9\u662f\u65b0\u7684, \u800c PassByRefill
\u7684\u51b2\u523a\u6570\u53c8\u53d8\u56de 1
\u4e86, \u6240\u4ee5\u63a5\u4e0b\u6765\u6211\u4eec\u5c1d\u8bd5\u901a\u8fc7 Session
\u6765\u4fee\u6b63\u8fd9\u4e2a\u9519\u8bef.
MyCelesteModSession.csnamespace Celeste.Mod.MyCelesteMod;\n\npublic class MyCelesteModSession : EverestModuleSession\n{\n public Dictionary<string, int> RoomIdToPassByRefillDashes = new(); // \u6211\u4eec\u5c06\u8bb0\u5f55\u6bcf\u4e2a\u623f\u95f4\u540d\u5bf9\u5e94\u7684PassByRefill\u7684\u51b2\u523a\u6570\n}\n
SetPassByRefillDashesTrigger.csusing Celeste.Mod.Entities;\n\nnamespace MyCelesteMod;\n\n[CustomEntity(\"MyCelesteMod/SetPassByRefillDashesTrigger\")]\npublic class SetPassByRefillDashesTrigger : Trigger\n{\n public int Dashes;\n\n public SetPassByRefillDashesTrigger(EntityData data, Vector2 offset)\n : base(data, offset)\n {\n Dashes = data.Int(\"dashes\");\n }\n\n public override void OnEnter(Player player)\n {\n base.OnEnter(player);\n MyCelesteModModule.Session.RoomIdToPassByRefillDashes[SceneAs<Level>().Session.LevelData.Name] = Dashes;\n }\n}\n
PassByRefill.csusing Celeste.Mod.Entities;\n\nnamespace MyCelesteMod;\n\n[CustomEntity(\"MyCelesteMod/PassByRefill\")]\npublic class PassByRefill : Entity\n{\n private int _dashes = 1;\n\n public int Dashes => MyCelesteModModule.Session.RoomIdToPassByRefillDashes.GetValueOrDefault(SceneAs<Level>().Session.LevelData.Name, _dashes);\n\n private Image image;\n\n public PassByRefill(Vector2 position, int dashes)\n {\n Depth = 1;\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(64, 64);\n Collider = hitbox;\n\n MTexture tex = GFX.Game[\"MyCelesteMod/pass_by_refill\"];\n image = new(tex);\n Add(image);\n }\n\n public PassByRefill(EntityData data, Vector2 offset)\n : this(data.Position + offset, data.Int(\"dashes\"))\n {\n }\n\n public override void Update()\n {\n base.Update();\n var player = Scene.Tracker.GetEntity<Player>();\n if (player is not null && CollideCheck(player))\n {\n player.Dashes = Dashes;\n }\n }\n}\n
"},{"location":"trans/session_settings_savedata/#savedata","title":"SaveData","text":"\u987e\u540d\u601d\u4e49, SaveData
\u7528\u6765\u4fdd\u5b58\u4e00\u4e9b\u6301\u4e45\u5316\u6570\u636e, \u4f8b\u5982\u5f53\u524d\u5b58\u6863\u603b\u65f6\u95f4, \u603b\u6b7b\u4ea1\u6570, \u603b\u8349\u8393\u6570\u7b49. \u4f7f\u7528\u5b83\u4e0e\u4f7f\u7528 Session
\u6781\u5176\u76f8\u4f3c:
MyCelesteModSaveData.csnamespace Celeste.Mod.MyCelesteMod;\n\npublic class MyCelesteModSaveData : EverestModuleSaveData\n{\n}\n
MyCelesteModModule.csnamespace Celeste.Mod.MyCelesteMod;\n\npublic class MyCelesteModModule : EverestModule\n{\n public static MyCelesteModModule Instance { get; private set; }\n\n public override Type SettingsType => typeof(MyCelesteModSettings);\n public static MyCelesteModSettings Settings => (MyCelesteModSettings)Instance._Settings;\n\n public override Type SessionType => typeof(MyCelesteModSession);\n public static MyCelesteModSession Session => (MyCelesteModSession)Instance._Session;\n\n public override Type SaveDataType => typeof(MyCelesteModSaveData);\n public static MyCelesteModSaveData SaveData => (MyCelesteModSaveData)Instance._SaveData;\n\n public override void Load()\n {\n Instance = this;\n }\n\n public override void Unload()\n {\n }\n}\n
"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\u200b\\u3000\\-\u3001\u3002\uff0c\uff0e\uff1f\uff01\uff1b]+","pipeline":["stemmer"]},"docs":[{"location":"","title":"\u9996\u9875","text":"\u672c\u7cfb\u5217\u6559\u7a0b\u4e3b\u8981\u5199\u81ea\u4e8e\u4e2a\u4eba\u5728\u5236\u4f5c\u851a\u84dd CodeMod \u7684\u4e00\u4e9b\u7ecf\u9a8c \u672c\u7f51\u7ad9\u5185\u5bb9\u5f00\u6e90\u5728: github.com/Saplonily/CelesteModTutorial \u5341\u5206\u6b22\u8fce\u6765\u63d0 pr \u548c issue \u4ee5\u4fee\u590d\u5404\u79cd\u8bed\u6cd5\u9519\u8bef, \u7528\u8bcd\u9519\u8bef\u548c\u5185\u5bb9\u9519\u8bef\u4ee5\u53ca\u5efa\u8bae_(:\u0437\u300d\u2220)_
\u5927\u90e8\u5206\u6587\u7ae0\u53ef\u80fd\u4f1a\u5199\u7684\u4e0d\u660e\u4e0d\u767d\u4ee5\u81f3\u4e8e\u9700\u8981\u9891\u7e41\u4fee\u6539, \u5982\u679c\u4f60\u6709\u66f4\u597d\u7684\u4fee\u6539\u5efa\u8bae\u7684\u8bdd\u6b22\u8fce\u6765\u63d0 issue.
\u90a3\u4e48\u4e00\u5207\u5c31\u7eea, \u53ef\u4ee5\u5f00\u59cb\u9605\u8bfb \u5165\u95e8-\u7b2c\u4e00\u8282 \u4e86:
\u5f00\u59cb - Celeste Everest MonoMod
\u987a\u4fbf\u611f\u8c22\u4e00\u4e9b\u4e3a\u672c\u6559\u7a0b\u8d21\u732e\u7684\u4eba:
Apple Sheep - \u5728\u5199\u4f5c\u521d\u671f\u63d0\u4f9b\u4e86\u5927\u91cf\u4fee\u6539\u5efa\u8bae (Bilibili) \u591c\u8c37\u7d2b\u5e7d - \u4e3a\u914d\u7f6e\u73af\u5883\u8282\u63d0\u4f9b\u4e86\u4f7f\u7528\u6a21\u677f\u7684\u5efa\u8bae (Bilibili) \u7535\u7bb1 - \u5236\u4f5c\u4e86\u5305\u542b\u57fa\u7840 Loenn \u4f7f\u7528\u6559\u7a0b\u7684\u4f5c\u56fe\u6559\u7a0b (Bilibili) Lucky boy - Session, Settings, SaveData \u8282\u7684\u4e00\u4e9b\u8865\u5145, \u4ee5\u53ca\u94a9\u53d6 Helper \u65b9\u6cd5, debug, tracker, flag, tag \u8282\u7684\u4f5c\u8005 (GitHub) \u4ee5\u53ca\u6211\u81ea\u5df1 :D
Saplonily (Bilibili, Outlook) \u4ee5\u53ca\u6559\u7a0b\u5927\u90e8\u5206\u5185\u5bb9\u7684\u6765\u6e90:
\u548c\u4e00\u5207\u7684\u57fa\u7840:
\u5728\u7f51\u7ad9\u4e2d\u7684\u4ee3\u7801\u5757\u4e2d\u7684\u4e00\u4e9b\u9ad8\u4eae\u5728\u6a2a\u5411\u6eda\u52a8\u65f6\u4f1a\u53d1\u751f\u622a\u65ad, \u5373\u9ad8\u4eae\u5e76\u6ca1\u6709\u8986\u76d6\u6574\u884c, \u8fd9\u4e2a\u662f mkdocs-material
\u81ea\u8eab\u7684 bug, \u800c\u4e14\u770b\u4e0a\u53bb\u8bf4\u662f\u4fee\u590d\u8d77\u6765\u5f88\u56f0\u96be, issue \u94fe\u63a5: mkdocs-material issue #452.
bug \u4e8e\u4e0b:
t11ntpj808mbc1gu4lx7n9d8tj5q3ck3t1c0aclc Liquorice oat cake carrot cake. Halvah lemon drops bear claw fruitcake. Marshmallow danish jelly-o toffee.\njqlksiohper0brg9x2ajcm7ajjf8ptjxprqstvda Apple pie cake jelly-o sugar plum.\nx3mjly0wn48wy7lgf2bfymbykommv8dbyp7an1n8 Toffee candy brownie carrot cake jujubes sweet roll chocolate gingerbread.\nq0b5pj6eacuwj3t1i4jv7yxf00mi6osc0h5etcfz Cupcake tiramisu danish brownie danish jujubes gingerbread toffee gummi bears.\nu25qzla31ahqxd2x6b2wgpbxvw88h5w6mujoqtuq Fruitcake jelly beans candy canes icing pastry liquorice. Bear claw tart chocolate sweet souffl\u00e9 sweet roll marshmallow ice cream liquorice.\n9xcjy4nvh1jinka64lkdr1nhagm8odp0frr56nks Bear claw tootsie roll toffee biscuit cotton candy macaroon. \n5rmcwguz3jzws8w1hh2jbfdau74jip3f8rbu10oy Pudding caramels carrot cake sweet roll danish oat cake.\ns50wqctf9059ets5ezp4oeq7p6pfr24ntww2d15v Oat cake macaroon pastry cheesecake. Dessert topping chocolate bar. \nvue3y73jcwsg5um4pw8aqhuv3njgtg9iq0ortx5p Sesame snaps candy canes muffin lollipop wafer. \n1o6edje4xcb7vtcvct4ghawafdvmvgkx4r0scny5 Macaroon pudding gingerbread. \n
\u672c\u7cfb\u5217\u5185\u5bb9\u4f9d\u636eCC BY-SA 4.0\u8bb8\u53ef\u8bc1\u8fdb\u884c\u6388\u6743
"},{"location":"arc/basic_env/","title":"\u57fa\u7840\u73af\u5883\u914d\u7f6e - \u65e7","text":""},{"location":"arc/basic_env/#_1","title":"\u9879\u76ee\u521b\u5efa","text":"\u5728vs\u521b\u5efa\u9879\u76ee\u9875\u9762\u4e2d\u6211\u4eec\u9700\u8981\u9009\u62e9\u8fd9\u4e2a:
\u6ce8\u610f\u8981\u9009\u5e26 .NET Framework
\u5b57\u6837\u7684, \u851a\u84dd\u7684\u5e95\u5c42\u6846\u67b6\u76f8\u5bf9\u4e8e\u76ee\u524d\u7684 .NET
\u5df2\u7ecf\u5f88\u53e4\u8001\u4e86, \u6240\u4ee5\u53ef\u80fd\u4f1a\u88ab\u7a0d\u5fae\u7279\u6b8a\u70b9\u5bf9\u5f85(, \u4e4b\u540e\u5728\u4e3a\u9879\u76ee\u547d\u540d\u7684\u7a97\u53e3\u4e2d\u7684\u9879\u76ee\u6846\u67b6\u8bb0\u5f97\u7cbe\u786e\u9009\u62e9 .NET Framework 4.5.2
.
\u5982\u679c\u4f60\u6ca1\u6709 .NET Framework 4.5.2
\u7684\u9009\u9879\u8bf7\u68c0\u67e5\u662f\u5426\u5b89\u88c5\u4e86\u6b64\u6846\u67b6, \u5e76\u4e14\u4f60\u9009\u62e9\u7684\u662f\u5e26 .NET Framework
\u5b57\u6837\u7684\u7c7b\u5e93\u9879\u76ee.
\u5f53\u4f60\u521b\u5efa\u5b8c\u9879\u76ee\u540e, \u4f60\u4f1a\u5f97\u5230\u4e00\u4e2a\u4ee3\u7801\u6587\u4ef6 Class1.cs
, \u5b83\u770b\u8d77\u6765\u50cf: Class1.cs
using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace MyCelesteMod\n{\n public class Class1\n {\n\n }\n}\n
"},{"location":"arc/basic_env/#_2","title":"\u6dfb\u52a0\u5bf9\u851a\u84dd\u7684\u5f15\u7528","text":"\u56e0\u4e3a\u6211\u4eec\u662f\u851a\u84dd mod \u561b, \u6240\u4ee5\u80af\u5b9a\u5f97\u4f9d\u8d56\u4e00\u4e9b\u851a\u84dd\u7684\u4e1c\u897f, \u5373\u4f9d\u8d56\u4e8e\u851a\u84dd\u7684\u7a0b\u5e8f\u96c6. \u5177\u4f53\u64cd\u4f5c\u6765\u8bf4:
\u5728\u89e3\u51b3\u65b9\u6848\u89c6\u56fe\u7a97\u53e3\u4f60\u7684\u9879\u76ee\u4e0b\u7684\u5f15\u7528
\u4e0a\u53f3\u51fb \u9009\u62e9\u6dfb\u52a0\u5f15\u7528
\u5728\u65b0\u7684\u7a97\u53e3\u9009\u62e9\u5de6\u4fa7\u7684\u6d4f\u89c8
\u70b9\u51fb\u7a97\u53e3\u53f3\u4e0b\u89d2\u7684\u6d4f\u89c8
\u5b8c\u6210\u540e\u5728\u5f39\u51fa\u7684\u6587\u4ef6\u9009\u62e9\u6846\u4e2d\u9009\u62e9\u4ee5\u4e0b\u51e0\u4e2a\u5728\u851a\u84dd\u6839\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6: Celeste.exe
FNA.dll
MMHOOK_Celeste.dll
YamlDotNet.dll
\u5bf9\u4e8e steam \u7248\u851a\u84dd\u7684\u76ee\u5f55\u901a\u5e38\u4f1a\u5728 C:\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste
\u53e6\u5916\u4e3a\u4e86\u4fdd\u8bc1\u4f60\u7684 mod \u7684\u8de8\u5e73\u53f0\u6027, \u4f60\u7684\u5f15\u7528\u5217\u8868\u91cc System
\u5f00\u5934\u7684\u53ea\u80fd\u5305\u542b:
System
System.Configuration
System.Core
System.Data
System.Drawing
System.Runtime.Serialization
System.Security
System.Xml
System.Xml.Linq
\u5982\u679c\u4f60\u7684\u9879\u76ee\u5f15\u7528\u6709\u5176\u4ed6 System
\u5f00\u5934\u7cfb\u5217\u7684\u5f15\u7528, \u5e76\u4e14\u5b83\u4eec\u4e0d\u5728\u4e0a\u8ff0\u5217\u8868\u4e0a, \u4f60\u9700\u8981\u5c06\u5176\u79fb\u9664(\u53f3\u952e->\u79fb\u9664).
"},{"location":"arc/basic_env/#module","title":"\u6dfb\u52a0 Module \u7c7b","text":"ok\u5728\u6211\u4eec\u4e00\u756a\u6298\u817e\u4e0b\u6211\u4eec\u7ec8\u4e8e\u53ef\u4ee5\u5f00\u59cb\u6765\u5199\u4ee3\u7801\u4e86, \u90a3\u4e48\u9996\u5148\u628a\u4f60\u7684 Class1.cs
\u91cd\u547d\u540d\u6210 (\u4f60\u7684mod\u540d)Module.cs
, \u6bd4\u5982\u8fd9\u91cc\u6211\u7684 mod \u540d\u53eb MyCelesteMod
, \u90a3\u4e48\u8fd9\u4e2a\u6587\u4ef6\u6700\u597d\u53eb\u505a MyCelesteModModule.cs
, \u8fd9\u662f\u4e3a\u4e86\u65b9\u4fbf\u65e5\u540e\u5f00\u53d1\u80fd\u4e00\u773c\u8bc6\u522b\u51fa\u8fd9\u662f\u6211\u4eec\u6700\u65e9\u671f\u521b\u5efa\u7684\u90a3\u4e2a\u5173\u952e\u7c7b.
\u5982\u679c\u4f60\u7684 vs \u63d0\u793a\u4f60\u662f\u5426\u91cd\u547d\u540d\u6807\u8bc6\u7b26, \u4f60\u53ef\u4ee5\u9009\u662f, \u8fd9\u6837\u90a3\u4e2a\u6587\u4ef6\u91cc\u7684 Class1
\u7c7b\u540d\u4e5f\u4f1a\u5e2e\u4f60\u91cd\u547d\u540d
\u90a3\u4e48\u540c\u6837\u5730\u5bf9\u8fd9\u4e2a\u6587\u4ef6\u91cc\u7684\u7c7b\u7684\u540d\u5b57\u4e5f\u91cd\u547d\u540d, \u7136\u540e\u6211\u4eec\u8ba9\u8fd9\u4e2a\u7c7b\u7ee7\u627f\u4e8e EverestModule
.
\u5982\u679c\u51fa\u73b0\u4e86\u672a\u547d\u540d\u6807\u8bc6\u7b26\u7684\u9519\u8bef, \u8bf7\u68c0\u67e5\u4f60\u662f\u5426\u6b63\u786e\u5f15\u7528\u4e86 Celeste.exe
\u5e76\u4e14 using \u4e86 Celeste.Mod
\u547d\u540d\u7a7a\u95f4
EverestModule
\u662f\u4e00\u4e2a\u62bd\u8c61\u7c7b ,\u90a3\u4e48\u73b0\u5728\u6211\u4eec\u9700\u8981\u52a0\u5165\u4e24\u4e2a\u65b9\u6cd5\u4ee5\u5b9e\u73b0\u5b83, \u540c\u65f6\u8ba9vs\u95ed\u5634. MyCelesteMod.cs
public override void Load()\n{\n}\n\npublic override void Unload()\n{\n}\n
Load
\u65b9\u6cd5\u4f1a\u5728 Everest \u52a0\u8f7d\u4f60\u7684 Mod \u65f6\u88ab\u8c03\u7528 Unload
\u65b9\u6cd5\u4f1a\u5728 Everest \u5378\u8f7d\u4f60\u7684 Mod \u65f6\u88ab\u8c03\u7528 \u5728\u8fd9\u91cc\u6211\u4eec\u4f1a\u5199\u4e2a\u7c7b\u4f3c Hello world \u7684\u4e1c\u897f, \u5373\u5728 Load
\u91cc\u6253\u5370\u4e9b\u8bdd. em, \u53ef\u80fd\u4e0d\u662f\u4f60\u671f\u671b\u7684 Console.WriteLine
\u800c\u662f Logger.Log
, \u5c31\u50cf\u8fd9\u6837:
Logger.Log(LogLevel.Info, \"MyCelesteMod\", \"Hello World! Hello Everest!\");\n
\u8fd9\u662f\u4e00\u4e2a\u851a\u84dd\u5e95\u5c42\u6846\u67b6 Monocle
\u5f15\u64ce\u91cc\u7684\u4e00\u4e2a\u9759\u6001\u7c7b, \u5728\u4e4b\u540e\u6211\u4eec\u4f1a\u4ecb\u7ecd\u851a\u84dd\u4e2d\u5e38\u89c1\u7c7b\u7684\u4f7f\u7528. \u4e0b\u9762\u662f\u8fd9\u4e2a\u65b9\u6cd5\u7684\u53c2\u6570\u5217\u8868:
\u7b2c\u4e00\u4e2a\u53c2\u6570: \u8fd9\u53e5\u65e5\u5fd7\u7684\u7b49\u7ea7, \u8fd9\u91cc\u6211\u4eec\u5148\u9009 Info
. \u7b2c\u4e8c\u4e2a\u53c2\u6570: \u8fd9\u53e5\u65e5\u5fd7\u7684 Tag
, \u901a\u5e38\u5b83\u662f\u4f60\u7684 Mod \u540d\u5b57 \u7b2c\u4e09\u4e2a\u53c2\u6570: \u6211\u4eec\u5e0c\u671b\u8f93\u51fa\u7684\u8bdd \u90a3\u4e48\u4f60\u73b0\u5728\u7684\u4ee3\u7801\u5e94\u8be5\u662f\u5927\u6982\u8fd9\u6837\u5b50\u7684: MyCelesteMod.cs
using Celeste.Mod;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace MyCelesteMod\n{\n public class MyModModule : EverestModule\n {\n public override void Load()\n {\n Logger.Log(LogLevel.Info, \"MyCelesteMod\", \"Hello World! Hello Everest!\");\n }\n\n public override void Unload()\n {\n\n }\n }\n}\n
\u73b0\u5728, \u6309\u4e0b Ctrl + B
, vs \u5e94\u8be5\u4f1a\u542f\u52a8\u7f16\u8bd1.
\u4f60\u4f1a\u9047\u5230\u4e00\u4e2a\u5173\u4e8e x86
\u4e0e AnyCpu
\u67b6\u6784\u4e0d\u7b26\u7684\u8b66\u544a, \u8fd9\u91cc\u6211\u4eec\u5148\u5ffd\u7565\u5b83\u5e76\u5728\u540e\u9762\u89e3\u51b3.
\u7f16\u8bd1\u5b8c\u6210, \u6211\u4eec\u5c31\u53ef\u4ee5\u627e\u5230\u6211\u4eec\u7f16\u8bd1\u51fa\u6765\u7684\u65b0\u9c9c\u7684\u7a0b\u5e8f\u96c6: <\u4f60\u7684\u9879\u76ee\u540d>/<\u4f60\u7684\u9879\u76ee\u540d>/bin/Debug/<\u4f60\u7684\u9879\u76ee\u540d>.dll
, \u4f60\u7684 vs \u7684\u8f93\u51fa\u7a97\u53e3\u4e5f\u5e94\u8be5\u4f1a\u5199\u4e0a\u8fd9\u4e2a dll \u7684\u5b8c\u6574\u8def\u5f84.
"},{"location":"arc/basic_env/#everest","title":"\u8ba9 Everest \u52a0\u8f7d","text":"\u4ee5\u4e0a\u4e00\u987f\u64cd\u4f5c\u8fc7\u540e\u4f60\u4f1a\u53d1\u73b0\u4f60\u7684\u851a\u84dd\u4ec0\u4e48\u4e5f\u6ca1\u53d1\u751f(\u4e50). \u56e0\u4e3a\u6211\u4eec\u8fd8\u6ca1\u544a\u8bc9\u5b83\u8ba9\u5b83\u52a0\u8f7d\u6211\u4eec\u7684 mod! \u4e3a\u4e86\u8ba9 Everest \u52a0\u8f7d\u6211\u4eec\u7684 mod, \u5176\u4e2d\u4e00\u4e2a\u65b9\u6cd5\u5c31\u662f\u5728\u851a\u84dd\u7684 Mods \u6587\u4ef6\u5939\u91cc\u9762\u65b0\u5efa\u4e00\u4e2a\u6587\u4ef6\u5939, \u5e76\u653e\u5165\u6211\u4eec\u7684 mod \u6587\u4ef6, \u5b83\u7684\u540d\u5b57\u6211\u4eec\u6700\u597d\u5c31\u662f\u9879\u76ee\u540d\u5b57, \u6bd4\u5982 MyCelesteMod
, \u7136\u540e\u5728\u8fd9\u91cc\u5199\u4e00\u4efd everest.yaml
\u6587\u4ef6, \u5b83\u5305\u542b\u6211\u4eec mod \u7684\u4e00\u4e9b\u57fa\u672c\u4fe1\u606f: everest.yaml
- Name: <mod\u540d\u5b57>\nVersion: <\u7248\u672c>\nDLL: <dll\u4f4d\u7f6e>\nDependencies:\n - Name: Everest\n Version: <\u4f9d\u8d56\u7684 everest \u7248\u672c>\n
ok, \u6211\u4eec\u6765\u6162\u6162\u586b\u8fd9\u4e9b\u4e1c\u897f - mod\u540d\u5b57
: \u63a8\u8350\u4e3a\u9879\u76ee\u540d\u6bd4\u5982 MyCelesteMod
- \u7248\u672c
: \u7531\u4e8e\u662f\u5f00\u53d1\u65e9\u671f, \u6240\u4ee5\u7248\u672c\u63a8\u8350\u6307\u5b9a\u4e3a0\u5f00\u5934\u7684 0.1.0
- \u4f9d\u8d56\u7684 everest \u7248\u672c
: \u8fd9\u91cc\u586b\u4f60\u7684 everest \u7248\u672c\u5c31\u884c\u4e86, \u6bd4\u5982\u8bf4\u5982\u679c\u4f60\u662f 3876 \u90a3\u4e48\u8fd9\u91cc\u5e94\u8be5\u5199 1.3876.0
- Dll \u4f4d\u7f6e
: \u6211\u4eec\u5148\u628a\u4e4b\u524d\u7f16\u8bd1\u7684\u65b0\u9c9c(\u53ef\u80fd\u73b0\u5728\u4e0d\u548b\u65b0\u9c9c\u4e86)\u7684 dll \u590d\u5236\u5230\u8fd9\u4e2a\u6587\u4ef6\u5939\u6765, \u6ca1\u8bb0\u9519\u7684\u8bdd\u5728\u8fd9\u91cc\u53eb MyCelesteMod.dll
, ok, everest.yaml
\u91cc\u8981\u5199\u7684 dll \u4f4d\u7f6e\u662f\u76f8\u5bf9\u4e8e\u8fd9\u4e2a\u6587\u4ef6\u5939\u7684, \u6211\u4eec\u5c31\u653e\u5728\u5b83\u91cc\u9762\u7b2c\u4e00\u5c42, \u6240\u4ee5\u6211\u4eec\u76f4\u63a5\u5199 MyCelesteMod.dll
\u5c31\u884c\u4e86. \u73b0\u5728\u4f60\u7684\u90a3\u4e2a\u6587\u4ef6\u5939\u73b0\u5728\u53ef\u80fd\u957f\u8fd9\u4e2a\u6837\u5b50:
MyCelesteMod MyCelesteMod.dll everest.yaml everest.yaml\u53ef\u80fd\u957f\u8fd9\u4e2a\u6837\u5b50: everest.yaml
- Name: MyCelesteMod\nVersion: 0.1.0\nDLL: MyCelesteMod.dll\nDependencies:\n - Name: Everest\n Version: 1.3876.0\n
ok, \u5728\u542f\u52a8\u4e4b\u524d\u6211\u4eec\u8fd8\u8981\u5e72\u6700\u540e\u4e00\u4ef6\u5c0f\u4e8b, \u5c31\u662f\u6211\u4eec\u7684\u65e5\u5fd7, \u5b83\u6253\u5370\u5728\u6587\u4ef6\u91cc\u540c\u65f6\u4e5f\u6253\u5370\u5728\u63a7\u5236\u53f0\u91cc, \u65e5\u5fd7\u6587\u4ef6\u7ffb\u9605\u6bd4\u8f83\u9ebb\u70e6, \u6240\u4ee5\u4e3a\u4e86\u65e5\u540e\u65b9\u4fbf\u8c03\u8bd5, \u6211\u4eec\u8fd8\u662f\u5148\u8ba9\u851a\u84dd\u542f\u52a8\u7684\u540c\u65f6\u542f\u52a8\u4e00\u4e2a\u63a7\u5236\u53f0\u597d\u4e00\u70b9. Everest \u5df2\u7ecf\u4e3a\u6211\u4eec\u505a\u4e86\u8fd9\u4ef6\u4e8b\u4e86, \u6211\u4eec\u8981\u505a\u7684\u53ea\u662f\u5728\u851a\u84ddexe\u540c\u76ee\u5f55\u4e0b\u627e\u5230everest-launch.txt
, \u6ca1\u627e\u5230\u4e5f\u6ca1\u5173\u7cfb, \u65b0\u5efa\u4e00\u4e2a\u5c31\u53ef\u4ee5\u4e86, \u7136\u540e\u5728\u91cc\u9762\u5199\u4e0a--console
, \u662f\u7684\u5c31\u8fd9\u4e00\u5c0f\u70b9\u4e1c\u897f, \u7136\u540e\u6211\u4eec\u4fdd\u5b58, \u542f\u52a8\u851a\u84dd!
\u542f\u52a8\u540e\u4f60\u5e94\u8be5\u4f1a\u540c\u65f6\u770b\u5230\u4e00\u4e2a\u63a7\u5236\u53f0\u7a97\u53e3, \u626b\u89c6\u4e00\u4e0b: console output
[MonoMod] [AutoPatch] Patch pass\n[MonoMod] [AutoPatch] PatchRefs pass\n[MonoMod] [PostProcessor] PostProcessor pass #1\n[MonoMod] [Write] Writing modded module into output file.\n(07/05/2023 23:22:16) [Everest] [Info] [MyCelesteMod] Hello World! Hello Everest!\n(07/05/2023 23:22:16) [Everest] [Info] [core] Module MyCelesteMod 0.1.0 registered.\n(07/05/2023 23:22:16) [Everest] [Info] [loader] Loading mods with unsatisfied optional dependencies (if any)\nFNA3D Driver: D3D11\nD3D11 Adapter: Intel(R) UHD Graphics 630\nBEGIN LOAD\n- GFX LOAD: 139ms\n- MTN LOAD: 9ms\nWINDOW-1600x900\nGAME DISPLAYED (in 291ms)\n- AUDIO LOAD: 454ms\n- GFX DATA LOAD: 75ms\n
\u5927\u6982\u5728\u5982\u4e0a\u7684\u4f4d\u7f6e\u9644\u8fd1(\u5728\u8fd9\u91cc\u662f\u7b2c5\u884c)\u4f60\u5c31\u80fd\u627e\u5230\u4f60\u7684 Hello world \u4e86, \u81f3\u6b64\u57fa\u672c\u73af\u5883\u914d\u7f6e\u7ed3\u675f."},{"location":"arc/sdk-styled-proj/","title":"\u504f\u597d - sdk-styled csproj","text":""},{"location":"arc/sdk-styled-proj/#sdk-style-csproj","title":"Sdk-style csproj","text":"\u73b0\u5728\u6253\u5f00\u4f60\u7684\u9879\u76ee\u76ee\u5f55\u4e2d\u7684 .csproj
\u6587\u4ef6(\u901a\u5e38\u4e5f\u4f1a\u88ab\u53eb\u4f5c*\u9879\u76ee\u6587\u4ef6*), \u5b83\u7528\u4e8e\u7ec4\u7ec7\u63cf\u8ff0\u4f60\u7684\u9879\u76ee\u662f\u4ec0\u4e48\u6837\u5b50\u7684, \u4f60\u53ef\u80fd\u4f1a\u53d1\u73b0\u975e\u5e38\u7684\u6742\u4e71\u4e0d\u53ef\u8bfb, \u5c31\u50cf:
.csproj<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n <Import Project=\"$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props\" Condition=\"Exists('$(MSBuildExtensionsPath)\\$(MSBuildToolsVersion)\\Microsoft.Common.props')\" />\n <PropertyGroup>\n <Configuration Condition=\" '$(Configuration)' == '' \">Debug</Configuration>\n <Platform Condition=\" '$(Platform)' == '' \">AnyCPU</Platform>\n <ProjectGuid>{100E625E-04C6-434F-865C-3E6E50A379B5}</ProjectGuid>\n <OutputType>Library</OutputType>\n <AppDesignerFolder>Properties</AppDesignerFolder>\n <RootNamespace>MyCelesteMod</RootNamespace>\n <AssemblyName>MyCelesteMod</AssemblyName>\n <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>\n <FileAlignment>512</FileAlignment>\n <Deterministic>true</Deterministic>\n </PropertyGroup>\n <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n <DebugSymbols>true</DebugSymbols>\n <DebugType>full</DebugType>\n <Optimize>false</Optimize>\n <OutputPath>bin\\Debug\\</OutputPath>\n <DefineConstants>DEBUG;TRACE</DefineConstants>\n <ErrorReport>prompt</ErrorReport>\n <WarningLevel>4</WarningLevel>\n </PropertyGroup>\n <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n <DebugType>pdbonly</DebugType>\n <Optimize>true</Optimize>\n <OutputPath>bin\\Release\\</OutputPath>\n <DefineConstants>TRACE</DefineConstants>\n <ErrorReport>prompt</ErrorReport>\n <WarningLevel>4</WarningLevel>\n </PropertyGroup>\n <ItemGroup>\n <Reference Include=\"Celeste\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\Celeste.exe</HintPath>\n </Reference>\n <Reference Include=\"FNA\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\FNA.dll</HintPath>\n </Reference>\n <Reference Include=\"MMHOOK_Celeste\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\MMHOOK_Celeste.dll</HintPath>\n </Reference>\n <Reference Include=\"YamlDotNet\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\YamlDotNet.dll</HintPath>\n </Reference>\n <Reference Include=\"System\" />\n <Reference Include=\"System.Core\" />\n <Reference Include=\"System.Xml.Linq\" />\n <Reference Include=\"Microsoft.CSharp\" />\n <Reference Include=\"System.Xml\" />\n </ItemGroup>\n <ItemGroup>\n <Compile Include=\"MyModModule.cs\" />\n <Compile Include=\"Properties\\AssemblyInfo.cs\" />\n </ItemGroup>\n <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n</Project>\n
Note
\u5bf9\u4e8e\u6b64\u90e8\u5206\u7684\u5185\u5bb9\u4f60\u53ef\u80fd\u9700\u8981\u9605\u8bfb\u4e86\u89e3\u4e00\u4e0b XML
\u683c\u5f0f\u6587\u4ef6
\u5b9e\u9645\u4e0a\u5bf9\u4e8e\u6211\u4eec\u771f\u6b63\u7ecf\u5e38\u4fee\u6539\u7684\u5c5e\u6027\u53ea\u6709\u4e0a\u9762\u6807\u4eae\u7684\u884c, \u90a3\u4e48\u5982\u679c\u8fd9\u65f6\u5019\u4f7f\u7528 Sdk-style csproj
\u4f1a\u597d\u5f88\u591a, \u5b83\u770b\u4e0a\u53bb\u662f\u8fd9\u6837\u7684:
Sdk-style csproj<Project Sdk=\"Microsoft.NET.Sdk\">\n\n <PropertyGroup>\n <OutputType>Library</OutputType>\n <RootNamespace>MyCelesteMod</RootNamespace>\n <AssemblyName>MyCelesteMod</AssemblyName>\n <TargetFramework>net452</TargetFramework>\n </PropertyGroup>\n\n <ItemGroup>\n <Reference Include=\"Celeste\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\Celeste.exe</HintPath>\n </Reference>\n <Reference Include=\"FNA\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\FNA.dll</HintPath>\n </Reference>\n <Reference Include=\"MMHOOK_Celeste\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\MMHOOK_Celeste.dll</HintPath>\n </Reference>\n <Reference Include=\"YamlDotNet\">\n <HintPath>..\\..\\..\\..\\..\\..\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\YamlDotNet.dll</HintPath>\n </Reference>\n <Reference Include=\"System\" />\n <Reference Include=\"System.Core\" />\n <Reference Include=\"System.Xml.Linq\" />\n <Reference Include=\"Microsoft.CSharp\" />\n <Reference Include=\"System.Xml\" />\n </ItemGroup>\n\n</Project>\n
\u4f60\u4f1a\u53d1\u73b0\u5176\u5b9e\u8fd9\u91cc\u53ea\u7559\u4e0b\u4e86\u6211\u4eec\u4e0a\u9762\u6807\u9ec4\u7684\u4e1c\u897f, \u662f\u7684, \u8fd9\u5c31\u662f Sdk-style csproj
\u7684\u4f18\u70b9. \u8fc1\u79fb\u81f3 Sdk-style csproj
\u975e\u5e38\u7b80\u5355, \u4f60\u53ea\u9700\u8981:
\u5220\u9664 PropertyGroup
\u548c ItemGroup
\u53ca\u65c1\u8fb9\u7684\u975e\u6807\u9ec4\u8282\u70b9 \u5220\u9664 Project
\u8282\u70b9\u4e0b\u7684\u4e24\u4e2a Import
\u5220\u9664 Project
\u8282\u70b9\u7684\u6240\u6709\u5c5e\u6027 \u91cd\u65b0\u5728 Project
\u8282\u70b9\u4e0a\u52a0\u5165\u5c5e\u6027: Sdk = \"Microsoft.NET.Sdk\"
TargetFrameworkVersion
\u66f4\u6539\u4e3a\u65b0\u7248\u7684 TargetFramework
, v4.5.2
\u66f4\u6539\u4e3a net452
Note
\u4e0d\u7528\u62c5\u5fc3\u5220\u6389\u8fd9\u4e48\u591a\u4e1c\u897f\u4f1a\u51fa\u73b0\u95ee\u9898, \u5b9e\u9645\u4e0a\u6211\u4eec\u5220\u6389\u7684\u4e1c\u897f\u53ea\u662f\u5408\u5e76\u5165 Sdk = \"Microsoft.NET.Sdk\"
\u8fd9\u4e00\u53e5\u4e86\u800c\u5df2
\u8fd9\u4e2a\u65f6\u5019\u6574\u4e2a\u6587\u4ef6\u6e05\u6670\u53ef\u8bfb:
\u6839\u8282\u70b9\u7684 Project
\u4e0b\u6302\u8f7d\u7740 PropertyGroup
\u4ee5\u53ca ItemGroup
, PropertyGroup
\u63cf\u8ff0\u4e86\u6211\u4eec\u9879\u76ee\u7684\u4e00\u4e9b\u901a\u7528\u5c5e\u6027, \u6bd4\u5982\u8f93\u51fa\u7c7b\u578b, \u547d\u540d\u7a7a\u95f4, \u7a0b\u5e8f\u96c6\u6635\u79f0\u4ee5\u53ca\u9879\u76ee\u6846\u67b6\u7248\u672c, ItemGroup
\u5219\u63cf\u8ff0\u4e86\u6211\u4eec\u9879\u76ee\u4e2d\u7684\u4e00\u4e9b\u5f15\u7528\u7b49. \u5728\u8fd9\u91cc\u63d0\u53ca\u8fd9\u4e2a\u662f\u56e0\u4e3a\u5728\u540e\u9762\u90e8\u5206\u6211\u4eec\u4f1a\u9700\u8981\u4fee\u6539 .csproj
\u6587\u4ef6, \u901a\u8fc7\u5bf9\u6bd4\u4f60\u53ef\u4ee5\u53d1\u73b0\u8fd9\u4e24\u4e2a xml \u6587\u4ef6\u90fd\u6709 PropertyGroup
\u548c ItemGroup
\u8282\u70b9 (\u5982\u679c\u6709\u591a\u4e2a\u8282\u70b9\u7684\u8bdd, \u4efb\u610f\u4e00\u4e2a\u90fd\u884c), \u6240\u4ee5\u6211\u4eec\u4e4b\u540e\u5bf9\u9879\u76ee\u6587\u4ef6\u7684\u4fee\u6539\u7684\u63cf\u8ff0\u90fd\u4f1a\u57fa\u4e8e\u8fd9\u4e24\u4e2a\u8282\u70b9.
Warning
\u8bb0\u5f97\u5220\u9664 Properties
\u6587\u4ef6\u5939\u91cc\u7684 cs \u6587\u4ef6, \u5b83\u53ef\u80fd\u4f1a\u4e0e sdk-styled csproj \u81ea\u52a8\u751f\u6210\u7684\u6587\u4ef6\u76f8\u51b2\u7a81
"},{"location":"begin/basic_env/","title":"\u57fa\u7840\u73af\u5883\u914d\u7f6e","text":"Note
\u672c\u8282\u5185\u5bb9\u7531\u624b\u52a8\u914d\u7f6e\u91cd\u5199\u4e3a\u901a\u8fc7\u6a21\u677f\u914d\u7f6e, \u65e7\u7248\u4f60\u53ef\u4ee5\u5230\u5f52\u6863-\u57fa\u7840\u73af\u5883\u914d\u7f6e\u4e2d\u627e\u5230(\u4e0d\u63a8\u8350)
"},{"location":"begin/basic_env/#celeste","title":"Celeste","text":"Note
\u5982\u679c\u4f60\u4e0d\u662f Windows \u7528\u6237\u7684\u8bdd\u8fd9\u4e00\u6b65\u4f60\u53ef\u4ee5\u76f4\u63a5\u8df3\u8fc7.
Info
\u5728 Everest Core \u7248\u672c\u540e(Stable \u7248\u672c\u53f7\u5927\u4e8e 4465)\u5f3a\u5236\u5207\u6362\u4e3a\u4e86 FNA \u7248\u672c, \u5982\u679c\u4f60\u5df2\u662f Core \u7248\u672c\u4f60\u53ef\u4ee5\u8df3\u8fc7\u8fd9\u4e00\u6b65.
Everest \u9700\u6c42\u6211\u4eec\u4f7f\u7528 FNA \u7248\u672c\u7684\u851a\u84dd, \u800c Linux \u548c MacOS \u4e0a\u7684\u851a\u84dd\u5df2\u7ecf\u5c31\u662f FNA \u7248\u672c\u4e86, \u800c\u5728 Windows \u4e0a\u5219\u662f XNA \u7248\u672c, \u6240\u4ee5\u6211\u4eec\u9700\u8981\u4e00\u4e9b\u65b9\u6cd5\u5207\u6362\u5230 FNA \u7248\u672c:
\u5728 Steam \u4e0a: \u5e93->Celeste, \u53f3\u952e\u83dc\u5355\u5c5e\u6027->\u6d4b\u8bd5\u7248->Opengl \u5728 itch \u4e0a: \u91cd\u65b0\u4e0b\u8f7d\u4e00\u4e2a Celeste Windows OpenGL
\u7248\u672c \u5728 Epic \u4e0a: \u5df2\u7ecf\u662f FNA \u7248\u672c\u4e86 Note
Everest \u4f1a\u5728\u8fd0\u884c\u65f6\u5c06\u4f60\u4ee5 FNA \u7248\u672c\u5236\u4f5c\u7684 mod \u91cd\u94fe\u63a5\u4e3a XNA, \u6240\u4ee5\u4f60\u4e0d\u662f\u5f88\u9700\u8981\u5728\u610f\u8fd9\u4fe9\u7684\u5dee\u8ddd \u6ce8\u610f\u66f4\u6362\u7248\u672c\u540e\u4f1a\u53d8\u56de\u539f\u7248, \u4f60\u9700\u8981\u91cd\u65b0\u5b89\u88c5 Everest
"},{"location":"begin/basic_env/#c","title":"C# \u7f16\u7a0b\u80fd\u529b \u4e0e \u5f00\u53d1\u73af\u5883","text":"\u56e0\u4e3a\u6211\u4eec\u662f Code Mod, \u55ef, \u90a3\u4e48\u5199\u4e00\u4e9b\u4ee3\u7801\u662f\u5fc5\u4e0d\u53ef\u5c11\u7684, \u851a\u84dd\u662f\u4f7f\u7528 C#
\u57fa\u4e8e .NET Framework 4.5.2
\u6765\u5236\u4f5c\u7684, \u90a3\u4e48\u5b66\u4e60 C#
\u5f53\u7136\u662f\u5fc5\u4e0d\u53ef\u5c11\u7684.
Info
\u5728 Everest Core \u7248\u672c\u4e0a\u851a\u84dd\u88ab\u8fc1\u79fb\u5230\u4e86 .NET 7
\u4e0a, \u4e0d\u8fc7\u57fa\u4e8e\u65e7\u6846\u67b6\u7684 mod \u4f1a\u5c3d\u53ef\u80fd\u5730\u88ab Everest \u81ea\u52a8\u8f6c\u6362\u4e3a\u57fa\u4e8e\u65b0\u6846\u67b6\u7684 mod.
Info
\u7406\u8bba\u4e0a\u6240\u6709 .NET \u7cfb\u8bed\u8a00\u6bd4\u5982 VB.NET
F#
\u90fd\u53ef\u4ee5, \u4e0d\u8fc7\u4e3a\u4e86\u65b9\u4fbf\u8d77\u89c1\u6211\u4eec\u8fd8\u662f\u4f7f\u7528 C#.
\u597d\u5427\u8fd9\u53e5\u8bdd\u53ef\u80fd\u8bf4\u7684\u592a\u5e73\u6de1\u4e86(, \u6bd5\u7adf\u5927\u90e8\u5206\u851a\u6279\u851a\u84dd mod \u7231\u597d\u8005\u5c31\u662f\u88ab\u8fd9\u4e00\u6b65\u5361\u4f4f\u7684, \u90a3\u4e48\u8fd9\u91cc...\u53ea\u80fd\u7ed9\u4f60\u63a8\u8350\u51e0\u4e2a\u5b66\u4e60\u6e20\u9053\u4e86, \u6bd5\u7adf\u5728\u8fd9\u91cc\u6ca1\u5fc5\u8981\u8ba9\u8fd9\u4e2a\u6559\u7a0b\u8fc7\u4e8e\u5168\u80fd.
\u89c6\u9891: Bilibili - \u4e11\u840c\u6c14\u8d28\u72d7 - \u3010C#\u96f6\u57fa\u7840\u5165\u95e8\u6559\u7a0b Visual Studio 2022\u3011\u4eba\u751f\u4f4e\u8c37\u6765\u5b66C# (\u5168p, \u7a0d\u5fae\u4e0d\u5168) \u89c6\u9891: Bilibili - C#\u4ece\u5165\u95e8\u5230\u7cbe\u901a\uff08\u7b2c5\u7248\uff09 (1-71p, 109-132p) \u89c6\u9891: Bilibili - \u5218\u94c1\u731b - C#\u8bed\u8a00\u5165\u95e8\u8be6\u89e3-\u7b2c1\u5b63-\u526a\u8f91\u7248-\u516833\u8bfe-\u5206154\u96c6 (1-152p) \u7f51\u7ad9: Runnob - C# \u6559\u7a0b \u7f51\u7ad9: w3schools - C# \u6559\u7a0b (\u82f1\u6587) \u4e66\u7c4d: C#\u5165\u95e8\u7ecf\u5178-\u7b2c7\u7248-C# 6.0 Info
\u5982\u679c\u4f60\u6ca1\u6709\u80fd\u529b\u652f\u6301\u6b63\u7248\u4e66\u7c4d\u7684\u8bdd, \u4f60\u53ef\u4ee5\u5230\u4e00\u4e9b C# \u5f00\u53d1\u8005\u7fa4\u5185\u5bfb\u627e\u5b83\u7684\u7535\u5b50\u975e\u6b63\u7248(\u6bd4\u5982\u89c6\u9891 1.
up \u7684\u7fa4\u5185) \u4e0a\u9762\u51e0\u4e2a\u6211\u66f4\u52a0\u63a8\u8350\u7684\u662f 1.
\u548c 3.
\u501f\u7528 4.
\u7684\u76ee\u5f55, \u786e\u4fdd\u4f60\u5bf9\u4e0b\u9762\u8fd9\u4e9b\u6982\u5ff5(\u753b \u00d7 \u7684\u6682\u65f6\u5728\u851a\u84dd Code Mod \u4e2d\u7528\u4e0d\u5230)\u6709\u8db3\u591f\u6e05\u6670\u7684\u4e86\u89e3\u5728\u5f00\u59cb\u4f60\u7684\u851a\u84dd Code Mod \u4e4b\u65c5\u4e4b\u524d:
\u76f8\u4fe1\u5728\u4e0a\u9762\u7684\u6559\u7a0b\u4e2d\u4f60\u5e94\u8be5\u5df2\u7ecf\u88ab\u63a8\u8350\u4e86\u4e00\u4e9b\u7f16\u8f91\u5668 / IDE, \u90a3\u4e48\u5728\u672c\u6559\u7a0b\u4e2d\u6211\u4e2a\u4eba\u4f1a\u4e3a\u4e86\u65b9\u4fbf\u4ec5\u5728 Windows
\u4e0a\u4f7f\u7528 Visual Studio
, \u5f53\u7136\u4e0d\u4fdd\u8bc1\u5728\u5176\u4ed6\u5730\u65b9\u4f1a\u9047\u5230\u5947\u5947\u602a\u602a\u7684\u95ee\u9898. _(:\u0437\u300d\u2220)_
"},{"location":"begin/basic_env/#_2","title":"\u901a\u8fc7\u6a21\u677f\u521b\u5efa\u9879\u76ee","text":"Info
\u5728\u851a\u84dd\u56fd\u5916\u793e\u533a\u6d41\u884c\u7740\u53e6\u4e00\u4e2a mod \u9879\u76ee\u6a21\u677f, \u4e0d\u8fc7\u6211\u4e2a\u4eba\u4e0d\u592a\u559c\u6b22\u5b83, \u4e0d\u8fc7\u4f60\u9700\u8981\u7684\u8bdd\u8fd9\u662f Github \u4e3b\u9875 \u6240\u4ee5\u8fd9\u91cc\u4e3b\u8981\u4f7f\u7528\u6211\u4e2a\u4eba\u5236\u4f5c\u4e5f\u662f\u4e2a\u4eba\u6700\u5e38\u7528\u7684\u4e00\u4e2a.
_(:\u0437\u300d\u2220)_ \u6839\u636e\u4e00\u4e9b\u53cd\u9988\u6211\u4eec\u53d1\u73b0\u65e7\u7684\u624b\u52a8\u914d\u7f6e\u73af\u5883\u7684\u65b9\u5f0f\u975e\u5e38\u7684\u590d\u6742\u96be\u64cd\u4f5c( \u6240\u4ee5\u5462\u8fd9\u91cc\u5c31\u63a8\u8350\u4e00\u79cd\u65b0\u7684\u914d\u7f6e\u73af\u5883\u7684\u65b9\u5f0f - \u4f7f\u7528\u6a21\u677f \u8003\u8651\u5230 nuget \u5b89\u88c5\u6a21\u677f\u4e5f\u9700\u8981\u4e00\u5b9a\u7684\u547d\u4ee4\u884c\u57fa\u7840... \u6240\u4ee5\u8fd9\u91cc\u8003\u8651\u63d0\u4f9b\u76f4\u63a5\u7684\u4e0b\u8f7d\u94fe\u63a5, \u6216\u8005\u4f60\u4e5f\u53ef\u4ee5\u9009\u62e9\u4f7f\u7528 dotnet cli
\u4ece nuget \u4e0a\u7684\u6a21\u677f\u5b89\u88c5:
Note
\u4f60\u53ef\u80fd\u8fd8\u9700\u8981\u5b89\u88c5 .NET 8 SDK
\u6765\u4f7f\u7528\u8be5\u6a21\u677f, \u4f60\u53ef\u4ee5\u5728\u8fd9\u91cc\u627e\u5230\u5b83
\u4f7f\u7528 dotnet cli \u4ece\u6a21\u677f\u65b0\u5efa\u9879\u76ee \u9996\u5148\u5728\u4e00\u4e2a\u4f60\u559c\u6b22\u7684\u4f4d\u7f6e\u653e\u7f6e\u4f60\u7684\u9879\u76ee\u6587\u4ef6\u5939, \u540d\u5b57\u5373\u4e3a\u4f60\u7684\u9879\u76ee\u540d, \u4f8b\u5982 MyCelesteMod
:
mkdir MyCelesteMod\ncd MyCelesteMod\n
\u7136\u540e\u5728\u6b64\u4f4d\u7f6e\u5b89\u88c5 nuget \u4e0a\u6211\u7684 mod \u6a21\u677f(\u5982\u679c\u4f60\u6ca1\u6709\u5b89\u88c5\u7684\u8bdd): dotnet new install Saladim.CelesteModTemplate\n
\u7136\u540e\u4f60\u5c31\u80fd\u4f7f\u7528\u8fd9\u6761\u6307\u4ee4\u76f4\u63a5\u521b\u5efa\u9879\u76ee\u4e86: dotnet new sapcelestemod\n
\u540d\u5b57\u5373\u4e3a\u4e0a\u5c42\u6587\u4ef6\u5939\u540d, \u6216\u8005\u4f60\u53ef\u4ee5\u4f7f\u7528 -n
\u53c2\u6570\u91cd\u5199\u9879\u76ee\u540d\u5b57: dotnet new sapcelestemod -n MySuperCelesteMod\n
\u6a21\u677f\u76ee\u524d\u9ed8\u8ba4\u4e0d\u4f1a\u521b\u5efa\u9488\u5bf9 Everest Core \u7684 Code Mod, \u5982\u679c\u4f60\u9700\u8981\u7684\u8bdd\u4f60\u53ef\u4ee5\u4f20\u5165 --core-only true
\u53c2\u6570: dotnet new sapcelestemod --core-only true\n
\u5b8c\u6210\u540e\u4f7f\u7528\u4f60\u559c\u6b22\u7684\u7f16\u8f91\u5668\u6253\u5f00\u9879\u76ee(\u5bf9\u4e8e vs \u76f4\u63a5\u6253\u5f00 .csproj \u6587\u4ef6), \u90a3\u4e48\u6309\u7406\u6765\u8bf4\u4f60\u4f1a\u770b\u5230\u8fd9\u51e0\u4e2a\u6587\u4ef6:
CelesteMod.props CelesteMod.targets Common.props MyCelesteModModule.cs MyCelesteMod.csproj \u4ee5\u53ca\u4f60\u7684\u9879\u76ee, \u5b83\u7684\u540d\u5b57\u662f MyCelesteMod
, \u4e0d\u540c\u4e8e\u65e7\u7684\u65b9\u6cd5, \u5728\u8fd9\u91cc\u4f60\u7684\u914d\u7f6e\u8fc7\u7a0b\u5f88\u7b80\u5355:
\u9996\u5148\u6253\u5f00 Common.props
, \u5c06\u91cc\u9762\u7684 CelesteRootPath
\u5185\u7684\u5185\u5bb9\u6539\u6210\u4f60\u7684\u851a\u84dd\u5b89\u88c5\u4f4d\u7f6e <Project>\n <PropertyGroup>\n <CelesteRootPath>C:\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste</CelesteRootPath>\n <CommonCelesteUsings>true</CommonCelesteUsings>\n <CommonCelesteReferences>true</CommonCelesteReferences>\n <ModAssetsFolderName>ModFolder</ModAssetsFolderName>\n </PropertyGroup>\n</Project>\n
\u73b0\u5728\u4f60\u53ef\u4ee5\u6309\u4e0b Ctrl+B
\u6216\u8005\u624b\u52a8\u70b9\u51fb \u751f\u6210->\u751f\u6210\u89e3\u51b3\u65b9\u6848
, \u5982\u679c\u4f60\u5728\u4f60\u7684 vs \u8f93\u51fa\u91cc\u9762\u770b\u5230\u4e86\u7c7b\u4f3c\u8fd9\u4e24\u53e5:
1>MyCelesteMod -> D:\\User\\temp\\cm\\bin\\x86\\Debug\\net452\\MyCelesteMod.dll\n1>MyCelesteMod -> C:/Program Files (x86)/Steam/steamapps/common/Celeste/Mods/MyCelesteMod_copy/MyCelesteMod.dll\n
\u5e76\u4e14\u4f60\u5728\u4f60\u7684\u851a\u84dd Mod \u76ee\u5f55\u4e0b\u627e\u5230\u4e86\u8fd9\u4e2a\u88ab\u521b\u5efa\u7684\u76ee\u5f55, \u90a3\u4e48\u4f60\u7684\u73af\u5883\u5c31\u7b97\u662f\u914d\u5b8c\u4e86, \u5982\u679c\u4f60\u5f88\u611f\u5174\u8da3\u8fd9\u4e4b\u4e2d\u53d1\u751f\u4e86\u4ec0\u4e48, \u8981\u5f15\u7528\u54ea\u4e9b\u7a0b\u5e8f\u96c6, \u8fd9\u4e2a\u6a21\u677f\u80cc\u540e\u5e72\u4e86\u4ec0\u4e48, \u4f60\u53ef\u4ee5\u53bb\u770b\u90a3\u590d\u6742\u7684\u65e7\u7684\u914d\u7f6e\u65b9\u6cd5.
Note
\u8fd9\u4e2a\u6a21\u677f\u4f7f\u7528 msbuild
\u5e2e\u52a9\u4e86\u4f60\u5f88\u591a\u4e8b! \u6bd4\u5982\u5f53\u4f60\u7f16\u8bd1\u5b8c\u9879\u76ee\u4e4b\u540e\u5b83\u4f1a\u590d\u5236\u7f16\u8bd1\u7ed3\u679c\u5230\u9879\u76ee\u76ee\u5f55\u7684 ModFolder
\u76ee\u5f55\u4e0b, \u7136\u540e\u5c06\u6574\u4e2a ModFolder
\u590d\u5236\u5230\u851a\u84dd\u7684 Mods\\{\u4f60\u7684mod\u540d}_copy
\u6587\u4ef6\u5939\u4e0b! \u6240\u4ee5\u5f53\u6211\u4eec\u9700\u8981\u66f4\u6539\u4e00\u4e9b\u6bd4\u5982\u8bf4 loenn \u7684\u914d\u7f6e\u6587\u4ef6, everest.yaml
\u7684\u5185\u5bb9, \u4f60\u7684\u6d4b\u8bd5\u5730\u56fe\u7b49\u65f6, \u4f60\u53ea\u9700\u8981\u7b80\u5355\u5730\u91cd\u65b0\u7f16\u8bd1\u4e00\u904d\u9879\u76ee, \u7136\u540e\u7b49\u5f85\u6a21\u677f\u6765\u5e2e\u4f60\u505a\u5269\u4e0b\u7684\u6d3b!
"},{"location":"begin/basic_env/#_3","title":"\u66f4\u6539\u7ec6\u8282","text":"\u901a\u8fc7\u6a21\u677f\u7684\u8bdd\u4f9d\u7136\u6709\u4e9b\u4e1c\u897f\u9700\u8981\u81ea\u884c\u66f4\u6539, \u6bd4\u5982\u8fd9\u4e2a Mod \u7684\u540d\u5b57. \u66f4\u6539 Mod \u7684\u540d\u5b57\u5f88\u7b80\u5355, \u4f60\u53ea\u9700\u8981\u7b80\u5355\u5730\u5728 vs \u91cc\u91cd\u547d\u540d\u9879\u76ee\u7684\u540d\u5b57 \u6bd4\u5982\u6211\u60f3\u53eb\u505a MyAwesomeMod
, \u90a3\u4e48\u4f60\u53ef\u4ee5\u901a\u8fc7\u8fd9\u6837: \u987a\u4fbf\u522b\u5fd8\u4e86\u628a\u7c7b\u4f3c MyCelesteModModule.cs
\u7684\u6587\u4ef6\u540d\u4e5f\u6539\u6210\u7c7b\u4f3c MyAwesomeModModule.cs
, \u4ee5\u53ca\u6539\u540d\u540e\u6e05\u7406\u4e00\u4e0b ModFolder \u4e0b\u9762\u53ef\u80fd\u6709\u7684\u4e00\u4e9b\u4ee5\u8fc7\u53bb\u540d\u5b57\u547d\u540d\u7684 .dll \u548c .pdb \u6587\u4ef6!
"},{"location":"begin/basic_env/#module","title":"Module \u7c7b","text":"\u5c31\u50cf\u6211\u4eec\u7684\u7ecf\u5178\u7684\u63a7\u5236\u53f0 C# \u5e94\u7528\u7a0b\u5e8f\u4e00\u6837\u6709\u4e2a Main
\u65b9\u6cd5, \u6211\u4eec\u7684\u851a\u84dd Mod \u4e5f\u6709\u4e00\u4e2a\u7c7b\u4f3c\u7684\u4e1c\u897f, \u90a3\u5c31\u662f Everest \u63d0\u4f9b\u7ed9\u6211\u4eec\u7684 EverestModule
\u7c7b. \u90a3\u4e48, \u73b0\u5728\u6253\u5f00\u4f60\u7684 MyCelesteModModule.cs
\u90a3\u4e2a\u6587\u4ef6, \u4f60\u5e94\u8be5\u4f1a\u770b\u5230\u7c7b\u4f3c\u7ed3\u6784\u8fd9\u6837\u7684\u4ee3\u7801:
namespace MyCelesteMod;\n\npublic class MyCelesteModModule : EverestModule\n{\n public override void Load()\n {\n\n }\n\n public override void Unload()\n {\n }\n}\n
\u5728\u5f00\u5934\u6211\u4eec\u58f0\u660e\u4e86\u547d\u540d\u7a7a\u95f4, \u63a5\u4e0b\u6765\u6211\u4eec\u58f0\u660e\u4e86\u4e00\u4e2a\u7c7b, \u7136\u540e\u8ba9\u5b83\u7ee7\u627f\u4e8e EverestModule
, \u6ce8\u610f\u8fd9\u4e2a\u7c7b\u662f\u62bd\u8c61\u7684, \u5b83\u8981\u6c42\u6211\u4eec\u5b9e\u73b0\u7684\u4e24\u4e2a\u65b9\u6cd5\u5206\u522b\u4e3a Load
\u4e0e Unload
. \u8fd9\u4e24\u4e2a\u65b9\u6cd5\u5f88\u7b80\u5355: Load
\u65b9\u6cd5\u5728\u4f60\u7684 mod \u88ab\u52a0\u8f7d\u65f6\u8c03\u7528. Unload
\u65b9\u6cd5\u5728\u4f60\u7684 mod \u88ab\u5378\u8f7d\u65f6\u8c03\u7528. \u901a\u5e38\u6211\u4eec\u4f1a\u5728 Load
\u65b9\u6cd5\u91cc\u52a0\u8f7d\u6211\u4eec\u9700\u8981\u7684\u8d44\u6e90, \u8fdb\u884c\u9002\u5f53\u7684\u521d\u59cb\u5316, \u5728 Unload
\u65b9\u6cd5\u91cc\u91ca\u653e\u6211\u4eec\u7684\u8d44\u6e90. \u5728\u8fd9\u91cc\u4e3a\u4e86\u660e\u663e\u53ef\u89c1, \u6211\u4eec\u5728 Load
\u65b9\u6cd5\u91cc\u901a\u8fc7\u4e00\u4e2a\u851a\u84dd\u4e2d\u7684\u7c7b Logger
\u6253\u5370\u51fa\u4e86\u4e00\u53e5 \"Hello World\".
\u5982\u679c\u4f60\u597d\u5947 Logger.Log
\u8fd9\u4e2a\u65b9\u6cd5\u4f60\u53ef\u4ee5\u5c55\u5f00\u6765\u4e86\u89e3 Logger
\u662f\u4e00\u4e2a\u851a\u84dd\u5e95\u5c42\u5f15\u64ce Monocle
\u7684\u4e00\u4e2a\u5de5\u5177\u7c7b, \u5b83\u5e2e\u52a9\u4f60\u6253\u5370\u8f93\u51fa\u4e00\u4e9b\u8c03\u8bd5\u4fe1\u606f, \u901a\u5e38\u8fd9\u4e9b\u4fe1\u606f\u4f1a\u88ab\u6253\u5370\u8fdb\u63a7\u5236\u53f0\u7684\u540c\u65f6\u5199\u5165\u6e38\u620f\u7684 log.txt
\u6587\u4ef6\u4e2d, \u8fd9\u4e5f\u5c31\u89e3\u91ca\u4e86\u4e3a\u4ec0\u4e48\u4f60\u9047\u5230\u5404\u79cd\u95ee\u9898\u65f6\u522b\u4eba\u603b\u8981\u6c42\u4f60\u53d1\u9001\u4f60\u7684 log.txt
. Logger.Log
\u6709\u4e24\u4e2a\u91cd\u8f7d, \u5176\u4e2d\u4e00\u4e2a\u7684\u7b7e\u540d\u662f:
public static void Log(LogLevel logLevel, string tag, string str)\n
\u5b83\u4f1a\u4ee5 logLevel
\u7684\u65e5\u5fd7\u7b49\u7ea7\u6253\u5370\u4e00\u4e2a\u6807\u7b7e\u4e3a tag
\u7684\u6d88\u606f str
, \u53e6\u4e00\u4e2a\u91cd\u8f7d\u4e0d\u8981\u6c42\u4f60\u4f20\u5165 logLevel
\u4f46\u4f1a\u9ed8\u8ba4\u4f60\u7684 logLevel
\u4e3a LogLevel.Verbose
. LogLevel
\u679a\u4e3e\u5305\u542b Verbose, Debug, Info, Warn, Error
. \u901a\u5e38\u5bf9\u4e8e\u666e\u901a\u65e5\u5fd7\u6211\u4eec\u4f1a\u9009\u62e9 Info
, \u5bf9\u4e8e\u8f83\u591a\u7684\u8c03\u8bd5\u4fe1\u606f\u9009\u62e9 Debug
, \u5bf9\u4e8e\u5197\u4f59\u7684\u4fe1\u606f\u9009\u62e9 Verbose
, \u5bf9\u4e8e\u4e00\u4e9b\u9519\u8bef\u4f46\u4e0d\u5f71\u54cd\u6e38\u620f\u8fdb\u884c\u7684\u4fe1\u606f\u9009\u62e9 Warn
, \u5bf9\u4e8e\u4e00\u4e9b\u81f4\u547d\u6027\u9519\u8bef\u6211\u4eec\u4f1a\u9009\u62e9 Error
. \u4e00\u822c\u5730, \u6e38\u620f\u53ea\u4f1a\u6253\u5370 Info
\u7b49\u7ea7\u53ca\u4ee5\u4e0a\u7684\u65e5\u5fd7, \u4f60\u53ef\u4ee5\u901a\u8fc7\u5728\u851a\u84dd\u542f\u52a8\u7684\u547d\u4ee4\u884c\u4e2d\u52a0\u5165--loglevel {\u7b49\u7ea7}
\u6765\u6307\u5b9a\u8fc7\u6ee4\u7b49\u7ea7."},{"location":"begin/basic_env/#everestyaml","title":"everest.yaml","text":"ok, \u6211\u4eec\u524d\u9762\u51e0\u4e4e\u5df4\u62c9\u5df4\u62c9\u8bb2\u4e86\u51e0\u4e4e\u4e09\u5343\u591a\u4e2a\u5b57, \u4f46\u662f\u4f9d\u7136\u6ca1\u6709\u8ba9\u851a\u84dd\u52a0\u8f7d\u5230\u6211\u4eec\u7684mod, \u4e0d\u8fc7\u522b\u6025, \u8fd9\u662f\u5012\u6570\u7b2c\u4e8c\u6b65\u4e86. \u5b9e\u9645\u4e0a\u6709\u5173 code mod \u7684\u6240\u6709\u4ee3\u7801\u76f8\u5173\u7684\u4e1c\u897f\u6211\u4eec\u90fd\u5df2\u7ecf\u505a\u5b8c\u4e86, \u5269\u4f59\u7684\u5176\u5b9e\u53ea\u662f\u4e00\u4e2a\u666e\u901a mod \u8981\u505a\u7684 ---- \u5199 everest.yaml
. \u5728\u8fd9\u91cc\u6211\u4eec\u9700\u8981\u5728 ModFolder
\u8fd9\u4e2a\u6587\u4ef6\u5939\u91cc\u505a\u8fd9\u4ef6\u4e8b, \u90a3\u4e48, \u5728\u4f60\u7684\u8fd9\u4e2a\u6587\u4ef6\u5939\u4e0b\u521b\u5efa everest.yaml
\u7a7a\u6587\u4ef6, \u4f60\u7684\u76ee\u5f55\u7ed3\u6784\u53ef\u80fd\u50cf\u662f:
Note
.dll
\u6587\u4ef6\u548c .pdb
\u6587\u4ef6\u4ec5\u4f1a\u5728\u4f60\u6784\u5efa\u8fc7\u9879\u76ee\u540e\u51fa\u73b0, \u6709\u65f6\u5019\u751a\u81f3 ModFolder \u76ee\u5f55\u4e5f\u4f1a\u5728\u6784\u5efa\u8fc7\u540e\u51fa\u73b0
ModFolder everest.yaml MyCelesteMod.dll MyCelesteMod.pdb \u597d\u7684, \u73b0\u5728\u6211\u4eec\u6253\u5f00 everest.yaml
, \u7136\u540e\u50cf\u4e00\u4e2a\u666e\u901a\u7684 mapper \u4e00\u6837\u586b\u5199\u4fe1\u606f:
- Name: MyCelesteMod\n Version: 0.1.0\n DLL: MyCelesteMod.dll\n Dependencies:\n - Name: Everest\n Version: 1.3971.0\n
\u8fd9\u4e9b\u53c2\u6570\u5206\u522b\u662f: Name
: \u4f60\u7684 mod \u540d\u5b57 Version
: \u4f60\u7684 mod \u7684\u7248\u672c DLL
: \u5982\u679c\u4f60\u662f code mod \u7684\u8bdd, \u8fd9\u91cc\u586b\u5165\u4f60\u7684 code (\u4e5f\u5c31\u662f dll \u6587\u4ef6) \u7684\u4f4d\u7f6e, \u8fd9\u91cc\u6211\u4eec\u662f\u76f4\u63a5\u628a .dll \u6587\u4ef6\u653e\u5230\u8fd9\u4e2a yaml \u7684\u65c1\u8fb9\u4e86, \u6240\u4ee5\u76f4\u63a5\u5199\u540d\u5b57\u5c31\u597d \u6700\u540e\u662f\u6700\u5e95\u4e0b\u7684\u90a3\u4e2a\u4f9d\u8d56, \u8fd9\u91cc\u6211\u4eec\u53ea\u4f9d\u8d56\u6700\u57fa\u7840\u7684 Everest, \u7248\u672c\u586b\u4e0a\u4f60\u76ee\u524d\u4f7f\u7528\u7684 Everest \u7248\u672c, \u8fd9\u91cc\u6211\u5c31\u586b\u5199 3971 \u4e86. \u5982\u679c\u4f60\u7684 mod \u4f9d\u8d56 Everest Core, \u4f60\u9700\u8981\u5728\u8fd9\u91cc\u5c06 Everest
\u66f4\u6539\u4e3a EverestCore
, \u5e76\u5c06\u7248\u672c\u53f7\u586b\u5199\u5927\u4e8e 4465 \u7684\u503c.
"},{"location":"begin/basic_env/#_4","title":"\u6700\u540e\u4e00\u6b65!","text":"\u4e3a\u4e86\u65b9\u4fbf\u6211\u4eec\u7684\u8c03\u8bd5, \u6211\u4eec\u9700\u8981\u8ba9\u851a\u84dd\u6253\u5f00\u7684\u540c\u65f6\u6253\u5f00\u63a7\u5236\u53f0, \u8fd9\u4e00\u6b65\u5f88\u7b80\u5355:
\u627e\u5230\u851a\u84dd\u6839\u76ee\u5f55\u4e0b\u7684 everest-launch.txt
, \u6ca1\u6709\u7684\u8bdd\u65b0\u5efa\u4e00\u4e2a\u7a7a\u7684\u5c31\u884c\u4e86 \u5411\u91cc\u9762\u5199\u5165 --console
\u641e\u5b9a, \u8d70\u4f60! \u73b0\u5728, \u91cd\u65b0\u7f16\u8bd1\u9879\u76ee, \u8ba9 msbuild
\u5e26\u7740\u4f60\u7684 ModFolder
\u7684\u5185\u5bb9\u524d\u5f80\u851a\u84dd Mods \u6587\u4ef6\u5939\u4e0b, \u542f\u52a8\u851a\u84dd. \u5728\u540c\u65f6\u542f\u52a8\u7684\u9ed1\u4e4e\u4e4e\u7684\u547d\u4ee4\u884c\u7a97\u53e3\u4e0a\u4f60\u5e94\u8be5\u80fd\u5728\u8fd9\u9644\u8fd1\u770b\u5230\u90a3\u53e5\u719f\u6089\u7684 Hello world:
(07/08/2023 21:18:59) [Everest] [Info] [core] Module DialogCutscene 1.0.0 registered.\n(07/08/2023 21:18:59) [Everest] [Info] [core] Module UpdateChecker 1.0.2 registered.\n(07/08/2023 21:18:59) [Everest] [Info] [core] Module InfiniteSaves 1.0.0 registered.\n(07/08/2023 21:18:59) [Everest] [Info] [core] Module DebugRebind 1.0.0 registered.\n(07/08/2023 21:18:59) [Everest] [Info] [core] Module RebindPeriod 1.0.0 registered.\n(07/08/2023 21:19:00) [Everest] [Info] [Everest.LuaBoot] Lua ready.\n(07/08/2023 21:19:00) [Everest] [Info] [MyCelesteMod] Hello World!\n(07/08/2023 21:19:00) [Everest] [Info] [core] Module MyAwesomeMod 0.1.0 registered.\n(07/08/2023 21:19:00) [Everest] [Info] [loader] Loading mods with unsatisfied optional dependencies (if any)\nFNA3D Driver: D3D11\nD3D11 Adapter: Intel(R) UHD Graphics 630\n
"},{"location":"begin/basic_env/#_5","title":"\u8fd8\u6ca1\u5b8c","text":"\u5728\u7ecf\u8fc7\u5982\u4e0a\u7684\u914d\u7f6e\u540e, \u4f60\u4f1a\u53d1\u73b0\u5728\u851a\u84dd\u542f\u52a8\u7684\u65f6\u5019, \u8fdb\u884c\u7f16\u8bd1\u5e76\u590d\u5236\u8d44\u6e90\u65f6\u4f1a\u62a5\u9519, \u8fd9\u662f\u56e0\u4e3a Everest \u9501\u5b9a\u5360\u7528\u4e86\u5b83\u4eec, \u5bfc\u81f4\u4f60\u4e0d\u5f97\u4e0d\u8ba9\u8fd9\u4e00\u5207\u5728\u851a\u84dd\u5173\u95ed\u65f6\u8fdb\u884c, \u540c\u65f6\u7531\u4e8e\u851a\u84dd\u7684\u91cd\u542f\u901f\u5ea6\u4e0d\u662f\u5f88\u7406\u60f3, \u8fd9\u5927\u5927\u7684\u62c9\u4f4e\u4e86 mod \u5f00\u53d1\u6548\u7387. \u4e0d\u8fc7\u597d\u5728 Everest \u63d0\u4f9b\u4e86\u4e00\u4e2a\u6280\u672f\u53eb\u505a code hot reload
, \u5373\u70ed\u91cd\u8f7d, \u5b83\u5141\u8bb8\u4f60\u5728\u6e38\u620f\u8fd0\u884c\u671f\u95f4\u66ff\u6362\u4f60\u7684\u4ee3\u7801\u5e76\u91cd\u8f7d\u8d44\u6e90, \u5b83\u76ee\u524d\u8fd8\u5728 wip \u72b6\u6001. \u8981\u5f00\u542f\u8fd9\u9879\u529f\u80fd, \u9996\u5148\u5230\u4f60\u7684\u851a\u84dd\u6839\u76ee\u5f55\u4e0b\u7684 Saves \u76ee\u5f55, \u627e\u5230\u5e76\u6253\u5f00 modsettings-Everest.celeste
\u8fd9\u4e2a\u6587\u4ef6, \u7ffb\u5230\u5927\u6982\u4e2d\u95f4\u7684\u4f4d\u7f6e, \u627e\u5230\u5c5e\u6027 CodeReload_WIP
, \u5c06\u5176\u66f4\u6539\u4e3a true
, \u6b64\u65f6\u91cd\u65b0\u7f16\u8bd1\u4f60\u7684\u9879\u76ee, \u4f60\u5e94\u8be5\u5c31\u4e0d\u4f1a\u518d\u5f97\u5230\u4efb\u4f55\u9519\u8bef, \u5e76\u4e14 Everest \u4e5f\u6b63\u786e\u5730\u70ed\u91cd\u8f7d\u4e86\u4f60\u7684 mod \u548c\u4f60\u7684 mod \u8d44\u6e90.
"},{"location":"begin/basic_env/#_6","title":"\u6700\u540e\u4e00\u4e9b\u788e\u788e\u5ff5","text":"\u8fd9\u4e00\u8282\u5b8c\u6210\u540e\u4f60\u7684\u76ee\u5f55\u7ed3\u6784\u5927\u6982\u4f1a\u50cf\u662f:
MyCelesteMod (\u4f60\u7684\u6839\u76ee\u5f55) ModFolder everest.yaml MyCelesteMod.dll MyCelesteMod.pdb CelesteMod.props CelesteMod.targets Common.props MyCelesteMod.csproj MyCelesteModModule.cs \u5176\u4e2d\u6b63\u5982\u4e4b\u524d\u6240\u4ecb\u7ecd\u7684, \u6211\u63a8\u8350\u5982\u679c\u4f60\u4f7f\u7528\u8be5\u6a21\u677f\u7684\u8bdd, mod \u7684\u8d44\u6e90\u6587\u4ef6\u5e94\u8be5\u653e\u5728 ModFolder
\u4e2d, \u7136\u540e\u5c31\u50cf\u5f80\u5e38\u4e00\u6837\u653e\u7f6e\u4f60\u7684 mod \u8d44\u6e90, \u5f53\u4f60\u7684\u9879\u76ee\u5728\u6784\u5efa\u65f6\u5b83\u4eec\u4f1a\u81ea\u52a8\u88ab\u590d\u5236. \u5e76\u4e14\u5c06\u4ee3\u7801\u6587\u4ef6\u653e\u7f6e\u5728 .csproj \u540c\u76ee\u5f55\u4e0b\u6216\u5d4c\u5957\u6587\u4ef6\u5939\u4e0b, \u5982\u679c\u4f60\u6ca1\u6709\u66f4\u6539\u4f60\u7684\u9879\u76ee\u800c\u53ea\u66f4\u6539\u4e86\u8d44\u6e90\u6587\u4ef6\u65f6\u4f60\u4f1a\u53d1\u73b0\u7f16\u8bd1\u9879\u76ee\u4f1a\u56e0\u4e3a \"\u6240\u6709\u6587\u4ef6\u90fd\u662f\u6700\u65b0\u7684\" \u800c\u8df3\u8fc7\u7f16\u8bd1, \u800c\u540c\u65f6\u4e5f\u4f1a\u8df3\u8fc7\u6211\u4eec\u7684\u8d44\u6e90\u590d\u5236, \u5bf9\u6b64\u7684\u8bdd\u6211\u4eec\u6709\u4e24\u79cd\u89e3\u51b3\u65b9\u6848:
\u76f4\u63a5\u5f3a\u5236\u91cd\u65b0\u6784\u5efa\u9879\u76ee (vs \u4e2d \"\u751f\u6210\" -> \"\u91cd\u65b0\u751f\u6210\u9879\u76ee\") \u5728\u9879\u76ee\u6839\u76ee\u5f55\u6267\u884c msbuild -target:PostModBuild
\u547d\u4ee4\u884c \u597d\u50cf\u662f\u6709\u66f4\u597d\u7684\u89e3\u51b3\u65b9\u6cd5, \u4e0d\u8fc7\u9274\u4e8e\u672c\u4eba MSBuild \u77e5\u8bc6\u4e0d\u8db3\u53ea\u80fd\u505a\u6210\u8fd9\u6837\u4e86(x
"},{"location":"begin/celeste_everest_monomod/","title":"Celeste Everest MonoMod","text":""},{"location":"begin/celeste_everest_monomod/#celeste","title":"Celeste","text":"\u989d, \u6765\u8fd9\u91cc\u7684\u5e94\u8be5\u90fd\u77e5\u9053 Celeste \u662f\u4ec0\u4e48\u5427(( \u540e\u6587\u4e2d\u63d0\u5230\u7684 Celeste
, \u851a\u84dd
\u90fd\u4f1a\u53ea\u6307 Celeste \u8fd9\u4e2a\u6e38\u620f, \u4e5f\u5c31\u662f\u6211\u4eec\u6b63\u5728\u5b66\u4e60\u7684\u4e3a\u5176\u5236\u4f5c mod \u7684\u5bf9\u8c61.
"},{"location":"begin/celeste_everest_monomod/#everest","title":"Everest","text":"\u4f5c\u4e3a\u4e00\u4e2a\u851a\u84dd\u7684 mod \u73a9\u5bb6, \u5b89\u88c5 Everest \u662f\u5fc5\u4e0d\u53ef\u5c11\u7684\u6b65\u9aa4, \u56e0\u4e3a\u6211\u4eec\u7684 mod \u4f9d\u8d56\u4e8e\u5b83\u6240\u63d0\u4f9b\u7684\u5236\u4f5c mod \u4e2d\u6240\u5fc5\u987b\u7684\u4e1c\u897f. \u5b83\u5f00\u6e90\u5728 Github \u4e0a. \u53ef\u80fd\u4f60\u8fd8\u542c\u8fc7 Olympus, \u5b83\u662f\u4e00\u4e2a Everest \u7684\u5b89\u88c5\u5668, \u4e5f\u662f\u4e00\u4e2a mod \u7ba1\u7406\u5668.
\u5982\u679c\u4f60\u8fd8\u73a9\u8fc7 Minecraft \u7684\u8bdd\u6211\u4eec\u53ef\u4ee5\u5efa\u7acb\u4e00\u4e2a\u8fd9\u6837\u7684\u5947\u5999\u5173\u7cfb:
\u851a\u84dd\u4fa7 MC\u4fa7 Celeste Minecraft Everest Forge/Fabric Olympus PCL2/HCML \u989d\u5916\u5730, Everest, Forge, Fabric \u8fd9\u4e00\u7c7b\u4e1c\u897f\u6211\u4eec\u5bf9\u5176\u6709\u4e2a\u7edf\u79f0, \u53eb\u505a ModApi
. \u5c31\u50cf Celeste \u548c Minecraft \u88ab\u7edf\u79f0\u4e3a\u6e38\u620f\u672c\u4f53/\u539f\u7248.
"},{"location":"begin/celeste_everest_monomod/#monomod","title":"MonoMod","text":"Everest \u5e95\u5c42\u57fa\u4e8e MonoMod, \u5728\u8fd9\u91cc\u4f60\u53ea\u9700\u8981\u77e5\u9053 Everest \u4f9d\u8d56\u4e86 MonoMod, \u540c\u6837\u5730\u5b83\u4e5f\u662f\u4e00\u4e2a\u5f00\u6e90\u9879\u76ee(Github). \u6709\u8da3\u7684\u662f, Everest \u7684\u4e3b\u8981\u7ef4\u62a4\u8005\u4e4b\u4e00\u4e5f\u662f MonoMod \u7684\u4e3b\u8981\u7ef4\u62a4\u8005, \u540c\u65f6 MonoMod \u4e5f\u662f\u4e00\u4e9b\u5176\u4ed6\u6e38\u620f\u7684 mod \u5e95\u5c42, \u6bd4\u5982 Terraria \u7684 tModLoader, Fez \u7684 FEZMod \u7b49\u7b49.
\u90a3\u4e48\u5728\u8fd9\u4e09\u4e2a\u57fa\u7840\u6982\u5ff5\u4e86\u89e3\u4e4b\u540e\u4f60\u5c31\u53ef\u4ee5\u5f00\u59cb\u5236\u4f5c\u4f60\u7684\u7b2c\u4e00\u4e2a mod\u4e86: \u57fa\u7840\u73af\u5883\u914d\u7f6e
"},{"location":"begin/hook%2Creading_1/","title":"\u94a9\u5b50, \u9605\u8bfb\u4ee3\u7801, demo1","text":""},{"location":"begin/hook%2Creading_1/#_1","title":"\u524d\u8a00","text":"\u5728\u8fd9\u4e00\u8282, \u6211\u4eec\u4f1a\u4ecb\u7ecd\u5728\u5236\u4f5c mod \u4e2d\u7684\u4e00\u4e2a\u5f88\u91cd\u8981\u7684\u6280\u672f: \u94a9\u5b50(Hook), \u6211\u4eec\u4e3b\u8981\u4ecb\u7ecd On \u94a9\u5b50, \u5728\u4e4b\u540e\u6211\u4eec\u4f1a\u9605\u8bfb\u851a\u84dd\u7684\u4ee3\u7801, \u6700\u540e\u6211\u4eec\u4f1a\u5236\u4f5c\u4e00\u4e2a\u4fee\u6539\u73a9\u5bb6\u51b2\u523a\u6570\u7684\u5c0f demo.
"},{"location":"begin/hook%2Creading_1/#on","title":"\u94a9\u5b50 (\u7279\u6307 On \u94a9\u5b50)","text":"\u5bf9\u4e8e C# \u7684\u4e00\u4e2a\u666e\u901a\u7684\u51fd\u6570\u6765\u8bf4, \u5b83\u88ab\u8c03\u7528\u65f6\u770b\u8d77\u6765\u662f\u8fd9\u6837\u7684:
graph LR\n A[\u8c03\u7528\u65b9] --> B[\u5373\u5c06\u8c03\u7528\u8be5\u51fd\u6570];\n subgraph \u8be5\u51fd\u6570\n B --> C[\u8be5\u51fd\u6570\u4e3b\u4f53];\n C --> D[\u7ed3\u675f\u8c03\u7528\u8be5\u51fd\u6570];\n end\n D --> E[\u8c03\u7528\u65b9];
\u5f53\u6211\u4eec\u5f15\u5165\u94a9\u5b50\u6280\u672f\u540e, \u8fd9\u4e2a\u51fd\u6570\u8c03\u7528\u65f6\u4f1a\u50cf\u88ab\"\u94a9\"\u4f4f\u4e00\u6837\u8f6c\u8eab\u53bb\u8c03\u7528\u6211\u4eec\u7684\u51fd\u6570:
graph LR\n A[\u8c03\u7528\u65b9]; B[\u5373\u5c06\u8c03\u7528\u8be5\u51fd\u6570];\n F[\u94a9\u5b50]; G[\u6211\u4eec\u7684\u51fd\u6570];\n H[\u8be5\u51fd\u6570\u4e3b\u4f53];\n D[\u7ed3\u675f\u8c03\u7528\u8be5\u51fd\u6570];\n E[\u8c03\u7528\u65b9];\n subgraph \u8be5\u51fd\u6570\n B; H; D;\n end\n A --> B;\n B --> F;\n F --> G;\n H --> D;\n G --> H;\n G -.\u6216\u8005.-> D;\n D --> E;
\u5982\u56fe\u6240\u89c1, \u8be5\u94a9\u5b50\u5141\u8bb8\u4f60\u5728\u8c03\u7528\u67d0\u4e2a\u51fd\u6570\u65f6\u8f6c\u8eab\u53bb\u8c03\u7528\u6211\u4eec\u7684\u51fd\u6570, \u540c\u65f6\u4f60\u80fd\u9009\u62e9\u6211\u4eec\u7684\u51fd\u6570\u6267\u884c\u5b8c\u540e\u662f\u5426\u518d\u6267\u884c\u56de\u539f\u51fd\u6570.
\u5728 Everest \u4e2d, \u501f\u52a9\u4e8e MonoMod \u7684\u6280\u672f, \u521b\u5efa\u4e00\u4e2a On \u94a9\u5b50\u7b80\u5355\u7684\u5c31\u50cf:
\u7b80\u5355\u7684\u94a9\u53d6...public override void Load()\n{\n On.Celeste.Player.Update += Player_Update;\n}\n\nprivate void Player_Update(On.Celeste.Player.orig_Update orig, Player self)\n{\n orig(self);\n}\n\npublic override void Unload()\n{\n On.Celeste.Player.Update -= Player_Update;\n}\n
\u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\u6211\u4eec\u4f7f\u7528\u7c7b\u4f3c\u8ba2\u9605\u4e8b\u4ef6\u7684\u8bed\u6cd5\u53bb\u94a9\u4f4f\u4e86 Player
\u7c7b\u7684 Update
\u65b9\u6cd5(\u8be5\u65b9\u6cd5\u6bcf\u5e27\u90fd\u4f1a\u8c03\u7528\u4e00\u904d), Everest \u4e3a\u6211\u4eec\u628a\u51e0\u4e4e\u6240\u6709\u53ef\u80fd\u94a9\u53d6\u7684\u51fd\u6570\u653e\u5230\u4e86\u547d\u540d\u7a7a\u95f4 On
\u4e2d, \u5f53\u4f60\u60f3\u94a9\u53d6\u67d0\u4e2a\u65b9\u6cd5\u65f6\u53ea\u9700\u901a\u8fc7 On
\u547d\u540d\u7a7a\u95f4\u4e00\u8def\"\u70b9\"\u5230\u4f60\u60f3\u8981\u7684\u65b9\u6cd5\u4e0a, \u7136\u540e\u4f7f\u7528\u4e00\u4e2a\u94a9\u5b50\u51fd\u6570\u4ee5\u50cf\u4e8b\u4ef6\u4e00\u6837\u7684\u8bed\u6cd5\"\u8ba2\u9605\"\u5c31\u80fd\u94a9\u4f4f\u5b83! \u5728\u8fd9\u91cc\u6211\u4eec\u7684\u94a9\u5b50\u51fd\u6570\u5c31\u662fPlayer_Update
, \u4f60\u53ef\u80fd\u6ce8\u610f\u5230\u53c2\u6570\u5f88\u590d\u6742, \u662f\u7684, \u6240\u4ee5\u4e00\u822c\u6765\u8bf4\u6211\u90fd\u662f\u4f9d\u8d56 IDE \u5e2e\u6211\u81ea\u52a8\u586b\u5199\u8fd9\u4e9b\u53c2\u6570\u5c31\u50cf:
Note
\u6ce8\u610f IDE \u751f\u6210\u7684\u51fd\u6570\u9ed8\u8ba4\u5305\u542b\u4e00\u53e5\u629b\u51fa\u5f02\u5e38\u8bed\u53e5, \u8bb0\u5f97\u628a\u5b83\u6539\u6389
orig
\u53c2\u6570\u662f\u4e00\u4e2a\u59d4\u6258, \u8c03\u7528\u5b83\u5c31\u76f8\u5f53\u4e8e\u8c03\u7528\u8fd9\u4e2a\u94a9\u5b50\u94a9\u4f4f\u7684\u539f\u51fd\u6570, \u4e5f\u5c31\u662f\u8bf4\u4f60\u53ef\u4ee5\u5728\u8be5\u51fd\u6570\u8c03\u7528\u524d\u505a\u4e9b\u4e8b, \u4e5f\u53ef\u4ee5\u5728\u8be5\u51fd\u6570\u8c03\u7528\u540e\u505a\u4e9b\u4e8b, \u6216\u8005\u5e72\u8106\u4e0d\u8c03\u7528\u8fd9\u4e2a\u51fd\u6570, \u751a\u81f3\u8c03\u7528\u8fd9\u4e2a\u51fd\u6570\u591a\u6b21. \u901a\u5e38\u6765\u8bf4\u6211\u4eec\u90fd\u4f1a\u5728\u672b\u5c3e\u7b80\u5355\u7684\u8c03\u7528\u56de\u53bb\u907f\u514d\u9020\u6210\u4e0d\u5fc5\u8981\u7684\u9ebb\u70e6.
\u4e00\u4e9b\u94a9\u5b50\u672c\u8eab...private void Player_Update(On.Celeste.Player.orig_Update orig, Player self)\n{\n // \u5728\u8fd9\u4e4b\u524d\u505a\u4e00\u4e9b\u4e8b...\n\n // \u5f53\u67d0\u4e9b\u5947\u602a\u7684\u6761\u4ef6\u4e0d\u6210\u7acb\u65f6\u6211\u4eec\u624d\u8c03\u7528\u56de\u53bb\u539f\u6765\u7684\u51fd\u6570...\n if (!xxx)\n orig(self);\n\n // \u5728\u8fd9\u4e4b\u540e\u505a\u4e00\u4e9b\u4e8b...\n}\n
\u5982\u679c\u4f60\u94a9\u53d6\u5230\u7684\u662f\u4e00\u4e2a\u6210\u5458\u51fd\u6570(\u4e5f\u53eb\u6210\u5458\u65b9\u6cd5), \u90a3\u4e48\u53c2\u6570\u901a\u5e38\u4f1a\u5e26\u6709\u4e00\u4e2a self
, \u5b83\u8868\u793a\u6267\u884c\u8fd9\u4e2a\u6210\u5458\u51fd\u6570\u65f6 this
\u7684\u503c, \u90a3\u4e48\u81ea\u7136\u5730\u5982\u679c\u4f60\u94a9\u53d6\u7684\u662f\u4e00\u4e2a\u9759\u6001\u51fd\u6570\u90a3\u4e48\u662f\u6ca1\u6709\u8fd9\u4e2a\u53c2\u6570\u7684. \u5982\u679c\u4f60\u94a9\u53d6\u7684\u51fd\u6570\u662f\u5e26\u53c2\u6570\u7684, \u90a3\u4e48\u53c2\u6570\u5217\u8868\u4f1a\u539f\u5c01\u4e0d\u52a8\u7684\u6392\u5217\u5728\u524d\u9762\u63d0\u5230\u7684\u53c2\u6570\u7684\u540e\u9762.
\u6bd4\u5982\u4f60\u5c1d\u8bd5\u94a9\u53d6 Player.Jump
\u51fd\u6570\u65f6, \u5b83\u7684\u4e09\u4e2a\u53c2\u6570\u4f1a\u8fd9\u6837\u4f20\u9012\u7ed9\u4f60:
private void Player_Jump(On.Celeste.Player.orig_Jump orig, Player self, bool particles, bool playSfx)\n
\u6700\u540e, \u4e0d\u8981\u5fd8\u8bb0\u5728 Unload
\u65b9\u6cd5\u91cc\u53d6\u6d88\u6389\u6211\u4eec\u7684\u94a9\u5b50(\u901a\u8fc7-=
), \u9632\u6b62\u6211\u4eec\u7684\u94a9\u5b50\u5728\u4e0d\u5fc5\u8981\u7684\u5730\u65b9\u4ea7\u751f\u4e0d\u597d\u7684\u5f71\u54cd: \u53d6\u6d88\u94a9\u5b50
public override void Unload()\n{\n On.Celeste.Player.Update -= Player_Update;\n}\n
"},{"location":"begin/hook%2Creading_1/#i","title":"\u9605\u8bfb\u4ee3\u7801 I","text":"\u5230\u8fd9\u91cc\u76f8\u4fe1\u4f60\u80af\u5b9a\u6709\u5f88\u591a\u95ee\u53f7, \u6bd4\u5982\u8fd9\u4e9b\u51fd\u6570\u90fd\u662f\u5e72\u4ec0\u4e48\u7684?
Player
\u662f\u4ec0\u4e48? Player.Update
\u662f\u4ec0\u4e48? Player.Jump
\u53c8\u662f\u4ec0\u4e48?? \u6240\u4ee5\u8fd9\u65f6\u6211\u4eec\u5c31\u9700\u8981\u9605\u8bfb\u851a\u84dd\u7684\u4ee3\u7801\u6765\u4e86\u89e3\u8fd9\u4e9b\u4e1c\u897f. \u5f53\u7136, \u851a\u84dd\u662f\u4e2a\u5546\u4e1a\u6e38\u620f, \u60f3\u6307\u671b\u5b83\u5f00\u6e90\u6240\u6709\u4ee3\u7801\u662f\u4e0d\u53ef\u80fd\u7684, \u90a3\u6211\u4eec\u5c31\u5fc5\u987b\u5f97\u501f\u52a9\u4e00\u4e9b\u53cd\u7f16\u8bd1\u5de5\u5177. \u5728\u8fd9\u91cc\u6211\u4f1a\u63a8\u8350 dnSpy
\u4f7f\u7528\u8be5\u8f6f\u4ef6\u5f88\u7b80\u5355:
\u6253\u5f00\u5b83 \u70b9\u51fb\u5de6\u4e0a\u89d2\u7684\u6587\u4ef6
, \u6253\u5f00
\u9009\u62e9 Celeste.exe
(\u5982\u679c\u4f60\u4f7f\u7528 core \u7248\u672c\u7684 everest, \u4f60\u9700\u8981\u9009\u62e9 Celeste.dll
) \u5c55\u5f00\u851a\u84dd\u7684\u7a0b\u5e8f\u96c6 \u4f60\u73b0\u5728\u53ef\u4ee5\u770b\u5230\u851a\u84dd\u90fd\u6709\u54ea\u4e9b\u7c7b\u4e86 \u4f60\u73b0\u5728\u4e5f\u53ef\u4ee5\u770b\u5230\u851a\u84dd\u90fd\u6709\u54ea\u4e9b\u51fd\u6570\u4e86 Warning
\u4e0d\u8981\u4e0a\u4f20\u53cd\u7f16\u8bd1\u540e\u7684\u4ee3\u7801\u5230\u4efb\u4f55\u5730\u65b9, \u8fd9\u53ef\u80fd\u4f1a\u4e0d\u907f\u514d\u7684\u9020\u6210\u4e00\u4e9b\u4e89\u8bae.
\u73b0\u5728\u6211\u4eec\u6d4f\u89c8\u851a\u84dd\u7684\u4ee3\u7801\u5c31\u50cf\u4f60\u5728 IDE \u91cc\u6d4f\u89c8\u4f60\u7684\u9879\u76ee\u4e00\u6837, \u867d\u7136\u8fd9\u4e0d\u662f\u6211\u4eec\u7684\u9879\u76ee. \u5728\u6d4f\u89c8\u8fc7\u7a0b\u4e2d, \u901a\u5e38\u53ef\u80fd\u4f60\u4f1a\u5bf9\u7740\u4e00\u4e2a\u5b57\u6bb5\u3001\u4e00\u4e2a\u51fd\u6570\u53d1\u5446, \u5927\u6982\u662f\u56e0\u4e3a\u4f60\u6839\u672c\u4e0d\u77e5\u9053\u5b83\u662f\u505a\u4ec0\u4e48\u7684! \u597d\u5728 dnSpy
\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5f88\u597d\u7528\u7684\"\u5206\u6790\"\u529f\u80fd\u6765\u7f13\u89e3\u8fd9\u4e2a : \u5728\u8fd9\u91cc\u4f60\u53ef\u4ee5\u770b\u5230\u54ea\u4e9b\u5b57\u6bb5\u3001\u54ea\u4e9b\u51fd\u6570\u88ab\u8c01\u8c03\u7528\u4e86\u3001\u88ab\u8c01\u5f15\u7528\u4e86\u3001\u88ab\u8c01\u66f4\u6539\u4e86:
"},{"location":"begin/hook%2Creading_1/#monocle-ec","title":"Monocle, EC \u67b6\u6784","text":"\u5728\u8fd9\u91cc\u6211\u4f1a\u7b80\u5355\u4ecb\u7ecd\u4e00\u4e0b\u6574\u4e2a\u851a\u84dd\u662f\u600e\u4e48\u7ec4\u7ec7\u8d77\u6765\u7684. \u9996\u5148\u851a\u84dd\u57fa\u4e8e Monocle
\u5f15\u64ce, \u8fd9\u662f matt
\u81ea\u5df1\u5f00\u53d1\u7684\u4e00\u4e2a\u5f15\u64ce, \u6240\u4ee5\u522b\u6307\u671b\u4f60\u80fd\u5728\u7f51\u4e0a\u627e\u5230\u5b83\u7684\u6559\u7a0b(, \u5176\u6b21 Monocle
\u518d\u6b21\u4f9d\u8d56 XNA
(\u5df2\u505c\u6b62\u7ef4\u62a4) \u6216\u8005 FNA
(XNA
\u6846\u67b6\u7684\u91cd\u65b0\u5b9e\u73b0), XNA
\u63d0\u4f9b\u7684 api \u90fd\u975e\u5e38\u539f\u59cb, \u751a\u81f3\u8fde\u6700\u57fa\u672c\u7684\u573a\u666f\u7ec4\u7ec7\u4e4b\u7c7b\u7684\u90fd\u6ca1\u6709, \u90a3\u4e48 Monocle
\u5c31\u662f\u6765\u5b9e\u73b0\u8fd9\u4e9b\u7684.
\u901a\u5e38\u6765\u8bf4\u4e00\u4e2a\u6b63\u5728\u8fd0\u884c\u7684 Monocle
\u6e38\u620f\u7684\u7ed3\u6784\u5c31\u50cf:
graph LR\nR[Engine] --- A;\n\nA[Scene] --- B[Entity A];\nA --- C[Entity B];\nA --- E[Entity ...];\nB --- F[Component A];\nB --- G[Component B];\nC --- H[Component A];\nC --- I[Component C];\nC --- J[Component ...];
Scene
\u8868\u793a\u4e00\u4e2a\u573a\u666f, \u6bd4\u5982\u4e3b\u754c\u9762\u573a\u666f, pico8 \u573a\u666f, \u4ee5\u53ca\u6700\u5e38\u89c1\u7684 gameplay \u573a\u666f. Entity
\u8868\u793a\u4e00\u4e2a\u5b9e\u4f53, \u6bd4\u5982\u8bf4\u739b\u5fb7\u7433\u5c31\u662f\u4e00\u4e2a\u5b9e\u4f53, \u4e00\u4e2a\u5f39\u7403\u662f\u4e00\u4e2a\u5b9e\u4f53, \u4e00\u4e2a\u6ce1\u6ce1\u662f\u4e00\u4e2a\u5b9e\u4f53. Component
\u8868\u793a\u4e00\u4e2a\u7ec4\u4ef6, \u5b83\u9644\u52a0\u4e0e\u5b9e\u4f53\u4e4b\u4e0a, \u901a\u5e38\u6211\u4eec\u80fd\u76f4\u63a5\u770b\u5230\u7684\u53ea\u6709\u56fe\u7247\u7ec4\u4ef6, \u6bd4\u5982\u5ca9\u6d46\u5757\u7684\u8d34\u56fe\u5c31\u662f\u7531 Image
\u7ec4\u4ef6\u6765\u5c55\u73b0\u7684, \u73a9\u5bb6\u7684\u52a8\u753b\u7531 Sprite
\u7ec4\u4ef6\u5c55\u73b0. Info
\u4ee5\u4e0a\u8fd9\u4e2a\u67b6\u6784\u6211\u4eec\u5c31\u79f0\u4e3a EC
\u67b6\u6784, \u5b83\u662f\u6e38\u620f\u7684\u4e00\u79cd\u7ec4\u7ec7\u65b9\u5f0f\u7684\u5b9e\u73b0.
\u901a\u5e38\u5730, \u6bcf\u8fc7 1/60
\u79d2, Engine
\u5c31\u4f1a\u88ab\u8c03\u7528\u5b83\u7684 Update()
\u51fd\u6570\u7528\u6765\u66f4\u65b0\u6e38\u620f\u903b\u8f91, Engine.Update()
\u5185\u90e8\u4f1a\u518d\u6b21\u8c03\u7528 Scene
\u7684 Update()
\u51fd\u6570, Scene.Update()
\u5185\u90e8\u4f1a\u904d\u5386\u5b83\u6240\u6709\u7684 Entity
\u5e76\u8c03\u7528\u5b83\u4eec\u7684 Update()
\u51fd\u6570, Entity.Update()
\u5185\u90e8\u8fd8\u4f1a\u904d\u5386\u5b83\u6240\u6709\u7684 Component
\u5e76\u8c03\u7528\u5b83\u4eec\u7684 Update()
\u51fd\u6570.
\u90a3\u4e48\u81ea\u7136, Player.Update()
\u5c31\u662f\u739b\u5fb7\u7433\u6bcf\u5e27\u7684\u66f4\u65b0\u903b\u8f91\u6240\u5728\u7684\u5730\u65b9\u4e86. \u73b0\u5728\u6211\u4eec\u505a\u4e00\u4e2a\u5c0f demo, \u5c06\u73a9\u5bb6\u7684\u51b2\u523a\u6570\u91cf\u9501\u6b7b\u4e3a\u5355\u51b2.
"},{"location":"begin/hook%2Creading_1/#_2","title":"\u9501\u5b9a\u5355\u51b2","text":"\u901a\u8fc7\u7b80\u5355\u7684\u6d4f\u89c8\u851a\u84dd\u7684\u4ee3\u7801, \u4f60\u4e86\u89e3\u5230(\u6ca1\u4e86\u89e3\u5230\u4e5f\u6b63\u5e38, \u540e\u9762\u4f1a\u8bf4\u4e00\u4e9b\u5e38\u89c1\u7c7b\u548c\u7ed3\u6784\u5e2e\u52a9\u4f60\u7406\u89e3) Player.Dashes
\u8fd9\u4e2a\u5b57\u6bb5\u50a8\u5b58\u4e86\u73a9\u5bb6\u7684\u51b2\u523a\u6570\u91cf, \u90a3\u4e48\u73b0\u5728\u6211\u4eec\u5c06\u5b83\u9501\u5b9a\u4e3a 1, \u4e5f\u5c31\u662f\u5355\u51b2. \u9996\u5148\u6211\u4eec\u94a9\u53d6 Player.Update()
, \u7136\u540e\u5728\u786e\u4fdd\u8c03\u7528\u56de\u539f\u6765\u7684\u51fd\u6570\u540e\u76f4\u63a5\u5c06 Dashes
\u5f3a\u5236\u4fee\u6539\u4e3a 1.
\u9501\u5b9a\u51b2\u523a\u4e3a1!public override void Load()\n{\n On.Celeste.Player.Update += Player_Update;\n}\n\nprivate void Player_Update(On.Celeste.Player.orig_Update orig, Player self)\n{\n self.Dashes = 1;\n orig(self);\n}\n\npublic override void Unload()\n{\n On.Celeste.Player.Update -= Player_Update;\n}\n
\u90a3\u4e48\u73b0\u5728\u7f16\u8bd1, \u6309\u4e4b\u524d\u7684\u5185\u5bb9\u64cd\u4f5c, \u5e76\u91cd\u542f\u851a\u84dd, \u4f60\u5e94\u8be5\u5c31\u4f1a\u770b\u5230\u4f60\u7684\u739b\u5fb7\u7433\u6c38\u8fdc\u90fd\u4f1a\u6709\u5355\u51b2\u4e86(\u5373\u4f7f\u662f\u5728\u7a7a\u4e2d!).
"},{"location":"begin/hook%2Creading_1/#_3","title":"\u94a9\u5b50\u7684\u6700\u4f73\u5b9e\u8df5","text":"\u6211\u4eec\u5e94\u8be5\u5c3d\u53ef\u80fd\u4e00\u6b21\u6027\u5730\u5c31\u5c06\u6211\u4eec\u6240\u9700\u8981\u7684\u6240\u6709\u94a9\u5b50\u5728 Load
\u91cc\u52a0\u8f7d\u5b8c, \u56e0\u4e3a\u521b\u5efa\u94a9\u5b50\u5b9e\u9645\u4e0a\u7684\u5f00\u9500\u5e76\u4e0d\u5c0f, \u5982\u679c\u4f60\u9700\u8981\u67d0\u4e9b \"\u67d0\u4e9b\u6761\u4ef6\u4e0d\u6210\u7acb\u4e0d\u542f\u52a8\u94a9\u5b50, \u6761\u4ef6\u6210\u7acb\u518d\u542f\u52a8\u94a9\u5b50\" \u7684\u903b\u8f91\u7684\u8bdd, \u6211\u5efa\u8bae\u4f60\u5e94\u8be5\u59cb\u7ec8\u4fdd\u6301\u94a9\u5b50, \u7136\u540e\u5728\u94a9\u5b50\u5185\u90e8\u5224\u65ad\u4f60\u7684\u6761\u4ef6, \u4e0d\u6210\u7acb\u65f6\u4f60\u5e94\u8be5\u76f4\u63a5\u56de\u8c03\u539f\u6765\u7684\u65b9\u6cd5\u5e76\u4e0d\u505a\u4efb\u4f55\u5176\u4ed6\u4e8b\u60c5.
"},{"location":"begin/preference/","title":"\u504f\u597d","text":"\u5728\u672c\u7cfb\u5217\u6559\u7a0b\u4e2d\u672c\u4eba\u53ef\u80fd\u4f1a\u5076\u5c14\u4e60\u60ef\u6027\u7684\u4f7f\u7528\u4e00\u4e9b\u6bd4\u8f83\u65b0\u7684 C# \u8bed\u6cd5\u6216\u8005\u662f\u7279\u6027, \u901a\u5e38\u8fd9\u662f\u5927\u90e8\u5206 C# \u6559\u7a0b\u4e2d\u5f88\u5c11\u63d0\u53ca\u7684, \u6240\u4ee5\u4e3a\u4e86\u907f\u514d\u56f0\u60d1\u6211\u4f1a\u5728\u8fd9\u91cc\u63d0\u53ca\u4ed6\u4eec.
Note
\u4e3a\u4e86\u4f7f\u7528\u8fd9\u4e9b\u8bed\u6cd5\u4f60\u53ef\u80fd\u9700\u8981\u5b89\u88c5 .NET 8 SDK
, \u5982\u679c\u4f60\u65e0\u6cd5\u7406\u89e3\u67d0\u4e9b\u4e1c\u897f, \u6ca1\u5173\u7cfb, \u4f60\u4f9d\u7136\u53ef\u4ee5\u4f7f\u7528\u540c\u65f6\u63d0\u53ca\u5230\u7684\u7b49\u6548\u65b9\u6cd5
"},{"location":"begin/preference/#_2","title":"\u7b80\u5355\u4e86\u89e3\u9879\u76ee\u6587\u4ef6","text":"\u5728\u89e3\u51b3\u65b9\u6848\u8d44\u6e90\u7ba1\u7406\u5668\u4e2d, \u53cc\u51fb\u4f60\u7684\u9879\u76ee, \u6309\u7406\u6765\u8bf4\u4f60\u5e94\u8be5\u4f1a\u6253\u5f00\u8be5\u9879\u76ee\u7684 .csproj
\u6587\u4ef6, \u901a\u5e38\u4e5f\u53eb\u505a\u9879\u76ee\u6587\u4ef6, \u5b83\u63cf\u8ff0\u4e86\u8fd9\u4e2a\u9879\u76ee\u7684\u5404\u65b9\u9762\u7684\u4fe1\u606f, \u5e76\u4e14\u4ee5\u4e0b\u51e0\u5c0f\u8282\u7684\u5185\u5bb9\u4e5f\u4f9d\u8d56\u4e8e\u6b64. \u5982\u679c\u4f60\u4f7f\u7528\u7684\u662f\u4ece\u6a21\u677f\u914d\u7f6e\u7684\u73af\u5883, \u90a3\u4e48\u4f60\u5e94\u8be5\u4f1a\u770b\u5230\u5982\u4e0b\u5185\u5bb9:
.csproj<Project Sdk=\"Microsoft.NET.Sdk\">\n <Import Project=\"CelesteMod.props\" />\n <Import Project=\"Common.props\" />\n <PropertyGroup>\n <RootNamespace>$(AssemblyName)</RootNamespace>\n <LangVersion>preview</LangVersion>\n </PropertyGroup>\n\n <ItemGroup>\n <Reference Include=\"System\" />\n <Reference Include=\"System.Core\" />\n <Reference Include=\"System.Xml.Linq\" />\n <Reference Include=\"System.Xml\" />\n </ItemGroup>\n\n <Import Project=\"CelesteMod.targets\" />\n</Project>\n
Note
\u8fd9\u4e2a\u6587\u4ef6\u662f XML \u683c\u5f0f\u7684, \u5982\u679c\u4f60\u4e0d\u719f\u6089 XML \u7684\u8bdd\u4f60\u53ef\u4ee5\u5230\u8fd9\u91cc\u7b80\u5355\u770b\u4e00\u4e0b, \u514d\u5f97\u4f60\u4e0d\u77e5\u9053\u6211\u4eec\u8ba8\u8bba\u7684\u4e1c\u897f\u90fd\u662f\u4ec0\u4e48
\u5176\u4e2d\u6211\u4eec\u53ea\u9700\u8981\u5173\u6ce8\u91cc\u9762\u7684 PropertyGroup
\u4ee5\u53ca ItemGroup
\u8282\u70b9 PropertyGroup
\u8282\u70b9\u5b9a\u4e49\u4e86\u8fd9\u4e2a\u9879\u76ee\u6709\u54ea\u4e9b\u5c5e\u6027, \u6bd4\u5982\u9879\u76ee\u6846\u67b6\u7248\u672c, \u8bed\u8a00\u7248\u672c, \u7a0b\u5e8f\u96c6\u6635\u79f0\u7b49 ItemGroup
\u5219\u5b9a\u4e49\u4e86\u8fd9\u4e2a\u9879\u76ee\u5305\u542b\u4ec0\u4e48, \u6bd4\u5982\u5f15\u7528\u4e86\u54ea\u4e9b\u7a0b\u5e8f\u96c6\u3001\u54ea\u4e9b nuget \u5305\u7b49.
"},{"location":"begin/preference/#implicit-usings-using","title":"Implicit Usings (\u9690\u5f0f Using)","text":"Note
\u5bf9\u4e8e\u901a\u8fc7\u6a21\u677f\u6784\u5efa\u7684\u9879\u76ee\u6765\u8bf4\u8fd9\u4e00\u6b65\u5df2\u7ecf\u5b8c\u6210, \u4f60\u53ef\u4ee5\u5c1d\u8bd5\u5c06 Common.props
\u4e2d\u7684 CommonCelesteUsings
\u66f4\u6539\u4e3a false
\u6765\u611f\u53d7\u6ca1\u6709\u542f\u7528\u7684\u6548\u679c
\u73b0\u5728\u770b\u770b\u4f60\u7684\u6e90\u6587\u4ef6\u5934\u9876\u662f\u4e0d\u662f\u5145\u6ee1\u4e86\u4e00\u5927\u5806 using xxx
? \u90a3\u5c31\u5bf9\u4e86, \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e2a\u7279\u6027\u6765\u8ba9\u5b83\u770b\u8d77\u6765\u66f4\u7b80\u4ecb\u4e9b. \u90a3\u4e48\u6253\u5f00\u4f60\u7684\u9879\u76ee\u6587\u4ef6, \u5411\u4f60\u7684 ItemGroup
\u4e2d\u52a0\u5165\u8fd9\u4e9b:
<Using Include=\"System\"/>\n<Using Include=\"System.Collections.Generic\"/>\n<Using Include=\"System.IO\"/>\n<Using Include=\"System.Linq\"/>\n<Using Include=\"System.Threading\"/>\n<Using Include=\"System.Threading.Tasks\"/>\n
\u8fd9\u4e2a\u65f6\u5019\u4f60\u5c31\u53ef\u4ee5\u79fb\u9664\u4f60\u7684\u5927\u90e8\u5206 System
\u5f00\u5934\u7684 Using \u8bed\u53e5\u5566, \u8fd9\u88ab\u79f0\u4e3a \u9690\u5f0f Using
, \u56e0\u4e3a\u6211\u4eec\u662f\u851a\u84dd mod, \u6240\u4ee5\u6211\u4eec\u7ecf\u5e38\u4e5f\u4f1a Using \u4ee5\u4e0b\u51e0\u4e2a\u547d\u540d\u7a7a\u95f4:
Celeste.Mod
: \u5305\u542b\u5f88\u591a Everest \u76f8\u5173\u4e1c\u897f Celeste
: \u851a\u84dd\u672c\u4f53\u6240\u5728\u547d\u540d\u7a7a\u95f4 Monocle
: \u851a\u84dd\u81ea\u5df1\u7684\u6e38\u620f\u5f15\u64ce Microsoft.Xna.Framework
: \u851a\u84dd\u81ea\u5df1\u7684\u6e38\u620f\u5f15\u64ce\u7684\u5e95\u5c42\u6846\u67b6 \u5bf9\u8fd9\u4e9b\u9690\u5f0f Using \u6211\u4eec\u4e5f\u5411 ItemGroup
\u52a0\u5165:
<Using Include=\"Celeste.Mod\"/>\n<Using Include=\"Celeste\"/>\n<Using Include=\"Monocle\"/>\n<Using Include=\"Microsoft.Xna.Framework\"/>\n
\u73b0\u5728\u6253\u5f00\u4f60\u7684\u4ee3\u7801\u6587\u4ef6, \u4f60\u53ef\u4ee5\u5c06\u5934\u9876\u4e0a\u7684\u5927\u90e8\u5206 Using \u90fd\u5220\u9664\u4e86, \u8fd9\u6837, \u4f60\u7684\u4ee3\u7801\u6587\u4ef6\u53d8\u7684\u66f4\u52a0\u7684\u5e72\u51c0\u6574\u6d01: MyModModule.cs
namespace MyCelesteMod\n{\n public class MyModModule : EverestModule\n {\n public override void Load()\n {\n\n Logger.Log(LogLevel.Info, \"MyCelesteMod\", \"Hello World! Hello Everest!\");\n }\n\n public override void Unload()\n {\n\n }\n }\n}\n
"},{"location":"begin/preference/#file-scoped-namespaces","title":"File Scoped Namespaces","text":"\u5bf9\u4e8e namespace \u547d\u540d\u7a7a\u95f4\u6765\u8bf4\u6211\u4eec\u901a\u5e38\u4e00\u4e2a\u6587\u4ef6\u53ea\u6709\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4, \u90a3\u4e48\u6700\u5916\u5c42\u7684 namespace \u7684\u7f29\u8fdb\u5c31\u6709\u4e9b\u6d6a\u8d39\u6a2a\u5411\u7a7a\u95f4, \u6240\u4ee5\u6211\u4eec\u9009\u62e9\u4f7f\u7528 File Scoped Namespaces
, \u8fd9\u5f88\u7b80\u5355:
\u5728 namespace MyCelesteMod
\u540e\u52a0\u4e0a\u4e00\u4e2a\u5206\u53f7 \u5220\u9664 namespace \u7684\u4e24\u4e2a\u5927\u62ec\u53f7 \u56de\u9000 namespace \u4e0b\u7684\u6240\u6709\u7f29\u8fdb \u641e\u5b9a\u4e86, \u8d70\u4f60! MyModModule.csnamespace MyCelesteMod;\n\npublic class MyModModule : EverestModule\n{\n public override void Load()\n {\n Logger.Log(LogLevel.Info, \"MyCelesteMod\", \"Hello World! Hello Everest!\");\n }\n\n public override void Unload()\n {\n\n }\n}\n
Info
\u5982\u679c\u4f60\u6536\u5230\u9519\u8bef CS8370
, \u90a3\u4f60\u53ef\u80fd\u9700\u8981\u5728 PropertyGroup
\u4e0b\u6dfb\u52a0\u8fd9\u4e00\u884c:
<LangVersion>preview</LangVersion>\n
"},{"location":"begin/preference/#_3","title":"\u65b9\u6cd5? \u51fd\u6570?","text":"\u55ef\u8fd9\u4e2a\u662f\u540e\u6765\u52a0\u7684, \u56e0\u4e3a\u6211\u53d1\u73b0\u6211\u5728\u6574\u4e2a\u6587\u6863\u91cc\u90fd\u5728\u6df7\u7528 \"\u65b9\u6cd5\" \u548c \"\u51fd\u6570\" \u8fd9\u4e24\u4e2a\u540d\u5b57, \u4f46\u662f\u4fee\u6539\u8d77\u6765\u6bd4\u8f83\u9ebb\u70e6\u6240\u4ee5\u6211\u8fd8\u662f\u9009\u62e9\u5728\u8fd9\u91cc\u8bf4\u51e0\u53e5: \"\u51fd\u6570\" \u662f\u6e90\u81ea\u53e4\u65e9\u7684\u9762\u5411\u8fc7\u7a0b\u8bed\u8a00\u7684\u6982\u5ff5, \u540e\u6765\u968f\u7740 OOP \u9762\u5411\u5bf9\u8c61\u601d\u60f3\u7684\u6d41\u884c, \u51fd\u6570\u9010\u6e10\u88ab\u5c01\u88c5\u5230\u7c7b\u91cc, \u800c\u7c7b\u91cc\u7684\u8fd9\u4e9b\u51fd\u6570\u5728\u4e60\u60ef\u4e0a\u6211\u4eec\u624d\u4f1a\u79f0\u4e4b\u4e3a \"\u65b9\u6cd5\", \u4f46\u662f\u4e5f\u6709\u4eba\u4ecd\u7136\u5c06\u8fd9\u4e9b\u4e1c\u897f\u79f0\u4e4b\u4e3a \"\u51fd\u6570\", \u6240\u4ee5\u5b9e\u9645\u4e0a\u5728\u9762\u5411\u5bf9\u8c61\u7684\u8bed\u8a00\u91cc\u4f60\u53ef\u4ee5\u5c06 \"\u65b9\u6cd5\" \u548c \"\u51fd\u6570\" \u770b\u4e3a\u4e00\u4e2a\u4e1c\u897f, \u6216\u8005\u4ec5\u5728\u672c\u6587\u6863\u4e2d\u8fd9\u4e48\u770b.
"},{"location":"begin/reading_2/","title":"\u9605\u8bfb\u4ee3\u7801 II","text":"\u4e00\u4e9b\u60c5\u51b5\u4e0b, \u9605\u8bfb\u7531\u53cd\u7f16\u8bd1\u5668\u751f\u6210\u7684\u4ee3\u7801\u65f6\u53ef\u80fd\u4e0d\u662f\u90a3\u4e48\u987a\u5229, \u90a3\u4e48\u8fd9\u4e00\u8282\u4f1a\u7b80\u5355\u8bf4\u4e00\u4e9b\u53cd\u7f16\u8bd1\u5668\u751f\u6210\u7684\u4ee3\u7801\u4e0e\u901a\u5e38\u7684 C# \u4ee3\u7801\u4e0d\u4e00\u6837\u7684\u5730\u65b9.
"},{"location":"begin/reading_2/#_1","title":"\u5947\u5947\u602a\u602a\u7684\u6635\u79f0\u4e0e\u4ee3\u7801","text":"\u5728\u53cd\u7f16\u8bd1\u5668\u4e2d\u53ef\u80fd\u4f1a\u51fa\u73b0\u8fd9\u79cd\u5947\u602a\u7684\u8bed\u6cd5: Celeste.FinalBoss (\u5373 6a \u540e\u534a\u6bb5 Badeline Boss \u5b9e\u4f53)
public void orig_ctor(EntityData e, Vector2 offset)\n{\n this..ctor(e.Position + offset, e.NodesOffset(offset), e.Int(\"patternIndex\", 0), e.Float(\"cameraPastY\", 120f), e.Bool(\"dialog\", false), e.Bool(\"startHit\", false), e.Bool(\"cameraLockY\", true));\n}\n
\u55ef...\u597d\u7684, \u9996\u5148 orig_ctor
\u8fd9\u4e2a\u540d\u5b57\u6709\u70b9\u602a\u4f46\u662f\u80fd\u63a5\u53d7, \u4f46\u662f\u63a5\u4e0b\u6765\u7684 this..ctor
\u662f\u4ec0\u4e48? \u5b83\u751a\u81f3\u5728 C#
\u4e2d\u662f\u4e2a\u975e\u6cd5\u8bed\u6cd5! \u5176\u5b9e\u8fd9\u5e76\u4e0d\u7f55\u89c1, \u7531\u4e8e Everest \u5bf9\u851a\u84dd\u7a0b\u5e8f\u7684\u4fee\u6539\u5e76\u4e0d\u53ea\u662f\u505c\u7559\u5728\u8868\u9762, \u800c\u66f4\u662f\u6df1\u5165\u5230\u4e86 IL \u4ee3\u7801\u5c42, \u8fd9\u662f\u4e00\u79cd\u76f8\u5bf9\u5e95\u5c42\u7684\u4ee3\u7801, \u4f60\u7684 C#
\u4ee3\u7801\u6700\u7ec8\u90fd\u4f1a\u88ab\u7f16\u8bd1\u4e3a IL
\u7136\u540e\u6254\u7ed9\u8fd0\u884c\u65f6(runtime)\u6765\u6267\u884c, \u540c\u6837\u5730, \u6240\u6709\u5176\u4ed6\u7684 .NET
\u7cfb\u8bed\u8a00\u6bd4\u5982 VB.NET
\u548c F#
\u4e5f\u90fd\u4f1a\u88ab\u7f16\u8bd1\u4e3a IL. \u90a3\u4e48\u65e2\u7136\u8fd9\u91cc\u7684 IL \u662f\u7531 C#
\u7f16\u8bd1\u800c\u6765\u7684, \u90a3\u4e48\u8fd9\u6837\u7684 IL \u591a\u591a\u5c11\u5c11\u4f1a\u6709\u4e00\u79cd \"C# \u5473\", \u53cd\u7f16\u8bd1\u5668\u5c31\u662f\u9760\u8fd9\u79cd\u4e00\u5b9a\u7684 \"C# \u5473\" \u6765\u9006\u63a8\u51fa\u53ef\u80fd\u7684 C#
\u6e90\u7801. \u4f46\u662f\u65e2\u7136\u8fd9\u91cc Everest \u76f4\u63a5\u5728 IL \u4ee3\u7801\u5c42\u8fdb\u884c\u4e86\u4fee\u6539, \u7834\u574f\u4e86\u8fd9\u79cd \"C# \u5473\", \u90a3\u81ea\u7136\u53cd\u7f16\u8bd1\u5668\u5c31\u4f1a\u751f\u6210\u5947\u5947\u602a\u602a\u751a\u81f3\u975e\u6cd5\u7684\u4ee3\u7801.
\u90a3\u4e48\u8fd9\u91cc\u751f\u6210\u7684\u5947\u602a\u975e\u6cd5\u7684\u4ee3\u7801\u662f\u4ec0\u4e48?
"},{"location":"begin/reading_2/#ctor-cctor","title":".ctor / .cctor","text":".ctor
\u662f\u4e00\u4e2a\u7279\u6b8a\u7684\u51fd\u6570\u540d\u79f0, \u8868\u793a\u8be5\u7c7b\u7684\u6784\u9020\u51fd\u6570, \u6bd4\u5982 Player..ctor(a, b)
\u5373\u8868\u793a\u8c03\u7528 Player
\u7c7b\u7684 .ctor
\u51fd\u6570, \u867d\u7136\u4f60\u81ea\u5df1\u662f\u505a\u4e0d\u5230\u7684.
.cctor
\u4e5f\u662f\u4e00\u4e2a\u7279\u6b8a\u7684\u51fd\u6570\u540d\u79f0, \u8868\u793a\u8be5\u7c7b\u7684\u9759\u6001\u6784\u9020\u51fd\u6570, \u6bd4\u5982 Input..cctor()
\u5373\u8868\u793a\u8c03\u7528 Input
\u7c7b\u7684\u65e0\u53c2\u9759\u6001\u6784\u9020\u51fd\u6570.
\u8fd9\u4e00\u7c7b\u51fd\u6570\u5728 IL
\u5c42\u6709\u4e2a\u6807\u8bb0\u53eb special name
, \u5f53\u53cd\u7f16\u8bd1\u5668\u53d1\u73b0\u4e00\u4e2a\u65b9\u6cd5\u540d\u4e3a .ctor
\u4e14\u5e26\u6709 special name
\u6807\u8bb0\u7684\u65b9\u6cd5\u65f6, \u53cd\u7f16\u8bd1\u5668\u5c31\u4f1a\u8ba4\u4e3a\u5b83\u662f\u4e00\u4e2a\u6784\u9020\u51fd\u6570, \u5982\u679c\u53cd\u7f16\u8bd1\u5668\u53d1\u73b0\u8fd9\u4e2a\u65b9\u6cd5\u5728\u4e00\u4e2a\u6784\u9020\u51fd\u6570\u5f00\u5934\u8c03\u7528\u4e86, \u90a3\u4e48\u53cd\u7f16\u8bd1\u5668\u5c31\u4f1a\u8ba4\u4e3a\u8fd9\u4e2a\u6784\u9020\u51fd\u6570\u5e26\u4e00\u4e2a\u6784\u9020\u51fd\u6570\u94fe, \u4f46\u662f\u5982\u679c\u5b83\u7684\u8c03\u7528\u4f4d\u7f6e\u5728\u5176\u4ed6\u4f4d\u7f6e, \u540c\u65f6\u53c8\u56e0\u4e3a C#
\u7f16\u8bd1\u5668\u662f\u4e0d\u53ef\u80fd\u8fd9\u4e48\u7f16\u8bd1\u7684, \u90a3\u4e48\u53cd\u7f16\u8bd1\u5668\u5c31\u4f1a\u4e0d\u77e5\u6240\u63aa, \u53ea\u80fd\u65e0\u5948\u7684\u751f\u6210 xxx..ctor()
\u8fd9\u79cd\u9519\u8bef\u7684\u8bed\u6cd5. \u8fd9\u4e5f\u662f\u6211\u4eec\u4e0a\u9762\u770b\u5230\u7684 this..ctor
\u8fd9\u79cd\u8bed\u6cd5\u88ab\u751f\u6210\u7684\u539f\u56e0, \u56e0\u4e3a\u8fd9\u4e2a\u6784\u9020\u51fd\u6570\u8c03\u7528\u4e0d\u5728\u6784\u9020\u51fd\u6570\u91cc\u51fa\u73b0, \u800c\u662f\u5728\u4e00\u4e2a\u6b63\u5e38\u7684 orig_ctor
\u65b9\u6cd5\u91cc\u9762!
Info
ctor
\u8fd9\u4e2a\u5947\u602a\u7684\u7f29\u5199\u6765\u81ea\u5355\u8bcd constructor
, \u76f4\u8bd1\u5373 \u6784\u9020\u5668
.
\u6240\u4ee5\u6211\u4eec\u901a\u5e38\u4e5f\u4f1a\u7528 .ctor
ctor
\u6765\u6307\u4ee3\u6784\u9020\u51fd\u6570, .cctor
cctor
\u6307\u4ee3\u9759\u6001\u6784\u9020\u51fd\u6570. \u6b64\u5916, Visual Studio \u4e2d\u6709\u4e2a\u81ea\u5e26\u7684\u4ee3\u7801\u7247\u6bb5\u5c31\u662f ctor
, \u5728\u7c7b\u4e2d\u6253\u51fa ctor \u5e76\u53cc\u51fb Tab \u952e, vs \u5c31\u4f1a\u81ea\u52a8\u751f\u6210\u8be5\u7c7b\u7684\u6784\u9020\u51fd\u6570, \u8fd9\u91cc\u7684 ctor
\u6765\u6e90\u4e5f\u5c31\u5728\u6b64.
Info
\u5728\u524d\u9762\u7684\u94a9\u5b50\u8282\u6211\u4eec\u6ca1\u6709\u63a2\u8ba8\u8fc7\u6784\u9020\u51fd\u6570\u5982\u4f55\u94a9\u53d6, \u5728\u8fd9\u91cc\u4f60\u53ef\u80fd\u5c31\u4f1a\u660e\u767d, \u94a9\u53d6\u540d\u5b57\u4e3a ctor
\u7684\u51fd\u6570\u5c31\u662f\u94a9\u53d6\u4e86\u6784\u9020\u51fd\u6570, \u9759\u6001\u6784\u9020\u51fd\u6570\u540c\u7406.
"},{"location":"begin/reading_2/#orig_","title":"orig_*","text":"\u8fd8\u6709\u4e00\u4e9b\u51fd\u6570\u4ee5 orig_
\u5f00\u5934, \u8fd9\u5176\u5b9e\u662f everest \u81ea\u5df1\"\u94a9\u53d6\"\u7684\u51fd\u6570. \u5728\u8fd9\u91cc, \u6bd4\u5982 Player.Update
\u65b9\u6cd5\u5c31\u88ab everest \u8fdb\u884c\u4e86\"\u94a9\u53d6\", \u800c\u94a9\u5b50\u51fd\u6570\u672c\u4f53\u5c31\u662f Player.Update
, \u800c\u5bf9\u5e94\u6211\u4eec\u94a9\u5b50\u7684 orig
\u59d4\u6258\u5728\u5c31\u4f53\u73b0\u4e3a orig_Update
\u65b9\u6cd5.
Player.Update (\u50cf\u94a9\u5b50\u672c\u4f53\u4e00\u6837!)public override void Update()\n{\n this.orig_Update(); // \u5c31\u50cf\u5728\u6211\u4eec\u7684\u94a9\u5b50\u91cc\u8c03\u7528 orig \u59d4\u6258\u4e00\u6837\n // \u5c31\u50cf\u5728\u6211\u4eec\u7684\u94a9\u5b50\u91cc\u5728\u51fd\u6570\u6267\u884c\u5b8c\u540e\u505a\u4e9b\u4e8b\u60c5\u4e00\u6837\n Level level = base.Scene as Level;\n if (level == null)\n ......\n}\n// Player.orig_Update() \u5c31\u50cf\u6211\u4eec\u7684\u94a9\u5b50\u94a9\u53d6\u7684\u539f\u51fd\u6570!\n
Info
\u5982\u679c\u4f60\u81ea\u884c\u94a9\u53d6 Player.Update
\u51fd\u6570\u8fd9\u79cd\u5df2\u88ab everest \"\u94a9\u53d6\" \u7684\u51fd\u6570\u5b9e\u9645\u4e0a\u4f60\u94a9\u53d6\u7684\u662f everest \u7684\u94a9\u5b50, \u8fd9\u5bf9\u4e8e On
\u94a9\u5b50\u53ef\u80fd\u6ca1\u6709\u5927\u5f71\u54cd, \u4f46\u662f\u5bf9\u4e8e\u540e\u9762\u6211\u4eec\u4f1a\u8bf4\u7684 IL
\u94a9\u5b50\u6709\u5f88\u5927\u5f71\u54cd, \u4e0d\u8fc7\u8fd9\u4e9b\u6211\u4eec\u7b49\u5230\u540e\u9762\u518d\u8bf4.
"},{"location":"begin/reading_2/#statemachine","title":"StateMachine","text":"\u8fd9\u662f Monocle \u4e2d\u7684\u4e00\u4e2a Component \u7c7b, \u662f\u4e00\u4e2a\u72b6\u6001\u673a\u7684\u5b9e\u73b0, \u5177\u4f53\u7684\u7528\u6cd5\u6211\u4f1a\u5728 \u5e38\u89c1 Celeste, Monocle \u7c7b\u5728\u5199\u4e86.jpg \u8282\u8bf4, \u8fd9\u91cc\u4ec5\u662f\u65b9\u4fbf\u4f60\u9605\u8bfb\u4e00\u4e0b\u76f8\u5173\u7684\u4ee3\u7801:
"},{"location":"begin/reading_2/#st","title":"St*
\u7c7b\u5b57\u6bb5","text":"\u5728\u9605\u8bfb Player
\u7c7b\u7684\u4ee3\u7801\u65f6, \u4f60\u4f1a\u770b\u5230\u8fd9\u4e9bSt
\u5f00\u5934\u540d\u5b57\u7684\u5e38\u91cf\u4f46\u662f\u4f60\u627e\u4e0d\u5230\"\u88ab\u4f7f\u7528\"\u7684\u5730\u65b9:
const int StNormal = 0; const int StClimb = 1; const int StDash = 2; const int StSwim = 3; const int StBoost = 4; ...... \u8fd9\u4e9b\u662f\u73a9\u5bb6\u72b6\u6001\u673a\u7684\u72b6\u6001\u7f16\u53f7, \u81f3\u4e8e\u4f60\u627e\u4e0d\u5230\"\u88ab\u4f7f\u7528\"\u662f\u56e0\u4e3a\u5bf9\u4e8e const \u5e38\u91cf\u6210\u5458, c# \u7f16\u8bd1\u5668\u5728\u7f16\u8bd1\u671f\u5c31\u628a\u5f15\u7528\u7684\u8fd9\u4e9b\u4e1c\u897f\u76f4\u63a5\u66ff\u6362\u4e3a\u4e86\u6570\u5b57, \u4f60\u80fd\u770b\u5230\u7684\u53ea\u6709\u4fdd\u7559\u4e0b\u6765\u7684\u8fd9\u4e9b\u5e38\u91cf\u7684\u503c\u548c\u540d\u5b57. \u90a3\u8fd9\u6837\u4ee3\u7801\u4e2d\u5c31\u4e0d\u907f\u514d\u7684\u51fa\u73b0\u4e86\u5947\u602a\u7684\u9b54\u6570, \u6bd4\u5982\u8fd9\u91cc\u7684 24: int Player.FlingBirdUpdate()
private int FlingBirdUpdate()\n{\n base.MoveTowardsX(this.flingBird.X, 250f * Engine.DeltaTime, null);\n base.MoveTowardsY(this.flingBird.Y + 8f + base.Collider.Height, 250f * Engine.DeltaTime, null);\n return 24;\n}\n
Info
FlingBirdUpdate \u662f\u4e00\u4e2a\u72b6\u6001\u673a\u7684 Update \u51fd\u6570, \u6240\u6709\u8be5\u7c7b\u51fd\u6570\u7684\u8fd4\u56de\u503c\u8868\u793a\u4e0b\u4e00\u5e27\u73a9\u5bb6\u7684\u72b6\u6001\u5e94\u8be5\u662f\u4ec0\u4e48.
\u4f60\u80af\u5b9a\u5f88\u7591\u60d1\u8fd9\u4e2a\u5947\u602a\u7684 24 \u662f\u4ec0\u4e48, \u8fd9\u91cc\u6211\u4eec\u5df2\u7ecf\u77e5\u9053\u5b83\u662f\u4e2a\u72b6\u6001\u673a\u7f16\u53f7\u4e86, \u6211\u4eec\u53ea\u9700\u8981\u4e00\u4e0b\u8fd9\u4e2a\u7f16\u53f7\u5bf9\u5e94\u7684\u72b6\u6001. \u7ecf\u8fc7\u67e5\u8be2, \u4f60\u4f1a\u77e5\u9053\u7f16\u53f7\u4e3a 24 \u7684\u72b6\u6001\u662f StFlingBird
, \u5373\u88ab\u9e1f\u6254\u72b6\u6001(\u7b26\u5408\u8fd9\u91cc\u7684\u51fd\u6570\u540d!):
const int StFlingBird = 24;\n
\u5728\u8fd9\u91cc\u4f1a\u7b80\u5355\u5217\u51fa\u4e00\u4e0b Player
\u7684\u6240\u6709\u72b6\u6001\u4fbf\u4e8e\u67e5\u8be2:
const int StNormal = 0; // \u6b63\u5e38\nconst int StClimb = 1; // \u6500\u722c\nconst int StDash = 2; // \u51b2\u523a\nconst int StSwim = 3; // \u6c34\u4e2d\nconst int StBoost = 4; // \u7eff\u6ce1\u6ce1\u4e2d\nconst int StRedDash = 5; // \u7ea2\u6ce1\u6ce1\u4e2d\nconst int StHitSquash = 6; // \u7ea2\u6ce1\u6ce1\u649e\u5899\u6216\u649e\u5730\nconst int StLaunch = 7; // \u88ab \u5f39\u7403, \u9c7c \u5f39\u5f00\nconst int StPickup = 8; // \u6361\u8d77\u6293\u53d6\u7269\nconst int StDreamDash = 9; // \u7a7f\u679c\u51bb\nconst int StSummitLaunch = 10; // badeline\u6700\u540e\u4e00\u6b21\u4e0a\u629b\nconst int StDummy = 11; // \u5267\u60c5\u8fc7\u573a\u72b6\u6001\nconst int StIntroWalk = 12; // Walk \u7c7b\u578b\u7684 Intro (Intro \u5373\u73a9\u5bb6\u8fdb\u5165\u5173\u5361\u7684\u8868\u73b0\u65b9\u5f0f)\nconst int StIntroJump = 13; // Jump \u7c7b\u578b\u7684 Intro (1a)\nconst int StIntroRespawn = 14; // Respawn \u7c7b\u578b\u7684 Intro (\u91cd\u751f)\nconst int StIntroWakeUp = 15; // WakeUp \u7c7b\u578b\u7684 Intro (2a awake)\nconst int StBirdDashTutorial = 16; // \u5e8f\u7ae0\u6559\u51b2\u523a\u65f6\u51b2\u523a\u7ed3\u675f\u540e\u8fdb\u5165\u7684\u72b6\u6001\nconst int StFrozen = 17; // \u672a\u77e5\nconst int StReflectionFall = 18; // 6a-2 \u6389\u843d\u5267\u60c5\u6bb5\nconst int StStarFly = 19; // \u7fbd\u6bdb\u98de\u884c\nconst int StTempleFall = 20; // 5a \u955c\u5b50\u540e\u7684\u6389\u843d\u6bb5\nconst int StCassetteFly = 21; // \u6361\u5230\u78c1\u5e26\u540e\u7684\u6ce1\u6ce1\u5305\u88f9\u6bb5\nconst int StAttract = 22; // 6a badeline boss \u9760\u8fd1\u65f6\u7684\u5438\u5f15\u6bb5\nconst int StIntroMoonJump = 23; // 9a \u5f00\u573a\u4e0a\u5347\u5267\u60c5\u6bb5\nconst int StFlingBird = 24; // 9a \u9e1f\u6254\u72b6\u6001\nconst int StIntroThinkForABit = 25; // 9a Intro\n
"},{"location":"begin/simple_entity/","title":"\u7b80\u5355\u81ea\u5b9a\u4e49\u5b9e\u4f53","text":"\u5728\u77e5\u9053\u4e00\u4e9b mod \u5236\u4f5c\u4e2d\u6700\u4e3a\u57fa\u7840\u7684\u4e1c\u897f\u540e, \u6211\u4eec\u9996\u5148\u628a\u5174\u8da3\u70b9\u8f6c\u5411\u81ea\u5b9a\u4e49\u5b9e\u4f53, \u76f8\u4fe1\u76f8\u5bf9\u4e8e\u4fee\u6539\u5df2\u6709\u7684\u4e1c\u897f\u5e76\u4f34\u968f\u7740\u4e00\u5b9a\u7684\u70e7\u8111(\u6211\u8be5\u600e\u4e48\u6539? \u8fd9\u4e48\u6539\u4f1a\u4e0d\u4f1a\u7834\u574f\u5b98\u56fe\u5143\u7d20?), \u4f60\u53ef\u80fd\u66f4\u559c\u6b22\u81ea\u5df1\u5236\u4f5c\u4e00\u4e2a\u5b9e\u4f53, \u90a3\u5c31\u5bf9\u4e86! \u5728\u8fd9\u4e00\u8282, \u6211\u4eec\u4f1a\u4e86\u89e3 loenn \u7684\u57fa\u7840\u4f7f\u7528\u3001\u6dfb\u52a0\u4e00\u4e2a\u81ea\u5b9a\u4e49\u5b9e\u4f53\u7684\u901a\u7528\u6b65\u9aa4, \u4ee5\u53ca\u4e00\u4e9b\u6e38\u620f\u5e38\u7528\u7684\u65b9\u6cd5!
"},{"location":"begin/simple_entity/#_2","title":"\u6211\u4eec\u7684\u81ea\u5b9a\u4e49\u5b9e\u4f53\u7c7b","text":""},{"location":"begin/simple_entity/#_3","title":"\u5b83\u80fd\u5e72\u4ec0\u4e48","text":"\u5728\u5f00\u59cb\u5236\u4f5c\u8fd9\u4e2a\u81ea\u5b9a\u4e49\u5b9e\u4f53\u4e4b\u524d, \u6211\u4eec\u5148\u660e\u767d\u4e00\u4e0b\u8fd9\u4e2a\u5b9e\u4f53\u505a\u51fa\u6765\u662f\u4ec0\u4e48\u6548\u679c\u7684. \u90a3\u4e48, \u4e3a\u4e86\u7b80\u5355\u8d77\u89c1, \u8fd9\u91cc\u5c31\u505a\u4e00\u4e2a\u7b80\u5355\u7684\u529f\u80fd, \u5b83\u5927\u6982\u662f:
\u5b83\u53eb\u505a PassByRefill
\u957f\u5ea6\u548c\u5bbd\u5ea6\u662f\u968f\u610f\u7684 \u5b83\u770b\u8d77\u6765\u662f\u4e2a\u900f\u660e\u7684\u7ea2\u8272\u7269\u4f53 \u73a9\u5bb6\u4e0e\u5176\u78b0\u649e\u65f6\u4f1a\u9501\u5b9a\u4e3a\u67d0\u4e2a\u51b2\u523a\u6570 \u8fd9\u4e2a\u51b2\u523a\u6570\u53ef\u4ee5\u5728\u4f5c\u56fe\u8f6f\u4ef6\u4e2d\u8bbe\u7f6e \u662f\u7684\u5c31\u8fd9\u6837\u7b80\u5355, \u90a3\u4e48\u6211\u4eec\u5f00\u59cb\u5427.
"},{"location":"begin/simple_entity/#_4","title":"\u58f0\u660e\u8fd9\u4e2a\u7c7b","text":"Warning
\u5728\u524d\u9762\u6211\u4eec\u94a9\u53d6\u4e86 Player.Update()
\u5e76\u4e14\u5728\u4e00\u76f4\u4fee\u6539\u51b2\u523a\u6570\u4e3a 1! \u4e0d\u8981\u5fd8\u8bb0\u628a\u94a9\u5b50\u51fd\u6570\u4ee5\u53ca\u94a9\u53d6\u548c\u53d6\u6d88\u94a9\u53d6\u7684\u90a3\u4e9b\u4ee3\u7801\u5220\u6389, \u6700\u540e\u4f60\u7684 Module \u7c7b\u5e94\u8be5\u53ea\u5305\u542b\u4e24\u4e2a\u7a7a\u7684 Load
\u548c Unload
\u65b9\u6cd5!
\u9996\u5148\u5728\u4ee3\u7801\u4e2d, \u6211\u4eec\u9700\u8981\u58f0\u660e\u8fd9\u4e2a\u7c7b, \u4e5f\u5c31\u662f\u521b\u5efa\u4e00\u4e2a .cs \u6587\u4ef6, \u7136\u540e\u547d\u4e2a\u540d. \u5728\u8fd9\u91cc\u4f60\u8fd8\u9700\u8981\u7ee7\u627f\u4e00\u4e0b Entity
, \u5728\u524d\u9762\u6211\u4eec\u5df2\u7ecf\u4e86\u89e3\u8fc7\u4e86\u5b83\u662f Monocle
\u7684\u4e00\u4e2a\u7c7b, \u8868\u793a\u573a\u666f\u4e2d\u7684\u5b9e\u4f53. \u90a3\u4e48\u4f60\u5e94\u8be5\u4f1a\u5199\u51fa\u5982\u4e0b\u7684\u4ee3\u7801:
PassByRefill.csnamespace MyCelesteMod;\n\npublic class PassByRefill : Entity\n{\n\n}\n
ok, \u63a5\u4e0b\u6765, \u6211\u4eec\u52a0\u4e00\u4e2a\u8868\u793a\u51b2\u523a\u6570\u7684\u5b57\u6bb5, \u7136\u540e\u641e\u4e00\u4e2a\u6784\u9020\u51fd\u6570\u63a5\u6536\u5e76\u8d4b\u503c\u5b83: PassByRefill.cs
public int Dashes = 0;\n\npublic PassByRefill(Vector2 position, Vector2 size, int dashes)\n{\n Position = position;\n Dashes = dashes;\n}\n
\u8fd9\u91cc\u7684 position
\u53c2\u6570\u4f1a\u88ab\u7528\u4e8e\u8bbe\u7f6e\u5b83\u7684 Position
\u5b57\u6bb5, \u8fd9\u4e2a\u5b57\u6bb5\u4ece Monocle.Entity
\u7ee7\u627f\u800c\u6765, \u5b83\u8868\u793a\u8fd9\u4e2a Entity
\u5728\u573a\u666f\u4e2d\u6240\u5728\u7684\u4f4d\u7f6e(\u4e16\u754c\u5750\u6807). Vector2
\u662f\u4e00\u4e2a XNA \u4e2d\u7684\u7ed3\u6784\u4f53, \u5305\u542b\u4e00\u4e2a X
\u548c\u4e00\u4e2a Y
\u7684 float
\u5b57\u6bb5, \u5b83\u7528\u4e8e\u63cf\u8ff0\u4e00\u4e2a\u5e73\u9762\u5411\u91cf, \u5c31\u50cf\u4f60\u5728\u5e73\u9762\u76f4\u89d2\u5750\u6807\u7cfb\u4e2d\u6240\u505a\u7684\u4e00\u6837! \u4e0d\u8fc7\u8fd9\u91cc\u9700\u8981\u6ce8\u610f, \u6e38\u620f\u4e2d\u7684\u5750\u6807\u7cfb\u548c\u6211\u4eec\u901a\u5e38\u6570\u5b66\u4e2d\u7684\u5750\u6807\u7cfb\u4e0d\u540c, \u5b83\u7684\u539f\u70b9\u5728\u5de6\u4e0a\u89d2, X \u8f74\u6c34\u5e73\u5411\u53f3\u4f46\u662f Y \u8f74\u7ad6\u76f4\u5411\u4e0b! \u8bb0\u4f4f\u4e0d\u8981\u641e\u6df7\u4e86. \u4f60\u53ef\u80fd\u6ce8\u610f\u5230\u6211\u4eec\u5e76\u6ca1\u6709\u7406 size
\u8fd9\u4e2a\u8868\u793a\u5927\u5c0f\u53c2\u6570, \u7a0d\u7b49\u4e00\u4e0b, \u6211\u4eec\u7b49\u4f1a\u5c31\u4f1a\u4f7f\u7528\u5b83\u4e86.
\u63a5\u4e0b\u6765, \u6211\u4eec\u9700\u8981\u58f0\u660e\u4e00\u4e2a\u7279\u6b8a\u7684\u6784\u9020\u51fd\u6570, \u4ee5\u8ba9 Everest \u53cd\u5c04\u8c03\u7528\u5e76\u4f7f\u5f97\u6211\u4eec\u7684\u5b9e\u4f53\u53ef\u4ee5\u6b63\u5e38\u83b7\u53d6\u5730\u56fe\u7684\u6570\u636e: PassByRefill.cs
public PassByRefill(EntityData data, Vector2 offset) \n : this(data.Position + offset, new Vector2(data.Width, data.Height), data.Int(\"dashes\"))\n { }\n
\u5728\u8fd9\u91cc, EntityData data
\u50a8\u5b58\u4e86\u4f5c\u56fe\u8f6f\u4ef6\u4fdd\u5b58\u7684\u76f8\u5173\u6570\u636e, \u6211\u4eec\u8981\u63d0\u53d6\u5b83\u4eec\u5f88\u7b80\u5355. \u6bd4\u5982\u8bf4\u6211\u4eec\u8981\u63d0\u53d6\u4e00\u4e2a\u540d\u4e3a dashes
\u7684 int
\u7c7b\u578b\u7684\u6570\u636e, \u6211\u4eec\u5c31\u7b80\u5355\u5730\u8c03\u7528\u5b83\u7684\u65b9\u6cd5 Int(string name)
, \u7136\u540e\u662f\u5b83\u7684\u5927\u5c0f\u6570\u636e, \u5927\u5c0f\u5728\u8fd9\u662f\u4e2a\u7279\u6b8a\u7684\u4e1c\u897f, \u5f97\u9700\u8981\u901a\u8fc7 Width
\u548c Height
\u5b57\u6bb5\u6765\u63d0\u53d6, \u7136\u540e\u6211\u4eec\u6254\u8fdb Vector2
\u91cc\u5e76\u4f20\u9012\u7ed9\u6211\u4eec\u4e0a\u9762\u7684\u6784\u9020\u51fd\u6570. \u5bf9\u4e8e\u66f4\u591a\u65b9\u6cd5\u4ee5\u53ca\u8fd9\u90e8\u5206\u6570\u636e\u8be5\u5982\u4f55\u81ea\u5b9a\u4e49\u6211\u4eec\u4f1a\u5728\u672c\u8282\u540e\u534a\u90e8\u5206\u8bf4\u660e. Vector2 offset
\u53c2\u6570\u8868\u793a\u8fd9\u4e00\u9762\u7684\u6700\u5de6\u4e0a\u89d2\u7684\u4e16\u754c\u5750\u6807, EntityData
\u7684 Position
\u5b57\u6bb5\u8868\u793a\u7269\u4f53\u76f8\u5bf9\u4e8e\u8fd9\u4e00\u9762\u6700\u5de6\u4e0a\u89d2\u7684\u4f4d\u7f6e, \u6240\u4ee5\u6211\u4eec\u9700\u8981\u628a\u5b83\u76f8\u52a0\u6765\u5f97\u5230\u4e16\u754c\u5750\u6807. (\u56e0\u4e3a Entity.Position
\u901a\u5e38\u53ea\u5141\u8bb8\u4e16\u754c\u5750\u6807!)
Info
\u8fd9\u4e2a\u6784\u9020\u51fd\u6570\u7684\u7b7e\u540d\u4e5f\u80fd\u4e3a\u5176\u4ed6\u7684\u6837\u5b50, \u4f46\u662f\u6211\u4eec\u6700\u6700\u6700\u5e38\u7528\u7684\u4e00\u4e2a\u7248\u672c\u5c31\u662f\u4e0a\u9762\u8fd9\u4e2a
"},{"location":"begin/simple_entity/#everest","title":"\u8ba9 Everest \u627e\u5230\u5b83","text":"\u73b0\u5728\u6211\u4eec\u53ea\u5b9a\u4e49\u4e86\u4e00\u4e2a\u7c7b Everest \u90a3\u8fb9\u662f\u5565\u4e5f\u4e0d\u77e5\u9053\u7684, \u6240\u4ee5\u6211\u4eec\u5f97\u544a\u8bc9\u5b83, \u800c\u8fd9\u4e2a\u8fc7\u7a0b\u6211\u4eec\u4e00\u822c\u5c31\u53eb \u6ce8\u518c
. \u8981\u6ce8\u518c\u4e00\u4e2a\u81ea\u5b9a\u4e49\u5b9e\u4f53\u975e\u5e38\u7b80\u5355, \u6211\u4eec\u53ea\u9700\u8981\u5c06 CustomEntity
(\u5728\u547d\u540d\u7a7a\u95f4 Celeste.Mod.Entities
\u4e2d) \u88c5\u9970\u5230\u6211\u4eec\u7684\u7c7b\u4e0a\u5e76\u4f20\u5165\u6211\u4eec\u5b9e\u4f53\u7684 \"\u540d\u79f0 ID\". \u5c31\u50cf: PassByRefill.cs
[CustomEntity(\"MyCelesteMod/PassByRefill\")]\npublic class PassByRefill : Entity\n{\n......\n
\u5728\u8fd9\u91cc \"\u540d\u79f0 ID\" \u6211\u4eec\u4e00\u822c\u63a8\u8350\u4ee5 \"{Mod\u540d}/\u8be5\u5b9e\u4f53\u7c7b\u540d\" \u8fdb\u884c\u547d\u540d, \u5c31\u50cf\u8fd9\u91cc\u4e00\u6837, Mod \u540d\u4e3a MyCelesteMod
, \u7c7b\u540d\u4e3a PassByRefill
, \u5b9e\u4f53 \"\u540d\u79f0 ID\" \u5c31\u662f MyCelesteMod/PassByRefill
. \u8fd9\u91cc\u6211\u5efa\u8bae\u4f60\u8bb0\u4f4f\u5b83, \u5f85\u4f1a\u6211\u4eec\u4f1a\u5728\u4f5c\u56fe\u8f6f\u4ef6\u914d\u7f6e\u7684\u65f6\u5019\u7528\u5230."},{"location":"begin/simple_entity/#loenn","title":"Loenn","text":"\u4f5c\u56fe\u8f6f\u4ef6
\u851a\u84dd\u7684\u4f5c\u56fe\u8f6f\u4ef6\u6700\u6d41\u884c\u7684\u76ee\u524d\u6709 ahorn
\u4e0e loenn
, \u4e0d\u8fc7\u6211\u66f4\u63a8\u8350 loenn
, \u56e0\u4e3a ahorn
\u5b9e\u5728\u662f \u592a!!\u5361!!\u4e86!!
"},{"location":"begin/simple_entity/#_5","title":"\u57fa\u7840\u4f7f\u7528","text":"Loenn \u662f\u4e00\u4e2a\u851a\u84dd\u7684\u4f5c\u56fe\u8f6f\u4ef6, \u5f53\u7136\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528\u5b83\u4e0d\u662f\u5236\u4f5c\u51fa\u7cbe\u7f8e\u7684\u5730\u56fe, \u800c\u662f\u4ec5\u4ec5\u653e\u7f6e\u4e00\u4e0b\u6211\u4eec\u7684\u81ea\u5b9a\u4e49\u5b9e\u4f53! _(:\u0437\u300d\u2220)_, \u8fd9\u91cc\u6211\u4e0d\u600e\u4e48\u60f3\u91cd\u590d\u5b83\u7684\u57fa\u7840\u4f7f\u7528, \u6240\u4ee5\u6211\u63a8\u8350\u4f60\u53bb\u4ee5\u4e0b\u51e0\u4e2a\u89c6\u9891\u4e2d\u4e86\u89e3:
Bilibili \u3010Celeste\u851a\u84dd\u3011\u7535\u7bb1\u4f5c\u56fe\u6559\u7a0b\u91cd\u7f6e\u7248 0-1 Loenn\u7684\u5b89\u88c5 Bilibili \u3010Celeste\u851a\u84dd\u3011\u7535\u7bb1\u4f5c\u56fe\u6559\u7a0b\u91cd\u7f6e\u7248 1-1 Loenn\u7684\u4f7f\u7528 \u7248\u672c
\u5982\u679c\u4f60\u4e4b\u524d\u5df2\u7ecf\u4e0b\u8f7d\u4e86 Loenn, \u6211\u5efa\u8bae\u4f60\u786e\u4fdd\u5b83\u5347\u7ea7\u5230\u6700\u65b0\u7248\u4e86, \u56e0\u4e3a\u63a5\u4e0b\u6765\u7684\u67d0\u4e9b\u4e1c\u897f\u6211\u53ef\u80fd\u4e0d\u592a\u8bb0\u5f97\u662f\u54ea\u4e2a\u7248\u672c\u5f15\u5165\u7684\u4e86.
"},{"location":"begin/simple_entity/#loenn_1","title":"\u8ba9 Loenn \u627e\u5230\u6211\u4eec\u7684\u5b9e\u4f53","text":"\u76f8\u4fe1\u4f60\u73b0\u5728\u5df2\u7ecf\u61c2\u7684 Loenn \u57fa\u672c\u7684\u4f7f\u7528\u7528\u6cd5\u4e86, \u90a3\u4e48\u73b0\u5728, \u6211\u4eec\u8981\u7ed9 Loenn \u5199\u4e00\u4e9b\u4e1c\u897f\u8ba9\u5b83\u77e5\u9053\u6211\u4eec\u8fd9\u4e2a\u5b9e\u4f53 mapper \u4eec\u80fd\u7528\u4e86. \u9996\u5148\u6211\u4eec\u5728 ModFolder \u4e0b\u65b0\u5efa\u4e00\u4e2a\u53eb Loenn
\u7684\u6587\u4ef6\u5939, \u518d\u5728\u91cc\u9762\u65b0\u5efa\u4e00\u4e2a\u53eb entities
\u7684\u6587\u4ef6\u5939, \u518d\u5728\u91cc\u9762\u65b0\u5efa\u4e00\u4e2a\u53eb PassByRefill.lua
(\u4e5f\u5c31\u662f{\u5b9e\u4f53\u7c7b\u540d}.lua
) \u7684\u6587\u672c\u6587\u4ef6. \u73b0\u5728\u4f60\u7684\u76ee\u5f55\u7ed3\u6784\u5e94\u8be5\u662f\u8fd9\u6837\u7684:
ok, \u7136\u540e\u6211\u4eec\u6253\u5f00 PassByRefill.lua
, \u8fd9\u662f\u4e00\u4e2a lua
\u8bed\u8a00\u7684\u6e90\u6587\u4ef6, \u8fd9\u91cc\u6211\u4eec\u4e0d\u9700\u8981\u5f88\u591a lua
\u77e5\u8bc6, \u76f4\u63a5\u7167\u7740\u6284\u5c31\u597d\u4e86:
PassByRefill.lualocal entity = {}\n\nentity.name = \"MyCelesteMod/PassByRefill\"\nentity.placements = {\n name = \"normal\",\n data = {\n width = 16,\n height = 16,\n dashes = 1\n }\n}\n\nreturn entity\n
\u8fd8\u8bb0\u5f97\u6211\u4eec\u4e4b\u524d\u8bb0\u4f4f\u7684\u5b9e\u4f53 \"\u540d\u79f0 ID\" \u5417? \u5728\u8fd9\u91cc\u4f60\u5c31\u9700\u8981\u5c06\u5176\u8d4b\u503c\u7ed9 entity.name
.
\u7136\u540e\u662f entity
\u7684 placements
, \u5b83\u8868\u793a\u8fd9\u4e2a\u5b9e\u4f53\u7684\u653e\u7f6e\u9009\u9879, \u5728\u8fd9\u91cc\u6211\u4eec\u5148\u4e0d\u7ba1, \u4f60\u5c31\u7406\u89e3\u4e3a\u4f60\u5e0c\u671b Loenn \u600e\u4e48\u628a\u4f60\u8fd9\u4e2a\u5b9e\u4f53\u62c6\u5206\u4e3a\u591a\u4e2a\u653e\u7f6e\u9009\u9879, \u8fd9\u91cc\u6211\u4eec\u7684\u5199\u6cd5\u8868\u793a\u4e0d\u5e0c\u671b Loenn \u62c6\u5206\u5b83, \u5982\u679c\u8fd9\u91cc\u7684 placements
\u662f\u4e2a\u6570\u7ec4\u7684\u8bdd\u90a3\u4e48 Loenn \u5c31\u4f1a\u62c6\u5206\u5b83\u4e86. \u7ee7\u7eed\u5230 name
\u5c5e\u6027, \u5b83\u8868\u793a\u8fd9\u4e2a\u653e\u7f6e\u9009\u9879\u7684\u540d\u79f0, \u8fd9\u4e2a\u540d\u79f0\u662f\u4efb\u610f\u7684, \u5b83\u53ea\u88ab\u7528\u6765\u4f5c\u4e3a\u672c\u5730\u5316\u952e\u540d(\u672c\u5730\u5316\u5c31\u5305\u62ec\u6211\u4eec\u5e38\u8bf4\u7684\"\u6c49\u5316\"). \u7136\u540e\u662f data
\u5c5e\u6027, \u5b83\u8868\u793a\u8fd9\u4e2a\u5b9e\u4f53\u7684\u6570\u636e. \u5728\u8fd9\u91cc\u6211\u4eec\u58f0\u660e\u4e86\u4e09\u4e2a\u6570\u5b57\u7c7b\u578b\u7684\u5c5e\u6027: width
, height
, dashes
, \u524d\u4e24\u4e2a\u5c5e\u6027\u662f\u7279\u6b8a\u7684, \u5728\u4ee3\u7801\u4e2d\u63d0\u53d6\u53ea\u9700\u8981\u5bf9 EntityData
\u83b7\u53d6 Width
/Height
\u5b57\u6bb5\u5373\u53ef. \u7b2c\u4e09\u4e2a dashes
\u5c5e\u6027\u5c31\u662f\u6211\u4eec\u7684\u81ea\u5b9a\u4e49\u5c5e\u6027 \u5728 data
\u5bf9\u8c61\u91cc\u7684\u5c5e\u6027, \u540e\u9762\u7684\u7b49\u53f7\u5c31\u8868\u793a\u5b83\u7684\u9ed8\u8ba4\u503c, \u6bd4\u5982 width
\u9ed8\u8ba4\u4e3a 16, dashes
\u9ed8\u8ba4\u4e3a 1.
Note
\u5982\u679c\u4f60\u4e0d\u58f0\u660e width
\u548c height
\u5c5e\u6027\u5e76\u4e14\u4e0d\u52a0\u8d34\u56fe\u7684\u8bdd Loenn \u4f3c\u4e4e\u4f1a\u76f4\u63a5\u7981\u6b62\u4f60\u653e\u7f6e\u8fd9\u4e2a\u5b9e\u4f53.
\u597d\u5427\u770b\u8d77\u6765\u4e0a\u9762\u8fd9\u4e00\u5768*\u975e\u5e38\u96be\u61c2*, \u4e0d\u8fc7\u6ca1\u5173\u7cfb, \u53ea\u8981\u4f60\u4f1a\u76f4\u63a5\u590d\u5236\u4e0a\u9762\u7684\u4e1c\u897f, \u6539\u4e00\u4e0b entity.name
, \u5411 data
\u91cc\u52a0\u4e00\u4e9b\u5c5e\u6027\u5c31\u884c\u4e86. \u5b9e\u9645\u4e0a\u6211\u4e5f\u662f\u8fd9\u4e48\u505a\u7684.
\u90a3\u4e48, \u91cd\u65b0\u7f16\u8bd1\u6211\u4eec\u7684\u9879\u76ee, \u8ba9 msbuild
\u628a\u6211\u4eec\u7684\u4e1c\u897f\u590d\u5236\u8fc7\u53bb, \u8fd9\u65f6\u6253\u5f00\u6211\u4eec\u7684 Loenn (\u6216\u8005\u91cd\u542f Loenn), \u641c\u7d22\u4e00\u4e0b @MyCelesteMod
. \u90a3\u4e48\u5217\u8868\u4e0a\u5e94\u8be5\u53ea\u4f1a\u51fa\u73b0\u4e00\u4e2a\u540d\u5b57\u5f88\u5947\u602a\u7684\u9009\u9879(\u56e0\u4e3a\u6211\u4eec\u8fd8\u6ca1\u914d\u7f6e\u672c\u5730\u5316\u76f8\u5173\u7684\u4e1c\u897f!), \u73b0\u5728\u628a\u5b83\u653e\u5230\u4efb\u4f55\u4f60\u559c\u6b22\u7684\u5730\u65b9, \u6253\u5f00\u5b83\u7684\u5c5e\u6027\u6846, \u6211\u4eec\u5c31\u80fd\u770b\u5230\u4e00\u4e2a\u5927\u5927\u7684 dashes
\u5c5e\u6027\u5728\u4e0a\u9762\u5141\u8bb8\u6211\u4eec\u6539\u5566. \u4f60\u53ef\u80fd\u6ce8\u610f\u5230\u5b83\u662f\u5168\u767d\u7684! \u56e0\u4e3a\u6211\u4eec\u8fd8\u6ca1\u544a\u8bc9 Loenn \u5b83\u957f\u4ec0\u4e48\u6837! \u4e0d\u8fc7\u8fd9\u4e2a\u7b49\u4ee5\u540e\u6211\u4eec\u518d\u6765\u641e.
"},{"location":"begin/simple_entity/#_6","title":"\u56de\u5230\u4ee3\u7801","text":"\u73b0\u5728\u5728\u6e38\u620f\u4e2d\u8fdb\u5165\u653e\u4e86\u6211\u4eec\u90a3\u4e2a\u5b9e\u4f53\u7684\u90a3\u5f20\u56fe, \u7136\u540e\u5230\u4e4b\u524d\u4f60\u559c\u6b22\u7684\u90a3\u4e2a\u5730\u65b9, \u7136\u540e... \u662f\u7684, \u4f60\u5565\u4e5f\u4e0d\u4f1a\u770b\u89c1, \u56e0\u4e3a\u6211\u4eec\u4e5f\u6ca1\u544a\u8bc9\u6e38\u620f\u5b83\u957f\u4ec0\u4e48\u6837! \u540c\u65f6\u4f60\u8d70\u5230\u5b83\u9644\u8fd1, \u4e5f\u4e0d\u4f1a\u53d1\u751f\u4efb\u4f55\u4e8b, \u56e0\u4e3a\u6211\u4eec\u4e5f\u6ca1\u544a\u8bc9\u6e38\u620f\u8fd9\u4e2a\u5b9e\u4f53\u5e94\u8be5\u5e72\u4ec0\u4e48!
"},{"location":"begin/simple_entity/#_7","title":"\u544a\u8bc9\u6e38\u620f\u5b83\u8be5\u505a\u4ec0\u4e48","text":"\u90a3\u4e48, \u5c31\u50cf\u524d\u9762\u63cf\u8ff0\u7684\u4e00\u6837, \"\u73a9\u5bb6\u4e0e\u5176\u78b0\u649e\u65f6\u4f1a\u9501\u5b9a\u4e3a\u67d0\u4e2a\u51b2\u523a\u6570\", \u90a3\u4e48\u6211\u4eec\u9700\u8981\u505a\u4e00\u4e9b\u78b0\u649e. \u5728 Monocle
\u91cc\u8fd9\u9879\u5de5\u4f5c\u5f88\u7b80\u5355, \u6211\u4eec\u9996\u5148\u5728\u6784\u9020\u51fd\u6570\u91cc\u53bb new
\u4e00\u4e2a\u957f\u65b9\u5f62\u7684\u78b0\u649e\u7bb1: PassByRefill.PassByRefill
public PassByRefill(Vector2 position, Vector2 size, int dashes)\n{\n Hitbox hitbox = new(size.X, size.Y);\n}\n
Info
\u6211\u4eec\u5728\u8fd9\u91cc\u7528\u5230\u4e86\u4e4b\u524d\u7684 size
\u53c2\u6570
Hitbox
\u5c31\u662f\u6211\u4eec\u60f3\u8981\u7684\u957f\u65b9\u5f62\u78b0\u649e\u7bb1, \u5b83\u7684\u552f\u4e00\u7684\u6784\u9020\u5668\u63a5\u6536\u56db\u4e2a\u53c2\u6570, \u524d\u4e24\u4e2a\u53c2\u6570\u4e3a\u5b83\u7684\u5bbd\u9ad8, \u540e\u4e24\u4e2a\u53c2\u6570\u4e3a\u8fd9\u4e2a\u78b0\u649e\u7bb1\u7684\u504f\u79fb(\u56e0\u4e3a\u78b0\u649e\u7bb1\u6211\u4eec\u8981\u9644\u52a0\u5230 Entity
\u8eab\u4e0a, \u6240\u4ee5\u4f1a\u6709\u504f\u79fb\u8fd9\u4e2a\u4e1c\u897f), \u8fd9\u4e24\u4e2a\u53c2\u6570\u9ed8\u8ba4\u90fd\u4e3a 0. \u7136\u540e\u8bbe\u7f6e\u5230 Entity
\u8eab\u4e0a: PassByRefill.PassByRefill
Collider = hitbox;\n
Collider
\u662f Entity
\u7684\u4e00\u4e2a\u5c5e\u6027, \u5b83\u8868\u793a\u8fd9\u4e2a Entity
\u81ea\u8eab\u7684\u78b0\u649e\u7bb1. Collider
\u5c5e\u6027\u662f Collider
\u7c7b\u578b\u7684, \u5b83\u662f\u4e00\u4e2a\u62bd\u8c61\u7c7b\u8868\u793a\u4e00\u4e2a\u78b0\u649e\u4f53, \u8fd9\u91cc\u6211\u4eec\u7684 Hitbox
\u5c31\u662f\u5b83\u7684\u4e00\u4e2a\u5b9e\u73b0, \u4e5f\u5c31\u662f\u4e00\u79cd\u957f\u65b9\u5f62\u7684\u5b9e\u73b0. \u78b0\u649e\u7bb1\u8bbe\u7f6e\u5b8c\u540e, \u6211\u4eec\u5c31\u8be5\u5728 Update()
\u68c0\u6d4b\u78b0\u649e\u4e86, \u8fd9\u5f88\u7b80\u5355~ PassByRefill.Update()
public override void Update()\n{\n base.Update();\n // \u83b7\u53d6 Player \u5b9e\u4f8b (\u522b\u5bb3\u6015!)\n var player = Scene.Tracker.GetEntity<Player>();\n\n // \u68c0\u6d4b\u662f\u5426\u4e0e\u73a9\u5bb6\u78b0\u649e\n if (player is not null && this.CollideCheck(player))\n {\n // \u5982\u679c\u78b0\u649e\u4e86, \u90a3\u4e48\u8bbe\u7f6e\u5b83\u7684\u51b2\u523a\u6570\n player.Dashes = this.Dashes;\n }\n}\n
\u76f8\u4fe1\u4f60\u770b\u5230\u7b2c\u4e94\u884c\u4e00\u5b9a\u4f1a\u88ab\u5413\u4e00\u8df3! \u76f8\u4fe1\u90a3\u4e00\u4e32\u4e1c\u897f\u5bf9\u4e8e\u65b0\u4eba\u6765\u8bf4\u4e00\u5b9a\u5f88\u590d\u6742, \u4e0d\u8fc7\u6ca1\u5173\u7cfb, \u4f60\u53ea\u9700\u8981\u77e5\u9053\u90a3\u4e00\u4e32\u4f1a\u8fd4\u56de\u5728\u573a\u7684\u90a3\u4e2a\u73a9\u5bb6\u5c31\u884c(\u4e0d\u5728\u573a\u65f6\u4e3a null). \u7136\u540e\u6211\u4eec\u7528 Entity
\u7684 CollideCheck
\u68c0\u67e5\u6211\u4eec\u6709\u6ca1\u6709\u4e0e\u73a9\u5bb6\u53d1\u751f\u78b0\u649e, \u5982\u679c\u6709\u5219\u5f3a\u5236\u8bbe\u7f6e\u5b83\u7684\u51b2\u523a\u6570. \u7531\u4e8e\u6211\u4eec\u6bcf\u4e00\u5e27\u90fd\u5728\u68c0\u67e5, \u90fd\u5728\u8bbe\u7f6e, \u6240\u4ee5\u6700\u7ec8\u7684\u6548\u679c\u5c31\u662f\u73a9\u5bb6\u4e00\u65e6\u8fdb\u5165\u8fd9\u4e2a\u533a\u57df, \u51b2\u523a\u6570\u88ab\u9501\u5b9a\u4e3a Dashes
.
Info
\u5b9e\u9645\u4e0a\u8fd9\u91cc\u6709\u66f4\u597d\u7684\u65b9\u6cd5\u6765\u5355\u72ec\u68c0\u6d4b\u4e0e\u73a9\u5bb6\u7684\u78b0\u649e, \u4e3a\u4e86\u7b80\u5355\u8d77\u89c1\u8fd9\u91cc\u6ca1\u6709\u91c7\u7528. \u4e0d\u8fc7\u6211\u4eec\u4f9d\u7136\u4f1a\u5728\u540e\u9762\u63d0\u5230(\"\u5e38\u89c1 Celeste, Monocle \u7c7b\"\u8282). \u7b2c\u4e00\u884c\u7684 base.Update()
\u4f1a\u904d\u5386\u8c03\u7528\u8be5 Entity
\u7684\u6240\u6709 Component
\u7684 Update()
, \u901a\u5e38\u6211\u4eec\u9700\u8981\u5728\u5f00\u5934\u5c31\u8c03\u7528\u5b83. \u540e\u9762\u7684 Render()
\u4e5f\u662f.
Info
\u5728\u73a9\u5bb6\u6b7b\u4ea1\u540e\u7684\"\u70df\u82b1\"\u5e76\u4e0d\u662f Player
\u5b9e\u4f8b, \u6240\u4ee5\u6b64\u65f6\u6211\u4eec\u4f1a\u5f97\u5230\u4e00\u4e2a null
\u7684\u7ed3\u679c, \u5982\u679c\u4f60\u4e0d\u60f3\u8ba9\u4f60\u7684\u6e38\u620f\u5d29\u6e83\u7684\u8bdd\u8bb0\u5f97\u68c0\u67e5\u5b83\u662f\u5426\u4e3a null
.
"},{"location":"begin/simple_entity/#_8","title":"\u544a\u8bc9\u6e38\u620f\u5b83\u957f\u4ec0\u4e48\u6837","text":"\u90a3\u4e48, \u529f\u80fd\u505a\u597d\u540e, \u5f97\u8ba9\u73a9\u5bb6\u770b\u89c1, \u4e3a\u4e86\u7b80\u5355\u8d77\u89c1\u8fd9\u91cc\u6211\u4eec\u4e0d\u6253\u7b97\u4f7f\u7528\u56fe\u7247, \u53ea\u662f\u50cf\u524d\u9762\u63cf\u8ff0\u7684\u4e00\u6837, \u5b83\u662f\u4e2a\"\u900f\u660e\u7684\u7ea2\u8272\u7269\u4f53\", \u5728\u8fd9\u91cc\u6211\u4eec\u9700\u8981\u91cd\u5199 Entity
\u7684 Render()
\u65b9\u6cd5\u6765\u7ed8\u5236\u4e00\u4e2a\u7eaf\u8272\u957f\u65b9\u5f62, \u5b83\u4f1a\u5728\u6e38\u620f\u4e2d\u6bcf\u5e27\u90fd\u4f1a\u88ab\u8c03\u7528, \u5c31\u50cf Update()
\u4e00\u6837, \u4e0d\u8fc7\u5207\u8bb0\u4e0d\u8981\u5728\u8fd9\u4e24\u4e2a\u65b9\u6cd5\u91cc\u5e72\u4e0d\u76f8\u5173\u7684\u4e8b! \u4f60\u5e94\u8be5\u5728 Update()
\u91cc\u53ea\u66f4\u65b0\u4f60\u7684\u903b\u8f91, \u800c\u5728 Render()
\u91cc\u53ea\u505a\u7ed8\u5236. \u8fd9\u91cc\u6211\u4eec\u9009\u62e9\u7ed8\u5236\u4e00\u4e2a\u900f\u660e\u7684\u7ea2\u8272\u957f\u65b9\u5f62, \u6211\u4eec\u9700\u8981\u501f\u52a9\u8fd9\u4e2a\u51fd\u6570:
Monocle.Draw.RectDraw.Rect(Vector2 position, float width, float height, Color color)\n
\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u6211\u4eec\u5e0c\u671b\u7ed8\u5236\u7684\u4f4d\u7f6e(\u4e16\u754c\u5750\u6807) \u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u6211\u4eec\u5e0c\u671b\u7ed8\u5236\u7684\u5bbd\u5ea6 \u7b2c\u4e09\u4e2a\u53c2\u6570\u662f\u6211\u4eec\u5e0c\u671b\u7ed8\u5236\u7684\u9ad8\u5ea6 \u7b2c\u56db\u4e2a\u53c2\u6570\u662f\u6211\u4eec\u5e0c\u671b\u7ed8\u5236\u7684\u989c\u8272 \u6211\u4eec\u5728\u8fd9\u91cc\u4f1a\u8fd9\u6837\u7528\u5b83:
PassByRefill.Render()base.Render();\nColor c = Color.Red;\nc.A = 127;\nDraw.Rect(Position, Width, Height, c);\n
\u9996\u5148\u6211\u4eec\u83b7\u53d6\u4e00\u4e2a\u7ea2\u8272\u7684 Color
, \u7136\u540e\u8bbe\u7f6e\u900f\u660e\u5ea6\u4e3a 127
, \u7136\u540e\u8c03\u7528\u8fd9\u4e2a\u65b9\u6cd5\u7ed8\u5236. \u4f60\u53ef\u80fd\u6ce8\u610f\u5230 Width
\u548c Height
\u8fd9\u4e24\u4e2a\u4e1c\u897f, \u5b83\u662f Entity
\u7684\u4e24\u4e2a\u5c5e\u6027, \u9ed8\u8ba4\u5b83\u4eec\u90fd\u662f 0, \u5728\u4f60\u52a0\u5165\u78b0\u649e\u7bb1\u7684\u77ac\u95f4\u4ed6\u4eec\u4f1a\u53d8\u6210\u78b0\u649e\u7bb1\u7684\u5bbd\u548c\u9ad8, \u5728\u8fd9\u91cc\u5b83\u4eec\u7684\u503c\u5c31\u662f\u6211\u4eec\u4e4b\u524d\u8bbe\u7f6e\u7684 Hitbox
\u7684\u5bbd\u9ad8.
"},{"location":"begin/simple_entity/#_9","title":"\u51c6\u5907\u5c31\u7eea","text":"\u90a3\u4e48, \u4e00\u5207\u5c31\u7eea, \u7f16\u8bd1\u4f60\u7684\u9879\u76ee, \u5230\u90a3\u4e2a\u5730\u65b9, \u5728\u534a\u900f\u660e\u7ea2\u8272\u7684\u533a\u57df\u91cc\u4eab\u53d7\u9501\u5b9a\u51b2\u523a\u6570\u7684\u5feb\u4e50\u5427!
\u5982\u679c\u4f60\u9047\u5230\u4e86\u56f0\u96be, \u4f60\u53ef\u4ee5\u5bf9\u6bd4\u4e00\u4e0b\u6700\u7ec8\u7684\u4ee3\u7801: PassByRefill.cs
using Celeste.Mod.Entities;\n\nnamespace MyCelesteMod;\n\n[CustomEntity(\"MyCelesteMod/PassByRefill\")]\npublic class PassByRefill : Entity\n{\n public int Dashes = 0;\n\n public PassByRefill(Vector2 position, Vector2 size, int dashes)\n {\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(size.X, size.Y);\n Collider = hitbox;\n }\n\n public PassByRefill(EntityData data, Vector2 offset)\n : this(data.Position + offset, new Vector2(data.Width, data.Height), data.Int(\"dashes\"))\n { }\n\n public override void Update()\n {\n base.Update();\n var player = Scene.Tracker.GetEntity<Player>();\n if (player is not null && this.CollideCheck(player))\n {\n player.Dashes = this.Dashes;\n }\n }\n\n public override void Render()\n {\n base.Render();\n Color c = Color.Red;\n c.A = 127;\n Draw.Rect(Position, Width, Height, c);\n }\n}\n
"},{"location":"begin/simple_entity/#_10","title":"\u66f4\u591a","text":""},{"location":"begin/simple_entity/#loenn-dashes","title":"\u5728 Loenn \u4e2d\u7981\u6b62\u8bbe\u7f6e dashes \u4e3a\u5c0f\u6570","text":"\u5728 Loenn \u4e2d\u5982\u679c\u4f60\u6ca1\u6709\u663e\u5f0f\u6307\u5b9a\u67d0\u4e2a\u6570\u5b57 data \u7684\u7c7b\u578b\u7684\u8bdd\u5b83\u9ed8\u8ba4\u4f1a\u662f\u6d6e\u70b9\u6570, \u4e5f\u5c31\u662f\u4f60\u80fd\u8f93\u5165\u5c0f\u6570, \u4e0d\u8fc7\u8fd9\u4e0d\u4f1a\u5f88\u5f71\u54cd(\u8fd8\u662f\u6709\u7684!)\u4ee3\u7801\u90a3\u8fb9, \u6240\u4ee5\u6211\u4eec\u5f97\u8ddf Loenn \u8bf4\u4e00\u4e0b\u5b83\u662f\u4e2a\u6574\u6570! \u90a3\u4e48\u6211\u4eec\u5728\u4ee3\u7801\u7684 return \u4e4b\u524d\u8fd9\u6837\u8bbe\u7f6e\u4e00\u4e0b: PassByRefill.lua
entity.fieldInformation = \n{\n dashes = {\n fieldType = \"integer\"\n }\n}\n
\u5728\u8fd9\u91cc\u6211\u4eec\u8bbe\u7f6e\u4e86\u4e00\u4e2a\u65b0\u7684\u5c5e\u6027 fieldInformation
, \u7136\u540e\u5728\u91cc\u9762\u544a\u8bc9 Loenn \u6211\u4eec\u7684 dashes
\u8fd9\u4e2a\u5c5e\u6027\u7684 fieldType
\u662f integer
, \u4e5f\u5c31\u662f\u6574\u6570. \u90a3\u4e48\u73b0\u5728\u518d\u91cd\u65b0\u7f16\u8bd1, \u91cd\u542f Loenn, \u4f60\u5e94\u8be5\u4f1a\u770b\u5230 Loenn \u53ea\u5141\u8bb8\u4f60\u8f93\u5165\u6574\u6570\u4e86."},{"location":"begin/simple_entity/#loenn_2","title":"\u4e3a Loenn \u4fa7\u914d\u7f6e\u672c\u5730\u5316","text":"\u73b0\u5728\u6211\u4eec\u5728 Loenn \u4fa7\u6211\u4eec\u7684\u5b9e\u4f53\u653e\u7f6e\u9009\u62e9\u7684\u540d\u79f0\u975e\u5e38\u5947\u602a! \u8fd9\u80af\u5b9a\u4e0d\u662f\u4f60\u60f3\u8981\u7684\u7ed3\u679c, \u6240\u4ee5\u8fd9\u91cc\u6211\u4eec\u5c06\u4e3a\u5176\u914d\u7f6e\u672c\u5730\u5316. \u90a3\u4e48, \u5e38\u89c4\u5730, \u6211\u4eec\u9700\u8981\u5728 ModFolder/Loenn
\u8fd9\u4e2a\u6587\u4ef6\u5939\u4e0b\u518d\u65b0\u5efa\u4e00\u4e2a\u53eb lang
\u6587\u4ef6\u5939, \u7136\u540e\u5728\u91cc\u9762\u521b\u5efa\u4e00\u4e2a\u53eb en_gb.lang
\u7684\u7a7a\u6587\u4ef6, \u5b83\u662f Loenn \u9ed8\u8ba4\u8bfb\u53d6\u7684\u672c\u5730\u5316\u6587\u4ef6. \u73b0\u5728\u4f60\u7684\u76ee\u5f55\u7ed3\u6784\u5e94\u8be5\u50cf:
\u5728 en_gb.lang
\u6587\u4ef6\u91cc, \u6211\u4eec\u5199\u4e0b:
entities.MyCelesteMod/PassByRefill.placements.name.normal=PassByRefill\n
\u554a, \u8fd9\u4e00\u4e32\u53ef\u80fd\u6709\u4ebf\u70b9\u957f, \u6211\u4eec\u6162\u6162\u6765\u89e3\u91ca\u4e00\u4e0b: \u9996\u5148\u8fd9\u662f\u4e00\u4e2a\u5b9e\u4f53, \u6240\u4ee5\u4ee5 entities
\u5f00\u5934, \u7136\u540e\u6211\u4eec\u9700\u8981\u952e\u5165\u5b9e\u4f53\u7684\"\u540d\u79f0 ID\", \u7136\u540e\u518d\u4f9d\u6b21\u952e\u5165 placements
\u548c name
, \u8fd9\u8868\u793a\u6211\u4eec\u60f3\u672c\u5730\u5316\u7684\u5185\u5bb9\u662f\u90a3\u4e2a\u5b9e\u4f53\u7684\u653e\u7f6e\u9009\u9879\u7684\u540d\u79f0, \u6700\u540e\u952e\u5165\u653e\u7f6e\u9009\u9879\u7684\u540d\u5b57 \"normal\"(\u5b83\u5e94\u8be5\u4f1a\u5728\u4f60\u7684 lua \u7684\u7b2c\u4e94\u884c\u9644\u8fd1). ok \u73b0\u5728\u6211\u4eec\u5df2\u7ecf\u6307\u5b9a\u4e86\u6211\u4eec\u60f3\u672c\u5730\u5316\u4ec0\u4e48\u4e1c\u897f\u4e86, \u90a3\u4e48\u63a5\u4e0b\u6765\u7b80\u5355\u7684 ={\u5185\u5bb9}
, \u5728\u8fd9\u91cc\u662f PassByRefill
. \u6700\u540e, \u7f16\u8bd1\u590d\u5236, \u91cd\u542f Loenn, \u4f60\u5e94\u8be5\u5c31\u4f1a\u770b\u5230\u6211\u4eec\u7684\u5b9e\u4f53\u7ec8\u4e8e\u6709\u4e2a\u6b63\u5e38\u540d\u5b57\u4e86:
Info
\u5bf9\u4e8e\u5b83\u7684\u8d34\u56fe\u6211\u4eec\u4e4b\u540e\u518d\u8bf4, \u6211\u77e5\u9053\u4f60\u5f88\u6025\u4f46\u662f\u4f60\u5148\u522b\u6025.
"},{"location":"begin/simple_texturing/","title":"\u7b80\u5355\u8d34\u56fe","text":"\u55ef... \u90a3\u4e48\u5230\u8fd9\u4e00\u7ae0\u6211\u4eec\u8be5\u7ed9\u6211\u4eec\u5b9e\u4f53\u4e0a\u70b9\u8d34\u56fe\u4e86, \u4ee5\u53ca\u8fd8\u6709 Loenn \u4fa7\u7684\u8d34\u56fe, \u90a3\u4e48\u7ed3\u675f\u8fd9\u4e00\u7ae0\u540e\u4f60\u5e94\u8be5\u4f1a\u89c9\u5f97\u6211\u4eec\u7684\u5b9e\u4f53\u662f\u4e2a\"\u50cf\u6837\"\u7684\u5b9e\u4f53\u4e86. \u8fd9\u91cc\u6211\u4eec\u4f1a\u4f7f\u7528\u8fd9\u4e2a 64x64 \u7684\u8d85\u7ea7\u4e11\u964b\u7684\u8d34\u56fe:
\u554a\u5b83\u771f\u7684\u592a\u4e11\u964b\u4e86 \u4f60\u53ef\u4ee5\u5728\u8fd9\u91cc\u4e0b\u8f7d\u5b83: fucking_ugly_texture.png
"},{"location":"begin/simple_texturing/#_2","title":"\u7981\u6b62\u6211\u4eec\u7684\u5b9e\u4f53\u7f29\u653e","text":"\u5728\u8fd9\u91cc\u6211\u4eec\u7684\u8d34\u56fe\u662f\u6b63\u65b9\u5f62\u7684, \u6240\u4ee5\u8fd9\u91cc\u4e3a\u4e86\u65b9\u4fbf\u8d77\u89c1\u6682\u65f6\u8ba9\u6211\u4eec\u7684\u5b9e\u4f53\u4e0d\u80fd\u7f29\u653e, \u90a3\u4e48\u5728\u4ee3\u7801\u8fd9\u8fb9\u7684\u8868\u73b0\u5c31\u662f\u76f4\u63a5\u5220\u53bb\u4e0e Size \u6709\u5173\u7684\u4e1c\u897f\u5e76\u5c06\u78b0\u649e\u7bb1\u786c\u7f16\u7801\u6210 64x64 \u5927\u5c0f:
AfterBefore PassByRefill.cspublic PassByRefill(Vector2 position, int dashes)\n{\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(64, 64);\n Collider = hitbox;\n}\n\npublic PassByRefill(EntityData data, Vector2 offset)\n : this(data.Position + offset, data.Int(\"dashes\"))\n{ }\n
PassByRefill.cspublic PassByRefill(Vector2 position, Vector2 size, int dashes)\n{\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(size.X, size.Y);\n Collider = hitbox;\n}\n\npublic PassByRefill(EntityData data, Vector2 offset)\n : this(data.Position + offset, new Vector2(data.Width, data.Height), data.Int(\"dashes\"))\n{ }\n
Info
\u5728 Loenn \u90a3\u8fb9\u6211\u4eec\u5f85\u4f1a\u518d\u8bf4, \u5982\u679c\u4f60\u73b0\u5728\u5c31\u5220\u9664 width \u548c height \u5c5e\u6027\u7684\u8bdd\u4f60\u4f1a\u53d1\u73b0\u4f60\u653e\u7f6e\u4e0d\u4e86\u8fd9\u4e2a\u5b9e\u4f53
"},{"location":"begin/simple_texturing/#monocleimage","title":"\u8d34\u56fe\u4ee5\u53ca Monocle.Image","text":""},{"location":"begin/simple_texturing/#_3","title":"\u851a\u84dd\u4fa7","text":"ok \u90a3\u4e48\u73b0\u5728\u6211\u4eec\u8be5\u5728\u4ee3\u7801\u8fd9\u8fb9\u6765\u70b9\u8d34\u56fe\u4e86, \u8fd9\u91cc\u6211\u4eec\u4f1a\u7528\u5230\u4e4b\u524d\u63d0\u5230\u7684 Component
\u7684\u6982\u5ff5\u53ca\u5bf9\u5e94\u7684\u4e00\u4e2a\u65b0\u7684\u7c7b Monocle.Image
, \u5b83\u7684\u4f5c\u7528\u5c31\u662f\u7ed8\u5236\u8d34\u56fe. \u9996\u5148\u6211\u4eec\u5f97\u8ba9\u6e38\u620f\u627e\u5230\u5e76\u52a0\u8f7d\u5230\u6211\u4eec\u7684\u8d34\u56fe, \u8fd9\u4e00\u6b65\u5f88\u7b80\u5355\u5e76\u7c7b\u4f3c, \u53ea\u9700\u8981\u5957\u51e0\u5c42\u6587\u4ef6\u5939:
pass_by_refill.png
\u5373\u6211\u4eec\u7684\u8d34\u56fe, \u5982\u679c\u4f60\u540c\u65f6\u4e5f\u662f\u4e00\u4f4d mapper \u7684\u8bdd\u4f60\u4e00\u5b9a\u5f88\u719f\u6089\u8fd9\u4e2a\u6587\u4ef6\u5939\u5957\u5957\u4e50! \u5728\u4ee3\u7801\u8fd9\u8fb9, \u6211\u4eec\u4f7f\u7528 GFX.Game[\"MyCelesteMod/pass_by_refill\"]
\u6765\u83b7\u53d6\u8fd9\u4e2a\u8d34\u56fe, \u5b83\u662f\u4e00\u4e2a MTexture
\u7c7b\u578b\u7684\u5b9e\u4f8b, \u5728\u83b7\u53d6\u5230\u8fd9\u4e2a\u8d34\u56fe\u540e, \u6211\u4eec new
\u4e00\u4e2a Monocle.Image
, \u7136\u540e\u5728\u6784\u9020\u51fd\u6570\u4e2d\u4f20\u5165\u5b83, \u7136\u540e\u4f7f\u7528 this.Add
\u51fd\u6570\u6302\u8f7d\u5230\u6211\u4eec\u7684\u8fd9\u4e2a\u5b9e\u4f53\u4e0a, \u603b\u7684\u4ee3\u7801\u5e94\u8be5\u662f\u8fd9\u6837\u7684: PassByRefill.cs
public PassByRefill(Vector2 position, int dashes)\n{\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(64, 64);\n Collider = hitbox;\n\n MTexture tex = GFX.Game[\"MyCelesteMod/pass_by_refill\"];\n Image image = new(tex);\n this.Add(image);\n}\n
Info
GFX
\u662f\u851a\u84dd\u4e2d\u7684\u4e00\u4e2a\u7ba1\u7406\u8d34\u56fe\u7684\u7c7b, \u6211\u4eec\u7528\u5b83\u83b7\u53d6\u5230\u4e00\u4e2a\u8d34\u56fe\u7ec4 Game
, \u7136\u540e\u5411\u5b83\u68c0\u7d22\u4e00\u4e2a\u540d\u4e3a MyCelesteMod/pass_by_refill
\u7684\u8d34\u56fe, \u4f60\u53ef\u80fd\u4f1a\u7591\u60d1\u4e3a\u4ec0\u4e48\u8fd9\u91cc\u7684\u8def\u5f84\u53ea\u9700\u8981\u540e\u534a\u90e8\u5206, \u8fd9\u662f\u56e0\u4e3a GFX.Game
\u53ea\u4f1a\u68c0\u7d22 Atlases/Graphics/Gameplay
\u4e2d\u7684\u5185\u5bb9. \u540c\u6837\u7684, GFX.Portraits
\u53ea\u4f1a\u68c0\u7d22 Atlases/Graphics/Portraits
\u4e2d\u7684\u5185\u5bb9.
\u987a\u4fbf\u8bb0\u5f97\u5220\u6389\u6211\u4eec\u91cd\u5199\u7684 Render
\u51fd\u6570, \u6211\u4eec\u4e0d\u518d\u9700\u8981\u5b83\u4e86. \u603b\u7684\u7c7b\u5e94\u8be5\u662f\u8fd9\u6837\u7684: PassByRefill.cs
[CustomEntity(\"MyCelesteMod/PassByRefill\")]\n[Tracked]\npublic class PassByRefill : Entity\n{\n public int Dashes = 0;\n\n public PassByRefill(Vector2 position, int dashes)\n {\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(64, 64);\n Collider = hitbox;\n\n MTexture tex = GFX.Game[\"MyCelesteMod/pass_by_refill\"];\n Image image = new(tex);\n this.Add(image);\n }\n\n public PassByRefill(EntityData data, Vector2 offset)\n : this(data.Position + offset, data.Int(\"dashes\"))\n { }\n\n public override void Update()\n {\n base.Update();\n var player = Scene.Tracker.GetEntity<Player>();\n if (player is not null && this.CollideCheck(player))\n {\n player.Dashes = this.Dashes;\n }\n }\n}\n
"},{"location":"begin/simple_texturing/#loenn","title":"Loenn \u4fa7","text":"\u5728 Loenn \u4fa7\u8fd9\u8fb9\u4e5f\u975e\u5e38\u7b80\u5355, \u9996\u5148\u6211\u4eec\u5148\u5927\u80c6\u7684\u5220\u6389 width \u548c height \u5c5e\u6027:
AfterBefore PassByRefill.lualocal entity = {}\n\nentity.name = \"MyCelesteMod/PassByRefill\"\nentity.placements = {\n name = \"normal\",\n data = {\n dashes = 2\n }\n}\n\nentity.fieldInformation = \n{\n dashes = {\n fieldType = \"integer\"\n }\n}\n\nreturn entity\n
PassByRefill.lualocal entity = {}\n\nentity.name = \"MyCelesteMod/PassByRefill\"\nentity.placements = {\n name = \"normal\",\n data = {\n width = 16,\n height = 16,\n dashes = 2\n }\n}\n\nentity.fieldInformation = \n{\n dashes = {\n fieldType = \"integer\"\n }\n}\n\nreturn entity\n
\u7136\u540e\u8bbe\u7f6e entity \u7684 texture
\u5c5e\u6027, \u8fd9\u4f1a\u8ba9 Loenn \u4e3a\u5176\u8bbe\u7f6e\u8d34\u56fe:
entity.texture = \"MyCelesteMod/pass_by_refill\"\n
\u987a\u4fbf\u8bbe\u7f6e\u8d34\u56fe\u539f\u70b9\u4e3a\u5de6\u4e0a\u89d2, \u5426\u5219 Loenn \u4e2d\u7684\u663e\u793a\u53ef\u80fd\u4f1a\u4e0e\u5b9e\u9645\u6e38\u620f\u4e2d\u7684\u4e0d\u540c: entity.justification = { 0.0, 0.0 }\n
\u8fd9\u91cc\u7684\u8def\u5f84\u4e0e\u6211\u4eec\u4e4b\u524d\u5728\u4ee3\u7801\u4e2d\u7684\u7c7b\u4f3c. \u90a3\u4e48\u73b0\u5728\u603b\u4f53\u4e0a\u770b\u4e0a\u53bb\u5e94\u8be5\u662f\u8fd9\u6837\u7684: local entity = {}\n\nentity.name = \"MyCelesteMod/PassByRefill\"\nentity.placements = {\n name = \"normal\",\n data = {\n dashes = 2\n }\n}\n\nentity.fieldInformation = \n{\n dashes = {\n fieldType = \"integer\"\n }\n}\n\nentity.texture = \"MyCelesteMod/pass_by_refill\"\nentity.justification = { 0.0, 0.0 }\n\nreturn entity\n
"},{"location":"begin/simple_texturing/#_4","title":"\u6700\u540e","text":"\u6700\u540e\u7f16\u8bd1\u6211\u4eec\u7684\u9879\u76ee, \u6253\u5f00\u6216\u8005\u91cd\u542f Loenn, \u4f60\u5c31\u4f1a\u770b\u5230\u6211\u4eec\u7684\u5b9e\u4f53\u6709\u7740\u4e00\u4e2a\u4e0d\u600e\u4e48\u597d\u770b\u7684\u8d34\u56fe\u4e86! \u73b0\u5728\u8fdb\u5165\u5230\u6e38\u620f\u4e2d\u4f60\u4e5f\u4f1a\u770b\u5230\u8fd9\u4e2a\u4e0d\u600e\u4e48\u597d\u770b\u7684\u8d34\u56fe\u4e86!
"},{"location":"begin/simple_trigger/","title":"\u7b80\u5355\u81ea\u5b9a\u4e49 Trigger","text":"\u5982\u679c\u4f60\u662f\u4e00\u4f4d Mapper \u7684\u8bdd\u90a3\u4f60\u4e00\u5b9a\u77e5\u9053 Trigger \u662f\u591a\u4e48\u91cd\u8981\u7684\u5b58\u5728. \u5728\u8fd9\u91cc\u53ef\u80fd\u4e0d\u662f\u5f88\u80fd\u5728\u77ed\u7bc7\u5e45\u5185\u8bf4\u660e Trigger \u7684\u91cd\u8981\u6027, \u8fd9\u91cc\u53ea\u7b80\u5355\u4e3e\u51e0\u4e2a\u4f8b\u5b50:
\u7edd\u5927\u90e8\u5206\u955c\u5934\u7684\u79fb\u52a8\u4e0e\u504f\u79fb \u5267\u60c5\u7684\u89e6\u53d1, \u65e0\u5355\u53cc\u51b2\u7684\u5207\u6362 \u98ce\u7684\u6539\u53d8 \u91cd\u751f\u70b9\u7684\u8bbe\u7f6e \u97f3\u4e50\u53c2\u6570\u7684\u8bbe\u7f6e \u80cc\u666f\u7684\u6e10\u53d8, \u524d\u666f\u7684\u5404\u79cd\u53d8\u6362 \u4ee5\u4e0a\u51e0\u4e2a\u4f8b\u5b50\u4e0d\u8bf4\u7edd\u5927\u90e8\u5206, \u4e5f\u6709\u5f88\u5927\u7684\u5360\u6bd4\u90fd\u662f\u7531 Trigger \u5b8c\u6210\u7684. Trigger \u662f Entity \u7684\u5b50\u7c7b, \u5b83\u5e26\u6709\u4e00\u4e2a\u957f\u65b9\u5f62\u7684\u78b0\u649e\u7bb1, \u901a\u5e38\u5b83\u662f\u5bf9\u73a9\u5bb6\u4e0d\u53ef\u89c1\u7684, \u5f53\u73a9\u5bb6 \u8fdb\u5165(OnEnter)
, \u4fdd\u6301(OnStay)
, \u79bb\u5f00(OnLeave)
\u4f1a\u5206\u522b\u6267\u884c\u4e0d\u540c\u7684\u52a8\u4f5c, \u6bd4\u5982\u8bf4\u5f53\u73a9\u5bb6 \u8fdb\u5165
\u6539\u53d8\u98ce\u7684 Trigger \u65f6\u4f1a\u6539\u53d8\u573a\u4e0a\u7684\u98ce\u7684\u60c5\u51b5, \u5f53\u73a9\u5bb6 \u4fdd\u6301
\u5728\u955c\u5934\u504f\u79fb\u6539\u53d8 Trigger \u91cc\u65f6\u4f1a\u4fdd\u6301\u955c\u5934\u76f8\u5bf9\u4e8e\u73a9\u5bb6\u7684\u504f\u79fb\u4e8e\u4e00\u4e2a\u503c.
Info
\u5728\u5b98\u56fe\u7b2c\u4e5d\u7ae0\u5047\u5fc3\u9644\u8fd1\u7684 Trigger \u770b\u4e0a\u53bb\u5c31\u50cf: \u5728\u8fd9\u91cc, \u5de6\u8fb9\u6709\u4e2a\u8bbe\u7f6e\u91cd\u751f\u70b9\u7684 Trigger, \u4e2d\u95f4\u6709\u4e2a\u4fdd\u6301\u955c\u5934\u4f4d\u7f6e\u7684 Trigger, \u800c\u5728\u53f3\u8fb9\u6709\u4e2a\u66f4\u6539\u80cc\u666f\u7684 Trigger.
\u90a3\u4e48, \u662f\u65f6\u5019\u5236\u4f5c\u4e00\u4e2a\u5c5e\u4e8e\u6211\u4eec\u81ea\u5df1\u7684 Trigger \u4e86, \u7b80\u5355\u8d77\u89c1\u8fd9\u91cc\u6211\u4eec\u53ea\u505a\u51e0\u4e2a\u6700\u7b80\u5355\u7684\u529f\u80fd:
\u5b83\u53eb SetPassByRefillDashesTrigger
\u73a9\u5bb6\u8fdb\u5165\u540e\u4fee\u6539\u573a\u4e0a\u6240\u6709\u6211\u4eec\u4e4b\u524d\u7684 PassByRefill
\u5b9e\u4f53\u7684\u51b2\u523a\u6570 \u6ca1\u4e86, \u662f\u7684, \u5c31\u662f\u8fd9\u4e48\u7b80\u5355! "},{"location":"begin/simple_trigger/#entity","title":"\u50cf\u5bf9 Entity \u4e00\u6837\u5730\u505a\u51c6\u5907\u5de5\u4f5c","text":"\u9996\u5148\u5728\u4ee3\u7801\u4e2d\u51c6\u5907\u6211\u4eec\u7684\u7c7b, \u4e0d\u8fc7\u8fd9\u6b21\u6211\u4eec\u7ee7\u627f\u7684\u662f Trigger
. \u54e6\u5bf9\u4e86, \u5b83\u8fd8\u4f1a\u8981\u6c42\u58f0\u660e\u4e00\u4e2a\u5e26\u53c2\u7684\u6784\u9020\u51fd\u6570, \u56e0\u4e3a Trigger
\u57fa\u7c7b\u6ca1\u6709\u65e0\u53c2\u6784\u9020\u5668, \u6240\u4ee5\u4f60\u53ef\u80fd\u9700\u8981\u50cf\u5982\u4e0b\u4e00\u6837\u58f0\u660e\u4e00\u4e0b: SetPassByRefillDashesTrigger.cs
[CustomEntity(\"MyCelesteMod/SetPassByRefillDashesTrigger\")]\npublic class SetPassByRefillDashesTrigger : Trigger\n{\n public SetPassByRefillDashesTrigger(EntityData data, Vector2 offset)\n : base(data, offset)\n {\n\n }\n}\n
\u4f60\u53ef\u80fd\u4f1a\u53d1\u73b0\u5176\u5b9e\u5b83\u8981\u6c42\u7684\u5c31\u662f Everest \u8981\u6c42\u6211\u4eec\u5b9a\u4e49\u7684\u90a3\u4e2a! \u90a3\u521a\u597d\u6211\u4eec\u5c31\u4e0d\u7528\u518d\u989d\u5916\u5b9a\u4e49\u4e00\u4e2a\u4e86. \u7136\u540e\u6211\u4eec\u7a0d\u4f5c\u66f4\u6539, \u4ee5\u8ba9\u5b83\u4e5f\u80fd\u63d0\u53d6\u5230\u4e00\u4e2a\u53eb dashes
\u7684\u6570\u636e: SetPassByRefillDashesTrigger.cspublic int Dashes;\n\npublic SetPassByRefillDashesTrigger(EntityData data, Vector2 offset)\n : base(data, offset)\n{\n Dashes = data.Int(\"dashes\");\n}\n
\u6784\u9020\u51fd\u6570\u94fe
\u5f62\u5982 : base(data, offset)
: this(position)
\u7684\u8fd9\u79cd\u8bed\u6cd5\u53eb\u505a\u6784\u9020\u51fd\u6570\u94fe, \u8fd9\u4e00\u90e8\u5206\u4f3c\u4e4e\u5f88\u591a C# \u6559\u7a0b\u6ca1\u6709\u7279\u522b\u63d0\u53ca, \u5982\u679c\u4f60\u5bf9\u6b64\u4e0d\u662f\u5f88\u4e86\u89e3\u7684\u8bdd\u6211\u63a8\u8350\u4f60\u53bb\u67e5\u9605\u4e86\u89e3\u8be5\u8bed\u6cd5.
\u4f60\u53ef\u80fd\u6ce8\u610f\u5230 Trigger \u4e00\u822c\u90fd\u662f\u6709\u5bbd\u5ea6\u548c\u9ad8\u5ea6\u7684, \u5728\u8fd9\u91cc\u6211\u4eec\u5e76\u6ca1\u6709\u7528 EntityData data
\u53bb\u83b7\u53d6, \u800c\u4e14\u6211\u4eec\u4e5f\u6ca1\u8bbe\u7f6e\u5b83\u7684 Position
! \u5b9e\u9645\u4e0a\u5f53\u4f60 : base(data, offset)
\u65f6\u8fd9\u4e9b\u4e8b\u60c5\u5df2\u7ecf\u7531\u7236\u7c7b Trigger \u7684\u6784\u9020\u51fd\u6570\u505a\u4e86, \u5982\u679c\u4f60\u597d\u5947\u53ef\u4ee5\u7ffb\u9605 Trigger
\u6784\u9020\u51fd\u6570\u9644\u8fd1\u7684\u4ee3\u7801.
Trigger.Trigger(EntityData data, Vector2 offset) /// .......\npublic Trigger(EntityData data, Vector2 offset)\n : base(data.Position + offset)\n{\n base.Collider = new Hitbox(data.Width, data.Height);\n Visible = false;\n}\n/// .......\n
"},{"location":"begin/simple_trigger/#trigger_1","title":"Trigger \u7684\u5b9e\u9645\u529f\u80fd","text":"ok \u73b0\u5728\u8ba9\u6211\u4eec\u60f3\u60f3\u6211\u4eec\u7684 Trigger \u7684\u529f\u80fd\u5982\u4f55\u5b9e\u73b0. \u5b83\u5927\u6982\u5c31\u662f:
\u68c0\u6d4b\u73a9\u5bb6\u662f\u5426\u8fdb\u5165 \u8bbe\u7f6e\u573a\u4e0a\u6240\u6709 PassByRefill
\u7684 Dashes
\u5b57\u6bb5 \u6ca1\u4e86 \u5728\u8fd9\u91cc\u6211\u4eec\u4f1a\u4f7f\u7528 Trigger \u7684 OnEnter
\u865a\u51fd\u6570, \u5b83\u4f1a\u5728\u73a9\u5bb6\u9996\u6b21\u8fdb\u5165\u76841\u5e27\u88ab\u8c03\u75281\u6b21. SetPassByRefillDashesTrigger.cs
public override void OnEnter(Player player)\n{\n base.OnEnter(player);\n}\n
Note
\u851a\u84dd\u5185\u90e8\u5927\u90e8\u5206\u865a\u51fd\u6570\u91cd\u5199\u65f6\u6700\u597d\u5728\u5f00\u5934\u8c03\u7528\u4e00\u904d\u57fa\u7c7b\u7684\u5b9e\u73b0, \u9664\u975e\u4f60\u771f\u7684\u77e5\u9053\u5b83\u505a\u4e86\u4ec0\u4e48\u5e76\u4e14\u4f60\u771f\u7684\u4e0d\u9700\u8981\u5b83.
\u7136\u540e\u662f\u83b7\u53d6\u573a\u4e0a\u6240\u6709\u7684 PassByRefill
, \u4ee5\u4fbf\u6211\u4eec\u80fd\u8bbe\u7f6e\u5b83\u4eec\u7684 Dashes
. \u8fd9\u91cc\u6211\u4eec\u4f1a\u642c\u51fa\u4e00\u4e2a\u4f60\u53ef\u80fd\u773c\u719f\u7684\u4e00\u4e32: SetPassByRefillDashesTrigger.OnEnter(Player player)
// \u83b7\u53d6\u6240\u6709\u7684 PassByRefill\nvar refills = Scene.Tracker.GetEntities<PassByRefill>();\n
\u5728\u8fd9\u91cc\u6216\u8bb8\u8be5\u4ecb\u7ecd\u4ecb\u7ecd\u8fd9\u4e00\u4e32\u662f\u4ec0\u4e48\u4e86, \u9996\u5148\u6211\u4eec\u901a\u8fc7 Scene
\u5c5e\u6027\u83b7\u53d6\u81ea\u8eab\u6240\u5728\u7684\u573a\u666f, \u7136\u540e\u83b7\u53d6\u5b83\u7684 Tracker
. Tracker \u662f\u851a\u84dd\u573a\u666f\u5185\u7684\u4e00\u4e2a\u8f85\u52a9\u7c7b, \u5b83\u53ef\u4ee5\u5f88\u5feb\u7684\u5e2e\u4f60\u7b5b\u9009\u51fa\u573a\u4e0a\u7684\u5b9e\u4f53, \u5728\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528\u5b83\u7684 GetEntities<T>
\u6765\u7b5b\u9009\u51fa\u6240\u6709\u7c7b\u578b\u4e3a T
, \u4e5f\u5c31\u662f PassByRefill
\u7684\u5b9e\u4f53. \u90e8\u5206\u5b9e\u4f53\u5728\u573a\u4e0a\u53ef\u80fd\u6c38\u8fdc\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u65f6, \u6bd4\u5982\u8bf4\u6211\u4eec\u7684 Player
, \u9664\u975e\u4f60\u5b89\u88c5\u4e86\u5947\u5947\u602a\u602a\u7684 mod, \u5426\u5219\u5b83\u6c38\u8fdc\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b, \u8fd9\u79cd\u60c5\u51b5\u4e0b\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 GetEntity
, \u5b83\u53ea\u4f1a\u8fd4\u56de\u4e00\u4e2a\u5b9e\u4f8b. \u90a3\u4e48\u4f60\u73b0\u5728\u5e94\u8be5\u61c2\u5f97\u4e4b\u524d\u6211\u4eec\u5199\u4e0b\u7684 Scene.Tracker.GetEntity<Player>()
\u662f\u4ec0\u4e48\u610f\u601d\u4e86: \"\u4f7f\u7528\u573a\u666f\u7684 Tracker \u83b7\u53d6\u573a\u4e0a\u552f\u4e00\u7684\u90a3\u4e2a Player \u5b9e\u4f8b\".
\u54e6\u5bf9\u4e86, \u6211\u4eec\u8fd8\u5f97\u5728\u6211\u4eec\u60f3\u8981 Tracker \u83b7\u53d6\u7684\u5b9e\u4f53\u7684\u7c7b\u4e0a\u52a0\u4e00\u4e2a Tracked
\u7279\u6027, \u5c31\u50cf: PassByRefill.cs
[CustomEntity(\"MyCelesteMod/PassByRefill\")]\n[Tracked]\npublic class PassByRefill : Entity\n{\n
\u8fd9\u4e00\u6b65\u5176\u5b9e\u5f88\u5bb9\u6613\u88ab\u5fd8\u8bb0, \u5c31\u50cf\u6211\u5199\u5b8c\u521d\u7a3f\u5e76\u505a\u5230\u6700\u540e\u4e00\u6b65\u6e38\u620f\u5d29\u6e83\u65f6\u624d\u60f3\u8d77\u6765(\u4e50). \u597d\u7684\u7136\u540e\u6211\u4eec\u8be5\u8bbe\u7f6e PassByRefill
\u4eec\u7684 Dashes
... \u989d\u7b49\u7b49! \u4f60\u53ef\u80fd\u4f1a\u53d1\u73b0\u8fd9\u91cc\u7684 refills
\u5c40\u90e8\u53d8\u91cf\u5176\u5b9e\u662f\u4e2a List<Entity>
\u7c7b\u578b, \u8fd9\u4e2a\u6211\u4e0d\u592a\u6e05\u695a\u4e3a\u4ec0\u4e48, \u4f30\u8ba1\u662f\u4e00\u4e2a Monocle
\u5728\u5b9e\u73b0\u4e2d\u7684\u4e00\u4e2a\u5c0f\u9519\u8bef, \u4e3a\u4e86\u7ea0\u6b63\u5b83\u8fd9\u91cc\u6211\u4f1a\u4f7f\u7528 Linq
\u7684 Cast
\u6765\u8f6c\u6362\u4e00\u4e0b\u7c7b\u578b:
SetPassByRefillDashesTrigger.OnEnter(Player player)var refills = Scene.Tracker.GetEntities<PassByRefill>().Cast<PassByRefill>();\n
ok, \u73b0\u5728\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u904d\u5386\u5e76\u8bbe\u7f6e\u4e86: SetPassByRefillDashesTrigger.OnEnter(Player player)
foreach(var refill in refills)\n{\n refill.Dashes = this.Dashes;\n}\n
\u6700\u540e, \u4f60\u7684\u4ee3\u7801\u5e94\u8be5\u603b\u4f53\u4e0a\u662f\u8fd9\u4e2a\u6837\u5b50: SetPassByRefillDashesTrigger.cs
using Celeste.Mod.Entities;\n\nnamespace MyCelesteMod;\n\n[CustomEntity(\"MyCelesteMod/SetPassByRefillDashesTrigger\")]\npublic class SetPassByRefillDashesTrigger : Trigger\n{\n public int Dashes;\n\n public SetPassByRefillDashesTrigger(EntityData data, Vector2 offset)\n : base(data, offset)\n {\n Dashes = data.Int(\"dashes\");\n }\n\n public override void OnEnter(Player player)\n {\n base.OnEnter(player);\n var refills = Scene.Tracker.GetEntities<PassByRefill>().Cast<PassByRefill>();\n foreach(var refill in refills)\n {\n refill.Dashes = this.Dashes;\n }\n }\n}\n
"},{"location":"begin/simple_trigger/#loenn","title":"Loenn \u914d\u7f6e","text":"ok \u6211\u4eec\u7684 Trigger \u7684\u4ee3\u7801\u5df2\u7ecf\u5199\u597d\u4e86, \u63a5\u4e0b\u6765\u5199\u4e00\u4e2a Loenn \u914d\u7f6e\u5c31\u597d\u4e86, \u8fd9\u4e00\u6b65\u4e0e Entity \u7684\u5f88\u50cf, \u4e0d\u8fc7\u4f60\u9700\u8981\u628a\u5b83\u653e\u5230 triggers \u6587\u4ef6\u5939\u5185:
ModFolder Loenn entities triggers SetPassByRefillDashesTrigger.lua \u5185\u5bb9\u5927\u540c\u5c0f\u5f02:
SetPassByRefillDashesTrigger.lualocal trigger = {}\n\ntrigger.name = \"MyCelesteMod/SetPassByRefillDashesTrigger\"\ntrigger.placements = {\n name = \"normal\",\n data = {\n width = 16,\n height = 16,\n dashes = 2\n }\n}\n\ntrigger.fieldInformation = \n{\n dashes = {\n fieldType = \"integer\"\n }\n}\n\nreturn trigger\n
\u6700\u540e\u8bb0\u5f97\u5199\u4e2a\u672c\u5730\u5316\u4fe1\u606f, \u4e0d\u7136\u5b83\u7684\u540d\u5b57\u80af\u5b9a\u4f1a\u5f88\u4e11! \u8fd9\u4e00\u6b65\u4e5f\u662f\u5f88\u7c7b\u4f3c\u7684:
entities.MyCelesteMod/PassByRefill.placements.name.normal=PassByRefill\ntriggers.MyCelesteMod/SetPassByRefillDashesTrigger.placements.name.normal=SetPassByRefillDashesTrigger\n
Note
\u522b\u5fd8\u4e86\u7f16\u8bd1, \u4e0d\u8981\u50cf\u6211\u4e00\u6837\u5bf9\u7740 Loenn \u7591\u60d1\u6211\u7684 trigger/\u5b9e\u4f53 \u600e\u4e48\u4e0d\u89c1\u4e86(
"},{"location":"begin/simple_trigger/#_1","title":"\u6548\u679c","text":"\u73b0\u5728\u5728\u4f60\u7684\u5730\u56fe\u4e0a\u6446\u653e\u8fd9\u4e2a trigger \u4ee5\u53ca\u51e0\u4e2a PassByRefill
. \u6211\u5728\u8fd9\u91cc\u4f1a\u6446\u51e0\u4e2a\u80cc\u666f\u7816\u6765\u5e2e\u6211\u4eec\u8fa8\u8bc6\u8fd9\u4e2a trigger \u5728\u54ea, \u56e0\u4e3a trigger \u901a\u5e38\u90fd\u662f\u4e0d\u53ef\u89c1\u7684 (\u4f60\u53ef\u4ee5\u901a\u8fc7 ~
\u952e\u6216\u8005\u4e0b\u8f7d CelesteTAS
\u8fd9\u4e2a mod \u6765\u67e5\u770b\u78b0\u649e\u7bb1). \u90a3\u4e48\u89c1\u8bc1\u4f60\u7684\u6770\u4f5c\u5427!
\u8fdb\u5165 trigger \u524d (PassByRefill \u7684 Dashes \u8bbe\u7f6e\u4e3a 2): \u8fdb\u5165 trigger \u540e (\u88ab\u8bbe\u7f6e\u4e3a 1 \u4e86):
"},{"location":"begin/simple_trigger/#_2","title":"\u6700\u540e","text":"\u6211\u4eec\u76ee\u524d\u5b9e\u73b0\u7684\u90a3\u4e2a Entity \u4e0e\u8fd9\u4e2a Trigger \u7684\u642d\u914d\u5176\u5b9e\u95ee\u9898\u7e41\u591a, \u6bd4\u5982 Entity \u5982\u679c\u5728 Trigger \u89e6\u53d1\u540e\u624d\u88ab\u653e\u7f6e\u5230\u573a\u4e0a, \u90a3\u4e48\u51b2\u523a\u6570\u4f1a\u4fdd\u6301\u5b83\u7684\u9ed8\u8ba4, \u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u6700\u4f73\u7684\u65b9\u6848\u662f\u4f7f\u7528\u851a\u84dd\u4e2d\u7684 Session
, \u6211\u4eec\u4f1a\u5728\u540e\u9762\u63d0\u5230\u5b83.
"},{"location":"extra_cmcc/","title":"\u989d\u5916 - CMCC","text":"\u6b22\u8fce\u6765\u5230\u53c8\u4e00\u4e2a\u989d\u5916\u7ae0\u8282, \u4e0d\u8fc7\u8fd9\u91cc\u4e0d\u662f\u4e00\u4e2a\u65b0\u4e3b\u9898, \u53ea\u662f\u4e00\u4e2a\u7531 ForkKILLET \u5efa\u7acb\u7684\u4ed3\u5e93 CelesteMapperCooperationInChina (CMCC) \u7684\u4e00\u4e2a\u7f51\u9875\u5448\u73b0.
\u6e90 github \u4ed3\u5e93: https://github.com/ForkKILLET/CelesteMapperCooperationInChina
"},{"location":"extra_cmcc/cmcc/ReadMe/","title":"\u851a\u84dd\u5236\u56fe\u4e92\u52a9\uff08\u4e2d\u56fd\uff09 | CMCC","text":""},{"location":"extra_cmcc/cmcc/ReadMe/#_1","title":"\u80cc\u666f","text":"\u4e00\u4f4d\u5236\u56fe\u7fa4\u7fa4\u53cb\uff1a
\u8bdd\u8bf4\u6211\u6709\u4e00\u4e2a\u5c0f\u63d0\u8bae\uff0c\u4e0d\u77e5\u9053\u884c\u4e0d\u884c\uff0c\u5728\u672c\u7fa4\u53ef\u4ee5\u5efa\u7acb\u4e00\u4e2a\u53ef\u7f16\u8f91\u7684 FAQ \u6587\u6863\uff0c\u5927\u5bb6\u53ef\u4ee5\u628a\u505amod\u65f6\u5019\u9047\u5230\u7684\u4e00\u4e9b\u5c0f\u95ee\u9898\u548c\u89e3\u51b3\u65b9\u6848\u653e\u8fdb\u53bb\u2026\u2026
\u4e3a\u4e86\u65b9\u4fbf\u56fd\u5185\u851a\u84dd\uff08Celeste\uff09\u73a9\u5bb6\u5206\u4eab\u5236\u56fe\u7ecf\u9a8c\uff0c\u6211\u4eec\u5f00\u4e86\u4e00\u4e2a\u4ed3\u5e93\u5b58\u653e\u8fd9\u4e9b\u4fe1\u606f\u3002
\u4e24\u4e2a\u6ce8\u610f\u70b9\uff1a
\u4f18\u5148\u4f7f\u7528\u4e2d\u6587 \u4fdd\u8bc1\u56fd\u5185\u53ef\u8bbf\u95ee\u6027 "},{"location":"extra_cmcc/cmcc/ReadMe/#_2","title":"\u8bbf\u95ee","text":" GitHub Gitee \u955c\u50cf "},{"location":"extra_cmcc/cmcc/ReadMe/#_3","title":"\u5185\u5bb9\u7d22\u5f15","text":" FAQ\uff08\u65bd\u5de5\u4e2d\uff09 "},{"location":"extra_cmcc/cmcc/todo/","title":"FAQ","text":""},{"location":"extra_cmcc/cmcc/todo/#q1-loenn","title":"Q1 \u600e\u4e48\u62d6\u52a8 Loenn \u7684\u89c6\u89d2","text":"\u9f20\u6807\u957f\u6309\u53f3\u952e
\u9664\u6b64\u4e4b\u5916, \u5e38\u89c1\u7684 L\u00f6nn \u6309\u952e/\u5feb\u6377\u952e\u6709:
\u901a\u7528\u6309\u952e Ctrl + N: \u65b0\u5730\u56fe Ctrl + O: \u6253\u5f00\u5730\u56fe \u5c06 .bin \u62d6\u5230\u7a97\u53e3\u4e0a: \u6253\u5f00\u5730\u56fe Ctrl + S: \u4fdd\u5b58\u5730\u56fe Ctrl + Shift + S: \u53e6\u5b58\u4e3a Ctrl + T: \u65b0\u623f\u95f4(\u9762) Ctrl + Shift + T: \u6253\u5f00\u5f53\u524d\u623f\u95f4\u5c5e\u6027\u9762\u677f Alt + \u65b9\u5411\u952e: \u79fb\u52a8\u623f\u95f4(\u6b65\u957f 8px) Alt + Delete: \u5220\u9664\u623f\u95f4 Ctrl + Z: \u64a4\u56de Ctrl + Shift + Z: \u91cd\u505a \u9f20\u6807\u6eda\u8f6e: \u7f29\u653e Ctrl + \u2795 (\u52a0\u53f7): \u653e\u5927 Ctrl + \u2796 (\u51cf\u53f7): \u7f29\u5c0f \u53cc\u51fb\u9f20\u6807\u4e2d\u952e: \u7f29\u653e\u81f3\u53ef\u4ee5\u770b\u89c1\u6574\u4e2a\u5730\u56fe F11: \u5207\u6362\u5168\u5c4f \u65b9\u5411\u952e: \u5217\u8868\u4e2d\u5bfc\u822a \u7269\u4f53\u653e\u7f6e \u5de6\u952e: \u653e\u7f6e\u7269\u4f53 (8px \u5bf9\u9f50) \u6309\u4f4f Ctrl \u65f6\u5de6\u952e: \u653e\u7f6e\u7269\u4f53 (1px \u5bf9\u9f50) \u53f3\u952e: \u6253\u5f00\u5149\u6807\u6240\u6307\u7269\u4f53\u7684\u5c5e\u6027\u9762\u677f \u5de6\u952e\u5e76\u62d6\u52a8: \u5728\u653e\u7f6e\u53ef\u8c03\u6574\u5927\u5c0f\u7684\u7269\u4f53\u65f6\u8c03\u6574\u7269\u4f53\u7684\u5927\u5c0f \u4e2d\u952e: \u590d\u5236\u5149\u6807\u6240\u6307\u7269\u4f53 Q, E: \u51cf\u5c0f\u5bbd\u5ea6 / \u589e\u5927\u5bbd\u5ea6 A, D: \u51cf\u5c0f\u9ad8\u5ea6 / \u589e\u5927\u9ad8\u5ea6 L, R: \u9006\u65f6\u9488/\u987a\u65f6\u9488 \u65cb\u8f6c\u7269\u4f53 V, H: \u7eb5\u5411/\u6a2a\u5411 \u7ffb\u8f6c\u7269\u4f53 \u7269\u4f53\u9009\u62e9 \u5de6\u952e: \u9009\u62e9\u7269\u4f53 \u5df2\u9009\u62e9\u67d0\u7269\u4f53\u65f6\u5de6\u952e: \u5faa\u73af\u9009\u62e9\u5149\u6807\u5e95\u4e0b\u7684\u7269\u4f53 (\u4ece\u5c0f\u5230\u5927) \u5de6\u952e\u62d6\u52a8: \u9009\u62e9\u591a\u4e2a\u7269\u4f53 Shift + \u5de6\u952e\u5e76\u62d6\u52a8: \u52a0\u5165\u7269\u4f53\u5230\u5f53\u524d\u5df2\u9009\u62e9\u7269\u4f53\u5217\u8868\u4e2d Ctrl + A: \u5168\u9009\u7269\u4f53 \u5df2\u9009\u62e9\u67d0\u7269\u4f53\u65f6\u53f3\u952e: \u6253\u5f00\u7269\u4f53\u7684\u5c5e\u6027\u9762\u677f \u5df2\u9009\u62e9\u67d0\u7269\u4f53\u65f6\u5de6\u952e\u5e76\u62d6\u52a8: \u62d6\u52a8\u6240\u9009\u7269\u4f53 Shift + \u5df2\u9009\u62e9\u67d0\u7269\u4f53\u65f6\u5de6\u952e\u5e76\u62d6\u52a8: \u8f74\u5411\u62d6\u52a8\u7269\u4f53, \u5373\u4ec5\u5141\u8bb8\u7269\u4f53\u4e0a\u4e0b\u6216\u5de6\u53f3\u79fb\u52a8 \u5df2\u9009\u62e9\u67d0\u7269\u4f53\u65f6\u65b9\u5411\u952e: \u79fb\u52a8\u6240\u9009\u7269\u4f53 Q, E: \u51cf\u5c0f\u5bbd\u5ea6 / \u589e\u5927\u5bbd\u5ea6 A, D: \u51cf\u5c0f\u9ad8\u5ea6 / \u589e\u5927\u9ad8\u5ea6 Ctrl + \u4e0a\u9762\u7684\u6309\u952e: \u4f7f\u7528 1px \u5bf9\u9f50\u800c\u4e0d\u662f 8px L, R: \u9006\u65f6\u9488/\u987a\u65f6\u9488 \u65cb\u8f6c\u7269\u4f53 V, H: \u7eb5\u5411/\u6a2a\u5411 \u7ffb\u8f6c\u7269\u4f53 Shift + V / Shift + H: \u7ad6\u76f4/\u7eb5\u5411 \u7ffb\u8f6c\u9009\u5b9a\u533a\u57df \u5bf9 \u5b9e\u4f53/Trigger \u6309 N: \u5411 \u5b9e\u4f53/Trigger \u52a0\u5165\u7b2c\u4e00\u4e2a\u8282\u70b9 \u5bf9\u8282\u70b9\u6309 N: \u5728\u5df2\u9009\u62e9\u7684\u8282\u70b9\u540e\u52a0\u5165\u4e00\u4e2a\u8282\u70b9 Delete: \u5220\u9664\u6240\u9009\u7269\u4f53 Ctrl + C: \u590d\u5236\u7269\u4f53\u5230\u526a\u5207\u677f Ctrl + X: \u526a\u5207\u7269\u4f53\u5230\u526a\u5207\u677f Ctrl + V: \u4ece\u526a\u5207\u677f\u7c98\u8d34\u7269\u4f53 Brushes \u5de6\u952e: \u653e\u7f6e tile \u5de6\u952e\u5e76\u62d6\u52a8: \u5237 tile \u4e2d\u952e: \u8bbe\u7f6e\u5f53\u524d tile \u7c7b\u578b\u4e3a\u5149\u6807\u4e0b\u7684 tile \u7c7b\u578b Stylegrounds \u65b9\u5411\u952e: \u5728\u5217\u8868\u4e2d\u5bfc\u822a Alt + \u65b9\u5411\u952e: \u66f4\u6539\u987a\u5e8f Debug \u6309\u952e F5: \u91cd\u8f7d\u6240\u6709\u5b9e\u4f53\u548c trigger F6: \u6e05\u9664\u7ed8\u56fe\u7f13\u5b58\u5e76\u91cd\u7ed8\u5730\u56fe F7: \u91cd\u8f7d\u5de5\u5177 Ctrl + F5: \u91cd\u8f7d\u6574\u4e2a L\u00f6nn Ctrl + Shift + F5: \u91cd\u542f L\u00f6nn "},{"location":"extra_cmcc/cmcc/todo/#q2-loenn","title":"Q2 Loenn \u600e\u4e48\u79fb\u52a8\u623f\u95f4","text":"Alt + \u65b9\u5411\u952e \u5176\u4ed6\u6309\u952e/\u5feb\u6377\u952e\u89c1 Q1 \u4e2d\u7684\u5217\u8868
"},{"location":"extra_cmcc/cmcc/todo/#q3-loenn","title":"Q3 Loenn \u600e\u4e48\u653e\u5b9e\u4f53","text":"\u5728\u53f3\u8fb9\u7684\u83dc\u5355\u7684\u5de6\u8fb9\u4e00\u5217\u4e2d\u9009\u62e9 Placements, \u518d\u5728\u4e0b\u9762\u9009\u62e9 Entities, \u5728\u53f3\u8fb9\u9009\u62e9\u4e00\u6761\u7136\u540e\u5728\u623f\u95f4\u91cc\u5de6\u952e\u5c31\u80fd\u653e\u7f6e\u4e86. \u6b64\u5916\u5728\u53f3\u8fb9\u90a3\u4e00\u5217\u7684\u5e95\u4e0b\u6709\u4e2a\u767d\u8272\u7684\u641c\u7d22\u6846, \u53ef\u4ee5\u641c\u7d20\u7269\u4f53. \u5bf9\u4e8e\u641c\u7d22\u7279\u5b9a helper \u7684\u7269\u4f53, \u53ef\u4ee5\u5728\u524d\u9762\u52a0\u4e0a @helper\u540d
, \u4f8b\u5982\u641c\u7d22\u91cd\u529b helper \u4e2d\u7684\u5f39\u7403\u53ef\u4ee5\u952e\u5165 @gravityhelper bumper
, \u53ef\u4ee5\u53ea\u6253\u8bcd\u5934: @gra bu
.
"},{"location":"extra_cmcc/cmcc/todo/#q4-tile","title":"Q4 \u5982\u4f55\u81ea\u5b9a\u4e49 tile","text":"\u53ef\u4ee5\u53c2\u8003:
Bilibili - \u7535\u7bb1 - \u5236\u56fe\u6559\u7a0b\u7b2c\u4e94\u7ae0 \u81ea\u5b9a\u4e49 Tiles Bilibili - UnderDragon - tiles \u5e94\u7528\u6559\u7a0b "},{"location":"extra_luacs/begin/","title":"\u989d\u5916 - LuaCutscene","text":""},{"location":"extra_luacs/begin/#_1","title":"\u524d\u8a00","text":"\u6b22\u8fce\u6765\u5230\u8fd9\u4e2a\u989d\u5916\u7ae0\u8282, \u867d\u7136\u5b83\u88ab\u6211\u6254\u5230\u4e86 code mod \u6559\u7a0b\u4e4b\u4e2d, \u4f46\u662f\u5b83\u5b9e\u9645\u4e0a\u4e0d\u9700\u8981\u592a\u591a\u7684 C# \u80fd\u529b. \u5728\u8fd9\u91cc\u4f1a\u4e3b\u8981\u5305\u542b\u4e00\u4e9b LuaCutscene \u672c\u8eab\u4ee5\u53ca\u4f7f\u7528\u5176\u8c03\u7528 C# \u4ee3\u7801\u5b9e\u73b0\u7684\u6709\u8da3\u7684\u6548\u679c, \u5982\u679c\u4f60\u60f3\u8981\u4f60\u7684\u5267\u60c5\u62e5\u6709\u66f4\u591a\u7684\u70ab\u9177\u6548\u679c, \u800c\u4e0d\u662f\u5c40\u9650\u4e8e\u53ea\u6709\u5bf9\u8bdd\u6846\u548c Madeline \u65e0\u804a\u7684\u8d70\u52a8, \u6bd4\u5982\u70ab\u9177\u7684\u955c\u5934\u7f13\u52a8, \u5468\u8fb9\u5b9e\u4f53\u7684\u82b1\u6837\u8868\u6f14, \u751a\u81f3\u662f\u62e5\u6709\u6539\u53d8 gp \u80fd\u529b\u7684\u5267\u60c5! \u90a3\u4e48\u6216\u8bb8\u8fd9\u91cc\u521a\u597d\u5c31\u9002\u5408\u4f60. \u90a3\u4e48\u73b0\u5728\u5c31\u5f00\u59cb\u5427.
"},{"location":"extra_luacs/begin/#_2","title":"\u914d\u7f6e\u73af\u5883","text":"\u8fd9\u4e00\u6b65\u4e8b\u5b9e\u4e0a\u662f\u53ef\u9009\u7684, \u4e0d\u8fc7\u4e3a\u4e86\u66f4\u6109\u5feb\u7684 lua \u4ee3\u7801\u7684\u4e66\u5199, \u6211\u4e2a\u4eba\u8fd8\u662f\u89c9\u5f97\u633a\u6709\u5fc5\u8981\u7684. \u5728\u8fd9\u91cc\u6211\u4f1a\u63a8\u8350\u4f7f\u7528 VSCode \u914d\u4e0a Lua (sumneko.lua) \u63d2\u4ef6.
Note
\u6211\u4e2a\u4eba\u4e0d\u592a\u4f1a\u914d\u7f6e\u8fd9\u79cd lua \u73af\u5883, \u6240\u4ee5\u5982\u679c\u4f60\u9047\u5230\u4e86\u5927\u91cf\u7684\u672a\u5b9a\u4e49\u8b66\u544a\u4f60\u53ef\u4ee5\u9009\u62e9\u5728\u8bbe\u7f6e\u4e2d\u641c\u7d22 Lua.diagnostics.enable
\u5e76\u5c06\u5176\u5173\u95ed.
"},{"location":"extra_luacs/begin/#hello-world","title":"Hello World","text":"\u90a3\u4e48, \u8001\u4f20\u7edf. \u73b0\u5728, \u5728\u4f60\u7684\u5730\u56fe\u4e2d\u653e\u7f6e\u4e00\u4e2a LuaCutscene
\u7684 LuaCutscene/LuaCutsceneTrigger
, \u7136\u540e\u8bbe\u7f6e\u5176 Filename
\u53c2\u6570\u4e3a\u4e00\u4e2a lua \u6587\u4ef6\u7684\u8def\u5f84\u6bd4\u5982 Luas/testlua
(\u6ce8\u610f\u6ca1\u6709\u540e\u7f00.lua), \u7136\u540e Save Changes. \u7136\u540e\u6211\u4eec\u6839\u636e\u521a\u624d\u8bbe\u7f6e\u7684\u8def\u5f84\u6b63\u786e\u653e\u7f6e\u6211\u4eec\u7684 lua \u6587\u4ef6:
<\u4f60\u7684 mod \u540d\u5b57> \u7136\u540e\u5199\u4e0a\u6211\u4eec\u7684 Hello World:
function onBegin()\n print(\"[Cutscene] Hello from the Cutscene!\")\nend\n
\u4fdd\u5b58\u540e\u6309\u4e0b F3 \u952e\u91cd\u8f7d\u4f60\u7684\u5730\u56fe, \u7136\u540e\u8d70\u8fdb\u4f60\u6446\u653e\u7684 trigger \u5185, \u4e4b\u540e, \u68c0\u67e5\u4f60\u7684\u63a7\u5236\u53f0, \u6216\u8005\u68c0\u67e5\u4f60\u6700\u65b0\u7684 log.txt, \u4f60\u5e94\u8be5\u4f1a\u5728\u832b\u832b\u65e5\u5fd7\u6d77\u4e2d\u770b\u5230\u8fd9\u4e00\u884c\u8f93\u51fa:
(12/03/2023 10:36:35) [Everest] [Info] [LevelLoader] Loading Saplonily/FunnyButFuckingMaps/MaybeAFunnyMap\n(12/03/2023 10:36:35) [Everest] [Warn] [Content] CONFLICT in C:\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\Mods\\MaxHelpingHand v1.28.3.zip\\Graphics\\Sprites.xml: Overriding element player_playback.\n[Cutscene] Hello from the Cutscene!\n(12/03/2023 10:36:45) [Everest] [Info] [LevelLoader] Loading Saplonily/FunnyButFuckingMaps/MaybeAFunnyMapOverriding element player_playback.\n
\u9ad8\u4eae\u884c\u4fbf\u662f\u6211\u4eec\u7684 lua \u4ee3\u7801\u6253\u5370\u51fa\u6765\u7684.
Info
\u5728\u4e4b\u540e\u7684\u8fc7\u7a0b\u4e2d\u867d\u7136\u4f60\u53ef\u4ee5\u53cd\u590d\u7ffb\u770b log.txt \u6765\u77e5\u6653\u4f60\u7684 lua \u4ee3\u7801\u7684\u8fd0\u884c\u60c5\u51b5, \u4e0d\u8fc7\u8fd9\u663e\u7136\u4e0d\u5982\u4f60\u6709\u4e00\u4e2a\u63a7\u5236\u53f0\u7a97\u53e3\u76f4\u63a5\u80fd\u770b\u5230\u8f93\u51fa. \u5bf9\u4e8e\u5728 windows \u4e0a, \u4f60\u53ef\u4ee5\u5411\u851a\u84dd\u6839\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6 everest-launch.txt
\u65b0\u52a0\u5165\u4e00\u884c --console
\u6765\u5728\u851a\u84dd\u6bcf\u6b21\u542f\u52a8\u65f6\u9644\u5e26\u4e00\u4e2a\u63a7\u5236\u53f0\u7a97\u53e3.
"},{"location":"extra_luacs/begin/#hello-world_1","title":"\u5bf9\u8bdd Hello World","text":"\u5f53\u7136, \u5728\u63a7\u5236\u53f0\u91cc\u770b\u65e0\u804a\u7684\u65e5\u5fd7\u6253\u5370\u662f\u6ca1\u610f\u601d\u7684, \u6240\u4ee5\u73b0\u5728\u6211\u4eec\u5411\u5b83\u52a0\u5165\u51e0\u6761\u5bf9\u8bdd. \u9996\u5148\u4e3a\u4f60\u8fd9\u4e00\u6bb5\u5bf9\u8bdd\u8d77\u4e00\u6bb5\u540d\u5b57, \u6bd4\u5982 TESTDIALOG_HELLO
, \u901a\u5e38\u6211\u4eec\u5efa\u8bae\u524d\u7f00\u662f\u4f60\u7684\u5730\u56fe\u540d\u4ee5\u9632\u547d\u540d\u51b2\u7a81, \u540e\u7f00\u4f60\u53ef\u4ee5\u6839\u636e\u4f60\u7684\u7231\u597d\u6765\u53d6, \u6bd4\u5982\u52a0\u4e0a\u5267\u60c5\u6240\u5728\u9762\u540d, \u6216\u8005\u5e72\u8106\u662f\u5267\u60c5\u7684\u81ea\u589e\u5e8f\u53f7. \u7136\u540e\u65b0\u5efa\u4e00\u4e2a Simplified Chinese.txt
, \u4e5f\u5c31\u662f\u5bf9\u8bdd\u6587\u4ef6:
<\u4f60\u7684 mod \u540d\u5b57> \u4ee5\u53ca\u5b83\u7684\u5185\u5bb9:
TESTDIALOG_HELLO=\n [MADELINE left normal]\n \u6211\u662f {+MADELINE}.\n
\u7136\u540e\u66f4\u6539 lua \u4ee3\u7801:
function onBegin()\n say(\"TESTDIALOG_HELLO\")\nend\n
\u73b0\u5728\u91cd\u8f7d\u8d44\u6e90, \u8fdb\u5165 trigger, \u4f60\u5c31\u80fd\u770b\u5230 Madeline \u5fae\u7b11\u200b\u7740\u8bf4 \"\u6211\u662f <\u4f60\u7684\u5b58\u6863\u540d>.\" \u4e86. \u5728\u8fd9\u91cc\u5bf9\u8bdd\u72b6\u6001\u65f6\u73a9\u5bb6\u4f9d\u7136\u80fd\u52a8, \u53ef\u4ee5\u901a\u8fc7\u5c06 lua \u4ee3\u7801\u6539\u6210\u8fd9\u6837\u6765\u5728\u5bf9\u8bdd\u8fdb\u884c\u65f6\u7981\u6b62\u79fb\u52a8:
function onBegin()\n disableMovement()\n say(\"TESTDIALOG_HELLO\")\n enableMovement()\nend\n
\u5bf9\u8bdd dialog \u6587\u4ef6\u7684\u76f8\u5173\u5185\u5bb9\u8fd9\u91cc\u5c31\u4e0d\u7ec6\u5199\u4e86, \u63a8\u8350\u53c2\u8003\u851a\u84dd\u5236\u56fe\u6559\u7a0b\u7684\u51ac\u83dc\u6559\u7a0b, \u4f60\u53ef\u4ee5\u5230\u851a\u84dd\u7684\u5236\u56fe\u7fa4 (633125440) \u4e2d\u53d6\u5f97, \u6216\u8005\u4e5f\u53ef\u4ee5\u5728\u8fd9\u4e2a\u7f51\u76d8\u94fe\u63a5\u4e2d\u53d6\u5f97.
"},{"location":"extra_luacs/begin/#_3","title":"\u57fa\u7840\u6982\u5ff5","text":"\u76f8\u4fe1\u5728\u524d\u9762\u7684\u9605\u8bfb\u4e2d\u4f60\u80af\u5b9a\u662f\u4e00\u5934\u96fe\u6c34\u7684, \u56e0\u4e3a\u4f60\u5bf9 lua \u4ee3\u7801\u901a\u5e38\u4f9d\u7136\u662f\u4e00\u65e0\u6240\u77e5\u7684, \u90a3\u5c31\u5bf9\u4e86, \u73b0\u5728\u6211\u4eec\u5c31\u6765\u4ecb\u7ecd\u51e0\u4e2a\u7b80\u5355\u7684\u6982\u5ff5.
"},{"location":"extra_luacs/begin/#_4","title":"\u51fd\u6570","text":"\u5728\u6211\u4eec\u521a\u521a\u7684 lua \u4ee3\u7801\u4e2d, \u6700\u5916\u56f4\u7684\u7531 function
\u5230 end
\u56f4\u8d77\u6765\u7684\u4e1c\u897f\u6211\u4eec\u5c31\u53eb\u4e00\u4e2a\u51fd\u6570:
function onBegin()\n disableMovement()\n say(\"TESTDIALOG_HELLO\")\n enableMovement()\nend\n
function
\u548c end
\u8fd9\u79cd\u5173\u7cfb\u5230\u4ee3\u7801\u7ed3\u6784\u7684\u4e1c\u897f\u6211\u4eec\u5c31\u53eb\u5b83 '\u5173\u952e\u5b57', function
\u5173\u952e\u5b57\u540e\u9762\u5230\u5de6\u62ec\u53f7\u4e4b\u5185\u7684\u5185\u5bb9\u5c31\u662f\u8fd9\u4e2a\u51fd\u6570\u7684\u51fd\u6570\u540d, \u5728\u8fd9\u91cc\u5373 onBegin
, \u5728\u8fd9\u91cc\u8fd9\u4e2a\u51fd\u6570\u540d\u662f\u7279\u6b8a\u7684, \u5b83\u4f1a\u88ab LuaCutscene \u5728\u73a9\u5bb6\u8fdb\u5165 trigger \u65f6\u4e14\u5267\u60c5\u53ef\u4ee5\u64ad\u653e\u65f6 '\u8c03\u7528'. \u62ec\u53f7\u5185\u7684\u5185\u5bb9\u6211\u4eec\u53eb\u53c2\u6570, \u8fd9\u91cc LuaCutscene \u8981\u6c42\u6211\u4eec onBegin
\u8fd9\u4e2a\u7279\u6b8a\u51fd\u6570\u4e0d\u80fd\u5e26\u53c2\u6570\u6216\u8005\u5e26\u4e00\u4e2a\u53c2\u6570, \u8fd9\u91cc\u6211\u4eec\u6682\u65f6\u7f6e\u7a7a, \u4e5f\u5c31\u662f\u53ea\u6709\u4e00\u5bf9\u62ec\u53f7, \u4e0d\u5e26\u53c2\u6570. \u800c\u8fd9\u4e4b\u4e2d\u7684\u5185\u5bb9\u4fbf\u662f\u51fd\u6570\u7684\u5185\u5bb9\u7269, \u4e5f\u5373\u4e3b\u4f53, \u5b83\u4f1a\u4ece\u4e0a\u5230\u4e0b\u987a\u5e8f\u6267\u884c\u6211\u4eec\u7684\u4ee3\u7801.
\u901a\u5e38\u4e3b\u4f53\u662f\u6211\u4eec\u6240\u805a\u7126\u7684\u4e1c\u897f, \u5728\u8fd9\u91cc, \u6211\u4eec\u7684\u4e3b\u4f53\u5305\u542b\u4e09\u884c\u4ee3\u7801. \u7b2c\u4e00\u884c\u4ee3\u7801\u662f disableMovement()
, \u4e5f\u5c31\u662f\u4e00\u4e2a\u540d\u79f0\u52a0\u4e0a\u4e00\u5bf9\u62ec\u53f7, \u5b83\u8868\u793a\u8c03\u7528\u4e00\u4e2a\u540d\u4e3a disableMovement
\u7684\u51fd\u6570, \u5e76\u4e14\u4e0d\u5e26\u53c2\u6570, \u8fd9\u548c\u521a\u624d\u51fd\u6570\u7684\u58f0\u660e\u6709\u70b9\u76f8\u50cf, disableMovement
\u662f\u4e00\u4e2a LuaCutscene \u4e3a\u6211\u4eec\u63d0\u524d\u51c6\u5907\u597d\u7684, \u4e5f\u5373 '\u5b9a\u4e49' \u597d\u7684\u51fd\u6570, \u5b83\u7684\u4f5c\u7528\u662f\u7981\u6b62\u73a9\u5bb6\u7684\u79fb\u52a8, \u4e0e\u4e4b\u76f8\u5bf9\u7684\u5c31\u662f enableMovement
\u51fd\u6570, \u5b83\u4f1a\u5141\u8bb8\u73a9\u5bb6\u79fb\u52a8. \u4e2d\u95f4\u7684\u7b2c\u4e8c\u884c\u4ee3\u7801\u8c03\u7528\u4e86 say
\u8fd9\u4e2a\u51fd\u6570, \u5b83\u8868\u793a\u64ad\u653e\u4e00\u4e2a\u5bf9\u8bdd, \u90a3\u4e48\u8fd9\u91cc\u5bf9\u8bdd\u540d\u5c31\u9700\u8981\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u4e86, \u6240\u4ee5\u6211\u4eec\u5728\u62ec\u53f7\u4e2d\u5199\u5165\u521a\u624d\u6211\u4eec\u7684\u5bf9\u8bdd\u540d TESTDIALOG_HELLO
, \u8bb0\u4f4f\u8981\u5e26\u53cc\u5f15\u53f7, \u56e0\u4e3a\u5b83\u662f\u4e00\u4e2a '\u5b57\u7b26\u4e32'.
Info
disableMovement
\u4e0e enableMovement
\u51fd\u6570\u90fd\u662f\u77ac\u95f4\u6267\u884c\u5b8c\u6bd5\u7684, \u51fd\u6570\u4f1a\u9a6c\u4e0a\u7ee7\u7eed\u6267\u884c\u4e0b\u9762\u7684\u4ee3\u7801, \u800c say
\u51fd\u6570\u8c03\u7528\u540e\u76f4\u5230\u73a9\u5bb6\u770b\u5b8c\u5bf9\u8bdd\u624d\u4f1a\u7ee7\u7eed\u6267\u884c\u4e0b\u9762\u7684\u4ee3\u7801. \u5bf9\u4e8e\u540e\u8005\u6211\u4eec\u7279\u522b\u5730\u79f0\u4e3a \u534f\u7a0b\u51fd\u6570
.
"},{"location":"extra_luacs/begin/#if","title":"\u53d8\u91cf, \u8fd4\u56de\u503c, if","text":"\u73b0\u5728, \u6211\u4eec\u89c2\u5bdf\u4e0b\u9762\u4ee3\u7801:
function onBegin()\n local hasFlag = getFlag(\"MY_AWESOME_FLAG\")\n if hasFlag then\n disableMovement()\n say(\"TESTDIALOG_HELLO\")\n enableMovement()\n end\nend\n
\u5728\u51fd\u6570\u5f00\u5934\u6211\u4eec\u4f7f\u7528\u4e86 local a = b()
\u8fd9\u79cd\u8bed\u6cd5, \u5f00\u5934\u7684 local
\u5173\u952e\u5b57\u8868\u793a\u6211\u4eec\u8981\u58f0\u660e\u4e00\u4e2a\u53d8\u91cf, \u7d27\u8ddf\u7684 hasFlag
\u8868\u793a\u8fd9\u4e2a\u53d8\u91cf\u7684\u540d\u79f0, \u968f\u540e\u518d\u6b21\u8ddf\u4e0a\u4e00\u4e2a =
\u53f7, \u8fd9\u8868\u793a\u6211\u4eec\u60f3\u4ee5 =
\u53f7\u540e\u8fb9\u7684\u503c\u4f5c\u4e3a\u8fd9\u4e2a\u53d8\u91cf\u7684\u503c, \u5728\u8fd9\u91cc\u5b83\u662f getFlag
\u8fd9\u4e2a\u9884\u5148\u5b9a\u4e49\u7684\u51fd\u6570\u7684\u8fd4\u56de\u503c, \u51fd\u6570\u901a\u5e38\u7528\u4e8e\u505a\u4e00\u4e9b\u4e8b\u60c5, \u800c\u5b83\u7684\u8fd4\u56de\u503c\u5c31\u8868\u793a\u8fd9\u4ef6\u4e8b\u505a\u7684\u5982\u4f55, \u5728\u8fd9\u91cc getFlag
\u51fd\u6570\u7528\u4e8e\u68c0\u6d4b\u5b83\u7684\u53c2\u6570\u6307\u4ee3\u7684\u90a3\u4e2a flag \u662f\u5426\u5b58\u5728, \u5f53\u68c0\u6d4b\u5230 flag \u5b58\u5728\u65f6\u5b83\u4f1a\u8fd4\u56de true
, \u5426\u4e4b\u5219\u8fd4\u56de false
. \u8fd9\u91cc\u8fd9\u4e2a\u8fd4\u56de\u503c\u7684 '\u7c7b\u578b' \u662f bool
, \u5b83\u53ea\u6709\u521a\u624d\u63d0\u5230\u7684\u4e24\u4e2a\u503c, \u6240\u4ee5\u540c\u6837\u5730 hasFlag
\u8fd9\u4e2a\u53d8\u91cf\u7684\u7c7b\u578b\u662f bool
.
\u5f53\u6211\u4eec\u4ece getFlag
\u5f97\u5230\u4e86\u5bf9\u5e94 flag \u662f\u5426\u5b58\u5728\u7684\u4fe1\u606f\u540e, \u6211\u4eec\u4f7f\u7528 if \u8bed\u53e5\u6765\u68c0\u6d4b\u5b83, \u9996\u5148\u6211\u4eec\u4ee5 if
\u5f00\u5934, \u7136\u540e\u7d27\u8ddf\u4e00\u4e2a bool
\u7c7b\u578b\u7684\u503c, \u4e5f\u5c31\u662f\u8fd9\u91cc\u7684 hasFlag
\u53d8\u91cf, \u7136\u540e\u518d\u8ddf\u4e0a\u4e00\u4e2a then
\u5173\u952e\u5b57, \u968f\u540e\u518d\u6b21\u8ddf\u4e0a\u4e00\u5c0f\u6bb5\u4ee3\u7801, \u968f\u540e\u4ee5 end
\u7ed3\u675f, \u8fd9\u91cc\u7684\u610f\u601d\u5c31\u662f\u6211\u4eec\u5e0c\u671b then
\u5230 end
\u6240\u5305\u56f4\u8d77\u6765 '\u4ee3\u7801\u5757' \u4ec5\u5728 hasFlag
\u4e3a true
, \u4e5f\u5373 getFlag
\u8fd4\u56de true
, \u4e5f\u5373 flag MY_AWESOME_FLAG
\u5b58\u5728\u65f6\u6267\u884c. \u73b0\u5728\u4f60\u53ef\u4ee5\u8bd5\u8bd5\u590d\u5236\u4e0a\u8ff0\u7684\u4ee3\u7801, \u7136\u540e\u5728\u4f60\u7684\u5730\u56fe\u4e2d\u653e\u7f6e\u4e24\u4e2a flag Trigger, \u4e00\u4e2a\u5f00\u542f MY_AWESOME_FLAG
\u8fd9\u4e2a flag, \u4e00\u4e2a\u5173\u95ed flag, \u7136\u540e\u5206\u522b\u5c1d\u8bd5\u8d70\u8fdb\u5267\u60c5 trigger, \u4f60\u5f88\u5bb9\u6613\u4f1a\u53d1\u73b0\u4ec5\u5728 MY_AWESOME_FLAG
flag \u5f00\u542f\u65f6\u5267\u60c5\u624d\u4f1a\u88ab\u64ad\u653e, \u4e5f\u5c31\u662f\u64ad\u653e\u5267\u60c5\u7684\u90a3\u4e09\u884c\u4ee3\u7801\u624d\u4f1a\u88ab\u6267\u884c.
\u5b9e\u9645\u4e0a\u65e2\u7136 if
\u5230 then
\u4e4b\u95f4\u53ea\u9700\u8981\u4e00\u4e2a\u7c7b\u578b\u4e3a bool
\u7684\u503c, \u90a3\u4e48\u8fd9\u91cc\u5176\u5b9e\u4e0d\u9700\u8981 hasFlag
\u8fd9\u4e2a\u53d8\u91cf\u4f5c\u4e3a\u8fc7\u6e21:
function onBegin()\n if getFlag(\"MY_AWESOME_FLAG\") then\n disableMovement()\n say(\"TESTDIALOG_HELLO\")\n enableMovement()\n end\nend\n
\u8fd9\u884c\u4ee3\u7801\u4e0e\u4e0a\u9762\u662f\u7b49\u6548\u7684.
\u901a\u5e38\u6709\u65f6\u5019\u6211\u4eec\u5e0c\u671b flag \u62e5\u6709\u60c5\u51b5\u4e0d\u4e00\u7684\u65f6\u5019\u64ad\u653e\u4e0d\u540c\u7684\u5267\u60c5, \u6bd4\u5982\u4e0a\u9762\u62e5\u6709 MY_AWESOME_FLAG
flag \u65f6\u64ad\u653e\u5267\u60c5 A, \u800c\u6ca1\u6709\u65f6\u64ad\u653e\u5267\u60c5 B. \u9996\u5148\u6211\u4eec\u5148\u66f4\u65b0\u6211\u4eec\u7684\u5bf9\u8bdd\u6587\u4ef6:
TESTDIALOG_HELLO=\n [MADELINE left normal]\n \u62e5\u6709 flag\n\nTESTDIALOG_HELLO_NOFLAG=\n [MADELINE left normal]\n \u6ca1\u6709 flag\n
\u7136\u540e\u66f4\u65b0 lua \u4ee3\u7801:
function onBegin()\n if getFlag(\"MY_AWESOME_FLAG\") then\n disableMovement()\n say(\"TESTDIALOG_HELLO\")\n enableMovement()\n else\n disableMovement()\n say(\"TESTDIALOG_HELLO_NOFLAG\")\n enableMovement()\n end\nend\n
\u73b0\u5728\u5728\u6e38\u620f\u4e2d\u5c1d\u8bd5\u4e00\u4e0b, \u7b26\u5408\u6211\u4eec\u7684\u671f\u671b: \u6ca1\u6709 flag \u65f6\u64ad\u653e TESTDIALOG_HELLO_NOFLAG
\u8fd9\u4e2a\u5bf9\u8bdd, \u62e5\u6709 flag \u65f6\u64ad\u653e TESTDIALOG_HELLO
\u8fd9\u4e2a\u5bf9\u8bdd.
\u89c2\u5bdf\u4e0a\u8ff0\u4ee3\u7801, \u6211\u4eec\u53d1\u73b0\u7981\u6b62\u548c\u5141\u8bb8\u79fb\u52a8\u7684\u90a3\u4e00\u5bf9\u51fd\u6570\u8c03\u7528\u6ca1\u5fc5\u8981\u91cd\u590d\u4e24\u904d\u5199\u5728 if \u91cc, \u56e0\u4e3a\u65e0\u8bba if \u7684\u6761\u4ef6\u662f\u5426\u6210\u7acb\u5b83\u4eec\u90fd\u662f\u5148\u7981\u6b62\u79fb\u52a8, \u7136\u540e\u518d\u5141\u8bb8\u79fb\u52a8, \u6240\u4ee5\u6211\u4eec\u5c06\u90a3\u4e00\u5bf9\u4ee3\u7801\u62bd\u79bb\u5e76\u653e\u7f6e\u5728\u6700\u4e0a\u4e0b:
function onBegin()\n disableMovement()\n if getFlag(\"MY_AWESOME_FLAG\") then\n say(\"TESTDIALOG_HELLO\")\n else\n say(\"TESTDIALOG_HELLO_NOFLAG\")\n end\n enableMovement()\nend\n
\u5f53\u7136, \u6548\u679c\u662f\u4e00\u6837\u7684, \u4f46\u662f\u6211\u4eec\u7684\u4ee3\u7801\u7b80\u6d01\u4e86\u4e0d\u5c11.
"},{"location":"extra_luacs/begin/#_5","title":"\u66f4\u591a\u51fd\u6570","text":"\u73b0\u5728, \u56de\u5fc6\u4e00\u4e0b\u6211\u4eec\u5df2\u7ecf\u4e86\u89e3\u5230\u4e86\u54ea\u4e9b\u51fd\u6570:
\u4e00\u4e2a\u6700\u4e0a\u9762\u4f7f\u7528\u8fc7\u7684\u51fd\u6570 print
, \u4f5c\u7528\u4e3a\u5c06\u5b83\u7684\u53c2\u6570\u5185\u5bb9\u8f93\u51fa\u51fa\u6765 disableMovement
, \u6ca1\u6709\u53c2\u6570, \u4f5c\u7528\u4e3a\u7981\u6b62\u73a9\u5bb6\u7684\u79fb\u52a8 enableMovement
, \u6ca1\u6709\u53c2\u6570, \u4f5c\u7528\u4e3a\u5141\u8bb8\u73a9\u5bb6\u7684\u79fb\u52a8 say
, \u4f5c\u7528\u4e3a\u64ad\u653e\u53c2\u6570\u6240\u6307\u7684\u5bf9\u8bdd getFlag
, \u4f5c\u7528\u4e3a\u68c0\u6d4b\u53c2\u6570\u6240\u6307\u7684 flag \u662f\u5426\u5b58\u5728, \u5e76\u4e14\u8fd4\u56de\u8be5\u503c \u5f53\u7136, \u51fd\u6570\u7684\u53c2\u6570\u4e0d\u53ef\u80fd\u53ea\u6709\u4e00\u4e2a, \u6bd4\u5982 cassetteFly
\u51fd\u6570:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\n -- cassetteFly \u8c03\u7528\u5b8c\u540e\u5e76\u4e0d\u4f1a\u7b49\u5f85...\n enableMovement()\nend\n
Info
-- \u5e76\u52a0\u4e0a\u7a7a\u683c\u8d77\u5934\u7684\u4e00\u884c\u8868\u793a\u4e00\u884c\u6ce8\u91ca, \u5f53\u4ee3\u7801\u6267\u884c\u5230\u8fd9\u65f6\u4f1a\u76f4\u63a5\u5ffd\u7565\u8fd9\u4e00\u884c, \u6b64\u5916\u8fd8\u6709\u5757\u6ce8\u91ca, \u5373\u5ffd\u7565\u5757\u6240\u5305\u56f4\u7684\u4e00\u6574\u5757\u4ee3\u7801:
function onBegin()\n --[[\n \u5728\u8fd9\u91cc\n \u5199\n \u4efb\u610f\n \u591a\n \u7684\u6ce8\u91ca!\n ]]--\n say(\"SOMETHING_INTERESTING\")\nend\n
cassetteFly
\u51fd\u6570\u4f5c\u7528\u4e3a\u4e58\u5750\u6ce1\u6ce1\u98de\u884c\u4e00\u6bb5\u8ddd\u79bb(\u6536\u96c6\u78c1\u5e26\u540e\u7684\u52a8\u4f5c), \u5b83\u9700\u8981\u63a5\u6536\u4e24\u4e2a\u53c2\u6570, \u5b83\u4eec\u5747\u4e3a number
\u7c7b\u578b, \u8868\u793a\u4e00\u4e2a\u6570\u5b57, \u591a\u4e2a\u53c2\u6570\u4e4b\u95f4\u4f7f\u7528 ,
\u9017\u53f7\u5206\u9694\u5f00\u6765, \u6ce8\u610f\u8fd9\u91cc\u53c2\u6570\u7c7b\u578b\u662f\u6570\u5b57, \u6240\u4ee5\u4e0d\u9700\u8981\u52a0\u4e0a\u53cc\u5f15\u53f7\u8868\u793a\u4e3a\u5b57\u7b26\u4e32. \u7b2c\u4e00\u4e2a\u53c2\u6570\u8868\u793a\u6a2a\u5411\u7684\u76f8\u5bf9\u98de\u884c\u8ddd\u79bb, \u5355\u4f4d px, \u6b63\u503c\u5411\u53f3, \u8d1f\u503c\u5411\u5de6, \u7b2c\u4e8c\u4e2a\u53c2\u6570\u8868\u793a\u7eb5\u5411\u7684\u76f8\u5bf9\u98de\u884c\u8ddd\u79bb, \u6b63\u503c\u5411\u4e0b, \u8d1f\u503c\u5411\u4e0a.
\u4e0d\u8fc7\u4e0d\u592a\u597d\u7684\u662f cassetteFly
\u4e0d\u662f\u534f\u7a0b\u51fd\u6570, \u8fd9\u4f1a\u9020\u6210\u8c03\u7528\u4e86\u8be5\u51fd\u6570\u540e\u9a6c\u4e0a\u8c03\u7528 enableMovement
\u51fd\u6570, \u8fd9\u4f1a\u6253\u65ad\u6ce1\u6ce1\u98de\u884c\u7684\u8fc7\u7a0b, \u6240\u4ee5\u6211\u4eec\u5148\u6682\u65f6\u5220\u6389 enableMovement
\u7684\u8c03\u7528, \u4e0d\u8fc7\u4e0d\u8981\u62c5\u5fc3, \u6ce1\u6ce1\u98de\u884c\u7ed3\u675f\u540e\u4f1a\u81ea\u52a8\u5e2e\u6211\u4eec\u5141\u8bb8\u79fb\u52a8:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\nend\n
\u7136\u540e\u5230\u6e38\u620f\u4e2d\u89c2\u5bdf\u8fd9\u4e2a\u6ce1\u6ce1\u98de\u884c\u8fdb\u884c\u6240\u9700\u7684\u5927\u6982\u65f6\u95f4, \u53d1\u73b0\u5927\u6982\u662f 1.5 \u79d2, \u6240\u4ee5\u6211\u4eec\u5728\u6ce1\u6ce1\u98de\u884c\u7684\u8c03\u7528\u540e\u9762\u7d27\u8ddf\u4e00\u4e2a wait
\u7684\u8c03\u7528:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\n wait(1.5)\nend\n
\u987a\u4fbf, \u6ce1\u6ce1\u98de\u884c\u7ed3\u675f\u540e\u4f1a\u81ea\u52a8\u5141\u8bb8\u79fb\u52a8, \u6240\u4ee5\u6211\u4eec\u8fd8\u5f97\u518d\u6b21\u7981\u6389\u79fb\u52a8:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\n wait(1.5)\n disableMovement()\nend\n
\u4ee5\u53ca, \u6211\u4eec\u8fd8\u5e0c\u671b\u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e4b\u540e\u518d\u64ad\u653e\u4e00\u6bb5\u5bf9\u8bdd:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\n wait(1.5)\n disableMovement()\n say(\"TESTDIALOG_FLY\")\nend\n
\u8fd9\u662f\u5bf9\u5e94\u7684 dialog:
TESTDIALOG_FLY=\n [MADELINE left normal]\n \u563f\u6211\u521a\u624d\u5b8c\u6210\u4e86\u4e00\u6b21\u6ce1\u6ce1\u98de\u884c\u54ce\n
\u987a\u4fbf\u4e0d\u8981\u5fd8\u4e86\u518d\u5141\u8bb8\u79fb\u52a8:
function onBegin()\n disableMovement()\n cassetteFly(-100, -100)\n wait(1.5)\n disableMovement()\n say(\"TESTDIALOG_FLY\")\n enableMovement()\nend\n
\u73b0\u5728\u5728\u6e38\u620f\u91cc\u8bd5\u4e00\u4e0b, \u662f\u4e0d\u662f\u5148\u5411\u5de6\u4e0a\u89d2\u8fdb\u884c\u4e00\u4e2a (-100, -100) \u7684\u6ce1\u6ce1\u98de\u884c, \u7136\u540e\u8fc7\u4e86 1.5 \u79d2\u540e\u51c6\u65f6\u64ad\u653e TESTDIALOG_FLY
\u8fd9\u4e2a\u5bf9\u8bdd, \u7136\u540e\u4ec5\u5728\u5bf9\u8bdd\u7ed3\u675f\u540e\u624d\u80fd\u79fb\u52a8?
\u9664\u4e86\u4f7f\u7528 flag trigger \u8bbe\u7f6e flag \u4ee5\u5916, \u8fd8\u53ef\u4ee5\u5728 lua \u4e2d\u8bbe\u7f6e flag:
function onBegin()\n setFlag(\"FLAG_FROM_LUA\", true)\nend\n
setFlag
\u51fd\u6570\u63a5\u6536\u4e24\u4e2a\u53c2\u6570, \u7b2c\u4e00\u4e2a\u53c2\u6570\u4e3a string \u7c7b\u578b, \u6307\u4ee3\u4e00\u4e2a flag, \u7b2c\u4e8c\u4e2a\u53c2\u6570\u4e3a bool \u7c7b\u578b, \u8868\u793a\u8981\u8bbe\u7f6e\u4e3a\u5f00\u542f\u8fd8\u662f\u5173\u95ed. \u90a3\u4e48\u663e\u800c\u6613\u89c1, \u6548\u679c\u5c31\u662f\u7ecf\u8fc7\u8fd9\u4e2a \"\u5267\u60c5\" trigger \u65f6 FLAG_FROM_LUA
\u8fd9\u4e2a flag \u4f1a\u88ab\u5f00\u542f. \u4f60\u53ef\u4ee5\u627e\u4e00\u4e9b\u5176\u4ed6\u7684 flag \u9a71\u52a8\u7684\u5b9e\u4f53\u6765\u9a8c\u8bc1\u4e00\u4e0b.
\u987a\u4fbf\u6211\u4eec\u8fd8\u53ef\u4ee5\u505a\u4e00\u4e2a\u6709\u8da3\u7684\u6548\u679c, \u7ecf\u8fc7 trigger \u65f6\u53cd\u8f6c\u5f00\u542f\u72b6\u6001:
function onBegin()\n setFlag(\"FLAG_FROM_LUA\", not getFlag(\"FLAG_FROM_LUA\"))\nend\n
getFlag
\u8fd4\u56de\u4e86\u4e00\u4e2a bool \u7c7b\u578b\u7684\u503c, \u7136\u540e\u6211\u4eec\u5728\u8fd9\u4e2a\u503c, \u5728\u8fd9\u91cc\u662f\u51fd\u6570\u8c03\u7528\u7684\u8fd4\u56de\u503c\u5de6\u4fa7\u5199\u4e00\u4e2a not, \u5b83\u8868\u793a\u7ffb\u8f6c bool \u7684\u503c, \u5373 true -> false, false -> true, \u90a3\u4e48\u5728\u8fd9\u91cc\u5c31\u662f\u6bcf\u6b21\u89e6\u53d1 trigger \u65f6 FLAG_FROM_LUA
\u7684\u5f00\u542f\u72b6\u6001\u88ab\u53cd\u8f6c.
"},{"location":"extra_luacs/begin/#_6","title":"\u903b\u8f91\u8fd0\u7b97\u7b26","text":"\u5bf9\u4e8e\u8fd9\u4e9b lua \u901a\u7528\u5185\u5bb9\u5c31\u76f4\u63a5\u4e22\u4e2a w3c \u7684\u94fe\u63a5\u4e86: Lua \u8fd0\u7b97\u7b26 w3cschool - https://www.w3cschool.cn/...
\u8fd0\u7528\u4e0a\u9762\u7684\u77e5\u8bc6\u4f60\u53ef\u4ee5\u5199\u4e00\u4e2a if \u4f7f\u5f97\u4ec5\u5728\u4e24\u4e2a flag \u540c\u65f6\u6210\u7acb\u65f6\u624d\u6267\u884c\u5185\u90e8\u7684\u4ee3\u7801:
function onBegin()\n local flagA = getFlag(\"MY_FLAG_A\")\n local flagB = getFlag(\"MY_FLAG_B\")\n\n if flagA and flagB then\n print(\"\u540c\u65f6\u6210\u7acb!\")\n end\nend\n
"},{"location":"extra_luacs/begin/#_7","title":"\u5176\u4ed6\u7279\u6b8a\u51fd\u6570","text":"\u9664\u4e86\u4e0a\u6587\u63d0\u5230\u7684 onBegin
\u8fd9\u4e2a\u7279\u6b8a\u51fd\u6570\u5916, \u8fd8\u6709\u53e6\u5916\u4e00\u4e2a\u7ecf\u5e38\u7528\u5230\u7684 onEnd
\u51fd\u6570, \u987e\u540d\u601d\u4e49, \u5c31\u662f\u5267\u60c5\u7ed3\u675f\u65f6\u88ab\u8c03\u7528\u7684\u51fd\u6570, \u5b83\u901a\u5e38\u4f1a\u5e26\u4e24\u4e2a\u53c2\u6570:
function onEnd(room, wasSkipped)\n -- \u505a\u4e00\u4e9b\u6e05\u7406\u5de5\u4f5c...\nend\n
\u901a\u5e38\u6211\u4eec\u53ea\u4f1a\u5728 onEnd
\u8c03\u7528\u4e2d\u505a\u6e05\u7406\u5de5\u4f5c, \u6bd4\u5982\u8bf4\u5220\u6389\u5267\u60c5\u4e2d\u51fa\u73b0\u7684\u989d\u5916\u5b9e\u4f53, \u8bbe\u7f6e\u73a9\u5bb6\u7684\u4f4d\u7f6e\u5230\u6700\u7ec8\u4f4d\u7f6e\u7b49\u7b49, \u6ce8\u610f\u7684\u662f, \u8df3\u8fc7\u5267\u60c5\u8fd9\u4e2a\u52a8\u4f5c\u5b9e\u9645\u4e0a\u4f1a\u76f4\u63a5\u6253\u65ad onBegin
\u7684\u6267\u884c, \u5e76\u4e14\u4e5f\u4f1a\u8c03\u7528 onEnd
, \u8fd9\u4e2a\u6253\u65ad\u4f4d\u7f6e\u662f\u4e0d\u53ef\u9884\u77e5. \u5176\u4e2d\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f Level
\u7c7b\u578b\u7684\u503c, \u5b83\u662f\u4e00\u4e2a\u851a\u84dd\u4ee3\u7801\u4e2d\u7684\u7c7b\u578b, \u8fd9\u91cc\u6211\u4eec\u6682\u65f6\u5ffd\u7565, \u6765\u5173\u6ce8\u7b2c\u4e8c\u4e2a\u53c2\u6570, \u5b83\u662f\u4e00\u4e2a bool
\u7c7b\u578b\u7684\u503c, \u5b83\u8868\u793a\u8fd9\u4e2a\u5267\u60c5\u662f\u81ea\u7136\u7ed3\u675f\u7684\u8fd8\u662f\u88ab\u8df3\u8fc7\u7684, \u6bd4\u5982\u5728\u4e00\u4e9b\u79fb\u52a8\u8f83\u591a\u7684\u5267\u60c5\u4e2d~(\u591a\u52a8\u75c7) ~, \u5176 onEnd
\u5c31\u4f1a\u901a\u5e38\u662f\u8bbe\u7f6e\u73a9\u5bb6\u7684\u4f4d\u7f6e\u5230\u6700\u7ec8\u4f4d\u7f6e, \u987a\u5e26\u4e00\u63d0, \u5b98\u56fe\u4e2d\u6709\u4e9b\u5267\u60c5\u7684\u4f4d\u7f6e\u8bbe\u7f6e\u53ea\u8bbe\u7f6e\u4e86\u6a2a\u5750\u6807, \u6240\u4ee5\u6bd4\u5982 5a \u8fdb\u5165\u5185\u90e8\u90a3\u6bb5\u8def\u7684\u5728\u534a\u7a7a\u4e2d\u8df3\u8fc7\u5267\u60c5\u6765\u76f4\u63a5\u6a2a\u5411\u79fb\u52a8\u5230\u6309\u94ae\u4e0a\u7684\u901f\u901a\u6280\u5de7\u624d\u5f97\u4ee5\u5b9e\u73b0.
\u6ce8\u610f\u7684\u662f, onEnd
\u51fd\u6570\u4e2d\u4e0d\u80fd\u4f7f\u7528\u534f\u7a0b\u51fd\u6570, \u5982\u679c\u4f60\u8fd9\u4e48\u505a\u4e86\u4f60\u4f1a\u5f97\u5230\u4e00\u4e2a attempt to yield from outside a coroutine
\u7684\u62a5\u9519, \u8fd9\u662f\u56e0\u4e3a onBegin
\u51fd\u6570\u672c\u8eab\u4e5f\u662f\u4e00\u4e2a\u534f\u7a0b\u51fd\u6570, \u8fd9\u624d\u5141\u8bb8\u4f60\u5728\u5185\u90e8\u4f7f\u7528\u534f\u7a0b\u51fd\u6570.
"},{"location":"extra_luacs/begin/#_8","title":"\u5176\u4ed6\u51fd\u6570","text":"\u9664\u4e86\u4e0a\u8ff0\u63d0\u5230\u7684 say
, getFlag
, setFlag
\u7b49\u5916, \u8fd8\u6709\u975e\u5e38\u591a\u9884\u5148\u5b9a\u4e49\u597d\u7684\u51fd\u6570, \u4f60\u53ef\u4ee5\u5728\u4e0b\u9762\u8fd9\u4e2a\u94fe\u63a5\u4e2d\u627e\u5230: Lua Cutscenes Documentaion - https://maddie480.ovh/...
\u5728\u4e0a\u9762\u8fd9\u4e2a\u6587\u6863\u4e2d\u6bd4\u5982\u8fd9\u4e2a\u51fd\u6570:
Function Description helpers.die([direction={0, 0}[, evenIfInvincible=false[, registerDeathInStats=true]]]) Kills the player. \u5176\u4e2d helpers.die
\u8bf4\u660e\u8fd9\u4e2a\u51fd\u6570\u540d\u662f die, \u540e\u9762\u5706\u62ec\u53f7\u56f4\u8d77\u6765\u7684\u8868\u793a\u5b83\u7684\u53c2\u6570, \u4e00\u5c42\u5c42\u4e2d\u62ec\u53f7\u56f4\u8d77\u6765\u7684\u8868\u793a\u53ef\u9009\u53c2\u6570, \u53c2\u6570\u540d\u540e\u9762\u52a0\u7b49\u4e8e\u53f7\u8868\u793a\u8be5\u53ef\u9009\u53c2\u6570\u7684\u9ed8\u8ba4\u503c, \u6bd4\u5982\u4e0a\u8ff0\u51fd\u6570\u7684\u8c03\u7528\u53ef\u4ee5\u6709:
\u8c03\u7528\u65b9\u5f0f \u7b49\u6548\u8c03\u7528\u65b9\u5f0f die() die(vector2(0, 0), false, true) die(vector2(1, 1)) die(vector2(1, 1), false, true) die(vector2(1, 1), true) die(vector2(1, 1), true, true) die(vector2(1, 1), true, false) die(vector2(1, 1), true, false) \u987a\u4fbf, \u5176\u4e2d\u7b2c\u4e00\u4e2a\u53c2\u6570\u7684\u7c7b\u578b\u662f\u4e2a Vector2
, \u8868\u793a\u4e00\u4e2a\u4e8c\u7ef4\u5411\u91cf, \u8fd9\u79cd\u7c7b\u578b\u7684\u503c\u4f60\u53ef\u4ee5\u8c03\u7528 vector2(1, 1)
\u51fd\u6570\u6765\u4ece\u8fd4\u56de\u503c\u5f97\u5230, \u987e\u540d\u601d\u4e49\u5b83\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f x \u5750\u6807, y \u5750\u6807. \u8fd9\u91cc\u5b83\u7684\u542b\u4e49\u662f\u73a9\u5bb6\u6b7b\u4ea1\u65f6\u7684\u7279\u6548\u65b9\u5411.
"},{"location":"extra_luacs/begin/#_9","title":"\u6700\u540e","text":"\u76f8\u4fe1\u5230\u8fd9\u91cc\u4f60\u5df2\u7ecf\u4f53\u4f1a\u5230\u4e86 luacutscene, \u6216\u8005\u8bf4\u6e38\u620f\u4e2d\u5185\u5d4c lua \u4ee3\u7801\u7684\u5f3a\u5927. \u5728\u4e4b\u540e\u7684\u6587\u7ae0\u4e2d\u5c31\u4e0d\u518d\u4f1a\u63d0\u53ca\u4e0e lua \u76f8\u5173\u7684\u95ee\u9898\u4e86, \u6240\u4ee5\u5728\u4e4b\u540e\u67e5\u627e\u5916\u90e8\u7684 lua \u6559\u7a0b\u662f\u5fc5\u8981\u7684, \u6bd4\u5982 w3cschool \u7684 lua \u6559\u7a0b.
"},{"location":"extra_luacs/cs_access/","title":"C# \u4ea4\u4e92","text":"\u4ece\u8fd9\u4e00\u5c0f\u8282\u5f00\u59cb\u5c31\u9700\u8981\u4f7f\u7528\u4e00\u5c0f\u4e9b C# \u77e5\u8bc6\u4e86, \u4e0d\u8fc7\u4e0d\u9700\u8981\u592a\u591a, \u4f60\u53ea\u9700\u8981\u80fd\u770b\u61c2 C# \u4fa7\u7684\u51fd\u6570, \u5b57\u6bb5, \u5c5e\u6027\u7b49\u7684\u5b9a\u4e49\u5c31\u884c.
"},{"location":"extra_luacs/cs_access/#c_1","title":"\u5f15\u5165 C# \u7c7b","text":"\u8981\u5f15\u7528\u4e00\u4e2a C# \u7c7b, \u9996\u5148\u9700\u8981\u5728\u6587\u4ef6\u9876\u90e8\u4f7f\u7528 require \u51fd\u6570:
local celeste = require(\"#Celeste.Celeste\")\n\nfunction onBegin()\n -- ...\nend\n
\u53c2\u6570\u9700\u8981\u4ee5 \"#<\u5b8c\u6574\u7c7b\u540d>\" \u683c\u5f0f\u4f20\u5165, \u6bd4\u5982\u4e0a\u8ff0\u4ee3\u7801\u5c31\u4f1a\u5f97\u5230\u4e00\u4e2a C# \u7c7b Celeste
, \u8fd9\u6837\u6211\u4eec\u53ef\u4ee5\u6765\u8c03\u7528\u4e00\u4e0b\u4ea7\u751f\u51bb\u7ed3\u5e27\u7684\u9759\u6001\u65b9\u6cd5:
local celeste = require(\"#Celeste.Celeste\")\n\nfunction onBegin()\n celeste.Freeze(0.5)\nend\n
\u5c31\u50cf\u4f60\u5728 C# \u4e2d\u6240\u505a\u7684\u4e00\u6837, \u4e0d\u8fc7\u8fd9\u91cc\u4f7f\u7528\u4e0a\u9762\u83b7\u53d6\u5230\u7684 celeste
\u4f5c\u4e3a\u4f60\u5728 C# \u4e2d\u4e66\u5199\u7684\u7c7b\u540d. \u4e0a\u8ff0\u4ee3\u7801\u5e94\u8be5\u4f1a\u5bfc\u81f4\u4f60\u8fdb\u5165 trigger \u65f6\u51bb\u7ed3 0.5 \u79d2.
"},{"location":"extra_luacs/cs_access/#_1","title":"\u65b9\u6cd5\u8c03\u7528, \u5b57\u6bb5, \u5c5e\u6027\u8bbf\u95ee","text":"\u901a\u5e38, \u5982\u679c\u4f60\u9700\u8981\u8bbf\u95ee C# \u4ee3\u7801\u5bf9\u73a9\u5bb6\u505a\u4e00\u4e9b\u6709\u8da3\u7684\u53d8\u52a8, \u83b7\u53d6\u73a9\u5bb6\u7c7b\u7684\u5b9e\u4f8b\u4ee5\u53ca\u5728\u5b9e\u4f8b\u4e0a\u8c03\u7528\u65b9\u6cd5\u662f\u5fc5\u4e0d\u53ef\u5c11\u7684.
\u5728 LuaCutscene \u4e2d\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u9884\u5b9a\u4e49\u548c\u8d4b\u503c\u7684 player
\u5168\u5c40\u53d8\u91cf, \u4e5f\u5c31\u662f\u5728\u4efb\u4f55\u65b9\u6cd5\u5185\u90fd\u80fd\u4f7f\u7528\u7684\u53d8\u91cf, \u4f8b\u5982, \u5728\u8fdb\u5165 trigger \u65f6\u5c06\u73a9\u5bb6\u7684\u51b2\u523a\u8bbe\u4e3a 2:
function onBegin()\n player.Dashes = 2\nend\n
\u4e0a\u8ff0\u4ee3\u7801\u8bbf\u95ee\u4e86 player \u5168\u5c40\u53d8\u91cf, \u5e76\u4e14\u8bbe\u7f6e\u5176 Dashes
\u5b57\u6bb5\u4e3a 2, \u4e5f\u5c31\u662f\u8bbe\u7f6e\u51b2\u523a\u6570\u4e3a2, \u4e0d\u8fc7\u8fd9\u6837\u4f1a\u5bfc\u81f4\u5728\u7a7a\u4e2d\u4e5f\u6062\u590d\u4e3a 2, \u6240\u4ee5\u6211\u4eec\u52a0\u5165\u5728\u662f\u5426\u5728\u5b89\u5168\u5730\u9762(\u8349\u8393\u80fd\u7ed3\u7b97\u7684\u90a3\u79cd)\u4e0a\u7684\u68c0\u6d4b:
function onBegin()\n if player.OnSafeGround then\n player.Dashes = 2\n end\nend\n
\u4e0a\u8ff0\u4ee3\u7801\u4e2d OnSafeGround
\u5c31\u662f\u4e00\u4e2a\u5c5e\u6027. \u4e0d\u8fc7\u4e0a\u9762\u8fd9\u6bb5\u4ee3\u7801\u6709\u4e00\u4e9b\u95ee\u9898, \u5f53\u4f60\u4ece\u4e0a\u5f80\u4e0b\u6389\u5165 trigger \u65f6, \u53ea\u6709\u8fdb\u5165\u7684\u90a3\u4e00\u5e27\u624d\u4f1a\u68c0\u6d4b\u5e76\u6062\u590d\u51b2\u523a, \u8fd9\u6709\u65f6\u5019\u5c31\u4e0d\u662f\u6211\u4eec\u60f3\u8981\u7684\u7ed3\u679c, \u6240\u4ee5\u6211\u4eec\u4f7f\u7528\u4e00\u4e2a\u65b0\u7684\u7279\u6b8a\u51fd\u6570 onStay
:
function onStay()\n if player.OnSafeGround then\n player.Dashes = 2\n end\nend\n
\u8fd9\u4f1a\u8ba9\u8fd9\u6bb5\u4ee3\u7801\u5728\u73a9\u5bb6\u63a5\u89e6\u5230 trigger \u7684\u6bcf\u4e00\u5e27\u90fd\u6267\u884c\u4ee3\u7801, \u7b26\u5408\u6211\u4eec\u76ee\u524d\u7684\u9700\u6c42. \u9664\u6b64\u4e4b\u5916\u8fd8\u6709\u53e6\u5916\u4e24\u4e2a: onEnter
\u548c onLeave
, \u5b83\u4eec\u90fd\u4e0d\u662f\u534f\u7a0b\u51fd\u6570, \u524d\u8005\u5728\u73a9\u5bb6\u8fdb\u5165 trigger \u65f6\u89e6\u53d1(\u8fd9\u4e0e onBegin
\u4e0d\u540c, \u6bd4\u5982\u5728\u5267\u60c5\u8fdb\u884c\u65f6\u4f60\u4f9d\u7136\u53ef\u4ee5\u63a7\u5236\u8fdb\u51fa trigger), \u540e\u8005\u5728\u73a9\u5bb6\u79bb\u5f00 trigger \u65f6\u6267\u884c.
\u5f53\u7136\u6211\u4eec\u8fd8\u53ef\u4ee5\u8c03\u7528\u4e00\u4e9b\u65b9\u6cd5, \u6bd4\u5982\u5267\u60c5\u5f00\u59cb\u65f6\u5f3a\u5236\u4e22\u5f03\u6293\u53d6\u7269:
function onBegin()\n player:Throw()\nend\n
\u6ce8\u610f\u5728\u8c03\u7528\u6210\u5458\u65b9\u6cd5\u65f6\u6211\u4eec\u9700\u8981\u4f7f\u7528 : \u7b26\u53f7, \u8fd9\u662f\u5230\u76ee\u524d\u4e3a\u6b62\u7684\u4e00\u4e2a\u7279\u4f8b.
"},{"location":"extra_luacs/cs_access/#_2","title":"\u79c1\u6709\u8bbf\u95ee","text":"\u5bf9\u4e8e\u79c1\u6709\u6210\u5458\u7684\u8bbf\u95ee, \u5728 Everest Core (\u622a\u6b62 4446) \u4e0a\u4f3c\u4e4e\u662f\u6709\u4e00\u4e9b\u95ee\u9898\u5bfc\u81f4\u5b8c\u5168\u4e0d\u80fd\u8bbf\u95ee, \u7ecf\u8fc7\u8be2\u95ee\u4f3c\u4e4e\u662f Core \u7684\u4e00\u4e9b\u7f13\u5b58\u95ee\u9898, \u5728 Stable \u4e0a\u4e0d\u4f1a\u51fa\u73b0, \u6545\u8fd9\u91cc\u6682\u65f6\u8df3\u8fc7, \u76f8\u5173\u79c1\u6709\u6210\u5458\u8bbf\u95ee\u53ef\u5728 C# \u4fa7\u64cd\u4f5c\u4f5c\u4e3a\u66ff\u4ee3.
"},{"location":"extra_luacs/cs_access/#_3","title":"\u534f\u7a0b","text":"lua \u4e0e c# \u4e24\u4fa7\u90fd\u6709\u534f\u7a0b\u7684\u6982\u5ff5, \u4e0d\u8fc7\u4e0d\u80fd\u76f4\u63a5\u4f7f\u7528, \u9700\u8981\u4e00\u5b9a\u7684\u8f6c\u6362, \u4f8b\u5982\u4f7f\u7528 Level.ZoomTo
\u51fd\u6570, \u5b83\u4f1a\u8fd4\u56de\u4e00\u4e2a\u5c06\u6444\u50cf\u673a\u7f29\u653e\u81f3\u67d0\u4e00\u70b9\u7684\u534f\u7a0b:
function onBegin()\n disableMovement()\n local level = player.Scene\n local c = level:ZoomTo(vector2(160, 90), 1.5, 2.0)\n coroutine.yield(c)\nend\n
\u4e0a\u8ff0\u4ee3\u7801\u8c03\u7528\u4e86 level
\u7684 ZoomTo
\u51fd\u6570, \u5e76\u5c06\u8fd4\u56de\u503c\u50a8\u5b58\u8d77\u6765, \u7136\u540e\u4f7f\u7528 coroutine.yield
\u5c06\u5176\u8f6c\u6362\u4e3a lua \u534f\u7a0b\u5e76\u7b49\u5f85. \u6e38\u620f\u4e2d\u7684\u6548\u679c\u5219\u4e3a\u76f8\u673a\u5728 2s \u5185\u5411\u5c4f\u5e55\u4e2d\u5fc3\u653e\u5927 1.5 \u500d. \u987a\u4fbf\u8fd9\u4e2a\u51fd\u6570\u8fd8\u6709\u4e2a\u914d\u5957\u7684\u7f29\u653e\u56de\u6765\u7684\u7248\u672c:
function onBegin()\n disableMovement()\n local level = player.Scene;\n coroutine.yield(level:ZoomTo(vector2(160, 90), 1.5, 2.0))\n coroutine.yield(level:ZoomBack(2.0))\nend\n
"},{"location":"extra_luacs/cs_access/#_4","title":"\u6700\u540e","text":"\u76f8\u4fe1\u5982\u679c\u4f60\u6ca1\u6709\u592a\u591a C# \u77e5\u8bc6\u7684\u8bdd, \u8fd9\u4e00\u5c0f\u8282\u4f60\u80af\u5b9a\u662f\u5f88\u56f0\u60d1\u4e0d\u77e5\u9053\u53d1\u751f\u4e86\u4ec0\u4e48\u7684, \u4e0d\u8fc7\u6ca1\u5173\u7cfb, \u4f60\u4f9d\u7136\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528\u540e\u7eed\u7ed9\u51fa\u7684\u4ee3\u7801\u6bb5\u548c\u73b0\u6210\u7684\u51fd\u6570\u6765\u505a\u4f60\u60f3\u505a\u7684\u4e8b.
"},{"location":"extra_luacs/examples/","title":"\u4f8b\u5b50","text":"\u5728\u8fd9\u4e00\u5c0f\u8282\u4e2d\u4f1a\u66f4\u591a\u5730\u4ecb\u7ecd\u4e00\u4e9b\u9884\u5b9a\u4e49\u51fd\u6570, \u4ee5\u53ca\u4e00\u4e9b\u5de5\u5177\u51fd\u6570\u7b49\u7b49, \u5728\u540e\u9762\u7684\u8282\u4e2d\u8fd8\u4f1a\u5305\u542b\u4e00\u4e9b helper \u5728 C# \u4fa7\u534f\u52a9\u5b9e\u73b0\u7684\u51fd\u6570.
"},{"location":"extra_luacs/examples/#_2","title":"\u4e00\u4e9b\u4ecb\u7ecd","text":"\u5c31\u5982\u4e4b\u524d\u6240\u8bf4\u7684, \u79fb\u52a8\u7684\u7981\u6b62\u72b6\u6001\u5e76\u4e0d\u4f1a\u5728\u5267\u60c5\u7ed3\u675f\u65f6\u81ea\u52a8\u89e3\u9664, \u5728\u5206\u652f\u590d\u6742\u5bb9\u6613\u5728\u672b\u5c3e\u5fd8\u8bb0\u8c03\u7528 enableMovement
\u7684\u60c5\u51b5\u4e0b, \u901a\u5e38\u5efa\u8bae\u5728 onEnd
\u51fd\u6570\u4e2d\u91cd\u65b0\u5141\u8bb8\u79fb\u52a8:
function onEnd()\n enableMovement()\nend\n
\u5bf9\u4e8e\u90e8\u5206\u8981\u6c42\u7edd\u5bf9\u5750\u6807\u7684\u51fd\u6570, \u4f60\u53ef\u4ee5\u901a\u8fc7\u6309\u4e0b\u952e\u76d8\u4e0a\u7684 ~
\u952e\u6765\u6253\u5f00\u8c03\u8bd5\u9762\u677f, \u5728\u754c\u9762\u5de6\u4e0a\u89d2\u4f1a\u6709\u4e00\u680f\u7c7b\u4f3c\u5982\u4e0b\u7684\u4fe1\u606f:
Area: 04 @ 12 (SID: Celeste/Saplonily/Test)\nCursor @\n screen: 792, 407\n world: -618, 213\n level: 1142, 397\n level, /8: 142, 49\n level, snap: 1136, 392\n
\u5176\u4e2d Area: 04 @ 12
\u4e2d\u7684 04
\u4e3a\u5f53\u524d\u623f\u95f4\u540d, 12
\u4e3a\u5f53\u524d\u7ae0\u8282 ID, \u901a\u5e38\u5bf9\u4e8e B \u9762\u5b83\u8fd8\u4f1a\u4ee5 H
\u7ed3\u5c3e, C \u9762\u4ee5 HH
\u7ed3\u5c3e. screen
\u8868\u793a\u76ee\u524d\u5149\u6807\u6240\u5728\u7684\u5c4f\u5e55\u5750\u6807, (0, 0)
\u8868\u793a\u5c4f\u5e55\u5de6\u4e0a\u89d2. level
\u8868\u793a\u76ee\u524d\u5149\u6807\u6240\u5728\u7684\u4e16\u754c\u5750\u6807, \u4e5f\u5c31\u662f walkTo
\u7b49\u51fd\u6570\u8981\u6c42\u6211\u4eec\u4f20\u5165\u7684\u7edd\u5bf9\u5750\u6807. level, /8
\u8868\u793a\u5149\u6807\u6240\u5728\u7684\u4e16\u754c\u5750\u6807\u9664\u4ee5 8 \u53d6\u6574\u7684\u7ed3\u679c, \u8fd9\u901a\u5e38\u7528\u4e8e\u5b9a\u4f4d\u4ee5 8px \u4e3a\u5355\u4f4d\u7684 tile. level, snap
\u7684\u503c\u4e3a level, /8
\u7684\u503c\u4e58\u4ee5 8, \u5728\u6570\u503c\u4e0a\u8868\u73b0\u4e3a\u5149\u6807\u6240\u5728\u4e16\u754c\u5750\u6807\u4e0e 8x8 \u7f51\u683c\u8fdb\u884c\u5bf9\u9f50\u7684\u7ed3\u679c.
\u5728\u88c5\u4e86 CelesteTAS
mod \u7684\u60c5\u51b5\u4e0b, \u4f60\u8fd8\u53ef\u4ee5\u5de6\u51fb\u5730\u56fe\u4e0a\u7684\u5b9e\u4f53\u6765\u83b7\u53d6\u66f4\u591a\u4fe1\u606f:
Area: 04 @ 12 (SID: Celeste/Saplonily/Test)\nCursor @\n screen: 792, 407\n entity type: Celeste.Glider\n entity name: glider\n entity id : 04:14\n mod name : Celeste\n world: -618, 213\n level: 1142, 397\n level, /8: 142, 49\n level, snap: 1136, 392\n
\u5176\u4e2d entity type
\u4e3a\u5de6\u51fb\u5230\u7684\u5b9e\u4f53\u7684\u5b9e\u4f53\u7c7b\u540d, \u4e5f\u5373\u4ee3\u7801\u7c7b\u540d. entity name
\u4e3a\u5b9e\u4f53\u7684\u540d\u79f0, \u4e5f\u662f\u5728\u5730\u56fe\u6587\u4ef6\u4e2d\u5b9e\u9645\u4fdd\u5b58\u7684\u540d\u5b57, \u901a\u5e38\u5728\u4e0e\u4ee3\u7801\u7c7b\u540d\u76f8\u4f3c\u7684\u4f7f\u7528\u573a\u666f\u4e2d\u4f1a\u7528\u5230. entity id
\u4e3a\u5b9e\u4f53\u7684 ID, \u901a\u5e38\u7528\u4e8e\u67d0\u4e9b\u9700\u8981\u4f20\u5165\u5b9e\u4f53 ID \u53c2\u6570\u7684 helper \u5b9e\u4f53. mod name
\u4e3a\u8be5\u5b9e\u4f53\u6240\u5c5e mod \u540d, \u5bf9\u4e8e\u539f\u7248\u5b9e\u4f53\u4e3a Celeste
.
\u4ee5\u9632\u4f60\u8fd8\u4e0d\u77e5\u9053, \u6e38\u620f\u7684\u5750\u6807\u7cfb\u4e0e\u5e38\u89c4\u7684\u6570\u5b66\u5750\u6807\u7cfb\u4e0d\u540c, \u5176 y \u5750\u6807\u7ecf\u8fc7\u4e86\u7ad6\u76f4\u7ffb\u8f6c:
"},{"location":"extra_luacs/examples/#_3","title":"\u7247\u6bb5","text":""},{"location":"extra_luacs/examples/#_4","title":"\u64ad\u653e\u73a9\u5bb6\u52a8\u753b","text":"function playSprite(sprite, duration)\n player.Sprite:Play(sprite, false, false)\n if duration then\n wait(duration)\n end\nend\n
\u4e0a\u8ff0\u4ee3\u7801\u5c01\u88c5\u4e86\u4e00\u4e2a\u51fd\u6570, \u4f7f\u5f97\u4f60\u53ef\u4ee5\u5411\u73a9\u5bb6\u64ad\u653e\u4e00\u4e2a\u52a8\u753b\u5e76\u7b49\u5f85\u51e0\u79d2, \u4f8b\u5982\u8ba9\u73a9\u5bb6\u64ad\u653e swimIdle
, \u4e5f\u5c31\u662f\u5728\u6c34\u4e2d\u65f6\u64ad\u653e\u7684\u52a8\u753b:
player.DummyAutoAnimate = false\nplaySprite(\"swimIdle\", 1)\nplayer.DummyAutoAnimate = true\n
\u5728\u73a9\u5bb6\u88ab\u7981\u6b62\u79fb\u52a8\u540e\u6e38\u620f\u4f9d\u7136\u4f1a\u5904\u7406\u73a9\u5bb6\u7684\u52a8\u753b, \u6240\u4ee5\u6211\u4eec\u7684 swimIdle
\u52a8\u753b\u4f1a\u7acb\u523b\u88ab\u66ff\u6362\u4e3a\u9ed8\u8ba4\u52a8\u753b, \u8fd9\u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e DummyAutoAnimate
\u4e3a false
\u6765\u7981\u6b62\u8fd9\u4e00\u884c\u4e3a.
\u6b64\u5916\u8fd8\u53ef\u4ee5\u6709\u53cd\u5411\u64ad\u653e\u52a8\u753b:
function playSpriteReversed(sprite, duration, from)\n player.Sprite:Reverse(sprite, false)\n -- from \u8fd8\u8981\u518d +1, \u907f\u514d\u6e38\u620f\u8df3\u8fc7\u6700\u540e\u4e00\u5e27\u800c\u4ece\u5012\u6570\u7b2c\u4e8c\u5e27\u5f00\u59cb\n player.Sprite:SetAnimationFrame(from + 1)\n if duration then\n wait(duration)\n end\nend\n
\u851a\u84dd\u7684\u5f15\u64ce Monocle
\u7684 Sprite
\u6709\u4e2a\u53cd\u5411\u64ad\u653e\u7684\u65b9\u6cd5, \u4f46\u662f\u5b83\u53ea\u4f1a\u4fee\u6539\u65b9\u5411\u4e3a\u53cd\u65b9\u5411, \u4e0d\u4f1a\u8df3\u5230\u6700\u540e\u4e00\u5e27\u5f00\u59cb, \u6240\u4ee5\u8fd9\u91cc\u4f60\u53ef\u80fd\u9700\u8981\u624b\u52a8\u67e5\u8be2\u4f60\u60f3\u8981\u53cd\u5411\u64ad\u653e\u7684\u52a8\u753b\u7684\u6700\u540e\u4e00\u5e27\u7684\u4f4d\u7f6e.
\u4f8b\u5982\u8ba9\u73a9\u5bb6\u62ac\u5934, \u7ed3\u675f\u540e\u7b49\u5f85 0.5 \u79d2\u7136\u540e\u518d\u4f4e\u5934\u7136\u540e\u7ed3\u675f\u5267\u60c5:
function onBegin()\n disableMovement()\n local level = player.Scene;\n player.DummyAutoAnimate = false\n playSprite(\"lookUp\", 0.5)\n wait(0.5)\n -- <Anim id=\"lookUp\" path=\"lookUp\" delay=\"0.1\" frames=\"2-7\"/>, \u6700\u540e\u4e00\u5e27\u662f 7\n playSpriteReversed(\"lookUp\", 0.5, 7)\n player.DummyAutoAnimate = true\nend\n
\u6b64\u5916\u4f60\u8fd8\u4f1a\u53d1\u73b0\u6b64\u65f6\u4f9d\u7136\u6709\u91cd\u529b, \u4f46\u662f\u4f60\u4f9d\u7136\u60f3\u8ba9\u73a9\u5bb6\u5728\u7a7a\u4e2d\u6e38\u52a8(\u9646\u6e38), \u4f60\u53ef\u4ee5\u8fd9\u6837\u7981\u7528\u91cd\u529b:
function onBegin()\n disableMovement()\n local level = player.Scene;\n player.DummyAutoAnimate = false\n player.DummyGravity = false\n playSprite(\"swimIdle\", 0.5)\n player.DummyGravity = true\n player.DummyAutoAnimate = true\nend\n
\u4e0a\u8ff0\u4f8b\u5b50\u7684\u5b8c\u6574 lua \u6587\u4ef6:
testCutscene.luafunction playSprite(sprite, duration)\n player.Sprite:Play(sprite, false, false)\n if duration then\n wait(duration)\n end\nend\n\nfunction playSpriteReversed(sprite, duration, from)\n player.Sprite:Reverse(sprite, false)\n player.Sprite:SetAnimationFrame(from + 1)\n if duration then\n wait(duration)\n end\nend\n\nfunction onBegin()\n disableMovement()\n local level = player.Scene;\n waitUntilOnGround()\n wait(1)\n player.DummyAutoAnimate = false\n player.DummyGravity = false\n playSprite(\"swimIdle\", 0.5)\n player.DummyGravity = true\n player.DummyAutoAnimate = true\nend\n\nfunction onEnd()\n enableMovement()\nend\n
"},{"location":"extra_luacs/reference/","title":"\u53c2\u8003","text":""},{"location":"extra_luacs/reference/#luacutscene","title":"LuaCutscene \u51fd\u6570","text":"\u5728\u524d\u9762\u7684\u5c0f\u8282\u4e2d\u6211\u4eec\u5df2\u7ecf\u63d0\u5230\u8fc7 LuaCutscene \u63d0\u4f9b\u4e86\u5927\u91cf\u7684\u51fd\u6570, \u90a3\u4e48\u8fd9\u91cc\u6211\u4eec\u5c06\u4ecb\u7ecd\u5176\u4e2d\u5e38\u7528\u7684\u4e00\u90e8\u5206(\u4e4b\u524d\u5df2\u4ecb\u7ecd\u8fc7\u7684\u5c06\u4e0d\u518d\u63d0\u53ca).
"},{"location":"extra_luacs/reference/#wait","title":"wait","text":"wait(duration)
\u534f\u7a0b\u51fd\u6570, \u6682\u505c\u51fd\u6570\u6267\u884c\u51e0\u79d2
duration: \u8981\u6682\u505c\u7684\u65f6\u95f4(\u79d2) "},{"location":"extra_luacs/reference/#walkto","title":"walkTo","text":"walkTo(x, walkBackwards=false, speedMultiplier=1.0, keepWalkingIntoWalls=false)
\u534f\u7a0b\u51fd\u6570, \u8ba9\u73a9\u5bb6\u884c\u8d70\u5230\u5750\u6807 x
x: \u76ee\u6807 x \u7edd\u5bf9\u5750\u6807, \u5355\u4f4d px walkBackwards: \u662f\u5426\u64ad\u653e\u4e3a\u5012\u8d70\u52a8\u753b speedMultiplier: \u901f\u5ea6\u500d\u7387 keepWalkingIntoWalls: \u649e\u5899\u65f6\u662f\u5426\u4fdd\u6301\u72b6\u6001\u76f4\u5230\u5899\u88ab\u79fb\u9664 \u5982\u679c\u5728\u884c\u8d70\u8fc7\u7a0b\u4e2d\u78b0\u5230\u5899\u90a3\u4e48\u8be5\u51fd\u6570\u4f1a\u7acb\u5373\u7ed3\u675f\u6267\u884c, \u9664\u975e keepWalkingIntoWalls
\u88ab\u8bbe\u7f6e\u4e3a true
, \u5982\u679c\u4e0d\u5e78\u5730\u78b0\u5230\u4e86\u4e0d\u53ef\u80fd\u4f1a\u88ab\u79fb\u9664\u7684\u5899, \u4f8b\u5982\u524d\u666f\u7816, \u90a3\u4e48\u5267\u60c5\u5c31\u4f1a\u6c38\u4e45\u5361\u4f4f.
"},{"location":"extra_luacs/reference/#walk","title":"walk","text":"walkTo(x, walkBackwards=false, speedMultiplier=1.0, keepWalkingIntoWalls=false)
\u4e0e walkTo
\u76f8\u540c, \u4f46 x \u4e3a\u76f8\u5bf9\u503c, \u4f8b\u5982 100
\u4f1a\u4f7f\u5f97\u73a9\u5bb6\u5411\u53f3\u884c\u8d70 100 px
"},{"location":"extra_luacs/reference/#runto","title":"runTo","text":"runTo(x, fastAnimation=false)
\u534f\u7a0b\u51fd\u6570, \u8ba9\u73a9\u5bb6\u8dd1\u5230\u5750\u6807 x
x: \u76ee\u6807 x \u7edd\u5bf9\u5750\u6807, \u5355\u4f4d px fastAnimation: \u662f\u5426\u4f7f\u7528\u5feb\u8dd1\u7684\u52a8\u753b \u4e0e walkTo
\u7c7b\u4f3c, \u4f46\u662f\u52a8\u753b\u53d8\u4e3a\u8dd1\u6b65. \u6ce8\u610f\u6b64\u51fd\u6570\u6ca1\u6709\u540c\u7b49\u7684 keepWalkingIntoWalls
\u53c2\u6570, \u5176\u7b49\u6548\u4e8e\u4e3a true
\u7684\u60c5\u51b5, \u4e5f\u5c31\u662f\u649e\u5899\u540e\u4e0d\u4f1a\u7ed3\u675f\u8be5\u51fd\u6570\u7684\u6267\u884c.
"},{"location":"extra_luacs/reference/#run","title":"run","text":"run(x, fastAnimation=false)
\u4e0e runTo
\u76f8\u540c, \u4f46 x \u4e3a\u76f8\u5bf9\u503c.
"},{"location":"extra_luacs/reference/#postcard","title":"postcard","text":"postcard(dialog, sfxIn, sfxOut=nil)
\u534f\u7a0b\u51fd\u6570, \u5411\u73a9\u5bb6\u663e\u793a\u660e\u4fe1\u7247
dialog: \u660e\u4fe1\u7247\u6240\u4f7f\u7528\u7684 dialog id, \u4e0e say
\u7684\u662f\u540c\u4e00\u79cd id sfxIn: \u5c55\u793a\u660e\u4fe1\u7247\u65f6\u64ad\u653e\u7684\u97f3\u9891 event id. sfxOut: \u660e\u4fe1\u7247\u79fb\u5f00\u65f6\u64ad\u653e\u7684\u97f3\u9891 event id. \u5bf9\u4e8e\u97f3\u9891\u76f8\u5173\u7684\u5185\u5bb9, \u4f8b\u5982\u83b7\u53d6 event id, \u53ef\u53c2\u8003\u7535\u7bb1\u5236\u56fe\u6559\u7a0b\u4e2d\u7684:
av986769059 - \u81ea\u5b9a\u4e49\u97f3\u4e50(\u57fa\u7840\u7bc7) av604397615 - \u81ea\u5b9a\u4e49\u97f3\u4e50(\u8fdb\u9636\u7bc7) av517096099 - \u81ea\u5b9a\u4e49\u97f3\u4e50(\u62d3\u5c55\u7bc7) \u5728\u660e\u4fe1\u7247\u51fa\u73b0\u65f6\u5c1d\u8bd5\u6682\u505c\u5e76\u8df3\u8fc7\u5267\u60c5\u4f1a\u4f7f\u5173\u5361\u5904\u4e8e\u4e00\u79cd\u5f88\u5947\u602a\u7684\u72b6\u6001, \u4f60\u53ef\u4ee5\u9009\u62e9\u7981\u7528\u5173\u5361\u7684\u6682\u505c\u6765\u907f\u514d\u5b83.
\u622a\u6b62 0.2.11
, postcard
\u51fd\u6570\u5b58\u5728\u7f16\u7801\u95ee\u9898, \u4e2a\u4eba\u5df2\u5f00 pr \u4fee\u590d
"},{"location":"extra_luacs/reference/#choice","title":"choice","text":"choice(...)
\u534f\u7a0b\u51fd\u6570, \u5411\u73a9\u5bb6\u5c55\u793a\u51e0\u4e2a\u5bf9\u8bdd\u9009\u9879(\u7c7b\u4f3c 6a \u5f00\u5934\u90a3\u79cd), \u8fd4\u56de\u73a9\u5bb6\u9009\u62e9\u7684\u5bf9\u8bdd\u5e8f\u53f7(\u6ce8\u610f\u4ece 1 \u5f00\u59cb).
\u8fd9\u662f\u4e00\u4e2a\u53ef\u53d8\u53c2\u6570\u7684\u51fd\u6570, \u4f8b\u5982\u4ee5\u4e0b\u4f7f\u7528:
local chosen = choice(\"CHOICE_1\", \"CHOICE_2\", \"CHOICE_3\");\nsay(\"CHOICE_SAY_\" .. tostring(chosen));\n
\u4f1a\u5411\u73a9\u5bb6\u5c55\u793a\u4e09\u4e2a\u9009\u9879, \u5e76\u4e14\u5728\u73a9\u5bb6\u9009\u62e9\u5b8c\u540e\u5c55\u793a\u5bf9\u5e94\u5e8f\u53f7\u5bf9\u5e94\u7684\u5bf9\u8bdd:
CHOICE_1
-> CHOICE_SAY_1
CHOICE_2
-> CHOICE_SAY_2
CHOICE_3
-> CHOICE_SAY_3
"},{"location":"extra_luacs/reference/#die","title":"die","text":"die(direction={0, 0}, evenIfInvincible=false, registerDeathInStats=true)
\u975e\u534f\u7a0b\u51fd\u6570, \u6740\u6b7b\u73a9\u5bb6
direction: \u6b7b\u4ea1\u65b9\u5411, \u4f8b\u5982 {1, 0}
\u8868\u793a\u6c34\u5e73\u5411\u53f3, {-1, -1}
\u8868\u793a\u5de6\u4e0a\u65b9 evenIfInvincible: \u662f\u5426\u5728\u73a9\u5bb6\u662f\u65e0\u654c\u65f6\u4e5f\u6740\u6b7b registerDeathInStats: \u662f\u5426\u8bb0\u5f55\u672c\u6b21\u6b7b\u4ea1, \u5426\u5219\u672c\u6b21\u6b7b\u4ea1\u4e0d\u4f1a\u589e\u52a0\u5b58\u6863\u6b7b\u4ea1\u6570 \u5c31\u5982\u6b64\u51fd\u6570\u6240\u505a\u7684, \u76f4\u63a5\u6740\u6b7b\u73a9\u5bb6, \u4e0d\u8fc7\u6b64\u51fd\u6570\u8c03\u7528\u540e\u4f9d\u7136\u4f1a\u6267\u884c\u540e\u9762\u7684\u4ee3\u7801, \u867d\u7136\u540c\u65f6\u540e\u9762\u7684\u4ee3\u7801\u4f1a\u88ab\u73a9\u5bb6\u6b7b\u4ea1\u540e\u7684\u81ea\u52a8\u91cd\u5f00\u76f4\u63a5\u6253\u65ad.
"},{"location":"extra_luacs/reference/#jump","title":"jump","text":"jump(duration=2.0)
\u975e\u534f\u7a0b\u51fd\u6570, \u4f7f\u73a9\u5bb6\u8df3\u8dc3
duration: \u8df3\u8dc3\u65f6\u957f, \u7b49\u4ef7\u4e8e\u4f60\u6309\u8df3\u952e\u7684\u65f6\u957f \u6709\u8da3\u7684\u662f, \u6b64\u51fd\u6570\u5373\u4f7f\u73a9\u5bb6\u5728\u7a7a\u4e2d\u4e5f\u4f1a\u8d77\u6548, \u4e0d\u8fc7\u6b64\u51fd\u6570\u5bfc\u81f4\u7684\u8df3\u4e0d\u4f1a\u89e6\u53d1 super \u4e0e hyper \u7b49\u673a\u5236.
"},{"location":"extra_luacs/reference/#waituntilonground","title":"waitUntilOnGround","text":"waitUntilOnGround()
\u534f\u7a0b\u51fd\u6570, \u7b49\u5f85\u73a9\u5bb6\u89e6\u78b0\u5230\u5730\u677f
"},{"location":"extra_luacs/reference/#changeroom","title":"changeRoom","text":"changeRoom(name)
changeRoom(name, spawnX, spawnY)
\u975e\u534f\u7a0b\u51fd\u6570 ,\u66f4\u6539\u73a9\u5bb6\u6240\u5728\u9762
name: \u76ee\u6807\u9762\u540d\u79f0 spawnX: \u65b0\u91cd\u751f\u70b9 x \u5750\u6807 spawnY: \u65b0\u91cd\u751f\u70b9 y \u5750\u6807 \u5982\u679c\u4e0d\u4f20\u5165\u65b0\u91cd\u751f\u70b9\u5750\u6807\u5219\u9ed8\u8ba4\u4e3a\u623f\u95f4\u5de6\u4e0b\u89d2. \u4e0d\u8fc7\u7ecf\u4e2a\u4eba\u6d4b\u8bd5\u8fd9\u4e2a\u91cd\u751f\u70b9\u7684\u8bbe\u7f6e\u4f1a\u9a6c\u4e0a\u5c31\u88ab\u65b0\u9762\u7684\u8fdb\u5165\u800c\u8986\u76d6, \u4e0d\u8fc7\u6709\u8da3\u7684\u662f, \u6b64\u51fd\u6570\u5141\u8bb8\u4f20\u5165\u4e00\u4e2a filler \u9762, \u6b64\u65f6\u91cd\u751f\u70b9\u5c31\u4e0d\u4f1a\u88ab\u8986\u76d6\u4e86.
"},{"location":"extra_luacs/reference/#teleportto","title":"teleportTo","text":"teleportTo(x, y)
\u975e\u534f\u7a0b\u51fd\u6570, \u4f20\u9001\u73a9\u5bb6\u5230\u76ee\u6807\u4f4d\u7f6e
x: \u76ee\u6807 x \u5750\u6807 y: \u76ee\u6807 y \u5750\u6807 \u6b64\u5916\u8fd9\u4e2a\u51fd\u6570\u8fd8\u6709\u53e6\u5916\u4e24\u4e2a\u91cd\u8f7d, \u4e0d\u8fc7\u6211\u4e2a\u4eba\u8fd8\u6ca1\u5f04\u61c2\u5b83\u7684\u7528\u6cd5, \u6545\u8fd9\u91cc\u5c31\u4e0d\u5199\u4e86.
"},{"location":"extra_luacs/reference/#teleport","title":"teleport","text":"\u4e0e teleportTo
\u76f8\u540c, \u4f46\u662f\u5750\u6807\u662f\u76f8\u5bf9\u5750\u6807
"},{"location":"extra_luacs/reference/#instantteleportto","title":"instantTeleportTo","text":"instantTeleportTo(x, y)
\u975e\u534f\u7a0b\u51fd\u6570, \u7acb\u5373\u4f20\u9001\u73a9\u5bb6\u5230\u76ee\u6807\u4f4d\u7f6e
x: \u76ee\u6807 x \u5750\u6807 y: \u76ee\u6807 y \u5750\u6807 \u6b64\u51fd\u6570\u4e0e teleportTo
\u7c7b\u4f3c, \u4f46\u662f\u5b83\u4f1a\u5728\u4f20\u9001\u7684\u540c\u65f6\u7acb\u5373\u8c03\u6574\u89c6\u91ce, \u4e5f\u5c31\u662f\u6444\u50cf\u673a\u7684\u4f4d\u7f6e. \u6b64\u5916\u8fd9\u4e2a\u51fd\u6570\u4e5f\u6709\u53e6\u5916\u4e00\u4e2a\u6709\u5173\u9762\u7684\u91cd\u8f7d((x, y, room)
), \u4f46\u662f\u4f20\u5165\u5176\u4ed6\u9762\u540e\u73a9\u5bb6\u4f1a\u8fdb\u5165\u4e00\u79cd\u5947\u602a\u7684\u5267\u60c5\u72b6\u6001.
"},{"location":"extra_luacs/reference/#instantteleport","title":"instantTeleport","text":"\u4e0e instantTeleportTo
\u76f8\u540c, \u4f46\u662f\u5750\u6807\u662f\u76f8\u5bf9\u5750\u6807
"},{"location":"extra_luacs/reference/#completearea","title":"completeArea","text":"completeArea(spotlightWipe=false, skipScreenWipe=false, skipCompleteScreen=false)
\u975e\u534f\u7a0b\u51fd\u6570, \u7ed3\u675f\u5f53\u524d\u7ae0\u8282, \u6b64\u51fd\u6570\u8c03\u7528\u540e\u4f1a\u91cd\u65b0\u5141\u8bb8\u73a9\u5bb6\u79fb\u52a8.
spotlightWipe
: true
\u65f6\u4e3a\u805a\u5149\u706f\u578b\u5207\u6362\u5230\u9ed1\u5c4f, false
\u4e3a\u6e10\u53d8\u578b. skipScreenWipe
: \u662f\u5426\u8df3\u8fc7\u5207\u6362\u5230\u9ed1\u5c4f\u7684\u8fc7\u7a0b skipCompleteScreen
: \u662f\u5426\u8df3\u8fc7\u7ed3\u7b97\u5c4f "},{"location":"extra_luacs/reference/#givekey","title":"giveKey","text":"giveKey()
\u975e\u534f\u7a0b\u51fd\u6570, \u7ed9\u4e88\u73a9\u5bb6\u4e00\u628a\u94a5\u5319.
"},{"location":"extra_luacs/reference/#makeunskippable","title":"makeUnskippable","text":"makeUnskippable()
\u975e\u534f\u7a0b\u51fd\u6570, \u4f7f\u5f53\u524d\u5267\u60c5\u65e0\u6cd5\u8df3\u8fc7
\u6709\u4e9b\u65f6\u5019\u4f60\u7684\u5267\u60c5\u8fc7\u4e8e\u590d\u6742, \u4ee5\u81f3\u4e8e\u4f60\u65e0\u6cd5\u826f\u597d\u5730\u9884\u6d4b\u76f4\u63a5\u8df3\u8fc7\u5267\u60c5\u5e94\u8be5\u505a\u4ec0\u4e48, \u6bd4\u5982\u73a9\u5bb6\u5230\u5e95\u79fb\u52a8\u5230\u54ea\u4e86, \u90a3\u4e48\u4f7f\u5b83\u65e0\u6cd5\u8df3\u8fc7\u53ef\u80fd\u662f\u4e2a\u4e0d\u9519\u7684\u9009\u62e9.
"},{"location":"extra_luacs/reference/#disableretry-enableretry","title":"disableRetry / enableRetry","text":"enableRetry()
disableRetry()
\u975e\u534f\u7a0b\u51fd\u6570, \u7981\u7528 / \u542f\u7528 \u91cd\u8bd5\u529f\u80fd.
\u6ce8\u610f\u6b64\u51fd\u6570\u7684\u6548\u679c\u5728\u5267\u60c5\u7ed3\u675f\u540e\u4e0d\u4f1a\u6062\u590d, \u5efa\u8bae\u624b\u52a8\u5728 onEnd()
\u5904\u91cd\u65b0\u542f\u7528.
"},{"location":"extra_luacs/reference/#disablepause-enablepause","title":"disablePause / enablePause","text":"helpers.disablePause()
helpers.enablePause()
\u975e\u534f\u7a0b\u51fd\u6570, \u7981\u7528 / \u542f\u7528 \u6682\u505c\u529f\u80fd.
\u6ce8\u610f\u6b64\u51fd\u6570\u7684\u6548\u679c\u5728\u5267\u60c5\u7ed3\u675f\u540e\u4e0d\u4f1a\u6062\u590d, \u5efa\u8bae\u624b\u52a8\u5728 onEnd()
\u5904\u91cd\u65b0\u542f\u7528.
"},{"location":"extra_luacs/reference/#endcutscene","title":"endCutscene","text":"endCutscene()
\u975e\u534f\u7a0b\u51fd\u6570, \u7ed3\u675f\u5f53\u524d\u5267\u60c5.
\u6ce8\u610f\u8be5\u51fd\u6570\u8c03\u7528\u540e\u540e\u9762\u7684\u4ee3\u7801\u4f9d\u7136\u4f1a\u6267\u884c, \u76f4\u5230\u9047\u5230\u4e00\u4e2a\u534f\u7a0b\u51fd\u6570, \u6216\u8005\u51fd\u6570\u88ab\u8fd4\u56de\u6216\u5230\u8fbe\u672b\u5c3e.
"},{"location":"other/xml-speedrun/","title":"XML \u7b80\u5355\u4ecb\u7ecd","text":"\u8fd9\u91cc\u4e3a\u4e86\u65b9\u4fbf\u67d0\u4e9b\u6ca1\u542c\u8bf4\u8fc7 XML \u7684\u4eba\u5feb\u901f\u4e86\u89e3 XML \u7684\u5927\u81f4\u8bed\u6cd5\u662f\u4ec0\u4e48, \u6240\u4ee5\u5f88\u591a\u7ec6\u8282\u65b9\u9762\u7684\u95ee\u9898\u6211\u4f1a\u76f4\u63a5\u5ffd\u7565, \u90a3\u4e48, \u5c31\u6b64\u5f00\u59cb\u5427:
"},{"location":"other/xml-speedrun/#_1","title":"\u5b9a\u4e49","text":"\u8fd9\u91cc\u6458\u6284\u4e00\u4e0b:
XML \u6307\u53ef\u6269\u5c55\u6807\u8bb0\u8bed\u8a00(eXtensible Markup Language). XML \u88ab\u8bbe\u8ba1\u7528\u6765\u4f20\u8f93\u548c\u5b58\u50a8\u6570\u636e, \u4e0d\u7528\u4e8e\u8868\u73b0\u548c\u5c55\u793a\u6570\u636e, HTML \u5219\u7528\u6765\u8868\u73b0\u6570\u636e.
XML \u662f\u4e00\u79cd\u4ee5\u683c\u5f0f\u5316\u50a8\u5b58\u6570\u636e\u7684\u8bed\u8a00, \u5728 msbuild
\u4e2d\u5b83\u5c31\u88ab\u7528\u6765\u4ee5\u683c\u5f0f\u5316\u7684\u65b9\u5f0f\u63cf\u8ff0\u6574\u4e2a\u9879\u76ee\u7684\u4fe1\u606f.
"},{"location":"other/xml-speedrun/#_2","title":"\u8282\u70b9, \u7279\u6027","text":"\u4e00\u6bb5\u5f88\u57fa\u7840\u7684 XML \u53ef\u80fd\u662f\u8fd9\u4e2a\u6837\u5b50\u7684:
<books>\n <book id=\"123\">\u8fd9\u662f\u7b2c\u4e00\u672c\u4e66</book>\n <book id=\"456\">\u8fd9\u662f\u7b2c\u4e8c\u672c\u4e66</book>\n <book id=\"114\">\u8fd9\u662f\u7b2c\u4e09\u672c\u4e66</book>\n <book id=\"514\">\u8fd9\u662f\u4e0d\u77e5\u9053\u7b2c\u51e0\u672c\u4e66</book>\n</books>\n
\u8fd9\u6bb5 XML \u7528\u4e2d\u6587\u89e3\u91ca\u8d77\u6765\u662f\u8fd9\u6837\u7684:
\u9996\u5148\u6211\u4eec\u5b9a\u4e49\u4e86\u4e00\u4e2a\u8282\u70b9, \u5b83\u7684\u540d\u5b57\u53eb\u505a \"books\", \u5b83\u6709\u5f88\u591a\u5b50\u8282\u70b9, \u5206\u522b\u662f:
\u4e00\u4e2a \"book\" \u8282\u70b9, \u5b83\u7684 id \u7279\u6027\u662f 123, \u5b83\u7684\u5185\u5bb9\u662f \"\u8fd9\u662f\u7b2c\u4e00\u672c\u4e66\" \u4e00\u4e2a \"book\" \u8282\u70b9, \u5b83\u7684 id \u7279\u6027\u662f 456, \u5b83\u7684\u5185\u5bb9\u662f \"\u8fd9\u662f\u7b2c\u4e8c\u672c\u4e66\" \u4e00\u4e2a \"book\" \u8282\u70b9, \u5b83\u7684 id \u7279\u6027\u662f 114, \u5b83\u7684\u5185\u5bb9\u662f \"\u8fd9\u662f\u7b2c\u4e09\u672c\u4e66\" \u4e00\u4e2a \"book\" \u8282\u70b9, \u5b83\u7684 id \u7279\u6027\u662f 514, \u5b83\u7684\u5185\u5bb9\u662f \"\u8fd9\u662f\u4e0d\u77e5\u9053\u7b2c\u51e0\u672c\u4e66\" \u5728\u8fd9\u91cc, \u6700\u5916\u5c42\u7684 \"books\" \u4ee5\u53ca\u91cc\u9762\u7684 \"book\" \u90fd\u79f0\u4e3a\u8282\u70b9, \u5176\u4e2d \"books\" \u8282\u70b9\u5185\u90e8\u6709\u5f88\u591a \"book\" \u8282\u70b9, \u800c \"book\" \u8282\u70b9\u5185\u90e8\u53ea\u6709\u4e00\u4e32\u6587\u672c. \u6bcf\u4e2a \"book\" \u8282\u70b9\u90fd\u6709\u4e00\u4e2a\u53eb\u505a id \u7684\u7279\u6027(\u6709\u65f6\u4e5f\u53eb\u505a\u5c5e\u6027, \u4e0d\u8fc7\u6ce8\u610f\u522b\u4e0e C# \u7684\u5c5e\u6027/\u7279\u6027\u76f8\u6df7\u6dc6).
\u5728\u8bed\u6cd5\u5c42\u9762\u4e0a, \u4e00\u4e2a\u8282\u70b9\u4ee5 <\u540d\u5b57> \u5f00\u59cb\u58f0\u660e, \u5728\u53d9\u8ff0\u5b8c\u5b83\u7684\u5185\u5bb9\u540e\u4ee5 </\u540d\u5b57> \u7ed3\u675f. \u5c5e\u6027\u5219\u5728\u8282\u70b9\u540d\u79f0\u4e4b\u540e\u4ee5\u7a7a\u683c\u5206\u9694\u6392\u5217: <\u540d\u5b57 \u5c5e\u60271=\"\u503c1\" \u5c5e\u60272=\"\u503c2\">, \u5c5e\u6027\u7684\u503c\u9700\u8981\u7531 \"
\u5305\u88f9. \u5bf9\u4e8e\u4e00\u4e9b\u6ca1\u6709\u5185\u90e8\u5185\u5bb9\u7684\u8282\u70b9, \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u81ea\u7ed3\u675f\u8bed\u6cd5:
<columns>\n <column id=\"xxx\"/>\n <column qwq=\"6\" awa=\"4\"/>\n <column/>\n <column/>\n <column/>\n</columns>\n
XML \u5141\u8bb8\u4ee5\u4efb\u610f\u6df1\u5ea6\u6765\u5d4c\u5957, \u6240\u4ee5\u6211\u4eec\u53ef\u4ee5\u8fd9\u6837\u6765\u7ec4\u88c5\u4e00\u4e2a\u5f88\u590d\u6742\u7684 XML:
<books>\n <book id=\"123\">\n <bookmarks page=\"1\">114514</bookmarks>\n <bookmarks page=\"2\">2333</bookmarks>\n <bookmarks page=\"123\">838</bookmarks>\n </book>\n <book id=\"456\">\n <bookmarks page=\"1\">\n <picture src=\"http://example.com\">\n this is alt\n </picture>\n <text content=\"text here!\"/>\n </bookmarks>\n <bookmarks page=\"2\">2333</bookmarks>\n </book>\n</books>\n
"},{"location":"trans/adv_hooks/","title":"IL \u94a9\u5b50\u4e0e\u968f\u610f\u94a9\u53d6","text":""},{"location":"trans/adv_hooks/#il_1","title":"IL \u94a9\u5b50","text":""},{"location":"trans/adv_hooks/#il_2","title":"\u63d2\u5165 IL","text":"\u73b0\u5728, \u4f60\u5df2\u7ecf\u4e86\u89e3\u4e86\u57fa\u672c\u7684 IL \u77e5\u8bc6, \u7a0d\u5fae\u4f1a\u4f7f\u7528 System.Reflection.Emit
\u5e93\u4e86, \u90a3\u4e48\u6211\u4eec\u5c31\u53ef\u4ee5\u5f00\u59cb\u4f7f\u7528 IL \u94a9\u5b50\u4e86. IL \u94a9\u5b50\u5141\u8bb8\u4f60\u4fee\u6539\u851a\u84dd\u7684\u4ee3\u7801, \u8fd9\u662f\u4e00\u4e2a\u5f88\u5f3a\u5927\u7684\u529f\u80fd, \u90a3\u4e48\u81ea\u7136\u800c\u7136, \u5b83\u7684\u4f7f\u7528\u4e5f\u4f1a\u53d8\u5f97\u66f4\u52a0\u590d\u6742.
IL \u94a9\u5b50\u4e0e On \u94a9\u5b50\u7684\u4e8b\u4ef6\u8ba2\u9605\u65b9\u5f0f\u5f88\u76f8\u50cf, \u53ea\u4e0d\u8fc7\u662f\u6362\u6210\u4e86 IL \u547d\u540d\u7a7a\u95f4, \u4e0d\u8fc7\u8981\u6ce8\u610f\u7684\u662f, \u65b9\u6cd5\u7684\u53c2\u6570\u4e0d\u518d\u662f\u539f\u51fd\u6570\u59d4\u6258\u52a0\u4e0a\u5176\u5bf9\u5e94\u53c2\u6570\u4e86, \u800c\u662f\u4e00\u4e2a ILContext
\u7c7b\u578b\u7684\u503c, \u540c\u65f6, \u65b9\u6cd5\u4e5f\u4e0d\u662f\u6bcf\u6b21\u8c03\u7528\u88ab\u94a9\u65b9\u6cd5\u65f6\u8c03\u7528, \u800c\u662f\u4ec5\u5728\u6e38\u620f\u542f\u52a8\u65f6\u8c03\u7528. \u4f8b\u5982, \u94a9\u53d6\u73a9\u5bb6\u7684 SuperWallJump
\u65b9\u6cd5(\u5728\u73a9\u5bb6\u505a\u51fa\u4e86\u4e00\u4e2a\u8e6d\u5899\u65f6\u8c03\u7528):
public override void Load()\n{\n IL.Celeste.Player.SuperWallJump += Player_SuperWallJump;\n}\n\nprivate void Player_SuperWallJump(ILContext il)\n{\n\n}\n\npublic override void Unload()\n{\n IL.Celeste.Player.SuperWallJump -= Player_SuperWallJump;\n}\n
\u73b0\u5728, \u6211\u4eec\u83b7\u53d6\u5230\u4e86\u4e00\u4e2a ILContext
, \u5b83\u8868\u793a\u8fd9\u4e2a\u65b9\u6cd5\u7684 IL
\u4e0a\u4e0b\u6587, \u4e0d\u8fc7\u5728\u8fd9\u91cc\u4f60\u4e0d\u9700\u8981\u77e5\u9053\u8fd9\u662f\u4ec0\u4e48, \u6211\u4eec\u901a\u5e38\u8981\u7684\u53ea\u662f\u4f7f\u7528\u5176\u521b\u5efa\u4e00\u4e2a ILCursor
:
ILCursor cur = new(il);\n
\u987e\u540d\u601d\u4e49, \u8fd9\u662f\u4e00\u4e2a \"IL \u6307\u9488\", \u5b83 \"\u6307\u5411\" \u8fd9\u4e2a\u65b9\u6cd5\u7684 IL \u4ee3\u7801\u7684\u67d0\u4e00\u884c, \u5b83\u62e5\u6709\u5f88\u591a\u65b9\u6cd5\u4ee5\u5141\u8bb8\u6211\u4eec\u5728\u5b83\u6307\u5411\u7684\u4f4d\u7f6e\u4e0b\u6dfb\u52a0, \u4fee\u6539, \u5220\u9664 IL, \u81ea\u7136, \u5b83\u4e5f\u5e26\u6709\u5f88\u591a\u65b9\u6cd5\u6765\u79fb\u52a8\u5b83\u7684\u6307\u5411, \u6700\u5e38\u7528\u7684\u65b9\u6cd5\u4e4b\u4e00\u662f TryGotoNext
, \u5b83\u7684\u53c2\u6570\u5217\u8868\u5305\u542b\u4e00\u7cfb\u5217\u7684 predicates
(\u8fd9\u8bcd\u4f3c\u4e4e\u6ca1\u4e2a\u7edf\u4e00\u7684\u7ffb\u8bd1, \u4e0d\u8fc7\u7406\u89e3\u5b83\u5f88\u7b80\u5355).
\u73b0\u5728, \u5047\u8bbe\u6211\u4eec\u7684\u76ee\u7684\u662f\u4fee\u6539\u73a9\u5bb6\u8e6d\u5899\u8df3\u65f6\u7684\u7ad6\u76f4\u901f\u5ea6\u4e3a 2 \u500d, \u90a3\u4e48\u6211\u4eec\u627e\u5230 SuperWallJump
\u65b9\u6cd5, \u6ce8\u610f\u5230\u7ad6\u76f4\u901f\u5ea6\u662f\u5728\u8fd9\u91cc\u8bbe\u7f6e\u7684:
Celeste.Player.SuperWallJump()...\nthis.wallSlideTimer = 1.2f;\nthis.wallBoostTimer = 0f;\nthis.Speed.X = 170f * (float)dir;\nthis.Speed.Y = -160f;\nthis.Speed += this.LiftBoost;\nthis.varJumpSpeed = this.Speed.Y;\nthis.launched = true;\n...\n
\u90a3\u4e48\u6211\u4eec\u67e5\u770b\u5b83\u9644\u8fd1 IL, \u7136\u540e\u67e5\u627e\u8fd9\u90e8\u5206 IL \u7684\u4e00\u4e2a\u7279\u5f81\u4ee5\u65b9\u4fbf\u6211\u4eec\u8fdb\u884c\u5b9a\u4f4d:
Celeste.Player.SuperWallJump()IL_0075: ldarg.1\nIL_0076: conv.r4\nIL_0077: mul\nIL_0078: stfld float32 [FNA]Microsoft.Xna.Framework.Vector2::X\nIL_007D: ldarg.0\nIL_007E: ldflda valuetype [FNA]Microsoft.Xna.Framework.Vector2 Celeste.Player::Speed\nIL_0083: ldc.r4 -160\nIL_0088: stfld float32 [FNA]Microsoft.Xna.Framework.Vector2::Y\nIL_008D: ldarg.0\nIL_008E: ldarg.0\n
\u6211\u4eec\u53d1\u73b0\u8fd9\u91cc\u6709\u4e00\u4e2a\u5f88\u7279\u6b8a\u7684 -160 \u6d6e\u70b9\u6570\u7684\u538b\u5165, \u5e76\u4e14\u7d27\u968f\u5176\u540e\u7684\u662f\u4e00\u4e2a Vector2::Y
\u5b57\u6bb5\u7684\u5b58\u5165, \u90a3\u4e48\u8fd9\u6837\u6211\u4eec\u5c31\u53ef\u4ee5\u4f7f\u7528\u8fd9\u4e2a\u7279\u5f81\u5c06 IL \u6307\u9488\u6307\u5411\u8fd9\u91cc:
if (cur.TryGotoNext(ins => ins.MatchLdcR4(-160f), ins => ins.MatchStfld<Vector2>(\"Y\")))\n{\n // \u6307\u9488\u4f4d\u4e8e ldc.r4 \u6307\u4ee4\u4e86\n}\n
\u4e0a\u8ff0\u4ee3\u7801\u4e2d\u6211\u4eec\u8981\u6c42 IL \u6307\u9488\u5411\u4e0b\u67e5\u627e, \u76f4\u5230\u627e\u5230\u4e00\u4e2a\u4f4d\u7f6e\u4f7f\u5f97 IL \u662f ldc.r4 -160f
\u5e76\u4e14\u4e0b\u4e00\u884c\u662f\u50a8\u5b58\u5230 Vector2
Y
\u5b57\u6bb5. \u5982\u679c\u6ca1\u627e\u5230\u5219\u8fd4\u56de false
. \u73b0\u5728, \u6211\u4eec\u7684\u6307\u9488\u5df2\u7ecf\u6307\u5411 ldc.r4
\u4e86, \u4f46\u662f\u6b64\u65f6\u5728\u8fd9\u4e2a\u4f4d\u7f6e\u52a0\u5165 IL \u4ee3\u7801\u5b9e\u9645\u4e0a\u4f1a\u52a0\u5230\u8fd9\u4e00\u884c\u4e0a\u9762\u53bb, \u6240\u6709\u6211\u4eec\u5f97\u5148\u8ba9\u5b83\u518d\u5411\u4e0b\u79fb\u52a8\u4e00\u884c, \u7136\u540e\u4f7f\u7528\u6211\u4eec\u7684 IL \u77e5\u8bc6, \u5c06\u5b83\u4e58\u4ee5\u4e2a 2:
if (cur.TryGotoNext(ins => ins.MatchLdcR4(-160f), ins => ins.MatchStfld<Vector2>(\"Y\")))\n{\n cur.Index++;\n cur.Emit(OpCodes.Ldc_R4, 2.0f);\n cur.Emit(OpCodes.Mul);\n}\n
Warning
\u6ce8\u610f OpCodes \u4f4d\u4e8e Mono.Cecil.Cil
\u800c\u4e0d\u662f System.Reflection.Emit
\u547d\u540d\u7a7a\u95f4\u4e0b.
\u73b0\u5728\u7f16\u8bd1\u8fd0\u884c, \u4f60\u5e94\u8be5\u80fd\u89c2\u5bdf\u5230\u8e6d\u5899\u8df3\u7684\u7ad6\u76f4\u901f\u5ea6\u53d8\u7684\u5f88\u5927!
\u6ce8\u610f\u7684\u662f, IL \u94a9\u5b50\u5f88\u5f3a\u5927, \u4f46\u4f7f\u7528\u5b83\u7684\u98ce\u9669\u4e5f\u5f88\u5927, \u7a0d\u6709\u4e0d\u614e\u5c31\u4f1a\u4f7f\u6574\u4e2a\u6e38\u620f\u76f4\u63a5\u5d29\u6e83. \u4f8b\u5982, \u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d, \u5982\u679c\u4f60\u5fd8\u8bb0\u4e86\u5411\u4e0b\u79fb\u52a8\u4e00\u884c, \u6211\u4eec\u5e0c\u671b\u63d2\u5165\u7684 IL \u4ee3\u7801\u5c31\u4f1a\u9519\u8bef\u5730\u88ab\u63d2\u5165\u81f3 ldc.r4 \u7684\u4e0a\u4e00\u884c, \u901a\u5e38\u8fd9\u4f1a\u5bfc\u81f4\u975e\u6cd5\u7684 IL \u4ee5\u5bfc\u81f4 JIT \u7f16\u8bd1\u5f02\u5e38, \u6216\u8005\u5176\u4ed6\u4e0d\u53ef\u9884\u77e5\u7684\u884c\u4e3a, \u4e0d\u8fc7\u5728\u8fd9\u91cc\u5b83\u4f1a\u5bfc\u81f4\u4e00\u4e2a\u66f4\u52a0\u4e25\u91cd\u7684\u95ee\u9898, \u5b83\u4f1a\u76f4\u63a5\u5d29\u6e83\u6389\u4f60\u7684\u6e38\u620f\u5e76\u4e14\u4e0d\u52a0\u4efb\u4f55 log.txt \u7684\u8f93\u51fa\u548c error_log.txt \u7684\u5f39\u51fa! \u4f60\u53ef\u4ee5\u81ea\u5df1\u5c1d\u8bd5\u4e00\u4e0b\u6765\u611f\u53d7\u5982\u679c IL \u94a9\u5b50\u4f7f\u7528\u5931\u8bef\u7684\u60c5\u51b5.
\u901a\u5e38\u66f4\u5e38\u89c1\u5730, \u6211\u4eec\u5e0c\u671b\u8fd9\u4e2a\u7cfb\u6570\u662f\u53ef\u4ee5\u968f\u65f6\u4fee\u6539\u7684, \u76f8\u4fe1\u4f60\u5f88\u5feb\u5c31\u80fd\u60f3\u5230\u6bd4\u5982\u50a8\u5b58\u5230\u5b57\u6bb5\u91cc, \u7136\u540e\u63d2\u5165\u4e00\u4e9b\u590d\u6742\u7684\u5b57\u6bb5\u8bfb\u53d6\u4ee3\u7801\u6216\u8005\u590d\u6742\u7684\u65b9\u6cd5\u8c03\u7528\u4ee3\u7801, \u4e0d\u8fc7 MonoMod \u4e3a\u6211\u4eec\u63d0\u4f9b\u4e86\u4e00\u4e2a\u66f4\u7b80\u5355\u7684\u65b9\u6cd5: EmitDelegate
, \u5b83\u80fd\u4e00\u952e\u751f\u6210\u8fd9\u4e9b\u590d\u6742\u7684\u65b9\u6cd5\u83b7\u53d6\u548c\u8c03\u7528.
\u4f8b\u5982\u4f60\u6709\u4e00\u4e2a\u9759\u6001\u65b9\u6cd5 GetFactorOfWallJumpYSpeed
, \u5b83\u4f1a\u6839\u636e\u4e00\u4e9b\u60c5\u51b5\u8fd4\u56de\u4e0d\u540c\u7684\u503c, \u4f8b\u5982\u5728\u8fd9\u91cc\u68c0\u6d4b\u6309\u8df3\u65f6\u662f\u5426\u540c\u65f6\u6309\u4e0b\u6293\u952e, \u662f\u5219\u7ffb\u500d\u7ad6\u76f4\u901f\u5ea6, \u5426\u5219\u4e0d\u53d8:
public static float GetFactorOfWallJumpYSpeed()\n{\n if (Input.Grab.Pressed)\n return 2.0f;\n else\n return 1.0f;\n}\n
\u4e0a\u9762\u5bf9\u5e94\u7684\u4ee3\u7801:
if (cur.TryGotoNext(ins => ins.MatchLdcR4(-160f), ins => ins.MatchStfld<Vector2>(\"Y\")))\n{\n cur.Index++;\n // as easy as pi!\n cur.EmitDelegate(GetFactorOfWallJumpYSpeed);\n cur.Emit(OpCodes.Mul);\n}\n
"},{"location":"trans/adv_hooks/#il_3","title":"\u79fb\u9664 IL","text":"\u901a\u5e38\u9664\u4e86\u63d2\u5165, \u6211\u4eec\u8fd8\u9700\u8981\u79fb\u9664 IL, \u5bf9\u4e8e\u4fee\u6539 IL \u7684\u60c5\u51b5\u6211\u4eec\u53ea\u9700\u8981\u5148\u79fb\u9664\u518d\u63d2\u5165\u5373\u53ef. \u8981\u79fb\u9664\u4e00\u884c IL, \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 Remove
\u65b9\u6cd5, Remove
\u65b9\u6cd5\u4f1a\u79fb\u9664\u6307\u9488\u6240\u6307\u7684 IL \u884c, \u4f8b\u5982\u6211\u4eec\u4f9d\u7136\u4fee\u6539\u73a9\u5bb6\u7684\u8e6d\u5899\u8df3\u7ad6\u76f4\u901f\u5ea6, \u4f46\u662f\u5728\u8fd9\u91cc\u6211\u4eec\u76f4\u63a5\u8986\u76d6\u6211\u4eec\u7684\u65b0\u503c:
if (cur.TryGotoNext(ins => ins.MatchLdcR4(-160f), ins => ins.MatchStfld<Vector2>(\"Y\")))\n{\n // \u6ce8\u610f\u6ca1\u6709 cur.Index++ \u4e86, \u8bb0\u4f4f Emit \u65f6\u65b0\u4ee3\u7801\u88ab\u6dfb\u52a0\u5230\u4e0a\u4e00\u884c, \u800c Remove \u65f6\u5219\u79fb\u9664\u5f53\u524d\u884c\n cur.Remove();\n // \u5f53\u524d\u4e00\u884c\u7684 IL \u5df2\u7ecf\u88ab\u79fb\u9664\u4e86, \u73b0\u5728\u6307\u9488\u5b9e\u9645\u4e0a\u6307\u5411\u4e4b\u524d\u7684\u4e0b\u4e00\u884c, \u6240\u4ee5\u6211\u4eec\u53ef\u4ee5\u76f4\u63a5 Emit\n cur.Emit(OpCodes.Ldc_R4, -300.0f);\n}\n
Note
\u5728\u63d2\u5165 IL, \u4fee\u6539 IL, \u66f4\u6539 IL \u6307\u9488\u6307\u5411\u65f6\u52a1\u5fc5\u6e05\u695a\u63d2\u5165\u4f4d\u7f6e, \u5220\u9664\u76ee\u6807, \u4ee5\u53ca\u64cd\u4f5c\u5b8c\u6210\u540e\u7684\u6307\u9488\u6307\u5411.
"},{"location":"trans/adv_hooks/#_1","title":"\u4efb\u610f\u94a9\u53d6","text":"\u76f8\u4fe1\u4f60\u5df2\u7ecf\u53d1\u73b0\u4e86, \u6709\u4e9b\u65b9\u6cd5\u6bd4\u5982\u53eb\u505a orig_xxx
\u7684\u65b9\u6cd5, \u4ee5\u53ca\u5c5e\u6027\u7684 getter \u548c setter \u4f60\u90fd\u65e0\u6cd5\u5728 On. \u548c IL. \u8fd9\u4e24\u4e2a\u547d\u540d\u7a7a\u95f4\u4e2d\u627e\u5230, \u540c\u65f6, \u94a9\u53d6\u522b\u7684 helper \u7684\u65b9\u6cd5\u4f3c\u4e4e\u4e5f\u65e0\u6cd5\u5b8c\u6210.
\u8fd9\u91cc\u6211\u4eec\u5f15\u5165\u4e24\u4e2a\u65b0\u7c7b: Hook
\u4e0e ILHook
, \u524d\u8005\u8868\u793a\u4e00\u4e2a On \u94a9\u5b50, \u540e\u8005\u8868\u793a\u4e00\u4e2a IL \u94a9\u5b50.
Hook
\u7684\u6784\u9020\u51fd\u6570\u62e5\u6709\u975e\u5e38\u591a\u91cd\u8f7d, \u5728\u8fd9\u91cc\u6211\u4eec\u53ea\u9700\u8981\u90a3\u4e2a (MethodBase method, Delegate to)
\u7684\u91cd\u8f7d, \u5b83\u8868\u793a\u6211\u4eec\u5e0c\u671b\u94a9\u53d6\u7b2c\u4e00\u4e2a\u53c2\u6570\u6307\u5b9a\u7684\u65b9\u6cd5, \u94a9\u5b50\u65b9\u6cd5\u662f\u7b2c\u4e8c\u4e2a\u53c2\u6570\u6307\u5b9a\u7684\u59d4\u6258.
\u4f8b\u5982, \u6211\u4eec\u5e0c\u671b\u94a9\u53d6 Player.Inventory
\u8fd9\u4e2a\u5c5e\u6027\u7684 get
\u65b9\u6cd5, \u4f7f\u5176\u603b\u662f\u8fd4\u56de PlayerInventory.TheSummit
, \u4e5f\u5c31\u662f\u603b\u662f\u5177\u6709\u80cc\u5305, \u53cc\u51b2\u7b49:
// \u50a8\u5b58\u6211\u4eec\u7684 hook, \u4ee5\u4fbf\u6211\u4eec\u5728 Unload \u4e2d\u91ca\u653e\u5b83\nprivate Hook playerInventory_get_hook;\n\npublic override void Load()\n{\n // \u5148\u4f7f\u7528\u53cd\u5c04\u627e\u5230 Player.Inventory \u5c5e\u6027\u7684 getter\n var playerInventory_get = typeof(Player).GetProperty(\"Inventory\").GetGetMethod();\n // \u4f7f\u7528\u5176\u521b\u5efa\u4e00\u4e2a On \u94a9\u5b50\n playerInventory_get_hook = new(playerInventory_get, PlayerInventoryHook);\n}\n\n// \u6211\u4eec\u9700\u8981\u624b\u52a8\u58f0\u660e orig \u65b9\u6cd5\u7684\u59d4\u6258, \u56e0\u4e3a\u8fd9\u91cc\u4e0d\u518d\u662f\u65b9\u4fbf\u7684\u4e8b\u4ef6\u8ba2\u9605\u4e86\npublic delegate PlayerInventory PlayerInventory_get_orig(Player self);\npublic static PlayerInventory PlayerInventoryHook(PlayerInventory_get_orig orig, Player self)\n{\n // \u76f4\u63a5\u5ffd\u7565 orig \u65b9\u6cd5\u7684\u8c03\u7528, \u5f3a\u5236\u8fd4\u56de 7a/b/c \u7684 Inventory\n return PlayerInventory.TheSummit;\n}\n\npublic override void Unload()\n{\n // \u8bb0\u5f97\u9500\u6bc1\u94a9\u5b50\n playerInventory_get_hook.Dispose();\n}\n
\u56e0\u4e3a\u4e0d\u518d\u662f\u4e4b\u524d\u65b9\u4fbf\u7684\u4e8b\u4ef6\u8ba2\u9605, \u6240\u4ee5\u94a9\u5b50\u7684 orig \u53c2\u6570\u7684\u59d4\u6258\u539f\u578b\u4f60\u5fc5\u987b\u5f97\u81ea\u5df1\u58f0\u660e, \u6ce8\u610f\u94a9\u5b50\u65b9\u6cd5\u548c\u94a9\u5b50 orig \u53c2\u6570\u7684\u53c2\u6570\u5217\u8868\u4e00\u5b9a\u8981\u5c0f\u5fc3\u51c6\u786e\u7684\u586b\u5199, \u5426\u5219\u4f1a\u76f4\u63a5\u9020\u6210\u6e38\u620f\u5d29\u6e83. \u4e0a\u8ff0\u4ee3\u7801\u7684\u6548\u679c\u5e94\u8be5\u662f\u4f60\u65e0\u8bba\u5982\u4f55\u90fd\u4f1a\u62e5\u6709 7a/b/c \u7684 Inventory, \u4e5f\u5373\u53cc\u51b2, \u5e26\u80cc\u5305\u7b49.
\u73b0\u5728, \u62e5\u6709\u4e86\u94a9\u5b50\u51fd\u6570, \u4f60\u53ef\u4ee5\u505a\u4efb\u4f55\u4f60\u4e4b\u524d\u4f7f\u7528\u8ba2\u9605\u4e8b\u4ef6\u6765\u521b\u5efa\u94a9\u5b50\u4e00\u6837\u7684\u4e8b. \u987a\u4fbf, \u4f7f\u7528\u8fd9\u79cd\u65b9\u6cd5\u4e5f\u5141\u8bb8\u4f60\u94a9\u53d6\u522b\u7684 helper \u7684\u65b9\u6cd5, \u751a\u81f3\u662f\u94a9\u53d6\u522b\u7684 helper \u7684\u94a9\u5b50\u65b9\u6cd5. \u4e0d\u8fc7\u5728\u6b64\u4e4b\u524d\u4f60\u9700\u8981\u4e3a\u4f60\u7684 mod \u58f0\u660e\u4f9d\u8d56\u6216\u8005\u53ef\u9009\u4f9d\u8d56, \u58f0\u660e\u53ef\u9009\u4f9d\u8d56\u540e\u53c8\u9700\u8981\u68c0\u6d4b\u5bf9\u5e94 mod \u662f\u5426\u52a0\u8f7d\u7b49\u7b49.
\u540c\u6837\u5730, IL \u94a9\u5b50\u7684\u521b\u5efa\u4e5f\u4e0e On \u94a9\u5b50\u76f8\u540c:
private ILHook playerInventory_get_ilhook;\n\npublic override void Load()\n{\n var playerInventory_get = typeof(Player).GetProperty(\"Inventory\").GetGetMethod();\n playerInventory_get_ilhook = new(playerInventory_get, PlayerInventoryILHook);\n}\n\npublic static void PlayerInventoryILHook(ILContext context)\n{\n // \u50cf\u4e4b\u524d\u4e00\u6837\u505a\u4f60\u5728 IL \u94a9\u5b50\u4e2d\u505a\u7684\u4e8b...\n}\n\npublic override void Unload()\n{\n playerInventory_get_ilhook.Dispose();\n}\n
\u4e0d\u8fc7\u4e0d\u518d\u9700\u8981\u624b\u52a8\u58f0\u660e orig \u59d4\u6258, \u56e0\u4e3a IL \u94a9\u5b50\u7684\u94a9\u5b50\u65b9\u6cd5\u53c2\u6570\u5217\u8868\u662f\u56fa\u5b9a\u7684.
Note
\u5173\u4e8e\u534f\u7a0b\u51fd\u6570\u7684\u94a9\u53d6\u4e0e\u4e0a\u8ff0\u6b65\u9aa4\u622a\u7136\u4e0d\u540c, \u8fd9\u4e00\u70b9\u6211\u4eec\u4f1a\u5728\u4e0b\u4e00\u8282\u63a2\u8ba8.
"},{"location":"trans/adv_hooks/#helper","title":"\u94a9\u53d6\u5176\u4ed6 helper","text":"Note
\u53c2\u8003 Everest Wiki
\u9996\u5148\u6211\u4eec\u5728\u94a9\u53d6\u524d\u9700\u8981\u786e\u4fdd\u5bf9\u5e94 helper \u5df2\u88ab\u52a0\u8f7d, \u90a3\u4e48\u6211\u4eec\u5148\u5728 everest.yaml
\u6587\u4ef6\u91cc\u52a0\u4e0a\u5bf9\u5e94\u7684\u53ef\u9009\u4f9d\u8d56, \u8fd9\u6837 Everest \u4f1a\u786e\u4fdd\u5b58\u5728\u8be5\u4f9d\u8d56\u65f6\u603b\u662f\u5728\u8be5\u4f9d\u8d56\u52a0\u8f7d\u4e4b\u540e\u518d\u52a0\u8f7d\u6211\u4eec\u7684 mod.
everest.yaml- Name: MyCelesteMod\n Version: 0.1.0\n DLL: Code/MyCelesteMod.dll\n Dependencies:\n - Name: EverestCore\n Version: 1.4465.0\n - Name: CommunalHelper\n Version: 1.20.4\n
\u63a5\u4e0b\u6765\u6211\u4eec\u4ee5 CommunalHelper
\u91cc\u7684 Chain
\u5b9e\u4f53\u4e3a\u4f8b, \u94a9\u53d6\u5b83\u7684 Update
:
private static Hook chainUpdateHook;\n\nprivate delegate void chainUpdateHookDelegate(Entity self);\n\npublic static void Load()\n{\n EverestModuleMetadata communalHelper = new()\n {\n Name = \"CommunalHelper\",\n Version = new Version(\"1.20.4\")\n };\n\n // \u5c1d\u8bd5\u83b7\u53d6 CommunalHelper \u7684 Module \u5b9e\u4f8b\n if (Everest.Loader.TryGetDependency(communalHelper, out EverestModule communalModule)) \n {\n Assembly communalAssembly = communalModule.GetType().Assembly; // \u62ff\u5230 communalHelper \u7684\u7a0b\u5e8f\u96c6\n Type chain = communalAssembly.GetType(\"Celeste.Mod.CommunalHelper.Entities.Chain\"); // \u62ff\u5230 Chain \u7684 Type\n MethodInfo method = chain.GetMethod(\"Update\", BindingFlags.Instance | BindingFlags.Public); // \u62ff\u5230 Update \u51fd\u6570\n chainUpdateHook = new Hook(method, ChainOnUpdate);\n // Logger.Log(LogLevel.Info, \"Test\", \"HookChainOnUpdate OK\");\n }\n}\n\npublic static void Unload()\n{\n chainUpdateHook.Dispose();\n}\n\nprivate static void ChainOnUpdate(chainUpdateHookDelegate orig, Entity chain)\n{\n orig(chain);\n // \u505a\u4e00\u4e9b\u4e8b\n // Logger.Log(LogLevel.Info, \"Test\", \"123\");\n}\n
\u4f46\u662f\u8fd9\u4e48\u5199\u5c31\u5f88\u96be\u53d7, \u800c\u4e14 chain \u7684\u7c7b\u578b\u4e3a Entity \u4e0d\u4e3a Chain \u4e86, \u60f3\u7c7b\u578b\u8f6c\u6210 Chain \u6211\u4eec\u53c8\u62ff\u4e0d\u5230 Chain, \u8fd9\u65f6\u5c31\u9700\u8981\u6211\u4eec\u6dfb\u52a0 CommunalHelper
\u7a0b\u5e8f\u96c6\u7684\u4f9d\u8d56(\u50cf\u4e00\u5f00\u59cb\u914d\u7f6e\u851a\u84dd code \u73af\u5883\u90a3\u6837)
dc \u793e\u533a\u4e60\u60ef\u7684\u505a\u6cd5\u662f\u5c06\u8fd9\u4e2a dll \u7684 ref \u7248\u672c (\u4e5f\u5c31\u662f stripped \u540e\u7684\u7248\u672c, \u5220\u9664\u4e86\u6240\u6709\u65b9\u6cd5\u7684\u5b9e\u73b0, \u53ea\u4fdd\u7559\u4e86\u5143\u6570\u636e) \u653e\u5230 mod \u76ee\u5f55\u5916\u9762\u7684 lib-stripped \u76ee\u5f55\u91cc\u7136\u540e\u5f15\u7528. \u53c2\u8003\u8349\u8393\u9171\u7684\u6e90\u7801. strip \u7684\u65b9\u6cd5\u4e0d\u552f\u4e00, \u4f8b\u5982\u4f60\u53ef\u4ee5\u4f7f\u7528 mono \u7684 strip \u5de5\u5177 mono-cil-strip
, \u6216\u8005 NStrip
\u8fd9\u4e2a\u5de5\u5177, \u5177\u4f53\u5728\u8fd9\u91cc\u5c31\u4e0d\u8bf4\u660e\u4e86.
\u6211\u4e2a\u4eba\u4e60\u60ef\u76f4\u63a5\u5f15\u7528 \u851a\u84dd\u6839\u76ee\u5f55/Mods/Cache/xxx.xxx.dll \u8fd9\u91cc\u7684 dll, \u5982\u679c\u4f60\u7684\u6a21\u677f\u662f\u6700\u65b0\u7684\u8bdd, \u4f60\u53ef\u4ee5\u4f7f\u7528 CelesteModReference
\u9879\u6765\u5f15\u7528, \u4f8b\u5982 BetterFreezeFrames \u4e2d\u7684\u4f7f\u7528\u4f8b\u5b50:
BetterFreezeFrames.csproj<ItemGroup>\n <CelesteModReference Include=\"FemtoHelper\" />\n <CelesteModReference Include=\"IsaGrabBag\" AssemblyName=\"IsaMods\" />\n <CelesteModReference Include=\"VivHelper\" />\n <CelesteModReference Include=\"FlaglinesAndSuch\" />\n <CelesteModReference Include=\"VortexHelper\" />\n</ItemGroup>\n
\u6bcf\u4e00\u9879\u7684 Include
\u8868\u793a mod \u540d\u79f0, \u53ef\u9009\u7684 AssemblyName
\u8868\u793a\u7a0b\u5e8f\u96c6\u540d\u79f0, \u9ed8\u8ba4\u4e3a Include
\u7684\u503c, \u8fd9\u6837\u5728\u6784\u5efa\u9879\u76ee\u65f6\u6a21\u677f\u4f1a\u81ea\u52a8\u5f15\u7528 Mods/Cache/(Include).(AssemblyName).dll \u8fd9\u4e2a\u7a0b\u5e8f\u96c6. \u73b0\u5728\u6211\u4eec\u5df2\u7ecf\u5f15\u7528\u597d\u4e86\u4f9d\u8d56\u4e86:
private static Hook chainUpdateHook;\n\nprivate delegate void chainUpdateHookDelegate(Chain self);\n\npublic static void Load()\n{\n EverestModuleMetadata communalHelper = new()\n {\n Name = \"CommunalHelper\",\n Version = new Version(\"1.20.4\")\n };\n bool isLoaded = Everest.Loader.DependencyLoaded(communalHelper);\n if (isLoaded)\n {\n chainUpdateHook = new Hook(typeof(Chain).GetMethod(\"Update\"), ChainOnUpdate);\n }\n}\n\nprivate static void ChainOnUpdate(chainUpdateHookDelegate orig, Chain chain)\n{\n orig(chain);\n Logger.Log(LogLevel.Info, \"Test\", \"123\");\n}\n\npublic static void Unload()\n{\n chainUpdateHook.Dispose();\n}\n
"},{"location":"trans/adv_hooks2/","title":"\u534f\u7a0b\u7684\u94a9\u53d6\u4e0e\u79c1\u6709\u8bbf\u95ee","text":""},{"location":"trans/adv_hooks2/#_2","title":"\u534f\u7a0b\u7684\u94a9\u53d6","text":""},{"location":"trans/adv_hooks2/#_3","title":"\u8fed\u4ee3\u5668\u51fd\u6570","text":"\u8fed\u4ee3\u5668\u51fd\u6570, \u4e5f\u5373\u65b9\u6cd5\u4f53\u5e26 yield return
\u6216 yield break
\u8bed\u53e5\u5e76\u8fd4\u56de IEnumerable
\u6216 IEnumerator
\u7684\u51fd\u6570, \u5b83\u5141\u8bb8\u4f60 \"\u4e2d\u65ad\" \u51fd\u6570\u7684\u8fd0\u884c\u5e76\u4e2d\u9014 \"\u8fd4\u56de\" \u4e00\u4e2a\u503c. \u7ecf\u8fc7\u524d\u9762 Alarm, Tween, Coroutine \u8282\u7684\u4ecb\u7ecd\u76f8\u4fe1\u4f60\u4e5f\u77e5\u9053\u5230\u4e86\u534f\u7a0b\u4e4b\u4e8e\u8fed\u4ee3\u5668\u51fd\u6570\u7684\u5f3a\u5927. \u4e0d\u8fc7\u5bf9\u4e8e\u534f\u7a0b\u51fd\u6570\u7684\u94a9\u53d6\u5e76\u4e0d\u662f\u90a3\u4e48\u7b80\u5355, \u9700\u8981\u4e00\u4e9b\u989d\u5916\u6b65\u9aa4.
\u5982\u679c\u4f60\u76f8\u5bf9\u4e86\u89e3\u4e00\u70b9 C# \u7684\u5e95\u5c42\u7684\u8bdd, \u4f60\u5e94\u8be5\u4f1a\u77e5\u9053\u8fed\u4ee3\u5668\u51fd\u6570\u6700\u7ec8\u4f1a\u88ab\u7f16\u8bd1\u4e3a\u4e00\u4e2a\u72b6\u6001\u673a\u7c7b, \u800c\u539f\u51fd\u6570\u53ea\u662f\u505a\u4e86\u4e00\u4e2a new \u5e76\u8fd4\u56de\u7684\u5de5\u4f5c. \u4e3a\u4e86\u5728\u53cd\u7f16\u8bd1\u5668\u6bd4\u5982 dnspy \u4e2d\u6d4f\u89c8\u8fd9\u4e2a\u72b6\u6001\u673a\u7c7b, \u4f60\u9700\u8981\u5173\u95ed\u7c7b\u4f3c\u7684 \u89c6\u56fe -> \u9009\u9879 -> \u53cd\u7f16\u8bd1\u5668 -> \u53cd\u7f16\u8bd1\u679a\u4e3e\u5668 \u8fd9\u4e2a\u529f\u80fd, \u8fd9\u6837\u53cd\u7f16\u8bd1\u5668\u624d\u4f1a\u5c55\u793a\u9690\u85cf\u7684\u72b6\u6001\u673a\u7c7b.
\u6bd4\u5982 FinalBoss.Attack01Sequence
\u65b9\u6cd5:
\u539f\u65b9\u6cd5:
private IEnumerator Attack01Sequence()\n{\n this.StartShootCharge();\n for (;;)\n {\n yield return 0.5f;\n this.Shoot(0f);\n yield return 1f;\n this.StartShootCharge();\n yield return 0.15f;\n yield return 0.3f;\n }\n yield break;\n}\n
\u5173\u95ed \u53cd\u7f16\u8bd1\u679a\u4e3e\u5668 \u9009\u9879\u540e:
private IEnumerator Attack01Sequence()\n{\n FinalBoss.<Attack01Sequence>d__49 <Attack01Sequence>d__ = new FinalBoss.<Attack01Sequence>d__49(0);\n <Attack01Sequence>d__.<>4__this = this;\n return <Attack01Sequence>d__;\n}\n
\u5176\u4e2d <Attack01Sequence>d__49
\u8fd9\u4e2a\u53e4\u602a\u7684\u7c7b\u540d\u5c31\u662f\u80cc\u540e\u751f\u6210\u7684\u72b6\u6001\u673a\u7c7b, \u800c\u65b9\u6cd5\u4f53\u7684\u5b9e\u9645\u5185\u5bb9\u5219\u5728\u8be5\u7c7b\u7684 MoveNext
\u65b9\u6cd5\u4e2d:
bool IEnumerator.MoveNext()\n{\n int num = this.<>1__state;\n FinalBoss finalBoss = this.<>4__this;\n switch (num)\n {\n case 0:\n this.<>1__state = -1;\n finalBoss.StartShootCharge();\n break;\n case 1:\n this.<>1__state = -1;\n finalBoss.Shoot(0f);\n this.<>2__current = 1f;\n this.<>1__state = 2;\n return true;\n case 2:\n this.<>1__state = -1;\n finalBoss.StartShootCharge();\n this.<>2__current = 0.15f;\n this.<>1__state = 3;\n return true;\n case 3:\n this.<>1__state = -1;\n this.<>2__current = 0.3f;\n this.<>1__state = 4;\n return true;\n case 4:\n this.<>1__state = -1;\n break;\n default:\n return false;\n }\n this.<>2__current = 0.5f;\n this.<>1__state = 1;\n return true;\n}\n
\u4e0a\u8ff0\u4ee3\u7801\u4e2d <>2__current
\u8fd9\u4e2a\u53e4\u602a\u7684\u5b57\u6bb5\u7528\u6765\u50a8\u5b58\u8fd4\u56de\u503c, <>1__state
\u5219\u7528\u6765\u50a8\u5b58\u534f\u7a0b\u8fd0\u884c\u7684\u8fdb\u5ea6.
"},{"location":"trans/adv_hooks2/#on","title":"On \u534f\u7a0b\u94a9\u5b50","text":"\u5bf9\u534f\u7a0b\u4f7f\u7528 On \u94a9\u5b50\u76f8\u5bf9\u7b80\u5355\u4e00\u70b9 ,\u4f8b\u5982\u94a9\u53d6 Celeste.NPC01_Theo.Talk
\u8fd9\u4e2a\u534f\u7a0b\u51fd\u6570, \u4e5f\u5c31\u662f 1a 6zb \u9762\u7684 theo \u7684\u5bf9\u8bdd\u7684\u534f\u7a0b, \u5982\u679c\u4f60\u76f4\u63a5\u4f7f\u7528\u5982\u4e0b\u4ee3\u7801(\u65b9\u6cd5 1):
public override void Load()\n{\n On.Celeste.NPC01_Theo.Talk += NPC01_Theo_Talk;\n}\n\nprivate IEnumerator NPC01_Theo_Talk(On.Celeste.NPC01_Theo.orig_Talk orig, NPC01_Theo self, Player player)\n{\n var it = orig(self, player);\n Logger.Log(LogLevel.Info, \"Test\", \"not the right time.\");\n return it;\n}\n\npublic override void Unload()\n{\n On.Celeste.NPC01_Theo.Talk -= NPC01_Theo_Talk;\n}\n
\u4f60\u4f1a\u53d1\u73b0\u5b83\u5b9e\u9645\u4e0a\u662f\u5728\u5bf9\u8bdd\u5f00\u59cb\u524d\u8f93\u51fa\u7684, \u8fd9\u5e76\u4e0d\u662f\u6211\u4eec\u60f3\u8981\u7684\u65f6\u673a, \u540c\u6837\u8fd9\u4e5f\u5f88\u597d\u7406\u89e3\u4e3a\u4ec0\u4e48\u4f1a\u8fd9\u6837, \u56e0\u4e3a\u539f\u51fd\u6570\u53ea\u662f\u8fd4\u56de\u4e86\u4e00\u4e2a\u80cc\u540e\u72b6\u6001\u673a\u7c7b\u7684\u65b0\u5b9e\u4f8b. \u4e3a\u4e86\u8fbe\u6210\u8fd9\u4e2a\u76ee\u7684, \u6211\u4eec\u9700\u8981\u8fd9\u4e48\u505a(\u65b9\u6cd5 2):
private IEnumerator NPC01_Theo_Talk(On.Celeste.NPC01_Theo.orig_Talk orig, NPC01_Theo self, Player player)\n{\n IEnumerator origEnum = orig(self, player);\n while (origEnum.MoveNext()) yield return origEnum.Current;\n Logger.Log(LogLevel.Info, \"Test\", \"the right time.\");\n}\n
\u4e5f\u5c31\u662f\u5c06\u5bf9\u5e94\u7684\u534f\u7a0b\u5305\u88c5\u8d77\u6765\u5e76\u5728\u6700\u540e\u9644\u52a0\u6211\u4eec\u7684\u4ee3\u7801. \u8bf4\u5230\u8fd9\u4e2a, \u4f60\u53ef\u80fd\u4f1a\u60f3\u5230\u8fd9\u6bb5\u4ee3\u7801\u53ef\u4ee5\u7b80\u5316\u6210\u8fd9\u6837(\u65b9\u6cd5 3):
private IEnumerator NPC01_Theo_Talk(On.Celeste.NPC01_Theo.orig_Talk orig, NPC01_Theo self, Player player)\n{\n yield return orig(self, player);\n Logger.Log(LogLevel.Info, \"Test\", \"does not execute.\");\n}\n
\u76f4\u63a5\u5c06\u534f\u7a0b\u8fd4\u56de\u5e76\u5728\u5176\u6267\u884c\u5b8c\u540e\u505a\u4e00\u4e9b\u4e8b, \u770b\u8d77\u6765\u4f3c\u4e4e\u6ca1\u4ec0\u4e48\u95ee\u9898? \u4f46\u662f! \u5982\u679c\u4f60\u770b\u8fc7 Coroutine
\u7684\u5b9e\u73b0\u7684\u8bdd, \u4f60\u4f1a\u53d1\u73b0\u534f\u7a0b\u8fd4\u56de\u53e6\u4e00\u4e2a\u534f\u7a0b\u65f6, \u53e6\u4e00\u4e2a\u534f\u7a0b\u5e76\u4e0d\u662f\u9a6c\u4e0a\u6267\u884c\u7684, \u800c\u662f\u7b49\u5230\u4e86\u4e0b\u4e00\u5e27, \u4e3a\u4e86\u66f4\u597d\u7684\u517c\u5bb9 tas, \u6211\u4eec\u8981\u4e48\u4f7f\u7528\u65b9\u6cd5 2, \u8981\u4e48\u4f7f\u7528\u5982\u4e0b\u7c7b\u4f3c\u7684\u4ee3\u7801(\u65b9\u6cd5 4):
private IEnumerator OuiFileSelect_Leave(On.Celeste.OuiFileSelect.orig_Leave orig, OuiFileSelect self, Oui next) \n{\n yield return new SwapImmediately(orig(self, next));\n Logger.Log(\"TestMod\", \"I left file select!\");\n}\n
\u4e5f\u5c31\u662f\u5728\u83b7\u53d6\u534f\u7a0b\u540e\u518d\u7528 everest \u4e3a\u6211\u4eec\u63d0\u4f9b\u7684 SwapImmediately
\u5305\u8d77\u6765, \u8fd9\u4f1a\u8ba9\u5185\u90e8\u7684\u534f\u7a0b\u7acb\u523b\u524d\u8fdb\u4e00\u6b21. \u800c\u4e0d\u4f1a\u7b49\u5f85\u591a\u4f59\u7684 1 \u5e27.
Info
\u5177\u4f53\u4e0a\u8ff0\u65b9\u6cd5\u7684\u884c\u4e3a\u63cf\u8ff0\u7684\u53ef\u80fd\u5e76\u4e0d\u662f\u5f88\u51c6\u786e, \u56e0\u4e3a\u6211\u4e2a\u4eba\u5f88\u5c11\u4f1a\u51fa\u73b0\u9700\u8981\u94a9\u53d6\u534f\u7a0b\u7684\u6848\u4f8b, \u5f88\u611f\u8c22\u5982\u679c\u4f60\u80fd\u5b8c\u5584\u5b83\u7684\u8bdd!
"},{"location":"trans/adv_hooks2/#il","title":"IL \u534f\u7a0b\u94a9\u5b50","text":"\u5bf9\u534f\u7a0b\u4f7f\u7528 IL \u94a9\u5b50\u76f8\u5bf9\u4f1a\u590d\u6742\u5f88\u591a, \u56e0\u4e3a\u5bf9\u539f\u51fd\u6570\u4f7f\u7528 IL \u94a9\u5b50\u901a\u5e38\u662f\u6ca1\u6709\u610f\u4e49\u7684, \u4e3a\u6b64, \u6211\u4eec\u9700\u8981\u83b7\u53d6\u5230\u80cc\u540e\u5b9e\u9645\u50a8\u5b58\u65b9\u6cd5\u4f53\u7684\u72b6\u6001\u673a\u7684 MoveNext
\u65b9\u6cd5:
var methodInfo = typeof(Player).GetMethod(\"DashCoroutine\", BindingFlags.NonPublic | BindingFlags.Instance).GetStateMachineTarget();\nILHook dashCoroutineHook = new ILHook(methodInfo, ILHookDashCoroutine);\n
\u5728\u8fd9\u91cc, MonoMod \u4e3a\u6211\u4eec\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5f88\u65b9\u4fbf\u7684\u62d3\u5c55\u65b9\u6cd5 GetStateMachineTarget
, \u5b83\u4f1a\u83b7\u53d6\u8fd9\u4e2a\u65b9\u6cd5\u5bf9\u5e94\u7684\u72b6\u6001\u673a\u7684 MoveNext
\u65b9\u6cd5, \u968f\u540e\u6211\u4eec\u624b\u52a8\u6784\u9020\u4e00\u4e2a IL \u94a9\u5b50, \u7136\u540e\u5c31\u50cf\u5f80\u5e38\u4e00\u6837\u5b9e\u73b0\u6211\u4eec\u7684\u94a9\u5b50. \u4e0d\u8fc7\u5f53\u7136, \u96be\u5ea6\u4f1a\u975e\u5e38\u5927, \u56e0\u4e3a\u901a\u5e38\u8fd9\u4e2a\u65b9\u6cd5\u662f\u975e\u5e38\u6df7\u4e71\u7684.
"},{"location":"trans/adv_hooks2/#_4","title":"\u79c1\u6709\u8bbf\u95ee","text":"\u901a\u5e38, \u4f60\u53ef\u80fd\u9700\u8981\u8bbf\u95ee\u4e00\u4e2a\u79c1\u6709\u65b9\u6cd5\u6216\u8005\u79c1\u6709\u5b57\u6bb5, \u9996\u5148\u6700\u5bb9\u6613\u60f3\u5230\u7684\u5f53\u7136\u662f\u53cd\u5c04, \u4e0d\u8fc7 MonoMod \u4e3a\u6211\u4eec\u63d0\u4f9b\u4e86\u4e00\u4e2a\u66f4\u597d\u7684\u4e1c\u897f: DynamicData
\u7c7b, \u4f8b\u5982\u8bbf\u95ee\u73a9\u5bb6\u7684\u79c1\u6709\u5b57\u6bb5 onGround
:
DynamicData playerData = DynamicData.For(player);\nbool onGround = playerData.Get<bool>(\"onGround\");\n
\u4fee\u6539\u4e5f\u5341\u5206\u7b80\u5355, \u4f8b\u5982\u4fee\u6539\u73a9\u5bb6\u7684\u6700\u5927\u4e0b\u843d\u901f\u5ea6:
playerData.Set(\"maxFall\", 660f);\n
\u8c03\u7528\u79c1\u6709\u65b9\u6cd5\u540c\u7406, \u53c2\u6570\u4e5f\u53ea\u9700\u4f5c\u4e3a params \u53c2\u6570\u4f20\u9012:
playerData.Invoke(\"Duck\");\n\nbool checkResult = (bool)playerData.Invoke(\"DreamDashCheck\", Vector2.UnitX);\n
\u5bf9\u4e8e\u9759\u6001\u7c7b, \u53ea\u9700\u8981\u7b80\u5355\u7684\u66f4\u6539\u83b7\u53d6 DynamicData
\u7684\u65b9\u5f0f:
DynamicData inputData = new DynamicData(typeof(Input));\n
\u968f\u540e\u9759\u6001\u65b9\u6cd5, \u5b57\u6bb5, \u5c5e\u6027\u7684\u8bbf\u95ee\u4e5f\u4e0e\u5b9e\u4f8b\u7684\u76f8\u540c.
\u5f53\u5b57\u7b26\u4e32\u6307\u5b9a\u7684\u6210\u5458\u4e0d\u5b58\u5728\u65f6, \u6ce8\u610f\u5e76\u4e0d\u4f1a\u62a5\u9519, \u5bf9\u4e8e\u5176\u7684\u975e\u6cdb\u578b Get
\u65b9\u6cd5\u4f1a\u7b80\u5355\u5730\u8fd4\u56de null \u503c, \u5bf9\u4e8e\u503c\u7c7b\u578b\u6cdb\u578b Get
\u65b9\u6cd5\u4f1a\u5f15\u53d1\u7a7a\u5f15\u7528\u5f02\u5e38, \u5bf9\u4e8e\u5f15\u7528\u7c7b\u578b\u6cdb\u578b Get
\u65b9\u6cd5\u8fd4\u56de null. \u4e0d\u8fc7\u5bf9\u4e8e Set
\u65b9\u6cd5, \u5982\u679c\u6307\u5b9a\u7684\u6210\u5458\u4e0d\u5b58\u5728\u65f6\u5b83\u4f1a\u5c06\u8fd9\u4e2a\u6210\u5458 \"\u7c98\u9644\" \u5230\u5bf9\u8c61\u4e0a, \u5c31\u50cf\u7ed9\u5bf9\u8c61\u52a8\u6001\u52a0\u4e86\u4e00\u6761\u5b57\u6bb5\u4e00\u6837, \u968f\u540e\u4f7f\u7528 Get
\u65b9\u6cd5\u4e5f\u80fd\u83b7\u53d6\u5230\u8fd9\u4e2a\u503c, \u4f60\u53ef\u4ee5\u4f7f\u7528\u5c06\u8fd9\u4e2a\u884c\u4e3a\u5f53 \"\u52a8\u6001\u6dfb\u52a0\u5b57\u6bb5\" \u4e00\u6837\u4f7f\u7528. \u4f8b\u5982:
DynamicData dd = DynamicData.For(player);\ndd.Set(\"mcm_attached\", \"some attached data...\");\n\n\n// ...\u4e00\u4e9b\u5176\u4ed6\u5730\u65b9\nstring data = dd.Get<string>(\"mcm_attached\");\nLogger.Log(LogLevel.Info, \"MyCelesteMod\", $\"data is {data}\");\n
\u4e0d\u8fc7\u8bb0\u5f97\u6dfb\u52a0\u81ea\u5df1 mod \u72ec\u7279\u7684\u547d\u540d\u524d\u7f00\u4ee5\u9632\u91cd\u540d, DynamicData
\u5728\u4e0d\u540c mod \u95f4\u662f\u5171\u4eab\u7684.
"},{"location":"trans/common1/","title":"Alarm, Tween, Coroutine","text":""},{"location":"trans/common1/#tween","title":"Tween","text":"Tween \u662f\u4e00\u4e2a\u5728 Monocle \u4e2d\u7528\u6765\u5b9e\u73b0\u7f13\u52a8\u7684 Component
, \u5728\u8fd9\u91cc\u4f60\u53ef\u4ee5\u8fdb\u884c\u6240\u6709 easings.net \u4e0a\u7684\u7f13\u52a8, \u5b83\u7684\u4f7f\u7528\u65b9\u6cd5\u5f88\u7b80\u5355: \u4f7f\u7528 Tween
// \u9996\u5148\u4f7f\u7528\u9759\u6001\u65b9\u6cd5 Tween.Create \u6765\u521b\u5efa\nTween tw = Tween.Create(Tween.TweenMode.Oneshot, Ease.BackIn, 1f, false);\n
\u8fd9\u91cc\u53c2\u6570\u53ef\u80fd\u76f8\u5bf9\u8f83\u591a:
\u7b2c\u4e00\u4e2a\u53c2\u6570 mode
: \u5b83\u8868\u793a\u7f13\u52a8\u7684\u7c7b\u578b, \u53ef\u7528\u7684\u6709: Persist
: \u7f13\u52a8\u7ed3\u675f\u540e\u8be5\u7ec4\u4ef6\u4f1a\u5931\u6d3b, \u76f4\u5230\u518d\u6b21\u88ab\u8c03\u7528 Start
Oneshot
: \u7f13\u52a8\u7ed3\u675f\u540e\u8be5\u7ec4\u4ef6\u4f1a\u79fb\u9664\u81ea\u8eab Looping
: \u7f13\u52a8\u7ed3\u675f\u4e00\u6b21\u540e\u4f1a\u7acb\u523b\u518d\u6b21\u5f00\u59cb\u540c\u4e00\u4e2a\u7f13\u52a8, \u5e76\u5faa\u73af YoyoOneshot
: \u7f13\u52a8\u7ed3\u675f\u540e\u4f1a\u7acb\u523b\u8fdb\u884c\u4e00\u6b21\u53cd\u5411\u7684\u7f13\u52a8, \u7ed3\u675f\u540e\u79fb\u9664\u81ea\u8eab YoyoLooping
: \u540c YoyoOneshot
, \u4f46\u662f\u4f1a\u5faa\u73af\u800c\u4e0d\u662f\u79fb\u9664\u81ea\u8eab \u7b2c\u4e8c\u4e2a\u53c2\u6570 easer
: \u5b83\u8868\u793a\u8be5\u7f13\u52a8\u7684 Easer
, \u901a\u5e38\u6211\u4eec\u4f7f\u7528 Ease
\u7c7b\u4e2d\u7684\u5df2\u6709\u9759\u6001\u5b57\u6bb5\u4e2d\u63d0\u4f9b\u7684\u5c31\u884c\u4e86, \u540c\u6837\u5730\u4f60\u53ef\u4ee5\u5728 easings.net \u611f\u53d7\u5e76\u68c0\u7d22\u4f60\u6240\u9700\u8981\u7684\u7f13\u52a8\u7c7b\u578b. \u7b2c\u4e09\u4e2a\u53c2\u6570 duration
: \u8868\u793a\u8be5\u7f13\u52a8\u8fdb\u884c\u7684\u65f6\u95f4(\u5355\u4f4d\u79d2), \u5bf9\u4e8e\u7279\u6b8a\u7684\u7f13\u52a8\u7c7b\u578b\u6765\u8bf4\u5b83\u6307\u4e00\u6b21\u6b63\u5411\u7f13\u52a8\u6216\u8005\u4e00\u6b21\u53cd\u5411\u7f13\u52a8\u6240\u9700\u65f6\u95f4. \u7b2c\u56db\u4e2a\u53c2\u6570 start
: \u662f\u5426\u7acb\u5373\u5f00\u59cb\u8fd9\u4e2a Tween
, \u5426\u5219\u6211\u4eec\u5f97\u9700\u8981\u624b\u52a8\u8c03\u7528 Start
\u65b9\u6cd5 \u5728\u521b\u5efa\u5b8c\u6211\u4eec\u7684 tw
\u5b9e\u4f8b\u540e, \u6211\u4eec\u5148\u5236\u70b9\u5c0f\u76ee\u6807:
\u5728\u7f13\u52a8\u5f00\u59cb\u65f6\u8f93\u51fa \"Tween start!\" \u5728\u7f13\u52a8\u8fc7\u7a0b\u65f6\u8f93\u51fa \"Tweening... Eased: <\u6b64\u65f6\u7684\u7f13\u52a8\u503c>, Percent: <\u7f13\u52a8\u5df2\u8fdb\u884c\u7684\u65f6\u95f4\u5360\u6bd4>\" \u5728\u7f13\u52a8\u7ed3\u675f\u540e\u8f93\u51fa \"Tween complete!\" \u5bf9\u4e8e\u5f00\u59cb\u548c\u7ed3\u675f\u5f88\u7b80\u5355, \u6211\u4eec\u53ea\u9700\u8981\u8d4b\u503c\u4e00\u4e9b\u5b57\u6bb5:
\u8d4b\u503c Tween \u7684\u4e00\u4e9b\u5b57\u6bb5tw.OnStart = t => Logger.Log(LogLevel.Info, \"test\", \"Tween start!\");\ntw.OnComplete = t => Logger.Log(LogLevel.Info, \"test\", \"Tween complete!\");\n
\u5728\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528 lambda \u8868\u8fbe\u5f0f\u4e3a\u5176\u8d4b\u503c, \u5176\u4e2d\u8be5 lambda \u88ab\u4f20\u5165\u7684\u53c2\u6570\u5c31\u662f\u8fd9\u4e2a Tween
\u5b9e\u4f8b, \u8fd9\u53ef\u4ee5\u5e2e\u52a9\u6211\u4eec\u907f\u514d lambda \u6355\u83b7\u4ee5\u53ca\u590d\u7528\u6211\u4eec\u7684 Tween
\u5904\u7406\u51fd\u6570.
\u5bf9\u4e8e\u7f13\u52a8\u8fc7\u7a0b, \u6211\u4eec\u9996\u5148\u4ecb\u7ecd\u4e24\u4e2a\u5c5e\u6027:
Eased
: \u8868\u793a\u8be5\u7f13\u52a8\u5f53\u524d\u7684 \"\u7f13\u52a8\u503c\" Percent
: \u8868\u793a\u8be5\u7f13\u52a8\u5df2\u8fdb\u884c\u65f6\u95f4\u5360\u6bd4, \u5373 \u5df2\u8fdb\u884c\u65f6\u95f4/\u603b\u65f6\u95f4 \u4e00\u4e2a\u66f4\u6e05\u695a\u7684\u4f8b\u5b50\u662f\u89c2\u5bdf easings.net \u7684\u56fe\u50cf, Eased
\u5373\u7eb5\u5750\u6807\u503c, Percent
\u5373\u6a2a\u5750\u6807\u503c.
\u90a3\u4e48\u8fd9\u91cc\u5c31\u5f88\u7b80\u5355\u5b9e\u73b0\u4e86:
tw.OnUpdate = t => Logger.Log(LogLevel.Info, \"test\", $\"Tweening... Eased: {t.Eased}, Percent: {t.Percent}\");\n
\u6700\u540e\u8bb0\u5f97 Start
\u5b83\u5e76\u4e14\u8bb0\u5f97\u628a\u5b83\u6302\u8f7d\u5230\u5b9e\u4f53\u4e0a, \u56e0\u4e3a\u5b83\u7684\u66f4\u65b0\u662f\u4f9d\u8d56\u5b9e\u4f53\u7684:
\u5f00\u59cb\u5e76\u6302\u8f7d// \u5982\u679c\u4f60\u5bf9 `start` \u53c2\u6570\u4f20\u5165 `true` \u90a3\u4e48\u4f60\u53ef\u4ee5\u4e0d\u7528\u505a\u8fd9\u4e00\u6b65\ntw.Start();\n// \u8fd9\u91cc\u5047\u8bbe\u6211\u4eec\u7684\u6240\u6709\u4ee3\u7801\u90fd\u8fdb\u884c\u5728\u4e00\u4e2a\u5b9e\u4f53\u5185\u90e8\nthis.Add(tw);\n
\u6216\u8005, \u6211\u4eec\u4f7f\u7528 Tween.Set
\u65b9\u6cd5, \u5b83\u662f\u4e00\u4e2a\u5de5\u5177\u65b9\u6cd5\u5141\u8bb8\u6211\u4eec\u7b80\u5316\u5bf9 Tween \u7684\u4f7f\u7528, \u4e0a\u9762\u7684\u4f8b\u5b50\u7528\u8fd9\u4e2a\u65b9\u6cd5\u53ef\u4ee5\u5199\u6210\u8fd9\u6837:
Tween tw = Tween.Set(this, Tween.TweenMode.Oneshot, 1f, Ease.BackIn,\n t => Logger.Log(LogLevel.Info, \"test\", $\"Tweening... Eased: {t.Eased}, Percent: {t.Percent}\"),\n t => Logger.Log(LogLevel.Info, \"test\", \"Tween complete!\"));\n// OnStart \u8fd8\u5f97\u624b\u52a8\u8bbe\u7f6e\u5450\ntw.OnStart = t => Logger.Log(LogLevel.Info, \"test\", \"Tween start!\");\ntw.Start();\n
\u5b83\u4f1a\u81ea\u52a8\u5e2e\u6211\u4eec\u6302\u8f7d\u5230\u5b9e\u4f53\u4e0a, \u4e0d\u8fc7\u4f9d\u7136\u9700\u8981\u6211\u4eec\u624b\u52a8 Start
, \u8fd9\u91cc\u65b9\u4fbf\u4e4b\u5904\u5c31\u5728\u4e8e\u4f60\u53ef\u4ee5\u76f4\u63a5\u628a\u4e00\u4e2a\u7b80\u5355\u7684\u51fd\u6570\u76f4\u63a5\u5728\u53c2\u6570\u4e2d\u4f20\u5165, \u800c\u4e0d\u662f Create
\u540e\u518d\u8bbe\u7f6e\u5b57\u6bb5. \u4e0d\u8fc7\u8fd9\u91cc\u53c2\u6570\u5217\u8868\u4e2d\u5e76\u6ca1\u6709 Start
\u76f8\u5173\u7684\u53c2\u6570, \u5982\u679c\u4f60\u8fd8\u9700\u8981\u8bbe\u7f6e Start
\u7684\u56de\u8c03\u7684\u8bdd\u4f60\u53ef\u4ee5\u56de\u9000\u5230\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\u7684\u65b9\u6cd5, \u5c31\u50cf\u4e0a\u9762\u7684\u4ee3\u7801\u4e00\u6837\u624b\u52a8\u8bbe\u7f6e OnStart
.
"},{"location":"trans/common1/#alarm","title":"Alarm","text":"\u987e\u540d\u601d\u4e49, \u5b83\u5c31\u662f\u4e2a'\u95f9\u949f', \u5b83\u5141\u8bb8\u4f60\u8bbe\u5b9a\u4e00\u4e2a\u65f6\u95f4\u5e76\u5728\u65f6\u95f4\u7ed3\u675f\u540e\u505a\u4e00\u4e9b\u4e8b\u60c5, \u5176\u4f7f\u7528\u8d77\u6765\u5f88\u7b80\u5355:
Alarm alarm = Alarm.Create(Alarm.AlarmMode.Oneshot, OnAlarm, 2f, false);\nAdd(alarm);\nalarm.Start();\n\nstatic void OnAlarm()\n{\n Logger.Log(LogLevel.Info, \"Test\", \"123\");\n}\n
\u7b2c\u4e00\u4e2a\u53c2\u6570 AlarmMode
\u4e0e Tween.TweenMode
\u7684\u57fa\u672c\u4e00\u81f4, \u8fd9\u91cc\u5c31\u4e0d\u8d58\u8ff0\u4e86 \u7b2c\u4e8c\u4e2a\u53c2\u6570\u8868\u793a\u65f6\u95f4\u5230\u540e\u7684\u56de\u8c03\u51fd\u6570 \u7b2c\u4e09\u4e2a\u53c2\u6570\u8868\u793a\u65f6\u95f4\u6709\u591a\u957f \u7b2c\u56db\u4e2a\u53c2\u6570\u4e5f\u4e0e tween \u7c7b\u4f3c, \u8868\u793a\u662f\u5426\u5e0c\u671b\u81ea\u52a8\u8c03\u7528 Start
\u65b9\u6cd5 \u9664\u4e86\u5728\u7b2c\u4e09\u4e2a\u53c2\u6570\u5904\u8bbe\u7f6e\u65f6\u95f4\u957f\u5ea6\u5916, Start
\u65b9\u6cd5\u4e5f\u5141\u8bb8\u6211\u4eec\u4f20\u5165\u4e00\u4e2a\u65f6\u95f4\u957f\u5ea6, \u8fd9\u4f1a\u5728\u4f60\u9700\u8981\u4e00\u4e2a\u4e0d\u5b9a\u957f\u7684\u95f9\u949f\u7684\u65f6\u5019\u5f88\u6709\u7528. \u9664\u6b64\u4e4b\u5916, Alarm
\u4e5f\u6709\u7c7b\u4f3c\u4e8e Tween.Set
\u7684\u65b9\u6cd5\u76f4\u63a5\u4f5c\u7528\u4e0e Entity
\u4e0a, \u53c2\u6570\u4e5f\u4e0e\u5176\u6784\u9020\u51fd\u6570\u76f8\u540c:
// \u4e0d\u8fc7\u8fd9\u91cc AlarmMode \u53cd\u800c\u88ab matt \u653e\u5230\u6700\u540e\u53bb\u4e86\nAlarm.Set(this, 2f, OnAlarm, Alarm.AlarmMode.Oneshot).Start();\n
"},{"location":"trans/common1/#coroutine","title":"Coroutine","text":"Coroutine
\u5e38\u89c1\u7684\u4e2d\u6587\u7ffb\u8bd1\u53eb\u505a '\u534f\u7a0b', \u5b83\u662f\u4e00\u4e2a\u975e\u5e38\u5f3a\u5927\u7684\u4e1c\u897f, async/await \u5f02\u6b65\u5141\u8bb8\u6211\u4eec\u50cf\u5199\u540c\u6b65\u4ee3\u7801\u4e00\u6837\u5199\u5f02\u6b65\u4ee3\u7801, \u5927\u6982\u7c7b\u4f3c\u5730, \u534f\u7a0b\u5c31\u5141\u8bb8\u6211\u4eec\u50cf\u5199\u4e00\u4e2a\u5728\u540c\u4e00\u5e27\u5185\u5141\u8bb8\u7684\u4ee3\u7801\u4e00\u6837\u5199\u5728\u4e0d\u540c\u5e27\u5185\u8fd0\u884c\u7684\u4ee3\u7801. \u597d\u5427\u4e0a\u9762\u8fd9\u53e5\u8bdd\u6709\u70b9\u4e71, \u4e0d\u8fc7\u6211\u4eec\u770b\u4e00\u4e0b\u4f8b\u5b50\u5c31\u4f1a\u7406\u89e3\u4e86:
var coroutine = new Coroutine(MakeRoutine());\nAdd(coroutine);\n\nstatic IEnumerator MakeRoutine()\n{\n Logger.Log(LogLevel.Info, \"tag\", \"\u5f00\u59cb!\");\n yield return 1f;\n Logger.Log(LogLevel.Info, \"tag\", \"\u8fc7\u4e861s!\");\n yield return 2f;\n Logger.Log(LogLevel.Info, \"tag\", \"\u53c8\u8fc7\u4e862s!\");\n yield break;\n}\n
Info
\u4e0a\u8ff0\u4ee3\u7801\u4e2d\u7684 yield return
\u7b49\u8bed\u6cd5\u5c5e\u4e8e \"\u8fed\u4ee3\u5668\u51fd\u6570\", \u5982\u679c\u4f60\u4e0d\u4e86\u89e3\u5b83\u7684\u8bdd\u4f60\u53ef\u4ee5\u5230 msdn \u4e0a\u6216\u8005 bing \u641c\u7d22 \u4e0a\u67e5\u627e\u5b83.
\u4e0a\u8ff0\u4ee3\u7801\u4f1a\u7acb\u523b\u6253\u5370\u4e00\u53e5 \"\u5f00\u59cb!\" \u7136\u540e\u7b49\u5f851s, \u7136\u540e\u6253\u5370 \"\u8fc7\u4e861s!\", \u518d\u8fc7\u4e862s\u540e\u518d\u6b21\u6253\u5370\"\u53c8\u8fc7\u4e862s!\". \u4e5f\u5c31\u662f\u8bf4\u4f60\u6bcf yield return
\u4e00\u4e2a\u6d6e\u70b9\u6570, \u6e38\u620f\u4f1a\u7b49\u5f85\u8be5\u79d2\u6570, \u7136\u540e\u7ee7\u7eed\u6267\u884c\u4e0b\u9762\u7684\u4ee3\u7801. \u4f60\u53ef\u80fd\u89c9\u5f97\u8fd9\u4e0d\u5c31\u662f\u4e2a\u9ad8\u7ea7\u70b9\u7684 Alarm
\u5417, \u786e\u5b9e, \u4f60\u4ecd\u7136\u53ef\u4ee5\u7528 Alarm
\u6765\u91cd\u5199\u8fd9\u90e8\u5206\u529f\u80fd, \u4e0d\u8fc7\u5f88\u5feb\u4f60\u5c31\u4f1a\u9677\u5165\u56de\u8c03\u5730\u72f1\u5e76\u4e14\u4ee3\u7801\u4e5f\u53d8\u7684\u5341\u5206\u96be\u8bfb:
Logger.Log(LogLevel.Info, \"tag\", \"\u5f00\u59cb!\");\nAlarm.Set(this, 1f, () =>\n{\n Logger.Log(LogLevel.Info, \"tag\", \"\u8fc7\u4e861s!\");\n Alarm.Set(this, 2f, () =>\n {\n Logger.Log(LogLevel.Info, \"tag\", \"\u53c8\u8fc7\u4e862s!\");\n\n }, Alarm.AlarmMode.Oneshot);\n\n}, Alarm.AlarmMode.Oneshot);\n
\u9664\u4e86\u8fd4\u56de\u4e00\u4e9b\u6d6e\u70b9\u6570, \u6211\u4eec\u8fd8\u53ef\u4ee5\u8fd4\u56de\u4e00\u4e2a null
, \u8fd9\u6837\u4f1a\u8ba9\u6e38\u620f\u4ec5\u7b49\u5f85\u4e00\u5e27, \u4e5f\u5c31\u662f\u5728\u8fd9\u6b21\u8fd4\u56de\u540e, \u6e38\u620f\u5728\u4e0b\u4e00\u5e27\u7acb\u523b\u7ee7\u7eed\u6267\u884c\u800c\u4e0d\u662f\u7b49\u5f85\u79d2\u6570. \u6bd4\u5982\u5728\u5b98\u56fe\u4e2d FallingBlock
\u5bf9\u5176\u7684\u4e00\u4e2a\u5e94\u7528(\u5df2\u7b80\u5316, \u5220\u9664\u4e86 BadelineBoss \u76f8\u5173\u7684\u4ee3\u7801): Celeste.FallingBlock.Sequence()
// \u6301\u7eed\u68c0\u6d4b\u662f\u5426\u73a9\u5bb6\u5728\u4e0a\u9762\u6293/\u7ad9\u7740\nwhile (!PlayerFallCheck())\n yield return null;\n// \u73a9\u5bb6\u6293/\u7ad9\u7740, \u8fdb\u5165\u6389\u843d\u72b6\u6001\nHasStartedFalling = true;\nwhile (true)\n{\n // \u5728\u771f\u6b63\u8fdb\u884c\u5411\u4e0b\u79fb\u52a8\u65f6\u5148\u7b49\u5f85 0.2s \n yield return 0.2f;\n\n // \u7136\u540e\u7b49\u5f85 0.4s, \u4f46\u662f\u73a9\u5bb6\u79bb\u5f00\u6389\u843d\u5757\u540e\u4f1a\u53d6\u6d88\u8fd9\u4e2a\u7b49\u5f85\n float waitTimer = 0.4f;\n while (waitTimer > 0f && PlayerWaitCheck())\n {\n yield return null;\n waitTimer -= Engine.DeltaTime;\n }\n\n // ......, \u6267\u884c\u6301\u7eed\u6389\u843d\u7684\u903b\u8f91, \u76f4\u5230\u78b0\u5230\u4e86\u5e73\u53f0(\u6cdb\u6307\u6240\u6709\u4e0a\u9762\u80fd\u7ad9\u7684\u4e1c\u897f, \u975e\u6307\u6728\u5e73\u53f0, \u4e0b\u540c)\u7136\u540e\u505c\u4e0b\n\n // \u6bcf\u9694 0.1s \u68c0\u6d4b\u662f\u5426\u5e95\u4e0b\u4f9d\u7136\u8fd8\u5b58\u5728\u5e73\u53f0, \u5426\u5219\u8fdb\u5165\u4e0b\u4e00\u6b21 while \u5faa\u73af\n while (CollideCheck<Platform>(Position + new Vector2(0f, 1f)))\n yield return 0.1f;\n}\n......\n
\u73b0\u5728\u56de\u5fc6\u4e00\u4e0b\u5b98\u56fe\u7684\u6389\u843d\u5757\u7684\u903b\u8f91, \u662f\u4e0d\u662f\u548c\u4e0a\u9762\u4ee3\u7801\u63cf\u8ff0\u7684\u4e00\u81f4? \u5982\u679c\u6ca1\u6709\u4e86\u534f\u7a0b, \u6211\u4eec\u5c31\u5f97\u7528\u4e00\u4e2a\u72b6\u6001\u53d8\u91cf\u6765\u50a8\u5b58\u6389\u843d\u5757\u8fdb\u884c\u5230\u54ea\u4e00\u6b65, \u5e76\u4e14\u65f6\u65f6\u523b\u523b\u7ef4\u62a4\u8fd9\u4e2a\u53d8\u91cf, \u65e5\u76ca\u53d8\u7684\u8d8a\u6765\u8d8a\u9ebb\u70e6. \u534f\u7a0b\u8fd8\u80fd\u8fd4\u56de\u53e6\u4e00\u4e2a\u534f\u7a0b, \u53ea\u9700\u8981\u8fd4\u56de\u4e00\u4e2a IEnumerator
:
var coroutine = new Coroutine(MakeRoutine());\nAdd(coroutine);\n\nstatic IEnumerator MakeRoutine()\n{\n Logger.Log(LogLevel.Info, \"tag\", \"\u5f00\u59cb!\");\n yield return 1f;\n Logger.Log(LogLevel.Info, \"tag\", \"\u8fc7\u4e861s!\");\n yield return MakeRoutineInner();\n Logger.Log(LogLevel.Info, \"tag\", \"\u5185\u90e8\u7684\u534f\u7a0b\u7ed3\u675f\u4e86!\");\n yield return MakeRoutineInner();\n Logger.Log(LogLevel.Info, \"tag\", \"\u5185\u90e8\u7684\u534f\u7a0b\u53c8\u4e00\u6b21\u7ed3\u675f\u4e86!\");\n yield break;\n}\n\nstatic IEnumerator MakeRoutineInner()\n{\n yield return 1f;\n Logger.Log(LogLevel.Info, \"tag\", \"\u5185\u90e8\u7b49\u4e861s!\");\n yield return 1f;\n Logger.Log(LogLevel.Info, \"tag\", \"\u5185\u90e8\u53c8\u7b49\u4e861s!\");\n yield break;\n}\n
\u5b83\u7684\u8f93\u51fa\u4f1a\u50cf\u662f: (09/30/2023 13:39:28) [Everest] [Info] [tag] \u5f00\u59cb!\n(09/30/2023 13:39:29) [Everest] [Info] [tag] \u8fc7\u4e861s!\n(09/30/2023 13:39:30) [Everest] [Info] [tag] \u5185\u90e8\u7b49\u4e861s!\n(09/30/2023 13:39:31) [Everest] [Info] [tag] \u5185\u90e8\u53c8\u7b49\u4e861s!\n(09/30/2023 13:39:31) [Everest] [Info] [tag] \u5185\u90e8\u7684\u534f\u7a0b\u7ed3\u675f\u4e86!\n(09/30/2023 13:39:32) [Everest] [Info] [tag] \u5185\u90e8\u7b49\u4e861s!\n(09/30/2023 13:39:33) [Everest] [Info] [tag] \u5185\u90e8\u53c8\u7b49\u4e861s!\n(09/30/2023 13:39:33) [Everest] [Info] [tag] \u5185\u90e8\u7684\u534f\u7a0b\u53c8\u4e00\u6b21\u7ed3\u675f\u4e86!\n
\u4f7f\u7528\u534f\u7a0b, \u6211\u4eec\u53ef\u4ee5\u5f88\u8f7b\u677e\u7684\u5c31\u50cf\u81ea\u7136\u63cf\u8ff0\u4e00\u4e2a\u8fc7\u7a0b\u4e00\u6837 \"\u81ea\u7136\" \u5730\u5199\u5b9e\u73b0\u7684\u4ee3\u7801, \u5b98\u56fe\u4e2d\u5267\u60c5\u7684\u5b9e\u73b0\u5c31\u662f\u4e00\u4e2a\u5f88\u597d\u7684\u4f8b\u5b50(\u6b64\u5904\u4e3a\u5e8f\u7ae0\u9e1f\u6559\u51b2\u523a\u7684\u5267\u60c5, \u5df2\u5927\u91cf\u7b80\u5316): Celeste.CS00_Ending
private IEnumerator Cutscene(Level level)\n{\n // \u6162\u6162\u51cf\u6162\u6e38\u620f\u901f\u5ea6\u76f4\u5230 0.0x, \u5e76\u4e14\u5728\u51cf\u6162\u5230 0.5x \u65f6\u505c\u6b62\u6865\u5d29\u584c\u97f3\u4e50\n while (Engine.TimeRate > 0f)\n {\n yield return null;\n if (Engine.TimeRate < 0.5f && bridge != null)\n bridge.StopCollapseLoop();\n level.StopShake();\n Engine.TimeRate -= Engine.RawDeltaTime * 2f;\n }\n // \u6b64\u65f6\u6e38\u620f\u901f\u5ea6\u4f1a\u88ab\u8bef\u51cf\u5230\u8d1f\u6570, \u8bbe\u7f6e\u56de 0 \u9632\u6b62\u6e38\u620f\u884c\u4e3a\u5f02\u5e38\n Engine.TimeRate = 0f;\n // \u5207\u6362\u73a9\u5bb6\u72b6\u6001\u5230 StDummy, \u5373\u7981\u6b62\u6240\u6709\u8f93\u5165\u548c\u4ea4\u4e92\n player.StateMachine.State = Player.StDummy;\n // \u9501\u5b9a\u73a9\u5bb6\u671d\u5411\u4e3a\u53f3\n player.Facing = Facings.Right;\n // \u65e0\u89c6\u6e38\u620f\u901f\u5ea6\u5730\u7b49\u5f85 1s, \u9ed8\u8ba4\u8fd4\u56de\u6d6e\u70b9\u6570\u7684\u7b49\u5f85\u4f1a\u53d7\u6e38\u620f\u901f\u5ea6\u5f71\u54cd,\n // \u8fd9\u91cc\u5982\u679c\u7528\u8fd4\u56de\u6d6e\u70b9\u6570\u7684\u7b49\u5f85\u4f1a\u9020\u6210\u534f\u7a0b\u505c\u6b62, \u56e0\u4e3a\u6e38\u620f\u901f\u5ea6\u4e3a 0x, \u5373\u7b49\u5f85\u6c38\u8fdc\u4e0d\u4f1a\u7ed3\u675f\n yield return WaitFor(1f);\n // \u64ad\u653e\u9e1f\u98de\u5165\u7684\u58f0\u97f3\n Audio.Play(\"event:/game/general/bird_in\", bird.Position);\n // \u8bbe\u7f6e\u9e1f\u7684\u671d\u5411\u548c\u52a8\u753b\n bird.Facing = Facings.Left;\n bird.Sprite.Play(\"fall\", false, false);\n // \u7f13\u52a8\u9e1f\u7684\u4f4d\u7f6e, \u5e76\u5728\u9e1f\u98de\u5230\u4e00\u534a\u65f6\u64ad\u653e\u98de\u884c\u7684\u52a8\u753b\n float percent = 0f;\n Vector2 from = bird.Position;\n Vector2 to = bird.StartPosition;\n while (percent < 1f)\n {\n bird.Position = from + (to - from) * Ease.QuadOut(percent);\n if (percent > 0.5f)\n bird.Sprite.Play(\"fly\", false, false);\n percent += Engine.RawDeltaTime * 0.5f;\n yield return null;\n }\n bird.Position = to;\n from = default(Vector2);\n to = default(Vector2);\n // \u64ad\u653e\u9e1f\u78b0\u5730\u7684\u97f3\u6548\n Audio.Play(\"event:/game/general/bird_land_dirt\", bird.Position);\n // \u5411\u5de6\u91ca\u653e\u5c18\u57c3\u7c92\u5b50\u6548\u679c\n Dust.Burst(bird.Position, - MathHelper.PI / 2, 12);\n // \u64ad\u653e\u95f2\u7f6e\u52a8\u753b, \u7136\u540e\u7b49\u5f85 0.5s \u540e\u518d\u6b21\u64ad\u653e\u5544\u5730\u7684\u52a8\u753b\n bird.Sprite.Play(\"idle\", false, false);\n yield return WaitFor(0.5f);\n bird.Sprite.Play(\"peck\", false, false);\n // \u7b49\u5f85 1.1s, \u4e5f\u5c31\u662f\u5dee\u4e0d\u591a\u5544\u5730\u52a8\u753b\u7684\u957f\u5ea6\n yield return WaitFor(1.1f);\n // \u64ad\u653e\u51b2\u523a\u6559\u5b66\n yield return bird.ShowTutorial(new BirdTutorialGui(\n bird, new Vector2(0f, -16f), Dialog.Clean(\"tutorial_dash\", null), \n new Vector2(1f, -1f), \"+\", BirdTutorialGui.ButtonPrompt.Dash\n ), caw: true);\n\n // \u6301\u7eed\u7b49\u5f85, \u76f4\u5230\u73a9\u5bb6\u6309\u4e0b\u4e86\u53f3\u4e0a\u51b2\n for (;;)\n {\n Vector2 aimVector = Input.GetAimVector(Facings.Right);\n if (aimVector.X > 0f && aimVector.Y < 0f && Input.Dash.Pressed)\n break;\n yield return null;\n }\n // \u8bbe\u7f6e\u73a9\u5bb6\u7684\u72b6\u6001\u4e3a \"\u9e1f\u51b2\u523a\u6559\u7a0b\" \u72b6\u6001, \u8fd9\u4e2a\u72b6\u6001\u5373\u51b2\u523a\u5f00\u59cb\u5230\u4e0a\u5cb8\u5e76\u5f3a\u5236\u79fb\u52a8\u5230\u53f3\u4fa7\u7684\u72b6\u6001\n player.StateMachine.State = Player.StBirdDashTutorial;\n player.Dashes = 0;\n level.Session.Inventory.Dashes = 1;\n // \u6062\u590d\u6e38\u620f\u901f\u7387\n Engine.TimeRate = 1f;\n // \u6536\u56de\u9e1f\u7684\u6559\u7a0b\u6846\u6846\n bird.Add(new Coroutine(bird.HideTutorial()));\n // \u7b49\u5f85 0.25s\n yield return 0.25f;\n // \u64ad\u653e\u9e1f\u88ab\u73a9\u5bb6\u5413\u8d70\u98de\u8d70\u7684\u52a8\u753b (\u6b64\u65f6\u5927\u7ea6\u662f\u73a9\u5bb6\u51b2\u523a\u7ed3\u675f\u7684\u65f6\u95f4)\n bird.Add(new Coroutine(bird.StartleAndFlyAway()));\n // \u7b49\u5f85\u76f4\u5230\u73a9\u5bb6\u843d\u5730, \u6216\u8005\u76f4\u5230\u73a9\u5bb6\u5bc4\u4e86\n while (!player.Dead && !player.OnGround(1))\n yield return null;\n // \u7b49\u5f85 2s\n yield return 2f;\n // \u64ad\u653e title_ping \u97f3\u6548, \u5982\u679c\u4f60\u60f3\u4e0d\u8d77\u6765\u7684\u8bdd\u4f60\u53ef\u4ee5\u53bb\u4ed4\u7ec6\u542c\u542c\n // \u5728\u851a\u84dd\u6e90 fmod \u5de5\u7a0b\u6587\u4ef6\u91cc\u5b83\u7684\u97f3\u9891\u6587\u4ef6\u4f4d\u4e8e music/kuraine/mus_lvl0_titleping_oneshot.ogg\n Audio.SetMusic(\"event:/music/lvl0/title_ping\");\n // \u7ee7\u7eed\u7b49\u5f85 2s\n yield return 2f;\n // \u5411\u573a\u666f\u4e2d\u52a0\u5165\u663e\u793a \"\u4f60\u80fd\u505a\u5230.\" \u8fd9\u53e5\u8bdd\u7684\u5b9e\u4f53\n endingText = new PrologueEndingText(false);\n Scene.Add(endingText);\n\n // \u83b7\u53d6\u5173\u5361\u4e2d\u63a7\u5236\u524d\u666f\u96ea\u548c\u80cc\u666f\u96ea\u7684\u5b9e\u4f53\n Snow bgSnow = level.Background.Get<Snow>();\n Snow fgSnow = level.Foreground.Get<Snow>();\n // \u987a\u4fbf\u52a0\u5165\u9ad8\u5206\u8fa8\u7387\u7684\u96ea, \u4e5f\u5373 ui \u5c42\u4e0a\u7684\u96ea (HiresSnow = High resolution snow)\n level.Add(level.HiresSnow = new HiresSnow(0.45f));\n // \u4f46\u662f\u5148\u628a\u900f\u660e\u5ea6\u8c03\u6210 0, \u7528\u6765\u7b49\u4f1a\u6e10\u53d8\n level.HiresSnow.Alpha = 0f;\n\n // \u5f00\u59cb\u6e10\u53d8\u4e09\u5c42\u96ea\u7684\u900f\u660e\u5ea6\n float ease = 0f;\n while (ease < 1f)\n {\n ease += Engine.DeltaTime * 0.25f;\n float eased = Ease.CubeInOut(ease);\n if (fgSnow != null)\n fgSnow.Alpha -= Engine.DeltaTime * 0.5f;\n if (bgSnow != null)\n bgSnow.Alpha -= Engine.DeltaTime * 0.5f;\n level.HiresSnow.Alpha = Calc.Approach(level.HiresSnow.Alpha, 1f, Engine.DeltaTime * 0.5f);\n // \u4e8e\u6b64\u540c\u65f6 \"\u4f60\u80fd\u505a\u5230.\" \u8fd9\u53e5\u8bdd\u4e5f\u6162\u6162\u964d\u4e0b\u6765\n endingText.Position = new Vector2(960f, 540f - 1080f * (1f - eased));\n // \u6444\u50cf\u673a\u4e5f\u6162\u6162\u5411\u4e0a\u79fb\u52a8\n level.Camera.Y = level.Bounds.Top - 3900f * eased;\n yield return null;\n }\n // \u7ed3\u675f\u8fd9\u4e2a\u5267\u60c5\n EndCutscene(level);\n yield break;\n}\n
"},{"location":"trans/common2/","title":"Flag, Tag, Tracker","text":""},{"location":"trans/common2/#flag","title":"Flag","text":"\u5373\u4e00\u4e2a bool
\u72b6\u6001, \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7 string
\u6765\u533a\u5206\u4e0d\u540c\u7684 flag
, \u7528 Dictionary<string, bool>
\u6765\u5b58\u50a8 flag
\u7684\u72b6\u6001(\u8fd9\u6837\u53ef\u80fd\u597d\u7406\u89e3\u70b9), \u4ee5\u8ba9\u6211\u4eec\u5728\u67d0\u4e2a\u65f6\u673a\u505a\u67d0\u4ef6\u4e8b( \u8be6\u60c5\u89c1 Session
).
\u7136\u540e Everest \u5df2\u7ecf\u4e3a\u6211\u4eec\u63d0\u4f9b\u4e86\u4e00\u4e2a\u7b80\u5355\u7684 FlagTrigger
, \u8ba9 player
\u78b0\u5230 trigger
\u7684\u65f6\u5019\u89e6\u53d1\u67d0\u4e2a flag
, \u63a5\u7740\u6211\u4eec\u5c31\u53ef\u4ee5\u5728 Session
\u91cc\u8bfb\u53d6, \u8fd9\u6837\u5bf9\u4e8e\u975e\u5e38\u7b80\u5355\u7684\u9700\u6c42\u5c31\u4e0d\u9700\u8981\u81ea\u5df1\u5199\u4e2a trigger
\u4e86, \u4f8b\u5982 \"player
\u78b0\u5230 FlagTrigger
\u5c31\u8df3\u4e00\u4e0b\" \u8fd9\u4e2a\u9700\u6c42: \u6211\u4eec\u53ef\u4ee5\u4e0d\u65ad\u8bfb\u53d6 flag
, \u5982\u679c\u62ff\u5230 true
\u5c31\u5220\u9664 flag
\u5e76\u6267\u884c\u8df3\u7684\u52a8\u4f5c.
"},{"location":"trans/common2/#tagbittag","title":"Tag(BitTag)","text":"\u7b80\u5355\u7406\u89e3
Global
: \u6c38\u4e45\u4fdd\u7559(\u6b7b\u4ea1\u4e0d\u9500\u6bc1) Persistent
: \u5207\u677f\u4fdd\u7559(\u6b7b\u4ea1\u9500\u6bc1) HUD
: \u753bUI\u7684,\u5207\u677f\u540e\u9500\u6bc1 TransitionUpdate
: \u5207\u677f\u8fc7\u7a0b\u7ee7\u7eed\u66f4\u65b0(\u6216\u8005\u8bf4\u65f6\u95f4\u6d41\u901f\u6b63\u5e38), \u5207\u677f\u540e\u9500\u6bc1 FrozenUpdate
: \u5728 Frozen \u72b6\u6001\u4e0b\u8fd8\u80fd\u66f4\u65b0\u7684\u5b9e\u4f53 PauseUpdate
: \u5728 Pause \u72b6\u6001\u4e0b\u8fd8\u80fd\u66f4\u65b0\u7684\u5b9e\u4f53 Note
\u6ce8\u610f\u6709\u4e9b\u6807\u7b7e\u53ea\u662f\u6682\u65f6\u4f7f\u7528, \u6240\u4ee5\u6211\u4e00\u822c\u4f1a\u7528\"xxx\u7684\u65f6\u5019\"\u6765\u63cf\u8ff0, \u5217\u51fa\u6765\u7684\u5b9e\u4f53\u4e5f\u4ec5\u4ec5\u662f\u8ddf\u8fd9\u4e2a\u6807\u7b7e\u6709\u5173, \u7531\u4e8e\u5b9e\u4f53\u5f88\u591a\u5f88\u6742\u4f1a\u6709\u758f\u6f0f, \u5982\u679c\u4f60\u89c9\u5f97\u54ea\u91cc\u4e0d\u5bf9\u6216\u8005\u611f\u5174\u8da3, \u76f4\u63a5\u53bb\u770b\u4ee3\u7801\u5c31\u597d\u4e86
"},{"location":"trans/common2/#global","title":"Global","text":"\u8868\u793a\u8be5 Entity \u662f\u5426\u662f\u5168\u5c40\u7684, \u4e00\u4e2a\u975e\u5168\u5c40\u5b9e\u4f53\u5728\u5173\u5361\u91cd\u8bd5\u540e\u4f1a\u6d88\u5931, \u5168\u5c40 Tag \u53ef\u4ee5\u907f\u514d\u8fd9\u4ef6\u4e8b, \u901a\u5e38\u5168\u5c40 Tag \u6700\u5e38\u89c1\u7684\u7528\u6cd5\u662f\u548c HUD \u7ed3\u5408\u5728\u4e00\u8d77, \u8fd9\u6837\u4f60\u5c31\u62e5\u6709\u4e86\u4e00\u4e2a\u5728\u6e38\u620f\u5185\u6301\u4e45\u7684 ui \u90e8\u4ef6\u4e86
Note
\u7531\u4e8e\u672c\u8d28\u4e0a\u53ea\u662f\u5728\u8be5\u5378\u8f7d\u7684\u65f6\u5019\u53d6\u6d88\u5378\u8f7d, \u6240\u4ee5\u5982\u679c\u518d\u6b21\u52a0\u8f7d\u573a\u666f, \u5bf9\u8c61\u4f9d\u65e7\u4f1a\u88abnew\u4e00\u4e2a, \u6240\u4ee5\u8981\u4e48\u662f\u5728new\u7684\u65f6\u5019\u903b\u8f91\u4e0a\u5224\u65ad(\u53c2\u8003CassetteBlockManager
)\u4ee5\u6d88\u9664\u9519\u8bef(\u6709\u70b9\u5355\u4f8b\u7684\u611f\u89c9), \u8981\u4e48\u662f\u7528\u4ee3\u7801\u5728Scene\u4e0a\u624b\u52a8\u6dfb\u52a0\u4e00\u4e2a\u7c7b\u4f3cManager\u7684\u4e1c\u897f, \u7531\u4e8e\u5176\u4ed6\u573a\u666f\u539f\u5148\u6ca1\u6709\u6446\u653e\u4f60\u8fd9\u4e2a\u5bf9\u8c61, \u81ea\u7136\u4e5f\u4e0d\u4f1a\u88ab\u52a0\u8f7d\u591a\u6b21
\u4f8b\u5982 \u80cc\u666f\u7816BackgroundTiles
\u8282\u594f\u5757\u7ba1\u7406\u5668CassetteBlockManager
(\u4f60\u4f1a\u53d1\u73b0\u8282\u594f\u9762\u91cd\u751f\u540e\u8f74\u6709\u70b9\u602a, \u56e0\u4e3amanager\u4e0d\u4f1areset) 4a\u73a9\u5bb6\u88ab\u955c\u5b50\u5438\u5165\u7684cutsceneCS04_MirrorPortal
(\u56e0\u4e3a\u80cc\u666f\u662f\u4e2a\u9ed1\u573a\u8fc7\u6e21, \u73a9\u5bb6\u53c8\u4f20\u9001\u4e86(\u6216\u8005\u8bf4\u5728\u53e6\u4e00\u4e2aroom\u91cd\u751f\u4e86), \u6240\u4ee5\u8981\u7528global\u6807\u7b7e\u624d\u80fd\u4fdd\u6301fadeout) 7a\u7ed3\u5c3e\u7684cutscene(\u540c\u4e0a)CS07_Credits
\u88abDetachStrawberryTrigger
(\u5982\u679cGlobal\u5c5e\u6027\u5f00\u4e86\u7684\u8bdd)\u4f5c\u7528\u7684Follower
\u4e3a\u7164\u7403\u7ed8\u5236\u63cf\u8fb9\u7684DustEdges
6a\u4e0b\u843d\u9762\u7684\u901f\u5ea6\u7ebfFallEffects
\u5403\u5fc3\u5f39\u51fapoem\u540e\u5e95\u4e0b\u7684\u9ed1\u8272panelFormationBackdrop
Pause\u754c\u9762\u4e0b\u65b9\u7684\u8349\u8393\u8bb0\u5f55 GameplayStats
\u4f5c\u7528\u4e8eGlassBlock
\u7684GlassBlockBg
(\u5b98\u56fe\u597d\u50cf`\u6ca1\u51fa\u73b0\u8fc7) Grab\u6a21\u5f0f\u4e3aToggle\u7684\u65f6\u5019\u7684\u8f85\u52a9\u663e\u793a\u5bf9\u8c61GrabbyIcon
\u4f1a\u5728\u7b2c8\u7ae0cold\u6a21\u5f0f\u4e0b\u5728core\u524d\u666f\u7816\u4e0a\u9644\u4e0a\u51b0\u971c\u7684IceTileOverlay
\u7ed8\u5236\u7535\u7f51\u91cc\u7684\u95ea\u7535LightningRenderer
\u7ed8\u5236\u955c\u5b50\u4e0a\u7684\u753b\u9762MirrorSurfaces
3a\u548cTheo\u5bf9\u8bdd\u5b8c\u540eTheo\u722c\u8fdb\u7ba1\u9053\u540e\u53ef\u4ee5\u5728\u9694\u58c1\u770b\u89c1NPC03_Theo_Escaping
OldSiteChaseMusicHandler
\u51b2\u523a\u8f85\u52a9\u6307\u793a\u5668PlayerDashAssist
\u4fdd\u5b58\u5e76\u9000\u51fa\u65f6\u53f3\u4e0b\u89d2\u7684IconSaveLoadIcon
\u7ba1\u7406Barrier\u7684\u5916\u90e8\u6e32\u67d3(\u91cc\u9762\u7c92\u5b50\u662fBarrier\u81ea\u5df1\u7684)SeekerBarrierRenderer
\u65b0\u6d6a\u5728\u7684\u65f6\u5019RGB\u5206\u79bb\u6548\u679cSeekerEffectsController
\u524d\u666f\u7816SolidTiles
\u8ba1\u65f6\u5668SpeedrunTimerDisplay
TempleEndingMusicHandler
\u8349\u8393\u8ba1\u6570TotalStrawberriesDisplay
\u6b8b\u5f71TrailManager
\u548cTrailManager.Snapshot
"},{"location":"trans/common2/#persistent","title":"Persistent","text":"\u8868\u793a\u9700\u8981\u6301\u4e45\u5316\u5728\u573a, \u5207\u677f\u4e0d\u5378\u8f7d\u7684\u5b9e\u4f53, \u6b7b\u4ea1\u4f1a\u5378\u8f7d, \u4e00\u822c\u5728Coroutine
\u91cc\u7528\u6765\u6682\u65f6\u4fdd\u5b58\u4e0b\u72b6\u6001
\u4f8b\u5982 birdNPC
\u6700\u540e\u4e00\u6b21\u98de\u8d70\u7684\u65f6\u5019 Booster
\u628aplayer\u5410\u51fa\u5207\u677f\u7684\u65f6\u5019 \u649e\u788eDashBlock
\u6389\u843d\u7684Debris
\u6240\u6709\u88abDetachStrawberryTrigger
(\u5e26\u91d1\u8349\u8393\u7684\u6708\u6885\u9762\u4f1a\u7528\u5230)\u89e3\u7ed1\u7684Follower
\u6240\u6709\u88ab\u73a9\u5bb6\u62fe\u8d77\u7684Follower
(Strawberry
, Key
\u7b49) \u6240\u6709\u88ab\u73a9\u5bb6\u62fe\u8d77\u7684Holdable
(TheoCrystal
, Glider(Jellyfish)
\u7b49) 7a 7b \u663e\u793a500m 1000m\u7684\u5b9e\u4f53HeightDisplay
LightningBreakerBox
\u7535\u7bb1\u88ab\u649e\u88c2\u7684\u65f6\u5019 MoonGlitchBackgroundTrigger
\u626b\u63cf\u7ebfGlitch\u89e6\u53d1\u7684\u65f6\u5019(\u8bb0\u5f97\u628aCelesteTAS\u78b0\u649e\u7bb1\u548c\u5149\u654f\u6a21\u5f0f\u5173\u4e86, \u4e0d\u7136\u770b\u4e0d\u5230(\u4e50)) Player\u81ea\u8eab(\u663e\u800c\u6613\u89c1) \u7b2c\u516b\u7ae0\u7684SandwichLava
\u7194\u5ca9\u971c\u51bb\u5939\u5fc3 SoundEmitter
(\u611f\u89c9\u5c31\u6bd4\u76f4\u63a5\u7528Audio\u591a\u4e86\u4e2a\u5207\u677f\u9500\u6bc1) StrawberryPoints
\u8349\u8393\u5f97\u5206\u70b9\u6570 \u7b2c\u4e03\u7ae0\u649e\u788eSummitGem
\u65f6\u7684\u95ea\u5149 TalkComponentUI
(\u73a9\u5bb6\u9760\u8fd1\u65f6\u5f39\u51fa\u7684prompt, \u4f8b\u5982\u671b\u8fdc\u955cLookout
\u4e0a\u7684\u90a3\u4e2a) (\u4f46\u5b83\u53c8\u662f\u7531TalkComponent
\u63a7\u5236\u7684, \u6240\u4ee5\u597d\u50cf\u5b83\u7684persistent\u6ca1\u7528?) "},{"location":"trans/common2/#hud","title":"HUD","text":"\u5373\u662f\u5426\u662f UI \u5c42, \u6b64\u9879\u5c31\u4f1a\u6539\u53d8 Entity.Render
\u7684\u7ed8\u5236\u903b\u8f91(\u6ce8\u610fPosition
\u4e0d\u53d8), \u4f7f\u7ed8\u5236\u5750\u6807\u57fa\u4e8e\u5c4f\u5e55\u5750\u6807(1920 x 1080
)\u800c\u4e0d\u662f\u4e16\u754c\u5750\u6807\u7ed8\u5236, \u5e76\u8c03\u6574\u7ed8\u5236\u987a\u5e8f\u4f7f\u5176\u7f6e\u4e8e\u9876\u5c42
Note
\u672c\u8d28\u4e0a\u9009\u62e9HUD Tag\u540e\u6e38\u620f\u4f1a\u5728\u7ed8\u5236\u65f6\u901a\u8fc7\u77e9\u9635\u628a\u5750\u6807\u4ece\u5c4f\u5e55\u7a7a\u95f4\u8f6c\u5316\u5230\u4e16\u754c\u7a7a\u95f4(\u53c2\u8003HiresRenderer
, \u7ebf\u6027\u4ee3\u6570\u6700\u6709\u7528\u7684\u4e00\u96c6~)
\u4f8b\u5982 \u9e1f\u7684\u6559\u7a0b\u6846BirdTutorialGui
6a\u7684\u6df1\u547c\u5438~BreathingMinigame
\u5403\u5230\u78c1\u5e26b\u9762\u89e3\u9501\u753b\u9762UnlockedBSide UnlockedRemixDisplay
2a Awake\u6700\u4e0a\u9762\u7684\u8bd7CS02_Journal.PoemPage
3a(11-a) \u7684\u5012\u95ed\u901a\u77e5CS03_Memo.MemoPage
6a \u7684\u548c\u597d\u62b1\u62b1CS06_BossEnd
6a \u7bdd\u706b\u524d\u548c\u7684Theo\u5bf9\u8bdd\u9009\u9879CS06_Campfire.Option
7a\u901a\u5173\u7684\u5236\u4f5c\u4eba\u5458\u540d\u5355CS07_Credits
\u5c3e\u58f0\u91cc\u7684\u8349\u8393\u86cb\u7cd5CS08_Ending
9a\u5c3e\u58f0 CS10_Ending
\u6536\u96c6\u5b8c\u8349\u8393\u7c7d\u7684\u5408\u6210\u52a8\u753b CSGEN_StrawberrySeeds
(\u4f46\u8fd9\u4e2a\u7c7b\u672c\u8eab\u5e76\u6ca1\u6709render, \u6240\u4ee5\u597d\u50cf\u6ca1\u7528?) \u542f\u52a8\u6e38\u620f\u65f6\u4e00\u5f00\u59cb\u51fa\u73b0\u7684credits \u548c logoGameLoader.handler
Pause\u754c\u9762\u4e0b\u65b9\u7684\u8349\u8393\u8bb0\u5f55 GameplayStats
7a 7b \u663e\u793a500m 1000m\u7684\u5b9e\u4f53HeightDisplay
HudRenderer
(\u7ba1UI\u663e\u9690\u7684) B\u9762\u5165\u573a\u63d2\u78c1\u5e26BSideTitle
\u5f00\u955c\u753b\u9762Lookout.Hud
\u7eaa\u5ff5\u7891\u6587\u5b57MemorialText
6a badeline\u8ff7\u4f60\u5bf9\u8bdd\u6846MiniTextbox
\u5404\u79cdOui, \u5404\u79cdpanel \u5403\u5fc3\u540e\u663e\u793a\u7684\u6587\u5b57Poem
\u660e\u4fe1\u7247Postcard
prologue\u7ed3\u5c3ePrologueEndingText
(You can do this!) \u81ea\u62cd\u7167Selfie
\u8ba1\u65f6\u5668SpeedrunTimerDisplay
\u8349\u8393\u8ba1\u6570TotalStrawberriesDisplay
TalkComponentUI
\u5bf9\u8bdd\u6846Textbox
\u51cc\u6ce2\u5fae\u6b65, \u5feb\u4e50\u7684\u821e\u6b65~WaveDashPresentation
"},{"location":"trans/common2/#transitionupdate","title":"TransitionUpdate","text":"\u5207\u677f\u8fc7\u7a0b\u7ee7\u7eed\u66f4\u65b0(\u6216\u8005\u8bf4\u65f6\u95f4\u6d41\u901f\u6b63\u5e38), \u5207\u677f\u540e\u9500\u6bc1)(\u6ce8\u610f: \u6807\u7b7e\u53ef\u4f5c\u7528\u4e8e\u8981\u88abload\u7684\u6216\u8005\u662f\u8981\u88abunload\u7684\u5bf9\u8c61
\u4f8b\u5982 \u7b2c\u4e03\u7ae0\u7ba1\u4e0a\u5347\u5207\u677f\u7684AscendManager
(\u597d\u50cf\u5c31\u5bf9\u5e94Loenn\u91cc\u7684SummitBackgroundManager
) 6a\u4ece\u4e3b\u4e16\u754ccutscene\u5207\u52306a\u7b2c\u4e8c\u7ae0\u6240\u7528\u7684\u9ed1\u573a\u8fc7\u6e21BackgroundFadeIn
6a\u7011\u5e03BigWaterfall
9a\u7684BirdPath
\u7bdd\u706bBonfire
\u7ea2(\u7eff)\u6ce1\u6ce1Booster
\u7b2c\u56db\u7ae0\u5404\u79cd\u65d7\u5e1cCliffsideWindFlag
3a\u6536\u62fe\u6742\u7269ClutterAbsorbEffect
3a\u6536\u62fe\u5b8c\u6742\u7269\u628a\u95e8\u5835\u4f4f\u7684\u90a3\u4e2a\u679c\u51bbClutterDoor
\u5706\u523aCrystalStaticSpinner
DustEdges
\u706b\u7403FireBall
\u5ca9\u6d46\u5899FireBarrier
GameplayStats
GrabbyIcon
\u5c3e\u58f0\u53f3\u4fa7\u9e1f\u5de2InvisibleBarrier
\u6bd4\u59826a\u84dd\u5fc3\u623f\u5de6\u8fb9\u7684\u5de6\u8fb9\u90a3\u4e2a\u623f\u95f4\u91cc\u7684\u4e00\u7f15\u7f15\u5149LightBeam
\u6539\u623f\u95f4\u706f\u5149\u7684\u900f\u660e\u5ea6LightFadeTrigger
LightningRenderer
\u9501\u5757\u88ab\u89e3\u9501\u540eLockBlock
MiniTextbox
9a\u5c0f\u874c\u86aaMoonCreature
\u79fb\u52a8\u5feb\u649e\u505c\u540e\u6389\u843d\u7684\u788e\u7247MoveBlock.Debris
NPC03_Theo_Vents
5a\u7a7f\u8fc7\u955c\u5b50\u4ece\u4e0a\u9762\u843d\u4e0b\u6765\u540e\u7684badelineNPC05_Badeline
OldSiteChaseMusicHandler
pico-8\u6e38\u620f\u673aPicoConsole
6a\u89e6\u624bReflectionTentacles
SandwichLava
SeekerBarrierRenderer
SoundEmitter
SpeedrunTimerDisplay
\u8349\u8393\u6536\u96c6\u7684\u65f6\u5019Strawberry
StrawberryPoints
5a\u5c3e\u58f0\u7ba1\u97f3\u4e50\u7684TempleEndingMusicHandler
TheoTheoCrystal
\u521d\u89c1Theo\u6c34\u6676\u7684\u5e95\u5ea7TheoCrystalPedestal
TotalStrawberriesDisplay
\u4f20\u9001\u5e26WallBooster
\u6c34Water
\u7011\u5e03WaterFall
9a\u6559\u51cc\u6ce2\u7684\u90a3\u4e2a\u5821WaveDashTutorialMachine
\u7b2c4\u7ae0\u7ba1\u98ce\u529b\u548c\u98ce\u5411\u7684WindController
"},{"location":"trans/common2/#frozenupdate","title":"FrozenUpdate","text":"Frozen\u53ea\u662fLevel\u91cc\u7684\u4e00\u4e2a\u51bb\u7ed3\u72b6\u6001(\u6216\u8005\u8bf4\u4e00\u4e2abool\u53d8\u91cf, \u800c\u4e0d\u662f\u771f\u7684\u8ba9\u6e38\u620ffreeze\u7684\u90a3\u4e2a\u51bb\u7ed3\u5e27)
\u4f8b\u5982 \u5403\u6c34\u6676\u6e85\u5c04\u7684\u767d\u7403AbsorbOrb
\u78c1\u5e26Cassette
\u8349\u8393\u7c7d\u5408\u6210\u52a8\u753bCSGEN_StrawberrySeeds
FormationBackdrop
\u89e3\u95011a\u6c34\u6676\u4e4b\u5fc3\u8fc7\u7a0bForsakenCitySatellite
\u6c34\u6676\u4e4b\u5fc3HeartGem
\u6c34\u6676\u4e4b\u5fc3\u4e0a\u7684\u6587\u5b57Poem
\u4fdd\u5b58\u5e76\u9000\u51fa\u65f6\u53f3\u4e0b\u89d2\u7684IconSaveLoadIcon
StrawberryPoints
StrawberrySeed
Textbox
\u6b8b\u5f71TrailManager.Snapshot
"},{"location":"trans/common2/#pauseupdate","title":"PauseUpdate","text":"\u5728Pause\u72b6\u6001\u4e0b\u8fd8\u80fd\u66f4\u65b0\u7684\u5b9e\u4f53
\u4f8b\u5982 Cassette.UnlockedBSide
(\u7531\u4e8e\u5b83\u662f\u7531Cassette\u63a7\u5236\u7684, \u6240\u4ee5\u76f8\u5f53\u4e8e\u81ea\u5e26\u4e00\u4e2aFrozenUpdate, \u4f46\u662f\u5b83\u5728\u88ab\u8c03\u7528\u524dPause\u5df2\u7ecf\u88ab\u9501\u4f4f\u4e86, \u6240\u4ee5\u8fd9\u4e2a\u72b6\u6001\u8c8c\u4f3c\u767d\u52a0\u4e86\ud83e\udd14) \u5c3e\u58f0CS08_Ending
GameplayStats
GrabbyIcon
LanguageSelectUI
1a\u5c3e, 2a\u5934\u7684\u7eaa\u5ff5\u7891Memorial
(\u7528\u5230\u6807\u7b7e\u7684\u5730\u65b9\u4e3b\u8981\u662f2a\u7eaa\u5ff5\u7891\u4e0a\u7684\u4e71\u7801) MemorialText
(\u56e0\u4e3apaused\u7684\u65f6\u5019\u4e0d\u80fd\u663e\u793a) OuiChapterSelectIcon
OuiFileSelectSlot
PicoConsole
SaveLoadIcon
SpeedrunTimerDisplay
Textbox
\u5e94\u8be5\u662f\u5f00\u59cb\u83dc\u5355TextMenu
TotalStrawberriesDisplay
UnlockedPico8Message
ViewportAdjustmentUI
"},{"location":"trans/common2/#tracker","title":"Tracker","text":"Tracker
\u7531 Scene
\u7ba1\u7406, \u5728\u6211\u4eec\u4f7f\u7528 Scene.Add(new Entity())
\u7684\u65f6\u5019, \u4f1a\u901a\u8fc7 EntityList
\u5411 Tracker
\u52a0\u5165 Entity
(\u5f53\u7136\u8fd8\u6709 Component
, \u4f46\u5728\u540e\u9762\u53ea\u63d0\u53ca Entity
). \u6240\u6709\u9700\u8981\u88ab Tracked
(\u6216\u8005\u8bf4\u88ab\u8bb0\u5f55) \u7684 Entity
\u9700\u8981\u52a0\u4e0a [Tracked]
\u7279\u6027. \u4f60\u8fd8\u53ef\u4ee5\u901a\u8fc7 [TrackedAs(typeof(xxx))]
\u7279\u6027\u8ba9\u4e00\u4e2a A
\u7c7b\u578b\u88ab\u540c\u65f6\u5f53\u4f5c B
\u7c7b\u578b, \u8fd9\u6837\u5c31\u53ef\u4ee5\u4f7f\u7528 Scene.Tracker.GetEntity<B>()
\u6765\u540c\u65f6\u62ff\u5230 A
\u548c B
\u4e86. \u8fd9\u4e2a\u7279\u6027\u4f5c\u4e3a Everest \u7684\u4e00\u4e2a\u62d3\u5c55\u5b58\u5728.
"},{"location":"trans/common3/","title":"Sprite, Image","text":"Sprite \u4f60\u53ef\u4ee5\u628a\u5b83\u5f53\u4f5c\u7ba1\u52a8\u753b\u7684
Image \u4f60\u53ef\u4ee5\u628a\u5b83\u5f53\u4f5c\u7ba1\u56fe\u7247\u7684
"},{"location":"trans/common3/#_1","title":"\u7ee7\u627f\u94fe","text":"Sprite
-> Image
-> GraphicsComponent
-> Component
, \u63a5\u4e0b\u6765\u4f1a\u9010\u4e00\u8bb2\u89e3
"},{"location":"trans/common3/#graphicscomponent","title":"GraphicsComponent","text":"\u63d0\u4f9b\u4e86\u6700\u57fa\u7840\u7684\u6e32\u67d3\u56fe\u7247\u6240\u9700\u7684\u4fe1\u606f\u548c\u5e38\u7528\u65b9\u6cd5\u5982: \u4f4d\u7f6e, \u65cb\u8f6c, \u7f29\u653e, \u951a\u70b9, \u989c\u8272\u7cfb\u6570, \u662f\u5426\u7ffb\u8f6c\u56fe\u50cf, \u63cf\u8fb9\u7b49
\u951a\u70b9
\u7b80\u5355\u7406\u89e3\u5c31\u662f\u4f60\u5728\u4e00\u5f20\u7167\u7247\u4e0a\u63d2\u4e86\u6839\u56fe\u9489, \u7167\u7247\u7684\u5e73\u79fb, \u65cb\u8f6c, \u7f29\u653e\u90fd\u662f\u57fa\u4e8e\u8fd9\u4e2a\u56fe\u9489\u7684
\u7c7b\u7684\u5c5e\u6027\u5b57\u6bb5\u65b9\u6cd5\u8bf4\u660e Vector2 Position: \u56fe\u7247\u76f8\u5bf9\u4e8eEntity.Position
\u7684\u4f4d\u7f6e Vector2 Origin: \u56fe\u7247\u7684\u951a\u70b9\u4f4d\u7f6e(\u4e5f\u5c31\u662f\u56fe\u7247\u7684\u65cb\u8f6c\u7f29\u653e\u5e73\u79fb\u57fa\u4e8e\u56fe\u7247\u7684\u54ea\u4e2a\u76f8\u5bf9\u4f4d\u7f6e) Vector2 Scale: \u56fe\u7247\u7684\u7f29\u653e float Rotation: \u56fe\u7247\u7684\u65cb\u8f6c(\u4ee5\u5f27\u5ea6\u4e3a\u5355\u4f4d\u987a\u65f6\u9488\u65cb\u8f6c(\u867d\u7136\u611f\u89c9\u9006\u65f6\u9488\u66f4\u7b26\u5408\u76f4\u89c9\u70b9)) Color Color: \u56fe\u7247\u7684\u989c\u8272\u7cfb\u6570(\u6e32\u67d3\u65f6\u4f1a\u5728\u539f\u6765\u56fe\u7247\u57fa\u8272\u7684\u57fa\u7840\u4e0a\u4e58\u4e0a\u8fd9\u4e2a\u503c, \u6240\u4ee5\u4e0d\u8981\u60f3\u7740\u7528\u767d\u8272\u5f53\u7cfb\u6570\u56fe\u7247\u5c31\u53d8\u6210\u7eaf\u767d\u7684\u4e86) SpriteEffects Effects: \u662f\u5426\u6c34\u5e73(\u7ad6\u76f4)\u53cd\u8f6c\u56fe\u7247 float X, Y: Position
bool FlipX, FlipY: \u5bf9Effects
\u7684\u5c01\u88c5 Vector2 RenderPosition: \u5b9e\u9645\u7684\u6e32\u67d3\u4f4d\u7f6e Vector2 RenderPosition: \u5b9e\u9645\u7684\u6e32\u67d3\u4f4d\u7f6e void DrawOutline(Color color, int offset = 1): \u628a\u81ea\u8eab\u5f80\u4e0a\u4e0b\u5de6\u53f3\u5e73\u79fboffset
, \u5e76\u4ee5color
\u4e3a\u989c\u8272\u7cfb\u6570\u901a\u8fc7Render
\u6765\u7ed8\u5236\u63cf\u8fb9 void DrawSimpleOutline(): offset
\u4e3a1\u4e2a\u5355\u4f4d\u7684\u9ed1\u8272\u63cf\u8fb9 "},{"location":"trans/common3/#image","title":"Image","text":"\u5bf9 GraphicsComponent
\u7684\u8fdb\u4e00\u6b65\u5c01\u88c5, \u4e3b\u8981\u63d0\u4f9b\u4e86 Texture
\u7eb9\u7406(\u56fe\u7247)\u76f8\u5173\u4fe1\u606f, \u6b64\u65f6\u5c31\u53ef\u4ee5\u6839\u636e\u4e4b\u524d\u7684\u4fe1\u606f\u6e32\u67d3\u51fa\u4e00\u5f20\u56fe\u7247\u4e86, \u5c31\u50cf\u4f60\u4e4b\u524d\u5728 PassByRefill
\u90a3\u8282\u505a\u7684\u90a3\u6837
\u7c7b\u7684\u5c5e\u6027\u5b57\u6bb5\u65b9\u6cd5\u8bf4\u660e MTexture Texture: \u6750\u8d28(\u4f60\u53ef\u4ee5\u628a\u5b83\u5f53\u6210\u4e00\u5f20png
\u56fe\u7247) virtual float Width, Height: \u56fe\u7247\u7684\u5bbd(\u9ad8) Image SetOrigin(float x, float y): \u8bbe\u7f6e\u951a\u70b9 Image CenterOrigin(): \u8bbe\u7f6e\u951a\u70b9\u5230\u4e2d\u5fc3(\u6bd4\u8f83\u5e38\u7528\u7684\u60c5\u51b5, \u6240\u4ee5\u4f60\u89c1\u5230\u7684\u951a\u70b9\u5927\u591a\u6570\u662f\u4f4d\u4e8e\u5341\u5b57\u56db\u5bab\u683c\u4e0a\u76849\u4e2a\u70b9) Image JustifyOrigin(Vector2 at): \u5355\u4f4d\u5316\u7684\u951a\u70b9\u5750\u6807(\u8303\u56f4\u662fVector2.Zero ~ Vector2.One
)( \u8fd9\u6837\u5f53\u6211\u4eec\u9700\u8981\u628a\u951a\u70b9\u8bbe\u7f6e\u5230\u4e2d\u5fc3\u7684\u65f6\u5019\u5c31\u4e0d\u9700\u8981\u7528new Vector2(Width, Height) / 2
\u4e86, \u76f4\u63a5\u7528new Vector2(0.5f, 0.5f)
\u5373\u53ef) SetColor(Color color): \u8bbe\u7f6eColor\u989c\u8272 "},{"location":"trans/common3/#sprite","title":"Sprite","text":"\u5bf9 Image
\u7684\u8fdb\u4e00\u6b65\u5c01\u88c5, \u63d0\u4f9b\u4e86\u5bf9\u52a8\u753b\u7684\u7ba1\u7406(\u4e00\u8fde\u4e32\u56fe\u7247\u5f62\u6210\u4e00\u4e2a\u5e27\u52a8\u753b, \u518d\u7528 id
\u5206\u7ec4, \u901a\u8fc7\u52a8\u753b\u72b6\u6001\u673a\u5b9e\u73b0\u52a8\u753b\u95f4\u7684\u8df3\u8f6c\u6216\u662f\u81ea\u8eab\u7684 loop
)
\u7c7b\u7684\u5c5e\u6027\u5b57\u6bb5\u65b9\u6cd5\u8bf4\u660e \u91cc\u9762\u6709\u4e00\u5c42Animation
\u7c7b, \u662f\u5bf9\u52a8\u753b\u7684\u7b80\u5355\u5c01\u88c5
public class Animation\n{\n public Animation()\n {\n }\n\n public float Delay; // \u4e00\u5e27\u52a8\u753b\u6301\u7eed\u591a\u5c11\u79d2\n public MTexture[] Frames; // \u52a8\u753b\u7684\u56fe\u7247\u5e27\u5e8f\u5217\n public Chooser<string> Goto; // Chooser\u4f60\u53ef\u4ee5\u7406\u89e3\u4e3a\u5bf9\u5206\u5c42\u968f\u673a\u6570\u62bd\u6837\u7684\u5c01\u88c5, \u8fd9\u91cc\u662f\u64ad\u653e\u5b8c\u5f53\u524d\u52a8\u753b\u540e\u5e94\u8be5\u8df3\u5230\u54ea\u4e2a\u52a8\u753b(\u4f60\u53ef\u4ee5\u53bb\u4e86\u89e3\u4e0b\"\u52a8\u753b\u72b6\u6001\u673a\") \n}\n
float Rate: \u52a8\u753b\u64ad\u653e\u901f\u5ea6\u500d\u7387(\u8d1f\u6570\u610f\u5473\u7740\u5012\u653e) bool UseRawDeltaTime: \u662f\u5426\u4f7f\u7528\u73b0\u5b9e\u65f6\u95f4\u6d41\u901f(\u56e0\u4e3a\u6e38\u620f\u53ef\u4ee5\u8c03\u901f\u561b) Vector2? Justify: Origin
\u7684\u989d\u5916\u504f\u79fb\u91cf Action OnFinish: \u5f53\u524d\u52a8\u753b\u64ad\u653e\u5b8c\u5207\u6362\u5230\u5176\u4ed6\u52a8\u753b\u65f6\u5e72\u7684\u4e8b Action OnLoop: \u52a8\u753b\u5f00\u59cb\u5faa\u73af\u65f6\u5e72\u7684\u4e8b Action OnFrameChange: \u52a8\u753b\u64ad\u653e\u4e0b\u4e00\u5e27\u65f6\u5e72\u7684\u4e8b Action OnLastFrame: \u64ad\u653e\u5230\u5b8c\u52a8\u753b\u6700\u540e\u4e00\u5e27\u65f6\u5e72\u7684\u4e8b Action OnChange: \u52a8\u753b\u5207\u6362\u65f6\u5e72\u7684\u4e8b Atlas atlas: \u56fe\u7247\u6765\u6e90\u4e8e\u54ea\u4e2aAtlas string Path: \u56fe\u7247\u7684\u76f8\u5bf9\u8def\u5f84 Dictionary animations: \u52a8\u753b\u96c6\u5408 Dictionary Animations: animations
Sprite.Animation currentAnimation: \u5f53\u524d\u52a8\u753b float animationTimer: \u52a8\u753b\u5e94\u8be5\u5f00\u59cb\u591a\u4e45\u4e86(\u7528\u6765\u5904\u7406Delay
\u7684) int width: \u6240\u6709\u52a8\u753b\u5e27\u7684\u6700\u5927\u5bbd\u5ea6 int height: \u6240\u6709\u52a8\u753b\u5e27\u7684\u6700\u5927\u9ad8\u5ea6 Reset(Atlas atlas, string path): \u6062\u590d\u51fa\u5382\u8bbe\u7f6e, \u8bbe\u7f6e\u65b0\u7684\u56fe\u7247\u8def\u5f84 MTexture GetFrame(string animation, int frame): \u62ff\u5230\u5bf9\u5e94id
\u52a8\u753b\u7684\u67d0\u4e00\u5e27\u56fe\u7247 Vector2 Center: new Vector2(this.Width / 2f, this.Height / 2f)
override void Update(): \u6838\u5fc3\u903b\u8f91, \u5efa\u8bae\u662f\u81ea\u5df1\u770b\u6e90\u7801 void SetFrame(MTexture texture): \u8bbe\u7f6e\u5f53\u524d\u5e27\u56fe\u7247, \u987a\u4fbf\u8c03\u6574\u4e00\u4e0b\u951a\u70b9 void SetAnimationFrame(int frame): \u91cd\u7f6eanimationTimer
\u5e76\u628a\u5f53\u524d\u5e27\u8bbe\u7f6e\u4e3a\u52a8\u753b\u7684\u7b2cframe
\u5e27 void AddLoop(string id, string path, float delay, params int[] frames): \u6dfb\u52a0\u4e00\u4e2aid\u4e3aid
\u7684\u52a8\u753b, \u5e76\u63d0\u4f9b\u76f8\u5e94\u53c2\u6570, \u540c\u65f6\u628aGoto
\u6307\u5411id
\u5f62\u6210loop
, \u5982\u679c\u6709\u9700\u8981, \u8fd8\u53ef\u4ee5\u6307\u5b9a\u67d0\u4e9b\u5e27\u6765loop
void Add(string id, string path, float delay, params int[] frames): \u65e0loop
\u7248\u7684AddLoop MTexture[] GetFrames(string path, int[] frames = null): \u901a\u8fc7\u76f8\u5bf9\u8def\u5f84\u52a0\u8f7d\u56fe\u7247\u5e8f\u5217, \u7ed9\u4e86frames
\u5c31\u52a0\u8f7d\u5bf9\u5e94\u7684 ClearAnimations(): \u6e05\u7a7a\u6ce8\u518c\u7684\u52a8\u753b void Play(string id, bool restart = false, bool randomizeFrame = false): \u64ad\u653e\u5bf9\u5e94id
\u7684\u52a8\u753b(\u76f8\u540c\u7684\u4e0d\u64ad\u653e, \u9664\u975erestart
), \u82e5\u5f00\u542frandomizeFrame
, \u5219\u4f1a\u968f\u673a\u5316animationTimer
\u548cCurrentAnimationFrame
void PlayOffset(string id, float offset, bool restart = false): \u64ad\u653e\u5bf9\u5e94id
\u7684\u52a8\u753b\u5e76\u5feb\u8fdboffset
\u65f6\u95f4 IEnumerator PlayRoutine(string id, bool restart = false): \u64ad\u653e\u5bf9\u5e94id
\u7684\u52a8\u753b\u76f4\u5230\u52a8\u753b\u505c\u6b62 IEnumerator ReverseRoutine(string id, bool restart = false): \u64ad\u653e\u5bf9\u5e94id
\u7684\u52a8\u753b\u76f4\u5230\u52a8\u753b\u505c\u6b62 IEnumerator PlayUtil(): \u76f4\u5230\u5f53\u524d\u52a8\u753b\u505c\u6b62 void Reverse(string id, bool restart = false): \u5c06\u52a8\u753b\u64ad\u653e\u65b9\u5411\u8bbe\u7f6e\u4e3a\u9006\u5e8f\u64ad\u653e Has(string id): \u67e5\u770b\u662f\u5426\u6ce8\u518c\u8fc7id\u4e3aid
\u7684\u52a8\u753b void Stop(): \u7ed3\u675f\u64ad\u653e\u52a8\u753b bool Animating: \u662f\u5426\u53ef\u4ee5\u64ad\u653e\u52a8\u753b string CurrentAnimationID: \u5f53\u524d\u52a8\u753bid string LastAnimationID: \u4e0a\u4e00\u4e2a\u52a8\u753bid int CurrentAnimationFrame: \u64ad\u653e\u5230\u5f53\u524d\u52a8\u753b\u7684\u54ea\u4e00\u5e27\u4e86 int CurrentAnimationTotalFrames: \u5f53\u524d\u52a8\u753b\u603b\u5e27\u6570 override float Width, Height: this.width
, this.height
Sprite CreateClone(): \u521b\u5efa\u5f53\u524dSprite
\u7684\u4e00\u4e2a\u526f\u672c Sprite CloneInto(Sprite clone): \u521b\u5efa\u5f53\u524dSprite
\u7684\u4e00\u4e2a\u526f\u672c\u5230clone
\u4e2d void DrawSubrect(Vector2 offset, Rectangle rectangle): \u7ed8\u5236\u5f53\u524dSprite\u7684\u67d0\u4e2a\u533a\u57df(\u6709\u70b9\u8499\u7248\u7684\u611f\u89c9) void LogAnimations(): \u8f93\u51fa\u6ce8\u518c\u8fc7\u7684\u52a8\u753b\u4fe1\u606f \u63a5\u4e0b\u6765\u63d0\u4f9b\u4e00\u4e2a\u5c0f\u793a\u4f8b, \u6211\u4eec\u9700\u8981\u5148\u8c03\u6574\u4e00\u4e0b\u5148\u524d\u7684\u6587\u4ef6\u7ed3\u6784
- Atlases\n - Gameplay\n - \u4f60\u7684mod\u540d(\u8fd9\u91cc\u5e94\u8be5\u662fMyCelesteMod)\n - pass_by_refill\n - img00 // \u540e\u9762\u768400, 01\u5fc5\u987b\u6309\u987a\u5e8f\u6765, \u8fd9\u91cc\u7684img\u63d0\u4f9b\u4e86\u4e4b\u524d\u7684\u6539\u8272\u7248\u672c\n - img01\n
\u63a5\u7740\u6211\u4eec\u5728 PassByRefill
\u4e2d\u628a\u8ddf Image
\u6709\u5173\u7684\u90e8\u5206\u66ff\u6362\u4e3a Sprite
, \u7136\u540e\u4f60\u5c31\u5f97\u5230\u4e86\u4e00\u4e2a\u4e00\u79d2\u4e00\u53d8\u7684\u52a8\u753b\u5566! private Sprite sprite;\n\npublic PassByRefill(Vector2 position, int dashes)\n{\n // ...\n\n sprite = new Sprite(GFX.Game, \"\u4f60\u7684mod\u540d/pass_by_refill/\");\n Add(sprite);\n sprite.AddLoop(\"idle\", \"img\", 1);\n sprite.Play(\"idle\");\n}\n
"},{"location":"trans/debug/","title":"Debug\u8c03\u8bd5","text":"\u53ea\u8981\u5199\u7a0b\u5e8f\u5c31\u514d\u4e0d\u4e86bug, \u6240\u4ee5\u6211\u4eec\u9700\u8981\u5f3a\u6709\u529b\u7684debug\u624b\u6bb5
\u6700\u5e38\u89c1\u7684debug\u624b\u6bb5\u662f\u901a\u8fc7 Logger.Log()
, \u80fd\u89e3\u51b3\u5927\u90e8\u5206\u95ee\u9898, \u4f46\u5f53\u9879\u76ee\u505a\u5927, \u5d4c\u5957\u53d8\u591a, Logger
\u8f93\u51fa\u7684\u4fe1\u606f\u5df2\u7ecf\u6ee1\u8db3\u4e0d\u4e86\u6211\u4eec\u7684\u65f6\u5019(\u751a\u81f3\u6211\u4eec\u90fd\u4e0d\u77e5\u9053\u8fd9\u4e2a bug \u54ea\u513f\u6765\u7684), \u6211\u4eec\u4e00\u822c\u5c31\u8981\u4f7f\u7528\u65ad\u70b9\u6765\u8c03\u8bd5, \u6b65\u9aa4\u5982\u4e0b:
\u6253\u5f00\u851a\u84dd \u5728\u4f60\u7684IDE\u4e0adebug\u9009\u9879\u9644\u8fd1\u9009\u62e9\u9644\u52a0\u5230\u8fdb\u7a0b, \u7136\u540e\u9009\u62e9\u851a\u84dd \u63a5\u7740\u5728\u65c1\u8fb9\u6253\u4e0a\u7ea2\u7ea2\u7684\u65ad\u70b9 \u7136\u540e\u5f53 madeline
\u78b0\u5230 PassByRefill
\u7684\u65f6\u5019, \u6e38\u620f\u8fdb\u7a0b\u5c31\u4f1a\u88ab\u9501\u4f4f, \u63a5\u7740\u4f60\u53ef\u4ee5\u901a\u8fc7\u6b65\u8fdb, \u6b65\u5165, \u6b65\u51fa\u7b49\u65b9\u5f0f\u8fdb\u884c\u8c03\u8bd5, \u83b7\u53d6\u60f3\u8981\u7684\u4fe1\u606f \u8c03\u8bd5\u5b8c\u6210\u540e, \u4f60\u53ef\u4ee5\u76f4\u63a5\u505c\u6b62\u8c03\u8bd5, \u6216\u8005\u628a\u65ad\u70b9\u70b9\u6389\u7136\u540e\u70b9\u51fb\"\u6062\u590d\u7a0b\u5e8f\u8fd0\u884c\", \u4e4b\u540e\u518d\u6253\u4e0a\u65ad\u70b9\u7ee7\u7eed\u8c03\u8bd5 "},{"location":"trans/ec_common/","title":"\u66f4\u591a EC","text":"\u90a3\u4e48\u7ecf\u8fc7\u524d\u9762\u7684\u9605\u8bfb, \u76f8\u4fe1\u4f60\u5df2\u7ecf\u4e86\u89e3\u5230\u4e86\u4e00\u4e9b\u5f88\u5f88\u5f88\u57fa\u672c\u7684\u77e5\u8bc6, \u90a3\u4e48\u4ece\u8fd9\u4e00\u7ae0\u5f00\u59cb\u5c31\u662f\u4e00\u4e9b\u96f6\u788e\u4e14\u6742\u4e71\u7684\u4e1c\u897f\u4e86. \u987a\u4fbf\u6240\u4ee5, \u6211\u8fd8\u662f\u5f88\u5efa\u8bae\u4f60\u53bb\u591a\u9605\u8bfb\u4e00\u4e0b\u539f\u7248\u7684\u4ee3\u7801\u4ee5\u53ca\u4e00\u4e9b\u5e38\u89c1\u7b80\u5355Helper\u7684\u6e90\u7801, \u6bd5\u7adf\u6211\u81ea\u5df1\u90fd\u4e0d\u77e5\u9053\u6211\u9700\u8981\u5728\u8fd9\u91cc\u8bf4\u4e9b\u4ec0\u4e48(
_(:\u0437\u300d\u2220)_
_(:\u0437\u300d\u2220)_ \u6446\u70c2\u4e86\u8fd9\u8282\u53ef\u80fd\u4f1a\u5f88\u4e0d\u660e\u6240\u4ee5(
"},{"location":"trans/ec_common/#_1","title":"\u751f\u547d\u5468\u671f","text":"\u5728\u524d\u9762\u6211\u4eec\u5df2\u7ecf\u4e86\u89e3\u5230\u4e86 Update
\u51fd\u6570\u548c Render
\u51fd\u6570, Update
\u4e0e Render
\u6bcf\u5e27\u90fd\u4f1a\u88ab\u8c03\u7528, \u5bf9\u4e8e\u903b\u8f91\u7684\u66f4\u65b0\u6211\u4eec\u5e94\u5728 Update
\u4e2d\u505a, \u800c\u6709\u5173\u7ed8\u5236\u7684\u4efb\u52a1\u6211\u4eec\u5e94\u8be5\u5728 Render
\u4e2d\u505a, \u8fd9\u662f\u56e0\u4e3a\u5373\u4f7f\u4f60\u5728 Update
\u4e2d\u8fdb\u884c\u4e86\u7ed8\u5236\u7684\u8c03\u7528, \u5728 Render
\u5f00\u59cb\u4e4b\u524d\u4e5f\u4f1a\u88ab\u851a\u84dd\u6e05\u7a7a. \u7c7b\u4f3c\u5730, \u6e38\u620f\u4e2d\u7684\u6682\u505c\u7684\u5b9e\u73b0\u539f\u7406\u662f\u505c\u6b62\u6bcf\u5e27 Update
\u7684\u8c03\u7528\u800c\u4fdd\u7559 Render
\u7684\u8c03\u7528, \u90a3\u4e48\u81ea\u7136\u5982\u679c\u4f60\u5728 Render
\u91cc\u8fdb\u884c\u903b\u8f91\u66f4\u65b0\u4f60\u4f1a\u7834\u574f\u6389\u6e38\u620f\u539f\u6709\u7684\u6682\u505c.
ok\u90a3\u4e48\u6211\u4eec balabala \u8bf4\u4e86\u4e00\u5927\u5806, \u63a5\u4e0b\u6765\u4ecb\u7ecd\u51e0\u4e2a\u4f1a\u88ab\u851a\u84dd\u8c03\u7528\u7684\u51fd\u6570, \u8fd9\u4e9b\u51fd\u6570\u4e5f\u53eb\u505a\u751f\u547d\u5468\u671f
\u51fd\u6570.
"},{"location":"trans/ec_common/#entity","title":"\u5bf9\u4e8e Entity","text":" Update
Render
DebugRender
: \u8be5\u51fd\u6570\u4f1a\u5728\u851a\u84dd\u8c03\u8bd5\u63a7\u5236\u53f0\u88ab\u6253\u5f00\u65f6\u88ab\u6bcf\u5e27\u88ab\u8c03\u7528\u4f5c\u4e3a debug \u6e32\u67d3, \u5373 everest \u9ed8\u8ba4 ~ \u952e\u6253\u5f00\u7684\u90a3\u4e2a, \u5b83\u7684\u9ed8\u8ba4\u884c\u4e3a\u662f\u7ed8\u5236\u8be5\u5b9e\u4f53\u7684\u78b0\u649e\u7bb1, \u5728\u8fd9\u91cc\u4f60\u53ef\u4ee5\u505a\u4e00\u4e9b\u8c03\u8bd5\u7528\u7684\u6807\u8bc6\u7684\u7ed8\u5236, \u5c31\u6bd4\u5982\u8bf4\u4f60\u7684\u5b9e\u4f53\u7684\u4f5c\u7528\u8303\u56f4\u4ec0\u4e48\u7684. Added
: \u5f53\u8be5\u5b9e\u4f53\u88ab\u4ee5 Scene.Add
\u51fd\u6570\u8c03\u7528\u52a0\u5165\u5230\u573a\u666f\u4e0a\u65f6\u8c03\u7528, \u5728\u8fd9\u91cc\u4f60\u53ef\u4ee5\u8bfb\u53d6\u573a\u666f\u7684\u4e00\u4e9b\u72b6\u6001\u6216\u8005 flag \u4e4b\u7c7b\u7684\u5e76\u66f4\u6539\u5b83\u7684\u884c\u4e3a. Awake
: \u8be5\u51fd\u6570\u4e0e Added
\u884c\u4e3a\u76f8\u540c, \u4f46\u662f\u5f53\u4e00\u5e27\u4e4b\u5185\u6709\u591a\u4e2a\u5b9e\u4f53\u88ab\u52a0\u5165\u573a\u666f\u65f6\u5b83\u4eec\u7684 Awake
\u4f1a\u5728\u8fd9\u4e9b\u5b9e\u4f53\u90fd\u88ab\u52a0\u5165\u540e\u518d\u6279\u91cf\u8c03\u7528, \u800c Added
\u5219\u662f\u52a0\u5165\u4e00\u4e2a\u5c31\u8c03\u7528\u4e00\u4e2a. \u4e00\u4e2a\u5f88\u597d\u7684\u5728\u5b98\u56fe\u4e2d\u8fd0\u7528\u7684\u4f8b\u5b50\u662f\u6d6e\u52a8\u5757\u7684\u8fde\u63a5, \u8fd9\u662f\u5728\u573a\u666f\u5f00\u59cb\u65f6\u505a\u7684, \u4e3a\u4e86\u9632\u6b62\u9057\u6f0f\u67d0\u4e9b\u6d6e\u52a8\u5757\u95f4\u7684\u8fde\u63a5\u5c31\u9700\u8981\u5728\u5b9e\u4f53\u90fd\u88ab\u52a0\u5165\u540e\u518d\u8c03\u7528. Removed
: \u5f53\u8be5\u5b9e\u4f53\u88ab\u4ee5 Scene.Remove
\u51fd\u6570\u8c03\u7528\u79fb\u9664\u573a\u666f\u65f6\u8c03\u7528, \u4f60\u53ef\u4ee5\u5728\u8fd9\u91cc\u53d6\u6d88\u4e00\u4e9b\u5b9e\u4f53\u5bf9\u573a\u666f\u7684\u4e00\u4e9b\u4f5c\u7528, \u6bd4\u5982\u8bf4\u80cc\u666f\u7684\u53d8\u5316. SceneBegin
: \u5f53\u573a\u666f\u88ab\u8c03\u7528 Scene.Begin
\u7684\u540c\u65f6\u8c03\u7528 SceneEnd
: \u5f53\u573a\u666f\u88ab\u8c03\u7528 Scene.End
\u7684\u540c\u65f6\u8c03\u7528 "},{"location":"trans/ec_common/#component","title":"\u5bf9\u4e8e Component","text":"\u5bf9\u4e8e Component \u6765\u8bf4\u5927\u90e8\u5206\u51fd\u6570\u4e0e Entity \u7684\u7c7b\u4f3c, \u53ea\u4e0d\u8fc7\u540d\u5b57\u524d\u52a0\u4e2a\u4e86 Entity. \u6bd4\u5982\u5b9e\u4f53\u7684 Awake
\u5bf9\u5e94 Component \u7684 EntityAwake
, \u901a\u5e38\u8fd9\u4e9b\u51fd\u6570\u88ab\u8c03\u7528\u7684\u5730\u65b9\u662f\u5bf9\u5e94\u7684 Entity \u7684\u751f\u547d\u5468\u671f\u51fd\u6570\u7684\u9ed8\u8ba4\u5b9e\u73b0, \u6240\u4ee5\u9664\u975e\u6709\u610f\u800c\u4e3a\u4e4b\u8bb0\u5f97\u5728\u5f00\u5934\u8c03\u7528\u57fa\u7c7b\u7684\u751f\u547d\u5468\u671f\u5b9e\u73b0: MyInterestingEntity.cs
public override void Awake()\n{\n // ensure `Awake`s of its components has been called\n base.Awake();\n // do other thing...\n}\n
"},{"location":"trans/ec_common/#scene","title":"\u5bf9\u4e8e Scene","text":"\u55ef... \u5bf9\u5e94 Scene \u7684\u4e00\u4e9b\u751f\u547d\u5468\u671f\u51fd\u6570\u6211\u4e2a\u4eba\u4e5f\u4e0d\u662f\u5f88\u4e86\u89e3\u6bd5\u7adf\u6211\u4eec\u5927\u90e8\u5206\u7684\u65f6\u95f4\u90fd\u5728 gameplay \u7684\u573a\u666f\u4e0a, \u6240\u4ee5\u8fd9\u8282\u5c31\u6682\u65f6\u5495\u4e86(._.)
"},{"location":"trans/ec_common/#_2","title":"\u5e38\u89c1\u7684\u65b9\u6cd5\u4e0e\u5c5e\u6027","text":" Scene.Add
: \u5c06\u4e00\u4e2a\u5b9e\u4f53\u52a0\u5165\u5230\u573a\u666f\u4e2d Entity.Add
: \u5c06\u4e00\u4e2a Component \u6302\u8f7d\u5230\u5b9e\u4f53\u4e0a Scene.Remove
: \u5c06\u4e00\u4e2a\u5b9e\u4f53\u79fb\u51fa\u573a\u666f Entity.Remove
: \u5c06\u4e00\u4e2a Component \u79fb\u51fa\u5b9e\u4f53 Entity.RemoveSelf
: \u5c06 Entity \u81ea\u8eab\u79fb\u51fa\u81ea\u8eab\u6240\u5728\u573a\u666f Component.RemoveSelf
: \u5c06 Component \u81ea\u8eab\u79fb\u51fa\u6240\u5728\u5b9e\u4f53 Scene.Entities
: \u83b7\u53d6\u5f53\u524d\u573a\u666f\u4e0a\u7684\u5b9e\u4f53\u5217\u8868 Entity.Components
: \u83b7\u53d6\u5f53\u524d\u5b9e\u4f53\u7684 Component \u5217\u8868 "},{"location":"trans/ec_common/#entity_1","title":"Entity","text":"Entity
\u672c\u8eab\u6709\u56db\u4e2a\u516c\u5f00\u7684\u5b57\u6bb5:
Active
, \u8be5 bool
\u5b57\u6bb5\u8868\u793a\u8be5 Entity
\u662f\u5426 \"\u5b58\u6d3b\", \u5426\u5219\u4e3a \"\u5931\u6d3b\", \"\u5931\u6d3b\" \u7684 Entity
\u5c06\u4e0d\u4f1a\u88ab\u8c03\u7528 Update
\u65b9\u6cd5\u76f4\u5230 Active
\u4e3a true
Collidable
, \u8be5 bool
\u5b57\u6bb5\u8868\u793a\u8be5 Entity
\u662f\u5426 \"\u53ef\u78b0\u649e\", \u4e0d\u53ef\u78b0\u649e\u7684\u5b9e\u4f53\u4e0e\u4efb\u4f55\u5b9e\u4f53\u8fdb\u884c\u78b0\u649e\u68c0\u6d4b\u65f6\u90fd\u4f1a\u8fd4\u56de false
, \u6240\u4ee5\u4f60\u53ef\u4ee5\u4f7f\u7528\u8be5\u81ea\u52a8\u7981\u7528\u5b83\u7684\u78b0\u649e\u7bb1 Visible
, \u8be5 bool
\u5b57\u6bb5\u8868\u793a\u8be5 Entity
\u662f\u5426 \"\u53ef\u89c1\", \u4e0d\u53ef\u89c1\u7684\u5b9e\u4f53\u4e0d\u4f1a\u88ab\u8c03\u7528 Render
\u65b9\u6cd5, \u6ce8\u610f\u5373\u4f7f\u4e0d\u53ef\u89c1\u5b83\u7684\u78b0\u649e\u7bb1\u4f9d\u7136\u5b58\u5728. Position
, \u8be5 Vector2
\u5b57\u6bb5\u8868\u793a\u8be5 Entity
\u7684\u4f4d\u7f6e, \u6ce8\u610f\u8fd9\u4e2a\u4f4d\u7f6e\u76f8\u5bf9\u7684\u5750\u6807\u7cfb\u662f\u4e0d\u540c\u7684, \u5bf9\u4e8e HUD \u5b9e\u4f53\u6765\u8bf4\u5b83\u7684\u5750\u6807\u7cfb\u662f\u4e00\u4e2a 1922 x 1092 \u7684\u539f\u70b9\u5de6\u4e0a\u89d2\u7684\u5c4f\u5e55\u5750\u6807, \u5bf9\u4e8e gameplay \u5b9e\u4f53\u6765\u8bf4\u5b83\u662f\u76f8\u5bf9\u4e8e\u4e16\u754c\u539f\u70b9\u7684\u5206\u5ea6\u503c\u4e3a 1px \u7684\u5750\u6807. \u8fd9\u4e2a\u884c\u4e3a\u53ef\u4ee5\u901a\u8fc7\u540e\u9762\u6240\u8bf4\u7684 Tag
\u6765\u914d\u7f6e. "},{"location":"trans/ec_common/#tag","title":"Tag","text":":thinking: \u9664\u6b64\u4e4b\u5916\u5462\u8fd8\u6709\u4e00\u4e2a\u5c0f\u4e1c\u897f\u53eb Tag
, \u8bed\u4e49\u4e0a\u6765\u8bf4\u5b83\u8868\u793a\u8fd9\u4e2a\u5b9e\u4f53\u7684\u4e00\u4e9b\u6807\u7b7e\u5c5e\u6027, \u4f60\u53ef\u4ee5\u901a\u8fc7 Entity.Tag
\u5c5e\u6027\u6765\u8bbf\u95ee\u5b83, \u5b83\u662f\u4e00\u4e2a 32 \u4f4d\u6574\u6570, \u5b83\u7684\u6bcf\u4e00\u4f4d\u8868\u793a\u4e00\u4e2a\u8be5\u5b9e\u4f53\u7684\"\u5c5e\u6027\", \u6211\u4eec\u901a\u5e38\u4f1a\u4f7f\u7528 AddTag
\u4ee5\u53ca RemoveTag
\u6765\u64cd\u4f5c\u5b83. \u8981\u83b7\u53d6\u573a\u666f\u4e2d\u6240\u6709\u62e5\u6709\u67d0\u4e00 Tag
\u7684\u5b9e\u4f53, \u6211\u4eec\u9700\u8981\u8bbf\u95ee Scene
\u7684 TagLists
\u800c\u4e0d\u662f Tracker
, \u7136\u540e\u4f7f\u7528\u5b83\u7684\u7d22\u5f15\u5668(\u5f62\u5982 tagList[yourtag]
\u7684\u8fd0\u7b97\u7b26)\u6765\u68c0\u7d22, \u6216\u8005\u4f60\u4e5f\u53ef\u4ee5\u4f7f\u7528\u7b80\u4fbf\u7684\u65b9\u6cd5---\u76f4\u63a5\u8bbf\u95ee Scene
\u7684\u7d22\u5f15\u5668. \u4e00\u822c\u7684\u8bdd, \u6211\u5bf9\u4e8e Tag
\u7684\u5e94\u7528\u5f88\u5c11, \u6700\u8fd1\u4e00\u6b21\u662f\u5c06\u4e00\u4e2a Entity
\u6807\u8bb0\u4e3a ui \u5c42, \u5b83\u7684\u4ee3\u7801\u770b\u8d77\u6765\u662f\u8fd9\u6837\u7684:
this.AddTag(Tags.HUD);\n
\u5f53\u4f60\u7684\u5b9e\u4f53\u62e5\u6709\u8fd9\u4e2a Tag \u540e, \u851a\u84dd\u4f1a\u5c06\u4f60\u7684\u5b9e\u4f53\u7ed8\u5236\u5728 ui \u5c42, \u6bd4\u8f83\u5e38\u89c1\u7684\u4f8b\u5b50\u5c31\u662f\u5de6\u4e0a\u89d2\u7684\u8ba1\u65f6\u5668, \u5b83\u5728\u6784\u9020\u5668\u5185\u5c31\u7ed9\u81ea\u5df1\u6253\u4e0a\u4e86 Tags.HUD
\u7684\u6807\u7b7e. \u4e5f\u5982\u4e0a\u9762\u6240\u8bf4\u7684, \u4e00\u4e9b\u851a\u84dd\u5e38\u89c1\u7684\u6240\u6709 Tag \u4f60\u90fd\u53ef\u4ee5\u5728 Celeste.Tags
\u7c7b\u5185\u627e\u5230. \u4ee5\u4e0b\u662f\u4e00\u4e9b\u53ef\u80fd\u5730\u5e38\u89c1\u7684 Tag:(\u5df2\u8fc1\u79fb)
PauseUpdate
: \u662f\u5426\u5728\u6682\u505c\u671f\u95f4\u4f9d\u7136\u88ab\u8c03\u7528 Update
, \u901a\u5e38\u7528\u4e8e ui \u5c42\u7684\u5b9e\u4f53\u4e0a FrozenUpdate
: \u662f\u5426\u5728 Frozen
\u72b6\u6001\u4e0b\u4f9d\u7136\u88ab\u8c03\u7528 Update
(\u6bd4\u5982\u8349\u8393\u7c7d\u52a8\u753b\u8fc7\u7a0b, 1a\u84dd\u5fc3\u89e3\u5bc6\u6210\u529f\u8fc7\u7a0b, \u6ce8\u610f\u6b64\u72b6\u6001\u4e0e\u51bb\u7ed3\u5e27\u65e0\u5173) TransitionUpdate
: \u662f\u5426\u5728\u5173\u5361\u5207\u677f\u65f6\u4f9d\u7136\u88ab\u8c03\u7528 Update
, \u901a\u5e38\u7528\u4e8e\u5728\u5207\u677f\u65f6\u66f4\u65b0\u4e00\u4e9b\u89c6\u89c9\u4e0a\u7684\u4e1c\u897f(\u6bd4\u5982\u7535\u7f51\u7684 \"\u653e\u7535\" \u52a8\u753b\u4e0d\u4f1a\u5728\u5207\u677f\u65f6\u9759\u6b62) HUD
: \u5373\u662f\u5426\u662f ui \u5c42, \u6b64\u9879\u5c31\u4f1a\u6539\u53d8 Entity.Render
\u7684\u7ed8\u5236\u903b\u8f91, \u4f7f\u7ed8\u5236\u5750\u6807\u57fa\u4e8e\u5c4f\u5e55\u5750\u6807\u800c\u4e0d\u662f\u4e16\u754c\u5750\u6807 Global
: \u8be5 Entity \u662f\u5426\u662f\u5168\u5c40\u7684, \u4e00\u4e2a\u975e\u5168\u5c40\u5b9e\u4f53\u5728\u5173\u5361\u91cd\u8bd5\u540e\u4f1a\u6d88\u5931, \u5168\u5c40 Tag \u53ef\u4ee5\u907f\u514d\u8fd9\u4ef6\u4e8b, \u901a\u5e38\u5168\u5c40 Tag \u6700\u5e38\u89c1\u7684\u7528\u6cd5\u662f\u548c HUD \u7ed3\u5408\u5728\u4e00\u8d77, \u8fd9\u6837\u4f60\u5c31\u62e5\u6709\u4e86\u4e00\u4e2a\u5728\u6e38\u620f\u5185\u6301\u4e45\u7684 ui \u90e8\u4ef6\u4e86. "},{"location":"trans/il/","title":"IL","text":"Info
\u5982\u679c\u4f60\u5728\u4e4b\u524d\u5df2\u7ecf\u5b66\u4e60\u8fc7 IL
\u5e76\u4e14\u4f7f\u7528\u8fc7\u7c7b\u4f3c\u7684 System.Reflection.Emit
\u8fd9\u4e9b api \u7684\u8bdd\u4f60\u53ef\u4ee5\u8df3\u8fc7\u8fd9\u4e00\u8282.
"},{"location":"trans/il/#_1","title":"\u7b80\u4ecb","text":"IL
\u5168\u79f0 Intermediate Language
, \u5373\u4e2d\u95f4\u8bed\u8a00, \u5728\u4e00\u4e9b\u8f83\u8001\u7684\u6587\u6863\u91cc\u9762\u5b83\u53ef\u80fd\u4e5f\u4f1a\u88ab\u53eb\u505a MSIL
, \u5373 Microsoft Intermediate Language
, \u5076\u5c14\u8fd8\u4f1a\u6709\u4e00\u4e9b\u5730\u65b9\u53eb\u505a CIL
, \u5373 Common Intermediate Language
, \u8fd9\u4e09\u79cd\u53eb\u6cd5\u901a\u5e38\u610f\u4e49\u4e0a\u90fd\u662f\u6307\u4e00\u4e2a\u4e1c\u897f. \u5728\u524d\u9762\u6211\u4eec\u5c31\u5df2\u7ecf\u63d0\u5230\u8fc7 IL
\u4e86(\u9605\u8bfb\u4ee3\u78012), \u4f46\u662f\u5e76\u6ca1\u6709\u6df1\u5165\u7684\u8bb2\u89e3\u5b83\u5230\u5e95\u662f\u4ec0\u4e48\u6837\u7684. IL
\u901a\u5e38\u6765\u8bf4\u53ef\u4ee5\u7406\u89e3\u6210\u4e24\u4e2a\u90e8\u5206, \u4e00\u4e2a \"\u6267\u884c\" \u90e8\u5206, \u4e00\u4e2a \"\u58f0\u660e\" \u90e8\u5206, \"\u6267\u884c\" \u90e8\u5206\u89c4\u5b9a\u4e86\u4e00\u4e2a\u51fd\u6570\u5185\u90e8\u7684\u4ee3\u7801\u5e94\u8be5\u600e\u4e48\u64cd\u63a7\u6211\u4eec\u7684\u7a0b\u5e8f, \u800c \"\u58f0\u660e\" \u90e8\u5206\u5219\u89c4\u5b9a\u4e86\u4e00\u4e2a\u51fd\u6570\u7684\u8fd4\u56de\u503c, \u53c2\u6570\u5217\u8868, \u8bbf\u95ee\u4fee\u9970\u7b26, \u6240\u5728\u7c7b, \u7c7b\u7684\u8bbf\u95ee\u4fee\u9970\u7b26, \u540d\u79f0\u7b49\u8fd9\u4e9b\u5143\u6570\u636e, \u83b7\u53d6\u8fd9\u4e9b\u5143\u6570\u636e\u5176\u5b9e\u4f60\u65e9\u5728\u5b66\u4e60\u53cd\u5c04\u7684\u65f6\u5019\u5c31\u8fdb\u884c\u8fc7. \u540c\u65f6\u4fee\u6539\u6216\u751f\u6210\u8fd9\u4e9b\u5143\u6570\u636e\u4e5f\u4e0d\u56f0\u96be, \u4f46\u662f\u5728\u8fdb\u884c\u851a\u84dd modding \u65f6\u4fee\u6539\u6216\u751f\u6210\u8fd9\u4e9b\u5143\u6570\u636e\u7684\u64cd\u4f5c\u51e0\u4e4e\u4e0d\u4f1a\u88ab\u4f7f\u7528\u5230, \u6240\u4ee5\u8fd9\u4e00\u8282\u6211\u4eec\u805a\u7126\u4e8e IL
\u7684 \"\u6267\u884c\" \u90e8\u5206, \u8bb2\u8ff0\u5176\u57fa\u672c\u7ed3\u6784, \u57fa\u7840\u8bed\u6cd5\u7b49\u5185\u5bb9.
"},{"location":"trans/il/#_2","title":"\u521d\u5370\u8c61","text":"HelloWorld!
namespace DynamicAssemblyTest;\n\npublic static class Program\n{\n public static void Main()\n {\n Console.WriteLine(\"Hello world!\");\n }\n}\n
\u73b0\u5728, \u8bd5\u7740\u7f16\u8bd1\u4e0a\u8ff0\u5f88\u7b80\u5355\u7684 HelloWorld \u7a0b\u5e8f, \u627e\u5230\u5176\u7a0b\u5e8f\u96c6, \u7136\u540e\u7528 dnSpy
(\u6216\u8005 ILSpy
\u4e5f\u884c) \u6253\u5f00\u5b83. \u4e0d\u8fc7\u8fd9\u6b21\u6211\u4eec\u4e0d\u662f\u5728\u770b C#
\u4ee3\u7801\u4e86, \u6211\u4eec\u9700\u8981\u770b IL
\u4ee3\u7801, \u6240\u4ee5\u6211\u4eec\u5728\u5982\u4e0b\u56fe\u7684\u8fd9\u4e2a\u4e0b\u62c9\u6846\u4e2d\u9009\u62e9 IL
:
\u5728\u56fe\u4e2d\u7684\u90a3\u4e00\u5768\u4f60\u53ef\u80fd\u4e0d\u77e5\u6240\u63aa\u7684\u4ee3\u7801\u5c31\u662f IL
\u4ee3\u7801\u4e86, \u5728\u4e0a\u8ff0 IL
\u4ee3\u7801\u4e2d .method
.class
\u8fd9\u4e00\u7c7b\u5b57\u6837\u5c31\u8868\u793a\u58f0\u660e\u4e00\u4e2a \u65b9\u6cd5/\u7c7b, \u800c\u5176\u540e\u9762\u6240\u8ddf\u7684\u4e00\u5927\u957f\u4e32\u5173\u952e\u5b57\u5c31\u662f\u4e00\u4e9b\u5143\u6570\u636e, \u6bd4\u5982\u7c7b\u540d, \u8bbf\u95ee\u4fee\u9970\u7b26\u7b49\u6211\u4eec\u4e4b\u524d\u8c08\u8bba\u8fc7\u7684\u4e1c\u897f, \u540e\u9762\u7684\u5927\u62ec\u53f7\u5c31\u8868\u793a\u8fd9\u4e2a\u58f0\u660e\u7684 \"\u5185\u5bb9\u7269\", \u901a\u5e38\u7c7b\u7684 \"\u5185\u5bb9\u7269\" \u6709\u5185\u90e8\u7c7b, \u65b9\u6cd5, \u6784\u9020\u5668, \u5b57\u6bb5, \u5c5e\u6027\u7b49, \u90a3\u4e48\u663e\u800c\u6613\u89c1\u8fd9\u91cc\u5c31\u6beb\u65e0\u7591\u95ee\u5c31\u662f IL
\u7684\u58f0\u660e\u90e8\u5206\u4e86. \u73b0\u5728\u6211\u4eec\u5173\u6ce8 .method
\u58f0\u660e, \u5176\u7684 \"\u5185\u5bb9\u7269\" \u5c31\u662f\u6211\u4eec\u63a5\u4e0b\u6765\u8981\u805a\u7126\u7684, \u5373 IL
\u7684 \"\u6267\u884c\" \u90e8\u5206. \u5728\u4e0a\u56fe\u4e2d dnSpy \u5e2e\u6211\u4eec\u5c06\u524d\u9762\u52a0\u4e0a\u4e86\u5b57\u8282\u5185\u5b58\u504f\u79fb\u7684\u90a3\u6bcf\u4e00\u884c\u5c31\u662f\u6211\u4eec\u7684 IL
\u4ee3\u7801\u4e86, \u4e0d\u8fc7\u8fd9\u91cc\u6211\u4eec\u4e0d\u592a\u4f1a\u9700\u8981\u8fd9\u4e2a\u504f\u79fb\u91cf, \u56e0\u4e3a\u5927\u591a\u6570\u6d89\u53ca\u64cd\u4f5c IL
\u7684\u5e93\u90fd\u4f1a\u4e3a\u6211\u4eec\u81ea\u52a8\u5b8c\u6210\u8fd9\u4e2a\u504f\u79fb\u7684\u8ba1\u7b97.
"},{"location":"trans/il/#_3","title":"\u5207\u6362\u73af\u5883 & \u52a8\u6001\u7a0b\u5e8f\u96c6","text":"\u73b0\u5728\u6211\u4eec\u9700\u8981\u4e00\u4e2a\u73af\u5883\u6765\u4e66\u5199\u6211\u4eec\u7684 IL
\u4ee3\u7801, \u5f53\u7136\u4f60\u867d\u7136\u5b8c\u5168\u53ef\u4ee5\u5c31\u5728 dnSpy \u5bf9\u7740\u90a3\u4e00\u5927\u5806 C#
\u7f16\u8bd1\u540e\u7684 IL
\u8fdb\u884c\u4fee\u6539, \u5e76\u9891\u7e41\u4fdd\u5b58\u4fee\u6539\u7136\u540e\u8fd0\u884c\u6765\u67e5\u770b\u6548\u679c, \u4f46\u662f\u8fd9\u603b\u5f52\u6ca1\u6709\u6211\u4eec\u76f4\u63a5\u5728 C#
\u4ee3\u7801\u91cc\u5199 IL
\u4ee3\u7801\u91cc\u65b9\u4fbf!
\u9996\u5148, \u6211\u4eec\u73b0\u5728\u53ef\u4ee5\u4e0d\u518d\u5728 mod \u5de5\u7a0b\u91cc\u5de5\u4f5c\u4e86, \u8fd9\u90e8\u5206\u5185\u5bb9\u662f\u72ec\u7acb\u5f00\u6765\u7684, \u6240\u4ee5\u6211\u4f1a\u63a8\u8350\u4f60\u65b0\u5efa\u4e00\u4e2a\u9879\u76ee\u6765\u505a\u8fd9\u4e9b. \u8fd9\u91cc\u6211\u7ed9\u9879\u76ee\u53d6\u7684\u540d\u662f DynamicAssemblyTest
, \u76ee\u6807\u6846\u67b6\u662f .net 8
. \u5b8c\u6210\u540e, \u590d\u5236\u7c98\u8d34\u4ee5\u4e0b\u4ee3\u7801(\u4e4b\u540e\u6211\u4eec\u4f1a\u6162\u6162\u89e3\u91ca\u7684):
using System.Reflection;\nusing System.Reflection.Emit;\n\nnamespace DynamicAssemblyTest;\n\npublic static class Program\n{\n public static MethodInfo GenerateMethod(Action<ILGenerator> generateAction)\n {\n AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new(\"MyAssembly\"), AssemblyBuilderAccess.RunAndCollect);\n ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule(\"MyTestModule\");\n TypeBuilder typeBuilder = moduleBuilder.DefineType(\"MyType\");\n MethodBuilder methodBuilder = typeBuilder.DefineMethod(\"MyMethod\", MethodAttributes.Public | MethodAttributes.Static);\n generateAction(methodBuilder.GetILGenerator());\n return typeBuilder.CreateType().GetMethod(\"MyMethod\")!;\n }\n\n public static void Main()\n {\n MethodInfo methodInfo = GenerateMethod(il =>\n {\n il.Emit(OpCodes.Ldstr, \"Hello Dynamic Method!\");\n il.Emit(OpCodes.Call, typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!);\n il.Emit(OpCodes.Ret);\n });\n Action action = methodInfo.CreateDelegate<Action>();\n action();\n }\n}\n
Note
\u6211\u9ed8\u8ba4\u542f\u7528\u4e86\u9690\u5f0f\u547d\u540d\u7a7a\u95f4, \u5982\u679c\u4f60\u9047\u5230\u4e86\u7c7b\u578b\u672a\u627e\u5230\u7684\u62a5\u9519\u90a3\u4f60\u5c31\u5f97\u624b\u52a8 using \u4e00\u4e0b\u5269\u4f59\u7684\u90a3\u4e9b\u547d\u540d\u7a7a\u95f4\u4e86.
\u73b0\u5728\u8fd0\u884c\u4f60\u7684\u7a0b\u5e8f, \u4f60\u5e94\u8be5\u4f1a\u5f97\u5230\u4e00\u53e5\u8f93\u51fa: Hello Dynamic Method!
. \u4e0a\u8ff0\u4ee3\u7801\u5176\u5b9e\u662f\u5728\u5728\u4ee3\u7801\u4e2d\u52a8\u6001\u5b9a\u4e49\u4e86\u4e00\u4e2a\u7a0b\u5e8f\u96c6, \u7136\u540e\u52a8\u6001\u5b9a\u4e49\u4e86\u4e00\u4e2a\u7c7b, \u5e76\u5411\u91cc\u9762\u52a8\u6001\u5b9a\u4e49\u4e86\u4e00\u4e2a MyMethod
\u65b9\u6cd5, \u4e4b\u540e\u6211\u4eec\u52a8\u6001\u5730 \"\u7f16\u8bd1\" \u4e86\u8fd9\u4e2a\u7a0b\u5e8f\u96c6\u5e76\u5c06\u5176\u88c5\u8f7d\u5230\u6211\u4eec\u7684\u7a0b\u5e8f\u96c6\u57df\u4e2d, \u5176\u4e2d, MyMethod
\u65b9\u6cd5\u7684 IL
\u7684\u5185\u5bb9\u5c31\u662f\u5728\u6211\u4eec\u7684 Main
\u65b9\u6cd5\u4e2d GenerateMethod
\u53c2\u6570\u4e2d\u7684\u59d4\u6258\u5b9a\u4e49\u7684. \u5f80\u7b80\u5355\u6765\u8bf4\u5c31\u662f\u6211\u4eec\u5728\u4ee3\u7801\u4e2d\u53cd\u5c04\u521b\u5efa\u4e86\u4e00\u6bb5\u65b0\u7684\u4ee3\u7801\u5e76\u6267\u884c, \u8fd9\u542c\u8d77\u6765\u662f\u4e0d\u662f\u9177\u6781\u4e86? \u4e0a\u9762\u8fd9\u4e2a\u52a8\u6001\u5b9a\u4e49\u7a0b\u5e8f\u96c6\u7684\u5e93\u53eb\u505a System.Reflection.Emit
, \u5728\u8fd9\u91cc\u6211\u4eec\u53ea\u662f\u4e3a\u4e86\u5b66\u4e60\u4e00\u70b9 IL
\u77e5\u8bc6\u800c\u4f7f\u7528, \u5230\u540e\u9762\u4fee\u6539\u851a\u84dd\u7684\u7a0b\u5e8f\u96c6\u65f6\u6211\u4eec\u9700\u8981\u4f7f\u7528 Everest \u5e26\u7684 Mono.Cecil
\u5e93, \u4e0d\u8fc7\u4ed6\u4eec\u5927\u540c\u5c0f\u5f02.
"},{"location":"trans/il/#il_1","title":"\u57fa\u672c IL
","text":"IL_0000: nop\nIL_0001: ldstr \"Hello world!\"\nIL_0006: call void [System.Console]System.Console::WriteLine(string)\nIL_000B: nop\nIL_000C: ret\n
\u901a\u5e38\u6765\u8bf4, \u4e00\u6bb5 IL
\u5305\u542b\u591a\u884c IL
, \u6bcf\u4e00\u884c IL
(\u6211\u5076\u5c14\u4e5f\u4f1a\u79f0\u4e3a\u4e00\u53e5 IL
) \u90fd\u5305\u542b\u4e00\u4e2a\u64cd\u4f5c\u7801(OpCode)\u4ee5\u53ca\u53ef\u4ee5\u6ca1\u6709\u7684\u53c2\u6570. \u6bd4\u5982\u4e0a\u8ff0\u6bb5 IL
, \u5176\u5305\u542b\u4e94\u884c IL
:
\u7b2c\u4e00\u884c IL
\u7684\u64cd\u4f5c\u7801\u662f nop
, \u6ca1\u6709\u53c2\u6570 \u7b2c\u4e8c\u884c IL
\u7684\u64cd\u4f5c\u7801\u662f ldstr
, \u53c2\u6570\u662f\u4e00\u4e32\u5b57\u7b26\u4e32, \u6216\u8005\u4e25\u8c28\u7684\u8bf4, \u662f\u4e00\u4e2a\u5b57\u7b26\u4e32\u7684 token
, \u5b83\u5f15\u7528\u4e86\u7a0b\u5e8f\u96c6\u5143\u6570\u636e\u4e2d\u5b58\u653e\u5b57\u7b26\u4e32\u672c\u4f53\u7684\u4f4d\u7f6e, \u4e0d\u8fc7\u6211\u4eec\u53ef\u4ee5\u5ffd\u7565\u8fd9\u4e2a\u7ec6\u8282, \u56e0\u4e3a\u6211\u4eec\u4e0d\u4f1a\u6d89\u53ca\u5230 IL
\u7684\u5177\u4f53\u5b57\u8282\u5c42\u9762\u7684\u4e1c\u897f. \u7b2c\u4e09\u884c IL
\u7684\u64cd\u4f5c\u7801\u662f call
, \u53c2\u6570\u662f\u4e00\u4e2a\u65b9\u6cd5, \u5b83\u4e5f\u662f\u4e00\u4e2a token
, \u5176\u4e5f\u662f\u5f15\u7528\u4e86\u5143\u6570\u636e\u4e2d\u5b58\u653e\u65b9\u6cd5\u672c\u4f53\u7684\u4f4d\u7f6e \u7b2c\u56db\u884c IL
\u7684\u64cd\u4f5c\u7801\u662f nop
, \u6ca1\u6709\u53c2\u6570 \u7b2c\u4e94\u884c IL
\u7684\u64cd\u4f5c\u7801\u662f ret
, \u6ca1\u6709\u53c2\u6570 \u90a3\u4e48, \u5728\u77e5\u9053 IL
\u7684\u57fa\u672c\u7ed3\u6784\u540e, \u6211\u4eec\u5c31\u53ef\u4ee5\u5177\u4f53\u5b66\u4e60 IL
\u8fd9\u4e9b\u64cd\u4f5c\u7801\u5230\u5e95\u5e72\u4e86\u4ec0\u4e48\u4e86.
"},{"location":"trans/il/#_4","title":"\u8bc4\u4f30\u6808","text":"Note
\u5982\u679c\u4f60\u5728\u8fd9\u91cc\u4e0d\u77e5\u9053\u6808\u662f\u4ec0\u4e48\u7684\u8bdd, \u4f60\u5c31\u8be5\u53bb\u590d\u4e60\u4e00\u4e0b\u4f60\u4e4b\u524d\u5b66\u4e60\u7684\u6570\u636e\u7ed3\u6784\u4e4b\u6808\u4e86.
\u5728 IL
\u4ee3\u7801\u4e2d, \u5927\u91cf\u64cd\u4f5c\u7b26\u672c\u8d28\u4e0a\u90fd\u662f\u5728\u64cd\u4f5c\u4e00\u4e2a\u53eb\u505a \u8bc4\u4f30\u6808
\u7684\u4e1c\u897f, \u4ece\u5b57\u9762\u4e0a\u6211\u4eec\u5c31\u53ef\u4ee5\u77e5\u9053\u5b83\u662f\u4e00\u4e2a\u6808, \u90a3\u4e48\u65e2\u7136\u662f\u6808, \u90a3\u4e48\u901a\u5e38\u5c31\u6709 \u538b\u5165
\u548c \u5f39\u51fa
\u4e24\u79cd\u64cd\u4f5c, \u8bc4\u4f30\u6808
\u4e5f\u662f\u5982\u6b64. \u6bd4\u5982\u5982\u4e0b C#
\u65b9\u6cd5:
static int Add(int a, int b, int c) \n{\n return a + b + c;\n}\n
\u5b83\u5728\u7f16\u8bd1\u5668\u7684 Release
\u4f18\u5316\u4e0b\u4f1a\u7f16\u8bd1\u6210\u5982\u4e0b IL
:
Info
\u7f16\u8bd1\u5668\u7684 Debug
\u7f16\u8bd1\u4e0b\u4f1a\u4ea7\u751f\u5f88\u591a\u7528\u4e8e\u8c03\u8bd5\u4ee3\u7801\u7684 IL
, \u76f8\u5bf9\u6765\u8bf4\u4f1a\u590d\u6742\u5f88\u591a, \u6240\u4ee5\u6211\u4eec\u4f7f\u7528 Release
\u7f16\u8bd1\u6765\u5c3d\u53ef\u80fd\u7b80\u5316
.method private hidebysig static \n int32 Add (\n int32 a,\n int32 b,\n int32 c\n ) cil managed \n {\n .maxstack 8\n\n IL_0000: ldarg.0\n IL_0001: ldarg.1\n IL_0002: add\n IL_0003: ldarg.2\n IL_0004: add\n IL_0005: ret\n } // end of method Program::Add\n
\u8fd9\u91cc\u6211\u4eec\u628a\u4e00\u90e8\u5206\u58f0\u660e\u90e8\u5206\u653e\u51fa\u6765\u4e86, \u4e0d\u8fc7\u6211\u4eec\u53ea\u9700\u8981\u5173\u5fc3\u8fd9\u4e00\u884c: .maxstack 8
, \u5b83\u8868\u793a\u8bf7\u6c42\u5728\u8fd9\u4e2a\u65b9\u6cd5\u6267\u884c\u8fc7\u7a0b\u4e2d\u8bc4\u4f30\u6808\u6709\u786e\u4fdd 8 \u4e2a\u5927\u5c0f\u7684\u7a7a\u95f4\u53ef\u4ee5\u4f7f\u7528. \u7528\u56fe\u8868\u7684\u65b9\u6cd5\u5927\u6982\u662f(\u6700\u5de6\u4fa7\u6808\u9ad8\u5ea6\u6700\u4f4e, \u5411\u53f3\u6808\u9ad8\u5ea6\u9010\u6e10\u589e\u52a0, \u7ea2\u8272\u8868\u793a\u76ee\u524d\u4f7f\u7528\u4e86\u7684\u6808\u4f4d, \u4e4b\u540e\u7684\u56fe\u8868\u540c):
flowchart LR\n S1 --- S2 --- S3 --- S4 --- S5 --- S6 --- S7 --- S8\n style S1 stroke:red
\u9996\u5148\u6211\u4eec\u4f1a\u4ecb\u7ecd\u4e00\u4e2a\u7cfb\u5217\u7684\u64cd\u4f5c\u7b26 ldarg.*
, \u5b83\u8868\u793a\u5c06\u65b9\u6cd5\u53c2\u6570\u5217\u8868\u4e2d\u7684\u7b2c *-1 \u4e2a\u53c2\u6570\u538b\u5165\u8bc4\u4f30\u6808\u4e2d, \u4e0d\u5e26\u53c2\u6570(ldarg.0
\u4e0e ldarg.1
\u91cc\u7684\u6570\u5b57\u662f\u64cd\u4f5c\u7b26\u672c\u8eab, \u4e0d\u8981\u8ba4\u4e3a\u5b83\u662f\u4e00\u4e2a\u53c2\u6570\u4e86), \u6ce8\u610f\u8fd9\u662f\u5728\u9759\u6001\u65b9\u6cd5\u4e2d\u800c\u8a00\u7684, \u5982\u679c\u8be5\u65b9\u6cd5\u662f\u6210\u5458\u65b9\u6cd5, \u90a3\u4e48 ldarg.0
\u5b9e\u9645\u4e0a\u538b\u5165\u7684\u662f this
\u7684\u503c, \u800c ldarg.1
\u624d\u662f\u7b2c\u4e00\u4e2a\u53c2\u6570.
\u5728\u4e0a\u8ff0\u6bb5 IL
\u4e2d, \u8be5\u65b9\u6cd5\u662f\u4e2a\u9759\u6001\u65b9\u6cd5, \u6240\u4ee5\u524d\u4e24\u884c ldarg.0
\u4e0e ldarg.1
\u4f1a\u5c06\u7b2c\u4e00\u4e2a\u53c2\u6570\u548c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u538b\u5165\u8bc4\u4f30\u6808\u4e2d. \u73b0\u5728\u5047\u8bbe\u6211\u4eec\u8c03\u7528\u4f20\u5165\u7684\u53c2\u6570\u5206\u522b\u662f 1, 2, 3
(Sn\u8868\u793a\u672a\u4f7f\u7528\u7684\u6808\u4f4d, a:b \u8868\u793a\u8be5\u4f4d\u7f6e\u5b58\u5165\u4e86\u4e00\u4e2aa\u7c7b\u578b\u7684b\u503c, \u540e\u540c):
flowchart \n subgraph start\n direction LR\n S1_3[\"S1\"] --- S2_3[\"S2\"] --- S3_3[\"S3\"] --- S4_3[\"S4\"]\n end\n\n subgraph ldarg.0\n direction LR\n S1[\"int32: 1\"] --- S2 --- S3 --- S4\n style S1 stroke:red\n end\n\n subgraph ldarg.1\n direction LR\n S1_2[\"int32: 1\"] --- S2_2[\"int32: 2\"] --- S3_2[\"S3\"] --- S4_2[\"S4\"]\n style S1_2 stroke:red\n style S2_2 stroke:red\n end\n\n start --> ldarg.0 --> ldarg.1
\u7136\u540e\u8981\u4ecb\u7ecd\u7684\u662f add
\u64cd\u4f5c\u7b26, add
\u64cd\u4f5c\u7b26\u4f1a\u5f39\u51fa\u8bc4\u4f30\u6808\u4e0a\u7684\u4e24\u4e2a\u5143\u7d20, \u7136\u540e\u5c06\u5b83\u4eec\u76f8\u52a0, \u7136\u540e\u5c06\u7ed3\u679c\u538b\u5165\u8bc4\u4f30\u6808. \u5f53\u8fd9\u4e24\u4e2a\u5143\u7d20\u4efb\u610f\u4e00\u4e2a\u4e0d\u662f\u57fa\u672c\u6570\u5b57\u7c7b\u578b\u65f6 jit \u5c31\u4f1a\u629b\u51fa InvalidProgramException
\u5f02\u5e38. \u540c\u65f6\u6ce8\u610f\u4e00\u4e2a\u7ec6\u8282, \u4f60\u4e3a\u7c7b\u91cd\u8f7d\u7684\u52a0\u53f7\u8fd0\u7b97\u7b26\u5e76\u4e0d\u662f\u4f7f\u7528\u7684\u8fd9\u4e2a\u64cd\u4f5c\u7b26, \u800c\u662f\u8c03\u7528\u7684\u4e00\u4e2a\u7279\u6b8a\u7684\u540d\u4e3a op_Add
\u7684\u5e26\u6709 special name
\u6807\u8bb0\u7684\u65b9\u6cd5. \u6700\u540e\u662f ret
\u64cd\u4f5c\u7b26, \u5f53\u65b9\u6cd5\u6ca1\u6709\u8fd4\u56de\u503c\u65f6\u5b83\u4f1a\u5c06\u63a7\u5236\u6743\u4ea4\u56de\u7ed9\u8c03\u7528\u8005, \u540c\u65f6 jit \u4f1a\u4e3a\u6211\u4eec\u68c0\u67e5\u8bc4\u4f30\u6808\u662f\u5426\u6e05\u7a7a, \u5982\u679c\u8bc4\u4f30\u6808\u4e0a\u8fd8\u6709\u4e1c\u897f\u90a3\u4e48\u540c\u6837 jit \u4f1a\u629b\u51fa\u5f02\u5e38. \u5f53\u65b9\u6cd5\u62e5\u6709\u8fd4\u56de\u503c\u65f6\u5b83\u4f1a\u786e\u4fdd\u8bc4\u4f30\u6808\u4e0a\u6709\u4e14\u53ea\u5269\u4e00\u4e2a\u5143\u7d20, \u7136\u540e\u5c06\u8fd9\u4e2a\u503c\u5f39\u51fa\u5e76\u538b\u5165\u8c03\u7528\u8005\u7684\u8bc4\u4f30\u6808\u4e0a(\u8bc4\u4f30\u6808\u662f\u65b9\u6cd5\u72ec\u7acb\u5730). \u90a3\u4e48\u81ea\u7136\u800c\u7136, \u6211\u4eec\u6700\u521d\u7684\u90a3 6 \u53e5 IL
\u5927\u6982\u4f1a\u662f\u8fd9\u4e2a\u5de5\u4f5c\u6d41\u7a0b:
flowchart \n subgraph start\n direction LR\n S1 --- S2 --- S3 --- S4\n end\n\n subgraph ldarg.0\n direction LR\n S1_2[\"int32: 1\"] --- S2_2[\"S2\"] --- S3_2[\"S3\"] --- S4_2[\"S4\"]\n style S1_2 stroke:red\n end\n\n subgraph ldarg.1\n direction LR\n S1_3[\"int32: 1\"] --- S2_3[\"int32: 2\"] --- S3_3[\"S3\"] --- S4_3[\"S4\"]\n style S1_3 stroke:red\n style S2_3 stroke:red\n end\n\n subgraph add\n direction LR\n S1_4[\"int32: 3\"] --- S2_4[\"S2\"] --- S3_4[\"S3\"] --- S4_4[\"S4\"]\n style S1_4 stroke:red\n end\n\n subgraph ldarg.2\n direction LR\n S1_5[\"int32: 3\"] --- S2_5[\"int32: 3\"] --- S3_5[\"S3\"] --- S4_5[\"S4\"]\n style S1_5 stroke:red\n style S2_5 stroke:red\n end\n\n subgraph 2ndadd [\"2nd add\"]\n direction LR\n S1_6[\"int32: 6\"] --- S2_6[\"S2\"] --- S3_6[\"S3\"] --- S4_6[\"S4\"]\n style S1_6 stroke:red\n end\n\n start --> ldarg.0 --> ldarg.1 --> add --> ldarg.2 --> 2ndadd --> ret
\u8fd9\u56fe\u505a\u5b8c\u540e\u770b\u4e0a\u53bb\u597d\u50cf\u4e0d\u662f\u60f3\u8c61\u4e2d\u7684\u90a3\u4e48\u76f4\u89c2...
"},{"location":"trans/il/#il_2","title":"\u4e66\u5199 IL
","text":"\u73b0\u5728\u6211\u4eec\u5df2\u7ecf\u4e86\u89e3\u4e86\u4e00\u5c0f\u4e9b IL
\u7684\u77e5\u8bc6, \u73b0\u5728\u6211\u4eec\u56de\u5230\u4e4b\u524d\u7684\u5de5\u7a0b\u4e2d, \u66f4\u6539\u4e3a\u4ee5\u4e0b\u4ee3\u7801:
using System.Reflection;\nusing System.Reflection.Emit;\n\nnamespace DynamicAssemblyTest;\n\npublic static class Program\n{\n public static MethodInfo GenerateMethod(Action<ILGenerator> generateAction)\n {\n AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new(\"MyAssembly\"), AssemblyBuilderAccess.RunAndCollect);\n ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule(\"MyTestModule\");\n TypeBuilder typeBuilder = moduleBuilder.DefineType(\"MyType\");\n MethodBuilder methodBuilder = typeBuilder.DefineMethod(\"MyMethod\", MethodAttributes.Public | MethodAttributes.Static\n , typeof(int), new Type[] { typeof(int), typeof(int), typeof(int) });\n generateAction(methodBuilder.GetILGenerator());\n return typeBuilder.CreateType().GetMethod(\"MyMethod\")!;\n }\n\n public static void Main()\n {\n MethodInfo methodInfo = GenerateMethod(il =>\n {\n il.Emit(OpCodes.Ldarg_0);\n il.Emit(OpCodes.Ldarg_1);\n il.Emit(OpCodes.Add);\n il.Emit(OpCodes.Ldarg_2);\n il.Emit(OpCodes.Add);\n il.Emit(OpCodes.Ret);\n });\n var func = methodInfo.CreateDelegate<Func<int, int, int, int>>();\n var result = func(1, 2, 3);\n Console.WriteLine($\"result is {result}\");\n }\n}\n
\u8fd9\u91cc\u6211\u4eec\u5728\u4e0a\u9762\u66f4\u6539\u4e86\u65b9\u6cd5\u7684\u5b9a\u4e49, \u4f7f\u5b83\u53d8\u4e3a\u5e26\u6709 int
\u8fd4\u56de\u503c\u4e14\u63a5\u6536 3 \u4e2a\u53c2\u6570\u7684\u65b9\u6cd5, \u7136\u540e\u9002\u5f53\u4fee\u6539\u6211\u4eec\u8c03\u7528\u8fd9\u4e2a\u65b9\u6cd5\u7684\u5730\u65b9, \u7136\u540e\u8fd0\u7528\u6211\u4eec\u521a\u624d\u7684 IL
\u77e5\u8bc6\u5b9e\u73b0\u8fd9\u4e2a\u65b9\u6cd5. \u73b0\u5728, \u8fd0\u884c\u5b83, \u4f60\u5e94\u8be5\u4f1a\u5f97\u5230 result is 6
\u7684\u8f93\u51fa, \u4f46\u662f\u6211\u4eec\u5168\u7a0b\u90fd\u6ca1\u6709\u5728 C#
\u4ee3\u7801\u4e2d\u4f7f\u7528 +
\u8fd0\u7b97\u7b26, \u800c\u662f\u76f4\u63a5\u5728 IL
\u4e2d\u8c03\u7528 add
\u64cd\u4f5c\u7b26, \u4ece\u67d0\u4e9b\u65b9\u9762\u6765\u8bf4\u8fd9\u633a\u6709\u8da3\u7684.
\u73b0\u5728, \u8bd5\u7740\u5b8c\u6210\u4e00\u4e2a\u5c0f\u7ec3\u4e60, \u5c06\u4e0a\u9762 GenerateMethod
\u65b9\u6cd5\u91cc\u5bf9 MyMethod
\u7684\u5b9e\u73b0\u4ece a + b + c
\u66f4\u6539\u4e3a a + b * c
.
\u63d0\u793a\u7b54\u6848 \u4e58\u6cd5\u7684\u64cd\u4f5c\u7b26\u4e3a mul
, \u5176\u4f7f\u7528\u65b9\u6cd5\u4e0e add
\u4e00\u81f4.
\u65b9\u6cd5\u4e00\u65b9\u6cd5\u4e8c\u89e3\u91ca il.Emit(OpCodes.Ldarg_1);\nil.Emit(OpCodes.Ldarg_2);\nil.Emit(OpCodes.Mul);\nil.Emit(OpCodes.Ldarg_0);\nil.Emit(OpCodes.Add);\nil.Emit(OpCodes.Ret);\n
il.Emit(OpCodes.Ldarg_0);\nil.Emit(OpCodes.Ldarg_1);\nil.Emit(OpCodes.Ldarg_2);\nil.Emit(OpCodes.Mul);\nil.Emit(OpCodes.Add);\nil.Emit(OpCodes.Ret);\n
\u5728\u65b9\u6cd5\u4e00\u4e2d\u6211\u4eec\u7684\u601d\u8def\u5f88\u81ea\u7136, \u5148\u538b\u5165\u540e\u4e24\u4e2a\u53c2\u6570\u4f7f\u5176\u76f8\u4e58\u540e\u518d\u4e0e\u7b2c\u4e00\u4e2a\u53c2\u6570\u76f8\u52a0. \u4e5f\u5c31\u662f\u5b9e\u73b0\u7684\u662f (b * c) + a
. \u5728\u65b9\u6cd5\u4e8c\u4e2d\u5c31\u9700\u8981\u52a8\u70b9\u8111\u5b50, \u6211\u4eec\u4e00\u6b21\u6027\u5c06\u4e09\u4e2a\u53c2\u6570\u538b\u5165\u4e86\u6808\u4e2d, \u7136\u540e\u6267\u884c\u4e00\u4e2a mul
\u64cd\u4f5c, \u5b83\u4f1a\u628a\u6700\u540e\u538b\u5165\u7684\u4e24\u4e2a\u5143\u7d20\u5f39\u51fa\u76f8\u4e58\u540e\u538b\u5165, \u7136\u540e\u6211\u4eec\u9a6c\u4e0a\u518d\u6267\u884c\u4e00\u4e2a add
\u64cd\u4f5c, \u5c06\u521a\u521a\u88ab\u538b\u5165\u7684\u5143\u7d20\u4e0e\u6700\u5f00\u59cb\u88ab\u538b\u5165\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u76f8\u52a0, \u4e5f\u5c31\u662f\u5b9e\u73b0\u7684\u662f a + (b * c)
.
\u73b0\u5728\u4f60\u53ef\u4ee5\u8bd5\u7740\u73a9\u4e00\u4e9b\u6709\u8da3\u7684\u4e1c\u897f, \u6bd4\u5982\u8bd5\u7740\u7528 ldarg.3
\u538b\u5165\u4e00\u4e2a\u4e0d\u5b58\u5728\u7684\u7b2c\u56db\u4e2a\u53c2\u6570, \u6216\u8005\u5728 ret
\u65f6\u8bc4\u4f30\u6808\u4e0a\u6ca1\u6709\u5143\u7d20\u6216\u8005\u6709\u5f88\u591a\u4e2a\u5143\u7d20. \u2003\u2014\u2014\u2014\u2014 \u5b83\u4eec\u90fd\u4f1a\u8ff7\u60d1 jit \u7136\u540e\u4e0d\u77e5\u6240\u63aa\u5730\u6254\u7ed9\u4f60\u4e00\u4e2a InvalidProgramException
.
\u90a3\u4e48\u518d\u6765\u8bd5\u8bd5 a - b + c
:
\u63d0\u793a\u7b54\u6848 \u51cf\u6cd5\u7684\u64cd\u4f5c\u7b26\u4e3a sub
, \u5b83\u4f1a\u5f39\u51fa\u4e24\u4e2a\u503c, \u5c06\u540e\u5f39\u51fa\u7684\u503c\u51cf\u53bb\u5148\u5f39\u51fa\u7684\u503c\u540e\u5c06\u7ed3\u679c\u538b\u5165\u8bc4\u4f30\u6808.
il.Emit(OpCodes.Ldarg_0);\nil.Emit(OpCodes.Ldarg_1);\nil.Emit(OpCodes.Sub);\nil.Emit(OpCodes.Ldarg_2);\nil.Emit(OpCodes.Add);\nil.Emit(OpCodes.Ret);\n
\u4f60\u53ef\u80fd\u5df2\u7ecf\u53d1\u73b0\u7684\u4e00\u4e2a\u6bd4\u8f83\u8212\u670d\u7684\u70b9\u662f, \u76f8\u51cf\u7684\u987a\u5e8f\u521a\u597d\u5c31\u662f\u538b\u5165\u7684\u987a\u5e8f, \u4e5f\u5373\u5f39\u51fa\u7684\u9006\u987a\u5e8f, \u8fd9\u70b9\u4f1a\u8ba9\u6211\u4eec\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u624b\u5199 IL
\u7684\u66f4\u7b26\u5408\u76f4\u89c9\u4e00\u70b9."},{"location":"trans/il/#_5","title":"\u65b9\u6cd5\u7684\u8c03\u7528","text":"\u73b0\u5728\u6211\u4eec\u7684 IL
\u6307\u4ee4\u53ea\u80fd\u505a\u4e9b\u52a0\u52a0\u51cf\u51cf\u662f\u4e0d\u662f\u5f88\u65e0\u804a? \u90a3\u4e48\u73b0\u5728\u6211\u4eec\u6765\u8bd5\u8bd5\u5728 IL
\u4e2d\u8c03\u7528\u65b9\u6cd5. \u5728 IL
\u4e2d\u6709\u4e09\u79cd\u8c03\u7528\u65b9\u6cd5\u6307\u4ee4:
\u64cd\u4f5c\u7b26 \u53c2\u6570 \u63cf\u8ff0 call
\u65b9\u6cd5 token \u6839\u636e\u65b9\u6cd5\u7684\u53c2\u6570\u5217\u8868(\u5305\u542b this
, \u5982\u679c\u5176\u662f\u6210\u5458\u65b9\u6cd5\u65f6)\u9006\u987a\u5e8f\u5f39\u51fa\u5bf9\u5e94\u6570\u91cf\u53c2\u6570\u5e76\u4ee5\u6b64\u8c03\u7528\u5bf9\u5e94\u65b9\u6cd5 callvirt
\u65b9\u6cd5 token \u540c call
, \u4f46\u662f\u8be5\u6307\u4ee4\u5728\u5bf9\u5e94\u65b9\u6cd5\u4e3a\u865a\u65b9\u6cd5\u65f6\u4f1a\u5411\u4e0b\u5bfb\u627e\u91cd\u5199\u540e\u7684\u65b9\u6cd5 calli
callsite \u63cf\u8ff0 \u6839\u636e callsite \u63cf\u8ff0 \u5f39\u51fa\u5bf9\u5e94\u53c2\u6570\u5e76\u518d\u6b21\u5f39\u51fa\u6240\u9700\u7684\u51fd\u6570\u6307\u9488\u5e76\u8c03\u7528 \u5176\u4e2d\u7528\u7684\u6700\u591a\u7684\u662f call
\u548c callvirt
, \u6700\u540e\u4e00\u4e2a calli
\u5728\u505a\u4e0e\u672c\u673a\u4ea4\u4e92\u65f6\u624d\u5e38\u7528, \u56e0\u4e3a\u5b83\u8981\u6c42\u6211\u4eec\u6709\u5bf9\u5e94\u7684\u51fd\u6570\u6307\u9488(\u51fd\u6570\u6307\u9488\u53ef\u80fd\u5f88\u591a\u6559\u7a0b\u4e0d\u4f1a\u63d0\u53ca, \u4f60\u53ef\u4ee5\u5728MSDN \u4e0a\u7684\u4e0d\u5b89\u5168\u4ee3\u7801\u3001\u6570\u636e\u6307\u9488\u548c\u51fd\u6570\u6307\u9488\u8fd9\u7bc7\u6587\u7ae0\u4e2d\u4e86\u89e3).
call
\u4e0e callvirt
\u6700\u4e3b\u8981\u7684\u533a\u522b\u662f, call
\u6307\u4ee4\u4e00\u65e6\u6307\u5b9a\u4e86\u5bf9\u5e94\u65b9\u6cd5, \u90a3\u4e48\u5728\u8fd0\u884c\u65f6\u8c03\u7528\u7684\u65b9\u6cd5\u662f\u4e0d\u4f1a\u53d8\u7684, \u6240\u4ee5\u5b83\u901a\u5e38\u751f\u6210\u4e8e\u9759\u6001\u65b9\u6cd5\u7684\u8c03\u7528\u4e2d, \u800c callvirt
\u5728\u8fd0\u884c\u65f6\u4f1a\u68c0\u6d4b\u76ee\u6807\u7c7b\u578b, \u5e76\u5411\u4e0b\u67e5\u627e\u53ef\u80fd\u7684\u88ab\u91cd\u5199\u540e\u7684\u65b9\u6cd5, \u6240\u4ee5\u6309\u5b57\u9762\u610f\u601d\u5b83\u7ecf\u5e38\u751f\u6210\u4e8e\u865a\u65b9\u6cd5\u7684\u8c03\u7528\u4e2d, \u4e0d\u8fc7\u4e00\u822c\u5bf9\u4e8e\u666e\u901a\u6210\u5458\u65b9\u6cd5\u7684\u8c03\u7528, C#
\u7f16\u8bd1\u5668\u4e5f\u4f1a\u751f\u6210 callvirt
\u6307\u4ee4, \u8fd9\u662f\u56e0\u4e3a callvirt
\u9700\u8981\u68c0\u67e5\u76ee\u6807\u7c7b\u578b, \u5728\u8c03\u7528\u5bf9\u8c61\u4e3a null
\u65f6\u5c31\u629b\u51fa NullReferenceException
, \u800c call
\u6307\u4ee4\u53ef\u80fd\u76f4\u5230\u65b9\u6cd5\u8c03\u7528\u4e00\u534a\u65f6\u624d\u5bdf\u89c9 this
\u4e3a null
, \u8fd9\u662f\u4e00\u4e2a\u5f88\u5371\u9669\u7684\u884c\u4e3a.
\u5728\u6211\u4eec\u5e9f\u8bdd\u5b8c\u4e4b\u540e, \u662f\u65f6\u5019\u505a\u4e00\u70b9\u5b9e\u9645\u7684\u4e86. \u73b0\u5728, \u6211\u4eec\u4e0d\u9700\u8981\u6211\u4eec\u4e4b\u524d\u6d4b\u8bd5 add
, ret
, mul
, sub
\u6307\u4ee4\u65f6\u58f0\u660e\u7684\u65b9\u6cd5\u7b7e\u540d\u4e86, \u6240\u4ee5\u6211\u4eec\u66f4\u6539\u5982\u4e0b\u4ee3\u7801, \u4f7f\u5f97\u6211\u4eec\u7684\u52a8\u6001\u65b9\u6cd5 MyMethod
\u8fd4\u56de void
\u5e76\u4e14\u4e0d\u63a5\u6536\u53c2\u6570:
public static MethodInfo GenerateMethod(Action<ILGenerator> generateAction)\n{\n AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new(\"MyAssembly\"), AssemblyBuilderAccess.RunAndCollect);\n ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule(\"MyTestModule\");\n TypeBuilder typeBuilder = moduleBuilder.DefineType(\"MyType\");\n MethodBuilder methodBuilder = typeBuilder.DefineMethod(\"MyMethod\", MethodAttributes.Public | MethodAttributes.Static\n , typeof(void), Type.EmptyTypes);\n generateAction(methodBuilder.GetILGenerator());\n return typeBuilder.CreateType().GetMethod(\"MyMethod\")!;\n}\n
\u987a\u4fbf\u628a\u4e0b\u9762\u4e5f\u6539\u6210\u8fd9\u6837, \u4ee5\u8d34\u5408\u6211\u4eec\u5728\u4e0a\u9762\u7684\u5b9a\u4e49, \u987a\u4fbf\u6e05\u7a7a\u4e00\u4e0b\u6211\u4eec\u7684\u65b9\u6cd5\u4f53:
MethodInfo methodInfo = GenerateMethod(il =>\n{\n il.Emit(OpCodes.Ret);\n});\nvar action = methodInfo.CreateDelegate<Action>();\naction();\n
\u73b0\u5728, \u6211\u4eec\u6253\u7b97\u4f7f\u7528 IL
\u5199\u4e00\u4e2a HelloWorld \u7a0b\u5e8f, \u90a3\u4e48\u5c31\u9700\u8981\u8c03\u7528 System.Console.WriteLine(string)
\u8fd9\u4e2a\u65b9\u6cd5, \u6ce8\u610f\u6b64\u65f6\u6211\u4eec\u5fc5\u987b\u6e05\u695a\u6211\u4eec\u8c03\u7528\u7684\u65b9\u6cd5\u7684\u5177\u4f53\u67d0\u4e2a\u91cd\u8f7d, \u73b0\u5728\u4f7f\u7528\u53cd\u5c04\u77e5\u8bc6, \u83b7\u53d6\u8fd9\u4e2a\u9759\u6001\u65b9\u6cd5\u7684 MethodInfo
:
var cws = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\n
\u7136\u540e\u6211\u4eec\u89c2\u5bdf\u5b83\u7684\u53c2\u6570, \u53d1\u73b0\u9700\u8981\u4e00\u4e2a string
, \u6240\u4ee5\u6211\u4eec\u5f97\u4f7f\u7528 ldstr
IL
\u6307\u4ee4, \u5b83\u4f1a\u5c06\u5b83\u53c2\u6570 token \u5bf9\u5e94\u7684\u5b57\u7b26\u4e32\u538b\u5165\u8bc4\u4f30\u6808, \u5728\u8fd9\u91cc\u6211\u4eec\u4e0d\u9700\u8981\u5173\u5fc3\u8fd9\u4e2a token \u5982\u4f55\u751f\u6210, System.Reflection.Emit
\u4f1a\u5e2e\u6211\u4eec\u505a\u597d\u8fd9\u4e9b, \u5728\u8fd9\u91cc\u53ea\u9700\u8981\u4f20\u5165 string
:
il.Emit(OpCodes.Ldstr, \"Hello World in IL!\");\n
\u4e00\u5207\u5c31\u7eea, \u8c03\u7528\u6211\u4eec\u7684\u65b9\u6cd5:
il.Emit(OpCodes.Call, cws);\n
\u603b\u7684\u4ee3\u7801\u5982\u4e0b:
var cws = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nil.Emit(OpCodes.Ldstr, \"Hello World in IL!\");\nil.Emit(OpCodes.Call, cws);\nil.Emit(OpCodes.Ret);\n
\u73b0\u5728, \u8fd0\u884c\u7a0b\u5e8f, \u4f60\u5e94\u8be5\u4f1a\u770b\u5230\u5982\u4e0b\u8f93\u51fa: \u54c7\u4f60\u592a\u5f3a\u4e86\u4f60\u505a\u5230\u4e86\u8fd9\u4e2a\u795e\u4ed9\u64cd\u4f5c\u4f60\u600e\u4e48\u53ef\u4ee5\u8fd9\u4e48\u5f3a\uff01\uff01\uff01\u2003\u5f85\u4f1a\u513f\u6211\u8bf4\u6211\u81ea\u5df1\u5462
Hello World in IL!\n
\u5bf9\u4e8e\u6709\u8fd4\u56de\u503c\u7684\u65b9\u6cd5, call
\u8c03\u7528\u5b8c\u540e\u4f1a\u5c06\u8fd4\u56de\u503c\u538b\u5165\u5806\u6808, \u6bd4\u5982\u8981\u5c06\u4ee5\u4e0b C#
\u4ee3\u7801\u8f6c\u4e3a IL
\u4ee3\u7801:
Console.WriteLine(Console.ReadLine());\n
\u53ea\u9700\u8981\u8fd9\u6837:
var cws = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar cr = typeof(Console).GetMethod(\"ReadLine\")!;\nil.Emit(OpCodes.Call, cr);\nil.Emit(OpCodes.Call, cws);\nil.Emit(OpCodes.Ret);\n
\u5f53\u6211\u4eec\u4e0d\u9700\u8981\u8fd4\u56de\u503c\u65f6, \u6211\u4eec\u5fc5\u987b\u663e\u5f0f\u4f7f\u7528 pop
\u6307\u4ee4\u820d\u5f03\u5b83, \u9632\u6b62\u5b83\"\u6c61\u67d3\"\u6211\u4eec\u7684\u8bc4\u4f30\u6808:
// \u7b49\u5f85\u7528\u6237\u7684\u4e00\u4e2a\u56de\u8f66\u8f93\u5165\nConsole.ReadLine();\nConsole.WriteLine(\"Hey, I see you pressed the Enter!\");\n
var cws = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar cr = typeof(Console).GetMethod(\"ReadLine\")!;\nil.Emit(OpCodes.Call, cr);\nil.Emit(OpCodes.Pop);\nil.Emit(OpCodes.Ldstr, \"Hey, I see you pressed the Enter!\");\nil.Emit(OpCodes.Call, cws);\nil.Emit(OpCodes.Ret);\n
\u65b9\u6cd5\u7684\u53c2\u6570\u5217\u8868\u987a\u5e8f\u548c\u538b\u6808\u987a\u5e8f\u4e00\u81f4, \u8c03\u7528\u591a\u53c2\u6570\u65b9\u6cd5\u4e5f\u4f1a\u663e\u5f97\u5f88\u81ea\u7136:
double a = Math.Pow(123, 4);\nConsole.WriteLine(a);\n
var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(double) })!;\nvar powMethod = typeof(Math).GetMethod(\"Pow\")!;\nil.Emit(OpCodes.Ldc_R8, 123.0);\nil.Emit(OpCodes.Ldc_R8, 4.0);\nil.Emit(OpCodes.Call, powMethod);\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
ldc.r8
\u6307\u4ee4\u5c06\u53c2\u6570\u4e2d\u7684 float64
, \u5373 double
\u5b57\u9762\u91cf\u538b\u5165\u8bc4\u4f30\u6808\u4e2d, \u7c7b\u4f3c\u7684\u64cd\u4f5c\u7b26\u8fd8\u6709 ldc.i4
, \u5b83\u5c06\u53c2\u6570\u4e2d\u7684 int32
\u5373 int
\u5b57\u9762\u91cf\u538b\u5165\u8bc4\u4f30\u6808\u4e2d, \u6ce8\u610f\u5728\u8fd9\u91cc\u4f20\u53c2\u6211\u4eec\u5fc5\u987b\u660e\u786e\u5199\u660e\u53c2\u6570\u7c7b\u578b, \u6bd4\u5982\u4e0a\u9762\u7684 IL
\u5982\u679c\u4f7f\u7528 123
\u800c\u4e0d\u662f 123.0
\u4f1a\u53d1\u751f jit \u5f02\u5e38\u6216\u884c\u4e3a\u975e\u671f\u671b, \u56e0\u4e3a\u53c2\u6570\u7c7b\u578b\u4e0d\u5339\u914d, 123
\u5339\u914d\u5230\u4e86 il.Emit
\u7684 int
\u91cd\u8f7d, \u800c\u6211\u4eec\u9700\u8981\u7684\u662f double
\u91cd\u8f7d, \u6240\u4ee5\u6211\u4eec\u5199\u660e 123.0
\u6216 123d
\u4ee5\u4f7f\u5176\u6210\u4e3a double
\u7c7b\u578b\u7684\u5b57\u9762\u91cf. \u5bf9\u4e8e float
long
double
\u7b49\u8fd9\u4e9b\u6709\u5bf9\u5e94\u5b57\u9762\u91cf\u540e\u7f00\u7684(f
, l
, d
) \u7c7b\u578b\u6211\u4eec\u76f4\u63a5\u52a0\u540e\u7f00\u5c31\u884c\u4e86, \u4f46\u5bf9\u4e8e short
\u548c byte
\u8fd9\u4e9b, \u6211\u4eec\u5fc5\u987b\u8fdb\u884c\u663e\u5f0f\u5f3a\u8f6c:
public static void Main()\n{\n MethodInfo methodInfo = GenerateMethod(il =>\n {\n // il \u4e2d\u6ca1\u6709\u5bf9\u5e94\u7684\u52a0\u8f7d `int16` \u548c `int8` \u7684\u6307\u4ee4, \u6211\u4eec\u5f97\u4f7f\u7528 `ldc.i4`, \n // \u867d\u7136\u5b83\u672c\u6765\u662f\u7528\u6765\u52a0\u8f7d `int32` \u7684, \u4f46 jit \u4f1a\u77e5\u9053\u6211\u4eec\u60f3\u8981\u5e72\u4ec0\u4e48\n // \u5bf9\u4e8e\u5c0f\u4e00\u70b9\u7684\u6574\u6570\u5b57\u9762\u91cf IL \u8fd8\u63d0\u4f9b\u4e86\u4e00\u4e2a `ldc.i4.s` \u6307\u4ee4\n // \u5176\u53c2\u6570\u4e3a `int8` \u5373 `byte` \u6216 `sbyte` \u7c7b\u578b\n var printByte = typeof(Program).GetMethod(\"PrintByte\")!;\n il.Emit(OpCodes.Ldc_I4_S, (byte)12);\n il.Emit(OpCodes.Call, printByte);\n il.Emit(OpCodes.Ldc_I4, (int)12);\n il.Emit(OpCodes.Call, printByte);\n il.Emit(OpCodes.Ret);\n });\n var action = methodInfo.CreateDelegate<Action>();\n action();\n\n}\n\npublic static void PrintByte(byte v)\n{\n Console.WriteLine($\"Your byte is {v}\");\n}\n
"},{"location":"trans/il/#_6","title":"\u5bf9\u8c61\u5b9e\u4f8b\u5316","text":"\u8fd9\u4e00\u6b65\u5f88\u7b80\u5355, \u4e3a\u4e86\u5b9e\u4f8b\u5316\u4e00\u4e2a\u5bf9\u8c61, \u6211\u4eec\u9700\u8981\u4f7f\u7528 newobj
\u64cd\u4f5c\u7b26, \u5176\u53c2\u6570\u4e3a\u5bf9\u5e94\u5bf9\u8c61\u7684\u4e00\u4e2a\u6784\u9020\u5668, \u8be5\u6307\u4ee4\u6267\u884c\u540e\u4f1a\u5c06\u6211\u4eec\u8981\u7684\u5bf9\u8c61\u538b\u5165\u8bc4\u4f30\u6808, \u6bd4\u5982\u5982\u4e0b C#
\u4ee3\u7801:
new StringBuilder();\n
\u6211\u4eec\u9700\u8981\u8fd9\u6837\u751f\u6210\u5b83\u7684 IL
:
var sbctor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes)!;\nil.Emit(OpCodes.Newobj, sbctor);\n
"},{"location":"trans/il/#_7","title":"\u6210\u5458\u65b9\u6cd5\u7684\u8c03\u7528","text":"\u73b0\u5728, \u6211\u4eec\u5728\u8bc4\u4f30\u6808\u4e0a\u6709\u4e86\u4e00\u4e2a\u5bf9\u8c61, \u6211\u4eec\u5c31\u53ef\u4ee5\u7528\u5b83\u8c03\u7528\u5b83\u7684\u6210\u5458\u65b9\u6cd5\u4e86. \u6210\u5458\u65b9\u6cd5\u7684\u8c03\u7528\u4e0e\u9759\u6001\u65b9\u6cd5\u8c03\u7528\u57fa\u672c\u4e00\u81f4, \u4f46\u662f\u6bcf\u6b21\u8c03\u7528\u4e4b\u524d\u6211\u4eec\u90fd\u5fc5\u987b\u8bb0\u5f97\u5c06 this
\u7684\u503c\u4f5c\u4e3a\u7b2c0\u4e2a\u53c2\u6570\u538b\u5165\u5806\u6808, \u987a\u4fbf, \u8bb0\u4f4f\u8fd9\u91cc\u7684 this
\u662f\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7684, \u6bcf\u6b21\u8c03\u7528\u90fd\u4f1a\u88ab\u5f39\u51fa\u8bc4\u4f30\u6808, \u6240\u4ee5\u5728\u8fde\u7eed\u8c03\u7528\u5b83\u7684\u6210\u5458\u65b9\u6cd5\u65f6\u8bb0\u5f97\u5c06 this
\u518d\u6b21\u538b\u5165. \u901a\u5e38\u6211\u4eec\u4f1a\u4f7f\u7528 callvirt
\u6765\u8c03\u7528\u6210\u5458\u65b9\u6cd5, \u4e00\u65b9\u9762\u4e3a\u4e86\u786e\u4fdd\u8c03\u7528\u5230\u4e86\u91cd\u5199\u540e\u7684\u865a\u51fd\u6570, \u4e00\u65b9\u9762\u4e3a\u4e86\u5c3d\u53ef\u80fd\u65e9\u7684\u68c0\u6d4b\u51fa this
\u4e3a null.
Console.WriteLine(new StringBuilder().Append(\"abc\").Append(\"def\").Append(\"ghi\").ToString());\n
var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar sbctor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes)!;\nvar appendMethod = typeof(StringBuilder).GetMethod(\"Append\", new Type[] { typeof(string) })!;\nvar toStringMethod = typeof(StringBuilder).GetMethod(\"ToString\", Type.EmptyTypes)!;\n// StringBuilder.Append \u65b9\u6cd5\u4f1a\u8fd4\u56de\u81ea\u8eab, \u6240\u4ee5\u8fd9\u91cc\u7684 `this` \u5728\u65b9\u6cd5\u88ab\u8c03\u7528\u540e\u53c8\u88ab\u5f39\u51fa\u53c8\u88ab\u538b\u5165\nil.Emit(OpCodes.Newobj, sbctor);\nil.Emit(OpCodes.Ldstr, \"abc\");\nil.Emit(OpCodes.Callvirt, appendMethod);\nil.Emit(OpCodes.Ldstr, \"def\");\nil.Emit(OpCodes.Callvirt, appendMethod);\nil.Emit(OpCodes.Ldstr, \"ghi\");\nil.Emit(OpCodes.Callvirt, appendMethod);\nil.Emit(OpCodes.Callvirt, toStringMethod);\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
\u4f46\u662f\u5b9e\u9645\u4e0a, \u6211\u4eec\u660e\u786e\u77e5\u9053 StringBuilder
\u662f\u5bc6\u5c01\u7684, \u6ca1\u4eba\u4f1a\u91cd\u5199\u5b83\u7684\u865a\u65b9\u6cd5, \u4ee5\u53ca\u8fd9\u91cc\u6211\u4eec\u660e\u786e\u77e5\u9053\u8fd9\u91cc\u7684 this
\u4e0d\u4e3a null, \u6240\u4ee5\u5b9e\u9645\u4e0a\u4e0a\u9762\u7684 callvirt
\u90fd\u80fd\u6362\u6210 call
:
var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar sbctor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes)!;\nvar appendMethod = typeof(StringBuilder).GetMethod(\"Append\", new Type[] { typeof(string) })!;\nvar toStringMethod = typeof(StringBuilder).GetMethod(\"ToString\", Type.EmptyTypes)!;\n// StringBuilder.Append \u65b9\u6cd5\u4f1a\u8fd4\u56de\u81ea\u8eab, \u6240\u4ee5\u8fd9\u91cc\u7684 `this` \u5728\u65b9\u6cd5\u88ab\u8c03\u7528\u540e\u53c8\u88ab\u5f39\u51fa\u53c8\u88ab\u538b\u5165\nil.Emit(OpCodes.Newobj, sbctor);\nil.Emit(OpCodes.Ldstr, \"abc\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Ldstr, \"def\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Ldstr, \"ghi\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Call, toStringMethod);\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
"},{"location":"trans/il/#_8","title":"\u5c40\u90e8\u53d8\u91cf","text":"\u4e5f\u8bb8\u4f60\u4e5f\u53d1\u73b0\u4e86, \u6211\u4eec\u4e0a\u9762\u7684\u4ee3\u7801\u90fd\u6709\u4e9b\"\u618b\u5c48\", \u8fd9\u662f\u56e0\u4e3a\u6211\u4eec\u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\u6ca1\u6709\u7528\u5230\u5c40\u90e8\u53d8\u91cf. \u5728 System.Reflection.Emit
\u4e2d, \u6211\u4eec\u5fc5\u987b\u663e\u5f0f\u6307\u5b9a\u6211\u4eec\u53ef\u80fd\u7528\u5230\u51e0\u4e2a\u5c40\u90e8\u53d8\u91cf\u4ee5\u53ca\u5bf9\u5e94\u7684\u7c7b\u578b, \u6bd4\u5982\u5982\u4e0b C# \u4ee3\u7801:
StringBuilder sb = new();\nsb.Append(\"abc\");\nsb.Append(\"def\");\nsb.Append(\"ghi\");\nstring str = sb.ToString();\nConsole.WriteLine(str);\n
\u6211\u4eec\u8fdb\u884c\u5206\u6790, \u53d1\u73b0\u5b83\u4f7f\u7528\u4e86\u4e24\u4e2a\u5c40\u90e8\u53d8\u91cf: sb
\u548c str
, \u6240\u4ee5\u6211\u4eec\u5728\u8c03\u7528 il.Emit
\u4e4b\u524d\u8c03\u7528 il.DeclareLocal
:
il.DeclareLocal(typeof(StringBuilder)); // 0\nil.DeclareLocal(typeof(string)); // 1\n
\u6ce8\u610f\u6211\u4eec\u8c03\u7528 DeclareLocal
\u7684\u987a\u5e8f, \u8fd9\u4e2a\u987a\u5e8f\u6211\u4eec\u5728\u4e0b\u9762\u7684 IL
\u4e2d\u5c31\u4f1a\u4f7f\u7528\u5b83:
\u54e6\u5929\u54ea\u5b83\u771f\u7684\u592a\u957f\u4e86var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar sbctor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes)!;\nvar appendMethod = typeof(StringBuilder).GetMethod(\"Append\", new Type[] { typeof(string) })!;\nvar toStringMethod = typeof(StringBuilder).GetMethod(\"ToString\", Type.EmptyTypes)!;\n\nil.DeclareLocal(typeof(StringBuilder)); // 0\nil.DeclareLocal(typeof(string)); // 1\n\nil.Emit(OpCodes.Newobj, sbctor);\n// \u5c06\u6211\u4eec\u7684 StringBuilder \u5bf9\u8c61\u5b58\u5230 0 \u53f7\u4f4d\u7684\u5c40\u90e8\u53d8\u91cf\u4e0a\nil.Emit(OpCodes.Stloc_0); \n// \u628a\u6211\u4eec\u4e4b\u524d\u5728 0 \u53f7\u4f4d\u5c40\u90e8\u53d8\u91cf\u4e0a\u5b58\u7684 StringBuilder \u5bf9\u8c61\u8bfb\u53d6\u51fa\u6765\u5e76\u538b\u5165\u8bc4\u4f30\u6808\u4e0a\nil.Emit(OpCodes.Ldloc_0); \n// \u51c6\u5907 StringBuilder.Append \u7684\u90a3\u4e2a\u53c2\u6570\u4f5c\u4e3a\u5176\u5185\u90e8 ldarg.1 \u4f1a\u8bfb\u53d6\u7684\u503c(ldarg.0 \u662f this)\nil.Emit(OpCodes.Ldstr, \"abc\");\nil.Emit(OpCodes.Call, appendMethod);\n// \u6211\u4eec\u5728\u8fd9\u91cc\u4e0d\u4f1a\u4f7f\u7528 StringBuilder.Append \u7684\u90a3\u4e2a\u7528\u4e8e\u94fe\u5f0f\u8c03\u7528\u7684\u8fd4\u56de\u503c\n// \u6240\u4ee5\u6211\u4eec\u4f7f\u7528 `pop` \u5f39\u51fa\u5b83\u907f\u514d\"\u6c61\u67d3\"\u6211\u4eec\u7684\u8bc4\u4f30\u6808.\nil.Emit(OpCodes.Pop);\nil.Emit(OpCodes.Ldloc_0);\nil.Emit(OpCodes.Ldstr, \"def\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Pop);\nil.Emit(OpCodes.Ldloc_0);\nil.Emit(OpCodes.Ldstr, \"ghi\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Pop);\nil.Emit(OpCodes.Ldloc_0);\nil.Emit(OpCodes.Call, toStringMethod);\nil.Emit(OpCodes.Stloc_1);\nil.Emit(OpCodes.Ldloc_1);\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
\u5728\u4e0a\u9762\u7684 IL
\u4e2d, stloc.0
\u5c06\u6808\u9876\u7684\u503c\u5f39\u51fa\u5e76\u5b58\u5230\u5c40\u90e8\u53d8\u91cf 0 \u53f7\u4f4d\u4e0a, ldloc.0
\u8bfb\u53d6\u5c40\u90e8\u53d8\u91cf 0 \u53f7\u4f4d\u7684\u503c\u7136\u540e\u5c06\u5176\u538b\u5165\u8bc4\u4f30\u6808\u4e0a. \u4e0d\u8fc7\u5b9e\u9645\u4e0a\u8fd9\u91cc\u7528\u4e0d\u7740\u5c40\u90e8\u53d8\u91cf, \u9664\u4e86\u4f7f\u7528 Append
\u8fd4\u56de\u7684 this
\u4e4b\u5916, \u6211\u4eec\u8fd8\u53ef\u4ee5\u4f7f\u7528 dup
\u6307\u4ee4\u6765\u7b80\u5316\u5927\u91cf\u7684 ldloc.0
\u64cd\u4f5c. \u9664\u6b64\u4e4b\u5916 string
\u90a3\u4e2a\u5c40\u90e8\u53d8\u91cf\u4e5f\u7528\u4e0d\u7740, \u6211\u4eec\u5728 ToString
\u540e\u76f4\u63a5\u8c03\u7528 Console.WriteLine
\u5373\u53ef, \u56e0\u4e3a\u8fd9\u65f6\u7684 string
\u521a\u597d\u5c31\u5728\u6808\u9876.
il.Emit(OpCodes.Newobj, sbctor);\n\nil.Emit(OpCodes.Dup);\nil.Emit(OpCodes.Ldstr, \"abc\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Pop);\n\nil.Emit(OpCodes.Dup);\nil.Emit(OpCodes.Ldstr, \"def\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Pop);\n\nil.Emit(OpCodes.Dup);\nil.Emit(OpCodes.Ldstr, \"ghi\");\nil.Emit(OpCodes.Call, appendMethod);\nil.Emit(OpCodes.Pop);\n\nil.Emit(OpCodes.Dup);\nil.Emit(OpCodes.Call, toStringMethod);\nil.Emit(OpCodes.Call, cw);\n\n// \u8bb0\u5f97\u5f39\u51fa\u6700\u521d newobj \u6307\u4ee4\u538b\u5165\u7684\u90a3\u4e2a\u5143\u7d20, \u5426\u5219\u6b64\u65f6 ret \u6808\u5c31\u4e0d\u662f\u7a7a\u7684\u4e86\n// \u8fd9\u4f1a\u5bfc\u81f4 jit \u629b\u51fa InvalidProgramException\nil.Emit(OpCodes.Pop);\n\nil.Emit(OpCodes.Ret);\n
dup
\u6307\u4ee4\u5f39\u51fa\u6808\u9876\u7684\u5143\u7d20, \u7136\u540e\u538b\u5165\u4e24\u904d\u8fd9\u4e2a\u5143\u7d20, \u4e5f\u5c31\u662f\u5b83\u4f1a\u590d\u5236\u6808\u9876\u7684\u5143\u7d20\u4e00\u904d\u5e76\u538b\u5165, \u5728\u8fd9\u91cc, \u6211\u4eec\u4f7f\u7528 dup
\u6307\u4ee4\u5728\u6bcf\u6b21\u9700\u8981 this
\u5bf9\u8c61\u65f6\u590d\u5236\u6700\u521d newobj
\u6307\u4ee4\u538b\u5165\u7684\u5143\u7d20, \u8fd9\u6837\u5c31\u65e0\u9700\u4f7f\u7528\u5c40\u90e8\u53d8\u91cf\u800c\u590d\u6742\u5316\u6211\u4eec\u7684 IL
\u4e86.
"},{"location":"trans/il/#_9","title":"\u5c5e\u6027\u7684\u8bbf\u95ee","text":"\u5728 IL
\u4e2d, \u5176\u5b9e\u6ca1\u6709\u4e00\u6761\u6307\u4ee4\u662f\u5173\u4e8e\u5c5e\u6027\u7684, \u56e0\u4e3a\u6211\u4eec\u77e5\u9053\u5c5e\u6027\u5b9e\u9645\u4e0a\u5c31\u662f\u4e00\u5bf9 getter \u548c setter \u800c\u5df2. \u901a\u5e38, \u4e00\u4e2a\u540d\u4e3a MyProp
\u7684\u5c5e\u6027\u7684 getter \u65b9\u6cd5\u53eb\u505a get_MyProp
, setter \u65b9\u6cd5\u53eb\u505a set_MyProp
, \u5982\u679c\u4f60\u5728 C# \u4e2d\u5c1d\u8bd5\u7ed9\u65b9\u6cd5\u8fd9\u6837\u8d77\u540d\u4f60\u4f1a\u53d1\u73b0\u7f16\u8bd1\u5668\u4f1a\u4e3a\u4e86\u9632\u6b62\u65b9\u6cd5\u91cd\u540d\u800c\u62a5\u9519, \u987a\u4fbf, \u8fd9\u4e00\u5bf9\u65b9\u6cd5\u5b83\u4eec\u5404\u81ea\u90fd\u6709\u4e00\u4e2a special name
\u7684\u7279\u6b8a\u6807\u8bb0\u4ee5\u4fbf\u7f16\u8bd1\u5668\u77e5\u6653\u5b83\u4eec\u5f52\u5c5e\u4e8e\u4e00\u4e2a\u5c5e\u6027.
\u6bd4\u5982\u5982\u4e0b C#
\u4ee3\u7801:
Console.WriteLine(\"123\".Length);\n
var cwInt = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(int) })!;\nvar stringGetLength = typeof(string).GetMethod(\"get_Length\")!;\nil.Emit(OpCodes.Ldstr, \"123\");\nil.Emit(OpCodes.Call, stringGetLength);\nil.Emit(OpCodes.Call, cwInt);\nil.Emit(OpCodes.Ret);\n
\u5728\u8fd9\u91cc\u6211\u4eec\u8c03\u7528\u7684\u5c31\u662f string
\u7684 get_Length
\u65b9\u6cd5. \u5c31\u662f\u8fd9\u4e48\u7b80\u5355.
"},{"location":"trans/il/#_10","title":"\u5b57\u6bb5\u7684\u8bbf\u95ee","text":"\u5bf9\u4e8e\u9759\u6001\u5b57\u6bb5\u7684\u8bbf\u95ee, \u6211\u4eec\u9700\u8981\u4f7f\u7528 ldsfld
\u64cd\u4f5c\u7b26, \u6bd4\u5982 Path.DirectorySeparatorChar
\u8fd9\u4e2a\u9759\u6001\u5b57\u6bb5:
Console.WriteLine(Path.DirectorySeparatorChar);\n
// \u6ce8\u610f\u4e0b\u8fd9\u91cc WriteLine \u7684\u91cd\u8f7d\u6362\u4e86, \u56e0\u4e3a Path.DirectorySeparatorChar \u662f char \u7c7b\u578b\u7684\nvar cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(char) })!;\nvar pathStfld = typeof(Path).GetField(\"DirectorySeparatorChar\")!;\nil.Emit(OpCodes.Ldsfld, pathStfld);\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
ldsfld
\u4f1a\u5c06\u53c2\u6570\u4e2d\u7684\u9759\u6001\u5b57\u6bb5\u7684 token \u5bf9\u5e94\u7684\u9759\u6001\u5b57\u6bb5\u7684\u503c\u538b\u5165\u8bc4\u4f30\u6808\u4e0a.
\u5bf9\u4e8e\u6210\u5458\u5b57\u6bb5\u7684\u8bbf\u95ee\u4e5f\u662f\u7c7b\u4f3c\u7684, \u4e0d\u8fc7\u5b83\u4f1a\u9700\u8981\u5f39\u51fa\u4e00\u4e2a this
\u5143\u7d20, \u6bd4\u5982\u5bf9\u4e8e\u5982\u4e0b C# \u7c7b:
\u5176\u5b9e\u662f\u627e\u4e0d\u5230\u00a0bcl\u00a0\u91cc\u7ecf\u5e38\u8bbf\u95ee\u6210\u5458\u5b57\u6bb5\u7684\u4f8b\u5b50\u624d\u88ab\u8feb\u58f0\u660e\u65b0\u7c7b\u7684
public class SomeClass\n{\n public string SomeString;\n public SomeClass()\n => SomeString = \"\u8fd9\u91cc\u662f\u4e00\u4e2a\u5b57\u7b26\u4e32!\";\n}\n
var someClassCtor = typeof(SomeClass).GetConstructor(Type.EmptyTypes)!;\nvar cwString = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar someClassFld = typeof(SomeClass).GetField(\"SomeString\")!;\nil.Emit(OpCodes.Newobj, someClassCtor);\nil.Emit(OpCodes.Ldfld, someClassFld);\nil.Emit(OpCodes.Call, cwString);\nil.Emit(OpCodes.Ret);\n
"},{"location":"trans/il/#_11","title":"\u8df3\u8f6c\u6307\u4ee4","text":"\u5728\u8fd9\u91cc\u6211\u4eec\u4f1a\u4ecb\u7ecd\u8fd9\u4e00\u8282\u7684\u6700\u540e\u4e00\u4e2a\u4e1c\u897f \u2014\u2014 \u8df3\u8f6c\u6307\u4ee4. \u5b83\u662f C# \u4e2d if
switch
for
while
goto
\u7b49\u6d41\u7a0b\u63a7\u5236\u8bed\u53e5\u90fd\u5341\u5206\u4f9d\u8d56\u7684\u4e1c\u897f.
\u5728 IL
\u4e2d, \u4e3a\u4e86\u65b9\u4fbf \u5927\u4e8e, \u5c0f\u4e8e, \u5927\u4e8e\u7b49\u4e8e, \u5c0f\u4e8e\u7b49\u4e8e, \u662f\u5426 null, \u662f\u5426\u975e0 \u7b49\u4f17\u591a\u6761\u4ef6\u8868\u8fbe\u5f0f\u7684\u5224\u65ad, IL
\u5f15\u5165\u4e86\u5927\u91cf\u6709\u5173\u7684\u6307\u4ee4, \u5177\u4f53\u5982\u4e0b\u8868(\u6458\u81ea MSDN):
\u6307\u4ee4 \u63cf\u8ff0 beq\u00a0\u00a0\u00a0 \u5982\u679c\u4e24\u4e2a\u503c\u76f8\u7b49, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. beq.s\u00a0\u00a0 \u5982\u679c\u4e24\u4e2a\u503c\u76f8\u7b49, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. bge\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. bge.s\u00a0\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. bge.un\u00a0\u00a0\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6, \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. bge.un.s\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6, \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. bgt\u00a0\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. bgt.s\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. bgt.un\u00a0\u00a0\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6, \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. bgt.un.s\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6, \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5927\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. ble\u00a0\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. ble.s\u00a0\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. ble.un\u00a0\u00a0\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6, \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. ble.un.s\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6, \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u6216\u7b49\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u6743\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. blt\u00a0\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. blt.s\u00a0\u00a0\u00a0 \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. blt.un\u00a0\u00a0\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6, \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. blt.un.s\u00a0 \u5f53\u6bd4\u8f83\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u65f6, \u5982\u679c\u7b2c\u4e00\u4e2a\u503c\u5c0f\u4e8e\u7b2c\u4e8c\u4e2a\u503c, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. bne.un\u00a0\u00a0\u00a0 \u5f53\u4e24\u4e2a\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u4e0d\u76f8\u7b49\u65f6, \u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. bne.un.s\u00a0 \u5f53\u4e24\u4e2a\u65e0\u7b26\u53f7\u6574\u6570\u503c\u6216\u4e0d\u53ef\u6392\u5e8f\u7684\u6d6e\u70b9\u578b\u503c\u4e0d\u76f8\u7b49\u65f6, \u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. br\u00a0\u00a0\u00a0\u00a0 \u65e0\u6761\u4ef6\u5730\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. br.s\u00a0\u00a0\u00a0\u00a0 \u65e0\u6761\u4ef6\u5730\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. brfalse\u00a0\u00a0 \u5982\u679c value \u4e3a false\u3001\u7a7a\u5f15\u7528\uff08Visual Basic \u4e2d\u7684 Nothing\uff09\u6216\u96f6, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. brfalse.s \u5982\u679c value \u4e3a false\u3001\u7a7a\u5f15\u7528\u6216\u96f6, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. brtrue\u00a0\u00a0\u00a0 \u5982\u679c value \u4e3a true\u3001\u975e\u7a7a\u6216\u975e\u96f6, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4. brtrue.s\u00a0 \u5982\u679c value \u4e3a true\u3001\u975e\u7a7a\u6216\u975e\u96f6, \u5219\u5c06\u63a7\u5236\u8f6c\u79fb\u5230\u76ee\u6807\u6307\u4ee4\uff08\u77ed\u683c\u5f0f\uff09. \u53ef\u4ee5\u53d1\u73b0, \u57fa\u672c\u90fd\u662f\u5404\u79cd\u5927\u4e8e\u5c0f\u4e8e\u7b49\u4e8e\u975e\u7a7a\u975e0\u7b49\u4ee5\u53ca\u6709\u7b26\u53f7\u65e0\u7b26\u53f7\u8fd9\u4e9b\u60c5\u51b5\u7684\u6392\u5217\u7ec4\u5408. \u4e0a\u8868\u4e2d\u6211\u4eec\u79f0\u9664\u4e86 br
\u4e0e br.s
\u6307\u4ee4\u5916\u7684\u6307\u4ee4\u4e3a \"\u6761\u4ef6\u8df3\u8f6c\u6307\u4ee4\", \u53cd\u4e4b\u6211\u4eec\u79f0\u4e3a \"\u65e0\u6761\u4ef6\u8df3\u8f6c\u6307\u4ee4\". \u8fd9\u91cc\u6211\u4eec\u53ea\u4f1a\u7b80\u5355\u4e3e\u4f8b br
brfalse
\u8fd9\u4e24\u4e2a\u6307\u4ee4\u7684\u4f7f\u7528. \u5176\u4ed6\u6307\u4ee4\u57fa\u672c\u53ea\u662f\u51e0\u4e2a\u6761\u4ef6\u4e0d\u540c\u7c7b\u578b\u4e0d\u540c\u7684\u5dee\u522b.
brfalse
\u6307\u4ee4\u4f1a\u4ece\u8bc4\u4f30\u6808\u4e0a\u5f39\u51fa\u4e00\u4e2a\u503c, \u7136\u540e\u67e5\u770b\u8be5\u503c\u662f\u5426\u4e3a false
\u6216\u8005 null
\u6216\u8005 0
, \u5982\u679c\u662f\u5219\u8df3\u8f6c\u5230\u53c2\u6570\u6240\u6307\u7684\u76ee\u6807\u4f4d\u7f6e, \u5426\u5219\u4e0d\u505a\u4efb\u4f55\u4e8b. \u6bd4\u5982\u5982\u4e0b C# \u4ee3\u7801:
public static void MyMethod(int value)\n{\n if (value == 0)\n {\n Console.WriteLine(\"value is 0!\");\n }\n else\n {\n Console.WriteLine(\"value is not 0.\");\n }\n}\n
\u987a\u4fbf\u8bb0\u5f97\u66f4\u6539\u6211\u4eec\u7684\u65b9\u6cd5\u5b9a\u4e49:
public static MethodInfo GenerateMethod(Action<ILGenerator> generateAction)\n{\n AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new(\"MyAssembly\"), AssemblyBuilderAccess.RunAndCollect);\n ModuleBuilder moduleBuilder = asmBuilder.DefineDynamicModule(\"MyTestModule\");\n TypeBuilder typeBuilder = moduleBuilder.DefineType(\"MyType\");\n MethodBuilder methodBuilder = typeBuilder.DefineMethod(\"MyMethod\", MethodAttributes.Public | MethodAttributes.Static\n , typeof(void), new Type[] { typeof(int) });\n generateAction(methodBuilder.GetILGenerator());\n return typeBuilder.CreateType().GetMethod(\"MyMethod\")!;\n}\n\npublic static void Main()\n{\n MethodInfo methodInfo = GenerateMethod(il =>\n {\n // TODO implement the IL body\n });\n var action = methodInfo.CreateDelegate<Action<int>>();\n action(1);\n}\n
\u5176\u5bf9\u5e94 IL
\u4e3a:
var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar valueIs0Target = il.DefineLabel();\nil.Emit(OpCodes.Ldarg_0);\nil.Emit(OpCodes.Brfalse, valueIs0Target);\nil.Emit(OpCodes.Ldstr, \"value is not 0.\");\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\nil.MarkLabel(valueIs0Target);\nil.Emit(OpCodes.Ldstr, \"value is 0!\");\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
\u5728\u8fd9\u91cc, \u5728\u4f7f\u7528 System.Reflection.Emit
\u5e93\u7684\u60c5\u51b5\u4e0b, \u6211\u4eec\u5728\u4ee3\u7801\u7684\u7b2c 2 \u884c\u5b9a\u4e49\u4e86\u4e00\u4e2a Label, \u7528\u6765\u4e4b\u540e\u4f5c\u4e3a\u6761\u4ef6\u8df3\u8f6c\u6307\u4ee4\u7684\u53c2\u6570\u4f20\u5165, \u4e0d\u8fc7\u76ee\u524d\u8fd9\u4e2a Label \u6ca1\u6709\u6307\u5411\u4efb\u4f55 IL
\u6307\u4ee4\u4f4d\u7f6e, \u6240\u4ee5\u6211\u4eec\u5728\u7b2c 8 \u884c\u8c03\u7528 MarkLabel
\u65b9\u6cd5, \u8c03\u7528\u5b8c\u8be5\u65b9\u6cd5\u540e\u7684\u4e0b\u4e00\u6b21 Emit
\u7684 IL
\u6307\u4ee4\u7684\u4f4d\u7f6e\u4fe1\u606f\u5c31\u4f1a\u88ab\u8bbe\u7f6e\u5230 Label \u4e2d, \u89c2\u5bdf\u4e0a\u8ff0\u4ee3\u7801\u4e0d\u96be\u53d1\u73b0, \u6211\u4eec\u8bfb\u53d6\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570, \u5982\u679c\u4e3a 0 \u90a3\u4e48\u8df3\u8f6c\u5230\u8f93\u51fa value is 0!
\u7684 IL
\u6307\u4ee4\u6bb5\u524d, \u800c\u5f53\u975e 0 \u65f6\u4e0d\u505a\u4efb\u4f55\u4e8b\u8ba9\u5176\u81ea\u7136\u6267\u884c\u5230\u8f93\u51fa value is not 0.
\u7684 IL
\u6307\u4ee4\u6bb5\u524d, \u4f60\u53ef\u4ee5\u66f4\u6539\u8c03\u7528\u8fd9\u4e2a\u65b9\u6cd5\u7684\u4ee3\u7801\u7684\u5730\u65b9\u4f20\u5165\u7684\u53c2\u6570\u6765\u89c2\u5bdf\u5b83\u7684\u8f93\u51fa(\u6bd4\u5982\u5c06 action(1)
\u6539\u4e3a action(0)
). \u987a\u4fbf, \u5728\u8fd9\u4e2a\u6307\u4ee4\u6bb5\u540e\u9762\u7d27\u8ddf\u4e00\u4e2a ret
\u6307\u4ee4\u76f4\u63a5\u8fd4\u56de\u8be5\u65b9\u6cd5\u9632\u6b62\u8bef\u6267\u884c\u5230\u540e\u9762\u7684 IL
\u6bb5. \u4e0d\u8fc7\u8fd9\u53ea\u5728\u540e\u9762\u6ca1\u6709\u4ee3\u7801\u9700\u8981\u6267\u884c\u7684\u60c5\u51b5\u4e0b\u594f\u6548, \u5982\u679c\u540e\u9762\u4f9d\u7136\u6709\u4ee3\u7801\u7684\u8bdd\u6211\u4eec\u5c31\u5f97\u4f7f\u7528 br
\u6307\u4ee4\u4e86.
br
\u6307\u4ee4\u6267\u884c\u540e\u4f1a\u5c06\u76ee\u524d\u7684\u6267\u884c\u4f4d\u7f6e\u65e0\u6761\u4ef6\u7684\u8df3\u8f6c\u5230\u5bf9\u5e94\u4f4d\u7f6e, \u6bd4\u5982\u521a\u624d\u4ecb\u7ecd brfalse
\u6307\u4ee4\u672b\u5c3e\u7684\u4e00\u70b9\u5c0f\u95ee\u9898, \u5373\u6bd4\u5982\u5982\u4e0b C# \u4ee3\u7801:
if (value == 0)\n{\n Console.WriteLine(\"value is 0!\");\n}\nelse\n{\n Console.WriteLine(\"value is not 0.\");\n}\nConsole.WriteLine(\"always execute me!\");\n
\u5728\u672b\u5c3e\u6211\u4eec\u6709\u4e00\u4e2a\u65b9\u6cd5\u8c03\u7528\u662f\u65e0\u5173 value
\u7684\u503c\u7684, \u4e4b\u524d\u7684\u4ee3\u7801\u6211\u4eec\u4e3a\u4e86\u9632\u6b62\u8bef\u6267\u884c IL
\u6211\u4eec\u4f7f\u7528\u4e86 ret
\u6307\u4ee4\u76f4\u63a5\u8fd4\u56de\u6574\u4e2a\u65b9\u6cd5, \u4f46\u662f\u73b0\u5728\u8fd9\u91cc\u6211\u4eec\u65e0\u6cd5\u8fd9\u4e48\u5e72, \u4e0d\u8fc7\u73b0\u5728\u6709 br
\u6307\u4ee4\u53ef\u4ee5\u4f7f\u7528\u4e86:
var cw = typeof(Console).GetMethod(\"WriteLine\", new Type[] { typeof(string) })!;\nvar valueIs0Target = il.DefineLabel();\nvar afterIfTarget = il.DefineLabel();\nil.Emit(OpCodes.Ldarg_0);\nil.Emit(OpCodes.Brfalse, valueIs0Target);\nil.Emit(OpCodes.Ldstr, \"value is not 0.\");\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Br, afterIfTarget);\nil.MarkLabel(valueIs0Target);\nil.Emit(OpCodes.Ldstr, \"value is 0!\");\nil.Emit(OpCodes.Call, cw);\nil.MarkLabel(afterIfTarget);\nil.Emit(OpCodes.Ldstr, \"always execute me!\");\nil.Emit(OpCodes.Call, cw);\nil.Emit(OpCodes.Ret);\n
"},{"location":"trans/il/#s","title":".s
\u7cfb\u6307\u4ee4","text":"\u4f60\u53ef\u80fd\u53d1\u73b0\u4e86\u5c31\u662f\u4e00\u4e9b IL
\u6307\u4ee4\u540c\u65f6\u8fd8\u6709\u4e00\u4e2a\u5e26 .s
\u540e\u7f00\u7684\u7248\u672c, \u8fd9\u4e2a\u6211\u4eec\u4e00\u822c\u53eb\u5b83\u7684 \"\u77ed\u683c\u5f0f\" \u7248\u672c, \u53cd\u4e4b\u53eb \"\u957f\u683c\u5f0f\" \u7248\u672c, \u6bd4\u5982\u5c31\u521a\u624d\u7684 br
\u5bf9\u5e94\u7684 br.s
, \u901a\u5e38\u7c7b\u4f3c\u8fd9\u4e00\u5bf9 IL
\u6307\u4ee4\u7684\u533a\u522b\u5c31\u662f .s
\u7248\u672c\u7684\u53c2\u6570\u4f1a\u77ed\u4e00\u70b9, \u6bd4\u5982\u957f\u683c\u5f0f\u7248\u672c\u7684\u53c2\u6570\u957f\u5ea6\u662f 4 \u5b57\u8282, \u800c\u77ed\u683c\u5f0f\u7248\u672c\u7684\u53c2\u6570\u957f\u5ea6\u53ef\u80fd\u5c31\u662f 2 \u5b57\u8282, \u6ce8\u610f\u8fd9\u91cc\u4e0d\u662f\u8bf4\u7684\u662f\u538b\u5165\u8bc4\u4f30\u6808\u7684\u503c\u7684\u7c7b\u578b, \u957f\u77ed\u683c\u5f0f\u7248\u672c\u6240\u505a\u7684\u4e8b\u60c5\u662f\u5b8c\u5168\u4e00\u6837\u7684, \u53ea\u662f\u4f20\u53c2\u5141\u8bb8\u4f60\u7528\u77ed\u4e00\u70b9\u7684\u53c2\u6570. \u8fd9\u5176\u5b9e\u5c31\u662f\u4e00\u4e2a\u5bf9 IL
\u6307\u4ee4\u7684\u5927\u5c0f\u4f18\u5316, \u7f16\u8bd1\u5668\u901a\u5e38\u5c31\u4f1a\u80fd\u7528 .s
\u7248\u672c\u5c31\u7528 .s
\u7248\u672c, \u5f53\u53c2\u6570\u9700\u6c42\u8d85\u8fc7\u77ed\u683c\u5f0f\u53c2\u6570\u8868\u8fbe\u8303\u56f4\u65f6\u624d\u4f1a\u4f7f\u7528\u957f\u683c\u5f0f, \u5bf9\u4e8e\u6211\u4eec\u7684\u8bdd\u5982\u679c\u4f60\u60f3\u5fae\u5fae\u7684\u4f18\u5316\u4e00\u4e0b\u4f60\u7684 IL
\u7684\u5927\u5c0f\u7684\u8bdd, \u4f60\u53ef\u4ee5\u9009\u62e9\u5728\u53c2\u6570\u8303\u56f4\u591f\u7528\u7684\u60c5\u51b5\u4e0b\u4f7f\u7528 .s
\u7248\u672c.
"},{"location":"trans/il/#_12","title":"\u7ed3\u5c3e","text":"\u81f3\u6b64, \u4e00\u4e9b\u57fa\u672c\u7684 IL
\u4f60\u5df2\u4e86\u89e3, \u6211\u4eec\u5728\u8fd9\u91cc\u4ecb\u7ecd\u7684 IL
\u6307\u4ee4\u4e0d\u8fc7\u662f\u51b0\u5c71\u4e00\u89d2, \u8fd8\u6709\u5f88\u591a\u5176\u4ed6\u7684 IL
\u6307\u4ee4\u6ca1\u6709\u4ecb\u7ecd, \u4e0d\u8fc7\u5b83\u4eec\u5927\u540c\u5c0f\u5f02, \u57fa\u672c\u90fd\u662f\u5bf9\u8bc4\u4f30\u6808\u7684\u5404\u79cd\u5404\u6837\u7684\u64cd\u4f5c, \u6211\u4eec\u53ea\u9700\u8981\u5728\u7528\u5230\u65f6\u6216\u8005\u5076\u5c14\u7ffb\u9605\u4e00\u4e0b IL
\u6307\u4ee4\u8868\u5c31\u80fd\u4e86\u89e3. \u6b64\u5916, \u8fd8\u6709\u5f88\u591a\u6bd4\u5982\u65b9\u6cd5\u7684\u7b7e\u540d, fixed
, try-catch
\u7b49\u5185\u5bb9\u6211\u4eec\u8fd8\u6ca1\u6709\u6d89\u53ca\u5230, \u4e0d\u8fc7\u5230\u76ee\u524d\u4e3a\u6b62\u5bf9\u4e8e\u851a\u84dd modding \u5df2\u7ecf\u52c9\u5f3a\u591f\u7528\u4e86. \u518d\u6b64\u5916, \u5728 dnSpy \u7684 IL
\u4ee3\u7801\u7684\u89c6\u89d2\u65f6, \u70b9\u51fb IL
\u64cd\u4f5c\u7b26\u7684\u540d\u79f0\u53ef\u4ee5\u5f88\u65b9\u4fbf\u5730\u8df3\u8f6c\u5230 msdn \u4e0a\u5bf9\u8fd9\u4e2a\u6307\u4ee4\u7684\u63cf\u8ff0. \u90a3\u4e48, \u5728\u4e86\u89e3\u4f7f\u7528 System.Reflection.Emit
\u5e93\u540e, \u6211\u4eec\u5c31\u53ef\u4ee5\u4f7f\u7528 Mono.Cecil
\u5728\u851a\u84dd\u4e2d\u66f4\u6539\u851a\u84dd\u7684\u7a0b\u5e8f\u96c6\u4e86.
\u4e00\u4e9b\u53ef\u80fd\u6709\u7528\u7684\u8d44\u6e90:
OpCodes Fields - Microsoft Learn (https://learn.microsoft.com/...) \u7406\u89e3IL - Rorschach - \u77e5\u4e4e (https://zhuanlan.zhihu.com/...) IL\u6307\u4ee4\u8be6\u7ec6 - Zery - \u535a\u5ba2\u56ed (https://www.cnblogs.com/...) "},{"location":"trans/session_settings_savedata/","title":"Session, Settings, SaveData","text":"\u8fd9\u90e8\u5206\u5185\u5bb9\u5728 Everest Wiki \u91cc\u662f\u5728\u914d\u7f6e\u73af\u5883\u7684\u540c\u65f6\u8bf4\u7684, \u6211\u4e2a\u4eba\u8ba4\u4e3a\u5e94\u8be5\u63a8\u540e\u4e00\u70b9\u4f46\u662f\u4f3c\u4e4e\u73b0\u5728\u63a8\u540e\u7684\u6709\u70b9\u8fc7\u5934.
\u4f60\u5e94\u8be5\u8fd8\u8bb0\u5f97\u6211\u4eec\u6700\u5f00\u59cb\u7684\u90a3\u4e2a\u7ee7\u627f\u4e8e EverestModule
\u7684\u7c7b MyCelesteModModule
, \u5230\u76ee\u524d\u4e3a\u6b62\u6211\u4eec\u53ea\u4f7f\u7528\u4e86\u5b83\u7684 Load
\u65b9\u6cd5\u548c Unload
\u65b9\u6cd5\u7528\u4e8e\u52a0\u8f7d\u521d\u59cb\u5316\u6211\u4eec\u7684\u94a9\u5b50. \u5f53\u7136, \u8fd9\u80af\u5b9a\u662f\u4e0d\u6b62\u7684, \u90a3\u4e48\u8fd9\u4e00\u8282\u5c06\u4f1a\u805a\u7126\u4e8e EverestModule
\u7684\u66f4\u591a\u7684\u5185\u5bb9.
"},{"location":"trans/session_settings_savedata/#settings","title":"Settings","text":""},{"location":"trans/session_settings_savedata/#_1","title":"\u57fa\u672c","text":"Settings, \u987e\u540d\u601d\u4e49\u5c31\u662f\u9009\u9879\u7684\u610f\u601d. Everest \u4e3a\u6211\u4eec\u5c01\u88c5\u4e86\u4e00\u4e2a\u975e\u5e38\u4fbf\u5229\u7684\u7cfb\u7edf, \u6211\u4eec\u8981\u505a\u7684\u53ea\u662f\u7b80\u5355\u5730\u52a0\u5165\u5c5e\u6027, \u7136\u540e\u88c5\u9970\u51e0\u4e2a\u7b80\u5355\u7684\u7279\u6027, \u5c31\u80fd\u521b\u5efa\u51fa\u6613\u7528\u7684\u83dc\u5355\u9009\u9879, \u5269\u4e0b\u7684 ui \u65b9\u9762\u548c\u4fdd\u5b58\u8bfb\u53d6\u7684\u5de5\u4f5c\u90fd\u7531 Everest \u8d1f\u8d23.
\u5728\u6b64\u4e4b\u524d, \u6211\u4eec\u5148\u4fdd\u5b58\u4e00\u4e0b\u6211\u4eec\u7684 EverestModule
\u5b9e\u4f8b\u4ee5\u65b9\u4fbf\u6211\u4eec\u8bbf\u95ee\u5b83\u7684\u5b9e\u4f8b(Everest \u4f1a\u786e\u4fdd\u5b83\u662f\u5355\u4f8b\u7684):
public class MyCelesteModModule : EverestModule\n{\n public static MyCelesteModModule Instance { get; private set; }\n\n public override void Load()\n {\n Instance = this;\n }\n\n public override void Unload()\n {\n }\n}\n
\u7136\u540e\u65b0\u5efa\u4e00\u4e2a\u540d\u5b57\u6700\u597d\u4ee5 mod \u5f00\u5934, Settings
\u7ed3\u5c3e\u7684 MyCelesteModSettings
\u7c7b\u5e76\u7ee7\u627f EverestModuleSettings
:
public class MyCelesteModSettings : EverestModuleSettings\n{\n\n}\n
\u7136\u540e\u5728 module \u7c7b\u91cc\u8fd9\u6837\u6ce8\u518c\u8fd9\u4e2a\u7c7b:
public class MyCelesteModModule : EverestModule\n{\n public static MyCelesteModModule Instance { get; private set; }\n\n public override Type SettingsType => typeof(MyCelesteModSettings);\n public static MyCelesteModSettings Settings => (MyCelesteModSettings)Instance._Settings;\n\n public override void Load()\n {\n Instance = this;\n }\n\n public override void Unload()\n {\n }\n}\n
\u73b0\u5728, \u6211\u4eec\u5411\u9009\u9879\u4e2d\u65b0\u52a0\u4e00\u6761\u516c\u5f00\u7684 bool \u7c7b\u578b\u7684\u5c5e\u6027:
public class MyCelesteModSettings : EverestModuleSettings\n{\n public bool AnInterestingSwitch { get; set; }\n}\n
\u73b0\u5728\u76f4\u63a5\u7f16\u8bd1\u4f60\u7684\u9879\u76ee, \u7136\u540e\u4f60\u5e94\u8be5\u4f1a\u770b\u5230 Everest \u4e3a\u4f60\u5728 mod \u9009\u9879\u4e2d\u751f\u6210\u4e86\u8fd9\u6837\u4e00\u6761\u6709\u8da3\u7684\u8bbe\u7f6e:
\u968f\u540e\u4f60\u5c31\u80fd\u5728\u4f60 mod \u7684\u4efb\u4f55\u5730\u65b9\u7528 MyCelesteModSettings.Settings.AnInterestingSwitch
\u6765\u8bbf\u95ee\u8fd9\u4e2a\u5f00\u5173\u4e86.
\u9664\u6b64\u4e4b\u5916 Everest \u8fd8\u652f\u6301\u679a\u4e3e, \u5b57\u7b26\u4e32\u548c\u6570\u5b57, \u5b83\u4eec\u5206\u522b\u4f1a\u751f\u6210\u8fd9\u6837\u7684\u9009\u9879:
public class MyCelesteModSettings : EverestModuleSettings\n{\n public bool AnInterestingSwitch { get; set; }\n\n [SettingRange(0, 100)]\n public int AnInteger { get; set; }\n\n public string AString { get; set; }\n\n public DayOfWeek DayOfWeek { get; set; }\n}\n
Info
AString
\u90a3\u6761\u9009\u9879\u662f\u4e00\u4e2a\u6309\u94ae, \u6309\u4e0b\u540e\u4f1a\u8fdb\u5165\u6587\u5b57\u8f93\u5165\u754c\u9762, \u5192\u53f7\u540e\u9762\u4f1a\u8ddf\u73a9\u5bb6\u8f93\u5165\u4e86\u7684\u6587\u5b57. DayOfWeek
\u9009\u9879\u5141\u8bb8\u4f60\u5de6\u53f3\u9009\u62e9 DayOfWeek
\u679a\u4e3e\u4e2d\u7684\u6bcf\u4e00\u9879.
\u5176\u4e2d int \u90a3\u6761\u5c5e\u6027\u9700\u8981\u88c5\u9970 SettingRange
\u7279\u6027\u5e76\u6307\u5b9a\u6700\u5927\u6700\u5c0f\u503c, \u5426\u5219 Everest \u4f1a\u62d2\u7edd\u751f\u6210\u5b83, \u6b64\u5916\u5b83\u8fd8\u6709\u4e2a\u53c2\u6570\u53ef\u4ee5\u7528\u6765\u6307\u5b9a\u8be5\u9009\u9879\u662f\u5426\u9700\u8981 \"\u5927\u7684\u8303\u56f4\" (LargeRange
), \u5982\u679c\u6307\u5b9a\u4e3a true, \u5219\u957f\u6309\u8c03\u6574\u8be5\u503c\u65f6\u7684\u589e\u957f\u901f\u5ea6\u4f1a\u6162\u6162\u589e\u52a0\u4ee5\u4fbf\u5feb\u901f\u8c03\u6574\u81f3\u66f4\u5927/\u5c0f\u7684\u503c.
\u9664\u4e86 SettingRange
\u7279\u6027, \u8fd8\u6709\u66f4\u591a\u5176\u4ed6\u7684\u7279\u6027\u7528\u4e8e\u6307\u793a\u8be5\u9009\u9879\u7684\u4e00\u4e9b\u6027\u8d28:
SettingNeedsRelauch
: \u6307\u793a\u8be5\u9009\u9879\u9700\u8981\u91cd\u542f\u6e38\u620f\u751f\u6548. SettingNumberInput
: \u5982\u679c\u8be5\u9009\u9879\u5bf9\u5e94\u7684\u5c5e\u6027\u662f\u4e2a\u6570\u5b57(int, float), \u90a3\u4e48\u4f7f\u7528\u8f93\u5165\u6587\u5b57\u7684\u83dc\u5355\u6765\u8f93\u5165\u6570\u5b57\u800c\u4e0d\u662f\u5de6\u53f3\u5207\u6362\u6570\u5b57. allowNegatives
: \u662f\u5426\u5141\u8bb8\u8d1f\u6570 maxLength
: \u5b57\u7b26\u4e32\u6700\u5927\u957f\u5ea6 SettingMaxLength
: \u8bbe\u7f6e\u8be5\u5b57\u7b26\u4e32\u9009\u9879\u7684\u6700\u5927\u957f\u5ea6. \u5426\u5219\u9ed8\u8ba4 12 \u4e2a\u5b57\u7b26. max
: \u6700\u5927\u957f\u5ea6 SettingInGame
: \u6307\u793a\u8be5\u9009\u9879\u662f\u5426\u51fa\u73b0\u5728\u6e38\u620f\u5185(\u56fe\u5185)\u83dc\u5355\u4e2d. SettingIgnore
: \u6307\u793a\u662f\u5426\u5ffd\u7565\u8be5\u9009\u9879\u88ab\u52a0\u5165\u83dc\u5355, \u6ce8\u610f\u5ffd\u7565\u540e\u4f9d\u7136\u4f1a\u88ab Everest \u6b63\u5e38\u8bfb\u53d6\u4fdd\u5b58. YamlIgnore
: \u6307\u793a\u662f\u5426\u5ffd\u7565\u8be5\u5c5e\u6027\u7684\u4fdd\u5b58. Note
YamlIgnore
\u4f4d\u4e8e\u547d\u540d\u7a7a\u95f4 YamlDotNet.Serialization
\u5185.
"},{"location":"trans/session_settings_savedata/#_2","title":"\u672c\u5730\u5316","text":"\u4f60\u53ef\u80fd\u4f1a\u53d1\u73b0\u9ed8\u8ba4\u751f\u6210\u7684\u9009\u9879\u540d\u5b57\u5c31\u662f\u5c5e\u6027\u540d, \u5c3d\u7ba1\u6211\u4eec\u901a\u5e38\u80fd\u731c\u5230\u5b83\u7684\u610f\u601d\u4ee5\u53ca\u5b83\u4f1a\u5e72\u4ec0\u4e48, \u4f46\u662f\u73a9\u5bb6\u4eec\u901a\u5e38\u4e0d\u4f1a, \u6240\u4ee5\u6211\u4eec\u8fd8\u5f97\u4e3a\u5176\u914d\u7f6e\u672c\u5730\u5316, \u5176\u5c31\u5305\u542b\u4e86\u6211\u4eec\u901a\u5e38\u8bb2\u7684 \"\u6c49\u5316\", \"\u4e2d\u6587\u7ffb\u8bd1\".
\u5728\u8fd9\u91cc, \u6211\u4eec\u9700\u8981\u7684\u672c\u5730\u5316\u952e\u540d\u662f modoptions_{\u7c7b\u540d}_{\u5c5e\u6027\u540d}
, \u4f8b\u5982\u5982\u4e0b\u7c7b:
public class MyCelesteModSettings : EverestModuleSettings\n{\n public bool EnableFunnyThing { get; set; }\n}\n
\u5176\u4e2d\u90a3\u6761\u5c5e\u6027\u5bf9\u5e94\u7684\u672c\u5730\u5316\u952e\u540d\u5219\u662f: modoptions_mycelestemod_enablefunnything
, \u6240\u4ee5\u6211\u4eec\u5c06\u5176\u5199\u5728 Dialog \u6587\u4ef6\u91cc:
ModFolder/Dialog/Simplified Chinese.txtmodoptions_mycelestemod_enablefunnything=\u5f00\u542f\u6709\u8da3\u7684\u4e1c\u897f\n
ModFolder/Dialog/english.txtmodoptions_mycelestemod_enablefunnything=Enable funny thing\n
Note
\u5982\u679c\u4f60\u4e0d\u77e5\u9053 dialog \u6587\u4ef6\u662f\u4ec0\u4e48\u7684\u8bdd, \u4f60\u53ef\u4ee5\u8be2\u95ee mapper \u4eec, \u6216\u8005\u5728\u8fd9\u91cc\u4f60\u5c31\u5e72\u8106\u7167\u505a, \u4e5f\u5c31\u662f\u65b0\u5efa\u5982\u5176\u6807\u9898\u6240\u5c55\u793a\u7684\u6587\u4ef6\u7136\u540e\u7c98\u8d34\u5bf9\u5e94\u5185\u5bb9.
\u6b64\u5916, mod \u9009\u9879\u7684\u5927\u6807\u9898\u4e5f\u6709\u4e2a\u672c\u5730\u5316\u952e\u540d, \u76f8\u5bf9\u4e8e\u4e0a\u9762\u7684\u952e\u540d\u53ea\u662f\u5c06\u5c5e\u6027\u540d\u6362\u6210\u4e86 title
, \u4f8b\u5982\u4ee5\u4e0b dialog \u6587\u4ef6:
ModFolder/Dialog/Simplified Chinese.txtmodoptions_mycelestemod_enablefunnything=\u5f00\u542f\u6709\u8da3\u7684\u4e1c\u897f\nmodoptions_mycelestemod_title=\u6211\u7684\u6709\u8da3 mod \u7684\u8bbe\u7f6e (MyCelesteMod)\n
ModFolder/Dialog/english.txtmodoptions_mycelestemod_enablefunnything=Enable funny thing\nmodoptions_mycelestemod_title=funny MyCelesteMod\n
Note
\u65f6\u523b\u8bb0\u5f97\u586b\u5145 english.txt
, \u56e0\u4e3a\u5982\u679c\u5176\u4ed6\u8bed\u8a00\u6ca1\u627e\u5230\u8fd9\u4e2a\u952e\u540d\u4f1a\u9ed8\u8ba4\u56de\u9000\u5230 english
, \u5982\u679c\u518d\u6ca1\u6709\u7684\u8bdd\u5c31\u4f1a\u76f4\u63a5\u5c55\u793a\u4e11\u964b\u7684\u952e\u540d.
\u672c\u5730\u5316\u952e\u540d\u5e76\u4e0d\u662f\u56fa\u5b9a\u7684, \u4f60\u53ef\u4ee5\u4f7f\u7528 SettingName
\u88c5\u9970\u5230\u7c7b\u4e0a\u6216\u8005\u5c5e\u6027\u4e0a\u6765\u4fee\u6539\u5b83, \u4e0d\u8fc7\u6211\u4e2a\u4eba\u4e0d\u662f\u5f88\u5efa\u8bae\u4fee\u6539\u5b83, \u56e0\u4e3a\u9ed8\u8ba4\u7684\u503c\u4f5c\u4e3a\u952e\u540d\u5b8c\u5168\u591f\u7528, \u6b64\u5916\u8fd8\u6709\u4e00\u4e2a SettingSubText
\u7279\u6027, \u5b83\u53ef\u4ee5\u5411\u8be5\u9009\u9879\u88ab\u9009\u4e2d\u65f6\u5728\u5e95\u4e0b\u663e\u793a\u4e00\u884c\u5c0f\u5b57, \u5b83\u7684\u53c2\u6570\u540c\u6837\u662f\u4e2a\u672c\u5730\u5316\u952e\u540d, \u7c7b\u4f3c\u7684\u8fd8\u6709 SettingSubHeader
\u7279\u6027, \u5b83\u4f1a\u5411\u8be5\u9009\u9879\u4e4b\u524d\u52a0\u5165\u4e00\u4e2a\u5c0f\u6807\u9898.
\u5bf9\u4e8e\u679a\u4e3e\u6bcf\u4e00\u9879\u7684\u503c\u53ef\u4ee5\u4f7f\u7528 modoptions_{\u7c7b\u540d}_{\u5c5e\u6027\u540d}_{\u679a\u4e3e\u9879\u540d}
\u6765\u6307\u5b9a, \u4f8b\u5982\u5bf9\u4e8e DayOfWeek
\u679a\u4e3e\u7c7b\u578b\u7684 Day
\u5c5e\u6027:
ModFolder/Dialog/Simplified Chinese.txtmodoptions_mycelestemod_day_sunday=\u661f\u671f\u65e5\nmodoptions_mycelestemod_day_monday=\u661f\u671f\u4e00\nmodoptions_mycelestemod_day_tuesday=\u661f\u671f\u4e8c\nmodoptions_mycelestemod_day_wednesday=\u661f\u671f\u4e09\nmodoptions_mycelestemod_day_thursday=\u661f\u671f\u56db\nmodoptions_mycelestemod_day_friday=\u661f\u671f\u4e94\nmodoptions_mycelestemod_day_saturday=\u661f\u671f\u516d\n
Info
\u5982\u679c\u4f60\u5b9e\u9645\u6d4b\u8bd5\u7684\u8bdd\u4f60\u4f1a\u53d1\u73b0 \u4e09
\u5b57\u548c \u4e94
\u5b57\u6ca1\u6709\u6e32\u67d3\u51fa\u6765, \u8fd9\u662f\u6b63\u5e38\u7684, \u56e0\u4e3a\u851a\u84dd\u7684\u5b57\u5e93\u4e2d\u6ca1\u6709\u8fd9\u4e24\u4e2a\u5b57, \u8fd9\u91cc\u6211\u5c31\u4e0d\u8d58\u8ff0\u5982\u4f55\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u4e86, \u5177\u4f53\u53ef\u4ee5\u54a8\u8be2 mapper \u4eec. (\u65e5\u5e38\u5077\u61d2.jpg)
"},{"location":"trans/session_settings_savedata/#_3","title":"\u6700\u540e","text":"\u6216\u8bb8\u4f60\u4e5f\u5df2\u7ecf\u731c\u5230\u4e86, Everest \u6b63\u662f\u4f7f\u7528\u7684 Yaml \u6765\u5e8f\u5217\u5316/\u53cd\u5e8f\u5217\u5316\u4f60\u7684 Settings
\u7c7b, \u6240\u4ee5\u8bf7\u52a1\u5fc5\u4e0d\u8981\u5728\u4f60\u7684 Settings
\u7c7b\u4e2d\u653e\u7f6e\u5947\u602a\u7684\u7c7b\u548c\u7ed3\u6784\u4f53! \u5982\u679c\u4f60\u8981\u8fd9\u4e48\u505a\u8bf7\u786e\u4fdd Everest \u80fd\u6b63\u786e\u5730\u5e8f\u5217\u5316/\u53cd\u5e8f\u5217\u5316\u4f60\u7684 Settings
\u7c7b, \u5426\u5219\u4f60\u7684\u8bbe\u7f6e\u5c06\u4e0d\u4f1a\u88ab\u6b63\u5e38\u4fdd\u5b58, \u6c38\u8fdc\u90fd\u662f\u9ed8\u8ba4\u503c.
"},{"location":"trans/session_settings_savedata/#session","title":"Session","text":""},{"location":"trans/session_settings_savedata/#_4","title":"\u57fa\u672c","text":"Session \u662f\u4e00\u4e2a\u851a\u84dd\u4e2d\u4fdd\u5b58\u6570\u636e\u7684\u6982\u5ff5, \u5b83\u7528\u4e8e\u4fdd\u5b58 \"\u4fdd\u5b58\u5e76\u9000\u51fa\" \u6309\u94ae\u6309\u4e0b\u540e\u6240\u4fdd\u5b58\u7684\u6570\u636e, \u4f8b\u5982\u5f53\u524d\u5df2\u6fc0\u6d3b\u7684 Flag, \u91cd\u751f\u70b9, \u5df2\u62fe\u53d6\u7684\u94a5\u5319, \u8349\u8393, \u6838\u5fc3\u7684\u6a21\u5f0f\u7b49. \u5728\u81ea\u5b9a\u4e49\u4f60\u81ea\u5df1\u7684 Session
\u540e, \u4f60\u53ef\u4ee5\u5728\u8fd9\u91cc\u4fdd\u5b58\u4f60\u81ea\u5df1\u72ec\u6709\u7684\u6536\u96c6\u7269\u4fe1\u606f, \u6216\u8005\u662f\u4e00\u4e9b\u5b9e\u4f53\u9700\u8981\u4e34\u65f6\u4fdd\u5b58\u4e8e\u5173\u5361\u7684\u6570\u636e. \u4e0e Settings \u76f8\u540c, \u6211\u4eec\u9700\u8981\u5148\u521b\u5efa\u4e00\u4e2a\u7ee7\u627f\u4e8e EverestModuleSession
\u7684\u7c7b, \u7136\u540e\u5728\u6a21\u5757\u7c7b\u4e2d\u58f0\u660e\u5b83:
MyCelesteModSession.csnamespace Celeste.Mod.MyCelesteMod;\n\npublic class MyCelesteModSession : EverestModuleSession\n{\n}\n
MyCelesteModModule.csnamespace Celeste.Mod.MyCelesteMod;\n\npublic class MyCelesteModModule : EverestModule\n{\n public static MyCelesteModModule Instance { get; private set; }\n\n public override Type SettingsType => typeof(MyCelesteModSettings);\n public static MyCelesteModSettings Settings => (MyCelesteModSettings)Instance._Settings;\n\n public override Type SessionType => typeof(MyCelesteModSession);\n public static MyCelesteModSession Session => (MyCelesteModSession)Instance._Session;\n\n public override void Load()\n {\n Instance = this;\n }\n\n public override void Unload()\n {\n }\n}\n
\u7136\u540e\u6211\u4eec\u5c31\u53ef\u4ee5\u5728\u4efb\u4f55\u6e38\u620f\u5904\u4e8e\u5173\u5361\u5185\u7684\u65f6\u5019\u4f7f\u7528 MyCelesteModModule.Session
\u6765\u8bbf\u95ee\u6211\u4eec\u7684 Session \u4e86. \u5982\u679c\u4f60\u5c1d\u8bd5\u5728\u6e38\u620f\u4e0d\u5728\u5173\u5361\u5185\u65f6\u8bfb\u53d6\u5b83, \u90a3\u4e48\u4f60\u4f1a\u5f97\u5230\u4e00\u4e2a null
\u503c.
\u5047\u8bbe\u6211\u4eec\u78b0\u4e86 SetPassByRefillDashesTrigger
\u4e4b\u540e\u53c8\u78b0\u5230 ChangeRespawnTrigger
\u6539\u53d8\u4e86\u91cd\u751f\u70b9, \u7528 Save And Quit
\u9000\u51fa\u4e86\u6e38\u620f, \u518d\u6b21\u8fdb\u5165\u65f6\u4f60\u4f1a\u53d1\u73b0\u91cd\u751f\u70b9\u662f\u65b0\u7684, \u800c PassByRefill
\u7684\u51b2\u523a\u6570\u53c8\u53d8\u56de 1
\u4e86, \u6240\u4ee5\u63a5\u4e0b\u6765\u6211\u4eec\u5c1d\u8bd5\u901a\u8fc7 Session
\u6765\u4fee\u6b63\u8fd9\u4e2a\u9519\u8bef.
MyCelesteModSession.csnamespace Celeste.Mod.MyCelesteMod;\n\npublic class MyCelesteModSession : EverestModuleSession\n{\n public Dictionary<string, int> RoomIdToPassByRefillDashes = new(); // \u6211\u4eec\u5c06\u8bb0\u5f55\u6bcf\u4e2a\u623f\u95f4\u540d\u5bf9\u5e94\u7684PassByRefill\u7684\u51b2\u523a\u6570\n}\n
SetPassByRefillDashesTrigger.csusing Celeste.Mod.Entities;\n\nnamespace MyCelesteMod;\n\n[CustomEntity(\"MyCelesteMod/SetPassByRefillDashesTrigger\")]\npublic class SetPassByRefillDashesTrigger : Trigger\n{\n public int Dashes;\n\n public SetPassByRefillDashesTrigger(EntityData data, Vector2 offset)\n : base(data, offset)\n {\n Dashes = data.Int(\"dashes\");\n }\n\n public override void OnEnter(Player player)\n {\n base.OnEnter(player);\n MyCelesteModModule.Session.RoomIdToPassByRefillDashes[SceneAs<Level>().Session.LevelData.Name] = Dashes;\n }\n}\n
PassByRefill.csusing Celeste.Mod.Entities;\n\nnamespace MyCelesteMod;\n\n[CustomEntity(\"MyCelesteMod/PassByRefill\")]\npublic class PassByRefill : Entity\n{\n private int _dashes = 1;\n\n public int Dashes => MyCelesteModModule.Session.RoomIdToPassByRefillDashes.GetValueOrDefault(SceneAs<Level>().Session.LevelData.Name, _dashes);\n\n private Image image;\n\n public PassByRefill(Vector2 position, int dashes)\n {\n Depth = 1;\n Dashes = dashes;\n Position = position;\n Hitbox hitbox = new(64, 64);\n Collider = hitbox;\n\n MTexture tex = GFX.Game[\"MyCelesteMod/pass_by_refill\"];\n image = new(tex);\n Add(image);\n }\n\n public PassByRefill(EntityData data, Vector2 offset)\n : this(data.Position + offset, data.Int(\"dashes\"))\n {\n }\n\n public override void Update()\n {\n base.Update();\n var player = Scene.Tracker.GetEntity<Player>();\n if (player is not null && CollideCheck(player))\n {\n player.Dashes = Dashes;\n }\n }\n}\n
"},{"location":"trans/session_settings_savedata/#savedata","title":"SaveData","text":"\u987e\u540d\u601d\u4e49, SaveData
\u7528\u6765\u4fdd\u5b58\u4e00\u4e9b\u6301\u4e45\u5316\u6570\u636e, \u4f8b\u5982\u5f53\u524d\u5b58\u6863\u603b\u65f6\u95f4, \u603b\u6b7b\u4ea1\u6570, \u603b\u8349\u8393\u6570\u7b49. \u4f7f\u7528\u5b83\u4e0e\u4f7f\u7528 Session
\u6781\u5176\u76f8\u4f3c:
MyCelesteModSaveData.csnamespace Celeste.Mod.MyCelesteMod;\n\npublic class MyCelesteModSaveData : EverestModuleSaveData\n{\n}\n
MyCelesteModModule.csnamespace Celeste.Mod.MyCelesteMod;\n\npublic class MyCelesteModModule : EverestModule\n{\n public static MyCelesteModModule Instance { get; private set; }\n\n public override Type SettingsType => typeof(MyCelesteModSettings);\n public static MyCelesteModSettings Settings => (MyCelesteModSettings)Instance._Settings;\n\n public override Type SessionType => typeof(MyCelesteModSession);\n public static MyCelesteModSession Session => (MyCelesteModSession)Instance._Session;\n\n public override Type SaveDataType => typeof(MyCelesteModSaveData);\n public static MyCelesteModSaveData SaveData => (MyCelesteModSaveData)Instance._SaveData;\n\n public override void Load()\n {\n Instance = this;\n }\n\n public override void Unload()\n {\n }\n}\n
"}]}
\ No newline at end of file
diff --git a/sitemap.xml.gz b/sitemap.xml.gz
index 137365f809f90df56aff737090343d2193d689b5..ae33214860728b8de9d494ef320b3371d30758c3 100755
GIT binary patch
delta 13
Ucmb=gXP58h;9#)bHj%vo02!16!vFvP
delta 13
Ucmb=gXP58h;Ami4JCVHt02@gI{{R30
diff --git a/trans/adv_hooks/index.html b/trans/adv_hooks/index.html
index a96f164..3b30589 100755
--- a/trans/adv_hooks/index.html
+++ b/trans/adv_hooks/index.html
@@ -527,6 +527,48 @@
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -634,6 +676,15 @@
+
+
+
+
+
+ 钩取其他 helper
+
+
+
@@ -687,6 +738,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
@@ -1138,6 +1210,15 @@
+
+
+
+
+
+ 钩取其他 helper
+
+
+
@@ -1327,20 +1408,7 @@ 移除 IL
任意钩取
相信你已经发现了, 有些方法比如叫做 orig_xxx
的方法, 以及属性的 getter 和 setter 你都无法在 On. 和 IL. 这两个命名空间中找到,
同时, 钩取别的 helper 的方法似乎也无法完成.
-这里我们引入两个新类: Hook
与 ILHook
, 前者表示一个 On 钩子, 后者表示一个 IL 钩子.
-
-
Info
-
Hook
与 ILHook
位于 MonoMod.RuntimeDetour
程序集中, 在旧模板里它没有被默认引用进来, 这是一个我个人的失误,
-如果你确实无法引用这两个类的话你可以在 CelesteMod.props
里的最底下的那个 ItemGroup
中加入这一条:
-
<Reference Include= "MonoMod.RuntimeDetour" >
- <HintPath> $(CelesteAssemblyPath)/MonoMod.RuntimeDetour.dll</HintPath>
- <Private> False</Private>
-</Reference>
-
-
+这里我们引入两个新类: Hook
与 ILHook
, 前者表示一个 On 钩子, 后者表示一个 IL 钩子.
Hook
的构造函数拥有非常多重载, 在这里我们只需要那个 (MethodBase method, Delegate to)
的重载,
它表示我们希望钩取第一个参数指定的方法, 钩子方法是第二个参数指定的委托.
例如, 我们希望钩取 Player.Inventory
这个属性的 get
方法, 使其总是返回 PlayerInventory.TheSummit
,
@@ -1394,10 +1462,9 @@
任意钩取
}
因为不再是之前方便的事件订阅, 所以钩子的 orig 参数的委托原型你必须得自己声明, 注意钩子方法和钩子 orig 参数的参数列表一定要小心准确的填写,
-否则会直接造成游戏崩溃. 上述代码的效果应该是你无论如何都会拥有 7a/b/c 的 Inventory, 也大概即双冲, 带背包.
+否则会直接造成游戏崩溃. 上述代码的效果应该是你无论如何都会拥有 7a/b/c 的 Inventory, 也即双冲, 带背包等.
现在, 拥有了钩子函数, 你可以做任何你之前使用订阅事件来创建钩子一样的事. 顺便, 使用这种方法也允许你钩取别的 helper 的方法,
-甚至是钩取别的 helper 的钩子方法. 不过在此之前你需要为你的 mod 声明依赖或者可选依赖, 声明可选依赖后又需要检测对应 mod 是否加载等等,
-这部分内容我们之后再说.
+甚至是钩取别的 helper 的钩子方法. 不过在此之前你需要为你的 mod 声明依赖或者可选依赖, 声明可选依赖后又需要检测对应 mod 是否加载等等.
同样地, IL 钩子的创建也与 On 钩子相同:
对于 Scene
-嗯... 对应 Scene 的一些生命周期函数我个人也不是很了解毕竟我们大部分的时间都在 gameplay 的场景上, 所以这节就暂时咕了(。_。)
+嗯... 对应 Scene 的一些生命周期函数我个人也不是很了解毕竟我们大部分的时间都在 gameplay 的场景上, 所以这节就暂时咕了(._.)
常见的方法与属性
Scene.Add
: 将一个实体加入到场景中
@@ -1298,12 +1361,12 @@ Tag
当你的实体拥有这个 Tag 后, 蔚蓝会将你的实体绘制在 ui 层, 比较常见的例子就是左上角的计时器, 它在构造器内就给自己打上了 Tags.HUD
的标签.
也如上面所说的, 一些蔚蓝常见的所有 Tag 你都可以在 Celeste.Tags
类内找到.
-以下是一些可能地常见的 Tag:
+以下是一些可能地常见的 Tag:(已迁移 )
PauseUpdate
: 是否在暂停期间依然被调用 Update
, 通常用于 ui 层的实体上
FrozenUpdate
: 是否在 Frozen
状态下依然被调用 Update
(比如草莓籽动画过程, 1a蓝心解密成功过程, 注意此状态与冻结帧无关)
TransitionUpdate
: 是否在关卡切板时依然被调用 Update
, 通常用于在切板时更新一些视觉上的东西(比如电网的 "放电" 动画不会在切板时静止)
-HUD
: 即是否是 ui 层, 此项就会更改 Entity
的 Position
的相对坐标系
+HUD
: 即是否是 ui 层, 此项就会改变 Entity.Render
的绘制逻辑, 使绘制坐标基于屏幕坐标而不是世界坐标
Global
: 该 Entity 是否是全局的, 一个非全局实体在关卡重试后会消失, 全局 Tag 可以避免这件事, 通常全局 Tag 最常见的用法是和 HUD 结合在一起,
这样你就拥有了一个在游戏内持久的 ui 部件了.
diff --git a/trans/il/index.html b/trans/il/index.html
index 8081f3e..22a09e5 100755
--- a/trans/il/index.html
+++ b/trans/il/index.html
@@ -13,7 +13,7 @@
-
+
@@ -525,6 +525,48 @@
+
+
+
+
+
+
+
+ Flag, Tag, Tracker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sprite, Image
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -780,6 +822,27 @@
+
+
+
+
+
+
+
+
+
+
+
+ 调试
+
+
+
+
+
+
+
+
+
@@ -2270,107 +2333,107 @@ 跳转指令
beq
-如果两个值相等,则将控制转移到目标指令。
+如果两个值相等, 则将控制转移到目标指令.
beq.s
-如果两个值相等,则将控制转移到目标指令(短格式)。
+如果两个值相等, 则将控制转移到目标指令(短格式).
bge
-如果第一个值大于或等于第二个值,则将控制转移到目标指令。
+如果第一个值大于或等于第二个值, 则将控制转移到目标指令.
bge.s
-如果第一个值大于或等于第二个值,则将控制转移到目标指令(短格式)。
+如果第一个值大于或等于第二个值, 则将控制转移到目标指令(短格式).
bge.un
-当比较无符号整数值或不可排序的浮点型值时,如果第一个值大于第二个值,则将控制转移到目标指令。
+当比较无符号整数值或不可排序的浮点型值时, 如果第一个值大于第二个值, 则将控制转移到目标指令.
bge.un.s
-当比较无符号整数值或不可排序的浮点型值时,如果第一个值大于第二个值,则将控制转移到目标指令(短格式)。
+当比较无符号整数值或不可排序的浮点型值时, 如果第一个值大于第二个值, 则将控制转移到目标指令(短格式).
bgt
-如果第一个值大于第二个值,则将控制转移到目标指令。
+如果第一个值大于第二个值, 则将控制转移到目标指令.
bgt.s
-如果第一个值大于第二个值,则将控制转移到目标指令(短格式)。
+如果第一个值大于第二个值, 则将控制转移到目标指令(短格式).
bgt.un
-当比较无符号整数值或不可排序的浮点型值时,如果第一个值大于第二个值,则将控制转移到目标指令。
+当比较无符号整数值或不可排序的浮点型值时, 如果第一个值大于第二个值, 则将控制转移到目标指令.
bgt.un.s
-当比较无符号整数值或不可排序的浮点型值时,如果第一个值大于第二个值,则将控制转移到目标指令(短格式)。
+当比较无符号整数值或不可排序的浮点型值时, 如果第一个值大于第二个值, 则将控制转移到目标指令(短格式).
ble
-如果第一个值小于或等于第二个值,则将控制转移到目标指令。
+如果第一个值小于或等于第二个值, 则将控制转移到目标指令.
ble.s
-如果第一个值小于或等于第二个值,则将控制转移到目标指令(短格式)。
+如果第一个值小于或等于第二个值, 则将控制转移到目标指令(短格式).
ble.un
-当比较无符号整数值或不可排序的浮点型值时,如果第一个值小于或等于第二个值,则将控制转移到目标指令。
+当比较无符号整数值或不可排序的浮点型值时, 如果第一个值小于或等于第二个值, 则将控制转移到目标指令.
ble.un.s
-当比较无符号整数值或不可排序的浮点型值时,如果第一个值小于或等于第二个值,则将控制权转移到目标指令(短格式)。
+当比较无符号整数值或不可排序的浮点型值时, 如果第一个值小于或等于第二个值, 则将控制权转移到目标指令(短格式).
blt
-如果第一个值小于第二个值,则将控制转移到目标指令。
+如果第一个值小于第二个值, 则将控制转移到目标指令.
blt.s
-如果第一个值小于第二个值,则将控制转移到目标指令(短格式)。
+如果第一个值小于第二个值, 则将控制转移到目标指令(短格式).
blt.un
-当比较无符号整数值或不可排序的浮点型值时,如果第一个值小于第二个值,则将控制转移到目标指令。
+当比较无符号整数值或不可排序的浮点型值时, 如果第一个值小于第二个值, 则将控制转移到目标指令.
blt.un.s
-当比较无符号整数值或不可排序的浮点型值时,如果第一个值小于第二个值,则将控制转移到目标指令(短格式)。
+当比较无符号整数值或不可排序的浮点型值时, 如果第一个值小于第二个值, 则将控制转移到目标指令(短格式).
bne.un
-当两个无符号整数值或不可排序的浮点型值不相等时,将控制转移到目标指令。
+当两个无符号整数值或不可排序的浮点型值不相等时, 将控制转移到目标指令.
bne.un.s
-当两个无符号整数值或不可排序的浮点型值不相等时,将控制转移到目标指令(短格式)。
+当两个无符号整数值或不可排序的浮点型值不相等时, 将控制转移到目标指令(短格式).
br
-无条件地将控制转移到目标指令。
+无条件地将控制转移到目标指令.
br.s
-无条件地将控制转移到目标指令(短格式)。
+无条件地将控制转移到目标指令(短格式).
brfalse
-如果 value 为 false、空引用(Visual Basic 中的 Nothing)或零,则将控制转移到目标指令。
+如果 value 为 false、空引用(Visual Basic 中的 Nothing)或零, 则将控制转移到目标指令.
brfalse.s
-如果 value 为 false、空引用或零,则将控制转移到目标指令。
+如果 value 为 false、空引用或零, 则将控制转移到目标指令.
brtrue
-如果 value 为 true、非空或非零,则将控制转移到目标指令。
+如果 value 为 true、非空或非零, 则将控制转移到目标指令.
brtrue.s
-如果 value 为 true、非空或非零,则将控制转移到目标指令(短格式)。
+如果 value 为 true、非空或非零, 则将控制转移到目标指令(短格式).
diff --git a/trans/imgs/code_dependency.jpg b/trans/imgs/code_dependency.jpg
new file mode 100755
index 0000000000000000000000000000000000000000..019bb4ae25f325b06cc3d99697dce0e1fc494ddb
GIT binary patch
literal 11890
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
literal 0
HcmV?d00001
diff --git a/trans/imgs/code_joke.jpg b/trans/imgs/code_joke.jpg
new file mode 100755
index 0000000000000000000000000000000000000000..80826db8e68ab2f971726bd121841b323db5e69a
GIT binary patch
literal 39949
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⁡;Um=7};lSiD;b_XJqdw~6j
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