[1.6.4]Учебник по моддингу

60
0
Начало
Установите (обновите) java. Скорее всего у вас стоит последняя версия, но предохранится не помешает. http://www.java.com/ru/.
1. Скачайте и установите JDK.
2. Создайте на рабочем столе или где вам удобно папку.
3. Скачайте Eclipse. Скачать.
4. Скачайте Forge (качайте рекомендованный, нам нужен src). Скачать.
Переместите все файлы из скачанного Forge в нашу созданную папку и запустите install.cmd. Этот процесс сам загрузит MCP, все установит и т.д., чем Forge и привлекателен.
Папку с eclipse также переместите на рабочий стол.
MCP (Minecraft Coder Pack) – коллекция скриптов и инструментов в помощь разработчику для создания модов клиента и сервера Minecraft'а. Данный пакет инструментов позволяет выполнять декомпиляцию кода сервера и клиента игры, а также обратные им действия.
Декомпиляция – процесс преобразования файлов игры в .java файлы, чтобы с ними можно было работать в среде программирования Eclipse.
Рекомпиляция – процесс, обратный декомпиляции – преобразовывает измененные файлы и файлы мода в .class файлы, с которыми работает игра.
Eclipse – среда разработки приложений на языке программирования Java. Вообще для разработки модов можно использовать и блокнот, но на Eclipse в сотни раз быстрее.
Запустите Eclipse. При первом (и при последующих, если не поставить галочку появлений) открытии появится окно, в котором Eclipse попросит указать его рабочее пространство. Указывайте нашу созданную папку, в ней mcp, а далее папку eclipse.
Когда вы запустили Eclipse, обратите внимание на одну делать. Слева, в Package Explorer открываете проект Minecraft (щелк по плюсику (как в проводнике windows)) и если в “JRE System Library” в квадратных скобках у вас стоит “[JavaSE-1.6]“, то нажмите правой кнопкой, свойства (properties) и в раскрывающемся списке (Execution environment) выберите JavaSE-1.7(jre7).
Подготовка закончена. Можно приступать к созданию модов!
Если у вас завис Forge во время установки и так несколько раз, то переместите вашу папку в системный диск и попробуйте установить там, мне помогло.
Итак, вы закончили подготовку и уже хотите создавать моды, ну тогда приступим!
В Package Explorer переходите в папочку src. Вы видите много пакетов. Один (или даже несколько) из них и будет вашим модом. Выделяете src (ЛКМ) и нажимаете ПКМ. В появившемся окошке выбираете New>Package. Появляется окно в котором нам предлагают вбить имя пакета. Имя должно быть в формате assets.что-то.что-то…. Ну тобишь для этого учебника имя пакета будет assets.testmod.src. Название пакета не должно оканчиваться на точку и не должно использовать зарезервированных Java слов (staic,new,private и т.д.). Жмете Finish и у вас, в самом верху появляется ваш белый пакет. Белый, потому что пустой. Исправим положение!
Для начала нам надо создать файл, в котором мы создадим имя, Id и версию нашего мода.
Кликаем ПКМ на наш созданный пакет и выбираем New>Class. Или же выделяем наш пакет и в верхней панели щелкаем по значку буквы c в зеленом кружочке с желтым крестиком справа сверху. Файл назовите как хотите, в нем будят находится константы для нашего мода (подробнее далее). Я назову его ModInfo и вам советую это название. Больше в окне Java Class ничего менять не нужно, кликайте Finish.
Ну вот вы и создали первый файл вашего мода.
Теперь, между скобочками класса ModInfo, который был создан автоматически пишем следующее(приведу весь файл целиком):
Код:
package assets.testmod.src;
 
public class ModInfo {
    /*
    * ID вашего мода
    */
    final static String MODID = "TestMod";
    /*
    * Имя вашего мода
    */
    final static String NAME = "Test Mod";
    /*
    * Версия вашего мода
    */
    final static String VERSION = "1.0.0";
}
Разберем данный код.
package assets.testmod.src; – собственно ваш пакет.
public class ModInfo {…} – класс. Имя класса всегда должно быть таким же, как и имя файла!
final static String MODID = “TestMod”; – объявление строковой(текстовой) константы(нельзя изменить) MODID(константы принято писать заглавными буквами) = “TestMod” – тут ваш ID мода(без пробелов).
final static String NAME = “Test Mod”; – все тоже самой, но название имя вашего мода(можно использовать почти все символы, включая пробелы).
final static String VERSION = “1.0.0″; – версия мода.
Все, пока все действия с файлом ModInfo.java мы закончили. Время создать файл лист – файл содержащий основной контент нашего мода.
(Вообще, ModInfo не обязателен. Эти же константы можно объявить и в файле листе нашего мода. Но об этом подробней в ролике).
Создаете еще один класс. Можете назвать его как хотите, но я назову его в честь названия моего мода – TestMod.java.
Вот тут то и будет происходить все действо.
Пишем в него такой код:
Код:
package assets.testmod.src;
 
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
 
@Mod(modid=ModInfo.MODID, name=ModInfo.NAME, version=ModInfo.VERSION)
 
public class TestMod {
    @Mod.Instance(ModInfo.MODID)
    public static TestMod mod;
 
    @EventHandler
    public void preInit(FMLPreInitializationEvent event)
    {
 
    }
 
    @EventHandler
    public void init(FMLInitializationEvent event)
    {
 
    }
 
    @EventHandler
    public void postInit(FMLPostInitializationEvent event)
    {
 
    }
 
    @EventHandler
    public void serverStarting(FMLServerStartingEvent event)
    {
 
    }
}
Разберем все по полкам. То, что было разобрано выше (например пакет или класс) разбирать не буду. Только новое!
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
Это импорты. Импорт – подключение других пакетов или файлов к нашему файлу. Если вы читали “Технические вещи Eclipse”, то знаете, что импорты можно автоматически добавлять комбинацией клавиш Ctr+Shift+O. Если их удалить, то некоторые слова eclipse выделит как ошибку.
@Mod(modid=ModInfo.MODID, name=ModInfo.NAME, version=ModInfo.VERSION) – тут то, ради чего мы создавали ModInfo.java. Как видите в поля modid,name,version вместо текста в кавычках мы вставили сначала ModInfo, как указатель на созданный файл и после точки имя нашей константы. Компилятор, увидев такую строку просто заменит ее на то, что у нас в ModInfo.
@Mod.Instance(ModInfo.MODID) – также указатель на наш ModInfo.java.
@EventHandler
public void init(FMLInitializationEvent event)
{
}
А здесь будут важные регистры, такие как регистрация блоков и другое важное. Все остальное пока неважно.
Ну вот и все! Вы создали инфо-файл и файл лист. Дальше самое интересное!
Блок
В этой главе начнем собственно наполнять наш пока пустой мод контентом, а именно – создадим блок.
Почему создание блока? Потому что его создание самое простое и демонстрирует основные принципы создания модов.
Начнем. Для начала создадим в нашем TestMod.java собственно блок.
Сразу после публикации нашего класса создаем и регистрируем блок:
Код:
public class TestMod {
 
 public static final Block testBlock = new TestBlock(2000).setUnlocalizedName("testBlock");
 
    @Mod.Instance(ModInfo.MODID)
    public static TestMod mod;
 
    @EventHandler
    public void preInit(FMLPreInitializationEvent event)
    {
 
    }
 
    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        GameRegistry.registerBlock(testBlock);
        LanguageRegistry.addName(testBlock, "Test Block");
    }
 
    @EventHandler
    public void postInit(FMLPostInitializationEvent event)
    {
 
    }
 
    @EventHandler
    public void serverStarting(FMLServerStartingEvent event)
    {
 
    }
Почти наверняка Eclipse высветит ошибки. Но мы уже знаем комбинацию клавиш Ctrl+Shift+O и все необходимые файлы, а именно – пакет с данными о блоках импортируются к нам.
Возможно будет выбор – какой пакет импортировать? Берите тот, имя которого начинается на net.minecraft.что-то.
public static final Block testBlock = new TestBlock(2000).setUnlocalizedName(“testBlock”);
testBlock – этакой id в массиве блоков (загляните в Block.java поймете) блока.
TestBlock – файл, который будет называться TestBlock.java (по названию).
2000 – id блока. Всего 4096 id выбирайте что-то в районе 2000 – 4000.
ID ни в коем случае не должны повторяться. Все может пройти и запуститься, но проблемы в игре неизбежны!
GameRegistry.registerBlock(testBlock);
LanguageRegistry.addName(testBlock, “Test Block”);
Тут проблем возникнуть не должно.
Первая строка регистрирует блок в игре, а вторая дает ему имя в игре.
В итоге наш TestMod должен выглядеть так:
Код:
package assets.testmod.src;
 
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
 
@Mod(modid=ModInfo.MODID, name=ModInfo.NAME, version=ModInfo.VERSION)
 
public class TestMod {
 
 public static final Block testBlock = new TestBlock(2000).setUnlocalizedName("testBlock");
 
    @Mod.Instance(ModInfo.MODID)
    public static TestMod mod;
 
    @EventHandler
    public void preInit(FMLPreInitializationEvent event)
    {
 
    }
 
    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        GameRegistry.registerBlock(testBlock);
        LanguageRegistry.addName(testBlock, "Test Block");
    }
 
    @EventHandler
    public void postInit(FMLPostInitializationEvent event)
    {
 
    }
 
    @EventHandler
    public void serverStarting(FMLServerStartingEvent event)
    {
 
    }
}
Теперь создаем файл TestBlock.java и пишем в него следующее:
Код:
package assets.testmod.src;
 
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
 
public class TestBlock extends Block
{
    protected TestBlock(int par1)
    {
        super(par1, Material.ground); // Материал
        this.setCreativeTab(CreativeTabs.tabBlock); // Таблица в креативе
        /*
        * Текстура
        */
        setTextureName(ModInfo.MODID.toLowerCase() + ":testBlock");
    }
}
Тут все просто и описано в комментариях.
Единственная загвоздка – текстура.
Сразу прошу заметить вызов нашего ModInfo.java с константой MODID. testBlock это имя текстуры (testBlock.png). Так куда же ее кидать?
Все просто идите по пути ваша созданная папка>mcp>src>minecraft>assets>testmod и создаете тут папку textures(так и только с таким именем), а внутри нее создаете папку blocks(тоже только с таким именем!) ну и кидаете туда вашу текстуру (testBlock.png).
С версии 1.5.2 Minecraft поддерживает квадратные текстуры абсолютно любого разрешения. По крайней мере от 16×16 до 512×512 точно. Так что можете создавать блок с супер четкой текстурой.
Вот и все.
Прежде чем мы приступим к созданию предмета, я хотел бы рассказать про дополнительные свойства блока. В этой главе вы поиграетесь с настройками блока и посмотрим на его основные параметры.
Итак в коде нашего блока (TestBlock.java (или ваш блок)) обратим внимание на строчку
super(par1, Material.ground); // Материал
ground – это наш материал. Если вы сотрете ground включая точку, а потом вновь поставите ее, то у вас выскочит список доступных в игре материалов. Я приведу их тут.
air
anvil
cactus
cake
circuits
clay
cloth
coral
dragonEgg
fire
glass
grass
ground
ice
iron
lava
leaves
piston
plants
portal
pumpkin
rock
sand
snow
sponge
tnt
vine
water
web
wood
С этим разобрались.
Дальше идет строчка
this.setCreativeTab(CreativeTabs.tabBlock); // Таблица в креативе
Тут то мы и указываем основные свойства. В данной строке блок добавляется в креативную таблицу в игре. Таблица указывается после точки. Если вы также сотрете ее название и точку, а потом поставите ее снова, то у вас выскочит список всех таблиц. Также привожу их список.
tabAllSearch – вкладка со всеми предметами
tabBlock – вкладка “Блоки”
tabBrewing – компоненты для зелий
tabCombat – вкладка “Оружие”
tabDecorations – вкладка “Декоративные блоки”
tabFood – вкладка “Еда”
tabMaterials – вкладка “Материалы”
tabMisc – вкладка “Разное”
tabRedstone – вкладка “Механизмы”
tabTools – вкладка “Инструменты”
tabTransport – вкладка “Транспортирующие”
Можете добавлять свои this'ы. Вот пример основных параметров для блока.
{
super(par1, Material.ground);
this.setCreativeTab(CreativeTabs.tabBlock);
this.setHardness(1.0F);
this.setLightValue(1.0F);
this.setResistance(3.0F);
this.setStepSound(soundMetalFootstep);
}
this.setHardness(1.0F); – скорость разрушения блока. 0.5F – как у грязи.
this.setLightValue(1.0F); – светимость блока. 1.0F – как у светокамня.
this.setResistance(3.0F); – взрывоустойчивость блока.
this.setStepSound(soundMetalFootstep); – звук, при ходьбе по блоку. Список:
soundAnvilFootstep – ходьба по наковальне
soundClothFootstep – ходьба по шерсти
soundGlassFootstep – ходьба по стеклу
soundGrassFootstep – ходьба по траве
soundGravelFootstep – ходьба по гравию
soundLadderFootstep – ходьба по лестнице
soundMetalFootstep – ходьба по драгоценным блокам
soundPowderFootstep – ходьба по пыли
soundSandFootstep – ходьба по песку
soundSnowFootstep – ходьба по снегу
soundStoneFootstep – ходьба по камню
soundWoodFootstep – ходьба по дереву
Хотите, чтобы имя блока было цветным? Пожалуйста:
LanguageRegistry.addName(testBlock, EnumChatFormatting.AQUA + “Test Block”);
Нажмите точку после EnumChatFormatting и вы увидите все доступные цвета.
Чтобы создать дроп с блока или моба, то пропишите такой код:
Код:
public int idDropped(int par1, Random par2Random, int par3)
    {
        return Item.appleGold.itemID;
    }
Разберем:
Item – файл, где создан дроп (все предметы стандартного майна находятся в Item.java, все блоки – в Block.java, ну а ваши блоки и предметы могут находится, к примеру, в TestMod.java, так и пишите без .java название файла, где создан контент).
appleGold – собственно текстовый id вашего предмета.
.itemID – или blockID – в зависимости от блока.
Вот и все! (И не забудьте импортировать пакеты (Ctrl+Shift+O)).
После того, как вы создали блок, было бы круто сделать так, чтобы он генерировался в мире!
Сделать это легко. В Регистрах пишем:
GameRegistry.registerWorldGenerator(new TestBlockGenerator());
Ну собственно регистрируем файл генератор. Наводим на TestBlockGenerator(), и в выпадающем списке создаем класс TestBlockGenerator. Внутри пишем:
Код:
package assets.testmod.src;
 
import java.util.Random;
 
import net.minecraft.world.World;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.feature.WorldGenMinable;
import cpw.mods.fml.common.IWorldGenerator;
 
public class TestBlockGenerator implements IWorldGenerator {
 
    @Override
    public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) {
        switch(world.provider.dimensionId) {
        case -1:
        generateNether();
        break;
        case 0:
        generateSurface(world, random, chunkX*16, chunkZ*16);
        break;
        case 1:
        generateEnd();
        break;
        }
    }
 
    public void generateNether() {
        //were not doing ore ore in the nether
        }
 
        public void generateSurface(World world, Random rand, int chunkX, int chunkZ) {
        for (int i = 0; i < 30; i++) {
        int randPosX = chunkX + rand.nextInt(16);
        int randPosY = rand.nextInt(64);
        int randPosZ = chunkZ + rand.nextInt(16);
 
        (new WorldGenMinable(TestMod.blockTest.blockID, 10)).generate(world, rand,
        randPosX, randPosY, randPosZ);
        }
        }
 
        public void generateEnd() {
        //were not going to generate in the end either
        }
}
Верхняя часть файла вам не нужна. Обратите внимание на три пустых метода (см. Самоучитель Java): generateNether, generateSurface, generateEnd – это собственно измерения, где блок будет генериться. В generateSurface у нас есть цикл, который и является по сути генератором. (int i = 0; i < 30; i++) 30 – собственно частота генерации.
int randPosY = rand.nextInt(64); – 64 – высота, до которой генерируется ваш блок
(TestMod.blockTest.blockID, 10) – какой блок генерируется и сколько блоков в жиле.
Вот так выглядит TestMod.java:
Код:
package assets.testmod.src;
 
import net.minecraft.block.Block;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
 
@Mod(modid=ModInfo.MODID, name=ModInfo.MODNAME, version=ModInfo.MODVERSION)
 
public class TestMod {
    @Mod.Instance(ModInfo.MODID)
    public static TestMod testmod;
 
    public static final Block blockTest = new BlockTest(3000).setUnlocalizedName("blockTest");
 
    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        GameRegistry.registerBlock(blockTest);
        LanguageRegistry.addName(blockTest, "Test Block");
 
        GameRegistry.registerWorldGenerator(new TestBlockGenerator());
    }
}
В этом уроке я расскажу вам, как сломать ваш блок СВОЕЙ киркой.
Добавьте в регистры такую строку:
MinecraftForge.setBlockHarvestLevel(blockTest, “pickaxe”, 3);
Разберем:
blockTest – то, что находится после pubic static Block
“pickaxe” – на что взаимодействует (axe – топор, spade – лопата, pickaxe – кирка, hoe – тяпка)
3 – этакой левел разрушения блока. Если вы загляните в EnumToolMaterial.java, то увидите что у каждого материала первая цифра от 0 до 3. 3 у EMERLAND, а 0 у WOOD и GOLD. Я думаю вы уже догадались. Если мы поставим 0, то блок будет ломать любая кирка. Если вы поставить 4, то только кирка с вашим материалом будет ломать этот блок. Ну а если 3, то только алмазная кирка. Внимание! serHardness – скорость разрушения блока влияет только на скорость, но не на добываемость!
Так выглядит TestMod.java :
Код:
package assets.testmod.src;

import net.minecraftforge.common.MinecraftForge;
import assets.testmod.src.block.BlockList;
import assets.testmod.src.item.ItemList;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid=ModInfo.MODID, name=ModInfo.MODNAME, version=ModInfo.MODVERSION)

public class TestMod {
    @Mod.Instance(ModInfo.MODID)
    public static TestMod testmod;

    public static final Block blockTest = new TestBlock(3000).setUnlocalizedName("blockTest");

    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        GameRegistry.registerBlock(blockTest);
        LanguageRegistry.addName(blockTest, "Block TEST");

        MinecraftForge.setBlockHarvestLevel(blockTest, "pickaxe", 3);
    }
}
Создать для блока разностороннюю текстуру легко. В файле BlockTest.java пишем следующее:
Код:
package assets.testmod.src;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.util.Icon;

public class BlockTest extends Block {

    private Icon front, side, top, bottom;

    public BlockTest(int par1) {
        super(par1, Material.rock);
        this.setCreativeTab(CreativeTabs.tabBlock);
    }

    public void registerIcons(IconRegister register)
    {
        front = register.registerIcon(ModInfo.MODID + ":testFront");
        bottom = register.registerIcon(ModInfo.MODID + ":testBottom");
        side = register.registerIcon(ModInfo.MODID + ":testSide");
        top = register.registerIcon(ModInfo.MODID + ":testTop");
    }

    @Override
    public Icon getIcon(int side, int meta)
    {
        return side == 1 ? this.top : (side == 0 ? this.bottom : (meta == 2 && side == 2 ? this.front : (meta == 3 && side == 5 ? this.front : (meta == 0 && side == 3 ? this.front : (meta == 1 && side == 4 ? this.front : this.side)))));
    }
}
Вот и все. В папку blocks кидаем 4 текстуры, которые и будут отображаться на вашем блоке.
В файле блока пишем:
Код:
@Override
    public void onBlockClicked(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer)
    {
        par5EntityPlayer.addPotionEffect(new PotionEffect(EffectId, Time, Power));
    }
Разберем сий код:
onBlockClicked – метод, выполняющийся, когда игрок бьет по блоку.
par5EntityPlayer.addPotionEffect(new PotionEffect(EffectId, Time, Power));
EffectId – Id эффекта (http://minecraft-ru.gamepedia.com/Эффекты_зелий)
Time – время действия в тиках (1 секунда = 20 тиков)
Power – сила эффекта
Вам когда-нибудь было интересно, как работает портал в ад с технической точки зрения? Никогда не заглядывали в BlockPortal.java? А зря, но не беда, так как сейчас я расскажу все, что смог оттуда вытянуть.
Начнем с самого простого – при щелчке по блоку заменить его на другой блок.
В файле блока напишите такой код:
Код:
public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
    {
        par1World.setBlock(par2, par3, par4, Block.blockDiamond.blockID);
        return true;
    }
onBlockActivated – при клике правой кнопкой
World par1World – переменная типа World (для работы с миром)
int par2, int par3, int par4 – x,y,z
EntityPlayer par5EntityPlayer – переменная типа EntityPlayer (для работы с игроком)
par1World.setBlock(par2, par3, par4, Block.blockDiamond.blockID); – поставить алмазный блок в точку 0,0,0 (то есть заменить блок, на который кликали).
Теперь, при правом щелчке по блоку, он исчезнет и вместо него появится алмазный блок!
Но это только начало магии.
Чтобы позиционировать создаваемый новый блок относительно того, по которому кликали (0,0,0), надо просто прибавлять значения к par2, par3, par4.
Например следующий код создаст алмазный блок справа от блока, по которому кликали (и он не исчезнет).
Код:
public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9)
    {
        par1World.setBlock(par2+1, par3, par4, Block.blockDiamond.blockID);
        return true;
    }
На этом с методом onBlockActivated можно закончить. Он себя исчерпал (дальше только ваша фантазия). А я перехожу дальше – Условие.
Теперь, сделаем так, чтобы наш тестовый блок превращался в алмазный, если его поджечь!
Пишем сей код:
Код:
public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
    {
        if(par1World.getBlockId(par2, par3+1, par4) == Block.fire.blockID)
        {
            par1World.setBlock(par2, par3, par4, Block.blockDiamond.blockID);
        }
    }
У нас идет проверка, что сверху есть огонь и преобразование нашего блока в алмазный, если он огонь присутствует.
На этом с мультиблочными структурами пока все. Возможно дальше буду развивать эту тему, а если не терпится, загляните в BlockPortal.java
Работаем мы с BlockTest.java
Пишем этот код внутрь:
Код:
public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4)
    {
        return null;
    }

    public boolean isOpaqueCube()
    {
        return false;
    }

    public boolean renderAsNormalBlock()
    {
        return false;
    }
Теперь вы можете проходить сквозь ваш блок. Теперь под этим кодом напишите:
Код:
public int getRenderType()
    {
        return 8;
    }
Сейчас наш блок станет полностью прозрачным. Но он все еще выделяется и находясь в нем невозможно работать с другими блоками.
Код:
public void setBlockBoundsBasedOnState(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
    {
        float f = 0.0000F;
        this.setBlockBounds(0.0F, 0.0F, 0.0F, 0.0F, f, 0.0F);
    }
Этот код уберет черные полоски выделения да и вообще блок как бы будет, но взаимодействовать с ним нельзя так как грубо говоря материально го уже не будет (но вот он сможет воздействовать на вас).
Собственно газ уже готов. Теперь добавим ему убийственные свойства.
Код:
public void onEntityCollidedWithBlock(World par1World, int par2, int par3, int par4, Entity par5Entity)
    {
        par5Entity.attackEntityFrom(DamageSource.cactus, 1.0F);
    }
Готово, теперь находясь в этом блоке вы будете получать урон! Убийственный газ готов!
Помните, что вы не можете использовать методы воздействия на блок (можете но не сможете их реализовать в игре, так как его там грубо говоря нет), такие как onBlockClick, onBlockActivated и т.д. Можете использовать только воздействие блока на вас – onEntityCollidedWithBlock, onEntityWalking и другие.
Предмет
В этой главе создадим простейший предмет.
Там же, где мы создавали блок (не GameRegistry, а выше) пишем такой код:
public static Item testItem = new TestItem(2021).setUnlocalizedName(“testItem”);
Скорее всего, он выведет ошибку. Добавляем необходимые импорты (Ctrl+Shift+O) и ошибка исчезает.
Ну а там, где у нас все регистрации пишем строчку, которая дает нашему итему имя в игре.
LanguageRegistry.addName(testItem, “Test Item”);
В итоге, мой TestMod.java будет выглядеть таким образом:
Код:
package assets.testmod.src;

import net.minecraft.item.Item;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid=ModInfo.MODID, name=ModInfo.MODNAME, version=ModInfo.MODVERSION)

public class TestMod {

    public static Item testItem = new TestItem(3200).setUnlocalizedName("testItem");

    @Mod.Instance(ModInfo.MODID)
    public static TestMod testmod;

    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        LanguageRegistry.addName(testItem, "Test Item");
    }
}
У нас все равно остается одна ошибка TestItem, но это из за того, как вы уже поняли, что отсутствует файл TestItem.java. Наводим мышкой на ошибку и у нас появляется в выпадающем меню предложение создать этот файл.
Код у него такой:
Код:
package assets.testmod.src;

import net.minecraft.item.Item;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;

public class TestItem extends Item
{
public TestItem(int par1)
{
        super(par1);
        this.setCreativeTab(CreativeTabs.tabTools);
}

@Override
public void registerIcons(IconRegister par1IconRegister)
{
                                this.itemIcon = par1IconRegister.registerIcon(ModInfo.MODID + ":testItem");
}
}
Если вы проходили главу про создание блока и главу “доп про блок”, то вам все станет понятно.
Чтобы у вас появилась текстура вашего итема, вам в папке textures (см. создание блока) надо создать папку items. Получается у вас в textures будет две папки – blocks items. Имена должны быть строго такими. И в items должна лежать текстура с именем testItem.png (.setUnlocalizedName).
Вот собственно и все.
Мы все хотим и любим есть. И главный герой в Minecraft не исключение. Бутерброды, соки, яблочные печеньки – почему нет?
Там же, где мы создавали предмет и блок пишем код:
public static Item testFood = new TestFood(2022, 1, 0.4F, false).setUnlocalizedName(“testFood”);
1 – количество восстанавливаемых полу-сердец. 1 = 0.5 сердца.
0.4F – на сколько утоляет голод
false – можно ли этой едой приручить волка (true – да, false – нет)
Так выглядит наш файл TestMod.java:
Код:
package assets.testmod.src;

import net.minecraft.item.Item;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid=ModInfo.MODID, name=ModInfo.MODNAME, version=ModInfo.MODVERSION)

public class TestMod {

  public static Item testFood = new TestFood(2022, 1, 0.4F, false).setUnlocalizedName("testFood");

    @Mod.Instance(ModInfo.MODID)
    public static TestMod testmod;

    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        LanguageRegistry.addName(testFood, "Test Item");
    }
}
Создаем файл TestFood.java:
Код:
package assets.testmod.src;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.item.ItemFood;

public class TestFood extends ItemFood
{
public TestFood(int par1, int par2, float par3, boolean par4)
{
super(par1, par2, par4);
maxStackSize = 64;
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon(ModInfo.MODID + “:testFood”);
}
}
maxStackSize = 64 – сколько предметов может быть в стаке
Итак многие, а может и не многие ждали этой главы. Она посвящена созданию своего меча. Следующая глава будет посвящена созданию инструментов. Я решил разнообразить процесс и создавать мы будем не testSword, а биту. Да да именно биту!
Что ж приступим. Там, где мы создавали блоки и предметы пишет две следующие строчки:
public static EnumToolMaterial BATTOOLMATERIAL = EnumHelper.addToolMaterial(“BAT”, 4, 150, 5, 0, 10);
public static final Item bat = new Bat(3000).setUnlocalizedName(“bat”);
Первая строка создает новый материал. Разберем:
“BAT” – собственно материал
4 – типо id мода. Следовательно следующий материал будет иметь id 5 и т.д.
150 – количество использований
5 – количество отнимаемых полу-сердечек
10 – зачаровываемость
Там где у нас все регистры пишем:
LanguageRegistry.addName(bat, “Bat”);
Наш TestMod стал выглядеть так:
Код:
package assets.testmod.src;

import net.minecraft.block.Block;
import net.minecraft.item.EnumToolMaterial;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.EnumHelper;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid=ModInfo.MODID, name=ModInfo.MODNAME, version=ModInfo.MODVERSION)

public class TestMod {

    public static final EnumToolMaterial BATTOOLMATERIAL = EnumHelper.addToolMaterial("BAT", 4, 150, 5, 0, 10);
    public static final Item bat = new Bat(3000).setUnlocalizedName("bat");

    @Mod.Instance(ModInfo.MODID)
    public static TestMod testmod;

    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        LanguageRegistry.addName(bat, "Bat");
    }
}
Теперь наводим на ошибку, высвечивающуюся под словом Bat, или просто создайте класс Bat.
Внутри пишем:
Код:
package assets.testmod.src;

import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemSword;

public class Bat extends ItemSword {
    public Bat(int par1)
    {
        super(par1, TestMod.BATTOOLMATERIAL);
        this.maxStackSize = 2;
        this.setCreativeTab(CreativeTabs.tabCombat);
    }

    @Override
    public void registerIcons(IconRegister par1IconRegister)
    {
        this.itemIcon = par1IconRegister.registerIcon(ModInfo.MODID + ":bat");
    }
}
Как видите – все точно также как и с обычным предметом, только он наследует класс ItemSword, а не Item.
TestMod.BATTOOLMATERIAL – тут собственно наш материал
Дальше идет количество предметов в стаке и добавление во вкладку Combat.
Текстуру кидаем в папку items, которую мы создали в прошлом уроке (testmod>textures>items>bat.png).
В прошлой главе мы создали биту. Теперь пришло время создать все остальное. Я покажу создание инструментов только на топоре, так как для всех остальных создание идентичное.
Приступим. Создадим новый материал взамен старого:
public static final EnumToolMaterial TEST = EnumHelper.addToolMaterial(“TEST”, 4, 2000, 10.0F, 5.0F, 10);
Разберем:
“TEST” – имя материала
4 – пробиваемость блоков
2000 – количество использований
10.0F – эффективность (скорость разрушения блоков)
5.0F – урон
10 – зачаровываемость
Создаем топор:
public static final Item testAxe = new TestAxe(3000).setUnlocalizedName(“testAxe”);
Так выглядит наш TestMod.java:
Код:
package assets.testmod.src;

import net.minecraft.block.Block;
import net.minecraft.item.EnumToolMaterial;
import net.minecraft.item.Item;
import net.minecraftforge.common.EnumHelper;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid=ModInfo.MODID, name=ModInfo.MODNAME, version=ModInfo.MODVERSION)

public class TestMod {

    public static final EnumToolMaterial TEST = EnumHelper.addToolMaterial("TEST", 4, 2000, 10.0F, 5.0F, 10);

    public static final Item testAxe = new TestAxe(3000).setUnlocalizedName("testAxe");

    @Mod.Instance(ModInfo.MODID)
    public static TestMod testmod;

    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        LanguageRegistry.addName(testAxe, "Test axe");
    }
}
Теперь создаем файл TestAxe.java и пишем в него следующее:
Код:
package assets.testmod.src;

import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.item.ItemAxe;

public class TestAxe extends ItemAxe {

    public TestAxe(int par1) {
        super(par1, TestMod.TEST);
    }

    @Override
    public void registerIcons(IconRegister par1IconRegister)
    {
        this.itemIcon = par1IconRegister.registerIcon(ModInfo.MODID + ":testAxe");
    }
}
super(par1, TestMod.TEST); – наш материал
Ну и текстуру кладете в папку items. Вот собственно и все. Все остальные предметы создавайте также, только вместо extends ItemAxe пишите ItemSword, ItemSpand(Лопата) ItemHoe(Тяпка), ItemPickaxe(Кирка). При необходимости можете написать под super this. и пошарить по свойствам – добавить что-то свое.
В файле итема пишем:
Код:
public ItemStack onItemRightClick(ItemStack is, World world, EntityPlayer player)
    {
        <<Какой-то код>>
    return is;
    }
Теперь при нажатии на ПКМ, будет выполняться <<какой-то код>>. Это может быть, например, наложение каких-то эффектов на игрока:
Код:
player.addPotionEffect(new PotionEffect(Potion.waterBreathing.id, 20, 20));
Этот код наложит на вас эффект дыхания под водой.
Тут можно задать любой код, на Ваше усмотрение. Все зависит от Вашей фантазии <img src="http://forum.mcmodding.ru/img/smilies/nomicons/smile.png" width="20" alt="nomicons/smile">
Броня
Для начала создаем собственный материал для брони (также как и для инструментов) :
Код:
public static EnumArmorMaterial TESTARMORMATERIAL = EnumHelper.addArmorMaterial("TESTARMORMATERIAL", 1000, new int[] {5, 20, 10, 5}, 10);
Разберем:
TESTARMORMATERIAL – собственно Id материала для брони
1000 – поглощаемый урон
{5, 20, 10, 5} – уровень брони на каждую ее часть (шлем, грудь, штаны, ботинки)
10 – зачаровываемость
Теперь создаем всю броню разом (привожу сразу весь TestMod.java):
Код:
package assets.testmod.src;

import net.minecraft.item.EnumArmorMaterial;
import net.minecraft.item.ItemArmor;
import net.minecraftforge.common.EnumHelper;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid=ModInfo.MODID, name=ModInfo.MODNAME, version=ModInfo.MODVERSION)

public class TestMod
{
    @Mod.Instance(ModInfo.MODID)
    public static TestMod testmod;
    
    public static EnumArmorMaterial TESTARMORMATERIAL = EnumHelper.addArmorMaterial("TESTARMORMATERIAL", 1000, new int[] {5, 20, 10, 5}, 10);
    
    public static ItemArmor testHelmet = new TestHelmet(3200, TestMod.TESTARMORMATERIAL, 0, 0);
    
    public static ItemArmor testChest = new TestChest(3201, TestMod.TESTARMORMATERIAL, 1, 1);
    
    public static ItemArmor testLeggins = new TestLeggins(3202, TestMod.TESTARMORMATERIAL, 2, 2);
    
    public static ItemArmor testBoots = new TestBoots(3203, TestMod.TESTARMORMATERIAL, 3, 3);
    
    @EventHandler
    public void modLoad(FMLInitializationEvent event)
    {
        LanguageRegistry.addName(testBoots, "Test boots");
        LanguageRegistry.addName(testChest, "Test chest");
        LanguageRegistry.addName(testHelmet, "Test helmet");
        LanguageRegistry.addName(testLeggins, "Test leggins");
    }
}
Вам остается только создать 4 файла: TestHelmet.java, TestChest.java, TestLeggins.java и TestBoots.java.
Далее напишите внутрь каждого файла этот код (он одинаковый для всех файлов (за исключением названия файла и текстуры в инвентаре)):
Код:
package assets.testmod.src;

import net.minecraft.client.main.Main;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumArmorMaterial;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

public class TestHelmet extends ItemArmor
{

    public TestHelmet(int par1, EnumArmorMaterial par2EnumArmorMaterial, int par3, int par4)
    {
        super(par1, par2EnumArmorMaterial, par3, par4);
        this.setCreativeTab(CreativeTabs.tabCombat);
    }
    
    /*
     * Иконка
     */
    @SideOnly(Side.CLIENT)
    public void registerIcons(IconRegister par1IconRegister)
    {
        this.itemIcon = par1IconRegister.registerIcon(ModInfo.MODID + ":testHelmet"); 
    }
    
    public void onArmorTickUpdate(World world, EntityPlayer player, ItemStack itemStack)
    {
        /*
         * Любой эффект, когда броня одета (не вся, а только определенный предмет(в данном случае - шлем))
         */
    }
    
    /*
     * Текстура брони на игроке
     */
    public String getArmorTexture(ItemStack stack, Entity entity, int slot, int layer)
    {
        return ModInfo.MODID + ":textures/armor/testArmor.png";
    }

}
Разберем:
public void registerIcons(IconRegister par1IconRegister) – собственно текстурка в инвентаре.
public void onArmorTickUpdate(World world, EntityPlayer player, ItemStack itemStack) – в этом методе вы можете прописать все, что душе угодно. Код в нем выполняется каждый игровой тик, когда соответствующий элемент брони надет.
public String getArmorTexture(ItemStack stack, Entity entity, int slot, int layer) – текстура брони на игроке. Запомните! Для все брони нужна лишь одна картинка! Здесь (http://minecraft.novaskin.me/editor?mod &acirc;€&brvbar; ayer_1.png) можете нарисовать текстуру брони. Затем скачиваете ее и кидаете в папку /textures/armor/testArmor.png.
Вот и все!
Крафт
В этой главе я опишу, как создавать для ваших будущих и существующих блоков и предметов крафты в верстаке и в печке.
Крафты записываются там же, где мы писали GameRegistry.блабла.
Приведу сразу весь файл, в котором мы получаем наш блок с помощью верстака, бесформенный крафт и с помощью печки :
Код:
package assets.testmod.src;

import assets.testmod.src.blocks.TestBlock;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerStartingEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid=ModInfo.MODID, name=ModInfo.NAME, version=ModInfo.VERSION)

public class TestMod {

    public static final Block testBlock = new TestBlock(2000).setUnlocalizedName("testBlock");

    @Mod.Instance(ModInfo.MODID)
    public static TestMod mod;

    @EventHandler
    public void preInit(FMLPreInitializationEvent event)
    {

    }

    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        GameRegistry.registerBlock(testBlock);
        LanguageRegistry.addName(testBlock, "Test Block");

        GameRegistry.addRecipe(new ItemStack(TestMod.testBlock, 1), new Object[]{ "XXX", "X#X", "XXX", Character.valueOf('X'), Block.cobblestone, ('#'), Block.dirt});
        GameRegistry.addShapelessRecipe(new ItemStack(TestMod.testBlock, 4), new Object[] {Item.appleGold});
        GameRegistry.addSmelting(Block.dirt.blockID, new ItemStack(TestMod.testBlock, 1), 1.0F);
    }

    @EventHandler
    public void postInit(FMLPostInitializationEvent event)
    {

    }

    @EventHandler
    public void serverStarting(FMLServerStartingEvent event)
    {

    }
}
Итак, начнем с крафта в верстаке:
Код:
GameRegistry.addRecipe(new ItemStack(TestMod.testBlock, 1), new Object[]{ "XXX", "XXX", "XXX", Character.valueOf('X'), Block.cobblestone});
(TestMod.testBlock, 1) – наш блок и его количество. Можете указать стандартный блок (Block.stone). Обратите внимание, что блоки из мода требуют указания файла, где они созданы (в нашем случае TestMod.java), значит и пишем TestMod.testBlock.
“XXX”, “XXX”, “XXX”,
Пока давайте представим это так – “123″, “456″, “789″,
Тогда наш верстак будет выглядеть так:
<span class="postimg"><img src="http://www.mcmodding.ru/wp-content/uploads/2013/06/craft.png" alt="http://www.mcmodding.ru/wp-content/uploads/2013/06/craft.png"></span>
Первые три X – слева направо первый ряд верстака и так далее.
Вместо X вы можете использовать все что угодно, например Y.
Character.valueOf('X'), Block.cobblestone – в скобочках указанный нами символ и что он из себя представляет (в этом случае – блок булыжника).
Можете использовать несколько символов, например:
{ “X#X”, “X#X”, “X#X”, Character.valueOf('X'), Block.cobblestone, ('#'), Block.dirt});
Думаю объяснять не стоит.
Далее, следующая строчка:
Код:
GameRegistry.addShapelessRecipe(new ItemStack(TestMod.testBlock, 4), new Object[] {Item.stick, Block.dirt});
Это тоже крафт в верстаке, но уже не зависящий от расположения ингредиентов.
(TestMod.testBlock, 4) – что получаем в каком количестве.
{Item.stick, Block.dirt} – что должно находиться в верстаке.
И наконец рецепт в печке:
Код:
GameRegistry.addSmelting(Block.dirt.blockID, new ItemStack(TestMod.testBlock, 1), 1.0F);
Block.dirt.blockID – что переплавляем (верхний слот)
TestMod.testBlock, 1 – что получаем и в каком количестве
1.0F – сколько опыта дадут за переплавку
Вот пока что все. Теперь вы можете добавить крафт любому своему предмету/блоку.
Сервер
Хотите поиграть на сервере с друзьями с вашим модом? Легко.
Для начала конечно у вас и у ваших друзей должен быть Forge на Minecraft с установленным вашим модом.
Теперь скачиваете minecraft-server.jar (на официальном сайте (снизу страницы)). Кидаете скачанный jar файл в какую-нибудь папку. Затем скачиваете Forge и скидываете его файлы в minecraft_server.jar (короче как вы патчите обычный Minecraft, так и minecraft_server). Теперь запускаете его и вот у вас знакомая по обычному Minecraft папка mods. Туда кидаете мод в архиве (смотрите “Создание готового мода”). Вот и все! Можете подключаться и играть с вашим модом!
В фале нашего мода пишем под всеми еще один @EventHandler :
Код:
package assets.testmod.src;

import net.minecraft.server.MinecraftServer;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLServerStartingEvent;

@Mod(modid=ModInfo.MODID, name=ModInfo.MODNAME, version=ModInfo.MODVERSION)

public class TestMod {

    @Mod.Instance(ModInfo.MODID)
    public static TestMod testmod;

    @EventHandler
    public void serverstarting(FMLServerStartingEvent event)
    {
        MinecraftServer.getServer().logInfo("TeSt MesSage INFO"); // Сообщение в сервере с приставкой [INFO]
        MinecraftServer.getServer().logWarning("TeSt MesSage WARNING"); // Сообщение в сервере с приставкой [WARNING]
        MinecraftServer.getServer().logSevere("TeSt MesSage Severe"); // Сообщение в сервере с приставкой [SEVERE]
        MinecraftServer.getServer().setMOTD("Test FORGE Server"); // Установка описания под сервером (в Minecraft)
        MinecraftServer.getServer().setDifficultyForAllWorlds(1); // Установка сложности
    }
}
Из комментариев понятно что делают данные команды. Там еще много команд. .set – задание разных параметров сервера, можете посмотреть список поставив точку и набрав set, вам высветится список всех параметров.
Манипуляции с сервером можно делать и в init, но только когда он запущен. А лучше только в serverstarting
 
60
0
Моб
Создать моба проще, чем кажется!
В регистрах (FMLInitiazaliation) пишем:
Код:
EntityList.addMapping(EntityTest.class, "Test", 111, 0x0033FF, 0x00CCFF);
Этот код создает моба, основным классом которого является EntityTest (создаете), с именем “Тest”, айди (Ctrl + клик по EntityList (снизу файла)), а также яйцо с цветом самого яйца (первое число) и цветом пупырышек (второе). Посмотреть цвета в таком формате можно посмотреть в начале учебника.
Теперь создайте класс EntityTest и напишите внутрь:
Код:
package assets.testmod.src;

import net.minecraft.entity.EntityLiving;
import net.minecraft.world.World;

public class EntityTest extends EntityLiving
{

    public EntityTest(World par1World)
    {
        super(par1World);
    }

}
Теперь можете заходить в игру и во вкладке “Разные”, в самом низу сможете найти яйцо. При правом клике видимых изменений не происходит, но на самом деле моб находиться прямо перед вами <img src="http://forum.mcmodding.ru/img/smilies/nomicons/smile.png" width="20" alt="nomicons/smile">
Дальше код будет различаться в зависимости от создаваемого моба.
Поменяйте:
extends EntityLiving
На:
extends EntityMob
Теперь у вас появился враждебный моб (у него будет даже некоторое подобие модели). При отключении gamemode он потихоньку ползет к вам и наносит урон.
Все монстры игры находятся в пакете: net.minecraft.entity.monster
Можете зайти в любой класс и создать любого монстра на ваш вкус.
Для примера я создам зомби, который будет гореть ночью, а днем будет вполне спокойно себя чувствовать.
После super() добавьте:
Код:
this.getNavigator().setBreakDoors(true);
        this.tasks.addTask(0, new EntityAISwimming(this));
        this.tasks.addTask(1, new EntityAIBreakDoor(this));
        this.tasks.addTask(2, new EntityAIAttackOnCollide(this, EntityPlayer.class, 1.0D, false));
        this.tasks.addTask(4, new EntityAIMoveTowardsRestriction(this, 1.0D));
        this.tasks.addTask(6, new EntityAIWander(this, 1.0D));
        this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 8.0F));
        this.tasks.addTask(7, new EntityAILookIdle(this));
        this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true));
        this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 0, true));
Этот код добавляет такие плюшки, как навигатор мобу (по теории он будет умнее) и возможность ломать двери.
Предлагаю вам самим разобраться в этих строка. Это подключение различных AI библиотек, которые будут влиять на поведение моба (короче он будет вести себя как зомби).
Код:
protected void func_110147_ax()
    {
        super.func_110147_ax();
        this.func_110148_a(SharedMonsterAttributes.field_111265_b).func_111128_a(40.0D);
        this.func_110148_a(SharedMonsterAttributes.field_111263_d).func_111128_a(0.23000000417232513D);
        this.func_110148_a(SharedMonsterAttributes.field_111264_e).func_111128_a(3.0D);
    }

    protected void entityInit()
    {
        super.entityInit();
        this.getDataWatcher().addObject(12, Byte.valueOf((byte)0));
        this.getDataWatcher().addObject(13, Byte.valueOf((byte)0));
        this.getDataWatcher().addObject(14, Byte.valueOf((byte)0));
    }
    
    public int getTotalArmorValue()
    {
        int i = super.getTotalArmorValue() + 2;

        if (i > 20)
        {
            i = 20;
        }

        return i;
    }
    
    protected boolean isAIEnabled()
    {
        return true;
    }
    
    public boolean isChild()
    {
        return this.getDataWatcher().getWatchableObjectByte(12) == 1;
    }
    
    public void setChild(boolean par1)
    {
        this.getDataWatcher().updateObject(12, Byte.valueOf((byte)(par1 ? 1 : 0)));

        if (this.worldObj != null && !this.worldObj.isRemote)
        {
            AttributeInstance attributeinstance = this.func_110148_a(SharedMonsterAttributes.field_111263_d);
        }
    }
    
    public boolean isVillager()
    {
        return this.getDataWatcher().getWatchableObjectByte(13) == 1;
    }
    
    public void setVillager(boolean par1)
    {
        this.getDataWatcher().updateObject(13, Byte.valueOf((byte)(par1 ? 1 : 0)));
    }
    
    public void onLivingUpdate()
    {
        if (worldObj.skylightSubtracted < 8)
        {
            float f = this.getBrightness(1.0F);

            if (f > 0.5F && this.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.worldObj.canBlockSeeTheSky(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)))
            {
                boolean flag = true;
                ItemStack itemstack = this.getCurrentItemOrArmor(4);

                if (itemstack != null)
                {
                    if (itemstack.isItemStackDamageable())
                    {
                        itemstack.setItemDamage(itemstack.getItemDamageForDisplay() + this.rand.nextInt(2));

                        if (itemstack.getItemDamageForDisplay() >= itemstack.getMaxDamage())
                        {
                            this.renderBrokenItemStack(itemstack);
                            this.setCurrentItemOrArmor(4, (ItemStack)null);
                        }
                    }

                    flag = false;
                }

                if (flag)
                {
                    this.setFire(8);
                }
            }
        }

        super.onLivingUpdate();
    }
    
    public boolean attackEntityFrom(DamageSource par1DamageSource, float par2)
    {
        if (!super.attackEntityFrom(par1DamageSource, par2))
        {
            return false;
        }
        else
        {
            EntityLivingBase entitylivingbase = this.getAttackTarget();

            if (entitylivingbase == null && this.getEntityToAttack() instanceof EntityLivingBase)
            {
                entitylivingbase = (EntityLivingBase)this.getEntityToAttack();
            }

            if (entitylivingbase == null && par1DamageSource.getEntity() instanceof EntityLivingBase)
            {
                entitylivingbase = (EntityLivingBase)par1DamageSource.getEntity();
            }

            if (entitylivingbase != null && this.worldObj.difficultySetting >= 3)
            {
                int i = MathHelper.floor_double(this.posX);
                int j = MathHelper.floor_double(this.posY);
                int k = MathHelper.floor_double(this.posZ);
                EntityZombie entityzombie = new EntityZombie(this.worldObj);

                for (int l = 0; l < 50; ++l)
                {
                    int i1 = i + MathHelper.getRandomIntegerInRange(this.rand, 7, 40) * MathHelper.getRandomIntegerInRange(this.rand, -1, 1);
                    int j1 = j + MathHelper.getRandomIntegerInRange(this.rand, 7, 40) * MathHelper.getRandomIntegerInRange(this.rand, -1, 1);
                    int k1 = k + MathHelper.getRandomIntegerInRange(this.rand, 7, 40) * MathHelper.getRandomIntegerInRange(this.rand, -1, 1);

                    if (this.worldObj.doesBlockHaveSolidTopSurface(i1, j1 - 1, k1) && this.worldObj.getBlockLightValue(i1, j1, k1) < 10)
                    {
                        entityzombie.setPosition((double)i1, (double)j1, (double)k1);

                        if (this.worldObj.checkNoEntityCollision(entityzombie.boundingBox) && this.worldObj.getCollidingBoundingBoxes(entityzombie, entityzombie.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(entityzombie.boundingBox))
                        {
                            this.worldObj.spawnEntityInWorld(entityzombie);
                            entityzombie.setAttackTarget(entitylivingbase);
                            entityzombie.func_110161_a((EntityLivingData)null);
                            break;
                        }
                    }
                }
            }

            return true;
        }
    }
    
    public void onUpdate()
    {
        super.onUpdate();
    }

    public boolean attackEntityAsMob(Entity par1Entity)
    {
        boolean flag = super.attackEntityAsMob(par1Entity);

        if (flag && this.getHeldItem() == null && this.isBurning() && this.rand.nextFloat() < (float)this.worldObj.difficultySetting * 0.3F)
        {
            par1Entity.setFire(2 * this.worldObj.difficultySetting);
        }

        return flag;
    }
    
    protected int getDropItemId()
    {
        return Item.rottenFlesh.itemID;
    }
    
    public EnumCreatureAttribute getCreatureAttribute()
    {
        return EnumCreatureAttribute.UNDEAD;
    }

    protected void dropRareDrop(int par1)
    {
        switch (this.rand.nextInt(3))
        {
            case 0:
                this.dropItem(Item.ingotIron.itemID, 1);
                break;
            case 1:
                this.dropItem(Item.carrot.itemID, 1);
                break;
            case 2:
                this.dropItem(Item.potato.itemID, 1);
        }
    }
    
    protected void addRandomArmor()
    {
        super.addRandomArmor();

        if (this.rand.nextFloat() < (this.worldObj.difficultySetting == 3 ? 0.05F : 0.01F))
        {
            int i = this.rand.nextInt(3);

            if (i == 0)
            {
                this.setCurrentItemOrArmor(0, new ItemStack(Item.swordIron));
            }
            else
            {
                this.setCurrentItemOrArmor(0, new ItemStack(Item.shovelIron));
            }
        }
    }
    
    public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    {
        super.writeEntityToNBT(par1NBTTagCompound);

        if (this.isChild())
        {
            par1NBTTagCompound.setBoolean("IsBaby", true);
        }

        if (this.isVillager())
        {
            par1NBTTagCompound.setBoolean("IsVillager", true);
        }
    }
    
    public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    {
        super.readEntityFromNBT(par1NBTTagCompound);

        if (par1NBTTagCompound.getBoolean("IsBaby"))
        {
            this.setChild(true);
        }

        if (par1NBTTagCompound.getBoolean("IsVillager"))
        {
            this.setVillager(true);
        }

        if (par1NBTTagCompound.hasKey("ConversionTime") && par1NBTTagCompound.getInteger("ConversionTime") > -1)
        {
            this.startConversion(par1NBTTagCompound.getInteger("ConversionTime"));
        }
    }
    
    public void onKillEntity(EntityLivingBase par1EntityLivingBase)
    {
        super.onKillEntity(par1EntityLivingBase);

        if (this.worldObj.difficultySetting >= 2 && par1EntityLivingBase instanceof EntityVillager)
        {
            if (this.worldObj.difficultySetting == 2 && this.rand.nextBoolean())
            {
                return;
            }

            EntityZombie entityzombie = new EntityZombie(this.worldObj);
            entityzombie.copyLocationAndAnglesFrom(par1EntityLivingBase);
            this.worldObj.removeEntity(par1EntityLivingBase);
            entityzombie.func_110161_a((EntityLivingData)null);
            entityzombie.setVillager(true);

            if (par1EntityLivingBase.isChild())
            {
                entityzombie.setChild(true);
            }

            this.worldObj.spawnEntityInWorld(entityzombie);
            this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1016, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
        }
    }
    
    public EntityLivingData func_110161_a(EntityLivingData par1EntityLivingData)
    {
        Object par1EntityLivingData1 = super.func_110161_a(par1EntityLivingData);
        float f = this.worldObj.func_110746_b(this.posX, this.posY, this.posZ);
        this.setCanPickUpLoot(this.rand.nextFloat() < 0.55F * f);


        this.addRandomArmor();
        this.enchantEquipment();

        if (this.getCurrentItemOrArmor(4) == null)
        {
            Calendar calendar = this.worldObj.getCurrentDate();

            if (calendar.get(2) + 1 == 10 && calendar.get(5) == 31 && this.rand.nextFloat() < 0.25F)
            {
                this.setCurrentItemOrArmor(4, new ItemStack(this.rand.nextFloat() < 0.1F ? Block.pumpkinLantern : Block.pumpkin));
                this.equipmentDropChances[4] = 0.0F;
            }
        }

        this.func_110148_a(SharedMonsterAttributes.field_111266_c).func_111121_a(new AttributeModifier("Random spawn bonus", this.rand.nextDouble() * 0.05000000074505806D, 0));
        this.func_110148_a(SharedMonsterAttributes.field_111265_b).func_111121_a(new AttributeModifier("Random zombie-spawn bonus", this.rand.nextDouble() * 1.5D, 2));

        if (this.rand.nextFloat() < f * 0.05F)
        {
            this.func_110148_a(SharedMonsterAttributes.field_111267_a).func_111121_a(new AttributeModifier("Leader zombie bonus", this.rand.nextDouble() * 3.0D + 1.0D, 2));
        }

        return (EntityLivingData)par1EntityLivingData1;
    }
    
    public boolean interact(EntityPlayer par1EntityPlayer)
    {
        ItemStack itemstack = par1EntityPlayer.getCurrentEquippedItem();

        if (itemstack != null && itemstack.getItem() == Item.appleGold && itemstack.getItemDamage() == 0 && this.isVillager() && this.isPotionActive(Potion.weakness))
        {
            if (!par1EntityPlayer.capabilities.isCreativeMode)
            {
                --itemstack.stackSize;
            }

            if (itemstack.stackSize <= 0)
            {
                par1EntityPlayer.inventory.setInventorySlotContents(par1EntityPlayer.inventory.currentItem, (ItemStack)null);
            }

            if (!this.worldObj.isRemote)
            {
                this.startConversion(this.rand.nextInt(2401) + 3600);
            }

            return true;
        }
        else
        {
            return false;
        }
    }
    
    protected void startConversion(int par1)
    {
        this.getDataWatcher().updateObject(14, Byte.valueOf((byte)1));
        this.removePotionEffect(Potion.weakness.id);
        this.addPotionEffect(new PotionEffect(Potion.damageBoost.id, par1, Math.min(this.worldObj.difficultySetting - 1, 0)));
        this.worldObj.setEntityState(this, (byte)16);
    }

    @SideOnly(Side.CLIENT)
    public void handleHealthUpdate(byte par1)
    {
        if (par1 == 16)
        {
            this.worldObj.playSound(this.posX + 0.5D, this.posY + 0.5D, this.posZ + 0.5D, "mob.zombie.remedy", 1.0F + this.rand.nextFloat(), this.rand.nextFloat() * 0.7F + 0.3F, false);
        }
        else
        {
            super.handleHealthUpdate(par1);
        }
    }
    
    protected boolean canDespawn()
    {
        return !this.isConverting();
    }
    
    public boolean isConverting()
    {
        return this.getDataWatcher().getWatchableObjectByte(14) == 1;
    }
    
    protected void convertToVillager()
    {
        EntityVillager entityvillager = new EntityVillager(this.worldObj);
        entityvillager.copyLocationAndAnglesFrom(this);
        entityvillager.func_110161_a((EntityLivingData)null);
        entityvillager.func_82187_q();

        if (this.isChild())
        {
            entityvillager.setGrowingAge(-24000);
        }

        this.worldObj.removeEntity(this);
        this.worldObj.spawnEntityInWorld(entityvillager);
        entityvillager.addPotionEffect(new PotionEffect(Potion.confusion.id, 200, 0));
        this.worldObj.playAuxSFXAtEntity((EntityPlayer)null, 1017, (int)this.posX, (int)this.posY, (int)this.posZ, 0);
    }
    
    protected int getConversionTimeBoost()
    {
        int i = 1;

        if (this.rand.nextFloat() < 0.01F)
        {
            int j = 0;

            for (int k = (int)this.posX - 4; k < (int)this.posX + 4 && j < 14; ++k)
            {
                for (int l = (int)this.posY - 4; l < (int)this.posY + 4 && j < 14; ++l)
                {
                    for (int i1 = (int)this.posZ - 4; i1 < (int)this.posZ + 4 && j < 14; ++i1)
                    {
                        int j1 = this.worldObj.getBlockId(k, l, i1);

                        if (j1 == Block.fenceIron.blockID || j1 == Block.bed.blockID)
                        {
                            if (this.rand.nextFloat() < 0.3F)
                            {
                                ++i;
                            }

                            ++j;
                        }
                    }
                }
            }
        }

        return i;
    }
Следующий код копирует все у зомби. Настроить горение вы можете попробовать в этой части кода (А конкретно worldObj.skylightSubtracted < 8. Именно этот код отвечает за время дня и вызывает горение.):
Код:
public void onLivingUpdate()
    {
        if (worldObj.skylightSubtracted < 8)
        {
            float f = this.getBrightness(1.0F);

            if (f > 0.5F && this.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.worldObj.canBlockSeeTheSky(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)))
            {
                boolean flag = true;
                ItemStack itemstack = this.getCurrentItemOrArmor(4);

                if (itemstack != null)
                {
                    if (itemstack.isItemStackDamageable())
                    {
                        itemstack.setItemDamage(itemstack.getItemDamageForDisplay() + this.rand.nextInt(2));

                        if (itemstack.getItemDamageForDisplay() >= itemstack.getMaxDamage())
                        {
                            this.renderBrokenItemStack(itemstack);
                            this.setCurrentItemOrArmor(4, (ItemStack)null);
                        }
                    }

                    flag = false;
                }

                if (flag)
                {
                    this.setFire(8);
                }
            }
        }

        super.onLivingUpdate();
    }
Продвинутый раздел - Создание бластера
Создайте обыкновенный предмет :
Код:
package assets.testmod.src;

import net.minecraft.item.Item;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid=ModInfo.MODID, name=ModInfo.MODNAME, version=ModInfo.MODVERSION)

public class TestMod
{
    @Mod.Instance(ModInfo.MODID)
    public static TestMod testmod;
    
    public static Item blaster;
    
    @EventHandler
    public void preModLoad(FMLPreInitializationEvent event)
    {
    }
    
    @EventHandler
    public void modLoad(FMLInitializationEvent event)
    {
        blaster = new Blaster(3001).setUnlocalizedName("blaster");
        
        LanguageRegistry.addName(blaster, "Blaster");
    }
    
    @EventHandler
    public void postModLoad(FMLPostInitializationEvent event)
    {
    }
}
Теперь создайте файл Blaster.java. Внутрь пишите:
Код:
package assets.testmod.src;

import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;

public class Blaster extends Item
{

    public Blaster(int id)
    {
        super(id);
        this.setCreativeTab(CreativeTabs.tabCombat);
        this.setFull3D();
    }
    
    public void registerIcons(IconRegister tex)
    {
        this.itemIcon = tex.registerIcon(ModInfo.MODID + ":blaster");
    }
    
    public ItemStack onItemRightClick(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer)
    {
        EntityBlasterBullet blasterBullet = new EntityBlasterBullet(par2World, par3EntityPlayer, 2.0F);
        par2World.spawnEntityInWorld(blasterBullet);
        return par1ItemStack;
    }
    
}
Тут все понятно. При нажатии правой кнопки создается объект плазмы и затем он же создается в мире (это разные вещи). Теперь создайте файл EntityBlasterBullet.java
Код:
package assets.testmod.src;

import java.util.List;

import net.minecraft.block.Block;
import net.minecraft.enchantment.EnchantmentThorns;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IProjectile;
import net.minecraft.entity.monster.EntityEnderman;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.packet.Packet70GameEvent;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.Explosion;
import net.minecraft.world.World;

public class EntityBlasterBullet extends Entity implements IProjectile
{

    private int xTile = -1;
    private int yTile = -1;
    private int zTile = -1;
    private int inTile;
    private int inData;
    private boolean inGround;

    /** 1 if the player can pick up the arrow */
    public int canBePickedUp;

    /** Seems to be some sort of timer for animating an arrow. */
    public int arrowShake;

    /** The owner of this arrow. */
    public Entity shootingEntity;
    private int ticksInGround;
    private int ticksInAir;
    
    public EntityBlasterBullet(World par1World, EntityLivingBase par2EntityLivingBase, float par3)
    {
        super(par1World);
        this.renderDistanceWeight = 10.0D;
        this.shootingEntity = par2EntityLivingBase;

        if (par2EntityLivingBase instanceof EntityPlayer)
        {
            this.canBePickedUp = 1;
        }

        this.setSize(0.5F, 0.5F);
        this.setLocationAndAngles(par2EntityLivingBase.posX, par2EntityLivingBase.posY + (double)par2EntityLivingBase.getEyeHeight(), par2EntityLivingBase.posZ, par2EntityLivingBase.rotationYaw, par2EntityLivingBase.rotationPitch);
        this.posX -= (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F);
        this.posY -= 0.10000000149011612D;
        this.posZ -= (double)(MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F);
        this.setPosition(this.posX, this.posY, this.posZ);
        this.yOffset = 0.0F;
        this.motionX = (double)(-MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI));
        this.motionZ = (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI));
        this.motionY = (double)(-MathHelper.sin(this.rotationPitch / 180.0F * (float)Math.PI));
        this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, par3 * 1.5F, 1.0F);
    }

    @Override
    public void setThrowableHeading(double par1, double par3, double par5, float par7, float par8)
    {
        float f2 = MathHelper.sqrt_double(par1 * par1 + par3 * par3 + par5 * par5);
        par1 /= (double)f2;
        par3 /= (double)f2;
        par5 /= (double)f2;
        par1 += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)par8;
        par3 += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)par8;
        par5 += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)par8;
        par1 *= (double)par7;
        par3 *= (double)par7;
        par5 *= (double)par7;
        this.motionX = par1;
        this.motionY = par3;
        this.motionZ = par5;
        float f3 = MathHelper.sqrt_double(par1 * par1 + par5 * par5);
        this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(par1, par5) * 180.0D / Math.PI);
        this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(par3, (double)f3) * 180.0D / Math.PI);
        this.ticksInGround = 0;
    }

    @Override
    protected void entityInit()
    {
        
    }

    @Override
    protected void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    {
        this.xTile = par1NBTTagCompound.getShort("xTile");
        this.yTile = par1NBTTagCompound.getShort("yTile");
        this.zTile = par1NBTTagCompound.getShort("zTile");
        this.inTile = par1NBTTagCompound.getByte("inTile") & 255;
        this.inData = par1NBTTagCompound.getByte("inData") & 255;
        this.arrowShake = par1NBTTagCompound.getByte("shake") & 255;
        this.inGround = par1NBTTagCompound.getByte("inGround") == 1;

        if (par1NBTTagCompound.hasKey("pickup"))
        {
            this.canBePickedUp = par1NBTTagCompound.getByte("pickup");
        }
        else if (par1NBTTagCompound.hasKey("player"))
        {
            this.canBePickedUp = par1NBTTagCompound.getBoolean("player") ? 1 : 0;
        }
    }

    @Override
    protected void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    {
        par1NBTTagCompound.setShort("xTile", (short)this.xTile);
        par1NBTTagCompound.setShort("yTile", (short)this.yTile);
        par1NBTTagCompound.setShort("zTile", (short)this.zTile);
        par1NBTTagCompound.setByte("inTile", (byte)this.inTile);
        par1NBTTagCompound.setByte("inData", (byte)this.inData);
        par1NBTTagCompound.setByte("shake", (byte)this.arrowShake);
        par1NBTTagCompound.setByte("inGround", (byte)(this.inGround ? 1 : 0));
        par1NBTTagCompound.setByte("pickup", (byte)this.canBePickedUp);
    }
    
    public void setVelocity(double par1, double par3, double par5)
    {
        this.motionX = par1;
        this.motionY = par3;
        this.motionZ = par5;

        if (this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F)
        {
            float f = MathHelper.sqrt_double(par1 * par1 + par5 * par5);
            this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(par1, par5) * 180.0D / Math.PI);
            this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(par3, (double)f) * 180.0D / Math.PI);
            this.prevRotationPitch = this.rotationPitch;
            this.prevRotationYaw = this.rotationYaw;
            this.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch);
            this.ticksInGround = 0;
        }
    }
    
    public boolean isInvulnerable()
    {
        return this.dataWatcher.getWatchableObjectByte(10) == 1;
    }
    
    public void onUpdate()
    {
        super.onUpdate();

        if (this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F)
        {
            float f = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ);
            this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(this.motionX, this.motionZ) * 180.0D / Math.PI);
            this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(this.motionY, (double)f) * 180.0D / Math.PI);
        }

        int i = this.worldObj.getBlockId(this.xTile, this.yTile, this.zTile);

        if (i > 0)
        {
            Block.blocksList[i].setBlockBoundsBasedOnState(this.worldObj, this.xTile, this.yTile, this.zTile);
            AxisAlignedBB axisalignedbb = Block.blocksList[i].getCollisionBoundingBoxFromPool(this.worldObj, this.xTile, this.yTile, this.zTile);
            this.worldObj.newExplosion(this, this.posX, this.posY, this.posZ, 10.0F, false, this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing"));
            this.setDead();
        }
        
        if (this.arrowShake > 0)
        {
            --this.arrowShake;
        }

        if (this.inGround)
        {
            int j = this.worldObj.getBlockId(this.xTile, this.yTile, this.zTile);
            int k = this.worldObj.getBlockMetadata(this.xTile, this.yTile, this.zTile);

            if (j == this.inTile && k == this.inData)
            {
                ++this.ticksInGround;

                if (this.ticksInGround == 1200)
                {
                    this.setDead();
                }
            }
            else
            {
                this.inGround = false;
                this.motionX *= (double)(this.rand.nextFloat() * 0.2F);
                this.motionY *= (double)(this.rand.nextFloat() * 0.2F);
                this.motionZ *= (double)(this.rand.nextFloat() * 0.2F);
                this.ticksInGround = 0;
                this.ticksInAir = 0;
            }
        }
        else
        {
            ++this.ticksInAir;
            Vec3 vec3 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ);
            Vec3 vec31 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ);
            MovingObjectPosition movingobjectposition = this.worldObj.rayTraceBlocks_do_do(vec3, vec31, false, true);
            vec3 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ);
            vec31 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ);

            if (movingobjectposition != null)
            {
                vec31 = this.worldObj.getWorldVec3Pool().getVecFromPool(movingobjectposition.hitVec.xCoord, movingobjectposition.hitVec.yCoord, movingobjectposition.hitVec.zCoord);
            }

            Entity entity = null;
            List list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.addCoord(this.motionX, this.motionY, this.motionZ).expand(1.0D, 1.0D, 1.0D));
            double d0 = 0.0D;
            int l;
            float f1;

            if (movingobjectposition != null && movingobjectposition.entityHit != null && movingobjectposition.entityHit instanceof EntityPlayer)
            {
                EntityPlayer entityplayer = (EntityPlayer)movingobjectposition.entityHit;

                if (entityplayer.capabilities.disableDamage || this.shootingEntity instanceof EntityPlayer && !((EntityPlayer)this.shootingEntity).func_96122_a(entityplayer))
                {
                    movingobjectposition = null;
                }
            }

            float f2;
            float f3;

            if (movingobjectposition != null)
            {
                if (movingobjectposition.entityHit != null)
                {
                    f2 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionY * this.motionY + this.motionZ * this.motionZ);
                    int i1 = MathHelper.ceiling_double_int((double)f2);

                    if (this.isBurning() && !(movingobjectposition.entityHit instanceof EntityEnderman))
                    {
                        movingobjectposition.entityHit.setFire(5);
                    }
                    else
                    {
                        this.motionX *= -0.10000000149011612D;
                        this.motionY *= -0.10000000149011612D;
                        this.motionZ *= -0.10000000149011612D;
                        this.rotationYaw += 180.0F;
                        this.prevRotationYaw += 180.0F;
                        this.ticksInAir = 0;
                    }
                }
                else
                {
                    this.xTile = movingobjectposition.blockX;
                    this.yTile = movingobjectposition.blockY;
                    this.zTile = movingobjectposition.blockZ;
                    this.inTile = this.worldObj.getBlockId(this.xTile, this.yTile, this.zTile);
                    this.inData = this.worldObj.getBlockMetadata(this.xTile, this.yTile, this.zTile);
                    this.motionX = (double)((float)(movingobjectposition.hitVec.xCoord - this.posX));
                    this.motionY = (double)((float)(movingobjectposition.hitVec.yCoord - this.posY));
                    this.motionZ = (double)((float)(movingobjectposition.hitVec.zCoord - this.posZ));
                    f2 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionY * this.motionY + this.motionZ * this.motionZ);
                    this.playSound("random.bowhit", 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F));
                    this.inGround = true;
                    this.arrowShake = 7;

                    if (this.inTile != 0)
                    {
                        Block.blocksList[this.inTile].onEntityCollidedWithBlock(this.worldObj, this.xTile, this.yTile, this.zTile, this);
                    }
                }
            }

            this.posX += this.motionX;
            this.posY += this.motionY;
            this.posZ += this.motionZ;
            f2 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ);
            this.rotationYaw = (float)(Math.atan2(this.motionX, this.motionZ) * 180.0D / Math.PI);

            float f4 = 0.99F;
            f1 = 0.00F;

            if (this.isInWater())
            {
                for (int j1 = 0; j1 < 4; ++j1)
                {
                    f3 = 0.25F;
                    this.worldObj.spawnParticle("bubble", this.posX - this.motionX * (double)f3, this.posY - this.motionY * (double)f3, this.posZ - this.motionZ * (double)f3, this.motionX, this.motionY, this.motionZ);
                }

                f4 = 0.8F;
            }

            this.motionX *= (double)f4;
            this.motionY *= (double)f4;
            this.motionZ *= (double)f4;
            this.motionY -= (double)f1;
            this.setPosition(this.posX, this.posY, this.posZ);
            this.doBlockCollisions();
        }
    }
    
    protected void onImpact(MovingObjectPosition par1MovingObjectPosition)
    {
        if (!this.worldObj.isRemote)
        {
            if (par1MovingObjectPosition.entityHit != null)
            {
                if (this.shootingEntity != null)
                {

                }
                else
                {
                    par1MovingObjectPosition.entityHit.attackEntityFrom(DamageSource.magic, 5.0F);
                }

                if (par1MovingObjectPosition.entityHit instanceof EntityLivingBase)
                {
                    byte b0 = 0;

                    if (this.worldObj.difficultySetting > 1)
                    {
                        if (this.worldObj.difficultySetting == 2)
                        {
                            b0 = 10;
                        }
                        else if (this.worldObj.difficultySetting == 3)
                        {
                            b0 = 40;
                        }
                    }

                    if (b0 > 0)
                    {
                        ((EntityLivingBase)par1MovingObjectPosition.entityHit).addPotionEffect(new PotionEffect(Potion.wither.id, 20 * b0, 1));
                    }
                }
            }

            this.worldObj.newExplosion(this, this.posX, this.posY, this.posZ, 1.0F, false, this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing"));
            this.setDead();
        }
    }
}
Предупреждаю! Код недоработан (есть баги с непроходимыми областями после взрыва!). Теперь при нажатии правой кнопки с бластером в руке создается плазмовая пуля и полетит по прямой, пока не столкнется с любым блоком. Столкнувшись с ним пуля взорвется (this.worldObj.newExplosion(this, this.posX, this.posY, this.posZ, 1.0F, false, this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing"));).
В этой главе сделаем наш бластер 3Dэшным.
Для этого пропишите в файле предмета, под super(par1) :
Код:
MinecraftForgeClient.registerItemRenderer(this.itemID, (IItemRenderer) new BlasterRender());
        this.setFull3D();
Верхняя строчка добавляет рендер бластеру, а нижняя отображает его в 3D.
Теперь создайте файл BlasterRender.java. Внутрь запилите :
Код:
package assets.testmod.src;

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiContainerCreative;
import net.minecraft.client.gui.inventory.GuiInventory;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.IItemRenderer;

import org.lwjgl.opengl.GL11;

public class BlasterRender implements IItemRenderer
{
    protected BlasterModel launcherModel;
    
    public BlasterRender()
    {
        launcherModel = new BlasterModel();
    }
    
    @Override
    public boolean handleRenderType(ItemStack item, ItemRenderType type) {
        switch(type)
        {
            case EQUIPPED: return true;
            default: return false;
        }
    }
    
    @Override
    public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper) 
    {
        return false;
    }
    
    @Override
    public void renderItem(ItemRenderType type, ItemStack item, Object... data) 
    {
        switch(type)
        {
        case EQUIPPED:
            {
                GL11.glPushMatrix();
                Minecraft.getMinecraft().renderEngine.func_110577_a(new ResourceLocation ("testmod", "textures/models/blasterModelTexture.png"));
                GL11.glRotatef(150F, 1F, 0F, 0F);
                GL11.glRotatef(65F, -10F, 1F, 0F);
                GL11.glRotatef(-80F, 0F, 0F, 1F);
                
                boolean isFirstPirson = true;
                if(data[1] != null && data[1] instanceof EntityPlayer)
                {
                    if(!((EntityPlayer)data[1] == Minecraft.getMinecraft().renderViewEntity && Minecraft.getMinecraft().gameSettings.thirdPersonView == 0 && !((Minecraft.getMinecraft().currentScreen instanceof GuiInventory || Minecraft.getMinecraft().currentScreen instanceof GuiContainerCreative) && RenderManager.instance.playerViewY == 180.0F)));
                    {
                        GL11.glTranslatef(-0.F, -0.0F, -0.0F);
                    }
                }
                else
                {
                    isFirstPirson = true;
                }
                
                GL11.glTranslatef(0.1F, 0.5F, -0.8F);
                float scale = 1.0F;
                GL11.glScalef(2.0F, 2.0F, 2.0F);
                launcherModel.render((Entity)data[1], 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0625F, isFirstPirson);
                GL11.glPopMatrix();
                
            }
            default:
                break;
        }
    }

}
Этот код задает размеры, угол наклона бластера и другое. Сразу говорю, что для каждой модели этот код разный!
Теперь создайте файл BlasterModel.java :
Код:
package assets.testmod.src;

import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;

public class BlasterModel extends ModelBase
{
    ModelRenderer Shape1;
    ModelRenderer Shape2;
    ModelRenderer Shape3;
    ModelRenderer Shape4;
    ModelRenderer Shape5;
    ModelRenderer Shape6;
    ModelRenderer Shape7;
  
  public BlasterModel()
  {
    textureWidth = 64;
    textureHeight = 32;
    
      Shape1 = new ModelRenderer(this, 0, 0);
      Shape1.addBox(0F, 0F, 0F, 3, 1, 8);
      Shape1.setRotationPoint(-1F, 0F, -5F);
      Shape1.setTextureSize(64, 32);
      Shape1.mirror = true;
      setRotation(Shape1, 0F, 0F, 0F);
      Shape2 = new ModelRenderer(this, 0, 0);
      Shape2.addBox(0F, 0F, 0F, 1, 1, 8);
      Shape2.setRotationPoint(1F, -1F, -5F);
      Shape2.setTextureSize(64, 32);
      Shape2.mirror = true;
      setRotation(Shape2, 0F, 0F, 0F);
      Shape3 = new ModelRenderer(this, 0, 0);
      Shape3.addBox(0F, 0F, 0F, 1, 1, 8);
      Shape3.setRotationPoint(-1F, -1F, -5F);
      Shape3.setTextureSize(64, 32);
      Shape3.mirror = true;
      setRotation(Shape3, 0F, 0F, 0F);
      Shape4 = new ModelRenderer(this, 0, 0);
      Shape4.addBox(0F, 0F, 0F, 3, 1, 8);
      Shape4.setRotationPoint(-1F, -2F, -5F);
      Shape4.setTextureSize(64, 32);
      Shape4.mirror = true;
      setRotation(Shape4, 0F, 0F, 0F);
      Shape5 = new ModelRenderer(this, 0, 0);
      Shape5.addBox(0F, 0F, 0F, 1, 1, 1);
      Shape5.setRotationPoint(0F, -1F, 3F);
      Shape5.setTextureSize(64, 32);
      Shape5.mirror = true;
      setRotation(Shape5, 0F, 0F, 0F);
      Shape6 = new ModelRenderer(this, 0, 0);
      Shape6.addBox(0F, 0F, 0F, 1, 1, 1);
      Shape6.setRotationPoint(0F, -2F, 4F);
      Shape6.setTextureSize(64, 32);
      Shape6.mirror = true;
      setRotation(Shape6, 0F, 0F, 0F);
      Shape7 = new ModelRenderer(this, 0, 28);
      Shape7.addBox(0F, 0F, 0F, 1, 3, 1);
      Shape7.setRotationPoint(0F, 0F, 4F);
      Shape7.setTextureSize(64, 32);
      Shape7.mirror = true;
      setRotation(Shape7, 0.2230717F, 0F, 0F);
  }
  
  public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5, boolean isFirstPirson)
  {
    super.render(entity, f, f1, f2, f3, f4, f5);
    setRotationAngles(f, f1, f2, f3, f4, f5, entity);
    Shape1.render(f5);
    Shape2.render(f5);
    Shape3.render(f5);
    Shape4.render(f5);
    Shape5.render(f5);
    Shape6.render(f5);
    Shape7.render(f5);
  }
  
  private void setRotation(ModelRenderer model, float x, float y, float z)
  {
    model.rotateAngleX = x;
    model.rotateAngleY = y;
    model.rotateAngleZ = z;
  }
  
  public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity ent)
  {
    super.setRotationAngles(f, f1, f2, f3, f4, f5, ent);
  }
}
Свою модель можете создать в программке создания моделей для Minecraft – Techne (http://techne.zeux.me/Techne/ApplicationDownload).
Рассказывать как работать в Techne я буду в отдельной главе.
Итак вы создали модель. И експортировали ее в Java файл (File>Export as…>Java).
Далее копируете код модели в файл BlasterModel. Теперь вам надо дописать пару словечек в готовый файл.
Во первых, замените експортированный метод setRotationAngles, приведенным методом выше.
Во вторых, замените експортированный метод render, приведенным в коде выше и добавьте свои части моделей (у меня модель состоит из 7 кусков (Shape1,Shape2 и т.д.). Вы естественно добавьте ниже свои.
 
60
0
GUI
Сначала нужно создать класс GuiHandler :
Код:
public class GuiHandler implements IGuiHandler {

    @Override
    public Object getServerGuiElement(int guiID, EntityPlayer player, World world, int x, int y, int z){
        switch(guiID){
            case 0:
                return new MyGui();
            default:
                return null;
        }
    }
    @Override
    public Object getClientGuiElement(int guiID, EntityPlayer player, World world, int x, int y, int z) {
        switch(guiID){
            case 0:
                return new MyGui();
            default:
                return null;
        }
    }
}
Этот класс возвращает нам сам GUI. Но перед созданием GUI нужно сей класс зарегистрировать. В главном классе в init(FMLInitializationEvent event) пишем такую строку :
Код:
NetworkRegistry.instance().registerGuiHandler(this.instance, new GuiHandler());
Нажимаем CTRL+SHIFT+O.
Теперь создаем класс MyGui :
Код:
public class MyGui extends GuiScreen
{
    public MyGui(){
        super();
    }
    @Override
         public void initGui() {
            super.initGui();
        }
    @Override
    protected void keyTyped(char par1, int par2){
        if (par2 == 1 || par2 == this.mc.gameSettings.keyBindInventory.keyCode)
        {
            this.mc.thePlayer.closeScreen();
        }
    }
}
keyTyped - этот метод реагирует на нажатие клавиш, в нашем случае, кнопку инвентаря (this.mc.gameSettings.keyBindInventory.keyCode) и в нашем случае закрывает GUI.
Чтобы вызвать наш GUI воспользуйтесь методом player.openGui(TestMod.instance, guiID, world, x, y, z). Его можно вставить в предмет или в блок, или в ,просто, какое-нибудь событие, которое вас интересует. Это может быть даже событие на попадание пули в кого-то (или во что-то), смотря какую цель вы преследуете.
Итак, чтобы нарисовать на экране что-то, надо вставить такой метод в наш класс MyGui:
Код:
@Override
public void drawScreen(int par1, int par2, float par3){
            
}
Чтобы нарисовать слово надо написать в этом методе : fontRenderer.drawString("Слово", x, y, Color);
x,y - позиция. Color - это цвет, например зелеленый: 0x99FF00.
Теперь когда вы вызовите открытие Gui, у вас остановится игра. Чтобы жизнь в мире текла своей обыденностью, вставьте в MyGui
Код:
public boolean doesGuiPauseGame()
    {
        return false;
    }
Полезное (Коды, Советы и т.п.)
Создать свой биом довольно легко.
В регистрах пишем:
Код:
GameRegistry.addBiome(new TestBiome(30));
Создаем класс TestBiome и пишем в него:
Код:
package assets.testmod.src;

import net.minecraft.block.Block;
import net.minecraft.world.biome.BiomeGenBase;

public class TestBiome extends BiomeGenBase {

    public TestBiome(int par1) {
        super(par1);
        this.biomeName = "Test Biome";
        this.topBlock = (byte)Block.blockLapis.blockID;
        this.fillerBlock = (byte)Block.blockDiamond.blockID;
    }

}
другие свойства биомов вы можете найти написал новый this., а также щелчком с зажатым Ctrl по напдиси BiomeGenBase.
Разберем:
biomeName = имя биома
topBlock = верхний блок (трава в Minecraft)
fillerBlock = 4 блока (грязи) под topBlock (травой).
Учтите, что topBlock и fillerBlock могут быть блоками с айди не более 256!
Открыв файл BiomeGenHills.java вы можете увидеть код генерации изумрудов и написать такой же себе.
Если вы что-то забыли про текстуры и вам неудобно рыться в главе про создание блока в поисках ответа, можете заглянуть сюда.
Путь к текстуре всегда прописывается в файле предмета (будь то блок или итем). Обычно он выглядит так :
Код:
@SideOnly(Side.CLIENT)
    public void registerIcons(IconRegister ir)
    {
    this.blockIcon = ir.registerIcon(ModInfo.MODID + ":testBlock");
    }
Пройдите по пути ваша созданная папка>mcp>src>minecraft>assets>testmod (или ваш пакет). В ней создайте папку textures и внутри нее создайте папки items и blocks. Вот и все. Если вы создали блок, то кидаете текстуру с именем testBlock (как в примере или свое) в папку blocks если же итем, то в items.
Ну а теперь гвоздь программы! То, зачем вы и открыли эту главу (наверное) – анимированные текстуры!
Ничего сложного в их создании нет.
Предположим, мы хотим анимировать блок. Текстура нашего блока называется testBlock.png. Ее размер (скорее всего) 16×16. А теперь главное понять принцип. Эту текстуру примем за 0. Теперь в любом графическом редакторе (лучше конечно Photoshop) увеличиваем высоту нашей картинки вдвое, тобишь размер станет 16×32. Получается у нас есть место для 2 блоков. Рисуем 2 блок сразу под первым. Его номер 1. И так далее делайте сколько хотите. Если ваша анимация состоит из 4 картинок, то размер картинки должен быть 16x(16*4) – 16×64. Вот и все текстура готова. Имя и расположение то же, что и обычная текстура блока.
Теперь создадим файл проигрывания нашей анимации. Не пугайтесь, ничего сложного тут нет. В той же папке, где находится текстура создайте файл с расширение .mcmeta (создайте txt-блокнот файл, затем Сохранить как>все файлы>имятекстуры.mcmeta. Затем, готовый .mcmeta файл откройте блокнотом и впишите внутрь
{
“animation”: {}
}

Вуаля – анимация готова и у вашего блока появилась красивая анимированная текстура!
{
“animation”: {
“frametime”: 3
}
}

А данный код внутри замедлит вашу анимацию. Вообще поройтесь в стандартных текстурах. Там есть пара анимированных текстур.
Теперь немного о том, как изменить скорость и последовательность анимации.
Теперь наверняка все хочется проверить, что же получилось? Как же выглядит долгожданный блок? Сделать это очень легко.
В верхней панели есть зеленый кружок с белым треугольничком, повернутым направо. Жмем и у нас запускается игра! И если весь код написан правильно, то игра благополучно запустится и вы увидет свой первый мод в действии.
Но вам хочется идти дальше и создать готовый мод, чтобы можно было скидывать его друзьям и делать еще кучу других вещей. Это также просто.
Заходим в созданную нами папку. Проходим в папку mcp и запускаем файл recompile.bat. Этот файл в финальный раз проверит наш мод на наличие ошибок. Их не должно быть. Если они и есть, то консоль укажет где именно. После успешного завершения рекомпиляции запустите файл reobfuscate.bat. Именно он создаст наш готовый мод! После успешного окончания в этой же папке появится новая папка reobuf. В ней заходите в папку minecraft>assets>testmod и кладете туда папку textures (со всеми текстурами). Теперь эту папку assets пихаем в zip архив, ну а дальше в папку mods уже в реальном minecraft!
Хотите создать свою вкладку в креативе, чтобы складывать туда свои блоки и итемы.
Все там же, где мы создаем блоки и итемы пишем:
Код:
public static CreativeTabs tabTest = new TabTest(CreativeTabs.getNextID(),"TestCreativeTab");
В этой главе мы создадим собственно растение. Свойства у него будут как у пшеницы.
Итак для начала нужно создать блок testPlant, который и будет самим блоком растения и предмет testSeeds, который будет являться семенами для выращивания растения.
Там где создавали блоки пишем:
Код:
public static Block testPlant = new testPlant(2040).setUnlocalizedName("testPlant");
    public static Item testSeeds = new testSeeds(2041).setUnlocalizedName("tomatoSeeds");
Если вы проходили главу про создание блоков вопросов возникнуть не должно.
В регистрах регистрируем наш блок и даем имя семенам:
Код:
GameRegistry.registerBlock(testPlant);
LanguageRegistry.addName(testSeeds, "Test Seeds");
Создаем файлы testPlant.java и testSeeds.
Код:
package assets.testmod.src;

import net.minecraft.block.Block;
import net.minecraft.block.BlockCrops;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.item.Item;
import net.minecraft.util.Icon;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeDirection;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

public class testPlant extends BlockCrops {

    private Icon[] iconArray;

    protected testPlant(int id) {
        super(id);
    }

    @SideOnly(Side.CLIENT)

    public Icon getIcon(int par1, int par2)
    {
        if (par2 < 0 || par2 > 3)
        {
            par2 = 3;
        }

        return this.iconArray[par2];
    }

    public boolean canBlockStay(World par1World, int par2, int par3, int par4)
    {
        return par1World.getBlockId(par2, par3-1, par4)==Block.tilledField.blockID;
    }

    public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
    {
        return par1World.getBlockId(par2, par3-1, par4)==Block.tilledField.blockID;
    }

    protected int getSeedItem()
    {
        return TestMod.testSeeds.itemID;
    }

    protected int getCropItem()
    {
        return Item.axeDiamond.itemID;
    }

    @SideOnly(Side.CLIENT)

    public void registerIcons(IconRegister par1IconRegister)
    {
        this.iconArray = new Icon[4];

        for (int i = 0; i < this.iconArray.length; ++i)
        {
            this.iconArray[i] = par1IconRegister.registerIcon(ModInfo.MODID + ":testPlant_" + i);
        }
    }

}
Итак начнем разбирать код:
Код:
public boolean canBlockStay(World par1World, int par2, int par3, int par4)
    {
        return par1World.getBlockId(par2, par3-1, par4)==Block.tilledField.blockID;
    }

    public boolean canPlaceBlockAt(World par1World, int par2, int par3, int par4)
    {
        return par1World.getBlockId(par2, par3-1, par4)==Block.tilledField.blockID;
    }
Block.tilledField.blockID – измените на любой блок (и сверху и снизу!). На том блоке, который вы выбрали можно будет выращивать ваше растение (к примеру Block.blockDiamond.blockID – на алмазном блоке).
Код:
protected int getSeedItem()
    {
        return TestMod.testSeeds.itemID;
    }
TestMod.testSeeds.itemID – семена для выращивания блока.
Код:
protected int getCropItem()
    {
        return Item.axeDiamond.itemID;
    }
Item.axeDiamond.itemID – дроп с полностью выращенного растения.
Код:
this.iconArray = new Icon[4];

        for (int i = 0; i < this.iconArray.length; ++i)
        {
            this.iconArray[i] = par1IconRegister.registerIcon(ModInfo.MODID + ":testPlant_" + i);
        }
Это массив из 4 элементов. Соответственно в blocks должно быть 4 текстуры стадии роста растения (testPlant_0.png, testPlant_1.png, testPlant_2.png, testPlant_3.png).
Теперь testSeeds.java :
Код:
package assets.testmod.src;

import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemReed;

public class testSeeds extends ItemReed {

    public testSeeds(int par1) {
        super(par1, TestMod.testPlant);
        this.setCreativeTab(CreativeTabs.tabMaterials);
    }

    @Override

    public void registerIcons(IconRegister par1IconRegister)
    {
                                    this.itemIcon = par1IconRegister.registerIcon(ModInfo.MODID + ":testSeeds");
    }

}
Разберем сий код:
super(par1, TestMod.testPlant); – что выращивают семена.
this.setCreativeTab(CreativeTabs.tabMaterials); – креативная вкладочка.
(ModInfo.MODID + “:testSeeds”); – текстура.
Ну и в регистры можете добавить строку
Эта строка добавляет дроп с травы :
Код:
MinecraftForge.addGrassSeed(new ItemStack(OresPlantsBase.ironSeeds), 10);
10 – редкость выпадания как у пшеницы
Вот так выглядит TestMod.java :
Код:
package assets.testmod.src;

import net.minecraft.block.Block;
import net.minecraft.item.Item;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;

@Mod(modid=ModInfo.MODID, name=ModInfo.MODNAME, version=ModInfo.MODVERSION)

public class TestMod {

    public static Block testPlant = new testPlant(3000).setUnlocalizedName("testPlant");
    public static Item testSeeds = new testSeeds(3001).setUnlocalizedName("tomatoSeeds");

    @Mod.Instance(ModInfo.MODID)
    public static TestMod testmod;

    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        GameRegistry.registerBlock(testPlant);
        LanguageRegistry.addName(testSeeds, "Test Seeds");
    }
}
Вот собственно и все – растение готово. Теперь можете сажать вашу алмазную пшеницу на алмазные блоки!:)
В регистрах пишем :
Код:
ChestGenHooks.addItem(ChestGenHooks.BONUS_CHEST, new WeightedRandomChestContent(new ItemStack(TestMod.testItem), 10, 30, 1));
BONUS_CHEST – категория, куда добавляется ваш предмет.
Все категории в игре на 1.5.2 можно посмотреть в eclipse, просто напишите где-нибудь ChestGenHooks и поставьте точку, вам выдадут все возможные варианты.
(TestMod.testItem) – собственно сам предмет.
10, 30, 1 – минимальный шанс появления, максимальный шанс, максимальное количество в сундуке.
Все просто.
Если строка создания блока выглядит так :
public static final Block testBlock = new TestBlock(2020).setUnlocalizedName("testBlock");
Удаляем все от конца включая =. Но ; оставьте. Теперь запись выглядит так :
public static final Block testBlock;
Ниже пишем ID:
public static int testBlockblockID;
Там где все регистры пишем удаленную часть из строки создания блока :
testBlock = new TestBlock(testBlockblockID,0).setUnlocalizedName("testBlock");
Но как вы заметили вместо id пишем уже созданный testBlockblockID.
Прописываем регистры, как в главе про создание блока.
Теперь в самом низу, в preInit пишем:
Код:
Configuration config = new Configuration(event.getSuggestedConfigurationFile());
config.load();//Писать надо только между load и save:
testBlockblockID = config.getBlock("testBlock", 2021).getInt();
config.save();
Вот собственно и все. С итемом также.
Так выглядит TestMod.java :
Код:
package assets.testmod.src;

import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.Configuration;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.Mod.PostInit;
import cpw.mods.fml.common.Mod.PreInit;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
import cpw.mods.fml.common.network.NetworkMod.SidedPacketHandler;
import cpw.mods.fml.common.SidedProxy;

@Mod (modid = "TestMod", name = "Test Mod", version = "0.0.1")
@NetworkMod (clientSideRequired = true, serverSideRequired = false, versionBounds = "1.0.0")

public class TestMod {
public static Block testBlock ;
public static int testBlockblockID;

@Instance(ModInfo.MODID)
public static TestModBase instance;

@EventHandler
public void load(FMLInitializationEvent event)
{
testBlock = new TestBlock(testBlockblockID,0).setUnlocalizedName("testBlock");

GameRegistry.registerBlock(testBlock);
LanguageRegistry.addName(testBlock, "Test Block");
}

@EventHandler
public void load(FMLPreInitializationEvent event)
{

}

@EventHandler
public void preLoad(FMLPreInitializationEvent event)
{
Configuration config = new Configuration(event.getSuggestedConfigurationFile());
config.load();
testBlockblockID = config.getBlock("testBlock", 2021).getInt();
config.save();
}

}
В этой главе я расскажу, как сделать добавление блоков и другого контента через отдельный файл. Ведь если вы создаете большой мод, то полезно разделять блоки в один файл, предметы в другой и т.д.
Приступим.
Начнем с распределения блоков.
В регистрах пишем BlocksList.blocks();
Теперь создаем новый пакет (например assets.testmod.src.block) и создаем в нем класс BlocksList (можно пакет не создавать, а просто создать класс).
Внутри класса BlocksList мы и будем, создавать, регистрировать, и давать имена блокам. И все это почти никак не связано с TestMod.java!
Вот TestMod.java:
Код:
package assets.testmod.src;

import assets.testmod.src.block.BlockList;
import assets.testmod.src.item.ItemList;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;

@Mod(modid=ModInfo.MODID, name=ModInfo.MODNAME, version=ModInfo.MODVERSION)

public class TestMod {
    @Mod.Instance(ModInfo.MODID)
    public static TestMod testmod;

    @EventHandler
    public void init(FMLInitializationEvent event)
    {
        BlocksList.blocks();
    }
}
Как видите он пустой.
Вот пример кода файла BlocksList с комментариями для 3 блоков :
Код:
package assets.testmod.src.block;

import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
import net.minecraft.block.Block;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.oredict.OreDictionary;

public class BlockList {

    /*
     * Здесь создаем блоки
     */
    public static Block blockTest;
    public static Block blockTest2;
    public static Block blockTest3;

    public static void blocks()
    {
        /*
         * Инициализируем блоки
         */
        blockTest = new BlockTest(3000).setUnlocalizedName("blockTest");
        blockTest2 = new BlockTest2(3001).setUnlocalizedName("blockTest2");
        blockTest3 = new BlockTest3(3002).setUnlocalizedName("blockTest3");

        /*
         * Регистрируем блоки
         */
        GameRegistry.registerBlock(blockTest);
        GameRegistry.registerBlock(blockTest2);
        GameRegistry.registerBlock(blockTest3);

        /*
         * Имя блоков в игре
         */
        LanguageRegistry.addName(blockTest, "Test Block 1");
        LanguageRegistry.addName(blockTest2, "Test Block 2");
        LanguageRegistry.addName(blockTest3, "Test Block 3");
    }

}
Ну а файлы BlockTest.java, BlockTest2.java, BlockTest3.java создадите сами (см. Создание блока).
Теперь распределим итемсы.
Опять же в регистрах пишем:
ItemsList.items();
TestMod.java показывать не буду, просто вставьте этот код под или вместо BlocksList.blocks();
Теперь создаем новый пакет (например assets.testmod.src.item) и создаем в нем класс ItemsList (можно пакет не создавать, а просто создать класс).
Ну и вот пример содержимого ItemsList.java с 3 предметами :
Код:
package assets.testmod.src.item;

import cpw.mods.fml.common.registry.LanguageRegistry;
import net.minecraft.item.Item;

public class ItemsList {

    /*
     * Здесь создаем предметы
     */
    public static Item itemTest;
    public static Item itemTest2;
    public static Item itemTest3;

    public static void items()
    {

        /*
         * Инициализируем предметы
         */
        itemTest = new ItemTest(3100).setUnlocalizedName("itemTest");
        itemTest2 = new ItemTest2(3101).setUnlocalizedName("itemTest2");
        itemTest3 = new ItemTest3(3102).setUnlocalizedName("itemTest3");

        /*
         * Имена предметам
         */
        LanguageRegistry.addName(itemTest, "Test Block 1");
        LanguageRegistry.addName(itemTest2, "Test Block 2");
        LanguageRegistry.addName(itemTest3, "Test Block 3");
    }

}
Ну а файлы ItemTest.java, ItemTest2.java, ItemTest3.java создадите сами (см. Создание предмета).
Чтобы сделать эффект магического переливания у предмета (как золотое яблоко), в файле предмета впишите код:
Код:
@SideOnly(Side.CLIENT)
    public boolean hasEffect(ItemStack par1ItemStack)
    {
        return true;
    }
Если заглянуть net.minecraft.block.Block, можно увидеть много строчек, похожих на эту:
Код:
public static final Block bedrock = (new Block(7, Material.rock)).setBlockUnbreakable()
.setResistance(6000000.0F).setStepSound(soundStoneFootstep).setUnlocalizedName("bedrock").disableStats()
.setCreativeTab(CreativeTabs.tabBlock).setTextureName("bedrock");
Это пример создания блока bedrock и добавление ему свойств. Например .setBlockUnbreakable() делает его неразрушимым (это же бэдрок). Остальные свойства легко понятны из их названий.
Пишем такой код :
Код:
worldObj.spawnEntityInWorld(new EntityLightningBolt(this.worldObj,this.xTile, this.yTile, this.zTile));
this.xTile, this.yTile, this.zTile - это позиция блока x,y,z соответственно
worldObj - это переменная вашего мира. Её можно получить через Minecraft.getMinecraft().theWorld, но в большинстве случаев она у вас должно быть и так.
Пишем такой код :
Код:
world.createExplosion(this, x, y, z, Power, flag);
x, y, z - позиция (Это понятно)
Power - сила взрыва (Например 1.0F)
flag - Может быть true или false. Если false, то блоки не разрушаються
Пишем такой код :
Код:
double radius = 3.0;
List<EntityItem> items = p.worldObj.getEntitiesWithinAABB(EntityItem.class, AxisAlignedBB.getBoundingBox(this.xTile - radius, this.yTile - radius, this.zTile - radius, this.xTile + radius, this.yTile + radius, this.zTile + radius));
            for(EntityItem item : items){
                <<Какой-то код>>
            }
Разберем :
List<EntityItem> items - создается список предметов которые лежат в радиусе radius от позиции this.xTile,this.yTile,this.zTile.
Цикл for(EntityItem item : items) проходится по всему полученному списку где мы можем выполнять различные действия.
Например :
Код:
item.onCollideWithPlayer(player);
onCollideWithPlayer притянет предмет item к игроку player
В вашем главном файле мода перед всеми методами пишем такие строчки:
Код:
public static KeyBinding[] Keys={new KeyBinding("key.number_1", Keyboard.KEY_F),new KeyBinding("key.number_2", Keyboard.KEY_R)};
boolean[]repeats={false,false};
В массиве Keys создаются кнопки.
"key.number_1" - это имя кнопки. Это имя можно добавить в файл локализации и сделать его человеко-читаемым.
Keyboard.KEY_F - это кнопка, которая будет стоять по умолчанию.
Дальше в методе public void init(FMLInitializationEvent event) пишем следующее :
Код:
KeyBindingRegistry.registerKeyBinding(new MyModKeyBinds(Keys,repeat));
Этот метод регистрирует наши кнопки с нашим классом. Но класса, который реализует эти кнопки нету! Поэтому наводи на высветляющею ошибку и создаем класс MyModKeyBinds :
Код:
package assets.testmod.src;

public class MyModKeyBinds extends KeyHandler
{
    private EnumSet tickTypes = EnumSet.of(TickType.CLIENT);
   
    public MyModKeyBinds(KeyBinding[] keyBindings, boolean[] repeatings)
    {
            super(keyBindings, repeatings);
    }
    @Override
    public String getLabel()
    {
            return "TutorialKey";
    }
    @Override
    public void keyDown(EnumSet<TickType> types, KeyBinding kb, boolean tickEnd, boolean isRepeat)
    {
            //what to do when key is pressed/down
    }
    @Override
    public void keyUp(EnumSet<TickType> types, KeyBinding kb, boolean tickEnd)
    {
            //What to do when key is released/up
    }
    @Override
    public EnumSet<TickType> ticks()
    {
            return tickTypes;
    }
}
Импортируем всё что нужно и кнопки готовы!
Создадим класс пули :
Код:
public class myBullet extends Entity implements IProjectile
{
    public int knockbackStrength = 0;
    public int xTile = -1;
    public int yTile = -1;
    public int zTile = -1;
    public Entity shootingEntity;
    public int ticksInAir;
    public double damage = 0.0D;
    private MovingObjectPosition EntityLivingBase;

    public myBullet(World par1World, EntityLivingBase par2EntityLivingBase, float par3)
    {
        super(par1World);
        this.renderDistanceWeight = 10.0D;
        this.shootingEntity = par2EntityLivingBase;
        this.setSize(0.5F, 0.5F);
        this.setLocationAndAngles(par2EntityLivingBase.posX, par2EntityLivingBase.posY + (double)par2EntityLivingBase.getEyeHeight(), par2EntityLivingBase.posZ, par2EntityLivingBase.rotationYaw, par2EntityLivingBase.rotationPitch);
        this.posX -= (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F);
        this.posY -= 0.10000000149011612D;
        this.posZ -= (double)(MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F);
        this.setPosition(this.posX, this.posY, this.posZ);
        this.motionX = (double)(-MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI));
        this.motionZ = (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI));
        this.motionY = (double)(-MathHelper.sin(this.rotationPitch / 180.0F * (float)Math.PI));
        this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, par3 * 1.5F, 1.0F);
    }
    public void entityInit(){}
    public void setThrowableHeading(double par1, double par3, double par5, float par7, float par8)
    {
        float f2 = MathHelper.sqrt_double(par1 * par1 + par3 * par3 + par5 * par5);
        par1 /= (double)f2;
        par3 /= (double)f2;
        par5 /= (double)f2;
        par1 += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)par8;
        par3 += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)par8;
        par5 += this.rand.nextGaussian() * (double)(this.rand.nextBoolean() ? -1 : 1) * 0.007499999832361937D * (double)par8;
        par1 *= (double)par7;
        par3 *= (double)par7;
        par5 *= (double)par7;
        this.motionX = par1;
        this.motionY = par3;
        this.motionZ = par5;
    }
    @SideOnly(Side.CLIENT)
    public void setVelocity(double par1, double par3, double par5)
    {
        this.motionX = par1;
        this.motionY = par3;
        this.motionZ = par5;

        if (this.prevRotationPitch == 0.0F && this.prevRotationYaw == 0.0F)
        {
            float f = MathHelper.sqrt_double(par1 * par1 + par5 * par5);
            this.prevRotationYaw = this.rotationYaw = (float)(Math.atan2(par1, par5) * 180.0D / Math.PI);
            this.prevRotationPitch = this.rotationPitch = (float)(Math.atan2(par3, (double)f) * 180.0D / Math.PI);
            this.prevRotationPitch = this.rotationPitch;
            this.prevRotationYaw = this.rotationYaw;
            this.setLocationAndAngles(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch);
        }
    }
    public void writeEntityToNBT(NBTTagCompound par1NBTTagCompound)
    {
        par1NBTTagCompound.setShort("xTile", (short)this.xTile);
        par1NBTTagCompound.setShort("yTile", (short)this.yTile);
        par1NBTTagCompound.setShort("zTile", (short)this.zTile);
    }

    public void readEntityFromNBT(NBTTagCompound par1NBTTagCompound)
    {
        this.xTile = par1NBTTagCompound.getShort("xTile");
        this.yTile = par1NBTTagCompound.getShort("yTile");
        this.zTile = par1NBTTagCompound.getShort("zTile");
    }
    public void addSpotEntity(MovingObjectPosition mob){this.EntityLivingBase=mob;}
    public void addActionWithBlock(){}
    public void addActionWithBlockThread(){}
    public void addActionWithEntity(){}
    public void addSpotEntityAndBlock(){
        Vec3 vec3 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ);
        Vec3 vec31 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ);
        MovingObjectPosition movingobjectposition = this.worldObj.rayTraceBlocks_do_do(vec3, vec31, false, true);
        vec3 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX, this.posY, this.posZ);
        vec31 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX + this.motionX, this.posY + this.motionY, this.posZ + this.motionZ);
        if (movingobjectposition != null)
        {
            vec31 = this.worldObj.getWorldVec3Pool().getVecFromPool(movingobjectposition.hitVec.xCoord, movingobjectposition.hitVec.yCoord, movingobjectposition.hitVec.zCoord);
        }
        Entity entity = null;
        List list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, this.boundingBox.addCoord(this.motionX, this.motionY, this.motionZ).expand(1.0D, 1.0D, 1.0D));
        double d0 = 0.0D;
        int l;
        float f1;
        for (l = 0; l < list.size(); ++l)
        {
            Entity entity1 = (Entity)list.get(l);
            if (entity1.canBeCollidedWith() && (entity1 != this.shootingEntity))
            {
                f1 = 0.3F;
                AxisAlignedBB axisalignedbb1 = entity1.boundingBox.expand((double)f1, (double)f1, (double)f1);
                MovingObjectPosition movingobjectposition1 = axisalignedbb1.calculateIntercept(vec3, vec31);
                if (movingobjectposition1 != null)
                {
                    double d1 = vec3.distanceTo(movingobjectposition1.hitVec);
                    if (d1 < d0 || d0 == 0.0D)
                    {
                        entity = entity1;
                        d0 = d1;
                    }
                }
            }
        }
        if (entity != null)
        {
            movingobjectposition = new MovingObjectPosition(entity);
        }
        if (movingobjectposition != null && movingobjectposition.entityHit != null && movingobjectposition.entityHit instanceof EntityPlayer)
        {
            EntityPlayer entityplayer = (EntityPlayer)movingobjectposition.entityHit;
            if (entityplayer.capabilities.disableDamage || this.shootingEntity instanceof EntityPlayer && !((EntityPlayer)this.shootingEntity).canAttackPlayer(entityplayer))
            {
                movingobjectposition = null;
            }
        }
        float f2,f3;
        if (movingobjectposition != null)
        {
            if (movingobjectposition.entityHit != null)
            {
                f2 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionY * this.motionY + this.motionZ * this.motionZ);
                int i1 = MathHelper.ceiling_double_int((double)f2 * this.damage);
                DamageSource damagesource = null;
                damagesource=causeBulletDamage(this, this.shootingEntity);
                if (!this.worldObj.isRemote)
                {
                    if (movingobjectposition.entityHit != null)
                    {
                        if (this.shootingEntity != null)
                        {}
                        else
                        {
                            movingobjectposition.entityHit.attackEntityFrom(DamageSource.magic, 5.0F);
                        }
         
                        if (movingobjectposition.entityHit instanceof EntityLivingBase)
                        {
                            addSpotEntity(movingobjectposition);
                            addActionWithEntity();
                        }
                    }
                }
                this.setDead();
                if (movingobjectposition.entityHit.attackEntityFrom(damagesource, (float)i1))
                {
                    if (movingobjectposition.entityHit instanceof EntityLivingBase)
                    {
                        EntityLivingBase entitylivingbase = (EntityLivingBase)movingobjectposition.entityHit;
                        if (!this.worldObj.isRemote)
                        {
                            entitylivingbase.setArrowCountInEntity(entitylivingbase.getArrowCountInEntity() + 1);
                        }
                        if (this.knockbackStrength > 0)
                        {
                            f3 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ);

                            if (f3 > 0.0F)
                            {
                                movingobjectposition.entityHit.addVelocity(this.motionX * (double)this.knockbackStrength * 0.6000000238418579D / (double)f3, 0.1D, this.motionZ * (double)this.knockbackStrength * 0.6000000238418579D / (double)f3);
                            }
                        }
                        if (this.shootingEntity != null)
                        {
                            EnchantmentThorns.func_92096_a(this.shootingEntity, entitylivingbase, this.rand);
                        }
                        if (this.shootingEntity != null && movingobjectposition.entityHit != this.shootingEntity && movingobjectposition.entityHit instanceof EntityPlayer && this.shootingEntity instanceof EntityPlayerMP)
                        {
                            ((EntityPlayerMP)this.shootingEntity).playerNetServerHandler.sendPacketToPlayer(new Packet70GameEvent(6, 0));
                        }
                    }
                    this.setDead();
                }
                else
                {
                    this.motionX *= -0.10000000149011612D;
                    this.motionY *= -0.10000000149011612D;
                    this.motionZ *= -0.10000000149011612D;
                    this.rotationYaw += 180.0F;
                    this.prevRotationYaw += 180.0F;
                }
            }
            else
            {
                this.xTile = movingobjectposition.blockX;
                this.yTile = movingobjectposition.blockY;
                this.zTile = movingobjectposition.blockZ;
                this.motionX = (double)((float)(movingobjectposition.hitVec.xCoord - this.posX));
                this.motionY = (double)((float)(movingobjectposition.hitVec.yCoord - this.posY));
                this.motionZ = (double)((float)(movingobjectposition.hitVec.zCoord - this.posZ));
                f2 = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionY * this.motionY + this.motionZ * this.motionZ);
                this.posX -= this.motionX / (double)f2 * 0.05000000074505806D;
                this.posY -= this.motionY / (double)f2 * 0.05000000074505806D;
                this.posZ -= this.motionZ / (double)f2 * 0.05000000074505806D;
            }
        }
    }
    public void addFlyBullet(){
        float f4 = 0.99F;
        float f1 = 0.0F;
        this.posX += this.motionX;
        this.posY += this.motionY;
        this.posZ += this.motionZ;
        this.motionX *= (double)f4;
        this.motionY *= (double)f4;
        this.motionZ *= (double)f4;
        this.motionY -= (double)f1;
        this.setPosition(this.posX, this.posY, this.posZ);
        this.doBlockCollisions();
    }
    public static DamageSource causeBulletDamage(myBullet par1, Entity entity)
    {
        return (new EntityDamageSourceIndirect("", par1, entity)).setProjectile();
    }
    public void onUpdate()
    {
        super.onUpdate();
        int i = this.worldObj.getBlockId(this.xTile, this.yTile, this.zTile);
        if (i > 0)
        {
            addActionWithBlock();
        }
        addSpotEntityAndBlock();
        addFlyBullet();
        addActionWithBlockThread();
    }
}
Я немного упростил сий код, поэтому разберемся:
onUpdate() - он обновляет пулю 20 раз в секунду и, собственно, позволяет ей двигаться и делать разные действия.
addActionWithBlockThread() - выполняются действия пока пуля летит.
addActionWithBlock() - выполняются действия когда пуля попала в блок.
addSpotEntityAndBlock() - этот метод определяет блок и моба.
addSpotEntity передает моба для метода addActionWithEntity() - он в свою очередь выполняет действия с мобом.
И наконец addFlyBullet() - заставляет пулю лететь.
Лучше всего, конечно, создавать классы с extends myBullet и в них уже наполнять методы действиями, но это на ваше усмотрение. Просто так экономится...код и все методы можно перенаполнить из класса extends myBullet. Также, чтобы менять направление пули, поэксперементируйте с переменными this.rotationPitch и this.rotationYaw.
Итак, чтобы наша пуля появилась в мире надо написать такой код :
Код:
<Название класса вашей пули> blasterBullet = new <Название класса вашей пули>(world, player, 2.0F);
world.spawnEntityInWorld(blasterBullet);
Этот код можно размещать где угодно, в блоке или в предмете, но обязательно в событии. Например нажатие ПКМ с предметом в руке :
Код:
public ItemStack onItemRightClick(ItemStack is, World world, EntityPlayer player){
     <Название класса вашей пули> blasterBullet = new <Название класса вашей пули>(world, player, 2.0F);
      world.spawnEntityInWorld(blasterBullet);
      return is;
}
Вот пример файла где использованы все методы :
Код:
public class testBullet extends hpmBullet
{
    public testBullet(World world,EntityLivingBase ELB, float par3) {
        super(world, ELB, par3);
    }
    public void addActionWithBlock(){
        ((EntityPlayer) this.shootingEntity).addChatMessage("hello Block");
        this.setDead();
    }
    public void addActionWithBlockEntity(){
        ((EntityPlayer) this.shootingEntity).addChatMessage("hello Mob");
        this.setDead();
    }
    public void addActionWithBlockThread(){
        ((EntityPlayer) this.shootingEntity).addChatMessage("I`m fly!!!");
        //Здесь this.setDead() не нужен!
    }
}
Не забываем про CTRL+SHIFT+O.
В классе EntityArrow (на него всегда следует ориентироваться при создании пули) есть много интересных методов и переменных. Некоторые из них более очевидны, как например переменная isBurning, некоторые менее. Так вот, чтобы заставить моба стрелять стрелами, надо спаунить стрелу по этому конструктору:
Код:
public EntityArrow(World par1World, EntityLivingBase par2EntityLivingBase, float par3)
    {
        super(par1World);
        this.renderDistanceWeight = 10.0D;
        this.shootingEntity = par2EntityLivingBase;

        if (par2EntityLivingBase instanceof EntityPlayer)
        {
            this.canBePickedUp = 1;
        }

        this.setSize(0.5F, 0.5F);
        this.setLocationAndAngles(par2EntityLivingBase.posX, par2EntityLivingBase.posY + (double)par2EntityLivingBase.getEyeHeight(), par2EntityLivingBase.posZ, par2EntityLivingBase.rotationYaw, par2EntityLivingBase.rotationPitch);
        this.posX -= (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F);
        this.posY -= 0.10000000149011612D;
        this.posZ -= (double)(MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * 0.16F);
        this.setPosition(this.posX, this.posY, this.posZ);
        this.yOffset = 0.0F;
        this.motionX = (double)(-MathHelper.sin(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI));
        this.motionZ = (double)(MathHelper.cos(this.rotationYaw / 180.0F * (float)Math.PI) * MathHelper.cos(this.rotationPitch / 180.0F * (float)Math.PI));
        this.motionY = (double)(-MathHelper.sin(this.rotationPitch / 180.0F * (float)Math.PI));
        this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, par3 * 1.5F, 1.0F);
    }
То есть так: EntityArrow entityarrow = new EntityArrow(World, EntityLivingBase, float).
А изменив две последние циферки в строчке:
this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, par3 * 1.5F, 1.0F);
можно изменить скорость пули и меткость попадания. А именно: par3* 1.5F - это скорость, 1.0F - это меткость.
Чтобы зажечь стрелу надо обратиться к методу: entityarrow.setFire(продолжительность горения в секундах).
На этом пока всё! <img src="http://forum.mcmodding.ru/img/smilies/nomicons/smile.png" width="20" alt="nomicons/smile">
Создадим класс LocalizationHandler :
Код:
public class LocalizationHandler {
public static void init(){
    for(String Localizationfile:Localizations.localeFiles){
        LanguageRegistry.instance().loadLocalization(Localizationfile, LocalizationHelper.getLocalfromFileName(Localizationfile), LocalizationHelper.isXMLFile(Localizationfile));
        }
    }
}
Этот класс, видимо, загрузит нам остальные классы созданные ниже, переводя нам все названия.
Создадим класс LocalizationHelper :
Код:
public class LocalizationHelper {
    public static boolean isXMLFile(String filename){
        return filename.endsWith(".lang");
    }
    public static String getLocalfromFileName (String fileName){
        return fileName.substring(fileName.lastIndexOf("/")+1, fileName.lastIndexOf("."));
    }
    public static String getLocalizationString (String key){
        return LanguageRegistry.instance().getStringLocalization(key);
    }
}
Этот класс подключает языковые файлы.
Создадим класс Localizations :
Код:
public class Localizations {
    public static String[] localeFiles ={ModInfo.LANGUAGE_LOCATION+"en_US.lang",ModInfo.LANGUAGE_LOCATION+"ru_RU.lang"};
}
В этом классе список возможных языковых файлов.
Теперь в главном файле мода в preLoad(FMLPreInitializationEvent event) пишем : LocalizationHandler.init();.
Теперь в файле ModInfo (При наличии такового) пишем такую строку : public static final String LANGUAGE_LOCATION = "/assets/testmod/lang/";.
В этой переменной содержится путь к нашим языковым файлам.
В директории создаем языковой файл (Например, если русский язык - ru_RU.lang, если английский язык - то en_US.lang).
Теперь чтобы получить переведенное имя, в setUnlocalizedName (LanguageRegistry.addName() нам уже не нужен!) мы должны написать в таком формате - item.imyavashegopredmeta.name (Если блок - то tile.imyavashegoblocka.name). А в языковом файле пишем item.imyavashegopredmeta.name=Мой предмет)
Вот и всё!)

Автор туториала: GerMes
Перенесено со старого форума.
 

necauqua

когда-то был anti344
Администратор
1,216
27
172
В 1.6.4 локализация уже грузится сама, это для оооооочень древних версий пишешь.
 
771
5
RaVeN написал(а):
ну вот нашёл как привинтить текстуру частице
Код:
  public void setParticleIcon(RenderEngine par1RenderEngine, Icon par2Icon)
    {
        if (this.getFXLayer() == 1)
        {
            this.particleIcon = par2Icon;
        }

Код:
public abstract class EntityParticle extends EntityFX{

    public EntityParticle(World wrd, double x, double y, double z){
        super(wrd, x, y, z);
    }
        //Этот метод скопипастен полностью, кроме того, что помечено.
    @Override
    public void renderParticle(Tessellator tess, float partialTicks, float par3, float par4, float par5, float par6, float par7){
        Minecraft.getMinecraft().renderEngine.bindTexture(getIconLoc());//МЕТКА
        GL11.glDepthMask(false);
        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        GL11.glAlphaFunc(GL11.GL_GREATER, 0.003921569F);//МЕТКА
        tess.startDrawingQuads();//МЕТКА
        tess.setBrightness(getBrightnessForRender(partialTicks));//МЕТКА
        float scale = 0.1F * particleScale;
        float x = (float)(prevPosX + (posX - prevPosX) * partialTicks - interpPosX);
        float y = (float)(prevPosY + (posY - prevPosY) * partialTicks - interpPosY);
        float z = (float)(prevPosZ + (posZ - prevPosZ) * partialTicks - interpPosZ);
        tess.addVertexWithUV(x - par3 * scale - par6 * scale, y - par4 * scale, z - par5 * scale - par7 * scale, /*НАЧАЛО_МЕТКИ*/0.0, 0.0/*КОНЕЦ_МЕТКИ*/);
        tess.addVertexWithUV(x - par3 * scale + par6 * scale, y + par4 * scale, z - par5 * scale + par7 * scale, /*НАЧАЛО_МЕТКИ*/1.0, 0.0/*КОНЕЦ_МЕТКИ*/);
        tess.addVertexWithUV(x + par3 * scale + par6 * scale, y + par4 * scale, z + par5 * scale + par7 * scale, /*НАЧАЛО_МЕТКИ*/1.0, 1.0/*КОНЕЦ_МЕТКИ*/);
        tess.addVertexWithUV(x + par3 * scale - par6 * scale, y - par4 * scale, z + par5 * scale - par7 * scale, /*НАЧАЛО_МЕТКИ*/0.0, 1.0/*КОНЕЦ_МЕТКИ*/);
        tess.draw();//МЕТКА
        GL11.glDisable(GL11.GL_BLEND);
        GL11.glDepthMask(true);
        GL11.glAlphaFunc(GL11.GL_GREATER, 0.1F);//МЕТКА
    }

    protected abstract ResourceLocation getIconLoc();

    @Override
    public int getFXLayer(){
        return 3;//Корень зла, если это - 3, то при рендере он без твоего согласия не вызывает заранее tess.startDrawingQuads(); и tess.draw(); , что позволяет иметь свою текстуру.
    }
        //Те три метода, что ниже, для удобства
    public EntityParticle setMaxAge(int maxAge){
        particleMaxAge = maxAge;
        return this;
    }

    public EntityParticle setGravity(double gravity){
        particleGravity = (float)gravity;
        return this;
    }

    public EntityParticle setScale(double scale){
        particleScale = (float)scale;
        return this;
    }
}
 
905
5
Анти, можно я его молотком ударю?
 
771
5
Гуи серверу не нужно, так что в методе getServerGuiElement вовращай просто null.
 
Вообще-то в getServerGuiElement нужно возвращать контейнер, если гуи с контейнером.
 
Нет. Но кроме того, нужен тайл энтити, чтобы хранить предметы, которые были положены в сундук или что там у тебя.
 
771
5
Эм...Что ты там на ноль делишь?
Caused by: java.lang.ArithmeticException: / by zero
 
200
0
В чём проблема?
@SideOnly(Side.CLIENT)
    public void registerIcons(IconRegister ir)
    {
    this.itemIcon = ir.registerIcon(ModInfo.MODID + ":testBlock");
    }
картинка в папках myMod\textures\items\testBlock.png

есть
 
34
0
evan написал(а):
В чём проблема?
@SideOnly(Side.CLIENT)
    public void registerIcons(IconRegister ir)
    {
    this.itemIcon = ir.registerIcon(ModInfo.MODID + ":testBlock");
    }
картинка в папках myMod\textures\items\testBlock.png

есть
Картинка должна быть assets\myMod\textures\items\testBlock.png
 
200
0
Царь написал(а):
evan написал(а):
В чём проблема?
@SideOnly(Side.CLIENT)
    public void registerIcons(IconRegister ir)
    {
    this.itemIcon = ir.registerIcon(ModInfo.MODID + ":testBlock");
    }
картинка в папках myMod\textures\items\testBlock.png

есть
Картинка должна быть assets\myMod\textures\items\testBlock.png
Всё правильно в моём коде, я просто папку с модом должен был назвать с маленькой буквы :D
 
200
0
Вопрос, как у пули убрать этот белый квадрат? Пытался брать код от стрелы лука, но не получалось.
Пытался делать как в уроке mcmodding.ru/учебник/, но крашился майн при выстреле
 

timaxa007

Модератор
5,831
409
672
evan написал(а):
Вопрос, как у пули убрать этот белый квадрат? Пытался брать код от стрелы лука, но не получалось.
Пытался делать как в уроке mcmodding.ru/учебник/, но крашился майн при выстреле
8f649b636dd2bf548f586cf94199df04.png

Просмотр изображения 2014-06-24_22.47.27.png
На серверной стороне это куб, а на клиенской стороне должно рендериться вместо куба.
Код:
RenderingRegistry.registerEntityRenderingHandler(EntityArrowMini.class, new RenderArrowMini());
 
Сверху