[Туториал][1.7.10] Создание аддона для Thaumcraft

19
3
На форуме уже есть урок на эту тему, однако он очень не полный и во многом устарел, этот урок будет по созданию аддонов для Thaumcraft на версию 4.2.3.5
Постепенно буду добавлять новые разделы
Первое где была ошибка в старом уроке, так это в установке
1)Сначала скачиваем API и Dev версию мода по ссылке
0_1852c2_c4f74b35_X5L

2) Все из архива API кидаем в scr/main/java/ (кидаем саму папку thaumcraft) 
3) Dev версию кидаем в eclipse/mods (или где у вас находится папка mods в проекте (если не eclipse))
Потом Нажимаем ПКМ по jar'у, в пункте Build Path выбираем Add to Build Path
Все! На этом этапе уже можно запускать тест мода  и Thaumcraft уже будет там стоять!
4) Добавляем тот же dev jar в libs и даем имя Thaumcraft (ну или Thaumcraft.jar если имя с разрешением), после чего в build.gradle в разделе dependencies пишем строчку 
Код:
compile files('libs/Thaumcraft.jar')
После этого проблем с компиляцией мода быть не должно
Готово! Мы полностью внедрили Thaumcraft в нашу среду!
Таумономиконе[/color]]
Для удобства создадим новый класс, например так:
Код:
public class Thauminicon {


public static final String catName = имя вкладки; //Не обязательно, так и не понял для чего это

public static final ResourceLocation[] backgrounds = new ResourceLocation[]{new ResourceLocation("mod","textures/tauminicon/background.png")}; //фон вкладки, разрешение 512х512 ,ищите сами как ResourceLocation делать, тут уроков 5 на эту тему находил
public static void setup() {
    ResearchCategories.registerCategory((String)имя вкладки , (ResourceLocation)new ResourceLocation("mod","textures/tauminicon/icon.png")/* иконка вкладки 128х128 */, (ResourceLocation)backgrounds[0]);
}
В главном классе пишем это:
Код:
@EventHandler
public void preLoad(FMLPreInitializationEvent event)
 {
  Thauminicon.setup();
}
Все, вкладка создана!
Для тех кто в танке, набалдашник это такая штука которая надевается на жезл, будем разбирать на примере кода из моего аддона, набалдашник дающий эффект лечения и регенерации:
Код:
public class RghlF extends ItemFocusBasic /* Наследование от Thaumcraft Focus */{
public RghlF() {
setCreativeTab(MainClass.cTabs); //добавляем в креатив
}

public IIcon iconOrnament; //Орнамент вокруг набалдашника

@SideOnly(Side.CLIENT)
public void registerIcons(IIconRegister ir) {
this.icon = ir.registerIcon("tutmod:reghF"); //текстура набалдашника
this.iconOrnament = ir.registerIcon("tutmod:reghD"); //текстура орнамента
this.depthIcon = ir.registerIcon("tutmod:reghDI"); //текстура внутри набалдашника
}
public IIcon depthIcon = null; //текстура внутри набалдашника
@SideOnly(Side.CLIENT)
 public IIcon getIconFromDamageForRenderPass(int par1, int renderPass)
 {
   return renderPass == 1 ? this.icon : this.iconOrnament; //установка глубины рендера подробнее ищите на сайте, пересказывать не буду, нужно для орнамента, а  так можно убрать
 }
 
 @SideOnly(Side.CLIENT)
 public boolean requiresMultipleRenderPasses()
 {
   return true; //поддержка нескольких фаз рендера, нужно для орнамента, а так можно убрать
 }
 
 public IIcon getOrnament(ItemStack itemstack)
 {
   return this.iconOrnament; //установка текстуры орнамента, если не нужно - убирайте
 }
 
 public IIcon getFocusDepthLayerIcon(ItemStack itemstack)
 {
   return this.depthIcon; //установка глубинной текстуры (как у гномьего проклятья, червоточены и т д), не нужно - убирайте
 }
public int getFocusColor(ItemStack focusstack) //Обязательно! Это цвет верхней текстуры набалдашника, нельзя убирать, настраивайте через сайты цветовых кодов RGB
 {
int a=255; //прозрачность, бесполезно менять
int r=255; //Красный спектр RGB
int g=255; //зеленый спектр RGB
int b=255; //Синий спектр RGB
   return  a << 24 | r << 16 | g << 8 | b << 0;
 }
public AspectList getVisCost(ItemStack focusstack) //какие аспекты юзает набалдашник
 {
return new AspectList().add(Aspect.EARTH, 2000).add(Aspect.WATER, 2000).add(Aspect.ENTROPY, 100); //одна еденица аспекта это 100, то есть у меня используется за активацию 20 теры, 20 аквы, 1 пердитио, какие есть аспекты ищите в файле thaumcraft/api/aspects/Aspect.java там через ctrl+f вводите название аспекта из игры и смотрите название внутри кода, они не совпадают, так например Sano внутри кода HEAL
 }
 
public int getActivationCooldown(ItemStack focusstack)
 {
   return 3000; //задержка активации, 1000 - это 1 секунда, тут стоит 3 секунды
 }

public ItemStack onFocusRightClick(ItemStack wandstack, World world, EntityPlayer player, MovingObjectPosition movingobjectposition) //активация правой кнопкой
 {
ItemWandCasting wand = (ItemWandCasting)wandstack.getItem();
if (player == null) {
     return wandstack; //проверка на наличие жезла, сложно объяснить, может кто в коментарии объяснит лучше, писать обязательно!
}
if (wand.consumeAllVis(wandstack, player, getVisCost(wandstack), true, false)) //если в жезле есть все нужные аспекты в достаточном количестве
   {
wand.consumeAllVis(wandstack, player, new AspectList().add(Aspect.EARTH, 2000).add(Aspect.WATER, 2000).add(Aspect.ENTROPY, 100), true, false); //снимаем то, что указали выше, можно писать и getVisCost(wandstack), но это не всегда лучше
player.addPotionEffect(new PotionEffect(Potion.regeneration.id, 25,4)); //какие то действия, тут накладывание эффектов регенерации и мгновенного лечения
player.addPotionEffect(new PotionEffect(Potion.heal.id, 1,1));
   }
else return wandstack;
return wandstack;
 
 }
 
 public FocusUpgradeType[] getPossibleUpgradesByRank(ItemStack itemstack, int rank) //прокачка набалдашника
 {
   switch (rank)
   {
   case 1: 
     return new FocusUpgradeType[] { FocusUpgradeType.frugal /* Это на уменьшение затрат*/};
   case 2: 
     return new FocusUpgradeType[] { FocusUpgradeType.frugal};
   case 3: 
     return new FocusUpgradeType[] { FocusUpgradeType.frugal};
   case 4: 
     return new FocusUpgradeType[] { FocusUpgradeType.frugal};
   case 5: 
     return new FocusUpgradeType[] { FocusUpgradeType.frugal};
   }
   return null;
 }
public String getSortingHelper(ItemStack itemstack)
 {
   return "HLRG"; //Имя набалдашника внутри мода, если не указать - не будет отабражаться в меню набалдашников!
 }
}
Вот и все, основные настройки набалдашника есть, теперь разбирем код набалдашника Адское пламя (то которое выпускает летучих мышей) 
Вот его код (я не заменял функции которые зашифровались, так что не удивляйтесь, то, что уже разобрали- пропущу):
Код:
public class ItemFocusHellbat
  extends ItemFocusBasic
{
  public IIcon iconOrnament;
  
  public ItemFocusHellbat()
  {
    func_77637_a(Thaumcraft.tabTC);
  }
  
  public String getSortingHelper(ItemStack itemstack)
  {
    return "HH" + super.getSortingHelper(itemstack);
  }
  
  @SideOnly(Side.CLIENT)
  public void func_94581_a(IIconRegister ir)
  {
    this.icon = ir.func_94245_a("thaumcraft:focus_hellbat");
    this.iconOrnament = ir.func_94245_a("thaumcraft:focus_hellbat_orn");
  }
  
  @SideOnly(Side.CLIENT)
  public IIcon func_77618_c(int par1, int renderPass)
  {
    return renderPass == 1 ? this.icon : this.iconOrnament;
  }
  
  @SideOnly(Side.CLIENT)
  public boolean func_77623_v()
  {
    return true;
  }
  
  public IIcon getOrnament(ItemStack itemstack)
  {
    return this.iconOrnament;
  }
  
  public ItemStack onFocusRightClick(ItemStack itemstack, World world, EntityPlayer player, MovingObjectPosition movingobjectposition)
  {
    ItemWandCasting wand = (ItemWandCasting)itemstack.func_77973_b(); //та же проверка что и выше
    

    Entity pointedEntity = EntityUtils.getPointedEntity(player.field_70170_p, player, 32.0D, EntityFireBat.class); //нужно для спавна летучих мышей
    
    double px = player.field_70165_t;
    double py = player.field_70163_u;
    double pz = player.field_70161_v;
    py = player.field_70121_D.field_72338_b + player.field_70131_O / 2.0F + 0.25D;
    px -= MathHelper.func_76134_b(player.field_70177_z / 180.0F * 3.141593F) * 0.16F;
    py -= 0.05000000014901161D;
    pz -= MathHelper.func_76126_a(player.field_70177_z / 180.0F * 3.141593F) * 0.16F;
    Vec3 vec3d = player.func_70676_i(1.0F);
    px += vec3d.field_72450_a * 0.5D;
    py += vec3d.field_72448_b * 0.5D;
    pz += vec3d.field_72449_c * 0.5D;
    if ((pointedEntity != null) && ((pointedEntity instanceof EntityLivingBase)))
    {
      if (!world.field_72995_K)
      {
        if (((pointedEntity instanceof EntityPlayer)) && (!MinecraftServer.func_71276_C().func_71219_W())) {
          return itemstack;
        }
        EntityFireBat firebat = new EntityFireBat(world);
        firebat.func_70012_b(px, py + firebat.field_70131_O, pz, player.field_70177_z, 0.0F);
        firebat.func_70784_b(pointedEntity);
        firebat.damBonus = wand.getFocusPotency(itemstack);
        firebat.setIsSummoned(true);
        firebat.setIsBatHanging(false);
        if (isUpgradedWith(wand.getFocusItem(itemstack), devilbats)) {
          firebat.setIsDevil(true);
        }
        if (isUpgradedWith(wand.getFocusItem(itemstack), batbombs)) {
          firebat.setIsExplosive(true);
        }
        if (isUpgradedWith(wand.getFocusItem(itemstack), vampirebats))
        {
          firebat.owner = player;
          firebat.setIsVampire(true);
        }
        if ((wand.consumeAllVis(itemstack, player, getVisCost(itemstack), true, false)) && (world.func_72838_d(firebat)))
        {
          world.func_72926_e(2004, (int)px, (int)py, (int)pz, 0);
          world.func_72956_a(firebat, "thaumcraft:ice", 0.2F, 0.95F + world.field_73012_v.nextFloat() * 0.1F);
        }
        else
        {
          world.func_72956_a(player, "thaumcraft:wandfail", 0.1F, 0.8F + world.field_73012_v.nextFloat() * 0.1F);
        }
      }
      player.func_71038_i();
    }
    return itemstack;
  }
  
  public int getFocusColor(ItemStack itemstack)
  {
    return 14431746; //тут цвет - просто цифры, мой метод удобнее
  }
  
  private static final AspectList costBase = new AspectList().add(Aspect.FIRE, 200).add(Aspect.ENTROPY, 100).add(Aspect.AIR, 100);
  private static final AspectList costBomb = new AspectList().add(Aspect.FIRE, 100).add(Aspect.ENTROPY, 200).add(Aspect.AIR, 100);
  private static final AspectList costDevil = new AspectList().add(Aspect.FIRE, 100).add(Aspect.ENTROPY, 100).add(Aspect.AIR, 100).add(Aspect.EARTH, 100); //тут будет несколько вариаций аспектов
  
  public AspectList getVisCost(ItemStack itemstack)
  {
    return isUpgradedWith(itemstack, devilbats) ? costDevil : isUpgradedWith(itemstack, batbombs) ? costBomb : costBase; //[SIZE=3][font=Monaco, Consolas, Courier, monospace]isUpg[/font][/SIZE][SIZE=3][font=Monaco, Consolas, Courier, monospace]radedWith это проверка на то или иное улучшение набалдашника[/font][/SIZE]
  }
  
  public int getActivationCooldown(ItemStack focusstack)
  {
    return 1000;
  }
  
  public FocusUpgradeType[] getPossibleUpgradesByRank(ItemStack itemstack, int rank)
  {
    switch (rank)
    {
    case 1: 
      return new FocusUpgradeType[] { FocusUpgradeType.frugal, FocusUpgradeType.potency };
    case 2: 
      return new FocusUpgradeType[] { FocusUpgradeType.frugal, FocusUpgradeType.potency };
    case 3: 
      return new FocusUpgradeType[] { FocusUpgradeType.frugal, FocusUpgradeType.potency, batbombs, devilbats };
    case 4: 
      return new FocusUpgradeType[] { FocusUpgradeType.frugal, FocusUpgradeType.potency };
    case 5: 
      return new FocusUpgradeType[] { FocusUpgradeType.frugal, FocusUpgradeType.potency, vampirebats };
    }
    return null;
  }
  
  public boolean canApplyUpgrade(ItemStack focusstack, EntityPlayer player, FocusUpgradeType type, int rank) //Может ли игрок прокачать то или иное улучшение
  {
    if ((type.equals(vampirebats)) && (!ThaumcraftApiHelper.isResearchComplete(player.func_70005_c_(), "VAMPBAT"))) /*изучено ли улучшение в тауминиконе? */{
      return false;
    }
    return true;
  }
  
  public static FocusUpgradeType batbombs = new FocusUpgradeType(13, new ResourceLocation("thaumcraft", "textures/foci/batbombs.png"), "focus.upgrade.batbombs.name", "focus.upgrade.batbombs.text", new AspectList().add(Aspect.ENERGY, 1).add(Aspect.TRAP, 1));
//добавление улучшения, [SIZE=3][font=Monaco, Consolas, Courier, monospace]FocusUpgradeType(id улучшения, иконка, название, описание, аспекты)[/font][/SIZE]
public static FocusUpgradeType devilbats = new FocusUpgradeType(14, new ResourceLocation("thaumcraft", "textures/foci/devilbats.png"), "focus.upgrade.devilbats.name", "focus.upgrade.devilbats.text", new AspectList().add(Aspect.ARMOR, 1));
  public static FocusUpgradeType vampirebats = new FocusUpgradeType(19, new ResourceLocation("thaumcraft", "textures/foci/vampirebats.png"), "focus.upgrade.vampirebats.name", "focus.upgrade.vampirebats.text", new AspectList().add(Aspect.HUNGER, 1).add(Aspect.LIFE, 1));
}
Думаю для начала хватит, позже добавлю урок на то, как сделать копию Набалдашника гномье проклятье
Начнем с рецептом и сразу пару моментом разберем без кода (он в конце) Очень важный момент, ключ, который фигурирует и в рецептах и в изучениях является связью между ними, если не изучено изучение которое имеет такой же ключ как и рецепт, то рецепт не заработает, точно так же он не заработает если у него нет ключа или он не к чему не прикреплен, но есть обход - прикреплять к главному изучению Thaumcraft, вот оно: BASICS
Вот теперь поехали
ShapedArcaneRecipe переменная = ThaumcraftApi.addArcaneCraftingRecipe(String ключ,ItemStack предмет на выходе, AspectList() аспекты, new Object[] {рецепт, тут так же как и на обычном верстаке}); //маг. верстак

CrucibleRecipe переменная = ThaumcraftApi.addCrucibleRecipe(String ключ, ItemStack на выходе, ItemStack что кидать, AspectList() аспекты); //тигель, кстати если изучено автоалхимия, то можно неограничего аспектов, например у меня в моде есть рецепт где нужно 256 ордо!

InfusionRecipe переменная = ThaumcraftApi.addInfusionCraftingRecipe(String ключ, ItemStack на выходе, int (1-9) нестабильность, AspectList() аспекты, ItemStack в центре, ItemStack[] все предметы на алтаре (кроме центра));
new ResearchItem(String ключ, String вкладка, AspectList() аспкты, причем кол-во аспктов нужно только для easy mode,int x,int y,int размер области исследования в свитке, ItemStack/ResourceLocation иконка)
.setPages(new ResearchPage[] { new ResearchPage(текст),new ResearchPage(рецепт) можно добавлять и дальше, это просто пример})
.registerResearchItem(); -регестрация нашего изучения, обязательно
P.s если x отрицательный, то будет смещение влево, положительный - вправо, y отрицательный - вверх, положительный - вниз
Изучения поддерживают разные изменения, вот список:
Косметические:
.setSpecial() - шипастая иконка, такие встречаются в центре, я их использую как обозначение направлений изучений

.setRound() - круглая иконка

.setStub() - квадратная иконка

Открытия:
.setAutoUnlock() - автооткрытие, даже если не открыто родительское изучение

.setParents(new String[] {}) -родительские изучения, если в той же вкладке находится, то будет идти линия от них

.setParentsHidden(new String[] {}) - то же самое, что и предыдущая, только линия идти не будет

.setSiblings(new String[] {}) - все, что укажите откроется вместе с этим изучением (после его изучения), как например банки открываются сами после изучения алхимии, значит в алхимии в этом пункте прописанно изучение банок

.setConcealed() -  изучение не отобразится, пока не будет изучено хотя бы одно из его родительских видимых изучений (если нет видимых, то просто родительский изучений)

.setSecondary() - Изучение за аспекты как в easy mode, пример - пустотные банки, иконка будет ромбовой формы

Скрытие изучений:
.setLost() - откроется случайно, пока изучаете что-то таумометром, но может и не открыться!

.SetHidden() - так же как и предыдущее, только может еще открыться за фрагменты знаний!

.setVirtual() - полностью скрытое изучение, открыть (но не показать в исследованиях) можно только через .setSiblings или .setAutoUnlock, в оригинальном тауме используется для разных комбинаций палочек например, нужно для разблокировки рецептов, которые зависят от нескольких изучений

Технические:
 .setPages(ResearchPage[] {}) - установка страниц в тауминиконе, пишется сразу после основной функции

.registerResearchItem() - завершение настройки и добавление на страницу, пишется после всех настроек и после него ставится ;
Все эти дополнения надо писать после .setPages, но до .registerResearchItem()

Все, теперь посмотрим как это объединяется на примере кода, да, все это пишем в такой же функции как наш setup ну или прямо в нем, главное после функций добавления предмета и вкладки! Это код на первые 2 изучения из моего мода
Код:
ShapedArcaneRecipe maincr = ThaumcraftApi.addArcaneCraftingRecipe("SM.MAINEF",new ItemStack(MainClass.mainitem), new AspectList().add(Aspect.AIR, 1).add(Aspect.ORDER, 1).add(Aspect.WATER, 1).add(Aspect.FIRE, 1).add(Aspect.EARTH, 1).add(Aspect.ENTROPY, 1), 
 new Object[] { "DDD", "PEP", "GGG", Character.valueOf('D'), new ItemStack(Items.diamond, 1, 0), Character.valueOf('P'), new ItemStack(ConfigBlocks.blockMagicalLog, 1, 0), Character.valueOf('E'), new ItemStack(Items.ender_pearl, 1, 0), Character.valueOf('G'), new ItemStack(Items.gold_ingot, 1, 0)}); //рецепт "главного" предмета
 
InfusionRecipe foesr = ThaumcraftApi.addInfusionCraftingRecipe("SM.FES", new ItemStack(MainClass.focutESpeed), 1, new AspectList().add(Aspect.AIR, 15).add(Aspect.ORDER, 5).add(Aspect.MAGIC, 10).add(Aspect.MOTION,20),
new ItemStack(MainClass.mainitem), new ItemStack[] {new ItemStack(Items.diamond), new ItemStack(Items.ender_eye), new ItemStack(Items.dye, 1, 4), new ItemStack(Items.ender_eye)});
//наполнение одного из набалдашников



new ResearchItem("SM.MAINEF", "WSLYMAGIC", new AspectList().add(Aspect.AIR, 6).add(Aspect.MAGIC, 3), 0, 0, 1, new ItemStack(MainClass.mainitem, 0 , 0))
 .setPages(new ResearchPage[] { new ResearchPage("tm.res_pg.main.1"),new ResearchPage(maincr)})
.setSpecial()
.setAutoUnlock()
.registerResearchItem(); //начальное изучение, настройки: откроется само, имеет шипастые края, находится в моей вкладке, на страницах будет: на 1- текст, на 2 - рецепт

new ResearchItem("SM.FES", "WSLYMAGIC", new AspectList().add(Aspect.AIR, 7).add(Aspect.ORDER, 7).add(Aspect.MAGIC, 12), 1, -2, 2, new ItemStack(MainClass.focutESpeed, 0 , 0))
.setPages(new ResearchPage[] { new ResearchPage("tm.res_pg.fes.1"),new ResearchPage(foesr)})
.setParents(new String[] {"SM.MAINEF", "INFUSION", "FOCUSFIRE"})
.registerResearchItem(); //изучение набалдашника, имеет родителей- основное изучение мода, набалдашники, наполнение (линия будет только к основному изучению мода т.к другие находятся в других вкладках). Опять же только текст и рецепт, иконка дается через ItemStack, расположение сверху справа, размер сетки в свитке будет средним
Думаю этого хватит для того, что бы сделать первые изучения, остальное найдете в оригинальном тауме
Это довольно просто, просто заместо Items пишите ConfigItems, заместо Blocks ConfigBlocks и т д, а названия смотрите по файлу RU_ru из таума (лично я так делаю), пример: ItemStack(ConfigBlocks.blockMagicalLog,1 ,1) - серебряное дерево
tc.research_category.КАТЕГОРИЯ - название вкладки

focus.upgrade.имя.name - название улучшения для набалдашника

focus.upgrade.regenmust.text - описание улучшения для набалдашника

tc.research_name.КЛЮЧ - имя изучения

tc.research_text.КЛЮЧ - описание изучения

tm.res_pg.изучения.страница - текст, это наиболее удобное обозначение, а так можно давать любое
Пример из моего мода для страницы:
tm.res_pg.main.1 - текст в тауминиконе для главного изучения
В будущем добавлю:
Как добавить аспект
Как добавить зачарование
Как сделать очки откровения

Нашли ошибку? Напишите в коментариях, я постараюсь быстро ее поправить
 
691
1
5
А ты в дождь без головного убора ходишь?


Если да, то как ты ещё от пневмонии не откинулся
 
19
3
Ivasik написал(а):
Откуда украл? Ссылку на источник.

Сам писал, с нуля, поглядывал сюда http://forum.mcmodding.ru/Тема-Разработка-аддона-для-Thaumcraft только в моменте значений некоторых функций, а так можешь по моей истории увидеть, почти все, что в гайде я спрашивал тут так или иначе, правда ответ в итоге находил сам


Ivasik написал(а):
Шляпа какая то, а не "туториал"

поясни, что не так и что поправить, вроде на рубаките часто гайды писал и все норм
 

Icosider

Kotliner
Администратор
3,601
99
664
Тогда не вводи людей в заблуждение, замени сайт на форум.
SLywnow написал(а):
На сайте уже есть урок на эту тему, однако он очень не полный и во многом устарел
Добавь статья которая была раньше и можешь в принципе продолжать, но я не считаю данный "туториал" руководством. Нужно что-то более сложное, чем простые вещи.
 
19
3
Ivasik написал(а):
Нужно что-то более сложное, чем простые вещи.

Что бы эти самые вещи найти ушло прилично времени т.к никто не смог ответить на вопросы, которые поднимаются тут, тем более я понимаю сложные вещи в классическом моддинге (без библиотек), а когда есть какое-то API по которому доков нема подобные темы просто необходимы, да кстати, правки внес
 
7,099
324
1,510
SLywnow написал(а):
Что бы эти самые вещи найти ушло прилично времени т.к никто не смог ответить на вопросы, которые поднимаются тут
В api таумркафта море комментариев на каждый метод
 
19
3
hohserg написал(а):
SLywnow написал(а):
Что бы эти самые вещи найти ушло прилично времени т.к никто не смог ответить на вопросы, которые поднимаются тут
В api таумркафта море комментариев на каждый метод

Но там далеко не все, в тех же набалдашниках и очках откровения пришлось много копаться, т.к там не из API брались функции и методы, а так конечно да
 
5,018
47
783
Код поправь. Мои глаза!!!
 
3,005
192
592
Maxik001 написал(а):
Код поправь. Мои глаза!!!

Если код в 1 строчку, как он будет править его ..  :idea:
 
57
2
0
Если кто-то ответит: у меня проблема при создании набалдашника, в API отсутствует класс ItemWandCasting, использую IntelliJ IDEA. Помогите, пожалуйста.
 
Сверху