Patch - solaris0115/RimWorldModGuide GitHub Wiki
ํจ์น ํจ์
๊ธฐ์กด์ ํจ์์ ์ ๊ทผ, ์ ์ดํ๋ ํ๋ชจ๋ ํจ์๋ค์ ํจ์น ํจ์
๋ผ๊ณ ํฉ๋๋ค.
ํจ์น ํจ์๋ค์ ๋ค์๊ณผ ๊ฐ์ ์์ฑ
์ด๋ ํจ์๋ฅผ ์ด์ฉํด ๋ง๋ค ์ ์์ต๋๋ค.
[HarmonyTargetMethod]
, [HarmonyPrepare]
, [HarmonyPrefix]
, [HarmonyPostfix]
, [HarmonyTranspiler]
TargetMethod()
, Prepare()
, Prefix()
, Postfix()
, Transpiler()
TargetMethod
๋ฏธํ์ธ
Prepare
๋ฏธํ์ธ
Prefix
Prefix๋ ๊ธฐ์กด์ ํจ์ ์ด์ ์ ๋จผ์ ์คํ๋ฉ๋๋ค.
Prefix๋ ๋๊ฐ์ง ํํ๋ก ๋ฐํ์ด ๊ฐ๋ฅํฉ๋๋ค. void
์ bool
bool๋ก ๋ฐํํ ๊ฒฝ์ฐ ๋ฐํ๊ฐ์ ๋ฐ๋ผ ๊ธฐ์กด์ ํจ์๊ฐ ์คํ๋ ์ง ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๊ฒ ๋ฉ๋๋ค.
true ์ผ๊ฒฝ์ฐ ๊ธฐ์กด์ ํจ์๋ฅผ ์คํํ๊ณ false์ผ ๊ฒฝ์ฐ ๊ธฐ์กด์ ํจ์๋ฅผ ์คํํ์ง ์์ต๋๋ค.
Postfix
Postfix๋ ๊ธฐ์กด์ ํจ์ ์ดํ์ ์คํ ๋ฉ๋๋ค.
Postfix๋ void ํํ๋ง ๋ฐํ์ด ๊ฐ๋ฅํฉ๋๋ค.
Transpiler
Transpiler๋ C# ์ด์
๋ธ๋ฆฌ์ด์ธ IL
์ ํตํด ๊ธฐ์กด์ ์ฝ๋๋ฅผ ๊ต์ฒดํ๋ ์์ฑ์
๋๋ค.
์ด๊ฒ์ ์ฌ์ฉํ๋ฉด ๊ธฐ์กด ํจ์์์์ ๋ช
๋ น์ด ์ธํธ๋ฅผ ๋ถ๋ถ์ ์์ ,๊ต์ฒด,์ญ์ ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
Patch ์ง์นจ
Prefix์ Postfix ๋ชจ๋ ์๋ณธํจ์์์ ์ฌ์ฉ๋ ํ๋ผ๋ฉํฐ์ ํด๋น ํด๋์ค์ ๋ณ์๋ค์ ์ ๊ทผํ ์ ์์ต๋๋ค.
ํด๋น ํ๋ผ๋ฉํฐ์ ํจ์นํ ํด๋์ค์ ์ ๊ทผ์ ํ๊ธฐ์ํด์๋ ์๋์ ๊ฐ์ ๊ท์น๋ค์ ๋ฐ๋ผ์ผ ํฉ๋๋ค.
- ํจ์นํจ์๋
static
ํํ์ ํจ์์ฌ์ผ ํฉ๋๋ค. Prefix
์ ๋ฐํํ์void
๋๋bool
๋ง ๊ฐ๋ฅํฉ๋๋ค.Postfix
๋void
ํํ์ ๋ฐํ๋ง ๊ฐ๋ฅํฉ๋๋ค.- ํจ์นํ ํด๋์ค๊ฐ
static
ํํ๊ฐ ์๋๋ผ๋ฉด ํ๋ผ๋ฉํฐ๋ก__instance
๋ผ๋ ๋ณ์๋ช ์ ์ฌ์ฉํ์ ์ผ ํด๋น ์ธ์คํด์ค๊ฐ์ ์ก์ธ์ค ํ ์ ์์ต๋๋ค. ๊ตฌ์กฐ์ฒด์ ๊ฒฝ์ฐ ๊ฐ์ ๋ฌ์์์ ์ค๋ฒํค๋๋ฅผ ํผํ๊ธฐ ์ํดref
ํค์๋๋ฅผ ํตํด ์ ๋ฌ๋ฉ๋๋ค. - ๊ธฐ์กด ํจ์์ ๋ฐํ๊ฐ์ ์ ๊ทผํ๊ธฐ ์ํด์๋
ref
ํค์๋์__result
๋ฅผ ์ฌ์ฉ ํ์ ์ผ ํฉ๋๋ค.(ํด๋์ค ํ์ ์ด๋, ๊ตฌ์กฐ์ฒด๋) - ํจ์น ํจ์์ ํ๋ผ๋ฉํฐ๋ ๊ธฐ์กด ํจ์์ ํ๋ผ๋ฉํฐ๋ค์ ๋ชจ๋ ์ ์ธํ ํ์ ์์ต๋๋ค. (์ํด๋ ๊ด์ฐฎ์ต๋๋ค.)
- ๋ง์ฝ ๊ธฐ์กด ํจ์์ ํ๋ผ๋ฉํฐ์ ์ ๊ทผํ๊ธฐ ์ํด์๋ ํจ์น ํจ์์ ํ๋ผ๋ฉํฐ๋ช ๊ณผ ํ์ ์ ๋ฐ๋์ ๋์ผํ๊ฒ ํด์ฃผ์ ์ผ ํฉ๋๋ค.
- ํจ์น ํจ์๋ ํ๋ผ๋ฉํฐ๋ฅผ ๊ฐ์ ธ์ฌ๋ ์ผ๋ฐ ํน์
ref
ํ์์ ์ด์ฉํ ์ ์์ต๋๋ค. Transpilers์๋ 2๊ฐ์ง ์ ํ์ ๋งค๊ฐ ๋ณ์๊ฐ ์์ต๋๋ค. MethodBase
๋ ํจ์น๋ ๊ธฐ์กด์ ํจ์ ๊ทธ ์์ฒด์ ๋๋ค.IEnumerable<CodeInstruction>
๋ ๊ธฐ์กด ํจ์์์ ์คํ๋๋ ๋ด๋ถ ์ด์ ๋ธ๋ฆฌ ๋ช ๋ น์ด ์งํฉ์ ๋๋ค.
์ฌ์ฉ ์
๋ค์ ์์ ๋ค์ ํตํด ๊ฐ๊ฐ ํจ์น ํจ์๋ค์ด ์ด๋ค ๋ฐฉ์์ผ๋ก ์ฐ์ด๋์ง ์์๋ณผ ๊ฒ ์ ๋๋ค.
์์ ์์ ์ฌ์ฉ๋ ํด๋์ค๋ BiomeWorker_Desert
๋ก ์ธ๊ณ์ง๋์์ ์ฌ๋ง ์์์ ๋ํ ์ ๋ณด๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
์ฌ๊ธฐ์ BiomeWorker
์์ ์์๋ฐ์ GetScore
ํจ์๋ฅผ ํตํด ๊ฐ๊ฐ์ ๋ฐ์ด์ด๋ค์ ๊ฐ ํ์ผ๋ก๋ถํฐ ์์์ ๊ฒฐ์ ํ๊ฒ ๋ฉ๋๋ค.
์ด๊ฒ์ ๊ธฐ์กด ํจ์ ๋ฏธ์คํ, ํด๋ฐ๊ณ ๋ 600์ดํ 0์ด์, ๊ฐ์๋ 300์ดํ์ผ ์จ๋๋ 35๋ ์ด์์ผ๋๋ง ์์ฑ
๋๋๋ก ๋ณ๊ฒฝํ๊ณ ์ ํฉ๋๋ค.
๊ฐ๊ฐ์ ํจ์น ํํ๋ณ๋ก ์์ ๋ฅผ ๋ณด์ฌ๋๋ฆด๊ฒ ์
๋๋ค.
๊ธฐ์กด ํจ์
BiomeWorker_Desert
ํด๋์ค๋ Static ํด๋์ค๊ฐ ์๋๋๋ค. ์ฆ ๊ฐ๊ฐ์ ์ธ์คํด์ค๊ฐ ์กด์ฌํฉ๋๋ค. ๋ง์ฝBiomeWorker_Desert
์ ๋ฉค๋ฒ๋ณ์๋ฅผ ์ฌ์ฉํ ์ผ์ด ์๋ค๋ฉดBiomeWorker __instance
ํน์BiomeWorker_Desert __instance
๋ผ๋ ๋งค๊ฐ ๋ณ์๊ฐ ํ์ํฉ๋๋ค.[์ฌ๊ธฐ์ ์๋๋๋ค.]GetScore
ํจ์๋Tile
ํ์ ์ ํ๋ผ๋ฉํฐ๋ฅผ ๊ฐ์ง๊ณ ์๊ณ ๊ทธ ์ด๋ฆ์tile
์ ๋๋ค. ๋์ผํ๊ฒ ์์ฑํด์ฃผ์ด์ผ ํฉ๋๋ค.GetScore
ํจ์์ ๋ฐํํ์float
ํ์ ์ ๋๋ค. ๋ฐํ๊ฐ์ ์์ ์ง์ ํ๊ณ ์ ํ๋ค๋ฉดfloat __result
๋ฅผ ํฌํจํ์ ์ผ ํฉ๋๋ค.
//RimWorld.BiomeWorker_Desert
public class BiomeWorker_Desert : BiomeWorker
{
public override float GetScore(Tile tile)
{
if (tile.WaterCovered)//ํด๋ฐ ๊ณ ๋ 0์ดํ๋ฉด -100์
{
return -100f;
}
if (tile.rainfall >= 600f)//๊ฐ์๋์ด 600์ด์์ด๋ฉด 0์
{
return 0f;
}
return tile.temperature + 0.0001f; //์จ๋+0.0001์ ์ ๋ฐํ
}
}
Prefix
- ๊ธฐ์กด ํด๋์ค์์์ ๋ฉค๋ฒ๋ณ์๋ฅผ ์ฌ์ฉํ ํ์๊ฐ ์์์ผ๋ก
__instance
ํ๋ผ๋ฉํฐ๋ ์ ๊ฑฐ GetScore
์ ๋ฐํ๋๋float
ํ์ ์ ์ ์๋ก ๋ฐ์ด์ด์ด ์ฑ ์ ๋จ์ผ๋ก__result
์ ํฌํจTile tile
์ ๋ฉค๋ฒ๋ฅผ ์ ๊ทผํ์ฌ ์กฐ๊ฑด๊ฒ์ฌ๋ฅผ ํด์ผํจ์ผ๋ก ํฌํจ- ๊ธฐ์กด ํจ์๊ฐ ๋ฏธ์คํ ๋๊ธฐ ์ํจ์ผ๋ก boolํ์ ์ ํจ์๋ก ์์ฑํ return ๊ฐ์ false
[HarmonyPatch(typeof(BiomeWorker_Desert))]
[HarmonyPatch("GetScore")]
[HarmonyPatch(new Type[] { typeof(Tile) })]
internal class DesertBiome_Patch
{
static bool Prefix(ref float __result,Tile tile)
{
if ((tile.elevation>600)||(tile.elevation < 0))//ํด๋ฐ๊ณ ๋ 600์ด๊ณผ 0๋ฏธ๋ง
{
__result= - 100f;
return false;
}
if (tile.temperature <35 )//๊ฐ์๋์ด 600์ด์์ด๋ฉด 0์
{
__result= 0f;
return false;
}
__result= tile.temperature + 0.0001f; //์จ๋+0.0001์ ์ ๋ฐํ
return false;//false์์ผ๋ก ๊ธฐ๋ณธ ํจ์๋ ๋ฏธ์คํ๋จ.
}
}
Postfix
- ๊ธฐ์กด ํด๋์ค์์์ ๋ฉค๋ฒ๋ณ์๋ฅผ ์ฌ์ฉํ ํ์๊ฐ ์์์ผ๋ก
__instance
ํ๋ผ๋ฉํฐ๋ ์ ๊ฑฐ GetScore
์ ๋ฐํ๋๋float
ํ์ ์ ์ ์๋ก ๋ฐ์ด์ด์ด ์ฑ ์ ๋จ์ผ๋ก__result
์ ํฌํจTile tile
์ ๋ฉค๋ฒ๋ฅผ ์ ๊ทผํ์ฌ ์กฐ๊ฑด๊ฒ์ฌ๋ฅผ ํด์ผํจ์ผ๋ก ํฌํจ- ๊ธฐ์กด ํจ์์ ๋ฐํ๊ฐ์ ๋ฌด์ํ๊ณ ์๊ฐ์ ์ค์ ํด์ผํจ
[HarmonyPatch(typeof(BiomeWorker_Desert))]
[HarmonyPatch("GetScore")]
[HarmonyPatch(new Type[] { typeof(Tile) })]
internal class DesertBiome_Patch
{
static void Postfix(ref float __result,Tile tile)
{
__result= 0;
if ((tile.elevation>600)||(tile.elevation < 0))//ํด๋ฐ๊ณ ๋ 600์ด๊ณผ 0๋ฏธ๋ง
{
__result= - 100f;
}
if (tile.temperature <35 )//๊ฐ์๋์ด 600์ด์์ด๋ฉด 0์
{
__result= 0f;
}
__result= tile.temperature + 0.0001f; //์จ๋+0.0001์ ์ ๋ฐํ
}
}
TransPiler
TransPiler๋ฅผ ํตํด C#๋ฅผ ๋น๋ํ๋ฉด ๋ง๋ค์ด์ง๋ ์ค๊ฐ์ฝ๋๋ฅผ ์์ ํ ์ ์์ต๋๋ค. prefix๋ฅผ ํตํด ํต์งธ๋ก ์ฝ๋๋ฅผ ๊ฐ๋ก์ฑ๊ฑฐ๋ ๋๋ ํ์์ ๋ถ์ฌ์ ์์ ํ ์ ์๋ค๋ฉด TransPiler๋ฅผ ํตํด ๊ธฐ์กด์ ์ฝ๋๋ฅผ ์์ ํ ์ ์์ต๋๋ค.
OpCodes
๊ธฐ์กด BiomeWorker_Desert
์ IL์ฝ๋
.class public auto ansi beforefieldinit RimWorld.BiomeWorker_Desert
extends RimWorld.BiomeWorker
{
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0xb3744
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void RimWorld.BiomeWorker::.ctor()
IL_0006: ret
} // end of method BiomeWorker_Desert::.ctor
//์ฌ๊ธฐ์๋ถํฐ GetScore ์ด์
๋ธ๋ฆฌ ๋ช
๋ น์ด์
๋๋ค.
.method public hidebysig virtual
instance float32 GetScore (
class RimWorld.Planet.Tile tile
) cil managed
{
// Method begins at RVA 0xb374c
// Code size 52 (0x34)
.maxstack 8
IL_0000: ldarg.1 //์ฒซ๋ฒ์งธ ์ธ์๋ฅผ ๊ณ์ฐ ์คํ์ ์ ์ฌ
IL_0001: callvirt instance bool RimWorld.Planet.Tile::get_WaterCovered()//waterCovered๊ฐ์ ๊ณ์ฐ์คํ์ผ๋ก ํธ์ฌ
IL_0006: brfalse IL_0011//๊ฒฐ๊ณผ๊ฐ์ด flase๋ฉด IL_0011๋ก ์ด๋
IL_000b: ldc.r4 -100 //๊ณ์ฐ์คํ์ -100์ floatํํ๋ก ํธ์ฌ
IL_0010: ret//ํ ๋งค์๋ ์ ์ด๋ฅผ ๋ฐํํ๊ณ ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ฉ์๋์ ๊ณ์ฐ์คํ์ผ๋ก ๊ฒฐ๊ณผ๊ฐ ํธ์ฌ
IL_0011: ldarg.1//์ฒซ๋ฒ์งธ ์ธ์๋ฅผ ๊ณ์ฐ ์คํ์ ์ ์ฌ
IL_0012: ldfld float32 RimWorld.Planet.Tile::rainfall //๊ณ์ฐ ์คํ์ tile.rainfall ๊ฐ์ ๊ฐ์ ธ์ด
IL_0017: ldc.r4 600 //๋ค์ ๊ณ์ฐ ์คํ์ 600fํธ์ฌ
IL_001c: blt.un IL_0027 //๊ณ์ฐ์คํ์ ์ฒซ๋ฒ์งธ๊ฐ๊ณผ ๋๋ฒ์งธ๊ฐ์ ๋น๊ตํ false์ผ๊ฒฝ์ฐ IL_0027๋ก ์ด๋
IL_0021: ldc.r4 0.0 // ๊ณ์ฐ ์คํ์ 0.0f๊ฐ์ ํธ์ฌ
IL_0026: ret//ํ ๋งค์๋ ์ ์ด๋ฅผ ๋ฐํํ๊ณ ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ฉ์๋์ ๊ณ์ฐ์คํ์ผ๋ก ๊ฒฐ๊ณผ๊ฐ ํธ์ฌ
IL_0027: ldarg.1//์ฒซ๋ฒ์งธ ์ธ์๋ฅผ ๊ณ์ฐ ์คํ์ ์ ์ฌ
IL_0028: ldfld float32 RimWorld.Planet.Tile::temperature//tile.temperature๊ฐ์ ๊ฐ์ ธ์ด
IL_002d: ldc.r4 0.0001//๊ณ์ฐ ์คํ์ 0.0001fํธ์ฌ
IL_0032: add//๊ณ์ฐ ์คํ ์์ ๋๊ฐ์ ํฉ์ฐ ํ ๊ณ์ฐ์คํ์ ํธ์ฌ
IL_0033: ret//ํ ๋งค์๋ ์ ์ด๋ฅผ ๋ฐํํ๊ณ ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ ๋ฉ์๋์ ๊ณ์ฐ์คํ์ผ๋ก ๊ฒฐ๊ณผ๊ฐ ํธ์ฌ
} // end of method BiomeWorker_Desert::GetScore
} // end of class RimWorld.BiomeWorker_Desert
์ฅํฉํ๊ฒ ์ด์ ๋ธ๋ฆฌ์ด๋ก ์์ฑ๋์์ง๋ง ๋จ์ํ๊ฒ ์์ฝํ๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๋งค If๋ฌธ ๋ถ๊ธฐ๋ง๋ค ์คํ๋ฉ๋ชจ๋ฆฌ์ ๋น๊ต๊ฒ์ฌํ ๊ฐ๋ค์ ์ ์ฌํ๊ณ ๋น๊ต๊ฒ์ฌํ ๊ฑด๋๋
- ret ๋ช
๋ น์ด๋ฅผ ํตํด ํ์ฌํจ์๋ฅผ ์ข
๋ฃํ๊ณ ์ต์์์ ์ ์ฌ๋ ๊ฒฐ๊ณผ๊ฐ์ ํด๋น
GetScore
ํจ์๋ฅผ ๋ถ๋ฌ์จ ๋ค๋ฅธํจ์ ์คํ์ต์์์ ์ ์ฌ.
๋ฐ๋ผ์ TransPiler๋ IL_0000๋ถํฐ IL_0033์ 16๊ฐ์ ๋ช
๋ น์ด ์งํฉ์ผ๋ก ์ด๋ฃจ์ด์ ธ ์์ต๋๋ค.
์ด๊ฒ์ ์ ๋ถ ์ง์ฐ๊ณ ์๋ก์ด ๋ช
๋ น์ด ์งํฉ์ ๋ฃ์ผ์
๋ ๋๊ณ ๋ถ๋ถ์ ์ผ๋ก ๋ช
๋ น์ด ๋ถ๊ธฐ๋ฅผ ์๋ก ๋ง๋ค์ด ์ฃผ์
๋ ๋ฉ๋๋ค.
์ด์ ์๋์ ๊ธฐ์กด ํจ์๋ฅผ IL์ ์ด์ฉํด ๋ชจ๋ ์งํ์ด ์ฌ๋ง์ด ๋๋๋ก ๋ฐ๊ฟ๋ณด๊ฒ ์ต๋๋ค.
[HarmonyPatch(typeof(BiomeWorker_Desert))]
[HarmonyPatch("GetScore")]
public static class DesertBiome_Patch
{
static IEnumerable<CodeInstruction> Transpiler(MethodBase original, IEnumerable<CodeInstruction> instructions)
{
yield return new CodeInstruction(OpCodes.Ldc_R4, 10000f);//์คํ ์ต์๋จ์ 10000f ํธ์ฌ
yield return new CodeInstruction(OpCodes.Ret);//์ ์ด๋ฐํํ 10000f๋ฅผ ํธ์ถํจ์ ์คํ์ต์๋จ์ ํธ์ฌ
}
}
์์ ๊ฐ์ด ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋์ต๋๋ค.
๋ค์ : ๋์ํจ์ ์ง์