From 6496cf80aee2dd3f97c12bb2f725275e00f4e59c Mon Sep 17 00:00:00 2001
From: Saplonily 这里为了方便某些没听说过 XML 的人快速了解 XML 的大致语法是什么, 所以很多细节方面的问题我会直接忽略, 那么, 就此开始吧: 这里摘抄一下: \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/CelesteModTourial \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 \u6700\u540e, \u611f\u8c22\u4e00\u4e9b\u4e3a\u672c\u6559\u7a0b\u8d21\u732e\u7684\u4eba: \u4ee5\u53ca\u6211\u81ea\u5df1 :D \u8bf4\u8d77\u6765\u56fd\u5185\u7684 coder \u770b\u8d77\u6765\u771f\u7684\u597d\u5c11\u54ce, \u6240\u4ee5\u8bf4\u5199\u8fd9\u4e2a\u6559\u7a0b\u53ef\u4ee5\u8ba4\u4e3a\u662f\u6211\u4e0d\u60f3\u5199\u7801\u60f3\u63a8\u7ed9\u522b\u4eba(( \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 bug \u590d\u73b0\u4e8e\u4e0b: XML 简单速成
+XML 简单介绍
定义
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. 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
\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:
\u5f15\u7528
\u4e0a\u53f3\u51fb\u6dfb\u52a0\u5f15\u7528
\u6d4f\u89c8
\u6d4f\u89c8
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).
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:
Info
.Tag
, \u901a\u5e38\u5b83\u662f\u4f60\u7684 Mod \u540d\u5b57\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.
\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:
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:
<?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:
<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:
PropertyGroup
\u548c ItemGroup
\u53ca\u65c1\u8fb9\u7684\u975e\u6807\u9ec4\u8282\u70b9Project
\u8282\u70b9\u4e0b\u7684\u4e24\u4e2a Import
Project
\u8282\u70b9\u7684\u6240\u6709\u5c5e\u6027Project
\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:
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
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.
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:
Celeste Windows OpenGL
\u7248\u672cNote
Everest \u4f1a\u5728\u8fd0\u884c\u65f6\u5c06\u4f60\u4ee5 FNA \u7248\u672c\u5236\u4f5c\u7684 mod \u91cd\u94fe\u63a5\u4e3a XNA, \u6240\u6709\u4f60\u4e0d\u662f\u5f88\u9700\u8981\u5728\u610f\u8fd9\u4fe9\u7684\u5dee\u8ddd \u6ce8\u610f\u66f4\u6362\u7248\u672c\u540e\u901a\u5e38\u4f1a\u53d8\u56de\u539f\u7248, \u8bb0\u5f97\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 CodeMod, \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
\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(wuwu), \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.
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 CodeMod \u4e2d\u7528\u4e0d\u5230)\u6709\u8db3\u591f\u6e05\u6670\u7684\u4e86\u89e3\u5728\u5f00\u59cb\u4f60\u7684\u851a\u84dd CodeMod \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
, \u90a3\u4f60\u9047\u5230\u4e86\u4ec0\u4e48\u5947\u602a\u7684\u95ee\u9898\u53ef\u4ee5\u5230\u4efb\u4f55\u80fd\u8054\u7cfb\u5230\u6211\u7684\u5730\u65b9\u95ee\u6211_(:\u0437\u300d\u2220)_
_(:\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\u6211\u89c9\u5f97\u8fd8\u662f\u63d0\u4f9b\u76f4\u63a5\u7684\u4e0b\u8f7d\u94fe\u63a5\u66f4\u597d, \u6216\u8005\u4f60\u4e5f\u53ef\u4ee5\u5230Github\u6e90, \u4e0b\u8f7d\u89e3\u538b\u540e, \u4f7f\u7528\u4f60\u7684 vs \u6253\u5f00\u5176\u4e2d\u7684 csproj \u6587\u4ef6, \u90a3\u4e48\u6309\u7406\u6765\u8bf4\u4f60\u4f1a\u770b\u5230\u8fd9\u51e0\u4e2a\u6587\u4ef6:
Note
\u4f60\u53ef\u80fd\u8fd8\u9700\u8981\u5b89\u88c5 .NET 6 SDK
\u6765\u4f7f\u7528\u8be5\u6a21\u677f, \u4f60\u53ef\u4ee5\u70b9\u51fb\u8fd9\u91cc\u4e0b\u8f7d
\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:
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
\u54b3\u54b3\u8fd9\u5c31\u662f\u65b0\u65b9\u6cd5\u7684\u4fbf\u5229(\u554a?), \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\u4e00\u53e5:
1>Copied files in 'ModFolder' to 'C:\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\Mods\\MyCelesteMod'\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}
\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!
\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!
\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 Module.cs
\u90a3\u4e2a\u6587\u4ef6, \u4f60\u5e94\u8be5\u4f1a\u770b\u5230\u7ed3\u6784\u8fd9\u6837\u7684\u4ee3\u7801:
namespace MyCelesteMod;\n\npublic class MyAwesomeModModule : EverestModule\n{\n public override void Load()\n {\n Logger.Log(LogLevel.Info, \"MyCelesteMod\", \"Hello World!\");\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\".
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
\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\u5b57Version
: \u4f60\u7684 mod \u7684\u7248\u672cDLL
: \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.
"},{"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:
everest-launch.txt
, \u6ca1\u6709\u7684\u8bdd\u65b0\u5efa\u4e00\u4e2a\u7a7a\u7684\u5c31\u884c\u4e86--console
\u73b0\u5728, \u91cd\u65b0\u7f16\u8bd1\u9879\u76ee, \u8ba9 msbuild
\u5e26\u7740\u4f60\u7684 ModFolder
\u7684\u5185\u5bb9\u98de\u5f80\u851a\u84dd Mods \u6587\u4ef6\u5939\u4e0b, \u542f\u52a8\u851a\u84dd. \u5728\u540c\u65f6\u542f\u52a8\u7684\u9ed1\u4e4e\u4e4e\u7684\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 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.
\u8fd9\u4e00\u8282\u5b8c\u6210\u540e\u4f60\u7684\u76ee\u5f55\u7ed3\u6784\u5927\u6982\u4f1a\u50cf\u662f:
\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. \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:
msbuild -target:CopyModAssets
\u547d\u4ee4\u884c\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\u4e3a\u5176\u5236\u4f5c mod \u7684\u5bf9\u8c61.
\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\u5728Github\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.
Everest \u5e95\u5c42\u57fa\u4e8e MonoMod, \u5728\u8fd9\u91cc\u4f60\u53ea\u9700\u8981\u77e5\u9053 Everest \u4f9d\u8d56\u4e86 MonoMod, \u540c\u6837\u5730\u8fd9\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.
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\u4f60\u662f\u5426\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:
\u6587\u4ef6
, \u6253\u5f00
Celeste.exe
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:
\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 Monogame
\u6216\u8005 FNA
, \u5b83\u4eec\u90fd\u662f\u5fae\u8f6f\u7684 XNA
\u6846\u67b6\u7684\u91cd\u65b0\u5b9e\u73b0(\u56e0\u4e3a XNA
\u65e9\u505c\u66f4\u4e86), 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.
\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.
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/#_2","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.
\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\u4f60\u7684\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 6 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
\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\u901f\u6210\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.
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\u897fCeleste
: \u851a\u84dd\u672c\u4f53\u6240\u5728\u547d\u540d\u7a7a\u95f4Monocle
: \u851a\u84dd\u81ea\u5df1\u7684\u6e38\u620f\u5f15\u64ceMicrosoft.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/prefer/#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:
namespace MyCelesteMod
\u540e\u52a0\u4e0a\u4e00\u4e2a\u5206\u53f7namespace 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
\u5982\u679c\u4f60\u6536\u5230\u9519\u8bef CS8370
, \u90a3\u4f60\u5c31\u9700\u8981\u5728 PropertyGroup
\u4e0b\u6dfb\u52a0\u8fd9\u4e00\u884c:
<LangVersion>preview</LangVersion>\n
"},{"location":"begin/prefer/#_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\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\u7684\u4ee3\u7801.
\u90a3\u4e48\u539f\u56e0\u8bf4\u5b8c\u4e86, \u63a5\u4e0b\u6765\u5c31\u6765\u89e3\u51b3\u8fd9\u4e9b \"\u662f\u4ec0\u4e48\" \u7684\u95ee\u9898:
"},{"location":"begin/reading_2/#ctor-cctor","title":".ctor / .cctor","text":".ctor
\u662f\u4e00\u79cd\u7279\u6b8a\u7684\u51fd\u6570\u540d\u79f0, \u8868\u793a\u7c7b\u7684\u6784\u9020\u51fd\u6570, \u6bd4\u5982 Player..ctor(a, b)
\u5c31\u8868\u793a\u8fd9\u91cc\u8c03\u7528\u4e86 Player..ctor
\u8fd9\u4e2a\u51fd\u6570, \u867d\u7136\u4f60\u81ea\u5df1\u5728 C# \u4e2d\u662f\u505a\u4e0d\u5230\u7684. \u6240\u4ee5\u6211\u4eec\u7ecf\u5e38\u4e5f\u4f1a\u7528 ctor
\u6216\u8005 .ctor
\u6765\u6307\u4ee3 \"\u6784\u9020\u51fd\u6570\".
.cctor
\u4e5f\u662f\u4e00\u79cd\u7279\u6b8a\u7684\u51fd\u6570\u540d\u79f0, \u8868\u793a\u7c7b\u7684\u9759\u6001\u6784\u9020\u51fd\u6570, \u6bd4\u5982 Input..cctor()
\u5c31\u8868\u793a\u8c03\u7528 Input
\u7c7b\u7684\u65e0\u53c2\u9759\u6001\u6784\u9020\u51fd\u6570. \u540c\u6837\u5730\u6211\u4eec\u901a\u5e38\u4e5f\u4f1a\u7528 cctor
\u6216\u8005 .cctor
\u6765\u6307\u4ee3 \"\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\u7f16\u8bd1, \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
\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.
\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.
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.
\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:
\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; // \u88ab\u56fa\u4f53\u6324\u538b?\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; // 7a, 7b \u4e0a\u5347\u8fc7\u573a\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:
PassByRefill
\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:
namespace 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\u7a7a\u95f4\u4e2d\u7684\u4f4d\u7f6e, \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\u9876\u70b9\u5728\u5de6\u4e0a\u89d2, X \u8f74\u6c34\u5e73\u5411\u53f3\u4f46\u662f Y \u8f74\u7ad6\u76f4\u5411\u4e0b! \u5207\u8bb0\u4e0d\u8981\u641e\u6df7\u4e86. Vector2
\u540c\u65f6\u4e5f\u53ef\u80fd\u8868\u793a\u5927\u5c0f, \u5373 X
\u5b57\u6bb5\u8868\u793a\u5bbd\u5ea6, Y
\u5b57\u6bb5\u8868\u793a\u957f\u5ea6, \u5728\u8fd9\u91cc\u6211\u4eec\u7528\u5b83\u6765\u63a5\u6536\u5b83\u7684\u5927\u5c0f. \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\u5728\u672c\u8282\u540e\u8fb9\u5c31\u4f1a\u4f7f\u7528\u5b83\u4e86.
\u63a5\u4e0b\u6765, \u6211\u4eec\u9700\u8981\u58f0\u660e\u4e00\u4e2a\u7279\u6b8a\u7684\u6784\u9020\u51fd\u6570, \u8fd9\u4e2a\u6784\u9020\u51fd\u6570\u7531 Everest \u53cd\u5c04\u8c03\u7528, \u7528\u4e8e\u5c06\u4f5c\u56fe\u8f6f\u4ef6\u90a3\u8fb9\u7684\u6570\u636e\u4f20\u9012\u7ed9\u6211\u4eec: 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)
\u5c31\u5f97\u5230\u4e86, \u7136\u540e\u662f\u5b83\u7684\u5927\u5c0f\u6570\u636e, \u7531\u4e8e\u5927\u5c0f\u662f\u4e2a\u7279\u6b8a\u7684\u4e1c\u897f, \u8fd9\u91cc\u6211\u4eec\u53ef\u4ee5\u76f4\u63a5\u901a\u8fc7 Width
\u548c Height
\u5c5e\u6027\u63d0\u53d6\u5e76 new
\u4e00\u4e2a Vector2
\u7ed3\u6784\u4f53\u6765\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
\u8868\u793a\u8fd9\u4e00\u9762\u7684\u6700\u5de6\u4e0a\u89d2\u7684\u4e16\u754c\u5750\u6807, EntityData
\u7684 Position
\u662f\u7269\u4f53\u76f8\u5bf9\u4e8e\u8fd9\u4e00\u9762\u6700\u5de6\u4e0a\u89d2\u7684\u5750\u6807, \u6240\u4ee5\u6211\u4eec\u9700\u8981\u628a\u5b83\u76f8\u52a0\u6765\u5f97\u5230\u4e16\u754c\u5750\u6807.(\u56e0\u4e3a Entity.Position
\u6c38\u8fdc\u53ea\u63a5\u53d7\u4e16\u754c\u5750\u6807!) Info
\u8fd9\u4e2a\u6784\u9020\u51fd\u6570\u7684\u53c2\u6570\u5217\u8868\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!!
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:
\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:
local 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
.
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.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\").data
\u5c5e\u6027, \u5b83\u8868\u793a\u8fd9\u4e2a\u5b9e\u4f53\u7684\u6570\u636e.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. 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\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.
\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
.
\u90a3\u4e48, \u529f\u80fd\u505a\u597d\u540e, \u7684\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.Rect
Draw.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.
\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(\u753b\u753b\u4e00\u70b9\u4e0d\u4f1aqwq):
\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:
MyCelesteMod
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 (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
\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\"\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:
\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:
SetPassByRefillDashesTrigger
PassByRefill
\u5b9e\u4f53\u7684\u51b2\u523a\u6570\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.
/// .......\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:
PassByRefill
\u7684 Dashes
\u5b57\u6bb5\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:
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:
\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. \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":"other/xml-speedrun/","title":"XML \u7b80\u5355\u901f\u6210","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.
\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 A, \u5b83\u7684\u540d\u5b57\u53eb\u505a\"books\", \u5b83\u6709\u5f88\u591a\u5b50\u8282\u70b9, \u5206\u522b\u662f:
\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).
\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/common1/","title":"Alarm, Tween, Coroutine","text":"\u90a3\u4e48\u7ecf\u8fc7\u524d\u9762\u8fd9\u4e48\u591a\u5e9f\u8bdd(\u786e\u4fe1)\u4e4b\u540e\u6211\u4eec\u7ec8\u4e8e\u6765\u5230\u4e86\u4ecb\u7ecd\u4e00\u4e9b\u5e38\u89c1\u7684\u851a\u84dd\u7c7b\u548c Monocle \u7c7b\u7684\u5730\u65b9(wuwu), \u90a3\u4e48...\u5c31\u5f00\u59cb\u5427.
"},{"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:
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\u8eabLooping
: \u7f13\u52a8\u7ed3\u675f\u4e00\u6b21\u540e\u4f1a\u7acb\u523b\u518d\u6b21\u5f00\u59cb\u540c\u4e00\u4e2a\u7f13\u52a8, \u5e76\u5faa\u73afYoyoOneshot
: \u7f13\u52a8\u7ed3\u675f\u540e\u4f1a\u7acb\u523b\u8fdb\u884c\u4e00\u6b21\u53cd\u5411\u7684\u7f13\u52a8, \u7ed3\u675f\u540e\u79fb\u9664\u81ea\u8eabYoyoLooping
: \u540c YoyoOneshot
, \u4f46\u662f\u4f1a\u5faa\u73af\u800c\u4e0d\u662f\u79fb\u9664\u81ea\u8eabeaser
: \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.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.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:
\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:
// \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
.
\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
AlarmMode
\u4e0e Tween.TweenMode
\u7684\u57fa\u672c\u4e00\u81f4, \u8fd9\u91cc\u5c31\u4e0d\u8d58\u8ff0\u4e86Start
\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.
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\u7528SceneEnd
: \u5f53\u573a\u666f\u88ab\u8c03\u7528 Scene.End
\u7684\u540c\u65f6\u8c03\u7528\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\u4e2dEntity.Add
: \u5c06\u4e00\u4e2a Component \u6302\u8f7d\u5230\u5b9e\u4f53\u4e0aScene.Remove
: \u5c06\u4e00\u4e2a\u5b9e\u4f53\u79fb\u51fa\u573a\u666fEntity.Remove
: \u5c06\u4e00\u4e2a Component \u79fb\u51fa\u5b9e\u4f53Entity.RemoveSelf
: \u5c06 Entity \u81ea\u8eab\u79fb\u51fa\u81ea\u8eab\u6240\u5728\u573a\u666fComponent.RemoveSelf
: \u5c06 Component \u81ea\u8eab\u79fb\u51fa\u6240\u5728\u5b9e\u4f53Scene.Entities
: \u83b7\u53d6\u5f53\u524d\u573a\u666f\u4e0a\u7684\u5b9e\u4f53\u5217\u8868Entity.Components
: \u83b7\u53d6\u5f53\u524d\u5b9e\u4f53\u7684 Component \u5217\u8868Entity
\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\u7bb1Visible
, \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.: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\u4e0aFrozenUpdate
: \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\u7cfbGlobal
: \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.Info
\u5982\u679c\u4f60\u5728\u4e4b\u524d\u5df2\u7ecf\u5b66\u4e60\u8fc7 IL
\u5e76\u4e14\u4f7f\u7528\u8fc7\u7c7b System.Reflection.Emit
\u8fd9\u4e9b api \u7684\u8bdd\u4f60\u53ef\u4ee5\u8df3\u8fc7\u8fd9\u4e00\u8282.
IL
\u5168\u79f0 Intermediate Language
, \u5728\u4e00\u4e9b\u8f83\u8001\u7684\u6587\u6863\u91cc\u9762\u5b83\u53ef\u80fd\u4e5f\u4f1a\u88ab\u53eb\u505a MSIL
, \u5373 Microsoft Intermediate Language
. \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.
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.
\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 7
. \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.
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
:
IL
\u7684\u64cd\u4f5c\u7801\u662f nop
, \u6ca1\u6709\u53c2\u6570IL
\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.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\u7f6eIL
\u7684\u64cd\u4f5c\u7801\u662f nop
, \u6ca1\u6709\u53c2\u6570IL
\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.
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\u5199IL
","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
.
\u4e58\u6cd5\u7684\u64cd\u4f5c\u7b26\u4e3a mul
, \u5176\u4f7f\u7528\u65b9\u6cd5\u4e0e add
\u4e00\u81f4.
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
:
\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:
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:
ar 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:
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\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.
\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.
\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":"\u6761\u4ef6\u8df3\u8f6c","text":"// TODO
"},{"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, \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:
\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/CelesteModTourial \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
\u6700\u540e, \u611f\u8c22\u4e00\u4e9b\u4e3a\u672c\u6559\u7a0b\u8d21\u732e\u7684\u4eba:
\u4ee5\u53ca\u6211\u81ea\u5df1 :D
\u8bf4\u8d77\u6765\u56fd\u5185\u7684 coder \u770b\u8d77\u6765\u771f\u7684\u597d\u5c11\u54ce, \u6240\u4ee5\u8bf4\u5199\u8fd9\u4e2a\u6559\u7a0b\u53ef\u4ee5\u8ba4\u4e3a\u662f\u6211\u4e0d\u60f3\u5199\u7801\u60f3\u63a8\u7ed9\u522b\u4eba((
\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 \u590d\u73b0\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
"},{"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:
\u5f15\u7528
\u4e0a\u53f3\u51fb\u6dfb\u52a0\u5f15\u7528
\u6d4f\u89c8
\u6d4f\u89c8
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).
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:
Info
.Tag
, \u901a\u5e38\u5b83\u662f\u4f60\u7684 Mod \u540d\u5b57\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.
\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:
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:
<?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:
<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:
PropertyGroup
\u548c ItemGroup
\u53ca\u65c1\u8fb9\u7684\u975e\u6807\u9ec4\u8282\u70b9Project
\u8282\u70b9\u4e0b\u7684\u4e24\u4e2a Import
Project
\u8282\u70b9\u7684\u6240\u6709\u5c5e\u6027Project
\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:
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
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.
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:
Celeste Windows OpenGL
\u7248\u672cNote
Everest \u4f1a\u5728\u8fd0\u884c\u65f6\u5c06\u4f60\u4ee5 FNA \u7248\u672c\u5236\u4f5c\u7684 mod \u91cd\u94fe\u63a5\u4e3a XNA, \u6240\u6709\u4f60\u4e0d\u662f\u5f88\u9700\u8981\u5728\u610f\u8fd9\u4fe9\u7684\u5dee\u8ddd \u6ce8\u610f\u66f4\u6362\u7248\u672c\u540e\u901a\u5e38\u4f1a\u53d8\u56de\u539f\u7248, \u8bb0\u5f97\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 CodeMod, \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
\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(wuwu), \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.
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 CodeMod \u4e2d\u7528\u4e0d\u5230)\u6709\u8db3\u591f\u6e05\u6670\u7684\u4e86\u89e3\u5728\u5f00\u59cb\u4f60\u7684\u851a\u84dd CodeMod \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
, \u90a3\u4f60\u9047\u5230\u4e86\u4ec0\u4e48\u5947\u602a\u7684\u95ee\u9898\u53ef\u4ee5\u5230\u4efb\u4f55\u80fd\u8054\u7cfb\u5230\u6211\u7684\u5730\u65b9\u95ee\u6211_(:\u0437\u300d\u2220)_
_(:\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\u6211\u89c9\u5f97\u8fd8\u662f\u63d0\u4f9b\u76f4\u63a5\u7684\u4e0b\u8f7d\u94fe\u63a5\u66f4\u597d, \u6216\u8005\u4f60\u4e5f\u53ef\u4ee5\u5230Github\u6e90, \u4e0b\u8f7d\u89e3\u538b\u540e, \u4f7f\u7528\u4f60\u7684 vs \u6253\u5f00\u5176\u4e2d\u7684 csproj \u6587\u4ef6, \u90a3\u4e48\u6309\u7406\u6765\u8bf4\u4f60\u4f1a\u770b\u5230\u8fd9\u51e0\u4e2a\u6587\u4ef6:
Note
\u4f60\u53ef\u80fd\u8fd8\u9700\u8981\u5b89\u88c5 .NET 6 SDK
\u6765\u4f7f\u7528\u8be5\u6a21\u677f, \u4f60\u53ef\u4ee5\u70b9\u51fb\u8fd9\u91cc\u4e0b\u8f7d
\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:
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
\u54b3\u54b3\u8fd9\u5c31\u662f\u65b0\u65b9\u6cd5\u7684\u4fbf\u5229(\u554a?), \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\u4e00\u53e5:
1>Copied files in 'ModFolder' to 'C:\\Program Files (x86)\\Steam\\steamapps\\common\\Celeste\\Mods\\MyCelesteMod'\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}
\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!
\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!
\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 Module.cs
\u90a3\u4e2a\u6587\u4ef6, \u4f60\u5e94\u8be5\u4f1a\u770b\u5230\u7ed3\u6784\u8fd9\u6837\u7684\u4ee3\u7801:
namespace MyCelesteMod;\n\npublic class MyAwesomeModModule : EverestModule\n{\n public override void Load()\n {\n Logger.Log(LogLevel.Info, \"MyCelesteMod\", \"Hello World!\");\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\".
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
\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\u5b57Version
: \u4f60\u7684 mod \u7684\u7248\u672cDLL
: \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.
"},{"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:
everest-launch.txt
, \u6ca1\u6709\u7684\u8bdd\u65b0\u5efa\u4e00\u4e2a\u7a7a\u7684\u5c31\u884c\u4e86--console
\u73b0\u5728, \u91cd\u65b0\u7f16\u8bd1\u9879\u76ee, \u8ba9 msbuild
\u5e26\u7740\u4f60\u7684 ModFolder
\u7684\u5185\u5bb9\u98de\u5f80\u851a\u84dd Mods \u6587\u4ef6\u5939\u4e0b, \u542f\u52a8\u851a\u84dd. \u5728\u540c\u65f6\u542f\u52a8\u7684\u9ed1\u4e4e\u4e4e\u7684\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 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.
\u8fd9\u4e00\u8282\u5b8c\u6210\u540e\u4f60\u7684\u76ee\u5f55\u7ed3\u6784\u5927\u6982\u4f1a\u50cf\u662f:
\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. \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:
msbuild -target:CopyModAssets
\u547d\u4ee4\u884c\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\u4e3a\u5176\u5236\u4f5c mod \u7684\u5bf9\u8c61.
\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\u5728Github\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.
Everest \u5e95\u5c42\u57fa\u4e8e MonoMod, \u5728\u8fd9\u91cc\u4f60\u53ea\u9700\u8981\u77e5\u9053 Everest \u4f9d\u8d56\u4e86 MonoMod, \u540c\u6837\u5730\u8fd9\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.
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\u4f60\u662f\u5426\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:
\u6587\u4ef6
, \u6253\u5f00
Celeste.exe
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:
\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 Monogame
\u6216\u8005 FNA
, \u5b83\u4eec\u90fd\u662f\u5fae\u8f6f\u7684 XNA
\u6846\u67b6\u7684\u91cd\u65b0\u5b9e\u73b0(\u56e0\u4e3a XNA
\u65e9\u505c\u66f4\u4e86), 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.
\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.
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/#_2","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.
\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\u4f60\u7684\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 6 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
\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\u901f\u6210\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.
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\u897fCeleste
: \u851a\u84dd\u672c\u4f53\u6240\u5728\u547d\u540d\u7a7a\u95f4Monocle
: \u851a\u84dd\u81ea\u5df1\u7684\u6e38\u620f\u5f15\u64ceMicrosoft.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/prefer/#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:
namespace MyCelesteMod
\u540e\u52a0\u4e0a\u4e00\u4e2a\u5206\u53f7namespace 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
\u5982\u679c\u4f60\u6536\u5230\u9519\u8bef CS8370
, \u90a3\u4f60\u5c31\u9700\u8981\u5728 PropertyGroup
\u4e0b\u6dfb\u52a0\u8fd9\u4e00\u884c:
<LangVersion>preview</LangVersion>\n
"},{"location":"begin/prefer/#_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\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\u7684\u4ee3\u7801.
\u90a3\u4e48\u539f\u56e0\u8bf4\u5b8c\u4e86, \u63a5\u4e0b\u6765\u5c31\u6765\u89e3\u51b3\u8fd9\u4e9b \"\u662f\u4ec0\u4e48\" \u7684\u95ee\u9898:
"},{"location":"begin/reading_2/#ctor-cctor","title":".ctor / .cctor","text":".ctor
\u662f\u4e00\u79cd\u7279\u6b8a\u7684\u51fd\u6570\u540d\u79f0, \u8868\u793a\u7c7b\u7684\u6784\u9020\u51fd\u6570, \u6bd4\u5982 Player..ctor(a, b)
\u5c31\u8868\u793a\u8fd9\u91cc\u8c03\u7528\u4e86 Player..ctor
\u8fd9\u4e2a\u51fd\u6570, \u867d\u7136\u4f60\u81ea\u5df1\u5728 C# \u4e2d\u662f\u505a\u4e0d\u5230\u7684. \u6240\u4ee5\u6211\u4eec\u7ecf\u5e38\u4e5f\u4f1a\u7528 ctor
\u6216\u8005 .ctor
\u6765\u6307\u4ee3 \"\u6784\u9020\u51fd\u6570\".
.cctor
\u4e5f\u662f\u4e00\u79cd\u7279\u6b8a\u7684\u51fd\u6570\u540d\u79f0, \u8868\u793a\u7c7b\u7684\u9759\u6001\u6784\u9020\u51fd\u6570, \u6bd4\u5982 Input..cctor()
\u5c31\u8868\u793a\u8c03\u7528 Input
\u7c7b\u7684\u65e0\u53c2\u9759\u6001\u6784\u9020\u51fd\u6570. \u540c\u6837\u5730\u6211\u4eec\u901a\u5e38\u4e5f\u4f1a\u7528 cctor
\u6216\u8005 .cctor
\u6765\u6307\u4ee3 \"\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\u7f16\u8bd1, \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
\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.
\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.
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.
\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:
\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; // \u88ab\u56fa\u4f53\u6324\u538b?\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; // 7a, 7b \u4e0a\u5347\u8fc7\u573a\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:
PassByRefill
\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:
namespace 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\u7a7a\u95f4\u4e2d\u7684\u4f4d\u7f6e, \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\u9876\u70b9\u5728\u5de6\u4e0a\u89d2, X \u8f74\u6c34\u5e73\u5411\u53f3\u4f46\u662f Y \u8f74\u7ad6\u76f4\u5411\u4e0b! \u5207\u8bb0\u4e0d\u8981\u641e\u6df7\u4e86. Vector2
\u540c\u65f6\u4e5f\u53ef\u80fd\u8868\u793a\u5927\u5c0f, \u5373 X
\u5b57\u6bb5\u8868\u793a\u5bbd\u5ea6, Y
\u5b57\u6bb5\u8868\u793a\u957f\u5ea6, \u5728\u8fd9\u91cc\u6211\u4eec\u7528\u5b83\u6765\u63a5\u6536\u5b83\u7684\u5927\u5c0f. \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\u5728\u672c\u8282\u540e\u8fb9\u5c31\u4f1a\u4f7f\u7528\u5b83\u4e86.
\u63a5\u4e0b\u6765, \u6211\u4eec\u9700\u8981\u58f0\u660e\u4e00\u4e2a\u7279\u6b8a\u7684\u6784\u9020\u51fd\u6570, \u8fd9\u4e2a\u6784\u9020\u51fd\u6570\u7531 Everest \u53cd\u5c04\u8c03\u7528, \u7528\u4e8e\u5c06\u4f5c\u56fe\u8f6f\u4ef6\u90a3\u8fb9\u7684\u6570\u636e\u4f20\u9012\u7ed9\u6211\u4eec: 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)
\u5c31\u5f97\u5230\u4e86, \u7136\u540e\u662f\u5b83\u7684\u5927\u5c0f\u6570\u636e, \u7531\u4e8e\u5927\u5c0f\u662f\u4e2a\u7279\u6b8a\u7684\u4e1c\u897f, \u8fd9\u91cc\u6211\u4eec\u53ef\u4ee5\u76f4\u63a5\u901a\u8fc7 Width
\u548c Height
\u5c5e\u6027\u63d0\u53d6\u5e76 new
\u4e00\u4e2a Vector2
\u7ed3\u6784\u4f53\u6765\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
\u8868\u793a\u8fd9\u4e00\u9762\u7684\u6700\u5de6\u4e0a\u89d2\u7684\u4e16\u754c\u5750\u6807, EntityData
\u7684 Position
\u662f\u7269\u4f53\u76f8\u5bf9\u4e8e\u8fd9\u4e00\u9762\u6700\u5de6\u4e0a\u89d2\u7684\u5750\u6807, \u6240\u4ee5\u6211\u4eec\u9700\u8981\u628a\u5b83\u76f8\u52a0\u6765\u5f97\u5230\u4e16\u754c\u5750\u6807.(\u56e0\u4e3a Entity.Position
\u6c38\u8fdc\u53ea\u63a5\u53d7\u4e16\u754c\u5750\u6807!) Info
\u8fd9\u4e2a\u6784\u9020\u51fd\u6570\u7684\u53c2\u6570\u5217\u8868\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!!
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:
\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:
local 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
.
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.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\").data
\u5c5e\u6027, \u5b83\u8868\u793a\u8fd9\u4e2a\u5b9e\u4f53\u7684\u6570\u636e.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. 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\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.
\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
.
\u90a3\u4e48, \u529f\u80fd\u505a\u597d\u540e, \u7684\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.Rect
Draw.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.
\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(\u753b\u753b\u4e00\u70b9\u4e0d\u4f1aqwq):
\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:
MyCelesteMod
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 (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
\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\"\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:
\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:
SetPassByRefillDashesTrigger
PassByRefill
\u5b9e\u4f53\u7684\u51b2\u523a\u6570\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.
/// .......\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:
PassByRefill
\u7684 Dashes
\u5b57\u6bb5\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:
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:
\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. \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":"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.
\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 A, \u5b83\u7684\u540d\u5b57\u53eb\u505a\"books\", \u5b83\u6709\u5f88\u591a\u5b50\u8282\u70b9, \u5206\u522b\u662f:
\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).
\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/common1/","title":"Alarm, Tween, Coroutine","text":"\u90a3\u4e48\u7ecf\u8fc7\u524d\u9762\u8fd9\u4e48\u591a\u5e9f\u8bdd(\u786e\u4fe1)\u4e4b\u540e\u6211\u4eec\u7ec8\u4e8e\u6765\u5230\u4e86\u4ecb\u7ecd\u4e00\u4e9b\u5e38\u89c1\u7684\u851a\u84dd\u7c7b\u548c Monocle \u7c7b\u7684\u5730\u65b9(wuwu), \u90a3\u4e48...\u5c31\u5f00\u59cb\u5427.
"},{"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:
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\u8eabLooping
: \u7f13\u52a8\u7ed3\u675f\u4e00\u6b21\u540e\u4f1a\u7acb\u523b\u518d\u6b21\u5f00\u59cb\u540c\u4e00\u4e2a\u7f13\u52a8, \u5e76\u5faa\u73afYoyoOneshot
: \u7f13\u52a8\u7ed3\u675f\u540e\u4f1a\u7acb\u523b\u8fdb\u884c\u4e00\u6b21\u53cd\u5411\u7684\u7f13\u52a8, \u7ed3\u675f\u540e\u79fb\u9664\u81ea\u8eabYoyoLooping
: \u540c YoyoOneshot
, \u4f46\u662f\u4f1a\u5faa\u73af\u800c\u4e0d\u662f\u79fb\u9664\u81ea\u8eabeaser
: \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.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.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:
\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:
// \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
.
\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
AlarmMode
\u4e0e Tween.TweenMode
\u7684\u57fa\u672c\u4e00\u81f4, \u8fd9\u91cc\u5c31\u4e0d\u8d58\u8ff0\u4e86Start
\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.
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\u7528SceneEnd
: \u5f53\u573a\u666f\u88ab\u8c03\u7528 Scene.End
\u7684\u540c\u65f6\u8c03\u7528\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\u4e2dEntity.Add
: \u5c06\u4e00\u4e2a Component \u6302\u8f7d\u5230\u5b9e\u4f53\u4e0aScene.Remove
: \u5c06\u4e00\u4e2a\u5b9e\u4f53\u79fb\u51fa\u573a\u666fEntity.Remove
: \u5c06\u4e00\u4e2a Component \u79fb\u51fa\u5b9e\u4f53Entity.RemoveSelf
: \u5c06 Entity \u81ea\u8eab\u79fb\u51fa\u81ea\u8eab\u6240\u5728\u573a\u666fComponent.RemoveSelf
: \u5c06 Component \u81ea\u8eab\u79fb\u51fa\u6240\u5728\u5b9e\u4f53Scene.Entities
: \u83b7\u53d6\u5f53\u524d\u573a\u666f\u4e0a\u7684\u5b9e\u4f53\u5217\u8868Entity.Components
: \u83b7\u53d6\u5f53\u524d\u5b9e\u4f53\u7684 Component \u5217\u8868Entity
\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\u7bb1Visible
, \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.: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\u4e0aFrozenUpdate
: \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\u7cfbGlobal
: \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.Info
\u5982\u679c\u4f60\u5728\u4e4b\u524d\u5df2\u7ecf\u5b66\u4e60\u8fc7 IL
\u5e76\u4e14\u4f7f\u7528\u8fc7\u7c7b System.Reflection.Emit
\u8fd9\u4e9b api \u7684\u8bdd\u4f60\u53ef\u4ee5\u8df3\u8fc7\u8fd9\u4e00\u8282.
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.
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.
\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 7
. \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.
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
:
IL
\u7684\u64cd\u4f5c\u7801\u662f nop
, \u6ca1\u6709\u53c2\u6570IL
\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.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\u7f6eIL
\u7684\u64cd\u4f5c\u7801\u662f nop
, \u6ca1\u6709\u53c2\u6570IL
\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.
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\u5199IL
","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
.
\u4e58\u6cd5\u7684\u64cd\u4f5c\u7b26\u4e3a mul
, \u5176\u4f7f\u7528\u65b9\u6cd5\u4e0e add
\u4e00\u81f4.
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
:
\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:
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:
ar 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:
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\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.
\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.
\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):
\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.
\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, \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:
如果你在之前已经学习过 IL
并且使用过类 System.Reflection.Emit
这些 api 的话你可以跳过这一节.
IL
全称 Intermediate Language
, 在一些较老的文档里面它可能也会被叫做 MSIL
, 即 Microsoft Intermediate Language
.
+
IL
全称 Intermediate Language
, 即中间语言, 在一些较老的文档里面它可能也会被叫做 MSIL
, 即 Microsoft Intermediate Language
,
+偶尔还会有一些地方叫做 CIL
, 即 Common Intermediate Language
, 这三种叫法通常意义上都是指一个东西.
在前面我们就已经提到过 IL
了(阅读代码2), 但是并没有深入的讲解它到底是什么样的.
IL
通常来说可以理解成两个部分, 一个 "执行" 部分, 一个 "声明" 部分, "执行" 部分规定了一个函数内部的代码应该怎么操控我们的程序,
而 "声明" 部分则规定了一个函数的返回值, 参数列表, 访问修饰符, 所在类, 类的访问修饰符, 名称等这些元数据, 获取这些元数据其实你早在学习反射的时候就进行过.
@@ -1888,8 +1903,280 @@
// TODO
+在这里我们会介绍这一节的最后一个东西 —— 跳转指令. 它是 C# 中 if
switch
for
while
goto
等流程控制语句都十分依赖的东西.
在 IL
中, 为了方便 大于, 小于, 大于等于, 小于等于, 是否 null, 是否非0 等众多条件表达式的判断,
+IL
引入了大量有关的指令, 具体如下表(摘自 MSDN):
指令 | +描述 | +
---|---|
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)或零,则将控制转移到目标指令。 | +
brfalse.s | +如果 value 为 false、空引用或零,则将控制转移到目标指令。 | +
brtrue | +如果 value 为 true、非空或非零,则将控制转移到目标指令。 | +
brtrue.s | +如果 value 为 true、非空或非零,则将控制转移到目标指令(短格式)。 | +
可以发现, 基本都是各种大于小于等于非空非0等以及有符号无符号这些情况的排列组合.
+上表中我们称除了 br
与 br.s
指令外的指令为 "条件跳转指令", 反之我们称为 "无条件跳转指令".
+这里我们只会简单举例 br
brfalse
这两个指令的使用. 其他指令基本只是几个条件不同类型不同的差别.
brfalse
指令会从评估栈上弹出一个值, 然后查看该值是否为 false
或者 null
或者 0
, 如果是则跳转到参数所指的目标位置, 否则不做任何事.
+比如如下 C# 代码:
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 |
|
顺便记得更改我们的方法定义:
+1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 |
|
其对应 IL
为:
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 |
|
在这里, 在使用 System.Reflection.Emit
库的情况下, 我们在代码的第 2 行定义了一个 Label, 用来之后作为条件跳转指令的参数传入,
+不过目前这个 Label 没有指向任何 IL
指令位置, 所以我们在第 8 行调用 MarkLabel
方法, 调用完该方法后的下一次 Emit
的 IL
指令的位置信息就会被设置到 Label 中,
+观察上述代码不难发现, 我们读取的第一个参数, 如果为 0 那么跳转到输出 value is 0!
的 IL
指令段前, 而当非 0 时不做任何事让其自然执行到输出 value is not 0.
的 IL
指令段前,
+你可以更改调用这个方法的代码的地方传入的参数来观察它的输出(比如将 action(1)
改为 action(0)
).
+顺便, 在这个指令段后面紧跟一个 ret
指令直接返回该方法防止误执行到后面的 IL
段. 不过这只在后面没有代码需要执行的情况下奏效,
+如果后面依然有代码的话我们就得使用 br
指令了.
br
指令执行后会将目前的执行位置无条件的跳转到对应位置, 比如刚才介绍 brfalse
指令末尾的一点小问题, 即比如如下 C# 代码:
1 +2 +3 +4 +5 +6 +7 +8 +9 |
|
在末尾我们有一个方法调用是无关 value
的值的, 之前的代码我们为了防止误执行 IL
我们使用了 ret
指令直接返回整个方法,
+但是现在这里我们无法这么干, 不过现在有 br
指令可以使用了:
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 |
|
.s
系指令你可能发现了就是一些 IL
指令同时还有一个带 .s
后缀的版本, 这个我们一般叫它的 "短格式" 版本, 反之叫 "长格式" 版本, 比如就刚才的 br
对应的 br.s
,
+通常类似这一对 IL
指令的区别就是 .s
版本的参数会短一点, 比如长格式版本的参数长度是 4 字节, 而短格式版本的参数长度可能就是 2 字节,
+注意这里不是说的是压入评估栈的值的类型, 长短格式版本所做的事情是完全一样的, 只是传参允许你用短一点的参数. 这其实就是一个对 IL
指令的大小优化,
+编译器通常就会能用 .s
版本就用 .s
版本, 当参数需求超过短格式参数表达范围时才会使用长格式, 对于我们的话如果你想微微的优化一下你的 IL
的大小的话,
+你可以选择在参数范围够用的情况下使用 .s
版本.
至此, 一些基本的 IL
你已了解, 我们在这里介绍的 IL
指令不过是冰山一角, 还有很多其他的 IL
指令没有介绍,
不过它们大同小异, 基本都是对评估栈的各种各样的操作, 我们只需要在用到时或者偶尔翻阅一下 IL
指令表就能了解.