[Guide][Для новичков]Решение частозадоваемых вопросов новичков

1,087
2
Привет, я решил, что пора бы уже сделать ГАЙД, в котором решатся многие проблемы новичков при создании мода. Есть конечно тема Skarlet, но в ней устарелая и не совсем приятная "инфа". Опираться иногда будет на другой мой гайд - [Mini-Guide]Локализация чего угодно и как угодно.
Чтобы осуществить это делаем так:
Код:
    public void addInformation(ItemStack is, EntityPlayer player, List list, boolean bool) {
     list.add("text"); //Добавили информацию "text"
    }
StatCollector здесь тоже работает(Он везде работает xD):
Код:
    public void addInformation(ItemStack is, EntityPlayer player, List list, boolean bool) {
     list.add(StatCollector.translateToLocal("modid.text.addInfo")); //Добавили локализируюмую инфу, которая будет локализироваться как "modid.text.addInfo"
    }
EnumChatFormatting тоже работает, показывать не буду, думаю сами сообразите.
Здесь так же работает 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"); //Добавили две строки информации, чаще всего лучше добавлять новую строку, чем делать так, чтобы информация не помещалась на экране.
    }
Не забываем, что is, player и bool здесь тоже не зря, ими тоже можно пользоваться при добавлении информации.
Рендерить что-либо можно по-разному, но, чтобы сделать заготовку нам нужен такой код:
Код:
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();
        }

}
Кстати ResourceLocation тоже многим не понятен (Я так заметил).
Как он украшивается?) Вот так:
Код:
public static final ResourceLocation название_переменной = new ResourceLocation("modid:папка"); //В этой штуке папка начинается от assets/modid/
А можно и так:
Код:
public static final ResourceLocation название_переменной = new ResourceLocation("modid", "папка"); //В этой штуке папка начинается от assets/modid/
Кстати пока не забыл. Рендер OBJ модели, если вы конечно осилите этот OBJ, но вряд ли:
Код:
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);
    }
}
Вообщем как сделать к примеру обнаружение блоков:
Код:
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++;
Есть ещё и setBlock. Там всё понятно, делается по принципу getBlock, только не в проверке и с указанием блока в самом методе setBlock.
Кстати о мире... Генерация руд!
Для начала создадим класс 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);
        }
    }
}
Естественно это сам метод так называется(addOreSpawn), но поверьте - можно добавлять к спауну любой блок.
Делается он довольно просто, но давайте я покажу:
Код:
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. Так не только вам спокойнее, но и нам :)
 
471
5
Может статья и полезная (я в коде не шарю), но с точки зрения оформления пока что 5/10
 
1,087
2
Так скажи, что бы следовало бы добавить, какие комменты к примеру к коду, чтобы новички поняли или ещё что нибудь посоветуй. К примеру мне как не новичку всё понятно, так хоть кто нибудь пусть поможет мне в объяснении (Точнее в том, что надо объяснить, я то не знаю, что можно ещё добавить).
 
2,955
12
Последний булеан в addInformation тру, если включён показ дополнительных свойств предметов (ака F3 + H). С жсончиками ничего сложного нет, но я предпочитаю HOCON.
 
1,137
5
3
Если что, то glPush/Pop это операции со стеком матриц. Push добавляет матрицу, Pop выкидывает её из стека. Рендер начинать с них не всегда обязательно!
 
329
13
FanKar написал(а):
Кстати пока не забыл. Рендер OBJ модели, если вы конечно осилите этот OBJ, но вряд ли:
p_129100_O_ p_130900_T_ p_168500_L_ p_197100_I_ p_130100_C_ p_164300_H_ p_156300_N_ p_198300_I_ p_182700_Y_ p_123700_null_ p_118600_G_ p_105700_A_ p_183100_I_ p_119500_D_ :happy: ! p_134300_V_ p_185100_S_ p_102000_E_ p_169800_null_ p_131100_P_ p_140400_O_ p_185700_N_ p_169300_Y_ p_170300_A_ p_117000_T_ p_172900_N_ p_127000_O_ .
 
1,087
2
Если что, то glPush/Pop это операции со стеком матриц. Push добавляет матрицу, Pop выкидывает её из стека. Рендер начинать с них не всегда обязательно!
Я и не противлюсь.
 
1,976
68
220
TaoGunner написал(а):
p_134300_V_ p_185100_S_ p_102000_E_ p_169800_null_ p_131100_P_ p_140400_O_ p_185700_N_ p_169300_Y_ p_170300_A_ p_117000_T_ p_172900_N_ p_127000_O_ .
В отличии от  твоего сообщения :D
[merge_posts_bbcode]Добавлено: 10.02.2016 09:36:19[/merge_posts_bbcode]

FanKar написал(а):
Предлагайте свои идеи по развитию данной темы
Если бы ты сделал ещё и блок плейсер, цены бы тебе не было (в хорошем смысле) :D

[merge_posts_bbcode]Добавлено: 10.02.2016 09:48:49[/merge_posts_bbcode]

FanKar написал(а):
На расстоянии 13 блоков разрушает блоки
12ти, т.к. у тебя "<13" и int, что значит от  1 до 12 :D
 
1,976
68
220
1rqtxz.jpg
Dragon2488 написал(а):
А нормальный блок плейсер делается на фейк плеерах
 
1,087
2
AlexSocol написал(а):
TaoGunner написал(а):
p_134300_V_ p_185100_S_ p_102000_E_ p_169800_null_ p_131100_P_ p_140400_O_ p_185700_N_ p_169300_Y_ p_170300_A_ p_117000_T_ p_172900_N_ p_127000_O_ .
В отличии от  твоего сообщения :D
[merge_posts_bbcode]Добавлено: 10.02.2016 09:36:19[/merge_posts_bbcode]

FanKar написал(а):
Предлагайте свои идеи по развитию данной темы
Если бы ты сделал ещё и блок плейсер, цены бы тебе не было (в хорошем смысле) :D

[merge_posts_bbcode]Добавлено: 10.02.2016 09:48:49[/merge_posts_bbcode]

FanKar написал(а):
На расстоянии 13 блоков разрушает блоки
12ти, т.к. у тебя "<13" и int, что значит от  1 до 12 :D 
Блин, всегда путаю :D
[merge_posts_bbcode]Добавлено: 10.02.2016 15:17:23[/merge_posts_bbcode]

Dragon2488 написал(а):
А нормальный блок плейсер делается на фейк плеерах 
Чего? Фигня, никаких фейковых игроков не нужно
 
1,137
5
3
Ааа, чтобы отловить эвенты игрока, связанные с блоком?
 
2,955
12
Нет, чувак, нужны. Во-первых, всякие onItemRightClick требуют игрока в аргументы, во-вторых без него никакой совместимости с баккитами и прочим тебе не видать, в третьих даже если ты умудришься запилить без него, получишь 100 багов в подарок.
[merge_posts_bbcode]Added: 11.02.2016 02:24:24[/merge_posts_bbcode]

И делаются эти фейк плееры очень просто, в фордже уже есть их реализация.
 
271
2
0
Я за перенос. Хочешь идеи для развития темы смотри вопросы [font=Verdana, Helvetica, Arial, sans-serif]Nix13Chanel. И мои... ))[/font]
 
Сверху