Туториал [1.3.2] [ALL] [Modding] Создание модов для MineCraft без использования ModLoader (08/05/2013г.)

Nicolayka

Владелец
Команда форума
Регистрация
4 Апр 2025
Сообщения
24
Реакции
0
Баллы
1
Город
Санкт-Петербург
Веб-сайт
paxgame.ru
Discord
nicolayka
Я всё же решился начать писать уроки без использования сторонних модов типо ModLoader и Forge.

Данный туториал пишется для клиента версии 1.3.2.

Для начала разберёмся, как всё же начать моддить. Для этого вам потребуется:
  1. Java Development Kit 6 (JDK 6) или Java Development 7 (JDK 7)
  2. Оригинальный minecraft.jar(папка bin) и minecraft_server.jar
  3. Notepad ++, Eclipse(лучше конечно использовать Eclipse)
  4. Minecraft Coder Pack (нужную вам версию можно посмотреть ниже)

MCP | Minecraft | ModLoader
7.2 | 1.3.2 | 1.3.2
7.0a | 1.3.1 | 1.3.1
6.2 | 1.2.5 | 1.2.5
6.1 | 1.2.4 | 1.2.4
6.0 | 1.2.3 | 1.2.3
5.6 | 1.1.1 | 1.0
5.4 | 1.0.0 | 1.0
Установка:
  1. Создайте папку в любом удобном для вас месте, желательно, что бы в пути небыло русских символов
  2. Скопируйте содержимое архива mcp в эту папку
  3. Скопируйте папку bin (из клиента) и minecraft_server.jar в папку jars
  4. Откройте minecraft.jar с помощью архиватора, и удалите папку META-INF (если такая имеется)
  5. Пропишите путь к javac.exe в системной переменной PATH

  6. Пример строки смотрите ниже (не забудьте : перед строчкой)

    ;C:\Program Files\Java\jdk1.7.0_07\bin

  7. Если же у вас установлена другая версия JAVA, то сначала посмотрите путь в папке ProgramFiles, а потом измените в строке
  8. Зайдите в Eclipse, при первом входе он вас попросит указать путь к новому проекту. Укажите путь до папки eclipse в новой папке
  9. Закройте Eclipse
  10. Запустите decompile.bat
  11. Как только декомпиляция закончится, открывайте Eclipse и кодьте =)
1. Добавление своего блока в игру + добавление в креатив (1.3.2)
1. Вам нужно создать новый файл под именем BlockNew.java в папке src.
2. Вот пример:

package net.minecraft.src;
import java.util.Random;

public class BlockNew extends Block
{
public BlockNew(int par1, int par2)
{
super(par1, par2, Material.rock);
this.setCreativeTab(CreativeTabs.tabBlock);
}
/**
* Returns the ID of the items to drop on destruction.
*/
public int idDropped(int par1, Random par2Random, int par3)
{
return Block.newBlock.blockID;
}
}
Список категорий для "креатива" (для добавления нашего блока в определённую закладку)

this.setCreativeTab(CreativeTabs.tabAllSearch); //Добавляет наш Block в категорию "Поиск" как и все предметы, блоки.
this.setCreativeTab(CreativeTabs.tabBlock); //Добавляет наш Block в категорию "Блоки" как Стекло, Земля, и т.д.
this.setCreativeTab(CreativeTabs.tabBrewing); //Добавляет наш Block в категорию "Зелья" как Зелья, Ингредиенты и т.д.
this.setCreativeTab(CreativeTabs.tabCombat); //Добавляет наш Block в категорию "Амуниция" как Броня, Мечи, и т.д.
this.setCreativeTab(CreativeTabs.tabDeco); //Добавляет наш Block в категорию "Декорации" как Цветки, Сундук, и т.д.
this.setCreativeTab(CreativeTabs.tabFood); //Добавляет наш Block в категорию "Еда" как Печеньки, Хлеб и т.д.
this.setCreativeTab(CreativeTabs.tabInventory); //Сюда не надо ничего не добавлять, если добавили Block, Item то они будут в иконке "Destroy Item".
this.setCreativeTab(CreativeTabs.tabMaterials); //Добавляет наш Block в категорию "Материалы" как Уголь, Сундук, и т.д.
this.setCreativeTab(CreativeTabs.tabMisc); //Добавляет наш Block в категорию "Разное" как Яйца мобов, Музыкальные диски, и т.д.
this.setCreativeTab(CreativeTabs.tabRedstone); //Добавляет наш Block в категорию "Редстоун" как Поршень, ТНТ, и т.д.
this.setCreativeTab(CreativeTabs.tabTools); //Добавляет наш Block в категорию "Инструменты" как Кирки, Компасс и т.д.
this.setCreativeTab(CreativeTabs.tabTransport); //Добавляет наш Block в категорию "Транспорт" как Вагонетка, Рульсы, и т.д.
3. Теперь нужно добавить ваш блок непосредственно в Block.java

Идём в конец файла и ищем


/**
* The index of the texture to be displayed for this block. May vary based on graphics settings. Mostly seems to
* come from terrain.png, and the index is 0-based (grass is 0).
*/
Над ним вставляем:


public static final Block newBlock = (new BlockNew(161, 8)).setHardness(3.0F).setResistance(5.0F).setStepSound(soundStoneFootstep).setBlockName("new").setRequiresSelfNotify();
Где:
161 - ID блока (свободные номера начинаются с 137)
8 - номер текстуры в terrain.png
setHardness(2.0F) - прочность ()
.setResistance(4F) - сопротивление
.setStepSound(soundGlassFootstep) - звук при разбиении
.setBlockName("new") - имя блока (для перевода через lang-файл)
.setLightValue(1.0F) - свечение блока

Если вы хотите сделать к примеру ступеньку, или же вертикальную палку, или паутину, то в файле BlockNew.java добавьте


public int getRenderType()
{
return 10;
}
Где 10 - TYPE (тип блока)

2. Создание нового рецепта крафта (добыча блока/предмета) (1.3.2)
1. Откройте CraftingManager.java

Ищем что-то похожее на:


this.addRecipe(new ItemStack(Block.enchantmentTable, 1), new Object[] {" B ", "D#D", "###", '#', Block.obsidian, 'B', Item.book, 'D', Item.diamond});
Добавляем после него рецепт для нашего только что созданного блока


this.addRecipe(new ItemStack(Block.new, 1), new Object[] {"###", "###", "###", '#', Block.dirt});
Где 1 - кол-во получаемого блока после крафта
# - в данном случае, все ячейки крафта заполняем землёй

3. Добавление блока в лист креативного режима (только для 1.2.5)
Открываем файл ContainerCreative.java
В самом верху видим:


itemList = new ArrayList();
Block ablock[] =
{
Block.cobblestone, Block.stone, Block.oreDiamond, Block.oreGold, Block.oreIron, Block.oreCoal, Block.oreLapis, Block.oreRedstone, Block.stoneBrick, Block.stoneBrick,
Block.stoneBrick, Block.stoneBrick, Block.blockClay, Block.blockDiamond, Block.blockGold, Block.blockSteel, Block.bedrock, Block.blockLapis, Block.brick, Block.cobblestoneMossy,
Block.stairSingle, Block.stairSingle, Block.stairSingle, Block.stairSingle, Block.stairSingle, Block.stairSingle, Block.obsidian, Block.netherrack, Block.slowSand, Block.glowStone,
Block.wood, Block.wood, Block.wood, Block.wood, Block.leaves, Block.leaves, Block.leaves, Block.leaves, Block.dirt, Block.grass,
Block.sand, Block.sandStone, Block.sandStone, Block.sandStone, Block.gravel, Block.web, Block.planks, Block.planks, Block.planks, Block.planks,
Block.sapling, Block.sapling, Block.sapling, Block.sapling, Block.deadBush, Block.sponge, Block.ice, Block.blockSnow, Block.plantYellow, Block.plantRed,
Block.mushroomBrown, Block.mushroomRed, Block.cactus, Block.melon, Block.pumpkin, Block.pumpkinLantern, Block.vine, Block.fenceIron, Block.thinGlass, Block.netherBrick,
Block.netherFence, Block.stairsNetherBrick, Block.whiteStone, Block.mycelium, Block.waterlily, Block.tallGrass, Block.tallGrass, Block.chest, Block.workbench, Block.glass,
Block.tnt, Block.bookShelf, Block.cloth, Block.cloth, Block.cloth, Block.cloth, Block.cloth, Block.cloth, Block.cloth, Block.cloth,
Block.cloth, Block.cloth, Block.cloth, Block.cloth, Block.cloth, Block.cloth, Block.cloth, Block.cloth, Block.dispenser, Block.stoneOvenIdle,
Block.music, Block.jukebox, Block.pistonStickyBase, Block.pistonBase, Block.fence, Block.fenceGate, Block.ladder, Block.rail, Block.railPowered, Block.railDetector,
Block.torchWood, Block.stairCompactPlanks, Block.stairCompactCobblestone, Block.stairsBrick, Block.stairsStoneBrickSmooth, Block.lever, Block.pressurePlateStone, Block.pressurePlatePlanks, Block.torchRedstoneActive, Block.button,
Block.trapdoor, Block.enchantmentTable, Block.redstoneLampIdle
};
И добавляем в этот список наш блок (или предмет)


, Block.new

4. Добавление блока в генерацию мира (1.3.2)
1. Открываем файл BiomeDecorator.java
Ищем


protected WorldGenerator dirtGen;
Добавляем после


protected WorldGenerator newGen;
Ищем


dirtGen = new WorldGenMinable(Block.dirt.blockID, 32);
Добавляем после


newGen = new WorldGenMinable(Block.new.blockID, 2); //Кол-во блоков в одном месторождении
Идём в самый конец файла и ищем


this.genStandardOre1(20, this.dirtGen, 0, 128);
Вставляем после:


this.genStandardOre1(20, this.newGen, 0, 128);
Где 0 минимальная высота, а 128 - максимальная, до куда будет генерироваться блок. Т.е с нулевой высоты по 128 будет генерироваться наш блок

5. Добавление имени блоку (1.3.2)
Открываем minecraft.jar, папку lang и нужный файл языка. К примеру ru_RU.lang
Листаем ниже и находим такой код:


tile.waterlily.name=Кувшинка
tile.dragonEgg.name=Яйцо дракона
tile.redstoneLight.name=Лампа
И добавляем по аналогии наше название блока! В title.*** пишутся имена блоков!



tile.new.name=Новый блок
tile.new.name - имя блока, которое мы использовали тут (когда создавами сам блок):


Теперь припишем имя к предмету (внизу описан предмет - роза, ну для него и напишем имя)
Чуть ниже ищем строки:

item.shovelIron.name=Железная лопата
item.pickaxeIron.name=Железная кирка
item.hatchetIron.name=Железный топор
И добавляем по аналогии наше название предмета! В item.*** пишутся имена редметов!



item.rose.name=Колючая роза
item.rose.name - имя предмета, которое мы использовали при создании предмета (тут)


Как только напишу тутор как создать свой предмет - опишу присвоение имени.

6. Добавление своего файла крафтинга (1.3.2)
1. Открываем файл CraftingManager.java
Ищем



(new RecipesDyes()).addRecipes(this);
Добавляем после


(new RecipesMyRecipes()).addRecipes(this);
2. Создаём файл с таким же именем как указали выше - RecipesMyRecipes.java

3. Добавляем в файл следующие строки




package net.minecraft.src;

public class RecipesMyRecipes
{
public RecipesMyRecipes()
{
}

/**
* Adds the food recipes to the CraftingManager.
*/
public void addRecipes(CraftingManager CraftingManager)
{
par1CraftingManager.addRecipe(new ItemStack(Item.new, 6), new Object[] {"###", "###", "###", '#', Block.dirt});
}
}
Думаю, если вы читали уроки по созданию модов на ModLoader, там описывался крафтинг

7. Создание своего растения
1. Открываем файл Block.java

2. Добавляем новый блок как описано выше
Пример


roseblock = new BlockRose(162, 168).setHardness(0.5F).setResistance(0.3F).setLightValue(0F).setBlockName("rose");
3. Создаём файл с названием BlockRose (в нашем случае)

4. Добавляем в файл следующие строки




package net.minecraft.src;

import java.util.Random;

public class BlockRose extends Block
{
protected BlockRose(int par1, int par2)
{
super(par1, Material.plants);//материал растение
blockIndexInTexture = par2;
float f = 0.375F;
setBlockBounds(0.5F - f, 0.0F, 0.5F - f, 0.5F + f, 1.0F, 0.5F + f);
setTickRandomly(true);
}

/**
* Ticks the block if it's been scheduled
*/
public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)//Это сам алгоритм роста.
{
if (par1World.isAirBlock(par2, par3 + 1, par4))
{
int i;

for (i = 1; par1World.getBlockId(par2, par3 - i, par4) == blockID; i++) { }

if (i < 5) //Вырастает до 4-х блоков (если хотим, что бы рост был до 5-ти, то пишем число 6, всегда на единицу БОЛЬШЕ)
{
int j = par1World.getBlockMetadata(par2, par3, par4);

if (j == 15) //скорость роста (чем меньше значение, тем быстрее ростёт)
{
par1World.setBlockWithNotify(par2, par3 + 1, par4, blockID);
par1World.setBlockMetadataWithNotify(par2, par3, par4, 0);
}
else
{
par1World.setBlockMetadataWithNotify(par2, par3, par4, j + 1);
}
}
}
}

/**
* Checks to see if its valid to put this block at the specified coordinates. Args: world, x, y, z
*/
public boolean canPlaceBlockAt(World par1World, int x, int y, int z)//можно ли ставить блок
{
int i = par1World.getBlockId(x, y - 1, z);

if((par1World.getBlockId(x, y-1, z) == blockID)||(par1World.getBlockId(x, y-1, z) == Block.dirt.blockID)||(par1World.getBlockId(x, y-1, z) == Block.grass.blockID))
return true;

return false;//да
}

/**
* 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)
{
checkBlockCoordValid(par1World, par2, par3, par4);
}

/**
* Checks if current block pos is valid, if not, breaks the block as dropable item. Used for reed and cactus.
*/
protected final void checkBlockCoordValid(World par1World, int par2, int par3, int par4)
{
if (!canBlockStay(par1World, par2, par3, par4))
{
dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
par1World.setBlockWithNotify(par2, par3, par4, 0);
}
}

/**
* Can this block stay at this position. Similar to canPlaceBlockAt except gets checked often with plants.
*/
public boolean canBlockStay(World par1World, int x, int y, int z) //где можно будет посадить растение
{
if((par1World.getBlockId(x, y-1, z) == blockID)||(par1World.getBlockId(x, y-1, z) == Block.dirt.blockID)||(par1World.getBlockId(x, y-1, z) == Block.grass.blockID))
return true;

return false;
}
public void onEntityCollidedWithBlock(World par1World, int x, int y, int z, Entity par5Entity)
{
par5Entity.attackEntityFrom(DamageSource.cactus, 1);//атака игрока

}
/**
* Returns a bounding box from the pool of bounding boxes (this means this box can change after the pool has been
* cleared to be reused)
*/
public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int i)//оптическая рамка
{
return null;
}

/**
* Returns the ID of the items to drop on destruction.
*/
public int idDropped(int par1, Random par2Random, int par3)//выбрасываем по id
{
return Item.rose.shiftedIndex;
}

public boolean isOpaqueCube()//делаем блок непрозрачным
{
return false;
}

/**
* If this block doesn't render as an ordinary block it will return False (examples: signs, buttons, stairs, etc)
*/
public boolean renderAsNormalBlock()
{
return false;
}

/**
* The type of render function that is called for this block
*/
public int getRenderType()
{
return 1;
}
}

8. Создание моба (враждебный и дружелюбный) (1.3.2)
1. Создадим файл EntityMobNew.java
package net.minecraft.src;

import java.util.Random;

public class EntityMobNew extends EntityMob // если хотите мирного моба, то пишите - public class EntityMobNew extends EntityCreature
{
private static final ItemStack defaultHeldItem = new ItemStack(Item.bow, 1); //Даём в руку "лук"

public EntityMobNew(World par1World)
{
super(par1World);
this.texture = "/mob/zombie.png";//скин для моба
this.moveSpeed = 0.2F;//скорость перемещения
this.attackStrength = 4; //атака игрока //только для враждебного моба (если мирный, то удалите)
this.getNavigator().setAvoidsWater(true);
this.tasks.addTask(0, new EntityAISwimming(this));
this.tasks.addTask(1, new EntityAIBreakDoor(this));
this.tasks.addTask(2, new EntityAIAttackOnCollide(this, net.minecraft.src.EntityPlayer.class, moveSpeed, false)); //только для враждебного моба (если мирный, то удалите)
//this.tasks.addTask(2, new EntityAIRestrictSun(this));//горит на солнце
//this.tasks.addTask(3, new EntityAIFleeSun(this, moveSpeed));//бежит от солнца
this.tasks.addTask(3, new EntityAIWander(this, moveSpeed));
this.tasks.addTask(4, new EntityAIWatchClosest(this, net.minecraft.src.EntityPlayer.class, 8F));
this.tasks.addTask(5, new EntityAILookIdle(this));
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, net.minecraft.src.EntityPlayer.class, 16F, 0, true));//только для враждебного моба (если мирный, то удалите)
this.tasks.addTask(3, new EntityAIAttackOnCollide(this, net.minecraft.src.EntityZombie.class, moveSpeed, true));//атакует зомби только для враждебного моба (если мирный, то удалите)
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, net.minecraft.src.EntityZombie.class, 16F, 0, false)); //только для враждебного моба (если мирный, то удалите)
this.tasks.addTask(3, new EntityAIAttackOnCollide(this, net.minecraft.src.EntitySkeleton.class, moveSpeed, true));//атакует скелетов только для враждебного моба (если мирный, то удалите)
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, net.minecraft.src.EntitySkeleton.class, 16F, 0, false));//только для враждебного моба (если мирный, то удалите)
this.tasks.addTask(3, new EntityAIAttackOnCollide(this, net.minecraft.src.EntitySpider.class, moveSpeed, true));//атакует пауков только для враждебного моба (если мирный, то удалите)
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, net.minecraft.src.EntitySpider.class, 16F, 0, false));//только для враждебного моба (если мирный, то удалите)
}

/**
* Returns true if the newer Entity AI code should be run
*/
public boolean isAIEnabled()
{
return true;
}

public int getMaxHealth()
{
return 100; //ХП моба
}

/**
* Returns the sound this mob makes while it's alive.
*/
protected String getLivingSound()
{
return "mob.zombie"; //постоянное издование звуков
}

/**
* Returns the sound this mob makes when it is hurt.
*/
protected String getHurtSound()
{
return "mob.zombiehurt";//звук при получении урона
}

/**
* Returns the sound this mob makes on death.
*/
protected String getDeathSound()
{
return "mob.zombiedeath";//звук при смерти
}

/**
* Возвращаем предмет, который находится в руке у моба, если такой имеется
*/
public ItemStack getHeldItem()
{
return defaultHeldItem;
}

/**
* Get this Entity's EnumCreatureAttribute
*/
public EnumCreatureAttribute getCreatureAttribute()
{
return EnumCreatureAttribute.UNDEAD;
}

/**
* Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
* use this to react to sunlight and start to burn.
*/
public void onLivingUpdate()
{
super.onLivingUpdate();
}

/**
* Returns the item ID for the item the mob drops on death.
*/
protected int getDropItemId() //обязательный дроп той или иной вещи
{
return Item.arrow.shiftedIndex; //что будет выпадать
}

protected void dropRareDrop(int par1)//рандомный дроп вещей после смерти моба (если хотим, что бы выпадали ваши вещи, то меняйте названия итемов на ваши)
{
switch (rand.nextInt(4))
{
case 0:
dropItem(Item.swordSteel.shiftedIndex, 1);
break;

case 1:
dropItem(Item.helmetSteel.shiftedIndex, 1);
break;

case 2:
dropItem(Item.ingotIron.shiftedIndex, 1);
break;

case 3:
dropItem(Item.shovelSteel.shiftedIndex, 1);
break;
}
}

static
{
}
}
2. Идём в файлик EntityList.java (тут создаём яйцо для моба)
Ищем:


addMapping(EntityEnderCrystal.class, "EnderCrystal", 200);
Добавляем ниже:


addMapping(EntityMobNew.class, "MobNew", 101, 0xc1c1c1, 0x7FFF00);
Где 0xc1c1c1 - основной цвет яйца; 0x7FFF00 - цвет внешней части яйца. Везде 0x - обязательно оставляйте. Всё что после - обычная цветовая гамма HTML
3. Теперь идём в файл генерации мира BiomeGenForest.java (указываем где будет спавниться моб. В нашем случае в лесу)
Ищем:

this.spawnableCreatureList.add(new SpawnListEntry(EntityWolf.class, 5, 4, 4));
Ниже добавляем:


this.spawnableCreatureList.add(new SpawnListEntry(EntityMobNew.class, 2, 1, 1));
Если моб у нас враждебный, то меняем CreatureList на MonsterList (моб будет спавниться ночью)
Если вы хотите, что бы моб спавнился везде, то идём в BiomeGenBase.java
Ищем:

this.spawnableMonsterList.add(new SpawnListEntry(EntityEnderman.class, 1, 1, 4));
Ниже добавляем:


this.spawnableCreatureList.add(new SpawnListEntry(EntityMobNew.class, 4, 2, 5));
опять же, если моб у нас враждебный, то меняем CreatureList на MonsterList (моб будет спавниться ночью)

!!! Не забываем добавить сам скин моба в папку mob !!!
Если у вас сделан моб, не похожий на человека или любого другого прямоходящего (или же Вы хотите, что бы Ваш моб держал в руке предмет), то вам придётся создать файл ModelMobNew.java (по аналогии к примеру даже с тем же Ocelot)

1. Создадим файл ModelMobNew.java:

package net.minecraft.src;
public class ModelMobNew extends ModelBiped
{
public ModelMobNew()
{
}
/**
* Sets the models various rotation angles.
*/
public void setRotationAngles(float par1, float par2)//изменяем внутри, если хотим что бы моб был не прямоходящим (и убираем теги закоментированного кода - /* ... */)
{
/*super.setRotationAngles(par1, par2, par3, par4, par5, par6);
float f = MathHelper.sin(onGround * (float)Math.PI);
float f1 = MathHelper.sin((1.0F - (1.0F - onGround) * (1.0F - onGround)) * (float)Math.PI);
bipedRightArm.rotateAngleZ = 0.0F;
bipedLeftArm.rotateAngleZ = 0.0F;
bipedRightArm.rotateAngleY = -(0.1F - f * 0.6F);
bipedLeftArm.rotateAngleY = 0.1F - f * 0.6F;
bipedRightArm.rotateAngleX = -((float)Math.PI / 2F);
bipedLeftArm.rotateAngleX = -((float)Math.PI / 2F);
bipedRightArm.rotateAngleX -= f * 1.2F - f1 * 0.4F;
bipedLeftArm.rotateAngleX -= f * 1.2F - f1 * 0.4F;
bipedRightArm.rotateAngleZ += MathHelper.cos(par3 * 0.09F) * 0.05F + 0.05F;
bipedLeftArm.rotateAngleZ -= MathHelper.cos(par3 * 0.09F) * 0.05F + 0.05F;
bipedRightArm.rotateAngleX += MathHelper.sin(par3 * 0.067F) * 0.05F;
bipedLeftArm.rotateAngleX -= MathHelper.sin(par3 * 0.067F) * 0.05F;*/
}
}
2. Идем в файл RenderManager.java
Ищем:

private RenderManager()
{
Дописываем ниже:


this.entityRenderMap.put(net.minecraft.src.EntityMobNew.class, new RenderBiped(new ModelMobNew(), 0.5F));
9f4a3a92f6a3.png

9. Создание своего биома (1.3.2)
1. Вам нужно создать новый файл под именем BiomeGenNewBiome.java

Пример файла:

package net.minecraft.src;

import java.util.List;

public class BiomeGenNewBiome extends BiomeGenBase
{
public BiomeGenNewBiome(int par1)
{
super(par1);
this.spawnableCreatureList.clear();//либо запрещаем спавнится мобам, либо удаляем и вставляем то, что ниже
this.spawnableCreatureList.add(new SpawnListEntry(net.minecraft.src.EntityWolf.class, 5, 4, 4));//Разрешаем спавнится волку в этом биоме (или удалите, тогда оставьте то, что выше)
this.topBlock = (byte)Block.gold.blockID; //это верхний слой блоков, первое что вы увидите, будет этот блок
this.fillerBlock = (byte)Block.dirt.blockID;//слой толщиной 3-5 блоков под topBlock
this.theBiomeDecorator.treesPerChunk = 10; //количество деревьев на 1 чанк
this.theBiomeDecorator.grassPerChunk = 2; //количество травы на 1 чанк
}
}
2. Теперь нужно добавить ваш новый биом в BiomeGenBase.java

Ищем строчку


public static final BiomeGenBase jungleHills = (new BiomeGenJungle(22)).setColor(2900485).setBiomeName("JungleHills").func_76733_a(5470985).setTemperatureRainfall(1.2F, 0.9F).setMinMaxHeight(1.8F, 0.5F);
Добавляем после неё


public static final BiomeGenBase newBiome = (new BiomeGenNewBiome(23)).setColor(0xfade55).setBiomeName("NewBiome").setTemperatureRainfall(0.8F, 0.4F).setMinMaxHeight(0.0F, 0.1F);
Где:
newBiome - само название биома
23 - ID биома (Пишите свободные номера, по стандарту свободные начинаются с 23)
setColor - цвет биома (0x обязательно должно быть, всё остальное - код цвета HTML)
setTemperatureRainfall - температура на биоме
setMinMaxHeight - минимальная и максимальная высота биома

3. Теперь идём в файл GenLayerBiome (в нём прописываем, что бы ваш биом появился в мире)
Ищем:

BiomeGenBase.taiga,
После, вставляем:


BiomeGenBase.newBiome
Там две строчки похожие, вставляем и там и там

10. Создание инструментов
1) Зарегистрируем кирку в Item.java
public static ItemMap map = (ItemMap)(new ItemMap(102)).setIconCoord(12, 3).setItemName("map");
Ищем
добавляем строчку

public static Item pickaxeDirt;
Листаем в самый низ и добавляем

pickaxeDirt = (new ItemPickaxe(130, EnumToolMaterial.DIRT)).setIconCoord(3, 6).setItemName("pickaxeDirt");
130 - id кирки
DIRT - новый материал
3 и 6 это координаты
Дальше идёт название кирки

2) Добавим новый материал и дадим ему характеристики.
Открываем EnumToolMaterial и находим

GOLD(0, 32, 12F, 0, 22);
";" меняем на "," и дописываем

DIRT(0, 59, 2.0F, 0, 15);

3) Теперь добавим рецепт нашей кирки.
Идём в CraftingManager
ищем

addShapelessRecipe(new ItemStack(Item.fireballCharge, 3), new Object[]
{
Item.gunpowder, Item.blazePowder, new ItemStack(Item.coal, 1, 1)
});
и после этого ставим

addRecipe(new ItemStack(Item.pickaxeDirt, 1), new Object []
{
"DDD", " S ", " S ", 'D', Block.dirt, 'S', Item.stick
});
Крафтится также как и любая кирка, только вместо железа, золота и т.д., угадайте что.

4) Добавление имени.
Идём в minecraft.jar/lang, открываем ru_RU.lang и после

item.fireball.name=Огненный шар
пишем

item.pickaxeDirtl.name=Земленая кирка
(название не придумал)

Как сделать меч, топор, лопату.
Делается точно также, только вместо pickaxe пишем: axe - топор, sword - меч, shovel - лопата.

Example

public static Item axeDirt;
axeDirt = (new ItemAxe(130, EnumToolMaterial.DIRT)).setIconCoord(3, 6).setItemName("axeDirt");
addRecipe(new ItemStack(Item.axeDirt, 1), new Object []
{
"DD ", "DS ", " S ", 'D', Block.dirt, 'S', Item.stick
});
item.axeDirtl.name=Земленой топор
Это топор.

11. Создание брони на основе новых материалов
1) Для начала откроем файл Item.java.
Найдём строчку

public static ItemMap map = (ItemMap)(new ItemMap(102)).setIconCoord(12, 3).setItemName("map");
и после неё пишем

public static Item helmetWood;
public static Item plateWood;
public static Item legsWood;
public static Item bootsWood;
Затем листаем в самый низ и после


speckledMelon = (new Item(126)).setIconCoord(9, 8).setItemName("speckledMelon").setPotionEffect(PotionHelper.speckledMelonEffect);
пишем


helmetWood = (new ItemArmor(130, EnumArmorMaterial.WOOD, 5, 0)).setIconCoord(0, 9).setItemName("helmetWood");
plateWood = (new ItemArmor(131, EnumArmorMaterial.WOOD, 5, 1)).setIconCoord(0, 10).setItemName("chestplateWood");
legsWood = (new ItemArmor(132, EnumArmorMaterial.WOOD, 5, 2)).setIconCoord(0, 11).setItemName("leggingsWood");
bootsWood = (new ItemArmor(133, EnumArmorMaterial.WOOD, 5, 3)).setIconCoord(0, 12).setItemName("bootsWood");
130 - id(рекомендую использовать с 130).
WOOD - материал.
5 - порядковый номер (0 - кожа, 1 - кольчуга, 2 - железо, 3 - алмаз, 4 - золото).
0 - шлем, 1 - нагрудник, 2 - штаны, 3 - носки).
0 и 9 это координаты.
setItemName - название брони.
2) Добавление своих характеристик.
Откроем EnumArmorMaterial.ja.va
Ищем строчку

DIAMOND(33, new int[] {
3, 8, 6, 3
}, 10);
Убираем ";" и ставим знак ",". Затем, после этого вставляем

WOOD(6, new int[] {
2, 5, 1, 2
}, 17);
У дерева приблизительно те же свойства, что и у кожи.

3) Затем добавим рецепт.
Открываем RecipesArmor.java и после

Item.ingotGold
ставим запятую и пишем


Block.planks
ниже

}, new Object[] {
Item.helmetLeather, Item.helmetChain, Item.helmetSteel, Item.helmetDiamond, Item.helmetGold
}, new Object[] {
Item.plateLeather, Item.plateChain, Item.plateSteel, Item.plateDiamond, Item.plateGold
}, new Object[] {
Item.legsLeather, Item.legsChain, Item.legsSteel, Item.legsDiamond, Item.legsGold
}, new Object[] {
Item.bootsLeather, Item.bootsChain, Item.bootsSteel, Item.bootsDiamond, Item.bootsGold
}
заменяем на

}, new Object[] {
Item.helmetLeather, Item.helmetChain, Item.helmetSteel, Item.helmetDiamond, Item.helmetGold, Item.helmetWood
}, new Object[] {
Item.plateLeather, Item.plateChain, Item.plateSteel, Item.plateDiamond, Item.plateGold, Item.plateWood
}, new Object[] {
Item.legsLeather, Item.legsChain, Item.legsSteel, Item.legsDiamond, Item.legsGold, Item.legsWood
}, new Object[] {
Item.bootsLeather, Item.bootsChain, Item.bootsSteel, Item.bootsDiamond, Item.bootsGold, Item.bootsWood
}

4) Сейчас мы добавим имя нашей броне.
Заходим в minecraft.jar/lang/, открываем ru_RU.lang
Ищем строчку item.fireball.name=Огненный шар и ниже пишем


item.helmetWood.name=Деревянный шлем
item.chestplateWood.name=Деревянная куртка
item.leggingsWood.name=Деревянные штаны
item.bootsWood.name=Деревянные ботинки
Вот и всё)

Инглиш версия en_US.lang
item.helmetWood.name=Wooden Helmet
item.chestplateWood.name=Wooden Plate
item.leggingsWood.name=Wooden Leggins
item.bootsWood.name=Wooden Boots

12. Создание еды (с эффектами) (1.3.2)
1) Для начала откроем файл Item.java.
2) Найдём данные строки:

/** Item index + 256 */
public final int shiftedIndex;
И над этим кодом добавим еду (итем)

public static Item newFood = (new ItemFood(133, 4, 0.3F, false)).setIconCoord(10, 0).setItemName("newFood").setAlwaysEdible();
Item newFood - название предмета (еды)
(new ItemFood( - говорит, что данный итем - еда (и посылается в файл ItemFood.java)
133 - ID предмета
4 - восполнение "полосок" голода
0.3F - *пока не разбирался*
false - приручение волка (да/нет)
setIconCoord(10, 0) - координаты текстуры в файле items.png
setItemName("newFood") - переменная (имя) для перевода через lang файл
.setAlwaysEdible() - всегда можно кушать

Если вы хотите добавить эффект к еде, то смотрите (остальные эффекты в файле Potion.java):
После:

(new ItemFood(133, 4, 0.3F, false)).setAlwaysEdible().
Вставляем:
1) Регенерация здоровья (Этот участок кода говорит, что если вы скушаете данную еду, то она будет регенерировать ваше здоровье определённое кол-во времени)


setPotionEffect(Potion.regeneration.id, 5, 0, 1.0F).
2) Отравление (Этот участок кода говорит, что если вы скушаете данную еду, то вы будете голодать определённое кол-во времени)


setPotionEffect(Potion.hunger.id, 30, 0, 0.8F).
Этот участок кода говорит, что если вы скушаете данную еду, то она будет регенерировать ваше здоровье определённое кол-во времени
5(30) - длительность эффекта
0 - интенсивность
1.0F(0.8F) - вероятность эффекта

13. Создание достижений
1. Откроем файл AchievementList.java

2. Найдём строки:

/** Is the 'Librarian' achievement */
public static Achievement bookcase = (new Achievement(26, "bookcase", -3, 6, Block.bookShelf, enchantments)).registerAchievement();
3. После, добавим:


public static Achievement mineDirt = (new Achievement(27, "mineDirt", 0, 0, Block.dirt, (Achievement)null)).registerAchievement();
Achievement mineDirt - название достижения
27 - ID достижения (свободные начинаются с 27)
"mineDirt" - перевод через lang файл
Block.dirt - при добыче КАКОГО блока (предмета) засчитывать достижение
(Achievement)null)) - независимое достижение, то есть ни как с досками, что бы сначала получить дерево, потом скрафтить из него доски.
registerAchievement() - регистрируем достижение

4. Откроем файл EntityItem.java и найдём в нём:

if (this.item.itemID == Block.wood.blockID)
{
par1EntityPlayer.triggerAchievement(AchievementList.mineWood);
}
5. Добавим после:


if (this.item.itemID == Block.dirt.blockID)
{
par1EntityPlayer.triggerAchievement(AchievementList.mineDirt);
}
То есть при добыче земли (в нашем случае) выводить надпись о выполнении достижения с картинкой данного блока (предмета)

14. Создание рецепта для печки (1.3.2)
1. Открываем файл FurnaceRecipes.java
2. Ищем строчку

this.addSmelting(Block.oreLapis.blockID, new ItemStack(Item.dyePowder, 1, 4), 0.2F);
3. После, добавляем


this.addSmelting(Item.baseItem.shiftedIndex, new ItemStack(Item.resultItem));
Где:
Item.baseItem
- предмет, который кладём в печку
Item.resultItem - предмет, который в итоге получится после плавки

Если вы хотите плавить блок, то добавляем что-то на подобии этого:


this.addSmelting(Block.baseBlock.blockID, new ItemStack(Item.resultItem), 0.2F);
Где:
Block.baseBlock - блок, который кладём в печку
Item.resultItem - предмет, который получается в итоге

Если вы хотите после плавки получить не предмет, а блок, то вместо:


new ItemStack(Item.resultItem), 0.2F);
Пишите:


new ItemStack(Block.glass), 0.1F);

15. Делаем предмет топливом для печки (1.3.2)
1. Открываем файл TileEntityFurnace.java
2. Ищем строчку

return var2 instanceof ItemTool && ((ItemTool)var2).func_77861_e().equals("WOOD") ? 200 : (var2 instanceof ItemSword && ((ItemSword)var2).func_77825_f().equals("WOOD") ? 200 : (var2 instanceof ItemHoe && ((ItemHoe)var2).func_77842_f().equals("WOOD") ? 200 : (var1 == Item.stick.shiftedIndex ? 100 : (var1 == Item.coal.shiftedIndex ? 1600 : (var1 == Item.bucketLava.shiftedIndex ? 20000 : (var1 == Block.sapling.blockID ? 100 : (var1 == Item.blazeRod.shiftedIndex ? 2400 : 0)))))));
3. В этом коде, после этого (и до "0")


(var1 == Item.blazeRod.shiftedIndex ? 2400 :
4. Вставляем код (пример)


(var1 == Item.newItem.shiftedIndex ? 2400 :
Где:
Item.newItem - предмет, который хотим сделать топливом
2400 - время горения (к примеру время горения у "угля" - 1600, что равно 80 секунд )

16. Добавляем новый (свой) игровой режим (1.3.2)
1. Открываем файл EnumGameType.java
1.1 Ищем строку:


ADVENTURE(2, "adventure"),
1.2 Добавляем, после:


NEWMODE(3, "newmode");
newmode - имя нашего режима игры
1.3 Ищем строки:

public void configurePlayerCapabilities(PlayerCapabilities par1PlayerCapabilities)
{
if (this == CREATIVE)
{
par1PlayerCapabilities.allowFlying = true;
par1PlayerCapabilities.isCreativeMode = true;
par1PlayerCapabilities.disableDamage = true;
}
else
{
par1PlayerCapabilities.allowFlying = false;
par1PlayerCapabilities.isCreativeMode = false;
par1PlayerCapabilities.disableDamage = false;
par1PlayerCapabilities.isFlying = false;
}
par1PlayerCapabilities.allowEdit = !this.isAdventure();
}
1.4 Заменяем на:


public void configurePlayerCapabilities(PlayerCapabilities par1PlayerCapabilities)
{
if (this == CREATIVE)
{
par1PlayerCapabilities.allowFlying = true;
par1PlayerCapabilities.isCreativeMode = true;
par1PlayerCapabilities.disableDamage = true;
}
else if(this == SURVIVAL)
{
par1PlayerCapabilities.allowFlying = false;
par1PlayerCapabilities.isCreativeMode = false;
par1PlayerCapabilities.disableDamage = false;
par1PlayerCapabilities.isFlying = false;
}
else if(this == NEWMODE)
{
par1PlayerCapabilities.allowFlying = false; //разрешаем/запрещаем игроку летать по двойному прыжку
par1PlayerCapabilities.isCreativeMode = false; //если у нас режим, похожий на креатив, то пишем true, если же нет - false
par1PlayerCapabilities.disableDamage = true; //вклчюаем/отключаем получение урона
par1PlayerCapabilities.isFlying = false;
}

par1PlayerCapabilities.allowEdit = !this.isAdventure();
}
NEWMODE - имя режима, которое мы вписывали тут

1.2 Добавляем, после:

NEWMODE(3, "newmode");

2. Делаем подобие инвентаря как в "креативе"
2.1 Для того, что бы сделать инвентарь как в креативе, надо найти строки:


public boolean isCreative()
{
return this == CREATIVE;
}
2.2 И приписать наш новый режим вот таким образом:


public boolean isCreative()
{
return this == CREATIVE || this == NEWMODE;
}
NEWMODE - имя режима, которое мы вписывали тут

1.2 Добавляем, после:

NEWMODE(3, "newmode");


3. Делаем подобие инвентаря как в "выживании"
3.1 Для того, что бы сделать инвентарь как в выживании, надо найти строки:


public boolean func_77144_e()
{
return this == SURVIVAL || this == ADVENTURE;
}
3.2 И приписать наш новый режим вот таким образом:


public boolean func_77144_e()
{
return this == SURVIVAL || this == ADVENTURE || this == NEWMODE;
}
NEWMODE - имя режима, которое мы вписывали тут

1.2 Добавляем, после:

NEWMODE(3, "newmode");


4. Добавляем наш режим в создание мира (в меню)
4.1 Открываем файл GuiCreateWorld.java
4.2 Ищем строки:


else if (this.gameMode.equals("hardcore"))
{
if (!this.field_73935_p)
{
this.field_73926_o = true;
}
this.field_73933_r = false;
this.gameMode = "creative";
this.func_73914_h();
this.field_73933_r = false;
this.field_73936_z.enabled = true;
this.field_73938_x.enabled = true;
}
4.3 Добавляем ниже:


else if (this.gameMode.equals("creative"))
{
if (!this.field_73935_p)
{
this.field_73926_o = true;
}
this.field_73933_r = false;
this.gameMode = "newmode";
this.func_73914_h();
this.field_73933_r = false;
this.field_73936_z.enabled = true;
this.field_73938_x.enabled = true;
}
creative - после какого режима будет показываться наш режим
newmode - имя нашего режима игры
4.4 Открываем файл GuiSelectWorld.java
4.5 Ищем строку:

private String[] localizedGameModeText = new String[3];
И меняем цифру 3 на 4, так как нумирация идёт с нуля, и получается 4 режима игры

NOT_SET(-1, ""),
SURVIVAL(0, "survival"),
CREATIVE(1, "creative"),
ADVENTURE(2, "adventure"),
NEWMODE(3, "newmode");
4.6 Ищем строку:


this.localizedGameModeText[EnumGameType.ADVENTURE.getID()] = var1.translateKey("gameMode.adventure");
4.7 Добавляем ниже наш новый режим


this.localizedGameModeText[EnumGameType.NEWMODE.getID()] = var1.translateKey("gameMode.newmode");
NEWMODE - имя режима, которое мы вписывали тут

1.2 Добавляем, после:

NEWMODE(3, "newmode");


5. Добавляем название режима и описание в lang файл
5.1 Открываем файл ru_RU.lang
5.2 Ищем строку:


gameMode.hardcore=Хардкор!
5.3 Добавляем ниже:


gameMode.newmode=Новый режим
Добавляем описание режима
5.4 Ищем строку


selectWorld.gameMode.hardcore.line2=сложностью и только одной жизнью
5.5 Добавляем ниже:


selectWorld.gameMode.newmode=Новый режим
selectWorld.gameMode.newmode.line1=Описание 1
selectWorld.gameMode.newmode.line2=описание 2
Всё, если Вы всё сделали правильно, то при создании мира, можно выбрать наш режим
72c8426bf350.png

И после перезахода в игру, ваш сохранённый мир будет показан
3bf66475d358.png

17. Создание своей (новой) жидкости (1.3.2) (Добавлено)
1. Открываем файл Block.java
2. Добавляем новый блок


public static final Block newFluidMoving = (new BlockNewFlowingFluid(160, Material.water)).setHardness(100.0F).setLightOpacity(3).setBlockName("new").setCreativeTab(CreativeTabs.tabBlock).disableStats().setRequiresSelfNotify();
public static final Block newFluidStill = (new BlockNewStationaryFluid(161, Material.water)).setHardness(100.0F).setLightOpacity(3).setBlockName("new").setCreativeTab(CreativeTabs.tabBlock).disableStats().setRequiresSelfNotify();
3. Создаём новые файлы
3.1. BlockNewFlowingFluid.java (текучая жидкость)


package net.minecraft.src;
import java.util.Random;
public class BlockNewFlowingFluid extends BlockFluid
{
/**
* Number of horizontally adjacent liquid source blocks. Diagonal doesn't count. Only source blocks of the same
* liquid as the block using the field are counted.
*/
int numAdjacentSources;
boolean isOptimalFlowDirection[];
int flowCost[];
protected BlockNewFlowingFluid(int par1, Material par2Material)
{
super(par1, par2Material);
numAdjacentSources = 0;
isOptimalFlowDirection = new boolean[4];
flowCost = new int[4];
}
/**
* Цвет жидкости
*/
public int colorMultiplier(IBlockAccess iblockaccess, int i, int j, int k)
{
return 0xFF6666;
}
/**
* Updates the flow for the BlockFlowing object.
*/
private void updateFlow(World par1World, int par2, int par3, int par4)
{
int i = par1World.getBlockMetadata(par2, par3, par4);
par1World.setBlockAndMetadata(par2, par3, par4, blockID + 1, i);
par1World.markBlocksDirty(par2, par3, par4, par2, par3, par4);
par1World.markBlockNeedsUpdate(par2, par3, par4);
}
public boolean getBlocksMovement(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
{
return blockMaterial != Material.lava;
}
/**
* Ticks the block if it's been scheduled
*/
public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
{
int var6 = this.getFlowDecay(par1World, par2, par3, par4);
byte var7 = 1;
if (this.blockMaterial == Material.lava && !par1World.provider.isHellWorld)
{
var7 = 2;
}
boolean var8 = true;
int var10;
if (var6 > 0)
{
byte var9 = -100;
this.numAdjacentSources = 0;
int var12 = this.getSmallestFlowDecay(par1World, par2 - 1, par3, par4, var9);
var12 = this.getSmallestFlowDecay(par1World, par2 + 1, par3, par4, var12);
var12 = this.getSmallestFlowDecay(par1World, par2, par3, par4 - 1, var12);
var12 = this.getSmallestFlowDecay(par1World, par2, par3, par4 + 1, var12);
var10 = var12 + var7;
if (var10 >= 8 || var12 < 0)
{
var10 = -1;
}
if (this.getFlowDecay(par1World, par2, par3 + 1, par4) >= 0)
{
int var11 = this.getFlowDecay(par1World, par2, par3 + 1, par4);
if (var11 >= 8)
{
var10 = var11;
}
else
{
var10 = var11 + 8;
}
}
if (this.numAdjacentSources >= 2 && this.blockMaterial == Material.water)
{
if (par1World.getBlockMaterial(par2, par3 - 1, par4).isSolid())
{
var10 = 0;
}
else if (par1World.getBlockMaterial(par2, par3 - 1, par4) == this.blockMaterial && par1World.getBlockMetadata(par2, par3, par4) == 0)
{
var10 = 0;
}
}
if (this.blockMaterial == Material.lava && var6 < 8 && var10 < 8 && var10 > var6 && par5Random.nextInt(4) != 0)
{
var10 = var6;
var8 = false;
}
if (var10 == var6)
{
if (var8)
{
this.updateFlow(par1World, par2, par3, par4);
}
}
else
{
var6 = var10;
if (var10 < 0)
{
par1World.setBlockWithNotify(par2, par3, par4, 0);
}
else
{
par1World.setBlockMetadataWithNotify(par2, par3, par4, var10);
par1World.scheduleBlockUpdate(par2, par3, par4, this.blockID, this.tickRate());
par1World.notifyBlocksOfNeighborChange(par2, par3, par4, this.blockID);
}
}
}
else
{
this.updateFlow(par1World, par2, par3, par4);
}
if (this.liquidCanDisplaceBlock(par1World, par2, par3 - 1, par4))
{
if (this.blockMaterial == Material.lava && par1World.getBlockMaterial(par2, par3 - 1, par4) == Material.water)
{
par1World.setBlockWithNotify(par2, par3 - 1, par4, Block.stone.blockID);
this.triggerLavaMixEffects(par1World, par2, par3 - 1, par4);
return;
}
if (var6 >= 8)
{
this.flowIntoBlock(par1World, par2, par3 - 1, par4, var6);
}
else
{
this.flowIntoBlock(par1World, par2, par3 - 1, par4, var6 + 8);
}
}
else if (var6 >= 0 && (var6 == 0 || this.blockBlocksFlow(par1World, par2, par3 - 1, par4)))
{
boolean[] var13 = this.getOptimalFlowDirections(par1World, par2, par3, par4);
var10 = var6 + var7;
if (var6 >= 8)
{
var10 = 1;
}
if (var10 >= 8)
{
return;
}
if (var13[0])
{
this.flowIntoBlock(par1World, par2 - 1, par3, par4, var10);
}
if (var13[1])
{
this.flowIntoBlock(par1World, par2 + 1, par3, par4, var10);
}
if (var13[2])
{
this.flowIntoBlock(par1World, par2, par3, par4 - 1, var10);
}
if (var13[3])
{
this.flowIntoBlock(par1World, par2, par3, par4 + 1, var10);
}
}
}
/**
* flowIntoBlock(World world, int x, int y, int z, int newFlowDecay) - Flows into the block at the coordinates and
* changes the block type to the liquid.
*/
private void flowIntoBlock(World par1World, int par2, int par3, int par4, int par5)
{
if (liquidCanDisplaceBlock(par1World, par2, par3, par4))
{
int i = par1World.getBlockId(par2, par3, par4);
if (i > 0)
{
if (blockMaterial == Material.lava)
{
triggerLavaMixEffects(par1World, par2, par3, par4);
}
else
{
Block.blocksList.dropBlockAsItem(par1World, par2, par3, par4, par1World.getBlockMetadata(par2, par3, par4), 0);
}
}
par1World.setBlockAndMetadataWithNotify(par2, par3, par4, blockID, par5);
}
}
/**
* calculateFlowCost(World world, int x, int y, int z, int accumulatedCost, int previousDirectionOfFlow) - Used to
* determine the path of least resistance, this method returns the lowest possible flow cost for the direction of
* flow indicated. Each necessary horizontal flow adds to the flow cost.
*/
private int calculateFlowCost(World par1World, int par2, int par3, int par4, int par5, int par6)
{
int i = 1000;
for (int j = 0; j < 4; j++)
{
if (j == 0 && par6 == 1 || j == 1 && par6 == 0 || j == 2 && par6 == 3 || j == 3 && par6 == 2)
{
continue;
}
int k = par2;
int l = par3;
int i1 = par4;
if (j == 0)
{
k--;
}
if (j == 1)
{
k++;
}
if (j == 2)
{
i1--;
}
if (j == 3)
{
i1++;
}
if (blockBlocksFlow(par1World, k, l, i1) || par1World.getBlockMaterial(k, l, i1) == blockMaterial && par1World.getBlockMetadata(k, l, i1) == 0)
{
continue;
}
if (!blockBlocksFlow(par1World, k, l - 1, i1))
{
return par5;
}
if (par5 >= 4)
{
continue;
}
int j1 = calculateFlowCost(par1World, k, l, i1, par5 + 1, j);
if (j1 < i)
{
i = j1;
}
}
return i;
}
/**
* Returns a boolean array indicating which flow directions are optimal based on each direction's calculated flow
* cost. Each array index corresponds to one of the four cardinal directions. A value of true indicates the
* direction is optimal.
*/
private boolean[] getOptimalFlowDirections(World par1World, int par2, int par3, int par4)
{
for (int i = 0; i < 4; i++)
{
flowCost = 1000;
int k = par2;
int j1 = par3;
int k1 = par4;
if (i == 0)
{
k--;
}
if (i == 1)
{
k++;
}
if (i == 2)
{
k1--;
}
if (i == 3)
{
k1++;
}
if (blockBlocksFlow(par1World, k, j1, k1) || par1World.getBlockMaterial(k, j1, k1) == blockMaterial && par1World.getBlockMetadata(k, j1, k1) == 0)
{
continue;
}
if (!blockBlocksFlow(par1World, k, j1 - 1, k1))
{
flowCost = 0;
}
else
{
flowCost = calculateFlowCost(par1World, k, j1, k1, 1, i);
}
}
int j = flowCost[0];
for (int l = 1; l < 4; l++)
{
if (flowCost[l] < j)
{
j = flowCost[l];
}
}
for (int i1 = 0; i1 < 4; i1++)
{
isOptimalFlowDirection[i1] = flowCost[i1] == j;
}
return isOptimalFlowDirection;
}
/**
* Returns true if block at coords blocks fluids
*/
//Думаю тут понятно.
private boolean blockBlocksFlow(World par1World, int par2, int par3, int par4)
{
int i = par1World.getBlockId(par2, par3, par4);
if (i == Block.doorWood.blockID || i == Block.doorSteel.blockID || i == Block.signPost.blockID || i == Block.ladder.blockID || i == Block.reed.blockID)
{
return true;
}
if (i == 0)
{
return false;
}
Material material = Block.blocksList.blockMaterial;
if (material == Material.portal)
{
return true;
}
return material.blocksMovement();
}
/**
* getSmallestFlowDecay(World world, intx, int y, int z, int currentSmallestFlowDecay) - Looks up the flow decay at
* the coordinates given and returns the smaller of this value or the provided currentSmallestFlowDecay. If one
* value is valid and the other isn't, the valid value will be returned. Valid values are >= 0. Flow decay is the
* amount that a liquid has dissipated. 0 indicates a source block.
*/
protected int getSmallestFlowDecay(World par1World, int par2, int par3, int par4, int par5)
{
int i = getFlowDecay(par1World, par2, par3, par4);
if (i < 0)
{
return par5;
}
if (i == 0)
{
numAdjacentSources++;
}
if (i >= 8)
{
i = 0;
}
return par5 >= 0 && i >= par5 ? par5 : i;
}
/**
* Returns true if the block at the coordinates can be displaced by the liquid.
*/
private boolean liquidCanDisplaceBlock(World par1World, int par2, int par3, int par4)
{
Material material = par1World.getBlockMaterial(par2, par3, par4);
if (material == blockMaterial)
{
return false;
}
if (material == Material.lava)
{
return false;
}
else
{
return !blockBlocksFlow(par1World, par2, par3, par4);
}
}
/**
* 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);
if (par1World.getBlockId(par2, par3, par4) == blockID)
{
par1World.scheduleBlockUpdate(par2, par3, par4, blockID, tickRate());
}
}
}
3.2. BlockNewStationaryFluid.java (стоячая жидкость)


package net.minecraft.src;
import java.util.Random;
public class BlockNewStationaryFluid extends BlockFluid
{
protected BlockNewStationaryFluid(int par1, Material par2Material)
{
super(par1, par2Material);
setTickRandomly(false);
if (par2Material == Material.lava)
{
setTickRandomly(true);
}
}
/**
* Цвет жидкости
*/
public int colorMultiplier(IBlockAccess iblockaccess, int i, int j, int k)
{
return 0xFF6666;
}

public boolean getBlocksMovement(IBlockAccess par1IBlockAccess, int par2, int par3, int par4)
{
return blockMaterial != Material.lava;
}
/**
* 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);
if (par1World.getBlockId(par2, par3, par4) == blockID)
{
setNotStationary(par1World, par2, par3, par4);
}
}
/**
* Changes the block ID to that of an updating fluid.
*/
private void setNotStationary(World par1World, int par2, int par3, int par4)
{
int i = par1World.getBlockMetadata(par2, par3, par4);
par1World.editingBlocks = true;
par1World.setBlockAndMetadata(par2, par3, par4, blockID - 1, i);
par1World.markBlocksDirty(par2, par3, par4, par2, par3, par4);
par1World.scheduleBlockUpdate(par2, par3, par4, blockID - 1, tickRate());
par1World.editingBlocks = false;
}
/**
* Ticks the block if it's been scheduled
*/
public void updateTick(World par1World, int par2, int par3, int par4, Random par5Random)
{
if (blockMaterial == Material.lava)
{
int i = par5Random.nextInt(3);
for (int j = 0; j < i; j++)
{
par2 += par5Random.nextInt(3) - 1;
par3++;
par4 += par5Random.nextInt(3) - 1;
int l = par1World.getBlockId(par2, par3, par4);
if (l == 0)
{
if (isFlammable(par1World, par2 - 1, par3, par4) || isFlammable(par1World, par2 + 1, par3, par4) || isFlammable(par1World, par2, par3, par4 - 1) || isFlammable(par1World, par2, par3, par4 + 1) || isFlammable(par1World, par2, par3 - 1, par4) || isFlammable(par1World, par2, par3 + 1, par4))
{
par1World.setBlockWithNotify(par2, par3, par4, Block.fire.blockID);
return;
}
continue;
}
if (Block.blocksList[l].blockMaterial.blocksMovement())
{
return;
}
}
if (i == 0)
{
int k = par2;
int i1 = par4;
for (int j1 = 0; j1 < 3; j1++)
{
par2 = (k + par5Random.nextInt(3)) - 1;
par4 = (i1 + par5Random.nextInt(3)) - 1;
if (par1World.isAirBlock(par2, par3 + 1, par4) && isFlammable(par1World, par2, par3, par4))
{
par1World.setBlockWithNotify(par2, par3 + 1, par4, Block.fire.blockID);
}
}
}
}
}
/**
* Checks to see if the block is flammable.
*/
private boolean isFlammable(World par1World, int par2, int par3, int par4)
{
return par1World.getBlockMaterial(par2, par3, par4).getCanBurn();
}
}
Дополнения для блоков (Обновлено) (1.3.2)
1. Запрещаем просмотр мира сквозь блок (как X-Ray)
Добавляем в файл блока перед последней скобкой данный код


public boolean isOpaqueCube()
{
return false;
}
2. Добавляем атаку игрока при соприкосновении с блоком
public void onEntityCollidedWithBlock(World par1World, int x, int y, int z, Entity par5Entity)
{
par5Entity.attackEntityFrom(DamageSource.cactus, 1);
}
3. Добавляем разные текстуры на разные поверхности блоков
1. Когда мы создаём блок, мы указываем основную текстуру блока, к примеру

(new BlockNew(46, 8))
8 - текстура блока (в нашем случаем мы указали переднюю текстуру блока)

2. Открываем файл самого блока, и добавляем


public int getBlockTextureFromSide(int par1)
{
return par1 == 0 ? this.blockIndexInTexture + 2 : (par1 == 1 ? this.blockIndexInTexture + 1 : this.blockIndexInTexture);
}
this.blockIndexInTexture + 2 - текстура нижней части блока (то есть мы к 8-ой текстуре прибавляем 2 и получаем 10-ую текстуру. Значит текстура, которая идёт по счёту 10-ой - становится вниз блока)
this.blockIndexInTexture + 1 - текстура верхней части блока (так же как и с нижней частью, только прибавляем 1, а не 2. А значит текстура, которая идёт 9-ой становится на верх блока)
4. Делаем блок "проходимым"
public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int i)
{
return null;
}

Создание второго items.png (1.3.2)
1. Открываем файл RenderItem.java
1.1. Добавляем Иморты


import net.minecraft.src.Item;
import net.minecraft.src.ItemStack;
1.2. Ищем строчки:


if (par3 < 256)
{
par2RenderEngine.bindTexture(par2RenderEngine.getTexture("/terrain.png"));
}
1.3. Добавляем после:


else if (Item.is2Item(par3))
{
par2RenderEngine.bindTexture(par2RenderEngine.getTexture("/gui/items-2.png"));
}
2. Открываем файл ItemRenderer.java
2.1. Добавляем Иморты


import net.minecraft.src.Item;
import net.minecraft.src.ItemStack;
2.2. Ищем строчки:


if (var4 != null)
{
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.mc.renderEngine.getTexture("/terrain.png"));
}
2.3. Добавляем после:


else if (Item.is2Item(par2ItemStack.itemID))
{
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.mc.renderEngine.getTexture("/gui/items-2.png"));
}
3. Открываем файл Item.java
3.1. Ищем:


public Item setTabToDisplayOn(CreativeTabs par1CreativeTabs)
{
this.field_77701_a = par1CreativeTabs;
return this;
}
3.2. Добавляем после:


public static boolean is2Item (int id)
{
return ((id >= 3000) && (id < 3257));
}
Теперь предметы с ID от 3000 до 3256 будут использовать Items-2.png
Сам файл items-2.png должен находится по этому пути: minecraft.jar/gui/items-2.png

Создание второго terrain.png (1.3.2) (доделано не до конца)
1. Открываем файл RenderItem.java
1.1. Добавляем Иморты

import net.minecraft.src.Block;
import net.minecraft.src.ItemStack;
1.2. Ищем строчки:


if (par3 < 256)
{
par2RenderEngine.bindTexture(par2RenderEngine.getTexture("/terrain.png"));
}
1.3. Добавляем после:


else if (Block.is2Block(par3))
{
par2RenderEngine.bindTexture(par2RenderEngine.getTexture("/terrain-2.png"));
}
2. Открываем файл ItemRenderer.java
2.1. Добавляем Иморты


import net.minecraft.src.Block;
import net.minecraft.src.ItemStack;
2.2. Ищем строчки:


if (var4 != null)
{
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.mc.renderEngine.getTexture("/terrain.png"));
}
2.3. Добавляем после:


else if (Block.is2Block(par2ItemStack.itemID))
{
GL11.glBindTexture(GL11.GL_TEXTURE_2D, this.mc.renderEngine.getTexture("/terrain-2.png"));
}
3. Открываем файл Block.java
3.1. Ищем:


/**
* Called when the time changes.
*/
public void onTimeChanged(World par1World, long par2, long par4) {}
3.2. Добавляем после:


public static boolean is2Block(int id)
{
return ((id >= 160) && (id < 251));
}
Теперь блоки с ID от 150 до 250 будут использовать terrain-2.png
Сам файл terrain-2.png должен находится по этому пути: minecraft.jar/terrain-2.png

Получаем любую версию MineCraft
Я хочу вам рассказать о таком ресурсе внутреннего пользования как http://assets.minecraft.net/ (Официальный storage)

1. Открываем сайт
Получаем xml документ

2. Смотрим, какую версию вы хотите.
К примеру нам требуется скачать версию клиента (сервера) 1.4.7 (можете выбрать также любой пререлиз)

3. Открываем поиск, и ищем тег 1_4_7
На наш запрос обнаружилось 4 результата,
Первый - совсем для внутреннего пользования, пропускаем. а затем видим 3 тега:
1_4_7/Minecraft_Server.exe
1_4_7/minecraft.jar
1_4_7/minecraft-server.jar

Знакомо? правильно - 2 - клиент, остальное - сервер.
Также мы видим метаинфу - размер и хэш файла.

4. Скачиваем нужную версию
Допустим возьмём клиент версии 1.4.7: дописываем к ссылке сайта

Ну и напоследок:
скажу что на сайте есть и другие "вкусности" например pe версия, а также файлы личного пользования(немногие, правда, запаролены).

Коды все рабочие и протестированные!
I_approve.gif

Отдельное спасибо:
FunnyAlien
blezigen - описание "Добавление имени блоку" и "Создание растения"
timkill - сборка моба из разных частей
_VlaDoS - создание брони и инструментов
ROBOCOP - описание категорий креатива
icool - добавление второго items.png
ROBOCOP - создание жидкости
cdkrot - скачиваем любую версию MineCraft

P.S Тема будет пополняться со временем, так как я сначала делаю, потом выкладываю.
Не забываем удалить папку!


META-INFиз minecraft.jar
Если не удалите её, то будет много ошибок!












Важно!
"Большинство модов после этого изменения клиента (сервера) работать уже не будет"
и
"Если обновите клиент, то ваши модификации удалятся"





Автор - я. Копирование без размещения ссылки - запрещено.








 
Главная Регистрация
Назад
Сверху