- Регистрация
- 4 Апр 2025
- Сообщения
- 24
- Реакции
- 0
- Баллы
- 1
- Город
- Санкт-Петербург
- Веб-сайт
- paxgame.ru
- Discord
- nicolayka
В этом учебнике вы научитесь моддить в Forge, тут написаны мои, и собраны разные туториалы, с разных источников. Удачи в моддинге!
Что требуется для моддинга с Forge?
1. JDK 7
2. MCP (Minecraft Coder Pack)
3. Forge-Src, находим Recommended:, и нажимаем Source. Другие версии тут.
4. Eclipse
5. Чистый клиент и обязательно сервер
Как скачать клиент (Пиратский)
Осталось обновить:
Создание Metadata блоку. - уже скоро
Создание Metadata итему.
История:
Внимание!
1.Если вы моддите в первый раз лучше всего идти постепенно, не пропуская уроков.
2.Если будут проблемы, или ошибки, не спешите в теме просить помощь, сначала посмотрите маленький FAQ.
Мини-FAQ
0.1. Подготовка.
0.2 Как сделать сам мод (Как запаковать в архив).
0.3 Как добавить текстуру в 1.5 (Объяснение)
1. Создание блока.
2. Создание предмета.
3. Рецепты (Крафт, Печка)
4. Как сделать еду.
5. Создание конфиг файла.
6. Создание Metadata блоку. Не обновлено!
7. Создание Metadata итему. Не обновлено!
8. Создание своей вкладки в CreativeTabs.
9. Прокси.
10. Создание моба.
11. Как сделать блок с моделью.
12. Что делать если не открывается сундук/печка
13. Как сделать свой сундук.
14. Как сделать свою печку.
Что требуется для моддинга с Forge?
1. JDK 7
2. MCP (Minecraft Coder Pack)
3. Forge-Src, находим Recommended:, и нажимаем Source. Другие версии тут.
4. Eclipse
5. Чистый клиент и обязательно сервер
Как скачать клиент (Пиратский)
Качаем minecraftSP.zip, распаковываем, нажимаем, и видем окно:
Ждём пока загрузка кончиться, и всё, у вас есть чистый клиент!

Ждём пока загрузка кончиться, и всё, у вас есть чистый клиент!
Осталось обновить:
Создание Metadata блоку. - уже скоро
Создание Metadata итему.
История:
30.04.2013 - Добавлен урок про Прокси.
24.04.2013 - Изменены 2 гайда.
22.04.2013 - Добавлены уроки по созданию брони, и инструментов.
16.04.2013 - Добавлено объяснение как убрать баг по открытию печки/сундука.
10.04.2013 - Обновлен Туториал по созданию сундука. Обновлен Туториал по созданию печки. Обновлены все гайды кроме 2-х.
07.04.2013 - Убрана надпись внизу темы по "Добавлению туториалов от других пользователей". Обновлен FAQ.
06.04.2013 - Изменен урок №1. Обновлен урок №0.2-8-9-10.
05.04.2013 - Обновлен урок по созданию Блока. Добавлен урок по текстурах. Обновлен урок по созданию предмета.
24.04.2013 - Изменены 2 гайда.
22.04.2013 - Добавлены уроки по созданию брони, и инструментов.
16.04.2013 - Добавлено объяснение как убрать баг по открытию печки/сундука.
10.04.2013 - Обновлен Туториал по созданию сундука. Обновлен Туториал по созданию печки. Обновлены все гайды кроме 2-х.
07.04.2013 - Убрана надпись внизу темы по "Добавлению туториалов от других пользователей". Обновлен FAQ.
06.04.2013 - Изменен урок №1. Обновлен урок №0.2-8-9-10.
05.04.2013 - Обновлен урок по созданию Блока. Добавлен урок по текстурах. Обновлен урок по созданию предмета.
Внимание!
1.Если вы моддите в первый раз лучше всего идти постепенно, не пропуская уроков.
2.Если будут проблемы, или ошибки, не спешите в теме просить помощь, сначала посмотрите маленький FAQ.
Мини-FAQ
Всё свои ошибки пишем в спойлерах:
[ spoiler ] [ /spoiler ]
Вопрос: Я написал код, как мне теперь его проверить в игре?
Ответ: Теперь вам надо его рекомпилировать, нажмите recompile.bat (Пакетный файл MS-DOS), подождите пока пройдёт время, и теперь нажмите startclient.bat.
Вопрос: Я хотел рекомпилировать мод, нажал recompile.bat, появилось окно и пропало, что мне делать?
Ответ: Запускать надо recompile.bat (Пакетный файл MS-DOS), это относится и другим bat'никам.
Вопрос: Нажал recompile.bat, всё было хорошо, но потом мне консоль написал это:
(Пример) src\minecraft\net\testmod\src\TestModBase.java:25: unmappable character for enco
ding UTF-8
//????
Ответ: Forge не принимает UTF-8, удаляйте все русские комментарии, а то рекомпилятор покарает вас ошибками.
Вопрос: У меня в игре не работают текстуры, вместо текстуры написано missing textures, что делать?
Ответ: Посмотрите урок №0.3.
[ spoiler ] [ /spoiler ]
Вопрос: Я написал код, как мне теперь его проверить в игре?
Ответ: Теперь вам надо его рекомпилировать, нажмите recompile.bat (Пакетный файл MS-DOS), подождите пока пройдёт время, и теперь нажмите startclient.bat.
Вопрос: Я хотел рекомпилировать мод, нажал recompile.bat, появилось окно и пропало, что мне делать?
Ответ: Запускать надо recompile.bat (Пакетный файл MS-DOS), это относится и другим bat'никам.
Вопрос: Нажал recompile.bat, всё было хорошо, но потом мне консоль написал это:
(Пример) src\minecraft\net\testmod\src\TestModBase.java:25: unmappable character for enco
ding UTF-8
//????
Ответ: Forge не принимает UTF-8, удаляйте все русские комментарии, а то рекомпилятор покарает вас ошибками.
Вопрос: У меня в игре не работают текстуры, вместо текстуры написано missing textures, что делать?
Ответ: Посмотрите урок №0.3.
0.1. Подготовка.
Не надо удалять META-INF, в minecraft.jar, и minecraft_server.jar
1. Создаем папку (Например: MCP Forge) и распаковываем туда содержание архива с MCP.
2. Копируем в папку ../MCP Forge/jars/ , из клиента папку bin и resources, из сервера нам потребуется только minecraft_server.jar.
3. Распаковываем архив с Forge-src в папку MCP Forge
4. Открываем папку ../MCP Forge/forge/ и запускаем файл install.cmd. Ждем окончания декомпиляции..
(P.S Если хотите что бы у вас уже был готовый MCP с Forge, например если вы случайно удалили его или ещё что-то, то: Когда декомпиляция пройдёт запустите игру пусть скачает lib, и потом добавьте в архив этот MCP Forge например так (mcp Forge 1.5.1)
5. "Устанавливаем" и запускаем Eclipse, во время запуска у вас "спросят" папку с проектом, указываем путь: ../MCP Forge/eclipse/
6. Итак, мы открыли проект, теперь (Обычно слева, есть Package explorer) смотрим, какую библиотеку он "ест"(В окне Package explorer, "открываем проект Minecraft" и если будет строка "JRE System Library [JavaSE-1.7]", то все нормально, но если строка "JRE System Library [JavaSE-1.6]", то нажимаем ПКМ(Правой кнопкой мыши), выбираем пункт Properties, далее открылось окно в нем пункт Execution environment, выбираем в нем JavaSE-1.7 и нажимаем Ok.
7. Итак, приготовления готовы.
Как же все таки начать писать мод?
Для начала, нам нужно создать "основу", то есть основную "папку" в которой будет храниться наша "основа" и все остальное.
1. Создаем папку (Например: MCP Forge) и распаковываем туда содержание архива с MCP.
2. Копируем в папку ../MCP Forge/jars/ , из клиента папку bin и resources, из сервера нам потребуется только minecraft_server.jar.
3. Распаковываем архив с Forge-src в папку MCP Forge
4. Открываем папку ../MCP Forge/forge/ и запускаем файл install.cmd. Ждем окончания декомпиляции..
(P.S Если хотите что бы у вас уже был готовый MCP с Forge, например если вы случайно удалили его или ещё что-то, то: Когда декомпиляция пройдёт запустите игру пусть скачает lib, и потом добавьте в архив этот MCP Forge например так (mcp Forge 1.5.1)
5. "Устанавливаем" и запускаем Eclipse, во время запуска у вас "спросят" папку с проектом, указываем путь: ../MCP Forge/eclipse/
6. Итак, мы открыли проект, теперь (Обычно слева, есть Package explorer) смотрим, какую библиотеку он "ест"(В окне Package explorer, "открываем проект Minecraft" и если будет строка "JRE System Library [JavaSE-1.7]", то все нормально, но если строка "JRE System Library [JavaSE-1.6]", то нажимаем ПКМ(Правой кнопкой мыши), выбираем пункт Properties, далее открылось окно в нем пункт Execution environment, выбираем в нем JavaSE-1.7 и нажимаем Ok.
7. Итак, приготовления готовы.
Как же все таки начать писать мод?
Для начала, нам нужно создать "основу", то есть основную "папку" в которой будет храниться наша "основа" и все остальное.
- 1.Заходим в Eclipse видим в Package Explorer папку Minecraft, открываем, и нажимаем ПКМ на папку src, выбираем New->Package. Открытом окне в строке Name, мы указываем название папки в которой будет все храниться (Для примера возьмем: mods.testmod.src ) и нажимаем Ok.
- 2. Нажимаем ПКМ по нашей папке ( mods.testmod.src ), далее New -> Class. В строке Name указываем название нашего файла (Например: TestModBase ) и нажимаем Finish.
- 3. Меняйте путь, но не уберайте mods, вот так например mods.NewItemMod.src.
- 4. В новых версиях надо импортировать "Очень много" всего, чтобы сделать это быстрее в Эклипсе нажимайте "ctrl + shift + o", и вам быстро он всё импортирует, а если появиться окно тогда выбирайте нужный вам импорт.
- 5. Если вы работаете не в эклипсе, тогда вам будет намного труднее, так что лучше перейти на него, он укажет где ошибка, и какие импорты надо, и вы не будете задавать глупых вопросов в комментариях.
package mods.testmod.src;
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 TestModBase {
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void postLoad(FMLPostInitializationEvent event)
{
}
}
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 TestModBase {
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void postLoad(FMLPostInitializationEvent event)
{
}
}
Когда вы уже сделаете мод, надо: Нажимайте recompile.bat, потом reobfuscate.bat, когда всё закончиться зайдите в папку reobf/minecraft/mods, и положите в папку testmod нашу папку с текстурами, textures, теперь нажимаем на папку mods правой кнопкой, Добавить в архив... выбираем формат .zip, пишем название мода, кидаем наш архив в клиент, в папку mods, играем!
В 1.5 теперь стало немного по другому добавлять текстуры, не надо волноваться, все можно понять, и научиться делать)
Путь текстур менять можно, кроме:
/textures/blocks/
/textures/items/
/textures/gui/
Как добавить текстуру блоку:
Как добавить текстуру итему:
Как добавить текстуру GUI:
Путь текстур менять можно, кроме:
/textures/blocks/
/textures/items/
/textures/gui/
Как добавить текстуру блоку:
Добавляем метод в блок:
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.blockIcon = par1IconRegister.registerIcon("testmod:testBlock");
}
("testmod:testBlock"), testmod - это "имя папки", в которой будет "папка с текстурой", testBlock - название нашей текстуры. Вот такое у нас размещение текстуры:
\Tutorial Forge 1.5.1\mcp744\src\minecraft\mods\testmod\textures\blocks\testBlock.png
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.blockIcon = par1IconRegister.registerIcon("testmod:testBlock");
}
("testmod:testBlock"), testmod - это "имя папки", в которой будет "папка с текстурой", testBlock - название нашей текстуры. Вот такое у нас размещение текстуры:
\Tutorial Forge 1.5.1\mcp744\src\minecraft\mods\testmod\textures\blocks\testBlock.png
Добавляем метод в итем:
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon("testmod:testItem");
}
("testmod:testItem"), testmod - это "имя папки", в которой будет "папка с текстурой", testItem - название нашей текстуры. Вот такое у нас размещение текстуры:
\Tutorial Forge 1.5.1\mcp744\src\minecraft\mods\testmod\textures\items\testItem.png
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon("testmod:testItem");
}
("testmod:testItem"), testmod - это "имя папки", в которой будет "папка с текстурой", testItem - название нашей текстуры. Вот такое у нас размещение текстуры:
\Tutorial Forge 1.5.1\mcp744\src\minecraft\mods\testmod\textures\items\testItem.png
Еще не готово!
Вот такое у нас размещение текстуры:
\Tutorial Forge 1.5.1\mcp744\src\minecraft\mods\testmod\textures\gui\testGui.png
Вот такое у нас размещение текстуры:
\Tutorial Forge 1.5.1\mcp744\src\minecraft\mods\testmod\textures\gui\testGui.png
TestModBase
package mods.testmod.src;
import net.minecraft.block.Block;
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 TestModBase {
/**
* Сам блок, .setUnlocalizedName("testBlock"); - это будет имя блока и текстуры,
* теперь все текстуры будут отдельно.
*/
public static final Block testBlock = new TestBlock(2020).setUnlocalizedName("testBlock");
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
GameRegistry.registerBlock(testBlock);//Регистрация блока
LanguageRegistry.addName(testBlock, "Test Block");//Имя блока
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void postLoad(FMLPostInitializationEvent event)
{
}
}
TestBlock
package mods.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;
public class TestBlock extends Block {
public TestBlock(int par1)
{
super(par1, Material.ground);//Материал
this.setCreativeTab(CreativeTabs.tabTools);//Добавляем в креатив
}
//Регистрируем текстуру
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.blockIcon = par1IconRegister.registerIcon("testmod:testBlock");
}
}
package mods.testmod.src;
import net.minecraft.block.Block;
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 TestModBase {
/**
* Сам блок, .setUnlocalizedName("testBlock"); - это будет имя блока и текстуры,
* теперь все текстуры будут отдельно.
*/
public static final Block testBlock = new TestBlock(2020).setUnlocalizedName("testBlock");
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
GameRegistry.registerBlock(testBlock);//Регистрация блока
LanguageRegistry.addName(testBlock, "Test Block");//Имя блока
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void postLoad(FMLPostInitializationEvent event)
{
}
}
TestBlock
package mods.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;
public class TestBlock extends Block {
public TestBlock(int par1)
{
super(par1, Material.ground);//Материал
this.setCreativeTab(CreativeTabs.tabTools);//Добавляем в креатив
}
//Регистрируем текстуру
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.blockIcon = par1IconRegister.registerIcon("testmod:testBlock");
}
}
TestModBase
package mods.testmod.src;
import net.minecraft.item.Item;
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 TestModBase {
public static Item testItem = new TestItem(2020).setUnlocalizedName("testItem");
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
LanguageRegistry.addName(testItem, "Test Item");
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void postLoad(FMLPostInitializationEvent event)
{
}
}
TestItem
package mods.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);
setCreativeTab(CreativeTabs.tabTools);
}
//Регистрация текстуры для итема немного отличается от блока
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon("testmod:testItem");
}
}
package mods.testmod.src;
import net.minecraft.item.Item;
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 TestModBase {
public static Item testItem = new TestItem(2020).setUnlocalizedName("testItem");
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
LanguageRegistry.addName(testItem, "Test Item");
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void postLoad(FMLPostInitializationEvent event)
{
}
}
TestItem
package mods.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);
setCreativeTab(CreativeTabs.tabTools);
}
//Регистрация текстуры для итема немного отличается от блока
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon("testmod:testItem");
}
}
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
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 TestModBase {
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
/**
* "Обычный крафт"
* При крафте получаем алмаз, 1 - сколько получим при крафте, для своего крафта пишем
* так: TestModBase.свой блок/итем. Если вам будет понятней то можете крафт записать и в другой форме.
*/
GameRegistry.addRecipe(new ItemStack(Block.oreDiamond, 1), new Object[]{ "XXX", "X#X", "XXX", Character.valueOf('X'), Block.cobblestone, ('#'), Block.dirt});
GameRegistry.addRecipe(new ItemStack(Block.oreDiamond, 1), new Object[]{
"XXX",
"X#X",
"XXX", Character.valueOf('X'), Block.cobblestone, ('#'), Block.dirt});
/**
* "Бесформенный крафт"
* С этим крафтом мы сможем класть наши вещи как попало. Кладём палку и грязь, получаем алмазную руду.
*/
GameRegistry.addShapelessRecipe(new ItemStack(Block.oreDiamond, 4), new Object[] {Item.stick, Block.dirt});
/**
* "Переплавка в печке"
* С земли делаем уголь, 1 - сколько получим после переплавки, 1.0F - опыт при переплавки
*/
GameRegistry.addSmelting(Block.dirt.blockID, new ItemStack(Item.coal, 1), 1.0F);
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void postLoad(FMLPostInitializationEvent event)
{
}
}
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
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 TestModBase {
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
/**
* "Обычный крафт"
* При крафте получаем алмаз, 1 - сколько получим при крафте, для своего крафта пишем
* так: TestModBase.свой блок/итем. Если вам будет понятней то можете крафт записать и в другой форме.
*/
GameRegistry.addRecipe(new ItemStack(Block.oreDiamond, 1), new Object[]{ "XXX", "X#X", "XXX", Character.valueOf('X'), Block.cobblestone, ('#'), Block.dirt});
GameRegistry.addRecipe(new ItemStack(Block.oreDiamond, 1), new Object[]{
"XXX",
"X#X",
"XXX", Character.valueOf('X'), Block.cobblestone, ('#'), Block.dirt});
/**
* "Бесформенный крафт"
* С этим крафтом мы сможем класть наши вещи как попало. Кладём палку и грязь, получаем алмазную руду.
*/
GameRegistry.addShapelessRecipe(new ItemStack(Block.oreDiamond, 4), new Object[] {Item.stick, Block.dirt});
/**
* "Переплавка в печке"
* С земли делаем уголь, 1 - сколько получим после переплавки, 1.0F - опыт при переплавки
*/
GameRegistry.addSmelting(Block.dirt.blockID, new ItemStack(Item.coal, 1), 1.0F);
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void postLoad(FMLPostInitializationEvent event)
{
}
}
Пишем в TestModBase это:
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
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 TestModBase {
/**
* 1-2 это количество заполняемых сердец, 0.4F, на сколько утоляет голод,
* false - можно ли прирученных волков кормить.
**/
//Обычная еда
public static Item testFood = new TestFood(5003, 1, 0.4F, false).setUnlocalizedName("testFood");
//Суп
public static Item testSoup = new TestSoup(5004, 2).setUnlocalizedName("testSoup");
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
LanguageRegistry.addName(testFood, "Test Food");
LanguageRegistry.addName(testSoup, "Test Soup");
GameRegistry.addRecipe(new ItemStack(TestModBase.testFood, 1), new Object[]{ "#X", Character.valueOf('X'), Item.appleRed, Character.valueOf('#'), Block.dirt});
GameRegistry.addRecipe(new ItemStack(TestModBase.testSoup, 1), new Object[]{ "ZC", Character.valueOf('C'), Item.bowlEmpty, Character.valueOf('Z'), Item.appleRed});
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void postLoad(FMLPostInitializationEvent event)
{
}
}
Создаём TestFood:
package mods.testmod.src;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.item.ItemFood;
/**
* Мы поставили родитель ItemFood, и теперь наша еда автоматически будет в категории tabFood.
**/
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("testmod:testFood");
}
}
И TestSoup:
package mods.testmod.src;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
public class TestSoup extends ItemFood
{
public TestSoup(int par1, int par2)
{
super(par1, par2, false);
this.setMaxStackSize(1);
}
public ItemStack onEaten(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer)
{
super.onEaten(par1ItemStack, par2World, par3EntityPlayer);
return new ItemStack(Item.bowlEmpty);//Когда мы покушаем в руке останется деревянная миска.
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon("testmod:testFood");
}
}
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
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 TestModBase {
/**
* 1-2 это количество заполняемых сердец, 0.4F, на сколько утоляет голод,
* false - можно ли прирученных волков кормить.
**/
//Обычная еда
public static Item testFood = new TestFood(5003, 1, 0.4F, false).setUnlocalizedName("testFood");
//Суп
public static Item testSoup = new TestSoup(5004, 2).setUnlocalizedName("testSoup");
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
LanguageRegistry.addName(testFood, "Test Food");
LanguageRegistry.addName(testSoup, "Test Soup");
GameRegistry.addRecipe(new ItemStack(TestModBase.testFood, 1), new Object[]{ "#X", Character.valueOf('X'), Item.appleRed, Character.valueOf('#'), Block.dirt});
GameRegistry.addRecipe(new ItemStack(TestModBase.testSoup, 1), new Object[]{ "ZC", Character.valueOf('C'), Item.bowlEmpty, Character.valueOf('Z'), Item.appleRed});
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void postLoad(FMLPostInitializationEvent event)
{
}
}
Создаём TestFood:
package mods.testmod.src;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.item.ItemFood;
/**
* Мы поставили родитель ItemFood, и теперь наша еда автоматически будет в категории tabFood.
**/
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("testmod:testFood");
}
}
И TestSoup:
package mods.testmod.src;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
public class TestSoup extends ItemFood
{
public TestSoup(int par1, int par2)
{
super(par1, par2, false);
this.setMaxStackSize(1);
}
public ItemStack onEaten(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer)
{
super.onEaten(par1ItemStack, par2World, par3EntityPlayer);
return new ItemStack(Item.bowlEmpty);//Когда мы покушаем в руке останется деревянная миска.
}
@Override
public void registerIcons(IconRegister par1IconRegister)
{
this.itemIcon = par1IconRegister.registerIcon("testmod:testFood");
}
}
Немного изменим TestModBase:
package mods.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 TestModBase {
//Немного изменим наш итем
public static Item testItem;
public static int testItemitemID; //обязательно добавляем itemID
//И изменим наш блок
public static Block testBlock ;
public static int testBlockblockID; //добавляем blockID
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
//Дописываем наш итем, и вместо айди теперь у нас TestItemitemID
testItem = new TestItem(testItemitemID).setUnlocalizedName("testItem");
//Дописываем блок
testBlock = new TestBlock(testBlockblockID,0).setUnlocalizedName("testBlock");
LanguageRegistry.addName(testItem, "Test Item");
GameRegistry.registerBlock(testBlock);
LanguageRegistry.addName(testBlock, "Test Block");
}
@PostInit
public void load(FMLPreInitializationEvent event)
{
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
Configuration config = new Configuration(event.getSuggestedConfigurationFile());
config.load();//Писать надо только между load и save:
testItemitemID = config.getItem("testItem", 2020).getInt();
testBlockblockID = config.getBlock("testBlock", 2021).getInt();
config.save();
}
}
package mods.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 TestModBase {
//Немного изменим наш итем
public static Item testItem;
public static int testItemitemID; //обязательно добавляем itemID
//И изменим наш блок
public static Block testBlock ;
public static int testBlockblockID; //добавляем blockID
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
//Дописываем наш итем, и вместо айди теперь у нас TestItemitemID
testItem = new TestItem(testItemitemID).setUnlocalizedName("testItem");
//Дописываем блок
testBlock = new TestBlock(testBlockblockID,0).setUnlocalizedName("testBlock");
LanguageRegistry.addName(testItem, "Test Item");
GameRegistry.registerBlock(testBlock);
LanguageRegistry.addName(testBlock, "Test Block");
}
@PostInit
public void load(FMLPreInitializationEvent event)
{
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
Configuration config = new Configuration(event.getSuggestedConfigurationFile());
config.load();//Писать надо только между load и save:
testItemitemID = config.getItem("testItem", 2020).getInt();
testBlockblockID = config.getBlock("testBlock", 2021).getInt();
config.save();
}
}
7. Создание Metadata итему. Не обновлено!
8. Создание своей вкладки в CreativeTabs.
[1.4.7]Внимание: Оригинальный туториал тут.
TestModBase:
package mods.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 TestModBase {
//Добавляем наш CreativeTabs
public static CreativeTabs tabTest = new TabTest(CreativeTabs.getNextID(),"TestCreativeTab");
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void load(FMLPreInitializationEvent event)
{
}
}
TabTest:
package mods.testmod.src;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import cpw.mods.fml.relauncher.*;
public class TabTest extends CreativeTabs {
public TabTest(int position, String tabID)
{
super(position, tabID); //Конструктор вкладки
}
/**
* Какая картинка будет в категории, алмазный топор. Для своего
* итема пишем так: TestModBase.TestItem.itemID
* для блока: TestModBase.TestBlock.blockID
*/
@SideOnly(Side.CLIENT)
public int getTabIconItemIndex()
{
return Item.diamond.itemID;
}
public String getTranslatedTabLabel()
{
return "More Diamond"; //Имя вкладки в игре
}
}
TestModBase:
package mods.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 TestModBase {
//Добавляем наш CreativeTabs
public static CreativeTabs tabTest = new TabTest(CreativeTabs.getNextID(),"TestCreativeTab");
@Instance("TestModID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
@PostInit
public void load(FMLPreInitializationEvent event)
{
}
}
TabTest:
package mods.testmod.src;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import cpw.mods.fml.relauncher.*;
public class TabTest extends CreativeTabs {
public TabTest(int position, String tabID)
{
super(position, tabID); //Конструктор вкладки
}
/**
* Какая картинка будет в категории, алмазный топор. Для своего
* итема пишем так: TestModBase.TestItem.itemID
* для блока: TestModBase.TestBlock.blockID
*/
@SideOnly(Side.CLIENT)
public int getTabIconItemIndex()
{
return Item.diamond.itemID;
}
public String getTranslatedTabLabel()
{
return "More Diamond"; //Имя вкладки в игре
}
}
Прокси:
Будем делать прокси, если мы например захотели сделать моба, или блок с моделью, и поставим этот мод на сервер, он закидает вас ошибками, или рендер просто не будет роботать, а прокси избавит нас от этой проблемы.
Добавляем в наш главный класс (базу):
@SidedProxy(clientSide = "mods.testmod.src.ClientProxy", serverSide = "mods.testmod.src.CommonProxyTutorial")
public static ClientProxy proxy;
После этого:
public class TestModBase {
Теперь регистрируем рендер в прокси:
proxy.registerRenderThings();
После:
@Init
public void load(FMLInitializationEvent event)
{
Создайем классы: CommonProxyTutorial, и ClientProxy.
Немного изменяем CommonProxyTutorial:
package mods.testmod.src;
public class CommonProxyTutorial
{
public void registerRenderThings()
{
}
}
И изменяем ClientProxy:
package mods.testmod.src;
public class ClientProxy extends CommonProxyTutorial
{
@Override
public void registerRenderThings()
{
}
}
Тут:
public void registerRenderThings()
{
}
будем писать наши рендеры:
Например вы дальше будете смотреть туториалы и делать моба.
public void registerRenderThings()
{
RenderingRegistry.registerEntityRenderingHandler(EntityCreeperMan.class, new RenderCreeperMan(new ModelBiped(), 0.3F));
}
Вот и все.
Будем делать прокси, если мы например захотели сделать моба, или блок с моделью, и поставим этот мод на сервер, он закидает вас ошибками, или рендер просто не будет роботать, а прокси избавит нас от этой проблемы.
Добавляем в наш главный класс (базу):
@SidedProxy(clientSide = "mods.testmod.src.ClientProxy", serverSide = "mods.testmod.src.CommonProxyTutorial")
public static ClientProxy proxy;
После этого:
public class TestModBase {
Теперь регистрируем рендер в прокси:
proxy.registerRenderThings();
После:
@Init
public void load(FMLInitializationEvent event)
{
Создайем классы: CommonProxyTutorial, и ClientProxy.
Немного изменяем CommonProxyTutorial:
package mods.testmod.src;
public class CommonProxyTutorial
{
public void registerRenderThings()
{
}
}
И изменяем ClientProxy:
package mods.testmod.src;
public class ClientProxy extends CommonProxyTutorial
{
@Override
public void registerRenderThings()
{
}
}
Тут:
public void registerRenderThings()
{
}
будем писать наши рендеры:
Например вы дальше будете смотреть туториалы и делать моба.
public void registerRenderThings()
{
RenderingRegistry.registerEntityRenderingHandler(EntityCreeperMan.class, new RenderCreeperMan(new ModelBiped(), 0.3F));
}
Вот и все.
Туториал по созданию анимации для Модели.
Создание враждебного моба.
Что надо сделать для своей модели:
Создание враждебного моба.
[1.4.7]Туториал взят отсюда.
Будем делать человека-крипера, начнём!
TestModBase
package mods.testmod.src;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityEggInfo;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.world.biome.BiomeGenBase;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.registry.EntityRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
@Mod(modid = "TestMod", name = "Test Mod", version = "1.0")
@NetworkMod(clientSideRequired = true, serverSideRequired = false)
public class TestModBase
{
//путь к прокси
@SidedProxy(clientSide = "mods.testmod.src.ClientProxyMob", serverSide = "mods.testmod.src.CommonProxyTutorial")
public static ClientProxyMob proxy;
static int startEntityId = 300;//Айди яйца
@Init
public void load(FMLInitializationEvent event)
{
proxy.registerRenderThings();
/**
* 10 - как часто появляется, 2 - это минимальное появление мобов в мире, 4 - максимальное,
* EnumCreatureType.monster - будет спавнится ночью.
*/
EntityRegistry.registerModEntity(EntityCreeperMan.class, "Creeper Man", 1, this, 80, 3, true);
EntityRegistry.addSpawn(EntityCreeperMan.class, 10, 2, 4, EnumCreatureType.monster, BiomeGenBase.desert, BiomeGenBase.desertHills, BiomeGenBase.forest);
LanguageRegistry.instance().addStringLocalization("entity.TestMod.Creeper Man.name", "Creeper Man");
/**
* Цвет яйца, чтобы поменять цвет смотрите внизу туториала.
*/
registerEntityEgg(EntityCreeperMan.class, 0xffffff, 0x000000);
}
public static int getUniqueEntityId()
{
do
{
startEntityId++;
}
while (EntityList.getStringFromID(startEntityId) != null);
return startEntityId;
}
public static void registerEntityEgg(Class entity, int primaryColor, int secondaryColor)
{
int id = getUniqueEntityId();
EntityList.IDtoClassMapping.put(id, entity);
EntityList.entityEggs.put(id, new EntityEggInfo(id, primaryColor, secondaryColor));
}
}
Теперь EntityCreeperMan:
Вот текстура:
package mods.testmod.src;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EnumCreatureAttribute;
import net.minecraft.entity.ai.EntityAIAttackOnCollide;
import net.minecraft.entity.ai.EntityAIBreakDoor;
import net.minecraft.entity.ai.EntityAIHurtByTarget;
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
import net.minecraft.entity.ai.EntityAISwimming;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
public class EntityCreeperMan extends EntityMob
{
public EntityCreeperMan(World par1World)
{
super(par1World);
this.texture = "/mods/testmod/textures/creeper_man.png";
this.moveSpeed = 0.25F;//Скорость
this.tasks.addTask(0, new EntityAISwimming(this));
this.tasks.addTask(1, new EntityAIBreakDoor(this));
this.tasks.addTask(2, new EntityAIAttackOnCollide(this, EntityPlayer.class, this.moveSpeed, false));
this.tasks.addTask(3, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
this.tasks.addTask(4, new EntityAIWander(this, this.moveSpeed));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 16.0F, 0, true));
}
//Сила атаки.
public int getAttackStrength(Entity par1Entity) { return 4; }
protected boolean isAIEnabled()
{
return true;
}
//Здоровье
public int getMaxHealth()
{
return 20;
}
//Броня
public int getTotalArmorValue()
{
return 2;
}
//Будет гореть днём, как и зомби
public void onLivingUpdate()
{
if (this.worldObj.isDaytime() && !this.worldObj.isRemote && !this.isChild())
{
float var1 = this.getBrightness(1.0F);
if (var1 > 0.5F && this.rand.nextFloat() * 30.0F < (var1 - 0.4F) * 2.0F && this.worldObj.canBlockSeeTheSky(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)))
{
boolean var2 = true;
ItemStack var3 = this.getCurrentItemOrArmor(4);
if (var3 != null)
{
if (var3.isItemStackDamageable())
{
var3.setItemDamage(var3.getItemDamageForDisplay() + this.rand.nextInt(2));
if (var3.getItemDamageForDisplay() >= var3.getMaxDamage())
{
this.renderBrokenItemStack(var3);
this.setCurrentItemOrArmor(4, (ItemStack)null);
}
}
var2 = false;
}
if (var2)
{
this.setFire(8);
}
}
}
super.onLivingUpdate();
}
//Звуки моба
protected String getLivingSound()
{
return "mob.zombie.say";
}
protected String getHurtSound()
{
return "mob.zombie.hurt";
}
protected String getDeathSound()
{
return "mob.zombie.death";
}
protected void playStepSound(int par1, int par2, int par3, int par4)
{
this.worldObj.playSoundAtEntity(this, "mob.zombie.step", 0.15F, 1.0F);
}
protected void dropRareDrop(int par1)
{
switch (this.rand.nextInt(2))
{
case 0:
this.dropItem(Item.ingotIron.itemID, 1);
break;
case 1:
this.dropItem(Item.helmetSteel.itemID, 1);
break;
}
}
protected int getDropItemId()
{
return Item.diamond.itemID;
}
public EnumCreatureAttribute getCreatureAttribute()
{
return EnumCreatureAttribute.UNDEAD;
}
}
Теперь делаем прокси, CommonProxyTutorial:
package mods.testmod.src;
public class CommonProxyTutorial
{
public void registerRenderThings()
{
}
}
И ClientProxyMob:
package mods.testmod.src;
import cpw.mods.fml.client.registry.RenderingRegistry;
import net.minecraft.client.model.ModelBiped;
import net.minecraftforge.client.MinecraftForgeClient;
public class ClientProxyMob extends CommonProxyTutorial
{
@Override
public void registerRenderThings()
{
RenderingRegistry.registerEntityRenderingHandler(EntityCreeperMan.class, new RenderCreeperMan(new ModelBiped(), 0.3F));
}
}
И RenderCreeperMan:
package mods.testmod.src;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
public class RenderCreeperMan extends RenderLiving
{
protected ModelBiped model;
public RenderCreeperMan (ModelBiped modelBiped, float f)
{
super(modelBiped, f);
model = ((ModelBiped)mainModel);
}
public void renderCreeperMan(EntityCreeperMan entity, double par2, double par4, double par6, float par8, float par9)
{
super.doRenderLiving(entity, par2, par4, par6, par8, par9);
}
public void doRenderLiving(EntityLiving par1EntityLiving, double par2, double par4, double par6, float par8, float par9)
{
renderCreeperMan((EntityCreeperMan)par1EntityLiving, par2, par4, par6, par8, par9);
}
public void doRender(Entity par1Entity, double par2, double par4, double par6, float par8, float par9)
{
renderCreeperMan((EntityCreeperMan)par1Entity, par2, par4, par6, par8, par9);
}
}
Вот тут можете взять другой цвет для яйца.
Будем делать человека-крипера, начнём!
TestModBase
package mods.testmod.src;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityEggInfo;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.world.biome.BiomeGenBase;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.registry.EntityRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
@Mod(modid = "TestMod", name = "Test Mod", version = "1.0")
@NetworkMod(clientSideRequired = true, serverSideRequired = false)
public class TestModBase
{
//путь к прокси
@SidedProxy(clientSide = "mods.testmod.src.ClientProxyMob", serverSide = "mods.testmod.src.CommonProxyTutorial")
public static ClientProxyMob proxy;
static int startEntityId = 300;//Айди яйца
@Init
public void load(FMLInitializationEvent event)
{
proxy.registerRenderThings();
/**
* 10 - как часто появляется, 2 - это минимальное появление мобов в мире, 4 - максимальное,
* EnumCreatureType.monster - будет спавнится ночью.
*/
EntityRegistry.registerModEntity(EntityCreeperMan.class, "Creeper Man", 1, this, 80, 3, true);
EntityRegistry.addSpawn(EntityCreeperMan.class, 10, 2, 4, EnumCreatureType.monster, BiomeGenBase.desert, BiomeGenBase.desertHills, BiomeGenBase.forest);
LanguageRegistry.instance().addStringLocalization("entity.TestMod.Creeper Man.name", "Creeper Man");
/**
* Цвет яйца, чтобы поменять цвет смотрите внизу туториала.
*/
registerEntityEgg(EntityCreeperMan.class, 0xffffff, 0x000000);
}
public static int getUniqueEntityId()
{
do
{
startEntityId++;
}
while (EntityList.getStringFromID(startEntityId) != null);
return startEntityId;
}
public static void registerEntityEgg(Class entity, int primaryColor, int secondaryColor)
{
int id = getUniqueEntityId();
EntityList.IDtoClassMapping.put(id, entity);
EntityList.entityEggs.put(id, new EntityEggInfo(id, primaryColor, secondaryColor));
}
}
Теперь EntityCreeperMan:
Вот текстура:

package mods.testmod.src;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EnumCreatureAttribute;
import net.minecraft.entity.ai.EntityAIAttackOnCollide;
import net.minecraft.entity.ai.EntityAIBreakDoor;
import net.minecraft.entity.ai.EntityAIHurtByTarget;
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
import net.minecraft.entity.ai.EntityAISwimming;
import net.minecraft.entity.ai.EntityAIWander;
import net.minecraft.entity.ai.EntityAIWatchClosest;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
public class EntityCreeperMan extends EntityMob
{
public EntityCreeperMan(World par1World)
{
super(par1World);
this.texture = "/mods/testmod/textures/creeper_man.png";
this.moveSpeed = 0.25F;//Скорость
this.tasks.addTask(0, new EntityAISwimming(this));
this.tasks.addTask(1, new EntityAIBreakDoor(this));
this.tasks.addTask(2, new EntityAIAttackOnCollide(this, EntityPlayer.class, this.moveSpeed, false));
this.tasks.addTask(3, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
this.tasks.addTask(4, new EntityAIWander(this, this.moveSpeed));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 16.0F, 0, true));
}
//Сила атаки.
public int getAttackStrength(Entity par1Entity) { return 4; }
protected boolean isAIEnabled()
{
return true;
}
//Здоровье
public int getMaxHealth()
{
return 20;
}
//Броня
public int getTotalArmorValue()
{
return 2;
}
//Будет гореть днём, как и зомби
public void onLivingUpdate()
{
if (this.worldObj.isDaytime() && !this.worldObj.isRemote && !this.isChild())
{
float var1 = this.getBrightness(1.0F);
if (var1 > 0.5F && this.rand.nextFloat() * 30.0F < (var1 - 0.4F) * 2.0F && this.worldObj.canBlockSeeTheSky(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)))
{
boolean var2 = true;
ItemStack var3 = this.getCurrentItemOrArmor(4);
if (var3 != null)
{
if (var3.isItemStackDamageable())
{
var3.setItemDamage(var3.getItemDamageForDisplay() + this.rand.nextInt(2));
if (var3.getItemDamageForDisplay() >= var3.getMaxDamage())
{
this.renderBrokenItemStack(var3);
this.setCurrentItemOrArmor(4, (ItemStack)null);
}
}
var2 = false;
}
if (var2)
{
this.setFire(8);
}
}
}
super.onLivingUpdate();
}
//Звуки моба
protected String getLivingSound()
{
return "mob.zombie.say";
}
protected String getHurtSound()
{
return "mob.zombie.hurt";
}
protected String getDeathSound()
{
return "mob.zombie.death";
}
protected void playStepSound(int par1, int par2, int par3, int par4)
{
this.worldObj.playSoundAtEntity(this, "mob.zombie.step", 0.15F, 1.0F);
}
protected void dropRareDrop(int par1)
{
switch (this.rand.nextInt(2))
{
case 0:
this.dropItem(Item.ingotIron.itemID, 1);
break;
case 1:
this.dropItem(Item.helmetSteel.itemID, 1);
break;
}
}
protected int getDropItemId()
{
return Item.diamond.itemID;
}
public EnumCreatureAttribute getCreatureAttribute()
{
return EnumCreatureAttribute.UNDEAD;
}
}
Теперь делаем прокси, CommonProxyTutorial:
package mods.testmod.src;
public class CommonProxyTutorial
{
public void registerRenderThings()
{
}
}
И ClientProxyMob:
package mods.testmod.src;
import cpw.mods.fml.client.registry.RenderingRegistry;
import net.minecraft.client.model.ModelBiped;
import net.minecraftforge.client.MinecraftForgeClient;
public class ClientProxyMob extends CommonProxyTutorial
{
@Override
public void registerRenderThings()
{
RenderingRegistry.registerEntityRenderingHandler(EntityCreeperMan.class, new RenderCreeperMan(new ModelBiped(), 0.3F));
}
}
И RenderCreeperMan:
package mods.testmod.src;
import net.minecraft.client.model.ModelBiped;
import net.minecraft.client.renderer.entity.RenderLiving;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
public class RenderCreeperMan extends RenderLiving
{
protected ModelBiped model;
public RenderCreeperMan (ModelBiped modelBiped, float f)
{
super(modelBiped, f);
model = ((ModelBiped)mainModel);
}
public void renderCreeperMan(EntityCreeperMan entity, double par2, double par4, double par6, float par8, float par9)
{
super.doRenderLiving(entity, par2, par4, par6, par8, par9);
}
public void doRenderLiving(EntityLiving par1EntityLiving, double par2, double par4, double par6, float par8, float par9)
{
renderCreeperMan((EntityCreeperMan)par1EntityLiving, par2, par4, par6, par8, par9);
}
public void doRender(Entity par1Entity, double par2, double par4, double par6, float par8, float par9)
{
renderCreeperMan((EntityCreeperMan)par1Entity, par2, par4, par6, par8, par9);
}
}
Вот тут можете взять другой цвет для яйца.
Для своей модели нам надо немного изменить методы:
//Legleft, Legright, Body, Head - это название для примера, у вас может быть другое название, и другое количество.
public void render(Entity par1Entity, float par2, float par3, float par4, float par5, float par6, float par7)
{
super.render(par1Entity, par2, par3, par4, par5, par6, par7);
setRotationAngles(par2, par3, par4, par5, par6, par7, par1Entity);
Legleft.render(par7);
Legright.render(par7);
Body.render(par7);
Head.render(par7);
}
private void setRotation(ModelRenderer model, float x, float y, float z)
{
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
public void setRotationAngles(float par1, float par2, float par3, float par4, float par5, float par6, Entity par7Entity)
{
super.setRotationAngles(par1, par2, par3, par4, par5, par6, par7Entity);
}
//Legleft, Legright, Body, Head - это название для примера, у вас может быть другое название, и другое количество.
public void render(Entity par1Entity, float par2, float par3, float par4, float par5, float par6, float par7)
{
super.render(par1Entity, par2, par3, par4, par5, par6, par7);
setRotationAngles(par2, par3, par4, par5, par6, par7, par1Entity);
Legleft.render(par7);
Legright.render(par7);
Body.render(par7);
Head.render(par7);
}
private void setRotation(ModelRenderer model, float x, float y, float z)
{
model.rotateAngleX = x;
model.rotateAngleY = y;
model.rotateAngleZ = z;
}
public void setRotationAngles(float par1, float par2, float par3, float par4, float par5, float par6, Entity par7Entity)
{
super.setRotationAngles(par1, par2, par3, par4, par5, par6, par7Entity);
}
[1.4.7]Внимание: Автор этого туториала не я.
Модели делаем в Techne.
TestModBase:
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemReed;
import net.minecraftforge.common.Configuration;
import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.client.registry.RenderingRegistry;
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 = "TestModBase", name = "Test Mod", version = "0.0.1")
@NetworkMod (clientSideRequired = true, serverSideRequired = false, versionBounds = "1.0.0")
public class TestModBase {
public static int renderTestModelID;//это будет наш RenderType
public static Block testModel = new BlockTest(2020).setCreativeTab(CreativeTabs.tabDecorations).setHardness(0.0F).setUnlocalizedName("testModel");
@Instance("TestModBaseID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
GameRegistry.registerBlock(testModel);
GameRegistry.registerTileEntity( mods.testmod.src.TileEntityTestModel.class, "TileEntityTestModel" );
LanguageRegistry.addName(testModel, "Head");
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityTestModel.class, new RendererTestModel());//регистрируем рендер, и энтити
//это поможет нам отрендерить модель в руке, то-есть как сундук
renderTestModelID = RenderingRegistry.getNextAvailableRenderId();
RenderingRegistry.registerBlockHandler(renderTestModelID, new TestBlockHandler());
}
@PostInit
public void load(FMLPreInitializationEvent event)
{
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
}
Самое главное не забывайте менять родитель на BlockContainer, чтобы в комментариях не писать глупых вопросов!
Теперь BlockTest:
package mods.testmod.src;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.*;
public class BlockTest extends BlockContainer
{
public BlockTest(int id)
{
super(id, Material.ground);
}
public int getRenderType()
{
return TestModBase.renderTestModelID;//выбираем наш рендер
}
public boolean isOpaqueCube()
{
return false;
}
public boolean renderAsNormalBlock()
{
return false;
}
@Override
public TileEntity createNewTileEntity(World world)
{
return new TileEntityTestModel();
}
}
TileEntityTestModel:
package mods.testmod.src;
import net.minecraft.tileentity.TileEntity;
public class TileEntityTestModel extends TileEntity
{
public TileEntityTestModel()
{
}
}
И теперь TestBlockHandler, он нужен для регистрации нашего RenderType:
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.world.IBlockAccess;
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
public class TestBlockHandler implements ISimpleBlockRenderingHandler
{
@Override
public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer)
{
if(block == TestModBase.testModel)//выбираем тот блок у которого своя модель
TileEntityRenderer.instance.renderTileEntityAt(new TileEntityTestModel(), -0.5D, -0.5D, -0.5D, 0F);//Меняет расположения модели в руке
}
@Override
public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer)
{
return false;
}
@Override
public boolean shouldRender3DInInventory()
{
return true;
}
@Override
public int getRenderId()
{
return 0;
}
}
RendererTestModel:
package mods.testmod.src;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.renderer.tileentity.*;
import net.minecraft.tileentity.TileEntity;
public class RendererTestModel extends TileEntitySpecialRenderer
{
private static ModelHead model;//наша модель
public RendererTestModel()
{
model = new ModelHead();
}
public void renderTileEntityAt(TileEntity tileEntity, double d1, double d2, double d3, float f)
{
this.renderTileEntity((TileEntityTestModel)tileEntity, d1, d2, d3, f);
}
public void renderTileEntity(TileEntityTestModel tileEntity, double d1, double d2, double d3, float f)
{
GL11.glPushMatrix();
GL11.glTranslatef((float)d1 + 0.5F, (float)d2 + 1.5F, (float)d3 + 0.5F);
GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F);
this.bindTextureByName("/mods/testmod/textures/head.png");//текстура
this.model.render();
GL11.glPopMatrix();
}
}
И теперь модель, ModelHead (Голова Стива):
package mods.testmod.src;
import net.minecraft.client.model.*;//Добавлем это
import net.minecraft.entity.Entity;//И это
public class ModelHead extends ModelBase
{
//fields
ModelRenderer head;
public ModelHead()
{
textureWidth = 64;
textureHeight = 32;
head = new ModelRenderer(this, 0, 0);
head.addBox(-4F, -8F, -4F, 8, 8, 8);
head.setRotationPoint(0F, 24F, 0F);
head.setTextureSize(64, 32);
head.mirror = true;
setRotation(head, 0F, 0F, 0F);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5)
{
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5, entity);//Изменяем
head.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)
{
setRotationAngles(f, f1, f2, f3, f4, f5);//Изменяем
}
//Добавляем метод
public void render()
{
head.render(0.0625F);
}
}
Вот для сравнение оригинальная модель головы, (еще до изменения) ModelHead:
// Date: 06.02.2013 17:41:58
// Template version 1.1
// Java generated by Techne
// Keep in mind that you still need to fill in some blanks
// - ZeuX
package net.minecraft.src;
public class ModelNew extends ModelBase
{
//fields
ModelRenderer head;
public ModelNew()
{
textureWidth = 64;
textureHeight = 32;
head = new ModelRenderer(this, 0, 0);
head.addBox(-4F, -8F, -4F, 8, 8, 8);
head.setRotationPoint(0F, 24F, 0F);
head.setTextureSize(64, 32);
head.mirror = true;
setRotation(head, 0F, 0F, 0F);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5)
{
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5);
head.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)
{
super.setRotationAngles(f, f1, f2, f3, f4, f5);
}
}
Модели делаем в Techne.
TestModBase:
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemReed;
import net.minecraftforge.common.Configuration;
import cpw.mods.fml.client.registry.ClientRegistry;
import cpw.mods.fml.client.registry.RenderingRegistry;
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 = "TestModBase", name = "Test Mod", version = "0.0.1")
@NetworkMod (clientSideRequired = true, serverSideRequired = false, versionBounds = "1.0.0")
public class TestModBase {
public static int renderTestModelID;//это будет наш RenderType
public static Block testModel = new BlockTest(2020).setCreativeTab(CreativeTabs.tabDecorations).setHardness(0.0F).setUnlocalizedName("testModel");
@Instance("TestModBaseID")
public static TestModBase instance;
@Init
public void load(FMLInitializationEvent event)
{
GameRegistry.registerBlock(testModel);
GameRegistry.registerTileEntity( mods.testmod.src.TileEntityTestModel.class, "TileEntityTestModel" );
LanguageRegistry.addName(testModel, "Head");
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityTestModel.class, new RendererTestModel());//регистрируем рендер, и энтити
//это поможет нам отрендерить модель в руке, то-есть как сундук
renderTestModelID = RenderingRegistry.getNextAvailableRenderId();
RenderingRegistry.registerBlockHandler(renderTestModelID, new TestBlockHandler());
}
@PostInit
public void load(FMLPreInitializationEvent event)
{
}
@PreInit
public void preLoad(FMLPreInitializationEvent event)
{
}
}
Самое главное не забывайте менять родитель на BlockContainer, чтобы в комментариях не писать глупых вопросов!
Теперь BlockTest:
package mods.testmod.src;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.*;
public class BlockTest extends BlockContainer
{
public BlockTest(int id)
{
super(id, Material.ground);
}
public int getRenderType()
{
return TestModBase.renderTestModelID;//выбираем наш рендер
}
public boolean isOpaqueCube()
{
return false;
}
public boolean renderAsNormalBlock()
{
return false;
}
@Override
public TileEntity createNewTileEntity(World world)
{
return new TileEntityTestModel();
}
}
TileEntityTestModel:
package mods.testmod.src;
import net.minecraft.tileentity.TileEntity;
public class TileEntityTestModel extends TileEntity
{
public TileEntityTestModel()
{
}
}
И теперь TestBlockHandler, он нужен для регистрации нашего RenderType:
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
import net.minecraft.world.IBlockAccess;
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
public class TestBlockHandler implements ISimpleBlockRenderingHandler
{
@Override
public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer)
{
if(block == TestModBase.testModel)//выбираем тот блок у которого своя модель
TileEntityRenderer.instance.renderTileEntityAt(new TileEntityTestModel(), -0.5D, -0.5D, -0.5D, 0F);//Меняет расположения модели в руке
}
@Override
public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer)
{
return false;
}
@Override
public boolean shouldRender3DInInventory()
{
return true;
}
@Override
public int getRenderId()
{
return 0;
}
}
RendererTestModel:
package mods.testmod.src;
import org.lwjgl.opengl.GL11;
import net.minecraft.client.renderer.tileentity.*;
import net.minecraft.tileentity.TileEntity;
public class RendererTestModel extends TileEntitySpecialRenderer
{
private static ModelHead model;//наша модель
public RendererTestModel()
{
model = new ModelHead();
}
public void renderTileEntityAt(TileEntity tileEntity, double d1, double d2, double d3, float f)
{
this.renderTileEntity((TileEntityTestModel)tileEntity, d1, d2, d3, f);
}
public void renderTileEntity(TileEntityTestModel tileEntity, double d1, double d2, double d3, float f)
{
GL11.glPushMatrix();
GL11.glTranslatef((float)d1 + 0.5F, (float)d2 + 1.5F, (float)d3 + 0.5F);
GL11.glRotatef(180F, 0.0F, 0.0F, 1.0F);
this.bindTextureByName("/mods/testmod/textures/head.png");//текстура
this.model.render();
GL11.glPopMatrix();
}
}
И теперь модель, ModelHead (Голова Стива):
package mods.testmod.src;
import net.minecraft.client.model.*;//Добавлем это
import net.minecraft.entity.Entity;//И это
public class ModelHead extends ModelBase
{
//fields
ModelRenderer head;
public ModelHead()
{
textureWidth = 64;
textureHeight = 32;
head = new ModelRenderer(this, 0, 0);
head.addBox(-4F, -8F, -4F, 8, 8, 8);
head.setRotationPoint(0F, 24F, 0F);
head.setTextureSize(64, 32);
head.mirror = true;
setRotation(head, 0F, 0F, 0F);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5)
{
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5, entity);//Изменяем
head.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)
{
setRotationAngles(f, f1, f2, f3, f4, f5);//Изменяем
}
//Добавляем метод
public void render()
{
head.render(0.0625F);
}
}
Вот для сравнение оригинальная модель головы, (еще до изменения) ModelHead:
// Date: 06.02.2013 17:41:58
// Template version 1.1
// Java generated by Techne
// Keep in mind that you still need to fill in some blanks
// - ZeuX
package net.minecraft.src;
public class ModelNew extends ModelBase
{
//fields
ModelRenderer head;
public ModelNew()
{
textureWidth = 64;
textureHeight = 32;
head = new ModelRenderer(this, 0, 0);
head.addBox(-4F, -8F, -4F, 8, 8, 8);
head.setRotationPoint(0F, 24F, 0F);
head.setTextureSize(64, 32);
head.mirror = true;
setRotation(head, 0F, 0F, 0F);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5)
{
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5);
head.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)
{
super.setRotationAngles(f, f1, f2, f3, f4, f5);
}
}
Когда вы сделали печку/сундук, и не можете её открыть в игре, а в консоль пишет это:
A mod tried to open a gui on the server without being a NetworkMod
, или в консоль ничего не пишет, надо чтобы modid, и Instance совпадали.
Вот смотрите, у нас в туториале:
@Mod (modid = "TestModBase", name = "Test", version = "0.0.1")
, и
@Instance("TestModBase")
, если TestModBase не будут совпадать, то вы не сможете открыть сундук.
A mod tried to open a gui on the server without being a NetworkMod
, или в консоль ничего не пишет, надо чтобы modid, и Instance совпадали.
Вот смотрите, у нас в туториале:
@Mod (modid = "TestModBase", name = "Test", version = "0.0.1")
, и
@Instance("TestModBase")
, если TestModBase не будут совпадать, то вы не сможете открыть сундук.
Я взял стандартный сундук, и немного изменил, приступим...
(В сундуке возможно есть баги, о багах пишите в тему)
TestModBase:
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.item.ItemBlock;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.*;
import cpw.mods.fml.common.event.FMLInitializationEvent;
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;
@Mod(modid="TestModBase", name="TestModBase", version="1.0")
@NetworkMod (clientSideRequired = true, serverSideRequired = false, versionBounds = "1.0.0")
public class TestModBase {
@Instance("TestModBase")
public static TestModBase instance;
public static Block newChest = new BlockNewChest(2020, 0).setUnlocalizedName("newChest");
@Init
public void init(FMLInitializationEvent event)
{
GameRegistry.registerBlock(newChest);
LanguageRegistry.addName(newChest, "New Chest");
//Регистрируем Энтити
GameRegistry.registerTileEntity(TileEntityNewChest.class, "containerNew Chest");
//Нужен для регистрации GUI и Container
NetworkRegistry.instance().registerGuiHandler(this, new GuiHandler());
}
}
Теперь блок BlockNewChest:
package mods.testmod.src;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.util.Iterator;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.passive.EntityOcelot;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryLargeChest;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityChest;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.Icon;
import net.minecraft.util.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import static net.minecraftforge.common.ForgeDirection.*;
public class BlockNewChest extends BlockContainer
{
private final Random random = new Random();
public final int field_94443_a;
private Icon bottomIcon;
private Icon topIcon;
private Icon frontIcon;
private Icon sideIcon;
protected BlockNewChest(int par1, int par2)
{
super(par1, Material.wood);
this.field_94443_a = par2;
this.setCreativeTab(CreativeTabs.tabDecorations);
}
//Указываем путь к текстурам
@Override
public void registerIcons(IconRegister par1IconRegister) {
bottomIcon = par1IconRegister.registerIcon("testmod:bottom");
topIcon = par1IconRegister.registerIcon("testmod:top");
sideIcon = par1IconRegister.registerIcon("testmod:side");
frontIcon = par1IconRegister.registerIcon("testmod:front");
}
public Icon getBlockTextureFromSideAndMetadata(int side, int metadata)
{
if(side == 0)
return bottomIcon;
else if(side == 1)
return topIcon;
else if((side == 2 && metadata == 2) || (side == 5 && metadata == 3) || (side == 3 && metadata == 0) || (side == 4 && metadata == 1))
return frontIcon;
else
return sideIcon;
}
/**
* Checks the neighbor blocks to see if there is a chest there. Args: world, x, y, z
*/
private boolean isThereANeighborChest(World par1World, int par2, int par3, int par4)
{
return par1World.getBlockId(par2, par3, par4) != this.blockID ? false : (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID ? true : (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID ? true : (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID ? true : par1World.getBlockId(par2, par3, par4 + 1) == this.blockID)));
}
/**
* Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
* their own) Args: x, y, z, neighbor blockID
*/
public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
{
super.onNeighborBlockChange(par1World, par2, par3, par4, par5);
TileEntityNewChest tileentitychest = (TileEntityNewChest)par1World.getBlockTileEntity(par2, par3, par4);
if (tileentitychest != null)
{
tileentitychest.updateContainingBlockInfo();
}
}
@Override
public void breakBlock(World world, int x, int y, int z, int par5, int par6) {
dropItems(world, x, y, z);
super.breakBlock(world, x, y, z, par5, par6);
}
private void dropItems(World world, int x, int y, int z){
Random rand = new Random();
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
if (!(tileEntity instanceof IInventory)) {
return;
}
IInventory inventory = (IInventory) tileEntity;
for (int i = 0; i < inventory.getSizeInventory(); i++) {
ItemStack item = inventory.getStackInSlot(i);
if (item != null && item.stackSize > 0) {
float rx = rand.nextFloat() * 0.8F + 0.1F;
float ry = rand.nextFloat() * 0.8F + 0.1F;
float rz = rand.nextFloat() * 0.8F + 0.1F;
EntityItem entityItem = new EntityItem(world,
x + rx, y + ry, z + rz,
new ItemStack(item.itemID, item.stackSize, item.getItemDamage()));
if (item.hasTagCompound()) {
entityItem.getEntityItem().setTagCompound((NBTTagCompound) item.getTagCompound().copy());
}
float factor = 0.05F;
entityItem.motionX = rand.nextGaussian() * factor;
entityItem.motionY = rand.nextGaussian() * factor + 0.2F;
entityItem.motionZ = rand.nextGaussian() * factor;
world.spawnEntityInWorld(entityItem);
item.stackSize = 0;
}
}
}
@Override
public boolean onBlockActivated(World world, int x, int y, int z,
EntityPlayer player, int idk, float what, float these, float are) {
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
if (tileEntity == null || player.isSneaking()) {
return false;
}
//Открывает GUI
player.openGui(TestModBase.instance, 0, world, x, y, z);
return true;
}
public IInventory func_94442_h_(World par1World, int par2, int par3, int par4)
{
Object object = (TileEntityNewChest)par1World.getBlockTileEntity(par2, par3, par4);
if (object == null)
{
return null;
}
else if (par1World.isBlockSolidOnSide(par2, par3 + 1, par4, DOWN))
{
return null;
}
else if (isOcelotBlockingChest(par1World, par2, par3, par4))
{
return null;
}
else if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID && (par1World.isBlockSolidOnSide(par2 - 1, par3 + 1, par4, DOWN) || isOcelotBlockingChest(par1World, par2 - 1, par3, par4)))
{
return null;
}
else if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID && (par1World.isBlockSolidOnSide(par2 + 1, par3 + 1, par4, DOWN) || isOcelotBlockingChest(par1World, par2 + 1, par3, par4)))
{
return null;
}
else if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID && (par1World.isBlockSolidOnSide(par2, par3 + 1, par4 - 1, DOWN) || isOcelotBlockingChest(par1World, par2, par3, par4 - 1)))
{
return null;
}
else if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID && (par1World.isBlockSolidOnSide(par2, par3 + 1, par4 + 1, DOWN) || isOcelotBlockingChest(par1World, par2, par3, par4 + 1)))
{
return null;
}
else
{
if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID)
{
object = new InventoryLargeChest("container.chestDouble", (TileEntityNewChest)par1World.getBlockTileEntity(par2 - 1, par3, par4), (IInventory)object);
}
if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID)
{
object = new InventoryLargeChest("container.chestDouble", (IInventory)object, (TileEntityNewChest)par1World.getBlockTileEntity(par2 + 1, par3, par4));
}
if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID)
{
object = new InventoryLargeChest("container.chestDouble", (TileEntityNewChest)par1World.getBlockTileEntity(par2, par3, par4 - 1), (IInventory)object);
}
if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID)
{
object = new InventoryLargeChest("container.chestDouble", (IInventory)object, (TileEntityNewChest)par1World.getBlockTileEntity(par2, par3, par4 + 1));
}
return (IInventory)object;
}
}
/**
* Returns a new instance of a block's tile entity class. Called on placing the block.
*/
public TileEntity createNewTileEntity(World par1World)
{
TileEntityNewChest tileentitychest = new TileEntityNewChest();
return tileentitychest;
}
/**
* Can this block provide power. Only wire currently seems to have this change based on its state.
*/
public boolean canProvidePower()
{
return this.field_94443_a == 1;
}
/**
* Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube
* returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X,
* Y, Z, side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
*/
public int isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
{
if (!this.canProvidePower())
{
return 0;
}
else
{
int i1 = ((TileEntityNewChest)par1IBlockAccess.getBlockTileEntity(par2, par3, par4)).numUsingPlayers;
return MathHelper.clamp_int(i1, 0, 15);
}
}
/**
* Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z,
* side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
*/
public int isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
{
return par5 == 1 ? this.isProvidingWeakPower(par1IBlockAccess, par2, par3, par4, par5) : 0;
}
/**
* Looks for a sitting ocelot within certain bounds. Such an ocelot is considered to be blocking access to the
* chest.
*/
public static boolean isOcelotBlockingChest(World par0World, int par1, int par2, int par3)
{
Iterator iterator = par0World.getEntitiesWithinAABB(EntityOcelot.class, AxisAlignedBB.getAABBPool().getAABB((double)par1, (double)(par2 + 1), (double)par3, (double)(par1 + 1), (double)(par2 + 2), (double)(par3 + 1))).iterator();
EntityOcelot entityocelot;
do
{
if (!iterator.hasNext())
{
return false;
}
EntityOcelot entityocelot1 = (EntityOcelot)iterator.next();
entityocelot = (EntityOcelot)entityocelot1;
}
while (!entityocelot.isSitting());
return true;
}
/**
* If this returns true, then comparators facing away from this block will use the value from
* getComparatorInputOverride instead of the actual redstone signal strength.
*/
public boolean hasComparatorInputOverride()
{
return true;
}
/**
* If hasComparatorInputOverride returns true, the return value from this is used instead of the redstone signal
* strength when this block inputs to a comparator.
*/
public int getComparatorInputOverride(World par1World, int par2, int par3, int par4, int par5)
{
return Container.func_94526_b(this.func_94442_h_(par1World, par2, par3, par4));
}
}
TileEntityNewChest:
package mods.testmod.src;
import java.util.Iterator;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.BlockChest;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryLargeChest;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
public class TileEntityNewChest extends TileEntity implements IInventory
{
private ItemStack[] chestContents = new ItemStack[36];
/** Determines if the check for adjacent chests has taken place. */
public boolean adjacentChestChecked = false;
/** Contains the chest tile located adjacent to this one (if any) */
public TileEntityNewChest adjacentChestZNeg;
/** Contains the chest tile located adjacent to this one (if any) */
public TileEntityNewChest adjacentChestXPos;
/** Contains the chest tile located adjacent to this one (if any) */
public TileEntityNewChest adjacentChestXNeg;
/** Contains the chest tile located adjacent to this one (if any) */
public TileEntityNewChest adjacentChestZPosition;
/** The current angle of the lid (between 0 and 1) */
public float lidAngle;
/** The angle of the lid last tick */
public float prevLidAngle;
/** The number of players currently using this chest */
public int numUsingPlayers;
/** Server sync counter (once per 20 ticks) */
private int ticksSinceSync;
private int field_94046_i = -1;
private String field_94045_s;
/**
* Returns the number of slots in the inventory.
*/
public int getSizeInventory()
{
return 27;
}
/**
* Returns the stack in slot i
*/
public ItemStack getStackInSlot(int par1)
{
return this.chestContents[par1];
}
/**
* Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
* new stack.
*/
public ItemStack decrStackSize(int par1, int par2)
{
if (this.chestContents[par1] != null)
{
ItemStack itemstack;
if (this.chestContents[par1].stackSize this.getInventoryStackLimit())
{
par2ItemStack.stackSize = this.getInventoryStackLimit();
}
this.onInventoryChanged();
}
/**
* Имя сундука в в инвентаре
*/
public String getInvName()
{
return "New Chest";
}
@Override
public boolean isInvNameLocalized() {
// TODO Auto-generated method stub
return false;
}
/**
* Reads a tile entity from NBT.
*/
public void readFromNBT(NBTTagCompound par1NBTTagCompound)
{
super.readFromNBT(par1NBTTagCompound);
NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items");
this.chestContents = new ItemStack[this.getSizeInventory()];
if (par1NBTTagCompound.hasKey("CustomName"))
{
this.field_94045_s = par1NBTTagCompound.getString("CustomName");
}
for (int i = 0; i < nbttaglist.tagCount(); ++i)
{
NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i);
int j = nbttagcompound1.getByte("Slot") & 255;
if (j >= 0 && j < this.chestContents.length)
{
this.chestContents[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
}
}
}
/**
* Writes a tile entity to NBT.
*/
public void writeToNBT(NBTTagCompound par1NBTTagCompound)
{
super.writeToNBT(par1NBTTagCompound);
NBTTagList nbttaglist = new NBTTagList();
for (int i = 0; i < this.chestContents.length; ++i)
{
if (this.chestContents != null)
{
NBTTagCompound nbttagcompound1 = new NBTTagCompound();
nbttagcompound1.setByte("Slot", (byte)i);
this.chestContents.writeToNBT(nbttagcompound1);
nbttaglist.appendTag(nbttagcompound1);
}
}
par1NBTTagCompound.setTag("Items", nbttaglist);
if (this.isInvNameLocalized())
{
par1NBTTagCompound.setString("CustomName", this.field_94045_s);
}
}
/**
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
* this more of a set than a get?*
*/
public int getInventoryStackLimit()
{
return 64;
}
/**
* Do not make give this method the name canInteractWith because it clashes with Container
*/
public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
{
return this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord) != this ? false : par1EntityPlayer.getDistanceSq((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D) 0 && this.lidAngle == 0.0F && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
{
double d1 = (double)this.xCoord + 0.5D;
d0 = (double)this.zCoord + 0.5D;
if (this.adjacentChestZPosition != null)
{
d0 += 0.5D;
}
if (this.adjacentChestXPos != null)
{
d1 += 0.5D;
}
this.worldObj.playSoundEffect(d1, (double)this.yCoord + 0.5D, d0, "random.chestopen", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F);
}
if (this.numUsingPlayers == 0 && this.lidAngle > 0.0F || this.numUsingPlayers > 0 && this.lidAngle < 1.0F)
{
float f1 = this.lidAngle;
if (this.numUsingPlayers > 0)
{
this.lidAngle += f;
}
else
{
this.lidAngle -= f;
}
if (this.lidAngle > 1.0F)
{
this.lidAngle = 1.0F;
}
float f2 = 0.5F;
if (this.lidAngle < f2 && f1 >= f2 && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
{
d0 = (double)this.xCoord + 0.5D;
double d2 = (double)this.zCoord + 0.5D;
if (this.adjacentChestZPosition != null)
{
d2 += 0.5D;
}
if (this.adjacentChestXPos != null)
{
d0 += 0.5D;
}
this.worldObj.playSoundEffect(d0, (double)this.yCoord + 0.5D, d2, "random.chestclosed", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F);
}
if (this.lidAngle < 0.0F)
{
this.lidAngle = 0.0F;
}
}
}
/**
* Called when a client event is received with the event number and argument, see World.sendClientEvent
*/
public boolean receiveClientEvent(int par1, int par2)
{
if (par1 == 1)
{
this.numUsingPlayers = par2;
return true;
}
else
{
return super.receiveClientEvent(par1, par2);
}
}
public void openChest()
{
if (this.numUsingPlayers < 0)
{
this.numUsingPlayers = 0;
}
++this.numUsingPlayers;
this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID, 1, this.numUsingPlayers);
this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID);
this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord - 1, this.zCoord, this.getBlockType().blockID);
}
public void closeChest()
{
if (this.getBlockType() != null && this.getBlockType() instanceof BlockChest)
{
--this.numUsingPlayers;
this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID, 1, this.numUsingPlayers);
this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID);
this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord - 1, this.zCoord, this.getBlockType().blockID);
}
}
/**
* Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot.
*/
public boolean isStackValidForSlot(int par1, ItemStack par2ItemStack)
{
return true;
}
/**
* invalidates a tile entity
*/
public void invalidate()
{
super.invalidate();
this.updateContainingBlockInfo();
}
}
Теперь самое главное, GuiHandler:
package mods.testmod.src;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import cpw.mods.fml.common.network.IGuiHandler;
public class GuiHandler implements IGuiHandler {
@Override
public Object getServerGuiElement(int id, EntityPlayer player, World world,
int x, int y, int z) {
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
//Открывает наш контейнер
if(tileEntity instanceof TileEntityNewChest)
{
return new ContainerNewChest(player.inventory, (TileEntityNewChest) tileEntity);
}
return null;
}
@Override
public Object getClientGuiElement(int id, EntityPlayer player, World world,
int x, int y, int z) {
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
//Открывает наше GUI
if(tileEntity instanceof TileEntityNewChest)
{
return new GuiNewChest(player.inventory, (TileEntityNewChest) tileEntity);
}
return null;
}
}
ContainerNewChest:
package mods.testmod.src;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
public class ContainerNewChest extends Container
{
private IInventory lowerChestInventory;
private int numRows;
public ContainerNewChest(IInventory par1IInventory, IInventory par2IInventory)
{
this.lowerChestInventory = par2IInventory;
this.numRows = par2IInventory.getSizeInventory() / 9;
par2IInventory.openChest();
int i = (this.numRows - 4) * 18;
int j;
int k;
for (j = 0; j < this.numRows; ++j)
{
for (k = 0; k < 9; ++k)
{
this.addSlotToContainer(new Slot(par2IInventory, k + j * 9, 8 + k * 18, 18 + j * 18));
}
}
for (j = 0; j < 3; ++j)
{
for (k = 0; k < 9; ++k)
{
this.addSlotToContainer(new Slot(par1IInventory, k + j * 9 + 9, 8 + k * 18, 103 + j * 18 + i));
}
}
for (j = 0; j < 9; ++j)
{
this.addSlotToContainer(new Slot(par1IInventory, j, 8 + j * 18, 161 + i));
}
}
public boolean canInteractWith(EntityPlayer par1EntityPlayer)
{
return this.lowerChestInventory.isUseableByPlayer(par1EntityPlayer);
}
/**
* Called when a player shift-clicks on a slot. You must override this or you will crash when someone does that.
*/
public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int par2)
{
ItemStack itemstack = null;
Slot slot = (Slot)this.inventorySlots.get(par2);
if (slot != null && slot.getHasStack())
{
ItemStack itemstack1 = slot.getStack();
itemstack = itemstack1.copy();
if (par2 < this.numRows * 9)
{
if (!this.mergeItemStack(itemstack1, this.numRows * 9, this.inventorySlots.size(), true))
{
return null;
}
}
else if (!this.mergeItemStack(itemstack1, 0, this.numRows * 9, false))
{
return null;
}
if (itemstack1.stackSize == 0)
{
slot.putStack((ItemStack)null);
}
else
{
slot.onSlotChanged();
}
}
return itemstack;
}
/**
* Callback for when the crafting gui is closed.
*/
public void onCraftGuiClosed(EntityPlayer par1EntityPlayer)
{
super.onCraftGuiClosed(par1EntityPlayer);
this.lowerChestInventory.closeChest();
}
/**
* Return this chest container's lower chest inventory.
*/
public IInventory getLowerChestInventory()
{
return this.lowerChestInventory;
}
}
И последнее GuiNewChest:
package mods.testmod.src;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
import net.minecraft.util.StatCollector;
import org.lwjgl.opengl.GL11;
@SideOnly(Side.CLIENT)
public class GuiNewChest extends GuiContainer
{
private IInventory upperChestInventory;
private IInventory lowerChestInventory;
/**
* window height is calculated with this values, the more rows, the heigher
*/
private int inventoryRows = 0;
public GuiNewChest(IInventory par1IInventory, IInventory par2IInventory)
{
super(new ContainerChest(par1IInventory, par2IInventory));
this.upperChestInventory = par1IInventory;
this.lowerChestInventory = par2IInventory;
this.allowUserInput = false;
short short1 = 222;
int i = short1 - 108;
this.inventoryRows = par2IInventory.getSizeInventory() / 9;
this.ySize = i + this.inventoryRows * 18;
}
/**
* Draw the foreground layer for the GuiContainer (everything in front of the items)
*/
protected void drawGuiContainerForegroundLayer(int par1, int par2)
{
this.fontRenderer.drawString(this.lowerChestInventory.isInvNameLocalized() ? this.lowerChestInventory.getInvName() : StatCollector.translateToLocal(this.lowerChestInventory.getInvName()), 8, 6, 4210752);
this.fontRenderer.drawString(this.upperChestInventory.isInvNameLocalized() ? this.upperChestInventory.getInvName() : StatCollector.translateToLocal(this.upperChestInventory.getInvName()), 8, this.ySize - 96 + 2, 4210752);
}
/**
* Draw the background layer for the GuiContainer (everything behind the items)
*/
protected void drawGuiContainerBackgroundLayer(float par1, int par2, int par3)
{
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
this.mc.renderEngine.bindTexture("/gui/container.png");//Путь к GUI, мы сделаем с стандартным
int k = (this.width - this.xSize) / 2;
int l = (this.height - this.ySize) / 2;
this.drawTexturedModalRect(k, l, 0, 0, this.xSize, this.inventoryRows * 18 + 17);
this.drawTexturedModalRect(k, l + this.inventoryRows * 18 + 17, 0, 126, this.xSize, 96);
}
}
(В сундуке возможно есть баги, о багах пишите в тему)
TestModBase:
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.item.ItemBlock;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.*;
import cpw.mods.fml.common.event.FMLInitializationEvent;
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;
@Mod(modid="TestModBase", name="TestModBase", version="1.0")
@NetworkMod (clientSideRequired = true, serverSideRequired = false, versionBounds = "1.0.0")
public class TestModBase {
@Instance("TestModBase")
public static TestModBase instance;
public static Block newChest = new BlockNewChest(2020, 0).setUnlocalizedName("newChest");
@Init
public void init(FMLInitializationEvent event)
{
GameRegistry.registerBlock(newChest);
LanguageRegistry.addName(newChest, "New Chest");
//Регистрируем Энтити
GameRegistry.registerTileEntity(TileEntityNewChest.class, "containerNew Chest");
//Нужен для регистрации GUI и Container
NetworkRegistry.instance().registerGuiHandler(this, new GuiHandler());
}
}
Теперь блок BlockNewChest:
package mods.testmod.src;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import java.util.Iterator;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.passive.EntityOcelot;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryLargeChest;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityChest;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.Icon;
import net.minecraft.util.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import static net.minecraftforge.common.ForgeDirection.*;
public class BlockNewChest extends BlockContainer
{
private final Random random = new Random();
public final int field_94443_a;
private Icon bottomIcon;
private Icon topIcon;
private Icon frontIcon;
private Icon sideIcon;
protected BlockNewChest(int par1, int par2)
{
super(par1, Material.wood);
this.field_94443_a = par2;
this.setCreativeTab(CreativeTabs.tabDecorations);
}
//Указываем путь к текстурам
@Override
public void registerIcons(IconRegister par1IconRegister) {
bottomIcon = par1IconRegister.registerIcon("testmod:bottom");
topIcon = par1IconRegister.registerIcon("testmod:top");
sideIcon = par1IconRegister.registerIcon("testmod:side");
frontIcon = par1IconRegister.registerIcon("testmod:front");
}
public Icon getBlockTextureFromSideAndMetadata(int side, int metadata)
{
if(side == 0)
return bottomIcon;
else if(side == 1)
return topIcon;
else if((side == 2 && metadata == 2) || (side == 5 && metadata == 3) || (side == 3 && metadata == 0) || (side == 4 && metadata == 1))
return frontIcon;
else
return sideIcon;
}
/**
* Checks the neighbor blocks to see if there is a chest there. Args: world, x, y, z
*/
private boolean isThereANeighborChest(World par1World, int par2, int par3, int par4)
{
return par1World.getBlockId(par2, par3, par4) != this.blockID ? false : (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID ? true : (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID ? true : (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID ? true : par1World.getBlockId(par2, par3, par4 + 1) == this.blockID)));
}
/**
* Lets the block know when one of its neighbor changes. Doesn't know which neighbor changed (coordinates passed are
* their own) Args: x, y, z, neighbor blockID
*/
public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
{
super.onNeighborBlockChange(par1World, par2, par3, par4, par5);
TileEntityNewChest tileentitychest = (TileEntityNewChest)par1World.getBlockTileEntity(par2, par3, par4);
if (tileentitychest != null)
{
tileentitychest.updateContainingBlockInfo();
}
}
@Override
public void breakBlock(World world, int x, int y, int z, int par5, int par6) {
dropItems(world, x, y, z);
super.breakBlock(world, x, y, z, par5, par6);
}
private void dropItems(World world, int x, int y, int z){
Random rand = new Random();
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
if (!(tileEntity instanceof IInventory)) {
return;
}
IInventory inventory = (IInventory) tileEntity;
for (int i = 0; i < inventory.getSizeInventory(); i++) {
ItemStack item = inventory.getStackInSlot(i);
if (item != null && item.stackSize > 0) {
float rx = rand.nextFloat() * 0.8F + 0.1F;
float ry = rand.nextFloat() * 0.8F + 0.1F;
float rz = rand.nextFloat() * 0.8F + 0.1F;
EntityItem entityItem = new EntityItem(world,
x + rx, y + ry, z + rz,
new ItemStack(item.itemID, item.stackSize, item.getItemDamage()));
if (item.hasTagCompound()) {
entityItem.getEntityItem().setTagCompound((NBTTagCompound) item.getTagCompound().copy());
}
float factor = 0.05F;
entityItem.motionX = rand.nextGaussian() * factor;
entityItem.motionY = rand.nextGaussian() * factor + 0.2F;
entityItem.motionZ = rand.nextGaussian() * factor;
world.spawnEntityInWorld(entityItem);
item.stackSize = 0;
}
}
}
@Override
public boolean onBlockActivated(World world, int x, int y, int z,
EntityPlayer player, int idk, float what, float these, float are) {
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
if (tileEntity == null || player.isSneaking()) {
return false;
}
//Открывает GUI
player.openGui(TestModBase.instance, 0, world, x, y, z);
return true;
}
public IInventory func_94442_h_(World par1World, int par2, int par3, int par4)
{
Object object = (TileEntityNewChest)par1World.getBlockTileEntity(par2, par3, par4);
if (object == null)
{
return null;
}
else if (par1World.isBlockSolidOnSide(par2, par3 + 1, par4, DOWN))
{
return null;
}
else if (isOcelotBlockingChest(par1World, par2, par3, par4))
{
return null;
}
else if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID && (par1World.isBlockSolidOnSide(par2 - 1, par3 + 1, par4, DOWN) || isOcelotBlockingChest(par1World, par2 - 1, par3, par4)))
{
return null;
}
else if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID && (par1World.isBlockSolidOnSide(par2 + 1, par3 + 1, par4, DOWN) || isOcelotBlockingChest(par1World, par2 + 1, par3, par4)))
{
return null;
}
else if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID && (par1World.isBlockSolidOnSide(par2, par3 + 1, par4 - 1, DOWN) || isOcelotBlockingChest(par1World, par2, par3, par4 - 1)))
{
return null;
}
else if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID && (par1World.isBlockSolidOnSide(par2, par3 + 1, par4 + 1, DOWN) || isOcelotBlockingChest(par1World, par2, par3, par4 + 1)))
{
return null;
}
else
{
if (par1World.getBlockId(par2 - 1, par3, par4) == this.blockID)
{
object = new InventoryLargeChest("container.chestDouble", (TileEntityNewChest)par1World.getBlockTileEntity(par2 - 1, par3, par4), (IInventory)object);
}
if (par1World.getBlockId(par2 + 1, par3, par4) == this.blockID)
{
object = new InventoryLargeChest("container.chestDouble", (IInventory)object, (TileEntityNewChest)par1World.getBlockTileEntity(par2 + 1, par3, par4));
}
if (par1World.getBlockId(par2, par3, par4 - 1) == this.blockID)
{
object = new InventoryLargeChest("container.chestDouble", (TileEntityNewChest)par1World.getBlockTileEntity(par2, par3, par4 - 1), (IInventory)object);
}
if (par1World.getBlockId(par2, par3, par4 + 1) == this.blockID)
{
object = new InventoryLargeChest("container.chestDouble", (IInventory)object, (TileEntityNewChest)par1World.getBlockTileEntity(par2, par3, par4 + 1));
}
return (IInventory)object;
}
}
/**
* Returns a new instance of a block's tile entity class. Called on placing the block.
*/
public TileEntity createNewTileEntity(World par1World)
{
TileEntityNewChest tileentitychest = new TileEntityNewChest();
return tileentitychest;
}
/**
* Can this block provide power. Only wire currently seems to have this change based on its state.
*/
public boolean canProvidePower()
{
return this.field_94443_a == 1;
}
/**
* Returns true if the block is emitting indirect/weak redstone power on the specified side. If isBlockNormalCube
* returns true, standard redstone propagation rules will apply instead and this will not be called. Args: World, X,
* Y, Z, side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
*/
public int isProvidingWeakPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
{
if (!this.canProvidePower())
{
return 0;
}
else
{
int i1 = ((TileEntityNewChest)par1IBlockAccess.getBlockTileEntity(par2, par3, par4)).numUsingPlayers;
return MathHelper.clamp_int(i1, 0, 15);
}
}
/**
* Returns true if the block is emitting direct/strong redstone power on the specified side. Args: World, X, Y, Z,
* side. Note that the side is reversed - eg it is 1 (up) when checking the bottom of the block.
*/
public int isProvidingStrongPower(IBlockAccess par1IBlockAccess, int par2, int par3, int par4, int par5)
{
return par5 == 1 ? this.isProvidingWeakPower(par1IBlockAccess, par2, par3, par4, par5) : 0;
}
/**
* Looks for a sitting ocelot within certain bounds. Such an ocelot is considered to be blocking access to the
* chest.
*/
public static boolean isOcelotBlockingChest(World par0World, int par1, int par2, int par3)
{
Iterator iterator = par0World.getEntitiesWithinAABB(EntityOcelot.class, AxisAlignedBB.getAABBPool().getAABB((double)par1, (double)(par2 + 1), (double)par3, (double)(par1 + 1), (double)(par2 + 2), (double)(par3 + 1))).iterator();
EntityOcelot entityocelot;
do
{
if (!iterator.hasNext())
{
return false;
}
EntityOcelot entityocelot1 = (EntityOcelot)iterator.next();
entityocelot = (EntityOcelot)entityocelot1;
}
while (!entityocelot.isSitting());
return true;
}
/**
* If this returns true, then comparators facing away from this block will use the value from
* getComparatorInputOverride instead of the actual redstone signal strength.
*/
public boolean hasComparatorInputOverride()
{
return true;
}
/**
* If hasComparatorInputOverride returns true, the return value from this is used instead of the redstone signal
* strength when this block inputs to a comparator.
*/
public int getComparatorInputOverride(World par1World, int par2, int par3, int par4, int par5)
{
return Container.func_94526_b(this.func_94442_h_(par1World, par2, par3, par4));
}
}
TileEntityNewChest:
package mods.testmod.src;
import java.util.Iterator;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.BlockChest;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryLargeChest;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
public class TileEntityNewChest extends TileEntity implements IInventory
{
private ItemStack[] chestContents = new ItemStack[36];
/** Determines if the check for adjacent chests has taken place. */
public boolean adjacentChestChecked = false;
/** Contains the chest tile located adjacent to this one (if any) */
public TileEntityNewChest adjacentChestZNeg;
/** Contains the chest tile located adjacent to this one (if any) */
public TileEntityNewChest adjacentChestXPos;
/** Contains the chest tile located adjacent to this one (if any) */
public TileEntityNewChest adjacentChestXNeg;
/** Contains the chest tile located adjacent to this one (if any) */
public TileEntityNewChest adjacentChestZPosition;
/** The current angle of the lid (between 0 and 1) */
public float lidAngle;
/** The angle of the lid last tick */
public float prevLidAngle;
/** The number of players currently using this chest */
public int numUsingPlayers;
/** Server sync counter (once per 20 ticks) */
private int ticksSinceSync;
private int field_94046_i = -1;
private String field_94045_s;
/**
* Returns the number of slots in the inventory.
*/
public int getSizeInventory()
{
return 27;
}
/**
* Returns the stack in slot i
*/
public ItemStack getStackInSlot(int par1)
{
return this.chestContents[par1];
}
/**
* Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
* new stack.
*/
public ItemStack decrStackSize(int par1, int par2)
{
if (this.chestContents[par1] != null)
{
ItemStack itemstack;
if (this.chestContents[par1].stackSize this.getInventoryStackLimit())
{
par2ItemStack.stackSize = this.getInventoryStackLimit();
}
this.onInventoryChanged();
}
/**
* Имя сундука в в инвентаре
*/
public String getInvName()
{
return "New Chest";
}
@Override
public boolean isInvNameLocalized() {
// TODO Auto-generated method stub
return false;
}
/**
* Reads a tile entity from NBT.
*/
public void readFromNBT(NBTTagCompound par1NBTTagCompound)
{
super.readFromNBT(par1NBTTagCompound);
NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items");
this.chestContents = new ItemStack[this.getSizeInventory()];
if (par1NBTTagCompound.hasKey("CustomName"))
{
this.field_94045_s = par1NBTTagCompound.getString("CustomName");
}
for (int i = 0; i < nbttaglist.tagCount(); ++i)
{
NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i);
int j = nbttagcompound1.getByte("Slot") & 255;
if (j >= 0 && j < this.chestContents.length)
{
this.chestContents[j] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
}
}
}
/**
* Writes a tile entity to NBT.
*/
public void writeToNBT(NBTTagCompound par1NBTTagCompound)
{
super.writeToNBT(par1NBTTagCompound);
NBTTagList nbttaglist = new NBTTagList();
for (int i = 0; i < this.chestContents.length; ++i)
{
if (this.chestContents != null)
{
NBTTagCompound nbttagcompound1 = new NBTTagCompound();
nbttagcompound1.setByte("Slot", (byte)i);
this.chestContents.writeToNBT(nbttagcompound1);
nbttaglist.appendTag(nbttagcompound1);
}
}
par1NBTTagCompound.setTag("Items", nbttaglist);
if (this.isInvNameLocalized())
{
par1NBTTagCompound.setString("CustomName", this.field_94045_s);
}
}
/**
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
* this more of a set than a get?*
*/
public int getInventoryStackLimit()
{
return 64;
}
/**
* Do not make give this method the name canInteractWith because it clashes with Container
*/
public boolean isUseableByPlayer(EntityPlayer par1EntityPlayer)
{
return this.worldObj.getBlockTileEntity(this.xCoord, this.yCoord, this.zCoord) != this ? false : par1EntityPlayer.getDistanceSq((double)this.xCoord + 0.5D, (double)this.yCoord + 0.5D, (double)this.zCoord + 0.5D) 0 && this.lidAngle == 0.0F && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
{
double d1 = (double)this.xCoord + 0.5D;
d0 = (double)this.zCoord + 0.5D;
if (this.adjacentChestZPosition != null)
{
d0 += 0.5D;
}
if (this.adjacentChestXPos != null)
{
d1 += 0.5D;
}
this.worldObj.playSoundEffect(d1, (double)this.yCoord + 0.5D, d0, "random.chestopen", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F);
}
if (this.numUsingPlayers == 0 && this.lidAngle > 0.0F || this.numUsingPlayers > 0 && this.lidAngle < 1.0F)
{
float f1 = this.lidAngle;
if (this.numUsingPlayers > 0)
{
this.lidAngle += f;
}
else
{
this.lidAngle -= f;
}
if (this.lidAngle > 1.0F)
{
this.lidAngle = 1.0F;
}
float f2 = 0.5F;
if (this.lidAngle < f2 && f1 >= f2 && this.adjacentChestZNeg == null && this.adjacentChestXNeg == null)
{
d0 = (double)this.xCoord + 0.5D;
double d2 = (double)this.zCoord + 0.5D;
if (this.adjacentChestZPosition != null)
{
d2 += 0.5D;
}
if (this.adjacentChestXPos != null)
{
d0 += 0.5D;
}
this.worldObj.playSoundEffect(d0, (double)this.yCoord + 0.5D, d2, "random.chestclosed", 0.5F, this.worldObj.rand.nextFloat() * 0.1F + 0.9F);
}
if (this.lidAngle < 0.0F)
{
this.lidAngle = 0.0F;
}
}
}
/**
* Called when a client event is received with the event number and argument, see World.sendClientEvent
*/
public boolean receiveClientEvent(int par1, int par2)
{
if (par1 == 1)
{
this.numUsingPlayers = par2;
return true;
}
else
{
return super.receiveClientEvent(par1, par2);
}
}
public void openChest()
{
if (this.numUsingPlayers < 0)
{
this.numUsingPlayers = 0;
}
++this.numUsingPlayers;
this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID, 1, this.numUsingPlayers);
this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID);
this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord - 1, this.zCoord, this.getBlockType().blockID);
}
public void closeChest()
{
if (this.getBlockType() != null && this.getBlockType() instanceof BlockChest)
{
--this.numUsingPlayers;
this.worldObj.addBlockEvent(this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID, 1, this.numUsingPlayers);
this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord, this.zCoord, this.getBlockType().blockID);
this.worldObj.notifyBlocksOfNeighborChange(this.xCoord, this.yCoord - 1, this.zCoord, this.getBlockType().blockID);
}
}
/**
* Returns true if automation is allowed to insert the given stack (ignoring stack size) into the given slot.
*/
public boolean isStackValidForSlot(int par1, ItemStack par2ItemStack)
{
return true;
}
/**
* invalidates a tile entity
*/
public void invalidate()
{
super.invalidate();
this.updateContainingBlockInfo();
}
}
Теперь самое главное, GuiHandler:
package mods.testmod.src;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import cpw.mods.fml.common.network.IGuiHandler;
public class GuiHandler implements IGuiHandler {
@Override
public Object getServerGuiElement(int id, EntityPlayer player, World world,
int x, int y, int z) {
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
//Открывает наш контейнер
if(tileEntity instanceof TileEntityNewChest)
{
return new ContainerNewChest(player.inventory, (TileEntityNewChest) tileEntity);
}
return null;
}
@Override
public Object getClientGuiElement(int id, EntityPlayer player, World world,
int x, int y, int z) {
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
//Открывает наше GUI
if(tileEntity instanceof TileEntityNewChest)
{
return new GuiNewChest(player.inventory, (TileEntityNewChest) tileEntity);
}
return null;
}
}
ContainerNewChest:
package mods.testmod.src;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
public class ContainerNewChest extends Container
{
private IInventory lowerChestInventory;
private int numRows;
public ContainerNewChest(IInventory par1IInventory, IInventory par2IInventory)
{
this.lowerChestInventory = par2IInventory;
this.numRows = par2IInventory.getSizeInventory() / 9;
par2IInventory.openChest();
int i = (this.numRows - 4) * 18;
int j;
int k;
for (j = 0; j < this.numRows; ++j)
{
for (k = 0; k < 9; ++k)
{
this.addSlotToContainer(new Slot(par2IInventory, k + j * 9, 8 + k * 18, 18 + j * 18));
}
}
for (j = 0; j < 3; ++j)
{
for (k = 0; k < 9; ++k)
{
this.addSlotToContainer(new Slot(par1IInventory, k + j * 9 + 9, 8 + k * 18, 103 + j * 18 + i));
}
}
for (j = 0; j < 9; ++j)
{
this.addSlotToContainer(new Slot(par1IInventory, j, 8 + j * 18, 161 + i));
}
}
public boolean canInteractWith(EntityPlayer par1EntityPlayer)
{
return this.lowerChestInventory.isUseableByPlayer(par1EntityPlayer);
}
/**
* Called when a player shift-clicks on a slot. You must override this or you will crash when someone does that.
*/
public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int par2)
{
ItemStack itemstack = null;
Slot slot = (Slot)this.inventorySlots.get(par2);
if (slot != null && slot.getHasStack())
{
ItemStack itemstack1 = slot.getStack();
itemstack = itemstack1.copy();
if (par2 < this.numRows * 9)
{
if (!this.mergeItemStack(itemstack1, this.numRows * 9, this.inventorySlots.size(), true))
{
return null;
}
}
else if (!this.mergeItemStack(itemstack1, 0, this.numRows * 9, false))
{
return null;
}
if (itemstack1.stackSize == 0)
{
slot.putStack((ItemStack)null);
}
else
{
slot.onSlotChanged();
}
}
return itemstack;
}
/**
* Callback for when the crafting gui is closed.
*/
public void onCraftGuiClosed(EntityPlayer par1EntityPlayer)
{
super.onCraftGuiClosed(par1EntityPlayer);
this.lowerChestInventory.closeChest();
}
/**
* Return this chest container's lower chest inventory.
*/
public IInventory getLowerChestInventory()
{
return this.lowerChestInventory;
}
}
И последнее GuiNewChest:
package mods.testmod.src;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
import net.minecraft.util.StatCollector;
import org.lwjgl.opengl.GL11;
@SideOnly(Side.CLIENT)
public class GuiNewChest extends GuiContainer
{
private IInventory upperChestInventory;
private IInventory lowerChestInventory;
/**
* window height is calculated with this values, the more rows, the heigher
*/
private int inventoryRows = 0;
public GuiNewChest(IInventory par1IInventory, IInventory par2IInventory)
{
super(new ContainerChest(par1IInventory, par2IInventory));
this.upperChestInventory = par1IInventory;
this.lowerChestInventory = par2IInventory;
this.allowUserInput = false;
short short1 = 222;
int i = short1 - 108;
this.inventoryRows = par2IInventory.getSizeInventory() / 9;
this.ySize = i + this.inventoryRows * 18;
}
/**
* Draw the foreground layer for the GuiContainer (everything in front of the items)
*/
protected void drawGuiContainerForegroundLayer(int par1, int par2)
{
this.fontRenderer.drawString(this.lowerChestInventory.isInvNameLocalized() ? this.lowerChestInventory.getInvName() : StatCollector.translateToLocal(this.lowerChestInventory.getInvName()), 8, 6, 4210752);
this.fontRenderer.drawString(this.upperChestInventory.isInvNameLocalized() ? this.upperChestInventory.getInvName() : StatCollector.translateToLocal(this.upperChestInventory.getInvName()), 8, this.ySize - 96 + 2, 4210752);
}
/**
* Draw the background layer for the GuiContainer (everything behind the items)
*/
protected void drawGuiContainerBackgroundLayer(float par1, int par2, int par3)
{
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
this.mc.renderEngine.bindTexture("/gui/container.png");//Путь к GUI, мы сделаем с стандартным
int k = (this.width - this.xSize) / 2;
int l = (this.height - this.ySize) / 2;
this.drawTexturedModalRect(k, l, 0, 0, this.xSize, this.inventoryRows * 18 + 17);
this.drawTexturedModalRect(k, l + this.inventoryRows * 18 + 17, 0, 126, this.xSize, 96);
}
}
Как и сундук, я взял стандартную печку, урезал, и немного изменил. Ну, начинаем...
(В печке возможно есть баги, о багах пишите в тему)
TestModBase:
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFurnace;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemBlock;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.*;
import cpw.mods.fml.common.event.FMLInitializationEvent;
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;
@Mod (modid = "TestModBase", name = "Test Mod", version = "0.0.1")
@NetworkMod (clientSideRequired = true, serverSideRequired = false, versionBounds = "1.0.0")
public class TestModBase {
@Instance("TestModBase")
public static TestModBase instance;
public static final Block newFurnaceIdle = (new BlockNewFurnace(2020, false)).setHardness(3.5F).setUnlocalizedName("newfurnace").setCreativeTab(CreativeTabs.tabDecorations);
public static final Block newFurnaceActive = (new BlockNewFurnace(2021, true)).setHardness(3.5F).setLightValue(0.875F).setUnlocalizedName("newfurnace");
@Init
public void init(FMLInitializationEvent event)
{
GameRegistry.registerBlock(newFurnaceIdle);
GameRegistry.registerBlock(newFurnaceActive);
LanguageRegistry.addName(newFurnaceIdle, "New Furnace");
GameRegistry.registerTileEntity(TileEntityNewFurnace.class, "containerNew Furnace");
NetworkRegistry.instance().registerGuiHandler(this, new GuiHandler());
}
}
BlockNewFurnace:
package mods.testmod.src;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityFurnace;
import net.minecraft.util.Icon;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class BlockNewFurnace extends BlockContainer
{
/**
* Is the random generator used by furnace to drop the inventory contents in random directions.
*/
private final Random furnaceRand = new Random();
/** True if this is an active furnace, false if idle */
private final boolean isActive;
/**
* This flag is used to prevent the furnace inventory to be dropped upon block removal, is used internally when the
* furnace block changes from idle to active and vice-versa.
*/
private static boolean keepFurnaceInventory = false;
@SideOnly(Side.CLIENT)
private Icon field_94458_cO;
@SideOnly(Side.CLIENT)
private Icon field_94459_cP;
private Icon bottomIcon;
private Icon topIcon;
private Icon sideIcon;
private Icon frontIcon;
protected BlockNewFurnace(int par1, boolean par2)
{
super(par1, Material.rock);
this.isActive = par2;
}
/**
* Returns the ID of the items to drop on destruction.
*/
public int idDropped(int par1, Random par2Random, int par3)
{
return TestModBase.newFurnaceIdle.blockID;
}
@Override
public void registerIcons(IconRegister par1IconRegister) {
bottomIcon = par1IconRegister.registerIcon("testmod:bottom");
topIcon = par1IconRegister.registerIcon("testmod:top");
frontIcon = par1IconRegister.registerIcon(this.isActive ? "testmod:furnace_front_active" : "testmod:front");//Если активно текстура одна, если не работает другая текстура. Не доработан поворот front
sideIcon = par1IconRegister.registerIcon("testmod:side");
}
public Icon getBlockTextureFromSideAndMetadata(int side, int metadata)
{
if(side == 0)
return bottomIcon;
else if(side == 1)
return topIcon;
else if((side == 2 && metadata == 2) || (side == 5 && metadata == 3) || (side == 3 && metadata == 0) || (side == 4 && metadata == 1))
return frontIcon;
else
return sideIcon;
}
/**
* Called whenever the block is added into the world. Args: world, x, y, z
*/
public void onBlockAdded(World par1World, int par2, int par3, int par4)
{
super.onBlockAdded(par1World, par2, par3, par4);
this.setDefaultDirection(par1World, par2, par3, par4);
}
/**
* set a blocks direction
*/
private void setDefaultDirection(World par1World, int par2, int par3, int par4)
{
if (!par1World.isRemote)
{
int l = par1World.getBlockId(par2, par3, par4 - 1);
int i1 = par1World.getBlockId(par2, par3, par4 + 1);
int j1 = par1World.getBlockId(par2 - 1, par3, par4);
int k1 = par1World.getBlockId(par2 + 1, par3, par4);
byte b0 = 3;
if (Block.opaqueCubeLookup[l] && !Block.opaqueCubeLookup[i1])
{
b0 = 3;
}
if (Block.opaqueCubeLookup[i1] && !Block.opaqueCubeLookup[l])
{
b0 = 2;
}
if (Block.opaqueCubeLookup[j1] && !Block.opaqueCubeLookup[k1])
{
b0 = 5;
}
if (Block.opaqueCubeLookup[k1] && !Block.opaqueCubeLookup[j1])
{
b0 = 4;
}
par1World.setBlockMetadataWithNotify(par2, par3, par4, b0, 2);
}
}
@Override
public boolean onBlockActivated(World world, int x, int y, int z,
EntityPlayer player, int idk, float what, float these, float are) {
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
if (tileEntity == null || player.isSneaking()) {
return false;
}
player.openGui(TestModBase.instance, 0, world, x, y, z);
return true;
}
/**
* Update which block ID the furnace is using depending on whether or not it is burning
*/
public static void updateFurnaceBlockState(boolean par0, World par1World, int par2, int par3, int par4)
{
int l = par1World.getBlockMetadata(par2, par3, par4);
TileEntity tileentity = par1World.getBlockTileEntity(par2, par3, par4);
keepFurnaceInventory = true;
if (par0)
{
par1World.setBlock(par2, par3, par4, TestModBase.newFurnaceActive.blockID);
}
else
{
par1World.setBlock(par2, par3, par4, TestModBase.newFurnaceIdle.blockID);
}
keepFurnaceInventory = false;
par1World.setBlockMetadataWithNotify(par2, par3, par4, l, 2);
if (tileentity != null)
{
tileentity.validate();
par1World.setBlockTileEntity(par2, par3, par4, tileentity);
}
}
@SideOnly(Side.CLIENT)
/**
* A randomly called display update to be able to add particles or other items for display
*/
public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
{
if (this.isActive)
{
int l = par1World.getBlockMetadata(par2, par3, par4);
float f = (float)par2 + 0.5F;
float f1 = (float)par3 + 0.0F + par5Random.nextFloat() * 6.0F / 16.0F;
float f2 = (float)par4 + 0.5F;
float f3 = 0.52F;
float f4 = par5Random.nextFloat() * 0.6F - 0.3F;
if (l == 4)
{
par1World.spawnParticle("smoke", (double)(f - f3), (double)f1, (double)(f2 + f4), 0.0D, 0.0D, 0.0D);
par1World.spawnParticle("flame", (double)(f - f3), (double)f1, (double)(f2 + f4), 0.0D, 0.0D, 0.0D);
}
else if (l == 5)
{
par1World.spawnParticle("smoke", (double)(f + f3), (double)f1, (double)(f2 + f4), 0.0D, 0.0D, 0.0D);
par1World.spawnParticle("flame", (double)(f + f3), (double)f1, (double)(f2 + f4), 0.0D, 0.0D, 0.0D);
}
else if (l == 2)
{
par1World.spawnParticle("smoke", (double)(f + f4), (double)f1, (double)(f2 - f3), 0.0D, 0.0D, 0.0D);
par1World.spawnParticle("flame", (double)(f + f4), (double)f1, (double)(f2 - f3), 0.0D, 0.0D, 0.0D);
}
else if (l == 3)
{
par1World.spawnParticle("smoke", (double)(f + f4), (double)f1, (double)(f2 + f3), 0.0D, 0.0D, 0.0D);
par1World.spawnParticle("flame", (double)(f + f4), (double)f1, (double)(f2 + f3), 0.0D, 0.0D, 0.0D);
}
}
}
/**
* Returns a new instance of a block's tile entity class. Called on placing the block.
*/
public TileEntity createNewTileEntity(World par1World)
{
return new TileEntityNewFurnace();
}
/**
* ejects contained items into the world, and notifies neighbours of an update, as appropriate
*/
public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
{
if (!keepFurnaceInventory)
{
TileEntityNewFurnace tileentityfurnace = (TileEntityNewFurnace)par1World.getBlockTileEntity(par2, par3, par4);
if (tileentityfurnace != null)
{
for (int j1 = 0; j1 < tileentityfurnace.getSizeInventory(); ++j1)
{
ItemStack itemstack = tileentityfurnace.getStackInSlot(j1);
if (itemstack != null)
{
float f = this.furnaceRand.nextFloat() * 0.8F + 0.1F;
float f1 = this.furnaceRand.nextFloat() * 0.8F + 0.1F;
float f2 = this.furnaceRand.nextFloat() * 0.8F + 0.1F;
while (itemstack.stackSize > 0)
{
int k1 = this.furnaceRand.nextInt(21) + 10;
if (k1 > itemstack.stackSize)
{
k1 = itemstack.stackSize;
}
itemstack.stackSize -= k1;
EntityItem entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.itemID, k1, itemstack.getItemDamage()));
if (itemstack.hasTagCompound())
{
entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy());
}
float f3 = 0.05F;
entityitem.motionX = (double)((float)this.furnaceRand.nextGaussian() * f3);
entityitem.motionY = (double)((float)this.furnaceRand.nextGaussian() * f3 + 0.2F);
entityitem.motionZ = (double)((float)this.furnaceRand.nextGaussian() * f3);
par1World.spawnEntityInWorld(entityitem);
}
}
}
par1World.func_96440_m(par2, par3, par4, par5);
}
}
super.breakBlock(par1World, par2, par3, par4, par5, par6);
}
/**
* If this returns true, then comparators facing away from this block will use the value from
* getComparatorInputOverride instead of the actual redstone signal strength.
*/
public boolean hasComparatorInputOverride()
{
return true;
}
/**
* If hasComparatorInputOverride returns true, the return value from this is used instead of the redstone signal
* strength when this block inputs to a comparator.
*/
public int getComparatorInputOverride(World par1World, int par2, int par3, int par4, int par5)
{
return Container.func_94526_b((IInventory)par1World.getBlockTileEntity(par2, par3, par4));
}
}
TileEntityNewFurnace:
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemHoe;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemSword;
import net.minecraft.item.ItemTool;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.ForgeDirection;
import net.minecraftforge.common.ForgeDummyContainer;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class TileEntityNewFurnace extends TileEntity implements ISidedInventory, net.minecraftforge.common.ISidedInventory
{
/**
* The ItemStacks that hold the items currently being used in the furnace
*/
private ItemStack[] furnaceItemStacks = new ItemStack[3];
/** The number of ticks that the furnace will keep burning */
public int furnaceBurnTime = 0;
/**
* The number of ticks that a fresh copy of the currently-burning item would keep the furnace burning for
*/
public int currentItemBurnTime = 0;
/** The number of ticks that the current item has been cooking for */
public int furnaceCookTime = 0;
/**
* Returns the number of slots in the inventory.
*/
public int getSizeInventory()
{
return this.furnaceItemStacks.length;
}
/**
* Returns the stack in slot i
*/
public ItemStack getStackInSlot(int par1)
{
return this.furnaceItemStacks[par1];
}
/**
* Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
* new stack.
*/
public ItemStack decrStackSize(int par1, int par2)
{
if (this.furnaceItemStacks[par1] != null)
{
ItemStack itemstack;
if (this.furnaceItemStacks[par1].stackSize this.getInventoryStackLimit())
{
par2ItemStack.stackSize = this.getInventoryStackLimit();
}
}
/**
* Имя в инвентаре
*/
public String getInvName()
{
return "New Furnace";
}
/**
* Reads a tile entity from NBT.
*/
public void readFromNBT(NBTTagCompound par1NBTTagCompound)
{
super.readFromNBT(par1NBTTagCompound);
NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items");
this.furnaceItemStacks = new ItemStack[this.getSizeInventory()];
for (int i = 0; i < nbttaglist.tagCount(); ++i)
{
NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i);
byte b0 = nbttagcompound1.getByte("Slot");
if (b0 >= 0 && b0 < this.furnaceItemStacks.length)
{
this.furnaceItemStacks[b0] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
}
}
this.furnaceBurnTime = par1NBTTagCompound.getShort("BurnTime");
this.furnaceCookTime = par1NBTTagCompound.getShort("CookTime");
this.currentItemBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
}
/**
* Writes a tile entity to NBT.
*/
public void writeToNBT(NBTTagCompound par1NBTTagCompound)
{
super.writeToNBT(par1NBTTagCompound);
par1NBTTagCompound.setShort("BurnTime", (short)this.furnaceBurnTime);
par1NBTTagCompound.setShort("CookTime", (short)this.furnaceCookTime);
NBTTagList nbttaglist = new NBTTagList();
for (int i = 0; i < this.furnaceItemStacks.length; ++i)
{
if (this.furnaceItemStacks != null)
{
NBTTagCompound nbttagcompound1 = new NBTTagCompound();
nbttagcompound1.setByte("Slot", (byte)i);
this.furnaceItemStacks.writeToNBT(nbttagcompound1);
nbttaglist.appendTag(nbttagcompound1);
}
}
par1NBTTagCompound.setTag("Items", nbttaglist);
}
/**
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
* this more of a set than a get?*
*/
public int getInventoryStackLimit()
{
return 64;
}
@SideOnly(Side.CLIENT)
/**
* Returns an integer between 0 and the passed value representing how close the current item is to being completely
* cooked
*/
public int getCookProgressScaled(int par1)
{
return this.furnaceCookTime * par1 / 200;
}
@SideOnly(Side.CLIENT)
/**
* Returns an integer between 0 and the passed value representing how much burn time is left on the current fuel
* item, where 0 means that the item is exhausted and the passed value means that the item is fresh
*/
public int getBurnTimeRemainingScaled(int par1)
{
if (this.currentItemBurnTime == 0)
{
this.currentItemBurnTime = 200;
}
return this.furnaceBurnTime * par1 / this.currentItemBurnTime;
}
/**
* Returns true if the furnace is currently burning
*/
public boolean isBurning()
{
return this.furnaceBurnTime > 0;
}
/**
* Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
* ticks and creates a new spawn inside its implementation.
*/
public void updateEntity()
{
boolean flag = this.furnaceBurnTime > 0;
boolean flag1 = false;
if (this.furnaceBurnTime > 0)
{
--this.furnaceBurnTime;
}
if (!this.worldObj.isRemote)
{
if (this.furnaceBurnTime == 0 && this.canSmelt())
{
this.currentItemBurnTime = this.furnaceBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
if (this.furnaceBurnTime > 0)
{
flag1 = true;
if (this.furnaceItemStacks[1] != null)
{
--this.furnaceItemStacks[1].stackSize;
if (this.furnaceItemStacks[1].stackSize == 0)
{
this.furnaceItemStacks[1] = this.furnaceItemStacks[1].getItem().getContainerItemStack(furnaceItemStacks[1]);
}
}
}
}
if (this.isBurning() && this.canSmelt())
{
++this.furnaceCookTime;
if (this.furnaceCookTime == 200)
{
this.furnaceCookTime = 0;
this.smeltItem();
flag1 = true;
}
}
else
{
this.furnaceCookTime = 0;
}
if (flag != this.furnaceBurnTime > 0)
{
flag1 = true;
BlockNewFurnace.updateFurnaceBlockState(this.furnaceBurnTime > 0, this.worldObj, this.xCoord, this.yCoord, this.zCoord);
}
}
if (flag1)
{
this.onInventoryChanged();
}
}
/**
* Returns true if the furnace can smelt an item, i.e. has a source item, destination stack isn't full, etc.
*/
private boolean canSmelt()
{
if (this.furnaceItemStacks[0] == null)
{
return false;
}
else
{
ItemStack itemstack = NewFurnaceRecipes.smelting().getSmeltingResult(this.furnaceItemStacks[0]);
if (itemstack == null) return false;
if (this.furnaceItemStacks[2] == null) return true;
if (!this.furnaceItemStacks[2].isItemEqual(itemstack)) return false;
int result = furnaceItemStacks[2].stackSize + itemstack.stackSize;
return (result
(В печке возможно есть баги, о багах пишите в тему)
TestModBase:
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFurnace;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemBlock;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.*;
import cpw.mods.fml.common.event.FMLInitializationEvent;
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;
@Mod (modid = "TestModBase", name = "Test Mod", version = "0.0.1")
@NetworkMod (clientSideRequired = true, serverSideRequired = false, versionBounds = "1.0.0")
public class TestModBase {
@Instance("TestModBase")
public static TestModBase instance;
public static final Block newFurnaceIdle = (new BlockNewFurnace(2020, false)).setHardness(3.5F).setUnlocalizedName("newfurnace").setCreativeTab(CreativeTabs.tabDecorations);
public static final Block newFurnaceActive = (new BlockNewFurnace(2021, true)).setHardness(3.5F).setLightValue(0.875F).setUnlocalizedName("newfurnace");
@Init
public void init(FMLInitializationEvent event)
{
GameRegistry.registerBlock(newFurnaceIdle);
GameRegistry.registerBlock(newFurnaceActive);
LanguageRegistry.addName(newFurnaceIdle, "New Furnace");
GameRegistry.registerTileEntity(TileEntityNewFurnace.class, "containerNew Furnace");
NetworkRegistry.instance().registerGuiHandler(this, new GuiHandler());
}
}
BlockNewFurnace:
package mods.testmod.src;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IconRegister;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityFurnace;
import net.minecraft.util.Icon;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class BlockNewFurnace extends BlockContainer
{
/**
* Is the random generator used by furnace to drop the inventory contents in random directions.
*/
private final Random furnaceRand = new Random();
/** True if this is an active furnace, false if idle */
private final boolean isActive;
/**
* This flag is used to prevent the furnace inventory to be dropped upon block removal, is used internally when the
* furnace block changes from idle to active and vice-versa.
*/
private static boolean keepFurnaceInventory = false;
@SideOnly(Side.CLIENT)
private Icon field_94458_cO;
@SideOnly(Side.CLIENT)
private Icon field_94459_cP;
private Icon bottomIcon;
private Icon topIcon;
private Icon sideIcon;
private Icon frontIcon;
protected BlockNewFurnace(int par1, boolean par2)
{
super(par1, Material.rock);
this.isActive = par2;
}
/**
* Returns the ID of the items to drop on destruction.
*/
public int idDropped(int par1, Random par2Random, int par3)
{
return TestModBase.newFurnaceIdle.blockID;
}
@Override
public void registerIcons(IconRegister par1IconRegister) {
bottomIcon = par1IconRegister.registerIcon("testmod:bottom");
topIcon = par1IconRegister.registerIcon("testmod:top");
frontIcon = par1IconRegister.registerIcon(this.isActive ? "testmod:furnace_front_active" : "testmod:front");//Если активно текстура одна, если не работает другая текстура. Не доработан поворот front
sideIcon = par1IconRegister.registerIcon("testmod:side");
}
public Icon getBlockTextureFromSideAndMetadata(int side, int metadata)
{
if(side == 0)
return bottomIcon;
else if(side == 1)
return topIcon;
else if((side == 2 && metadata == 2) || (side == 5 && metadata == 3) || (side == 3 && metadata == 0) || (side == 4 && metadata == 1))
return frontIcon;
else
return sideIcon;
}
/**
* Called whenever the block is added into the world. Args: world, x, y, z
*/
public void onBlockAdded(World par1World, int par2, int par3, int par4)
{
super.onBlockAdded(par1World, par2, par3, par4);
this.setDefaultDirection(par1World, par2, par3, par4);
}
/**
* set a blocks direction
*/
private void setDefaultDirection(World par1World, int par2, int par3, int par4)
{
if (!par1World.isRemote)
{
int l = par1World.getBlockId(par2, par3, par4 - 1);
int i1 = par1World.getBlockId(par2, par3, par4 + 1);
int j1 = par1World.getBlockId(par2 - 1, par3, par4);
int k1 = par1World.getBlockId(par2 + 1, par3, par4);
byte b0 = 3;
if (Block.opaqueCubeLookup[l] && !Block.opaqueCubeLookup[i1])
{
b0 = 3;
}
if (Block.opaqueCubeLookup[i1] && !Block.opaqueCubeLookup[l])
{
b0 = 2;
}
if (Block.opaqueCubeLookup[j1] && !Block.opaqueCubeLookup[k1])
{
b0 = 5;
}
if (Block.opaqueCubeLookup[k1] && !Block.opaqueCubeLookup[j1])
{
b0 = 4;
}
par1World.setBlockMetadataWithNotify(par2, par3, par4, b0, 2);
}
}
@Override
public boolean onBlockActivated(World world, int x, int y, int z,
EntityPlayer player, int idk, float what, float these, float are) {
TileEntity tileEntity = world.getBlockTileEntity(x, y, z);
if (tileEntity == null || player.isSneaking()) {
return false;
}
player.openGui(TestModBase.instance, 0, world, x, y, z);
return true;
}
/**
* Update which block ID the furnace is using depending on whether or not it is burning
*/
public static void updateFurnaceBlockState(boolean par0, World par1World, int par2, int par3, int par4)
{
int l = par1World.getBlockMetadata(par2, par3, par4);
TileEntity tileentity = par1World.getBlockTileEntity(par2, par3, par4);
keepFurnaceInventory = true;
if (par0)
{
par1World.setBlock(par2, par3, par4, TestModBase.newFurnaceActive.blockID);
}
else
{
par1World.setBlock(par2, par3, par4, TestModBase.newFurnaceIdle.blockID);
}
keepFurnaceInventory = false;
par1World.setBlockMetadataWithNotify(par2, par3, par4, l, 2);
if (tileentity != null)
{
tileentity.validate();
par1World.setBlockTileEntity(par2, par3, par4, tileentity);
}
}
@SideOnly(Side.CLIENT)
/**
* A randomly called display update to be able to add particles or other items for display
*/
public void randomDisplayTick(World par1World, int par2, int par3, int par4, Random par5Random)
{
if (this.isActive)
{
int l = par1World.getBlockMetadata(par2, par3, par4);
float f = (float)par2 + 0.5F;
float f1 = (float)par3 + 0.0F + par5Random.nextFloat() * 6.0F / 16.0F;
float f2 = (float)par4 + 0.5F;
float f3 = 0.52F;
float f4 = par5Random.nextFloat() * 0.6F - 0.3F;
if (l == 4)
{
par1World.spawnParticle("smoke", (double)(f - f3), (double)f1, (double)(f2 + f4), 0.0D, 0.0D, 0.0D);
par1World.spawnParticle("flame", (double)(f - f3), (double)f1, (double)(f2 + f4), 0.0D, 0.0D, 0.0D);
}
else if (l == 5)
{
par1World.spawnParticle("smoke", (double)(f + f3), (double)f1, (double)(f2 + f4), 0.0D, 0.0D, 0.0D);
par1World.spawnParticle("flame", (double)(f + f3), (double)f1, (double)(f2 + f4), 0.0D, 0.0D, 0.0D);
}
else if (l == 2)
{
par1World.spawnParticle("smoke", (double)(f + f4), (double)f1, (double)(f2 - f3), 0.0D, 0.0D, 0.0D);
par1World.spawnParticle("flame", (double)(f + f4), (double)f1, (double)(f2 - f3), 0.0D, 0.0D, 0.0D);
}
else if (l == 3)
{
par1World.spawnParticle("smoke", (double)(f + f4), (double)f1, (double)(f2 + f3), 0.0D, 0.0D, 0.0D);
par1World.spawnParticle("flame", (double)(f + f4), (double)f1, (double)(f2 + f3), 0.0D, 0.0D, 0.0D);
}
}
}
/**
* Returns a new instance of a block's tile entity class. Called on placing the block.
*/
public TileEntity createNewTileEntity(World par1World)
{
return new TileEntityNewFurnace();
}
/**
* ejects contained items into the world, and notifies neighbours of an update, as appropriate
*/
public void breakBlock(World par1World, int par2, int par3, int par4, int par5, int par6)
{
if (!keepFurnaceInventory)
{
TileEntityNewFurnace tileentityfurnace = (TileEntityNewFurnace)par1World.getBlockTileEntity(par2, par3, par4);
if (tileentityfurnace != null)
{
for (int j1 = 0; j1 < tileentityfurnace.getSizeInventory(); ++j1)
{
ItemStack itemstack = tileentityfurnace.getStackInSlot(j1);
if (itemstack != null)
{
float f = this.furnaceRand.nextFloat() * 0.8F + 0.1F;
float f1 = this.furnaceRand.nextFloat() * 0.8F + 0.1F;
float f2 = this.furnaceRand.nextFloat() * 0.8F + 0.1F;
while (itemstack.stackSize > 0)
{
int k1 = this.furnaceRand.nextInt(21) + 10;
if (k1 > itemstack.stackSize)
{
k1 = itemstack.stackSize;
}
itemstack.stackSize -= k1;
EntityItem entityitem = new EntityItem(par1World, (double)((float)par2 + f), (double)((float)par3 + f1), (double)((float)par4 + f2), new ItemStack(itemstack.itemID, k1, itemstack.getItemDamage()));
if (itemstack.hasTagCompound())
{
entityitem.getEntityItem().setTagCompound((NBTTagCompound)itemstack.getTagCompound().copy());
}
float f3 = 0.05F;
entityitem.motionX = (double)((float)this.furnaceRand.nextGaussian() * f3);
entityitem.motionY = (double)((float)this.furnaceRand.nextGaussian() * f3 + 0.2F);
entityitem.motionZ = (double)((float)this.furnaceRand.nextGaussian() * f3);
par1World.spawnEntityInWorld(entityitem);
}
}
}
par1World.func_96440_m(par2, par3, par4, par5);
}
}
super.breakBlock(par1World, par2, par3, par4, par5, par6);
}
/**
* If this returns true, then comparators facing away from this block will use the value from
* getComparatorInputOverride instead of the actual redstone signal strength.
*/
public boolean hasComparatorInputOverride()
{
return true;
}
/**
* If hasComparatorInputOverride returns true, the return value from this is used instead of the redstone signal
* strength when this block inputs to a comparator.
*/
public int getComparatorInputOverride(World par1World, int par2, int par3, int par4, int par5)
{
return Container.func_94526_b((IInventory)par1World.getBlockTileEntity(par2, par3, par4));
}
}
TileEntityNewFurnace:
package mods.testmod.src;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemHoe;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemSword;
import net.minecraft.item.ItemTool;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.ForgeDirection;
import net.minecraftforge.common.ForgeDummyContainer;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class TileEntityNewFurnace extends TileEntity implements ISidedInventory, net.minecraftforge.common.ISidedInventory
{
/**
* The ItemStacks that hold the items currently being used in the furnace
*/
private ItemStack[] furnaceItemStacks = new ItemStack[3];
/** The number of ticks that the furnace will keep burning */
public int furnaceBurnTime = 0;
/**
* The number of ticks that a fresh copy of the currently-burning item would keep the furnace burning for
*/
public int currentItemBurnTime = 0;
/** The number of ticks that the current item has been cooking for */
public int furnaceCookTime = 0;
/**
* Returns the number of slots in the inventory.
*/
public int getSizeInventory()
{
return this.furnaceItemStacks.length;
}
/**
* Returns the stack in slot i
*/
public ItemStack getStackInSlot(int par1)
{
return this.furnaceItemStacks[par1];
}
/**
* Removes from an inventory slot (first arg) up to a specified number (second arg) of items and returns them in a
* new stack.
*/
public ItemStack decrStackSize(int par1, int par2)
{
if (this.furnaceItemStacks[par1] != null)
{
ItemStack itemstack;
if (this.furnaceItemStacks[par1].stackSize this.getInventoryStackLimit())
{
par2ItemStack.stackSize = this.getInventoryStackLimit();
}
}
/**
* Имя в инвентаре
*/
public String getInvName()
{
return "New Furnace";
}
/**
* Reads a tile entity from NBT.
*/
public void readFromNBT(NBTTagCompound par1NBTTagCompound)
{
super.readFromNBT(par1NBTTagCompound);
NBTTagList nbttaglist = par1NBTTagCompound.getTagList("Items");
this.furnaceItemStacks = new ItemStack[this.getSizeInventory()];
for (int i = 0; i < nbttaglist.tagCount(); ++i)
{
NBTTagCompound nbttagcompound1 = (NBTTagCompound)nbttaglist.tagAt(i);
byte b0 = nbttagcompound1.getByte("Slot");
if (b0 >= 0 && b0 < this.furnaceItemStacks.length)
{
this.furnaceItemStacks[b0] = ItemStack.loadItemStackFromNBT(nbttagcompound1);
}
}
this.furnaceBurnTime = par1NBTTagCompound.getShort("BurnTime");
this.furnaceCookTime = par1NBTTagCompound.getShort("CookTime");
this.currentItemBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
}
/**
* Writes a tile entity to NBT.
*/
public void writeToNBT(NBTTagCompound par1NBTTagCompound)
{
super.writeToNBT(par1NBTTagCompound);
par1NBTTagCompound.setShort("BurnTime", (short)this.furnaceBurnTime);
par1NBTTagCompound.setShort("CookTime", (short)this.furnaceCookTime);
NBTTagList nbttaglist = new NBTTagList();
for (int i = 0; i < this.furnaceItemStacks.length; ++i)
{
if (this.furnaceItemStacks != null)
{
NBTTagCompound nbttagcompound1 = new NBTTagCompound();
nbttagcompound1.setByte("Slot", (byte)i);
this.furnaceItemStacks.writeToNBT(nbttagcompound1);
nbttaglist.appendTag(nbttagcompound1);
}
}
par1NBTTagCompound.setTag("Items", nbttaglist);
}
/**
* Returns the maximum stack size for a inventory slot. Seems to always be 64, possibly will be extended. *Isn't
* this more of a set than a get?*
*/
public int getInventoryStackLimit()
{
return 64;
}
@SideOnly(Side.CLIENT)
/**
* Returns an integer between 0 and the passed value representing how close the current item is to being completely
* cooked
*/
public int getCookProgressScaled(int par1)
{
return this.furnaceCookTime * par1 / 200;
}
@SideOnly(Side.CLIENT)
/**
* Returns an integer between 0 and the passed value representing how much burn time is left on the current fuel
* item, where 0 means that the item is exhausted and the passed value means that the item is fresh
*/
public int getBurnTimeRemainingScaled(int par1)
{
if (this.currentItemBurnTime == 0)
{
this.currentItemBurnTime = 200;
}
return this.furnaceBurnTime * par1 / this.currentItemBurnTime;
}
/**
* Returns true if the furnace is currently burning
*/
public boolean isBurning()
{
return this.furnaceBurnTime > 0;
}
/**
* Allows the entity to update its state. Overridden in most subclasses, e.g. the mob spawner uses this to count
* ticks and creates a new spawn inside its implementation.
*/
public void updateEntity()
{
boolean flag = this.furnaceBurnTime > 0;
boolean flag1 = false;
if (this.furnaceBurnTime > 0)
{
--this.furnaceBurnTime;
}
if (!this.worldObj.isRemote)
{
if (this.furnaceBurnTime == 0 && this.canSmelt())
{
this.currentItemBurnTime = this.furnaceBurnTime = getItemBurnTime(this.furnaceItemStacks[1]);
if (this.furnaceBurnTime > 0)
{
flag1 = true;
if (this.furnaceItemStacks[1] != null)
{
--this.furnaceItemStacks[1].stackSize;
if (this.furnaceItemStacks[1].stackSize == 0)
{
this.furnaceItemStacks[1] = this.furnaceItemStacks[1].getItem().getContainerItemStack(furnaceItemStacks[1]);
}
}
}
}
if (this.isBurning() && this.canSmelt())
{
++this.furnaceCookTime;
if (this.furnaceCookTime == 200)
{
this.furnaceCookTime = 0;
this.smeltItem();
flag1 = true;
}
}
else
{
this.furnaceCookTime = 0;
}
if (flag != this.furnaceBurnTime > 0)
{
flag1 = true;
BlockNewFurnace.updateFurnaceBlockState(this.furnaceBurnTime > 0, this.worldObj, this.xCoord, this.yCoord, this.zCoord);
}
}
if (flag1)
{
this.onInventoryChanged();
}
}
/**
* Returns true if the furnace can smelt an item, i.e. has a source item, destination stack isn't full, etc.
*/
private boolean canSmelt()
{
if (this.furnaceItemStacks[0] == null)
{
return false;
}
else
{
ItemStack itemstack = NewFurnaceRecipes.smelting().getSmeltingResult(this.furnaceItemStacks[0]);
if (itemstack == null) return false;
if (this.furnaceItemStacks[2] == null) return true;
if (!this.furnaceItemStacks[2].isItemEqual(itemstack)) return false;
int result = furnaceItemStacks[2].stackSize + itemstack.stackSize;
return (result