Harmony를 시작하기 전에 - solaris0115/RimWorldModGuide GitHub Wiki
Harmony(이하 하모니)는 런타임 중 .Net
메서드를 접근, 제어 하기 위한 라이브러리입니다.
하모니는 다음과 같은 기능들을 제공합니다.
- 기존의 코드를 유지한 채 아래의 기능들 수행
- 해당 기능 전후에 추가 기능 실행
- 기존 기능 수정[IL]
- 하나의 개체에 하모니를 통한 복수의 접근, 제어시 충돌 방지.
하모니는 .Net 2.0
이상부터 작동 가능하도록 설계되어 있습니다. 림월드에 쓰인 Unity 버전은 `.Net 3.5'를 지원함으로 큰 문제가 없을 것입니다. 그외 다른 의존성은 없으며 비슷한 타게임의 개발 환경에서도 작동할 가능성이 있습니다.
하모니는 기본적으로 PC, Mac, Linux에서 테스트 되었으며 32/64 bit 모두 지원합니다.
일반적 Unity 개발 환경에서는 단순히 하모니 dll을 포함하시기만 하면 됩니다.
모든 버전에서 .Net Core
에 대한 지원을 할 예정이며 현재 테스트 중 입니다.
프로젝트 내에 하모니dll을 추가하고 이후 ILMerge
와 같은 도구로 어셈블리 출력물에 합치세요.
하모니 라이브러리의 이름은 0Harmony.dll
입니다.
게임 시작시 나오는 메인화면[행성]을 하모니를 통해 교체하는 예제입니다.
아래는 림월드 메인 배경을 그리는 기존의 코드입니다.
namespace RimWorld
{
[StaticConstructorOnStartup]
public class UI_BackgroundMain : UIMenuBackground
{
private static readonly Vector2 BGPlanetSize = new Vector2(2048f, 1280f);
private static readonly Texture2D BGPlanet = ContentFinder<Texture2D>.Get("UI/HeroArt/BGPlanet", true);
public override void BackgroundOnGUI()
{
//원본배경의 크기를 잰뒤 현재 화면에 맞춰준다.
bool flag = true;
if ((float)UI.screenWidth > (float)UI.screenHeight * (UI_BackgroundMain.BGPlanetSize.x / UI_BackgroundMain.BGPlanetSize.y))
{
flag = false;
}
Rect position;
if (flag)
{
float height = (float)UI.screenHeight;
float num = (float)UI.screenHeight * (UI_BackgroundMain.BGPlanetSize.x / UI_BackgroundMain.BGPlanetSize.y);
position = new Rect((float)(UI.screenWidth / 2) - num / 2f, 0f, num, height);
}
else
{
float width = (float)UI.screenWidth;
float num2 = (float)UI.screenWidth * (UI_BackgroundMain.BGPlanetSize.y / UI_BackgroundMain.BGPlanetSize.x);
position = new Rect(0f, (float)(UI.screenHeight / 2) - num2 / 2f, width, num2);
}
//현재의 화면에 그림을 그려준다.(가로를 기준으로 세로비율을 맞춘다.)
GUI.DrawTexture(position, UI_BackgroundMain.BGPlanet, ScaleMode.ScaleToFit);
}
}
}
아래는 하모니를 통해 사용자 지정 메인화면을 만드는 코드 입니다.
using Harmony;
using RimWorld;
using System.Reflection;
using UnityEngine;
using Verse;
using System;
namespace Solaris
{
[StaticConstructorOnStartup]
internal static class Solaris
{
static Solaris()
{
HarmonyInstance harmonyInstance = HarmonyInstance.Create("com.Solaris.rimworld.mod");
harmonyInstance.PatchAll(Assembly.GetExecutingAssembly());
}
}
[HarmonyPatch(typeof(UI_BackgroundMain)), HarmonyPatch("BackgroundOnGUI")]
internal class BackGroundChanger
{
//본 모드의 사용자 지정 주소로 변경
static readonly Texture2D CustomBackground = ContentFinder<Texture2D>.Get("UI/Icons/Background", true);
internal static readonly Vector2 MainBackgroundSize = new Vector2(CustomBackground.width, CustomBackground.height);
static bool Prefix()
{
if (CustomBackground != null)
{
float width = (float)UI.screenWidth;
float num = (float)UI.screenWidth * (MainBackgroundSize.y / MainBackgroundSize.x);
GUI.DrawTexture(new Rect(0f, (float)UI.screenHeight / 2f - num / 2f, width, num), CustomBackground, ScaleMode.ScaleToFit, true);
}
//false일경우 기존의 코드 미실행.
//true면 실행[true일경우 prefix의 사용자 지정 배경이 그려진 뒤 기존의 그림이 그려짐으로 기존의 그림이 나옴.
return false;
}
}
}
이후 해당 모드폴더에 Textures/UI/Icons/Background.png
의 사용자 지정 메인화면을 넣으면 됩니다.
위 코드는 하모니의 Prefix를 이용해 만들어졌습니다.
기존의 코드인 UI_BackgroundMain.BackgroundOnGUI()
가 실행되기 전
새로만든 코드가 먼저 동작하고 이후 기존의 코드는 동작하지 않는 방식입니다.
물론 이것외 Postfix, transpiler
를 통해 동일한 기능을 만들 수 있습니다.
이로써 간단하게 하모니가 무엇을 하는지 알아 보았습니다.
하모니에 대한 자세한 내용은 다음 문서를 참고하세요.
다음: Bootstrapping