Привет, я решил, что пора бы уже сделать ГАЙД, в котором решатся многие проблемы новичков при создании мода. Есть конечно тема Skarlet, но в ней устарелая и не совсем приятная "инфа". Опираться иногда будет на другой мой гайд - [Mini-Guide]Локализация чего угодно и как угодно.
Из проблем, которые я решать не буду:
Так же не пишите в личку по поводу проектов. Просто было у меня уже не раз такое, а так легко я не буду что либо делать (Делать проект за бесплатно, помогать за бесплатно). Исключения - у меня есть всего-лишь один человек, которого я обучаю моддингу, так ещё и бесплатно, но тогда я был добреньким, ня :з
На последок - учите Java, чтобы не было многих проблем, да и вообще - собрались моддить - учите Java. Так не только вам спокойнее, но и нам
Чтобы осуществить это делаем так:
StatCollector здесь тоже работает(Он везде работает xD):
EnumChatFormatting тоже работает, показывать не буду, думаю сами сообразите.
Здесь так же работает String.format (С чего бы ему не работать?), NBT. Не забываем, чтобы добавить новую строку - используем \n:
Не забываем, что is, player и bool здесь тоже не зря, ими тоже можно пользоваться при добавлении информации.
Код:
public void addInformation(ItemStack is, EntityPlayer player, List list, boolean bool) {
list.add("text"); //Добавили информацию "text"
}
Код:
public void addInformation(ItemStack is, EntityPlayer player, List list, boolean bool) {
list.add(StatCollector.translateToLocal("modid.text.addInfo")); //Добавили локализируюмую инфу, которая будет локализироваться как "modid.text.addInfo"
}
Здесь так же работает String.format (С чего бы ему не работать?), NBT. Не забываем, чтобы добавить новую строку - используем \n:
Код:
public void addInformation(ItemStack is, EntityPlayer player, List list, boolean bool) {
list.add("Hello, i am first stroke\nHello, i am new stroke"); //Добавили две строки информации, чаще всего лучше добавлять новую строку, чем делать так, чтобы информация не помещалась на экране.
}
Рендерить что-либо можно по-разному, но, чтобы сделать заготовку нам нужен такой код:
Кстати ResourceLocation тоже многим не понятен (Я так заметил).
Как он украшивается?) Вот так:
А можно и так:
Кстати пока не забыл. Рендер OBJ модели, если вы конечно осилите этот OBJ, но вряд ли:
Код:
import org.lwjgl.opengl.GL11;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation;
public class Render* extends TileEntitySpecialRenderer {
private static final ResourceLocation texture = new ResourceLocation("папка до текстуры");
private КлассМодели model;
public Render*() {
model = new КлассМодели();
}
@Override
public void renderTileEntityAt(TileEntity te, double x, double y, double z, float scale) {
GL11.glPushMatrix();
GL11.glTranslatef((float) x + 0.5F, (float) y + 1.5F, (float) z + 0.5F);
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
this.model.render((Entity)null, 0.0F, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F);
GL11.glPopMatrix();
}
}
Как он украшивается?) Вот так:
Код:
public static final ResourceLocation название_переменной = new ResourceLocation("modid:папка"); //В этой штуке папка начинается от assets/modid/
Код:
public static final ResourceLocation название_переменной = new ResourceLocation("modid", "папка"); //В этой штуке папка начинается от assets/modid/
Код:
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.AdvancedModelLoader;
import net.minecraftforge.client.model.IModelCustom;
import org.lwjgl.opengl.GL11;
@SideOnly(Side.CLIENT)
public class Render* extends TileEntitySpecialRenderer
{
public static final ResourceLocation textures = new ResourceLocation("модиди:textures/models/текстура_обжа.png");
public static final IModelCustom model = AdvancedModelLoader.loadModel(new ResourceLocation("модиди:textures/special/models/модель.obj"));
public void doRender(TileEntity p_76986_1_, double p_76986_2_, double p_76986_4_, double p_76986_6_, float p_76986_8_, float p_76986_9_)
{
RenderHelper.disableStandardItemLighting();
GL11.glPushMatrix(); //Начинаем рендер
GL11.glTranslatef((float)p_76986_2_+0.5F, (float)p_76986_4_, (float)p_76986_6_+0.5F);
this.bindTexture(textures); //Привязываем текстуру
model.renderAll(); //Рендерим всё.
GL11.glPopMatrix(); //Завязываем с рендером
RenderHelper.enableStandardItemLighting();
}
/**
* Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture.
*/
protected ResourceLocation getEntityTexture(TileEntity p_110775_1_)
{
return textures;
}
@Override
public void renderTileEntityAt(TileEntity p_147500_1_, double p_147500_2_,
double p_147500_4_, double p_147500_6_, float p_147500_8_) {
if(p_147500_1_.getWorldObj().getBlockMetadata(p_147500_1_.xCoord, p_147500_1_.yCoord, p_147500_1_.zCoord) == 0)
this.doRender((TileEntity) p_147500_1_, p_147500_2_, p_147500_4_, p_147500_6_, p_147500_8_, 0);
}
}
Вообщем как сделать к примеру обнаружение блоков:
Не забываем, цикл тоже работает:
Есть ещё и setBlock. Там всё понятно, делается по принципу getBlock, только не в проверке и с указанием блока в самом методе setBlock.
Кстати о мире... Генерация руд!
Для начала создадим класс WorldGenerationHandler (Называйте как угодно, значения не имеет):
Естественно это сам метод так называется(addOreSpawn), но поверьте - можно добавлять к спауну любой блок.
Код:
if(world.getBlock(x, y, z) == Блок)
//Действие
Код:
for(x = 0; x > 3; x++) //По оси x проходим 3 блока. Тоже самое можно сделать с y и z.
if(world.getBlock(x, y, z) == Блок)
//Действие
while(x > 3)
world.getBlock...;
x++;
Кстати о мире... Генерация руд!
Для начала создадим класс WorldGenerationHandler (Называйте как угодно, значения не имеет):
Код:
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.world.World;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.feature.WorldGenMinable;
import cpw.mods.fml.common.IWorldGenerator;
public class WorldGenerationHandler implements IWorldGenerator {
@Override
public void generate(Random random, int chunkX, int chunkZ, World world, IChunkProvider chunkGenerator, IChunkProvider chunkProvider) {
switch(world.provider.dimensionId) {
case 0 :
generateSurface(world, random, chunkX*16, chunkZ*16);
case -1 :
generateNether(world, random, chunkX*16, chunkZ*16);
case 1 :
generateEnd(world, random, chunkX*16, chunkZ*16);
}
}
private void generateSurface(World world, Random random, int x, int z) {
addOreSpawn(блок, world, random, x, z, int x+*до какого уровня будет генериться руда*, z+*тоже самое, что и с x*, *максимальный размер жилы*, *шанс спауна*, *минимальный y*, *максимальный y*);
}
private void generateNether(World world, Random random, int x, int z) {
//Если вызовет необходимость - пишите
}
private void generateEnd(World world, Random random, int x, int z) {
//ну вы поняли)
}
private void addOreSpawn(Block block, World world, Random random, int blockXPos, int blockZPos, int maxX, int maxZ, int maxVeinSize, int chanceToSpawn, int minY, int maxY) {
for(int i = 0; i < chanceToSpawn; i++) {
int posX = blockXPos + random.nextInt(maxX);
int posY = minY + random.nextInt(maxY - minY);
int posZ = blockZPos + random.nextInt(maxZ);
(new WorldGenMinable(block, maxVeinSize)).generate(world, random, posX, posY, posZ);
}
}
}
Делается он довольно просто, но давайте я покажу:
И да, блок будет поворачиваться
Код:
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.init.Blocks;
import net.minecraft.util.IIcon;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
public class BlockBlockBreaker extends Block {
public IIcon[] blockIcons = new IIcon[2]; //У нас будет 3 разных текстурок для брейкера
public BlockBlockBreaker() {
super(Material.rock);
}
@SideOnly(Side.CLIENT)
public IIcon getIcon(IBlockAccess w, int x, int y, int z, int side)
{
int meta = w.getBlockMetadata(x, y, z);
return side == meta ? blockIcons[1] : blockIcons[0];
}
public IIcon getIcon(int side, int meta)
{
return side == 3 ? blockIcons[1] : blockIcons[0];
}
@Override
@SideOnly(Side.CLIENT)
public void registerBlockIcons(IIconRegister p_149651_1_)
{
this.blockIcons[0] = p_149651_1_.registerIcon("модайди:текстура_не_от_главной_стороны"); //Главная сторона та, которая ломает блоки
this.blockIcons[1] = p_149651_1_.registerIcon("модайди:текстура_от_главной_стороны");
}
public boolean canProvidePower()
{
return true; //Требует энергию
}
public void onNeighborBlockChange(World w, int x, int y, int z, Block n)
{
if(w.isBlockIndirectlyGettingPowered(x, y, z)) //Если блок нашёл откуда-то редстоун сигнал, то он делает следуещее. Можно убрать, если хотите, чтобы брейкер работал вечно
{
ForgeDirection d = ForgeDirection.values()[w.getBlockMetadata(x, y, z)];
Block broken = w.getBlock(x+d.offsetX, y+d.offsetY, z+d.offsetZ);
if(!broken.isAir(w, x+d.offsetX, y+d.offsetY, z+d.offsetZ)) //Если блок не воздух:
{
float hardness = broken.getBlockHardness(w, x+d.offsetX, y+d.offsetY, z+d.offsetZ); //Прочность
if(hardness >= 0 && hardness <= 10) //Проверяет блок на прочность, если он имеет прочность равную от нуля до десяти, то делает следующее:
{
for(int i = 1; i < 13; ++i) //На расстоянии 13 блоков разрушает блоки
{
int dX = x+d.offsetX*i;
int dY = y+d.offsetY*i;
int dZ = z+d.offsetZ*i;
Block b = w.getBlock(dX, dY, dZ);
if(b.getBlockHardness(w, dX, dY, dZ) == hardness)
{
b.breakBlock(w, dX, dY, dZ, b, w.getBlockMetadata(dX, dY, dZ));
b.onBlockDestroyedByPlayer(w, dX, dY, dZ, w.getBlockMetadata(dX, dY, dZ));
b.dropBlockAsItem(w, dX, dY, dZ, w.getBlockMetadata(dX, dY, dZ), 0);
w.setBlock(dX, dY, dZ, Blocks.air, 0, 2);
}else
break;
}
}
}
}
}
@Override
public int onBlockPlaced(World w, int x, int y, int z, int side, float hitX, float hitY, float hitZ, int meta)
{
return ForgeDirection.values()[side].ordinal();
}
}
Предлагайте свои идеи по развитию данной темы, если что-то не понятно или не так объяснил, или не работает - пишите.
Из проблем, которые я решать не буду:
- Создание GUI. Не покажу как это делать, ведь гуи вещь такая, что вы сами выбираете каким он будет, а уж как в этом деле всем угодить - не знаю.
- Анимация модели - делать это легко, можно прочитать гайды в учебнике по OpenGL. Для поворота к примеру можно использовать GL11.glRotate(), но не будем на этом заострять внимание. Просто знайте, что всё это легко сделать, просто надо подумать.
- Работа с JSON (JSON-конфиги к примеру итд). Может дело не новичковое, но всё таки, я сам даже не понимаю хорошо как с ним работать. Только учусь.
- Как создать моба? Может потом сделаю, но для начала проконсультируюсь с одним добрым и няшным человеком, у которого в нике есть цифры 45, ня :З
Так же не пишите в личку по поводу проектов. Просто было у меня уже не раз такое, а так легко я не буду что либо делать (Делать проект за бесплатно, помогать за бесплатно). Исключения - у меня есть всего-лишь один человек, которого я обучаю моддингу, так ещё и бесплатно, но тогда я был добреньким, ня :з
На последок - учите Java, чтобы не было многих проблем, да и вообще - собрались моддить - учите Java. Так не только вам спокойнее, но и нам