Journey to the West

Journey to the West

Not enough ratings
神州志西游Mod制作
By jim97
通过Harmony制作神州志西游的mod
   
Award
Favorite
Favorited
Unfavorite
第一部分 :游戏程序集公共化
  • 所需插件: NStrip [github.com]
  • 使用方式:拖拽游戏目录下的Assembly-CSharp.dll程序集到NStrip.exe上,在目录下自动生成Assembly-CSharp-nstrip.dll

第二部分:创建Mod程序
  1. 使用Visual Studio 2022新建一个类库项目
  2. 引用之前用NStrip公开的程序集Assembly-CSharp-nstrip.dll
  3. 创建一个继承游戏mod支持的类型
    public class ScriptTrainer: ModComponent { public static ScriptTrainer Instance; public void Awake() { Instance = this; #region[注入游戏补丁] var harmony = new Harmony("ScriptTrainer"); harmony.PatchAll(); #endregion } public void Start() { } public void Update() { if (Input.GetKeyDown(KeyCode.F9)) { var player = Game.Get().GetPlayer(); if (player != null) player.Gold += 10000; } } public void FixedUpdate() { } public void OnDestroy() { } } }
    注:Update()函数是在游戏的每一帧都会执行
    示例中通过if (Input.GetKeyDown(KeyCode.F9))来检测游戏中是否按下F9的按键来给玩家增加金钱

  4. 游戏中常用的类型和命令
    //玩家角色 Player player = Game.Get().GetPlayer(); //与前端显示连接的类型,卡片添加,卡牌修改等都需要用到 EngineWrapper engineWrapper = EngineWrapper.Get(); //获取当前角色可以得到的卡池 Dictionary<string, Card> cards = Game.Get().GetPlayer().CardPool.GetCards(); //获取全部通用卡牌 List<Card> cards = new CardSetNeutral().Cards; //获取玩家背包所有的卡牌 List<Card> cards = Game.Get().GetPlayer().Deck.GetCards() //通过ID获取游戏内的翻译 EngineWrapper.Get().GetLocalizedString("Merchant/IDS_TEXT_REMOVE_1_CARD") //创建一个卡牌选择的界面 EngineWrapper.Get().PickCards(cards, 10, “界面名称”, cardSelectedCallback, callbackOnSkip, constraint, false); cards是选择界面所显示的卡牌 10是最多可以选择的卡牌数量 cardSelectedCallback是选择卡牌后所执行的函数 callbackOnSkip是跳过选择后执行的函数 constraint是对卡牌进行筛选,确定哪些卡牌可以被选择 //示例:移除玩家背包中的卡牌 CardsCallback cardSelectedCallback = delegate (List<Card> picked) { if (picked.Count == 0) { return; } foreach (Card card in picked) { Game.Get().GetPlayer().Deck.RemoveCard(card); } EngineWrapper.Get().RemoveCards(picked, delegate () { }, false, 0.6f); }; EngineWrapper.Get().PickCards(Game.Get().GetPlayer().Deck.GetCards(), 10, EngineWrapper.Get().GetLocalizedString("Merchant/IDS_TEXT_REMOVE_1_CARD"), cardSelectedCallback, null, null, false); //示例2:升级玩家背包中的卡牌 CardsCallback cardSelectedCallback = delegate (List<Card> picked) { if (picked.Count == 0) { return; } EngineWrapper.Get().CreateAndUpgradeCards(picked, CardModifier.ValidLength.PERMANENT, null, null); }; EngineWrapper.Get().PickCardsFromDeckForUpgrade(10, EngineWrapper.Get().GetLocalizedString("Camp/IDS_TEXT_UPGRADE_1_CARD"), cardSelectedCallback, null, false); //获取当前角色可以得到的遗物 Dictionary<string, Relic> relics = Game.Get().GetPlayer().RelicPool.GetRelics(); //添加遗物到玩家 Game.Get().GetPlayer().AddRelic(item, null);
第三部分:Harmony的基本用法
  1. 在mod主程序的Awake中要对本mod命名空间下的所以补丁进行调用
    Harmony harmony = new Harmony(PLUGIN_GUID); harmony.PatchAll();
  2. 前补丁
    //Prefix 前补丁,在补丁的函数前执行 //RecyclingWells为类型名称,OnNetworkSpawn为函数名称 //__instance,当前注入类型入口 //__result,当前函数的返回值 //__runOriginal,如果设置为 false,则不运行原始方法代码。 //__<idx>,例如__0 函数的输入变量 [HarmonyPatch(typeof(RecyclingWells), "OnNetworkSpawn")] public class RecyclingWellsOverridePatch_OnNetworkSpawn { [HarmonyPrefix] public static bool Prefix(RecyclingWells __instance, ref int __result) { __result = 10; return false; } }
  3. 后补丁
    //Postfix后补丁,在函数执行后执行 [HarmonyPatch(typeof(Test), "Updata")] public class TestOverridePatch_Updata { [HarmonyPostfix] public static void Postfix(ref int __result) { __result \= 2; } }
  4. 多个同名函数的补丁制作
    //[HarmonyPatch(typeof(HexMapManager), "GenerateNewMap", new Type[] { typeof(Sector) })] //在HexMapManager类里有多个名为GenerateNewMap的函数时,HarmonyPatch的第三个参数是函数输入变量的类型,第四个参数是函数out输出变量的类型
  5. 可读写属性补丁制作
    //[HarmonyPatch(typeof(MinigameChest), "Price", MethodType.Getter)] //[HarmonyPatch(typeof(MinigameChest), "Price", MethodType.Setter)]
  6. 成员修改
    //Traverse.Create(__instance).Field("initialNumberOfUses").GetValue<T>(); //Traverse.Create(__instance).Field("initialNumberOfUses").SetValue(99); //initialNumberOfUses 是成员名称, T为该成员类型
  7. 多个函数用一个补丁
    [HarmonyPatch] public class BasicVehiclePatch { public static float DurabilityCostFloat = 0f; public static float Durability = 0f; public static float Energy = 0f; public static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(BasicVehicle), "OnPlayerEnterRange"); yield return AccessTools.Method(typeof(BasicVehicle), "GetInVehicle"); yield return AccessTools.Method(typeof(BasicVehicle), "OnPlayerGetOutVehicle"); yield return AccessTools.Method(typeof(BasicVehicle), "OnPlayerExitRange"); yield return AccessTools.Method(typeof(BasicVehicle), "Fire_EnergyWeapon"); } [HarmonyPrefix] public static void Prefix(ref BasicVehicle __instance, MethodBase __originalMethod) { } [HarmonyPostfix] public static void Postfix(ref BasicVehicle __instance) { } }
第四部分:上传MOD
  1. 通过VS的项目生成DLL文件
  2. 在任意位置创建Mod文件夹
    Mod ----mod.json ----Data --------DLLs ------------MyMod.dll
    其中mod.json的内容为
    { "DLLs":["Data/DLLs/MyMod.dll"], }
  3. 通过制作组的创意工坊上传软件[github.com]对Mod文件夹上传