Minecraft Forge: Converting Your Mod From 1.7.x To 1.8

Introduction


There have been several significant changes to the code base in the move to 1.8.  It is very unlikely that your 1.7.x mod will work without some effort to upgrade.  I will try to do more detailed tutorials on some of these topics, but for now this is a list of things I've found that need conversion that should help you.

I give some general tips on how to upgrade versions in Jabelar's Updating Your Mod tutorial.

My tips list is not complete so you should also check out other 1.8 conversion tutorials such as:


Main Areas Requiring Conversion


Generally, you need to watch out for the following types of changes:
  • The cpw packages have changes, so you need to change your imports.
  • The Block class has been entirely recoded to:
    • use IBlockState instead of metadata,
    • use BlockPos instead of int x, y, z coordinates,
    • use EnumFacing instead of int to represent the side of the block, and
    • use JSON files to map models and textures to blocks based on their state.
  • Items now use JSON files to map models and textures to blocks.
  • Many fields are now accessed by "setter" and "getter" methods rather than directly via public scope. For example, the Entity.attackTarget field is no longer public and must be accessed through setter and getter.
  • Many methods have updated, often similar names.  For example, with axis-aligned bounding boxes the getBoundingBox() method has changed to fromBounds().  Some functions that had good name in 1.7.10 have reverted to the "SRG" name.  For example, isEntityInvulnerable() method is now func_180431_b().
  • The parameters taken by some methods have changed (especially Block methods which now take BlockPos and EnumFacing).  For example, the addArmorMaterial() method has added another string parameter for the texture name. 
  • Vec3 vectors can be instantiated directly without needing a VectorHelper class.
  • More enumerations are used, like EnumFacing.  Also, the enumerated constants now use uppercase so EnumCreatureType.creature becomes EnumCreaterType.CREATURE.


Run Configuration


  • Run Configuration for Eclipse needs to change argument of tweak class to be at net.minecraft.fml instead of cpw.mods.fml.
  • Run Configuration for Eclipse needs to change the asset index to --assetIndex 1.8.

        Example Run Configuration used for client:
    --version 1.8 --tweakClass net.minecraftforge.fml.common.launcher.FMLTweaker 
    --accessToken accessToken --userProperties={} --assetIndex 1.8 
    --assetsDir C:/Users/yourWindowsUserNameHere/.gradle/caches/minecraft/assets 
    --username=<put your username here>


Imports


  • The cpw.mods.fml package has changed to net.minecraft.fml package, so you'll need to go through and update all imports of cpw and update them.  You can either do this with search and replace, or you can delete the cpw imports and have your IDE suggest imports or let it auto-add the imports.

Items


  • Most of the changes involve the new method of referencing models and textures through JSON:
    • Remove any IIcon stuff.
    • Remove the setTexture() calls in the Item constructors.
    • Create the textures JSON file according to Wuppy's tutorial.
    • Register the item renderers in the client proxy init handling method.
    • Warning: When registering items, it is important to use the exact same name as the JSON file so that it can look up textures now.
  • If you extend Item, you'll need to @Override the getSubItems() method otherwise (regardless of whether you setHasSubTypes() to true or false) 16 of the item will appear in the creative tab.  Code like this works:

    @Override
    @SideOnly(Side.CLIENT)
    public void getSubItems(Item parItem, CreativeTabs parTab, 
          List parListSubItems)
    {
        parListSubItems.add(new ItemStack(this, 1));
     }

  • The addArmorMaterial() method has added another string parameter for the texture name.  So you don't have to set texture in the armor class itself -- it will get it from the material.
  • The item EnumRarity now uses uppercase constants so EnumRarity.epic needs to be changed to EnumRarity.EPIC and so forth.
  • onItemUse() has changed to use BlockPos and EnumFacing parameters.

IPlantable Crops


  • The methods have changed to use BlockPos instead of int for x, y, z coordinates.  They also return IBlockState instead of Block.  Update accordingly.
  • The Block.canSustainPlant() now takes BlockPos and EnumFacing.

Blocks:


  • One big area of change is the use of BlockPos and EnumFacing to now hold the x, y, z position and side of the block.  So a lot of methods need to be updated to use those as parameters, such as:
    • isBlockSolid()
    • isSideSolid() 
    • getFlammability()
    • isFireSource() 
    • canPlaceBlockAt() 
    • shouldCheckWeakPower() 
  • Another big area of change is that the block itself and its metadata are now combined into an IBlockState.  So most methods that used metadata or the block need to be updated to use that as a parameter instead of int metadata, methods such as:
    • quantityDropped() 
    • getItemDropped() 
    • isToolEffective() 
    • getHarvestTool() 
    • Custom metadata will need to be converted to block state properties, which can be enumerated.
  • To convert your blocks to use the new system or IBlockState instead of metadata you  need to:
      1. In the custom Block class create a property field , possibly enumerated.  There are three types of property: PropertyBool, PropertyInteger, and PropertyEnum.  For example for a growing plant block you might use: public static final PropertyInteger AGE = PropertyInteger.create("age", 0, 7);
      2. Everywhere you used to set metadata with notify, you just have to update the property within the state.  For example: setDefaultState(blockState.getBaseState().withProperty(AGE, Integer.valueOf(5)));
      3. Everywhere you used to get metadata, you just have to get the value of the property from the state.  For example: blockState.getBaseState().getValue(AGE);
    • Key Point: The World.getBlock() function has changed to World.getBlockState(parPos).getBlock().
    • Furthermore, the block models and textures has been entirely changed to use JSON files. Check out TheGreyGhost's Block Models Tutorial.  Also:
      • Key Point: I recommend the Cubik modeling program as it creates the JSON for you!
      • Remove the setBlockTextureName() as it is no longer used.
      • Warning: When registering blocks, it is important to use the exact same name as the block states JSON so it can look up the textures.
      • Key Point: Basically the idea is that you have to create three JSON files for the block -- in blockstates, models.block and in models.item asset package directories:
        • The block state JSON is used to map the models to the block property values, so the names for the individual models can be anything but need to be listed in the block states JSON.
        • In the block model JSON, the "parent" is what used to be the render type.  You'll need to check out vanilla models to understand all the possible values, but for example "block/cross" is the flower type of rendering.
        • It seems in the block model JSON, the keys under the "texture" need to match up with the parent.  For example, for flower it is "cross" but for flower pot it is "plant".  Need to check out the vanilla models to understand the correct values.
    • Other miscellaneous changes:
      • setBlockName() is now called setUnlocalizedName().
      • isReplaceable() method now uses World parameter instead of IBlockAccess.
      • getDrops() method now uses IBlockAccess, BlockPos and IBlockState as parameters and also the parameters are rearranged so the EntityPlayer parameter is at end.
      • canCreatureSpawn() method now uses BlockPos and EnumCreatureType is changed to SpawnPlacementType.
    • Collision bounding boxes have changed
      • The method is now getCollisionBoundingBox() (not "from pool) and parameters updated to BlockPos and added IBlockState parameter.
      • AxisAlignedBB#getBoundingBox() method has changed to fromBounds().
    • BlockPos provides convenience methods such as offset() and add():
      • BlockPos#offset() works in the direction of the EnumFacing.
      • BlockPos#add() allows you to directly change the x, y, z coordinates.

    Potions:


    Some of the built in potion effects have updated names, or non-obfuscated.  E.g. absorption.

    Entities:


    • EnumCreatureType has changed constants to uppercase, so EnumCreatureType.creature becomes EnumCreatureType.CREATURE.
    • The EnchantmentHelper.getEnchantmentModifierLiving() has changed to func_152377_a() which is structured differently you need to pass the heldItem() into it as parameter.  Check out EntityMob#attackEntityAsMob() method for example.
    • isAIEnabled() is no longer valid.  Need to look at vanilla code to see what the replacement is.
    • The fall() method now takes an additional float and needs to be public.
    • the func_146082_f() method is now called setInLove().
    • attackTarget now must be accessed through setter and getter.
    • isEntityInvulnerable() method is now func_180431_b() and takes DamageSource as parameter.
    • func_110142_aN() is now called getCombatTracker().
    • The EntityPlayer method canPlayerEdit() seems to be func_175151_a().
    • The boundingBox field is now private so you need to use the getter getEntityBoundingBox(). Warning: The similarly named getBoundingBox() only returns null and should not be used.

    Vectors:


    • Vec3 doesn't need a VectorHelper.  Now you can just construct them directly.

    Commands:


    • There is now a function to get the entity directly from the command sender.  ICommandSender.getCommandSenderEntity().

    World


    • The getHeightValue() is no longer available in World, but the Chunk class provides an equivalent getHeight() function, so something like this helper function should be implemented:


        /**
         * Finds the topmost block position at an X, Z position in the world
         * @param parWorld
         * @param parX
         * @param parZ
         * @return
         */
        public static double getHeightValue(World parWorld, double parX, double parZ)
        {
            int intX = MathHelper.floor_double(parX);
            int intZ = MathHelper.floor_double(parZ);
    
         int chunkX = intX >> 4;
         int chunkZ = intZ >> 4;
         double height = parWorld.getChunkFromChunkCoords(chunkX, chunkZ)
           .getHeight(intX & 15, intZ & 15);
         
         return height;
        }
    

    • spawnParticle() has changed to now take an EnumParticleTypes instead of a name string, and takes an extra int array as parameter (most particles just create new int[0]).


    Materials



    • The canBlockGrass() method is no longer valid.  Not sure what the replacement is.
    • The isAdventureModeExempt() method is no longer valid.  Not sure what the replacement is.


    Renderers



    • The RenderLiving constructor now takes a RenderManager parameter, so need to add this to any super constructor calls in extended classes.
    • The Tesselator.instance now needs to be obtained through a getInstance() method.
    • passSpecialRender() is now public so make sure you @Override accordingly.


    Networking



    • Key Point: The networking code now executes on a separate thread. While this is mostly good, it may cause trouble because scheduling of vanilla packets versus custom packets may be different. For example, if you spawn an entity and immediately send a custom packet for that entity, the client may not have received the spawn packet before it gets your custom packet.
    • This forum discussion explains how to better handle the thread difference by making the onMessage() method a scheduled task and therefore thread-safe: TheGreyGhost's 1.8 Networking Threading Tutorial.
    • Tip: So, for custom fields for an entity, to initialize the client side it probably best to use IAdditionalSpawnData instead of a custom packet as otherwise such sync issues can happen.


    Tile Entities


    Here are some changes related to TileEntity class:

    • The updateEntity() method has been replaced through interface.  You need to implement the IUpdatePlayerListBox or ITickable (IUpdatePlayerListBox was moved and renamed to net.minecraft.util.ITickable in 1.8.8/1.8.9.) interface and @Override the update() method instead. 
    • getWorldObj() method is now named getWorld().
    • xCoord, yCoord, and zCoord are no longer available.  Instead use getPos().getX(), etc.
    • hasTileEntity() no longer takes metadata as a parameter

    Axis Aligned Bounding Boxes (AxisAlignedBB):


    Here are some changes related to the AxisAlignedBB class:
    • In 1.8 you can construct an AABB directly, whereas in 1.7.10 you had to call the getBoundingBox() method.

    No comments:

    Post a Comment