今日目標要把剩下的處理完,讓我們繼續下去吧,加油!
我們先處理[Day9]的部分。先將[Day6]的PigDoll
移除,因為這個算是半成品;再來我們將PigDoll_v2
這個類別移動到com.ithome.mymod.events
下,並且重新命名為PigDoll
:
進入到PigDoll
這個檔案,內容可以參考[Day9],我們這邊需要把自行處理Prxoy的部分移除(就是所有的@SideOnly(Side.CLIENT)
都拿掉):
移除後的PigDoll
長這樣
package com.ithome.mymod.events;
import com.ithome.mymod.entities.EntityScalePig;
import com.ithome.mymod.entities.RenderScalePig;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.ModelPig;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.entity.passive.EntityPig;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.client.event.RenderLivingEvent;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.LivingDropsEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class PigDoll {
private float scale = 1.0f;
private AtomicInteger count = new AtomicInteger(0);
private AtomicBoolean flag = new AtomicBoolean(false);
private List<String> firstRenderPig = new ArrayList<String>();
@SubscribeEvent
public void preRender(RenderLivingEvent.Pre event) {
if (event.entity.getCustomNameTag().startsWith("myPig")) {
String tag = event.entity.getCustomNameTag();
float parserScale = Float.parseFloat(tag.split("-")[1]);
if (flag.compareAndSet(false, true)) {
Minecraft.getMinecraft().getRenderManager().entityRenderMap.put(EntityScalePig.class,
new RenderScalePig(Minecraft.getMinecraft().getRenderManager(), new ModelPig(), 0.5f * parserScale));
}
if(event.renderer instanceof RenderScalePig) {
RenderScalePig render = (RenderScalePig) event.renderer;
render.setScale(parserScale);
}
if(!firstRenderPig.contains(tag)) {
EntityScalePig pig = (EntityScalePig) event.entity;
pig.scale(parserScale);
firstRenderPig.add(tag);
}
}
}
@SubscribeEvent
public void pigDoll(EntityJoinWorldEvent event) {
if (event.entity.worldObj.isRemote) return;
if (event.world.playerEntities.isEmpty()) return;
EntityPlayer player = (EntityPlayer) event.entity.worldObj.playerEntities.get(0);
float distance = event.entity.getDistanceToEntity(player);
if (distance < 7.0f) {
if (EntityPig.class.isAssignableFrom(event.entity.getClass())) {
if(!event.entity.getCustomNameTag().startsWith("myPig")) {
event.entity.setDead();
}
if(count.compareAndSet(5, 0)) {
scale = 1.0f;
firstRenderPig.clear();
return;
}
scale = scale * 0.8f;
EntityScalePig pig = new EntityScalePig(event.entity.worldObj);
pig.setPosition(event.entity.posX - 1.2f, event.entity.posY, event.entity.posZ);
pig.setCustomNameTag(String.format("myPig-%f", scale));
// 將豬的AI行為去除
EntityAIBase ai = new EntityAIBase() {
@Override
public boolean shouldExecute() {
return true;
}
};
ai.setMutexBits(0xFFFFFF);
pig.tasks.addTask(0, ai);
count.getAndIncrement();
event.entity.worldObj.spawnEntityInWorld(pig);
}
}
}
}
然後把註冊動作放到ClientProxy
的init()
內:
MinecraftForge.EVENT_BUS.register(new PigDoll());
最後,註冊我們EntityScalePig
的動作是Client與Server都需要的(因為他們都會用到這個實體),在Proxy
的概念下,如果不需要去關心是屬於Client或Server,就放在主程式內。因此我們把註冊EntityScalePig
實體的動作放到MyMod
的preInit()
內:
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
int availableId = 1;
while (EntityList.getClassFromID(availableId) != null) {
availableId++;
}
EntityRegistry.registerGlobalEntityID(EntityScalePig.class, EntityScalePig.name, availableId);
proxy.preInit(event);
}
[Da11]是指令部分,所以我們再建立一個叫做com.ithome.mymod.commands
的套件目錄,並且將BurningPigs
移動到這個套件內。
由於指令需要註冊到FMLServerStartingEvent
這個事件內,我們先回到IProxy
介面定義方法,然後將指令註冊放到ServerProxy
內(因為這個事件是Server端的)。注意:雖然ClientProxy
不會用到這個事件,但還是需要定義!
IProxy
package com.ithome.mymod.proxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
public interface IProxy {
/**
* 準備Minecraft的所有物體。舉凡讀取設定檔、建立方塊、物品,註冊物體到Minecraft等。
*
* @param event 事件
*/
void preInit(FMLPreInitializationEvent event);
/**
* 模組設置。例如註冊事件處理、註冊資源、建立配方(合成、燒煉與釀造)。
*
* @param event 事件
*/
void init(FMLInitializationEvent event);
/**
* 與其他模組互動。如果有任何其他需要處理的的功能,或是要建立與其他模組的相依關係。
*
* @param event 事件
*/
void postInit(FMLPostInitializationEvent event);
/**
* 註冊伺服器指令的地方,這個事件只會被Server呼叫。
*
* @param event 事件
*/
void serverStarting(FMLServerStartingEvent event);
}
ClientProxy
package com.ithome.mymod.proxy;
import com.ithome.mymod.commands.Colosseum;
import com.ithome.mymod.events.*;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
public class ClientProxy implements IProxy {
@Override
public void preInit(FMLPreInitializationEvent event) {
}
@Override
public void init(FMLInitializationEvent event) {
MinecraftForge.EVENT_BUS.register(new BlockBreakEvent());
MinecraftForge.EVENT_BUS.register(new TNTExplosions());
MinecraftForge.EVENT_BUS.register(new PigDroppingItems());
MinecraftForge.EVENT_BUS.register(new ZombieKnights());
MinecraftForge.EVENT_BUS.register(new SuperJump());
MinecraftForge.EVENT_BUS.register(new PigDoll());
FMLCommonHandler.instance().bus().register(new SuperJump());
}
@Override
public void postInit(FMLPostInitializationEvent event) {
}
@Override
public void serverStarting(FMLServerStartingEvent event) {
// 這個事件不應該不呼叫
}
}
ServerProxy
package com.ithome.mymod.proxy;
import com.ithome.mymod.commands.BurningPigs;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
public class ServerProxy implements IProxy {
@Override
public void preInit(FMLPreInitializationEvent event) {
}
@Override
public void init(FMLInitializationEvent event) {
}
@Override
public void postInit(FMLPostInitializationEvent event) {
}
@Override
public void serverStarting(FMLServerStartingEvent event) {
event.registerServerCommand(new BurningPigs());
}
}
最後,我們需要在MyMod
檔案內把這個新的事件FMLServerStartingEvent
加上,並標註@EventHandler
:
MyMod
package com.ithome.mymod;
import com.ithome.mymod.configs.Constants;
import com.ithome.mymod.entities.EntityScalePig;
import com.ithome.mymod.proxy.IProxy;
import net.minecraft.entity.EntityList;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.registry.EntityRegistry;
@Mod(modid = Constants.MOD_ID, name = Constants.MOD_NAME, version = Constants.VERSION)
public class MyMod {
@SidedProxy(serverSide = Constants.SERVER_PROXY, clientSide = Constants.CLIENT_PROXY)
public static IProxy proxy;
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
int availableId = 1;
while (EntityList.getClassFromID(availableId) != null) {
availableId++;
}
EntityRegistry.registerGlobalEntityID(EntityScalePig.class, EntityScalePig.name, availableId);
proxy.preInit(event);
}
@EventHandler
public void init(FMLInitializationEvent event) {
proxy.init(event);
}
@EventHandler
public void postInit(FMLPostInitializationEvent event) {
proxy.postInit(event);
}
@EventHandler
public void serverStarting(FMLServerStartingEvent event)
{
proxy.serverStarting(event);
}
}
[Day12]到[Day13]一樣是使用指令,同前一個步驟,所以這裡只將有變更的地方放上來:
ClientProxy的init()方法:
MinecraftForge.EVENT_BUS.register(new Colosseum());
ServerProxy的serverStarting()方法:
event.registerServerCommand(new ColosseumFillCommand());
[Day14]到[Day17]是新的物品與方塊,這個是屬於註冊物體的工作,會放在preInit()
方法內。因為註冊物品與Client或Server端無關,我們一樣直接放到MyMod
內就好:
MyMod
// 自定義的方塊
public static Block enderBlock;
// 自定義的物品
public static Item pillItem;
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
int availableId = 1;
while (EntityList.getClassFromID(availableId) != null) {
availableId++;
}
EntityRegistry.registerGlobalEntityID(EntityScalePig.class, EntityScalePig.name, availableId);
enderBlock = new EnderBlock();
GameRegistry.registerBlock(enderBlock, "enderBlock");
pillItem = new PillItem();
GameRegistry.registerItem(pillItem, "pillItem");
proxy.preInit(event);
}
@EventHandler
public void init(FMLInitializationEvent event) {
// 從方塊轉換成物品的方法
Item item = Item.getItemFromBlock(enderBlock);
// 定義方塊資源目錄
// 第一個參數是"{模組ID}:方塊註冊名稱"
// 第二個參數請使用"inventory",表示從資源庫內尋找
ModelResourceLocation location = new ModelResourceLocation(
"myfancymods:enderBlock",
"inventory"
);
// 註冊這個方塊物品的資源到Forge內
Minecraft.getMinecraft().getRenderItem().getItemModelMesher()
.register(item, 0, location);
// 註冊藥丸物品的資源到Forge內
Minecraft.getMinecraft().getRenderItem().getItemModelMesher()
.register(pillItem, 0, new ModelResourceLocation(
"myfancymods:pillItem",
"inventory"
));
proxy.init(event);
}
最後在[Day18]到[Day19],是屬於配方註冊。直接就想到將這部分的邏輯放到MyMod
底下:
MyMod
@EventHandler
public void init(FMLInitializationEvent event) {
// 從方塊轉換成物品的方法
Item item = Item.getItemFromBlock(enderBlock);
// 定義方塊資源目錄
// 第一個參數是"{模組ID}:方塊註冊名稱"
// 第二個參數請使用"inventory",表示從資源庫內尋找
ModelResourceLocation location = new ModelResourceLocation(
"myfancymods:enderBlock",
"inventory"
);
// 註冊這個方塊物品的資源到Forge內
Minecraft.getMinecraft().getRenderItem().getItemModelMesher()
.register(item, 0, location);
// 註冊藥丸物品的資源到Forge內
Minecraft.getMinecraft().getRenderItem().getItemModelMesher()
.register(pillItem, 0, new ModelResourceLocation(
"myfancymods:pillItem",
"inventory"
));
GameRegistry.addShapedRecipe(
new ItemStack(enderBlock),
"X X",
" X ",
"X X",
'X',
Blocks.dirt);
GameRegistry.addShapelessRecipe(
new ItemStack(pillItem, 9),
enderBlock
);
GameRegistry.addSmelting(
Items.sugar,
new ItemStack(pillItem, 1),
1.0f
);
pillItem.setPotionEffect(PotionHelper.blazePowderEffect);
proxy.init(event);
}
到這裡我們的Main
檔案就可以移除了。接下來更新資源檔的命名,把resources/assets/myfancymods
改名為resources/assets/mymod
就可以了。另外,在資源檔的目錄resources
下有一個mcmod.info
的檔案,我們順便將這個檔案做更新,可以讓我們的模組資訊更完整:
更改名稱後的resource目錄
mcmod.info
[
{
"modid": "mymod",
"name": "My Mod",
"description": "A mod for itHome",
"version": "${version}",
"mcversion": "${mcversion}",
"url": "",
"authorList": ["Sam"],
"credits": "",
"logoFile": "",
"screenshots": [],
"dependencies": []
}
]
檔案內容應該很好理解,這裡的"version"與"mcversion"是Forge內部保留字,會在執行時自動替換,我們不需要更改這部分內容。
我們的模組現在資訊更完整,並且可以"Disable"了。
如果到目前為止的程式碼你不是很了解的話,別擔心,到最後面會有完整的程式碼可以參考的。