Skip to content

Instantly share code, notes, and snippets.

Last active Dec 20, 2020
What would you like to do?
1.8.9 to 1.9 quick primer


Last updated: Wednesday, April 6

This is a quick primer for the cool 1.8.9 kids. Knowledge of 1.8.9 assumed.

  • Notable class remappings:

  • TE Syncing in 1.9.4: Important! See:

  • Registering things (Forge 1819+)

    • The registries have been cleaned up!
    • GameRegistry.register(<object>, <res location>) to register everything
      • Blocks, Items, Potions, PotionTypes, SoundEvents, Enchantments, Biomes, etc.
    • Will all be ID-assigned and synced by FML
    • You can also add your own registries to be managed by FML but I'm not sure on the precise details
    • Instead of GameData.get<X>Registry just use the fields in the class now (Block.blockRegistry, etc.)
    • IMPORTANT: Blocks and their ItemBlock forms are no longer registered together (Which was dumb anyway). Simply register the Item separately by constructing your own ItemBlock and registering it with the same name as the block. A side effect of this is that ItemBlocks are no longer restricted to having a single parameter Block constructor, since you are responsible for constructing it now.
  • Model/rendering changes

    • Block.shouldSideBeRendered has changed: "The given position is now the position of the block itself and no longer the adjacent block as it was in 1.8 or earlier. So people should change code with pos.offset(side)" (McJty)
    • Looks like Block.colorMultiplier and Item.getColorFromItemstack have disappeared...what?!
      • Don't fret, they've just been split out into a separate interface (allowing the same logic to be used for multiple block/item types
      • IBlockColor and IItemColor contain those two old methods.
      • BlockColors and ItemColors are where you register instances of the above interfaces to Block and Item instances.
      • The BlockColors and ItemColors instances can be obtained from Minecraft, and both contain methods to scan all registered Blocks/Items to apply coloring to an unspecified Block or Item.
    • ISmartBlockModel and ISmartItemModel are both gone
      • WHAT? OMG RIOT ༼ つ ◕_◕ ༽つ RIOT ༼ つ ◕_◕ ༽つ
      • oh wait...because vanilla has it now
      • IBakedModel's methods have changed
        • getFaceQuads and getGeneralQuads have been merged into getQuads
        • getQuads is side sensitive (face quads here!) and state sensitive :D
        • Morever, getQuads now returns a List<BakedQuad>. This means you can pass a custom IBakedModel directly into vanilla rendering methods and they will retain their "smartness". (Almost) no more dummy models that return an empty list in getFace/GeneralQuads!
      • So for blocks, just change your implements and do some fixups
      • For items, vanilla has added item overrides
        • IBakedModel returns an ItemOverrideList. If you need full control, a la ISmartItemModel, implement and return a subclass here. ItemOverrideList has the handleItemState you know and love.
        • For situations where you don't need as much control, in your Item construcor, call addPropertyOverride. You pass it first a unique identifier (which will determine how its specified in json), and a IItemPropertyGetter. This is essential a function from (stack, world, player) -> float. This float is then used in json to determine the model. A good example of how to use this is the vanilla ItemBow and bow.json.
        • The above replaces Item.getModel and most usages of ModelLoader.setCustomMeshDefinition. The former has been removed, but the latter is still there, in case you need it.
    • IPerspectiveAwareModel is still there.
    • IFlexibleBakedModel was removed as the vertex format has now been moved to the BakedQuad level. The implications of this are unknown right now.
    • The first person and third person camera transforms have both been split into left and right hand variants. Adjust accordingly.
  • Dual wielding and PlayerInteractEvent

    • Vanilla's interaction trace is really messy
    • The gist is:
      • If you want processing to "continue", return PASS, or false (from boolean methods)
      • If you want processing to "terminate", return SUCCESS, FAIL, or true (from boolean methods).
      • Whenever the client "continue"s, it keeps running other logic and then other hands
      • The server doesn't really "continue" since it does things in packet handlers.
      • Thus, it's safer to terminate early clientside than terminate early serverside and let the client keep going doing other things.
      • In other words, be optimistic on the client (prefer returning SUCCESS and true if you don't want processing to continue to other hands), and be truthful on the server.
    • I've rewritten PlayerInteractEvent to hopefully be a lot clearer and useable, and it's just been pulled into forge. Please help me test it!
  • EntityDataManager (aka DataWatcher)

    • Starting with 1.9, int-based datawatcher ids have been replaced with DataParameters, which can be obtained by calling EntityDataManager#createKey with the target Entity class, and the appropriate DataSerializer, which defines how the data should be serialized to the packet stream.
    • There are a number of pre-defined DataSerializers which can be found in DataSerializers, and additional serializers may be registered using DataSerializers#registerSerializer.
    • Notable method changes:
      • DataWatcher#addObject -> EntityDataManager#register
      • DataWatcher#updateObject -> EntityDataManager#set
      • DataWatcher#getWatchableObject* has been replaced with EntityDataManager#get
    • Check vanilla entities for concrete examples
  • Loot Tables:

    • ChestGenHooks has completely been deprecated, and for very good reason.
    • FishingHooks has also been deprecated.
    • The vanilla loot table system is much more powerful and flexible. In the coming days Forge will evaluate what changes are needed so modders can use it effectively. Read up on the vanilla wiki and the 1.9 code if you want to contribute to the discussion.
    • Some terms follow
    • LootTable: All it does is hold a bunch of LootPools
    • LootPool: Holds multiple LootEntry's. Holds multiple LootCondition's that must all be met for the pool to yield loot. Has fields rolls and bonusRolls to specify how many times the pool is queried
    • LootEntry: A loot entry itself. Can be of subclass empty, an item, or another LootTable entirely. Also holds its own collection of LootCondition's that are checked by the LootPool before querying the entry for items. Item loot entry subclass also has a collection of LootFunction's.
    • LootFunction: Simply put, are functions that transform a stack into another one. These also have LootConditions that must pass for application. Vanilla provides a variety: Enchant randomly, enchant at level, boost drops with looting, set attribute modifiers, set count, set damage, set meta, set NBT tag, and smelt.
    • LootCondition: Conditional check for all the above classes. Is a predicate that takes a Random and a LootContext. Vanilla provides: Entity has LootProperty, Entity has scoreboard score, Entity was killed by player, Random chance, random chance modified by looting.
    • LootProperty: Used solely for the above mentioned LootCondition. Vanilla provides one: Entity on fire.
    • LootContext: Contains the full context of this loot gathering event. Has the world, LootTableManager, looted entity, player involved if any, DamageSource of the killing blow, and luck level of the killer, and a Set<LootTable> to use.
    • The JSON syntax for all of these can be looked up on the vanilla wiki (search "Loot tables")
  • Datafixer:

    • Vanilla way of changing NBT tags on things from an old format to a new one
    • Probably very useful for us mods!
    • Not documented yet
  • Potions:

    • Now has full registry like blocks and items. REMOVE ALL YOUR INT ID'S!!!!!
    • Vanilla potions are now held as static fields in MobEffects instead of in Potion
    • PotionEffect no longer uses int ID's (thank god)
    • PotionType's are added
      • Defined as a list of PotionEffect's
      • Also registered to a registry
      • For example, PotionType minecraft:strong_regeneration is defined as one PotionEffect of Potion regeneration, with amplifier 1 and duration 450 ticks
      • All registered PotionTypes are added to the potion creative tab in normal, splash, and lingering form, as well as in Tipped Arrow form.
        • (Will we get a hook to disable this?)
    • Vanilla's way of defining brewing recipes has completely changed
      • Now in PotionHelper
      • You can register "potion items", items that can provide potion effects
      • You can register conversions between potion items. E.g. Items.potionItem + gunpowder -> Items.splashPotion. All Potion effects are carried across.
      • You can register conversions between potion types. E.g. regeneration + redstone -> long_regeneration. The potion item is retained.
      • As you can see, the logic has been separated!
      • "Conversions" are of type MixPredicate<T>, which in its constructor takes an input <T>, a Predicate<ItemStack> that matches the reagent, and the output <T>
        • NOTE: The implementation of the predicate provided, ItemPredicateInstance, uses -1 as the wildcard meta value instead of Short.MAX_VALUE, which is the value Mojang uses for crafting recipes (and also OreDictionary.WILDCARD_VALUE). goddammit -.-
      • PotionUtils has the whole range of NBT<->Potion interaction utility methods, as well as util methods to generate potion tooltips, etc.
  • Enchantments:

    • Now has full registry like blocks and items. REMOVE ALL YOUR INT ID'S!!!!!
  • Biomes:

    • Now has full registry like blocks and items. REMOVE ALL YOUR INT ID'S!!!!!
    • The weird +128 quirk seems to have been removed [citation needed]. If you know what this means then sigh a sigh of relief :D
  • Misc

    • EntityFX's are no longer real entities to remove the overhead that comes with being one.
Copy link

cpw commented Mar 9, 2016

10/10 would primer again!

Copy link

Wehavecookies56 commented Mar 16, 2016

It seems BlockHelper is now BlockStateMatcher
Edit: BlockHelper is now BlockMatcher and BlockStateHelper is now BlockStateMatcher.

Copy link

McJty commented Mar 24, 2016

Block.shouldSideBeRendered() has changed meaning. The given position is now the position of the block itself and no longer the adjacent block as it was in 1.8 or earlier. So people should change code with pos.offset(side)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment