ROOT
: 挂端主檔案夾
1x001 建立主包和主類
在
ROOT/src/minecraft
下建立新包,名字叫
me.hack.hackedclient
。如果沒有建立包的選項,就右鍵
ROOT/src/minecraft
檔案夾,選擇
Mark Directory as
-
Sources root
就可以了。 在主包内建立一個新的類,叫
HackedClient
。
.java
的檔案字尾會自動加! 同時,在主包下面建立一個新的包,叫
module
,這裡面将會存放所有的子產品和子產品管理器。在
module
裡建立兩個類,
Module
和
ModuleManager
。
Module
是所有子產品的模版,
ModuleManager
則是子產品管理器。最後,在
module
裡建立一個enum類,叫
Category
。
1x002 Category.java
package me.hack.hackedclient.module;
public enum Category {
COMBAT, MOVEMENT, PLAYER, RENDER, MISC
}
這個類就是一個子產品可能的分類,所有的子產品都會被分到這5個類裡面。
1x003 Module.java
package me.hack.hackedclient.module;
import net.minecraft.client.Minecraft;
public class Module {
protected Minecraft mc = Minecraft.getMinecraft();
private String name;
private int key;
private boolean toggled;
private Category category;
public Module(String nm, int k, Category c) {
name = nm;
key = k;
category = c;
toggled = false;
}
public void toggle() {
toggled = !toggled;
if(toggled) {
onEnable();
} else {
onDisable();
}
}
public void onEnable() {}
public void onDisable() {}
public void onUpdate() {}
public void onRender() {}
public Minecraft getMc() {
return mc;
}
public void setMc(Minecraft mc) {
this.mc = mc;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getKey() {
return key;
}
public void setKey(int key) {
this.key = key;
}
public boolean isToggled() {
return toggled;
}
public void setToggled(boolean toggled) {
this.toggled = toggled;
}
}
這個類是所有子產品的模版,其中
onEnable
,
onDisable
,
onUpdate
,和
onRender
是空的,因為子產品會override。
1x004 HackedClient.java
package me.hack.hackedclient;
import org.lwjgl.opengl.Display;
import me.hack.hackedclient.module.ModuleManager;
public class HackedClient {
public static String name = "Hacked Client", version = "1.0.0", creator = "me";
public static ModuleManager moduleManager;
public static void startClient() {
moduleManager = new ModuleManager();
Display.setTitle(name + " " + version + " by " + creator);
}
}
挂端的主類,用于将外挂注入到原我的世界中。
1x005 ModuleManager.java
package me.hack.hackedclient.module;
import java.util.ArrayList;
public class ModuleManager {
private static ArrayList<Module> mods;
public ModuleManager() {
mods = new ArrayList<Module>();
// COMBAT
// MOVEMENT
// PLAYER
// RENDER
// MISC
}
public static void newMod(Module m) {
mods.add(m);
}
public static ArrayList<Module> getModules() {
return mods;
}
public static void onUpdate() {
for(Module m : mods) {
m.onUpdate();
}
}
public static void onRender() {
for(Module m : mods) {
m.onRender();
}
}
public static void onKey(int k) {
for(Module m : mods) {
if(m.getKey() == k) {
m.toggle();
}
}
}
}
這個類是子產品控制器,所有的子產品都會在這裡被注冊。
1x006 注入
現在,我們會把我們挂端需要執行的代碼混到我的世界的源代碼裡面。
首先,輕按兩下RShift,打開
Minecraft.java
。然後,Ctrl+F搜尋
ingameGUI
,直到這行代碼:
...
this.ingameGUI = new GuiIngame(this);
...
在這行代碼下面添加:
// Hacked Client
HackedClient.startClient();
然後導入這個類。我建議你們在動我的世界源代碼的時候寫上注釋,這樣才能知道那些事我的世界的源代碼,那些是你後來加進去的。
往下翻,直到這裡:
...
private void createDisplay() throws LWJGLException
{
Display.setResizable(true);
Display.setTitle("Minecraft 1.8.8");
...
修改為:
...
private void createDisplay() throws LWJGLException
{
Display.setResizable(true);
Display.setTitle("Loading Hacked Client");
...
随後,還是在
Minecraft.java
裡,搜尋
k == 1
,直到這裡:
...
if (this.currentScreen != null)
{
this.currentScreen.handleKeyboardInput();
}
else
{
if(k == 1)
{
this.displayInGameMenu();
}
...
修改為:
...
if (this.currentScreen != null)
{
this.currentScreen.handleKeyboardInput();
}
else
{
// Hacked Client
HackedClient.moduleManager.onKey(k);
if(k == 1)
{
this.displayInGameMenu();
}
...
輕按兩下RShift,搜尋
EntityPlayerSP
,打開檔案後Ctrl+F搜尋
onLivingUpdate
,直到這裡:
...
public void onLivingUpdate()
{
if (this.sprintingTicksLeft > 0)
{
--this.sprintingTicksLeft;
...
修改為:
...
public void onLivingUpdate()
{
// Hacked Client
HackedClient.moduleManager.onUpdate();
if (this.sprintingTicksLeft > 0)
{
--this.sprintingTicksLeft;
...
輕按兩下RShift,搜尋
EntityRenderer
,打開後搜尋
"hand"
,直到這附近:
...
this.mc.mcProfiler.endStartSection("hand");
boolean flag3 = Reflector.callBoolean(Reflector.ForgeHooksClient_renderFirstPersonHand, new Object[] {this.mc.renderGlobal, Float.valueOf(partialTicks), Integer.valueOf(pass)});
...
修改為:
...
this.mc.mcProfiler.endStartSection("hand");
// Hacked Client
HackedClient.moduleManager.onRender();
boolean flag3 = Reflector.callBoolean(Reflector.ForgeHooksClient_renderFirstPersonHand, new Object[] {this.mc.renderGlobal, Float.valueOf(partialTicks), Integer.valueOf(pass)});
...
然後,你就可以開始寫子產品了!
1x007 第一個子產品 - AutoSprint
在
me.hack.hackedclient.module
中建立一個包,叫
movement
,所有移動類的子產品都會被存放在這裡。在這個包下建立一個類,叫
AutoSprint
,在裡面寫:
package me.hack.hackedclient.module.movement;
import me.hack.hackedclient.module.Category;
import me.hack.hackedclient.module.Module;
import org.lwjgl.input.Keyboard;
public class AutoSprint extends Module {
public AutoSprint() {
super("AutoSprint", Keyboard.KEY_F, Category.MOVEMENT);
}
@Override
public void onUpdate() {
if(this.isToggled()) {
if(!mc.thePlayer.isCollidedHorizontally && mc.thePlayer.moveForward > 0 && !mc.thePlayer.isSneaking()) {
mc.thePlayer.setSprinting(true);
}
}
super.onUpdate();
}
}
随後,把
ModuleManager
的構造器更改為:
public ModuleManager() {
mods = new ArrayList<Module>();
// COMBAT
// MOVEMENT
newMod(new AutoSprint());
// PLAYER
// RENDER
// MISC
}
并在
import
部分添加:
1x008 測試
現在,打開指令行,
cd
到
ROOT
,然後運作
recompile.bat
來重新編譯我的世界。編譯完成後,運作
startclient.bat
來啟動新的我的世界。如果沒錯的話,現在進入一個世界後按F,那麼你前進的時候将會自動跑步。至此,我們已經完成了第一個子產品!
— 完 —
如果大家遇到任何問題可以發在評論區,我會盡快回複!