1.21.1 to 26.1 NeoForge Porting Guide
This site indexes the upstream NeoForge porting primers so you can jump straight to the section that matters.
The upstream chain covered here is:
1.21.1 -> 1.21.2/3 -> 1.21.4 -> 1.21.5 -> 1.21.6 -> 1.21.7 -> 1.21.8 -> 1.21.9 -> 1.21.10 -> 1.21.11 -> 26.1
There is no separate 1.21.3 primer upstream. The 1.21.2 primer covers the 1.21.1 -> 1.21.2/3 step.
How to use this site
If you know what subsystem changed, use the Topic Map below. Every link goes directly to the relevant section.
If the same subsystem changed across multiple versions, see Repeatedly Changing Systems for the reading order.
If you want the raw primers, see Detailed Primers for a full table of contents with anchor links to every section.
If you have a compile error, use the Class and Method Index to find where it changed.
Topic Map
Build, mappings, names, imports, and package moves
- The Rename Shuffle (1.21.11)
- ResourceLocation to Identifier (1.21.11)
- The util Package (1.21.11)
- critereon to criterion (1.21.11)
- Entity and Object Subpackages (1.21.11)
- Java 25 and Deobfuscation (26.1)
- JSpecify Annotations (1.21.11)
- Usage Annotations (1.21.11)
Datagen, packs, registries, tags, codecs, loot, validation, and recipe serialization
- The Holder Set Transition (1.21.2)
- The Ingredient Shift (1.21.2)
- Recipes, now in Registry format (1.21.2)
- Recipe Providers, the ‘not actually’ of Data Providers (1.21.2)
- Instruments, the Datapack Edition (1.21.2)
- Trial Spawner Configurations, now in Datapack Form (1.21.2)
- Critereons, Supplied with HolderGetters (1.21.2 minor)
- Codecable Json Reload Listener (1.21.2 minor)
- Context Keys (1.21.2 minor)
- SimpleJsonResourceReloadListener (1.21.4 minor)
- MetadataSectionSerializer, replaced by Codecs (1.21.4 minor)
- Tags and Parsing (1.21.5)
- Model Rework (1.21.5)
- Registry Context Swapper (1.21.5 minor)
- Timer Callbacks, joining the codec club! (1.21.5 minor)
- Tag Providers: Appender Rewrite (1.21.6)
- Generic Encoding and Decoding: Replacing Direct NBT Access (1.21.6)
- Loot Type Unrolling (26.1)
- Validation Overhaul (26.1)
- Datapack Villager Trades (26.1)
- Serializer Records and Recipe Info (26.1)
- New Tag Providers (26.1 minor)
- Plantable Tags (26.1 minor)
Items, components, equipment, armor, tools, combat, dyes, and consumables
- Equipments and Items, Models and All (1.21.2)
- Armor Materials, Equipment, and Model (Textures) (1.21.2)
- Consumables (1.21.2)
- Interaction Results (1.21.2)
- BlockEntityTypes Privatized! (1.21.2)
- Registry Objcet Id, in the Properties? (1.21.2)
- Properties Changes (1.21.2)
- Fuel Values (1.21.2 minor)
- Mob Replacing Current Items (1.21.4)
- Weapons, Tools, and Armor: Removing the Redundancies (1.21.5)
- Data Component Getters (1.21.5)
- Component Interaction Events (1.21.5 minor)
- Item Owner (1.21.9 minor)
- Container User (1.21.9 minor)
- Slot Sources (1.21.11 minor)
- New Data Components (1.21.11)
- Data Component Initializers (26.1)
- Item Instances and Stack Templates (26.1)
- Dye Component (26.1)
- Data Component Additions (26.1 minor)
Rendering, models, shaders, particles, block models, item models, materials, atlases, and visual pipelines
- Gui Render Types (1.21.2)
- Shader Rewrites (1.21.2)
- Entity Render States (1.21.2)
- Fog Parameters (1.21.2 minor)
- Light Emissions (1.21.2 minor)
- Map Textures (1.21.2 minor)
- Client Items (1.21.4)
- Particles, rendered through Render Types (1.21.4)
- Render Pipeline Rework (1.21.5)
- Model Rework (1.21.5)
- Texture Atlas Reworks (1.21.5 minor)
- GUI Changes (1.21.6)
- Blaze3d Changes (1.21.6)
- Removal of Mob Effects Atlas (1.21.6 minor)
- Animation Baking (1.21.6 minor)
- ChunkSectionLayers (1.21.6 minor)
- Minor Migrations (1.21.7 – GUI render follow-ups)
- Minor Migrations (1.21.8 – GraphicsWorkarounds)
- Feature Submissions: The Movie (1.21.9)
- The Font Glyph Pipeline (1.21.9)
- Client Asset Split (1.21.9 minor)
- Oh Hey, Another Rendering Rewrite (1.21.11)
- Gizmos (1.21.11)
- Even More Rendering Changes (26.1)
- Entity Textures and Adult/Baby Models (26.1 minor)
- Audio Changes (26.1 minor)
Entities, mobs, mob AI, conversions, spawning, and entity data
- Interaction Results (1.21.2)
- EXPLOOOOSSSION! (1.21.2 minor –
Explosionis now an interface) - Mob Conversions (1.21.2 minor –
Mob#convertTochanged) - Minecart Behavior (1.21.2 minor)
- Ender Pearl Chunk Loading (1.21.2 minor)
- Entity References (1.21.5 minor – UUID replaced by
EntityReference) - Leashes (1.21.6 minor)
- Typed Entity Data (1.21.9 minor)
- Name And Id (1.21.9 minor)
- The Removal of interactAt (26.1 minor –
Entity#interactAtremoved) - Activities and Brains (26.1 minor – AI brain system changes)
- More Entity Sound Variant Registries (26.1 minor)
- Zombie Nautilus Variant (1.21.11 minor)
GUI, input, keybinds, debug screens, debug tooling, RPC tooling, and test infrastructure
- Gui Render Types (1.21.2)
- The Game Test Overhaul (1.21.5)
- GUI Changes (1.21.6)
- Minor Migrations (1.21.7)
- The Debugging Overhaul (1.21.9)
- Debug Screens (1.21.9)
- The JSON-RPC Management Servers (1.21.9)
- Input Handling Consolidation (1.21.9)
- Cursor Types (1.21.9 minor)
- Gizmos (1.21.11)
- Text Collectors (1.21.11 minor)
- OptionEnum Removal (1.21.11 minor)
- Container Screen Changes (26.1 minor)
- Input Message Editor Support (26.1 minor)
- Test Environment State Tracking (26.1 minor)
World state, saved data, game rules, timelines, clocks, players, permissions, waypoints, and other server-side systems
- Handling the Removal of Block Entities Properly (1.21.5)
- Voxel Shape Helpers (1.21.5)
- Weighted List Rework (1.21.5)
- Tickets (1.21.5)
- Saved Data, now with Types (1.21.5)
- Block Effect Appliers (1.21.5 minor)
- Waypoints (1.21.6)
- Server Player Changes (1.21.6)
- Permission Sources (1.21.6 minor)
- Level#isClientSide now private (1.21.9)
- Ticket Flags (1.21.9 minor)
- Respawn Data (1.21.9 minor)
- Permission Overhaul (1.21.11)
- The Timeline of Environment Attributes (1.21.11)
- The Game Rule Shuffle (1.21.11)
- Level#random field now protected (26.1)
- World Clocks and Time Markers (26.1)
- Splitting the Primary Level Data into Saved Data (26.1)
- Chat Permissions (26.1 minor)
- ChunkPos, now a record (26.1 minor)
- Cauldron Interaction Dispatchers (26.1 minor)
- Fluid Logic Reorganization (26.1 minor)
- Removal of Random Patch Feature (26.1 minor)
- Rule-Based Block State Providers (26.1 minor)
- File Fixer Upper (26.1 minor)
Remaining minor migrations
- Language File Removals and Renames (1.21.2)
- MacosUtil#IS_MACOS (1.21.2)
- Smarter Framerate Limiting (1.21.2)
- Orientations (1.21.2)
- The Removal of the Carving Generation Step (1.21.2)
- Consecutive Executors (1.21.2)
- Profilers and the Tracy Client (1.21.2)
- Tick Throttler (1.21.2)
- Music, now with Volume Controls (1.21.4)
- Descoping Player Arguments (1.21.5)
- Reload Instance Creation (1.21.5)
- The JOML Backing Interfaces (1.21.5)
- Mob Effects Field Renames (1.21.5)
- Reload Listener Shared State (1.21.9)
- The ‘On Shelf’ Transform (1.21.9)
- Shared Text Areas Debugger (1.21.11)
- Specific Logic Changes (1.21.11)
- Typed Instance (26.1)
- No More Tripwire Pipelines (26.1)
- Environment Attribute Additions (26.1)
- Specific Logic Changes (26.1)
Every primer also contains New Tags, Tag Changes, List of Additions, List of Changes, and List of Removals subsections within their Minor Migrations. For those, go to the full primer pages in Detailed Primers.
Class and Method Index
If you have a compile error or need to find where a specific class/method changed, search this table.
| Class / Method | Version | Section |
|---|---|---|
AbstractFurnaceBlockEntity fuel | 1.21.2 | Fuel Values |
AbstractMinecart | 1.21.2 | Minecart Behavior |
Activities / Brain | 26.1 | Activities and Brains |
AnimationDefinition#bake | 1.21.6 | Animation Baking |
ArmorItem / ArmorMaterial | 1.21.2 | Armor Materials, Equipment, and Model (Textures) |
BakedModel / BakedQuad | 1.21.5 | Model Rework |
BlockBehaviour#neighborChanged | 1.21.2 | Orientations |
BlockEntityType constructors | 1.21.2 | BlockEntityTypes Privatized! |
CauldronInteraction | 26.1 | Cauldron Interaction Dispatchers |
ChunkPos (now record) | 26.1 | ChunkPos, now a record |
ChunkSectionLayer | 1.21.6 | ChunkSectionLayers |
| Client item JSONs | 1.21.4 | Client Items |
Consumable / ConsumableListener | 1.21.2 | Consumables |
DataComponents getters | 1.21.5 | Data Component Getters |
DataComponents new types | 1.21.11 | New Data Components |
DataComponents initializers | 26.1 | Data Component Initializers |
DiggerItem / SwordItem removal | 1.21.5 | Weapons, Tools, and Armor: Removing the Redundancies |
DyeRecipe / DyeItem | 26.1 | Dye Component |
Entity#interactAt removal | 26.1 | The Removal of interactAt |
EntityReference (replaces UUID) | 1.21.5 | Entity References |
EntityRenderState | 1.21.2 | Entity Render States |
Explosion (now interface) | 1.21.2 | EXPLOOOOSSSION! |
GameRules | 1.21.11 | The Game Rule Shuffle |
GameTest framework | 1.21.5 | The Game Test Overhaul |
GenerationStep$Carving removal | 1.21.2 | The Removal of the Carving Generation Step |
GpuTexture / RenderPipeline | 1.21.5 | Render Pipeline Rework |
GuiGraphics / GUI rendering | 1.21.6 | GUI Changes |
Holder / HolderSet / HolderGetter | 1.21.2 | The Holder Set Transition |
Identifier (was ResourceLocation) | 1.21.11 | ResourceLocation to Identifier |
Ingredient | 1.21.2 | The Ingredient Shift |
InteractionResult | 1.21.2 | Interaction Results |
ItemInstance / StackTemplate | 26.1 | Item Instances and Stack Templates |
KeyMapping / input events | 1.21.9 | Input Handling Consolidation |
Leashable | 1.21.6 | Leashes |
Level#isClientSide | 1.21.9 | Level#isClientSide now private |
Level#random | 26.1 | Level#random field now protected |
LootContextParam / LootContextParamSet | 1.21.2 | Context Keys |
LootPoolEntry / loot codecs | 26.1 | Loot Type Unrolling |
Mob#convertTo | 1.21.2 | Mob Conversions |
OptionEnum removal | 1.21.11 | OptionEnum Removal |
Permission / PermissionSet | 1.21.11 | Permission Overhaul |
Profiler#get (replaces getProfiler) | 1.21.2 | Profilers and the Tracy Client |
Recipe registry format | 1.21.2 | Recipes, now in Registry format |
RecipeDisplay / SlotDisplay | 1.21.2 | Recipes, now in Registry format |
RenderType shuffle | 1.21.11 | Oh Hey, Another Rendering Rewrite |
SavedData / SavedDataType | 1.21.5 | Saved Data, now with Types |
ServerExplosion | 1.21.2 | EXPLOOOOSSSION! |
Shader JSON / .vsh / .fsh | 1.21.2 | Shader Rewrites |
SimpleJsonResourceReloadListener | 1.21.4 | SimpleJsonResourceReloadListener |
TagProvider appender | 1.21.6 | Tag Providers: Appender Rewrite |
Validatable / ValidationContext | 26.1 | Validation Overhaul |
| Villager trades (datapack) | 26.1 | Datapack Villager Trades |
VoxelShape helpers | 1.21.5 | Voxel Shape Helpers |
Waypoint system | 1.21.6 | Waypoints |
| World clocks / time markers | 26.1 | World Clocks and Time Markers |
| World data split | 26.1 | Splitting the Primary Level Data into Saved Data |
Source and attribution
The split primer pages are copied from ChampionAsh5357/neoforged-github, branch update/26.1. See Source And Attribution.
Repeatedly Changing Systems
This page is the guard rail for the direct port.
When the same subsystem changed in multiple intermediate versions, do not treat the earliest migration note as final. Use the latest applicable version as the source of truth, but still apply the older chapter first so the intermediate API transitions make sense.
Rendering and graphics
Relevant sections:
- Gui Render Types (1.21.2)
- Shader Rewrites (1.21.2)
- Entity Render States (1.21.2)
- Render Pipeline Rework (1.21.5)
- Model Rework (1.21.5)
- GUI Changes (1.21.6)
- Blaze3d Changes (1.21.6)
- Minor Migrations (1.21.7)
- Feature Submissions: The Movie (1.21.9)
- The Font Glyph Pipeline (1.21.9)
- Oh Hey, Another Rendering Rewrite (1.21.11)
- Even More Rendering Changes (26.1)
How to read them:
1.21.2/3changes GUI blits, shader JSON structure, and render-state assumptions.1.21.5is the first large rendering infrastructure rewrite aroundRenderPipeline,GpuTexture, and render passes.1.21.6changes GUI rendering flow again through prepare/render state separation.1.21.9changes how features are submitted for rendering.1.21.11changes samplers, render types, terrain split, and atlases.26.1is the final authority for block/item rendering, materials, tint sources, fluid models, particle layers, and backend-facing rendering APIs.
Practical rule:
- Treat
26.1as the final rendering target. - Keep
1.21.4client items and1.21.6GUI flow as still-active requirements, not obsolete history.
Item models and item metadata
Relevant sections:
- Client Items (1.21.4)
- Mob Replacing Current Items (1.21.4)
- Particles, rendered through Render Types (1.21.4)
- Weapons, Tools, and Armor: Removing the Redundancies (1.21.5)
- Data Component Getters (1.21.5)
- Feature Submissions: The Movie (1.21.9)
- Oh Hey, Another Rendering Rewrite (1.21.11)
- New Data Components (1.21.11)
- Data Component Initializers (26.1)
- Item Instances and Stack Templates (26.1)
- Dye Component (26.1)
- Even More Rendering Changes (26.1)
What sticks:
1.21.4client items are the baseline for item rendering data.1.21.5removes more hardcoded item-class assumptions in favor of components and equipment data.1.21.9,1.21.11, and26.1further change how items participate in rendering and metadata pipelines.
Practical rule:
- First convert item assets to client items.
- Then port behavior and metadata around components.
- Finally validate them against the
26.1rendering and item-instance model.
Tags, registries, codecs, and validation
Relevant sections:
- The Holder Set Transition (1.21.2)
- Registry Objcet Id, in the Properties? (1.21.2)
- Recipes, now in Registry format (1.21.2)
- Tags and Parsing (1.21.5)
- Tag Providers: Appender Rewrite (1.21.6)
- Generic Encoding and Decoding: Replacing Direct NBT Access (1.21.6)
- The Rename Shuffle (1.21.11)
- Loot Type Unrolling (26.1)
- Validation Overhaul (26.1)
- Serializer Records and Recipe Info (26.1)
What sticks:
1.21.2/3is whereHolderandHolderSetstart affecting large parts of the codebase.1.21.5changes tag access, parser behavior, codec-based reads and writes, and saved-data construction.1.21.6changes tag provider building and nudges more code toward generic encoding and decoding.1.21.11contributes rename churn that affects registry and identifier-facing code.26.1finalizes more codec-driven infrastructure with loot type unrolling and validation overhaul.
Practical rule:
- The earlier chapters tell you how to get onto holder- and codec-based APIs.
26.1is the final target for validation and loot registration shape.
Data components
Relevant sections:
- Consumables (1.21.2)
- Equipments and Items, Models and All (1.21.2)
- The Ingredient Shift (1.21.2)
- Recipes, now in Registry format (1.21.2)
- Weapons, Tools, and Armor: Removing the Redundancies (1.21.5)
- Data Component Getters (1.21.5)
- New Data Components (1.21.11)
- Data Component Initializers (26.1)
- Dye Component (26.1)
What sticks:
1.21.2/3introduces important component-facing migrations such as consumables and recipe-related data moves.1.21.5expands component-centered behavior for tools, armor, weapons, and general data access.1.21.11adds more component types.26.1continues with initializers, dye components, and more component additions.
Practical rule:
- Expect items and recipes to get less class-driven and more component-driven as you move forward.
Saved data and world state
Relevant sections:
- Saved Data, now with Types (1.21.5)
- Splitting the Primary Level Data into Saved Data (26.1)
- World Clocks and Time Markers (26.1)
What sticks:
1.21.5moves saved data toSavedDataType.26.1splits primary level data further into dedicated saved-data objects.
Practical rule:
- Do the
1.21.5migration first, then revisit every level/world persistence assumption again in26.1.
Developer tooling, tests, debugging, and permissions
Relevant sections:
- The Game Test Overhaul (1.21.5)
- The Debugging Overhaul (1.21.9)
- Debug Screens (1.21.9)
- The JSON-RPC Management Servers (1.21.9)
- Permission Overhaul (1.21.11)
- Gizmos (1.21.11)
- Java 25 and Deobfuscation (26.1)
What sticks:
1.21.5overhauls game tests.1.21.9overhauls debugging and management-server shape.1.21.11adds a permission overhaul and gizmo-focused visualization work.26.1adds Java 25 and more minor tooling-facing changes.
Practical rule:
- Port gameplay code first.
- Then re-enable your debug, test, and operator-only tooling against the later chapters.
Detailed Primers
These chapters preserve the upstream primer content step by step. Each section heading links directly to that section within the primer page.
1.21.1 -> 1.21.2/3
- Pack Changes
- The Holder Set Transition
- Gui Render Types
- Shader Rewrites
- Entity Render States
- Equipments and Items, Models and All
- Armor Materials, Equipment, and Model (Textures)
- Interaction Results
- Instruments, the Datapack Edition
- Trial Spawner Configurations, now in Datapack Form
- Recipe Providers, the ‘not actually’ of Data Providers
- The Ingredient Shift
- BlockEntityTypes Privatized!
- Consumables
- Registry Objcet Id, in the Properties?
- Properties Changes
- Recipes, now in Registry format
- Minor Migrations
1.21.2/3 -> 1.21.4
- Pack Changes
- Client Items
- Mob Replacing Current Items
- Particles, rendered through Render Types
- Minor Migrations
1.21.4 -> 1.21.5
- Pack Changes
- Handling the Removal of Block Entities Properly
- Voxel Shape Helpers
- Weapons, Tools, and Armor: Removing the Redundancies
- Weighted List Rework
- Tickets
- The Game Test Overhaul
- Data Component Getters
- Tags and Parsing
- Saved Data, now with Types
- Render Pipeline Rework
- Model Rework
- Minor Migrations
1.21.5 -> 1.21.6
- Pack Changes
- GUI Changes
- Waypoints
- Blaze3d Changes
- Tag Providers: Appender Rewrite
- Generic Encoding and Decoding: Replacing Direct NBT Access
- Server Player Changes
- Minor Migrations
1.21.6 -> 1.21.7
1.21.7 -> 1.21.8
1.21.8 -> 1.21.9
- Pack Changes
- The Debugging Overhaul
- Debug Screens
- Feature Submissions: The Movie
- The Font Glyph Pipeline
- The JSON-RPC Management Servers
- Input Handling Consolidation
Level#isClientSidenow private- Minor Migrations
1.21.9 -> 1.21.10
1.21.10 -> 1.21.11
- Pack Changes
- The Rename Shuffle
- Oh Hey, Another Rendering Rewrite
- Gizmos
- Permission Overhaul
- New Data Components
- The Timeline of Environment Attributes
- The Game Rule Shuffle
- Minor Migrations
1.21.11 -> 26.1
- Pack Changes
- Java 25 and Deobfuscation
- Loot Type Unrolling
- Validation Overhaul
- Datapack Villager Trades
Level#randomfield now protected- Data Component Initializers
- Item Instances and Stack Templates
- Serializer Records and Recipe Info
- Dye Component
- World Clocks and Time Markers
- Splitting the Primary Level Data into Saved Data
- Even More Rendering Changes
- Minor Migrations
Minecraft 1.21.1 -> 1.21.2 Mod Migration Primer
This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.1 to 1.21.2. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.
This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.
If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.
Pack Changes
There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.
The Holder Set Transition
Many of the methods that used TagKeys or raw registry objects have been replaced with the direct HolderSet object. A HolderSet is essentially a list of registry object references that can be dynamically updated and managed as needed by the game. There are effectively two kinds of HolderSets: direct and named. Named HolderSets are the object representation of tags in game. It’s called a named set as the HolderSet is referenced by the tag’s name. Direct HolderSets, on the other hand, are created by HolderSet#direct, which functions as an inlined list of values. These are useful when a separate object doesn’t need to be defined to construct some value.
For a JSON example:
// HolderSet#direct with one element
{
"holder_set": "minecraft:apple"
}
// HolderSet#direct with multiple elements
{
"holder_set": [
"minecraft:apple",
"minecraft:stick"
]
}
// HolderSet reference (tags)
{
"holder_set": "#minecraft:planks"
}
Generally, you should never be constructing holder sets incode except during provider generation. Each set type has a different method of construction.
First, to even deal with Holders or HolderSets, you will need access to the static registry instance via Registry or the datapack registry via HolderGetter. The HolderGetter is either obtained from a BootstrapContext#lookup during datapack registry generation or HolderLookup$Provider#lookupOrThrow either as part of generation or MinecraftServer#registryAccess during gameplay.
Once that is available, for direct HolderSets, you will need to get the Holder form of a registry object. For static registries, this is done through Registry#wrapAsHolder. For datapack registries, this is done through HolderGetter#getOrThrow.
// Direct holder set for Items
HolderSet<Item> items = HolderSet.direct(BuiltInRegistries.ITEM.wrapAsHolder(Items.APPLE));
// Direct holder set for configured features
// Assume we have access to the HolderGetter<ConfiguredFeature<?, ?>> registry
Holderset<ConfiguredFeature<?, ?>> features = HolderSet.direct(registry.getOrThrow(OreFeatures.ORE_IRON));
For named HolderSets, the process is similar. For both static and dynamic registries, you call HolderGetter#getOrThrow.
// Named holder set for Items
HolderSet<Item> items = BuiltInRegistries.ITEM.getOrThrow(ItemTags.PLANKS);
// Named holder set for biomes
// Assume we have access to the HolderGetter<Biome> registry
Holderset<Biome> biomes = registry.getOrThrow(BiomeTags.IS_OCEAN);
As these changes are permeated throughout the entire codebase, they will be listed in more relevant subsections.
Gui Render Types
Gui rendering methods within GuiGraphics now take in a Function<ResourceLocation, RenderType> to determine how to render the image. Also, blit methods now require the size of the PNG to be specified.
// For some GuiGraphics graphics
graphics.blit(
// How to render the texture
RenderType::guiTextured,
// The previous texture parameters
...,
// The size of the PNG to use
256, 256);
This means methods that provided helpers towards setting the texture or other properties that could be specified within a shader have been removed.
com.mojang.blaze3d.pipeline.RenderTarget#blitToScreen(int, int, boolean)->blitAndBlendToScreennet.minecraft.client.gui.GuiGraphicsdrawManagedis removedsetColoris removed - Now a parameter within theblitandblitSpritemethodsblit(int, int, int, int, int, TextureAtlasSprite, *)is removedbufferSource->drawSpecial, not one-to-one as this takes in a consumer of theMultiBufferSourceand ends the current batch instead of just returning theMultiBufferSource
net.minecraft.client.gui.components.PlayerFaceRenderer- All
drawmethods exceptdraw(GuiGraphics, PlayerSkin, int, int, int)takes in an additionalintthat defines the color
- All
net.minecraft.client.renderer.RenderType-guiTexturedOverlay- Gets the render type for an image overlayed onto the game screen. -guiOpaqueTexturedBackground- Gets the render type for a GUI texture applied to the background of a menu. -guiNauseaOverlay- Gets the render type for the nausea overlay. -guiTextured- Gets the render type for an image within a GUI menu.net.minecraft.client.resources.metadata.gui.GuiSpriteScaling$NineSlicenow takes in a boolean representing whether the center portion of the texture should be streched to fit the size
Shader Rewrites
The internals of shaders have been rewritten quite a bit.
Shaders Files
The main changes are the defined samplers and post shaders.
The DiffuseSampler and DiffuseDepthSampler have been given new names depending on the target to apply: InSampler, MainSampler, and MainDepthSampler. InSampler is used in everything but the transparency program shader.
// In some shader JSON
{
"samplers": [
{ "name": "MainSampler" },
// ...
]
}
Within post effect shaders, they have been changed completely. For a full breakdown of the changes, see PostChainConfig, but in general, all targets are now keys to objects, all pass inputs and filters are now lists of sampler inputs. As for how this looks:
// Old post effect shader JSON
// In assets/<namespace>/shaders/post
{
"targets": [
"swap"
],
"passes": [
{
"name": "invert",
"intarget": "minecraft:main",
"outtarget": "swap",
"use_linear_filter": true,
"uniforms": [
{
"name": "InverseAmount",
"values": [ 0.8 ]
}
]
},
{
"name": "blit",
"intarget": "swap",
"outtarget": "minecraft:main"
}
]
}
// New post effect JSON
// In assets/<namespace>/post_effect
{
"targets": {
"swap": {} // Swap is now a target object (fullscreen unless otherwise specified)
},
"passes": [
{
// Name of the program to apply (previously 'name')
// assets/minecraft/shaders/post/invert.json
"program": "minecraft:post/invert",
// Inputs is now a list
"inputs": [
{
// Targets the InSampler
// Sampler must be available in the program shader JSON
"sampler_name": "In",
// Reading from the main screen (previously 'intarget')
"target": "minecraft:main",
// Use GL_LINEAR (previously 'use_linear_filter')
"bilinear": true
}
],
// Writes to the swap target (previously 'outtarget')
"output": "swap",
"uniforms": [
{
"name": "InverseAmount",
"values": [ 0.8 ]
}
]
},
{
"program": "minecraft:post/blit",
"inputs": [
{
"sampler_name": "In",
"target": "swap"
}
],
"output": "minecraft:main"
}
]
}
Shader Programs
All shaders, regardless of where they are used (as part of a program or post effect), have a JSON within assets/<namespace>/shaders. This JSON defines everything the shader will use, as defined by ShaderProgramConfig. The main addition is the change to ResourceLocation relative references, and adding the defines header dynamically during load time.
// For some assets/my_mod/shaders/my_shader.json
{
// Points to assets/my_mod/shaders/my_shader.vsh (previously 'my_shader', without id specification)
"vertex": "my_mod:my_shader",
// Points to assets/my_mod/shaders/my_shader.fsh (previously 'my_shader', without id specification)
"fragment": "my_mod:my_shader",
// Adds '#define' headers to the shaders
"defines": {
// #define <key> <value>
"values": {
"ALPHA_CUTOUT": "0.1"
},
// #define flag
"flags": [
"NO_OVERLAY"
]
},
// A list of sampler uniforms to use in the shader
// There are 12 texture sampler uniforms Sampler0-Sampler11, though usually only Sampler0 is supplied
// Additionally, there are dynamic '*Sampler' for post effect shaders which are bound to read the specified targets or 'minecraft:main'
"samplers": [
{ "name": "Sampler0" }
],
// A list of uniforms that can be accessed within the shader
// A list of available uniforms can be found in CompiledShaderProgram#setUniforms
"uniforms": [
{ "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
{ "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
{ "name": "ModelOffset", "type": "float", "count": 3, "values": [ 0.0, 0.0, 0.0 ] },
{ "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] }
]
}
// For some assets/my_mod/shaders/my_shader.vsh (Vertex Shader)
// GLSL Version
#version 150
// Imports Mojang GLSL files
// Located in assets/<namespace>/shaders/include/<path>
#moj_import <minecraft:light.glsl>
// Defines are injected (can use 'ALPHA_CUTOUT' and 'NO_OVERLAY')
// Defined by the VertexFormat passed into the ShaderProgram below
in vec3 Position; // vec3 float
in vec4 Color; // vec4 unsigned byte (0-255)
// Samplers defined by the JSON
uniform sampler2D Sampler0;
// Uniforms provided by the JSON
uniform mat4 ModelViewMat;
uniform mat4 ProjMat;
uniform vec3 ModelOffset;
// Values to output to the fragment shader
out float vertexDistance;
out vec4 vertexColor;
out vec2 texCoord0;
void main() {
// Out values should be set here
}
// For some assets/my_mod/shaders/my_shader.fsh (Fragment Shader)
// GLSL Version
#version 150
// Imports Mojang GLSL files
// Located in assets/<namespace>/shaders/include/<path>
#moj_import <minecraft:fog.glsl>
// Defines are injected (can use 'ALPHA_CUTOUT' and 'NO_OVERLAY')
// Defined by the output of the vertex shader above
in float vertexDistance;
in vec4 vertexColor;
in vec2 texCoord0;
// Samplers defined by the JSON
uniform sampler2D Sampler0;
// Uniforms provided by the JSON
uniform vec4 ColorModulator;
// Values to output to the framebuffer (the color of the pixel)
out vec4 fragColor;
void main() {
// Out values should be set here
}
On the code side, shaders are stored internally as either a ShaderProgram or a CompiledShaderProgram. ShaderProgram represents the identifier, while the CompiledShaderProgram represents the shader itself to run. Both are linked together through the ShaderManager.
Shader programs are compiled dynamically unless specified as a core shader. This is done by registering the ShaderProgram to CoreShaders#PROGRAMS.
// List<ShaderProgram> PROGRAMS access
ShaderProgram MY_SHADER = new ShaderProgram(
// Points to assets/my_mod/shaders/my_shader.json
ResourceLocation.fromNamespaceAndPath('my_mod', 'my_shader'),
// Passed in vertex format used by the shader
DefaultVertexFormat.POSITION_COLOR,
// Lists the '#define' values and flags
// Value: '#define <key> <value>'
// Flag: '#define <flag>'
ShaderDefines.EMPTY
)
The shader programs are then set by calling RenderSystem#setShader with the ShaderProgram in question. In fact, all references to GameRenderer#get*Shader should be replaced with a ShaderProgram reference.
// In some rendering method
RenderSystem.setShader(MY_SHADER);
// Creating a new ShaderStateShard for a RenderType
ShaderStateShard MY_SHARD = new ShaderStateShard(MY_SHADER);
com.mojang.blaze3d.ProjectionType- An enum which holds the logic for how a projection matrix should be rendered.com.mojang.blaze3d.buffersBufferType- An enum that specifies the GL target buffer type.GpuBuffer- A wrapper around the GL buffer calls for handling the rendering of the screen.GpuFence- A handle for managing the sync status of the GPU fence.
com.mojang.blaze3d.platform.GlStateManagerglShaderSourcenow takes in aStringrather than aList<String>_glMapBufferRange- Delegates toGL30#glMapBufferRange._glFenceSync- Delegates toGL32#glFenceSync._glClientWaitSync- Delegates toGL32#glClientWaitSync._glDeleteSync- Delegates toGL32#glDeleteSync._glBuffserSubData- Delegates toGL15#glBufferSubData.
com.mojang.blaze3d.preprocessor.GlslPreprocessor#injectDefines- Injects any defined sources to the top of a loaded.*shfile.com.mojang.blaze3d.shadersBlendMode,Effect,EffectProgram,Program,ProgramManager,Shaderhas been bundled intoCompiledShaderUnformno longer takes in aShaderglGetAttribLocationis removedglBindAttribLocation->VertexFormat#bindAttributessetFromConfig- Sets the uniform parameters given the values and count of another uniform configuration.
com.mojang.blaze3d.systems.RenderSystemsetShadernow takes in theCompiledShaderProgram, orShaderProgramclearShader- Clears the current system shader.runAsFancyis removed, handled internally byLevelRenderer#getTransparencyChainsetProjectionMatrixnow takes in aProjectionTypethan just theVertexSortinggetVertexSorting->getProjectionType; not one-to-one, but theVertexSortingis accessible on theProjectionType
com.mojang.blaze3d.vertex.VertexBufferdrawWithShaderwill now noop when passing in a nullCompiledShaderProgram$Usage->com.mojang.blaze3d.buffers.BufferUsage
net.minecraft.client.Minecraft#getShaderManager- Returns the manager that loads all the shaders and post effects.net.minecract.client.rendererEffectInstanceclass is removed, replaced byCompiledShaderProgramin most casesGameRendererget*Shader->CoreShaders#*shutdownEffect->clearPostEffectcreateReloadListener->ShaderManagercurrentEffect->currentPostEffect
ItemBlockRenderTypes#getRenderTypeno longer takes in a boolean indicating whether to use the translucent render typeShaderInstance->CompiledShaderProgramCHUNK_OFFSET->MODEL_OFFSET- JSON shaders:
ChunkOffset->ModelOffset
- JSON shaders:
getUniformConfig- Returns the configuration of a uniform given its name.
LevelRenderer#graphicsChangedis removed, handled internally byLevelRenderer#getTransparencyChainPostChainConfig- A configuration that represents how a post effect shader JSON is constructed.PostPassnow takes in theResourceLocationrepresenting the output target instead of the in and outRenderTargets or thebooleanfilter mode, theCompiledShaderProgramto use instead of theResourceProvider, and a list of uniforms for the shader to consume- No longer
AutoCloseable addToFrameno longer takes in thefloattimegetEffect->getShaderaddAuxAsset->addInputprocess->addToFrame$Input- Represents an input of the post effect shader.$TargetInput- An input from aRenderTarget.$TextureInput- An input from a texture.
- No longer
PostChainconstructor is now created viaload- No longer
AutoCloseable MAIN_RENDER_TARGETis now publicgetNameis removed, replaced withShaderProgram#configIdprocessno longer takes in theDeltaTracker$TargetBundle- Handles the getting and replacement of resource handles within the chain.
- No longer
RenderTypeentityTranslucentCull,entityGlintDirectis removedarmorTranslucent- A render type which renders armor that can have a translucent texture.
ShaderDefines- The defined values and flags used by the shader as constants.ShaderManager- The resource listener that loads the shaders.ShaderProgram- An identifier for a shader.ShaderProgramConfig- The definition of the program shader JSON.Sheets#translucentCullBlockSheetis removedSkyRenderernow implementsAutoCloseable
net.minecraft.client.renderer.entity.ItemRenderergetFoilBufferDirectis removed, replaced bygetFoilBufferITEM_COUNT_BLIT_OFFSET->ITEM_DECORATION_BLIT_OFFSET
Entity Render States
Entity models and renderers have been more or less completely reworked due to the addition of EntityRenderStates. EntityRenderStates are essentially data object classes that only expose the computed information necessary to render the Entity. For example, a Llama does not need to know what is has in its inventory, just that it has a chest to render in the layer.
To start, you need to choose an EntityRenderState to use, or create one using a subclass if you need additional information passed to the renderer. The most common states to subclass is either EntityRenderState or LivingEntityRenderState for living entities. These fields should be mutable, as the state class is created only once for a renderer.
// Assuming MyEntity extends LivingEntity
public class MyEntityRenderState extends LivingEntityRenderState {
// An example of a field
boolean hasExampleData;
}
From there, you create the EntityModel that will render your Entity. The EntityModel has a generic that takes in the EntityRenderState along with taking in the ModelPart root, and optionally the RenderType factory as part of its super. The are no methods to implement by default; however, if you need to setup any kind of model movement, you will need to overrride setupAnim which modifies the ModelPart’s mutable fields using the render state. If your model does not have any animation, then a Model$Simple implementation can be used instead. This does not need anything implemented.
public class MyEntityModel extends EntityModel<MyEntityRenderState> {
public MyEntityModel(ModelPart root) {
super(root);
// ...
}
@Override
public void setupAnim(MyEntityRenderState state) {
// Calls resetPose and whatever other transformations done by superclasses
super.setupAnim(state);
// Perform transformations to model parts here
}
}
EntityModel also has three final methods from the Model subclass: root, which grabs the root ModelPart; allParts, which returns a list of all ModelParts flattened; and resetPose, which returns the ModelPart to their default state.
LayerDefinitions, MeshDefinitions, PartDefinitions, and CubeDeformations remain unchanged in their implementation and construction for the ModelLayerLocation -> LayerDefinition map in LayerDefinitions.
What about model transformations? For example, having a baby version of the entity, or where the model switches out altogether? In those cases, a separate layer definition is registered for each. For example, a Llama would have a model layer for the main Llama model, the baby model, the decor for both the adult and baby, and finally one for the spit. Since models are generally similar to one another with only a slight transformation, a new method was added to LayerDefinition to take in a MeshTransformer. MeshTransformers are basically unary operators on the MeshDefinition. For baby models, a BabyModelTransform mesh transformer is provided, which can be applied via LayerDefinition#apply.
public class MyEntityModel extends EntityModel<MyEntityRenderState> {
public static final MeshTransformer BABY_TRANSFORMS = ...;
public static LayerDefinition create() {
// ...
}
}
// Wherever the model layers are registered
ModelLayerLocation MY_ENTITY = layers.register("examplemod:my_entity");
ModelLayerLocation MY_ENTITY_BABY = layers.register("examplemod:my_entity_baby");
// Wherever the layer definitions are registered
defns.register(MY_ENTITY, MyEntityModel.create());
defns.register(MY_ENTITY_BABY, MyEntityModel.create().apply(MyEntityModel.BABY_TRANSFORMS));
But how does the model know what render state to use? That’s where the EntityRenderer comes in. The EntityRenderer has two generics: the type of the Entity, and the type of the EntityRenderState. The EntityRenderer takes in a Context object, similar to before. Additionally, getTextureLocation needs to be implemented, though this time it takes in the render state instead of the entity. The new methods to implement/override are createRenderState and extractRenderState. createRenderState constructs the default render state object. extractRenderState, meanwhile, populates the render state for the current entity being rendered. extractRenderState will need to be overridden if you are not using an existing render state class.
Of course, there are also subclasses of the EntityRenderer. First, there is LivingEntityRenderer. This has an additional generic of the EntityModel being rendered, and takes that value in the constructor along with the shadow radius. This renderer also accepts RenderLayers, which largely remain unchanged if you access the previous arguments through the render state. Then, there is the MobRenderer, which is what all entities extend. Finally, there is AgeableMobRenderer, which takes in two models - the adult and the baby - and decides which to render dependent on LivingEntityRenderState#isBaby. AgeableMobRenderer should be used with BabyModelTransform if the entity has a baby form. Otherwise, you will most likely use MobRenderer or EntityRenderer.
public class MyEntityRenderer extends AgeableMobRenderer<MyEntity, MyEntityRenderState, MyEntityModel> {
public MyEntityRenderer(EntityRendererProvider.Context ctx) {
super(
ctx,
new MyEntityModel(ctx.bakeLayer(MY_ENTITY)), // Adult model
new MyEntityModel(ctx.bakeLayer(MY_ENTITY_BABY)), // Baby model
0.7f // Shadow radius
);
// ...
}
@Override
public ResourceLocation getTextureLocation(MyEntityRenderState state) {
// Return entity texture here
}
@Override
public MyEntityRenderState createRenderState() {
// Constructs the reusable state
return new MyEntityRenderState();
}
@Override
public void extractRenderState(MyEntity entity, MyEntityRenderState state, float partialTick) {
// Sets the living entity and entity render state info
super.extractRenderState(entity, state, partialTick);
// Set our own variables
state.hasExampleData = entity.hasExampleData();
}
}
// Wherever the entity renderers are registered
renderers.register(MyEntityTypes.MY_ENTITY, MyEntityRenderer::new);
net.minecraft.client.modelAbstractBoatModel- A model that assumes there is aleft_paddleandright_paddlethat is animated according to the boat’s rowing time.AgeableHierarchicalModel,ColorableAgeableListModel,AgeableListModel->BabyModelTransformAnimationUtilsanimateCrossbowChargenow takes in afloatrepresenting the charge duration andintrepresenting the use ticks instead of aLivingEntityswingWeaponDownnow takes in aHumanoidArminstead of aMob
BabyModelTransform- A mesh transformer that applies a baby scaled form of the model.BoatModelcreatePartsBuilderis removedcreateChildren->addCommonParts, now privatecreateBodyModel->createBoatModel,createChestBoatModelwaterPatch->createWaterPatchpartsis removed
ChestBoatModel->BoatModel#createChestBoatModelChestedHorseModelclass is removed and now purely lives inLlamaModelandDonkeyModelChestRaftModel->RaftModel#createChestRaftModelColorableHierarchicalModelis now stored in the individualEntityRenderStateEntityModel- The generic now takes in a
EntityRenderState setupAnimonly takes in theEntityRenderStategenericprepareMobModelis removedcopyPropertiesTois removed, still exists inHumanoidModel
- The generic now takes in a
HierarchicalModelclass is removedHumanoidModel#rotLerpRad->Mth#rotLerpRadListModelclass is removedModelrenderToBufferis now finalroot- Returns the rootModelPart.getAnyDescendantWithName- Returns the first descendant of the root that has the specified name.animate- Give the current state and definition of the aninmation, transforms the model between the current time and the maximum time to play the animation for.animateWalk- Animates the walking cycle of the model.applyStatic- Applies an immediate animation to the specified state.$Simple- Constructs a simple model that has no additional animation.
ModelUtilsclass is removedParrotModel#getState->getPose, now publicPlayerModelno longer has a genericrenderEars->PlayerEarsModelrenderCape->PlayerCapeModelgetRandomModelPart->getRandomBodyPartgetArmPose- Returns the arm pose of the player given its render state.
RaftModel#createBodyModel->createRaftModelWardenModel#getTendrilsLayerModelParts,getHeartLayerModelParts,getBioluminescentLayerModelParts,getPulsatingSpotsLayerModelPartsnow take in theWardenRenderStateWaterPatchModel->BoatModel#createWaterPatchandModel$Simple
net.minecraft.client.model.geomModelLayerLocationis now a recordModelLayerscreateRaftModelName,createChestRaftModelNameis removedcreateSignModelName->createStandingSignModelName,createWallSignModelNamecreateBoatModelName,createChestBoatModelNameis removed
ModelPartrotateBy- Rotates the part using the givenQuaternionf.$Cube#polygons,$Polygon,$Vertexis now public
PartPoseis now a recordtranslated- Translates a pose.withScale,scaled- Scales a pose.
net.minecraft.client.model.geom.buildersLayerDefinition#apply- Applies a mesh transformer to the definition and returns a new one.MeshDefinition#transformed- Applies a transformation to the root pose and returns a new one.MeshTransformer- Transforms an existingMeshDefinitioninto a given form.PartDefinitionaddOrReplaceChildnow has an overload that takes in aPartDefinitionclearChild- Removes the child from the part definition.getChildren- Gets all the children of the current part.transformed- Applies a transformation to the current pose and returns a new one.
net.minecraft.client.renderer.entityAbstractBoatRenderer- A boat renderer that contains methods for the boat model and any additions to the boat itself.AgeableMobRenderer- A mob renderer that takes in the baby and adult model.BoatRenderernow takes in aModelLayerLocationinstead of abooleanEntityRenderDispatchernow takes in aMapRendererrenderno longer takes in the entity Y rotation
EntityRenderernow takes in a generic for theEntityRenderStategetRenderOffsetonly takes in theEntityRenderStategetBoundingBoxForCulling- Returns the bounding box of the entity to determine whether to cull or not.affectedByCulling- Returns whether the entity can be culled.renderonly takes in the render state, along with the stack, buffer source, and packet lightshouldShowNamenow takes in adoublefor the camera squared distance from the entitygetTextureLocationis removed, being moved to the classes where it is used, likeLivingEntityRenderer- Subsequent implementations of
getTextureLocationmay be protected or private
- Subsequent implementations of
renderNameTagnow takes in the render state instead of the entity and removes the partial tickfloatgetNameTag- Gets the name tag from the entity.getShadowRadiusnow takes in the render state instead of the entitycreateRenderState- Creates the render state object.extractRenderState- Reads any data from the entity to the render state.
EntityRendererProvider$Contexttakes in theMapRendererinstead of theItemInHandRendererLivingRendererisShakingnow takes in the render state instead of the entitysetupRotationsnow takes in the render state instead of the entitygetAttackAnim,getBobare now within the render stategetFlipDegreesno longer takes in the entitygetWhiteOverlayProgressnow takes in the render state instead of the entity and no longer takes in the entity Y rotationscalenow takes in the render state instead of the entity and no longer takes in the entity Y rotationshouldShowNamenow takes in adoublerepresenting the squared distance to the cameragetShadowRadiusnow takes in the render state instead of the entity
RaftRenderer- A raft renderer that implements theAbstractBoatRenderer.RenderLayerParent#getTextureLocationis removed
net.minecraft.client.renderer.entity.layersEnergySwirlLayer#isPowered- Returns whether the energy is powered.CustomHeadLayerand#translateToHeadtakes in aCustomHeadLayer$Transformsinstead of a scaling information hardcoding the transformPlayerItemInHandRenderertakes in anItemRendererinstead of aItemInHandRendererRenderLayertakes in anEntityRenderStategeneric instead of anEntitygenericcoloredCutoutModelCopyLayerRendertakes in a singleEntityModelwith the state info bundled into the render staterenderColoredCutoutModeltakes in non-generic forms of the rendering information, assuming aLivingEntityRenderStategetTextureLocationis removed, instead being passed directly into the appropriate locationrendernow takes in the render state instead of the entity and parameter information
SaddleLayerhas a constructor to take in a baby model.SheepFurLayer->SheepWoolLayerStuckInBodyLayernow takes in the model to apply the stuck objects to, the texture of the stuck objects, and the placement style of the objectsnumStucknow takes in the render state instead of the entityrenderStuckItemis now private
WardenEmissiveLayer->LivingEntityEmissiveLayer, a more generalized implementation
net.minecraft.client.renderer.entity.player.PlayerRendererrenderRightHand,renderLeftHandnow take in aResourceLocationinstead of theAbstractClientPlayerand abooleanwhether to render the left and/or right sleevesetupRotationsnow takes in the render state instead of the entity and parameter information
net.minecraft.world.entityAnimationState#copyFrom- Copies the animation state from another state.EntitynoCulling->EntityRenderer#affectedByCullinggetBoundingBoxForCulling->EntityRenderer#getBoundingBoxForCulling
LerpingModelclass is removedPowerableMobclass is removed
Model Baking
UnbakedModels now have a different method to resolve any dependencies. Instead of getting the dependencies and resolving the parents, this is now done through a single method called resolveDependencies. This method takes in the Resolver. The Resolver is responsible for getting the UnbakedModel for the ResourceLocation.
// For some UnbakedModel instance
public class MyUnbakedModel implements UnbakedModel {
@Nullable
protected ResourceLocation parentLocation;
@Nullable
protected UnbakedModel parent;
private final List<ItemOverride> overrides;
// ...
@Override
public void resolveDependencies(UnbakedModel.Resolver resolver) {
// Get parent model for delegate resolution
if (this.parentLocation != null) {
this.parent = resolver.resolve(this.parentLocation);
}
}
}
net.minecraft.client.renderer.blockBlockModel#getDependencies,resolveParents->resolveDependenciesBlockModelDefintionnow takes in aMultiPart$Definition, noList<BlockModelDefinition>constructor existsfromStream,fromJsonElementno longer take in a$ContextgetVariantsis removedisMultiPartis removedinstantiate->MultiPart$Definition#instantiate
MultiVariantis now a recordUnbakedBlockStateModel- An interface that represents a block state model, contains a single method to group states together with the same model.VariantSelector- A utility for constructing the state definitions from the model descriptor.
net.minecraft.client.renderer.block.modelBlockModelMISSING_MATERIAL- The material of the missing block texture.bakeno longer takes in theModelBakerandBlockModel$LoopExceptionclass is removed
net.minecraft.client.renderer.block.model.multipart.MultiPartnow implementsUnbakedBlockStateModelgetSelectors->$Definition#selectorsgetMultiVariants->$Definition#getMultiVariants
net.minecraft.client.resources.modelBakedModel#getOverrides->overrides, method is defaulted to an empty overrideBlockStateModelLoaderonly takes in the missing unbaked modelloadAllBlockStatesis removeddefinitionLocationToBlockMapper- Gets the state definition from a given resource locationloadBlockStateDefinitions->loadBlockStateDefinitionStackgetModelGroups->ModelGroupCollector$LoadedJson->$LoadedBlockModelDefinition$LoadedModelis now public$LoadedModels- A record which maps a model location to a loaded model.
BuiltInModelno longer takes in theItemOverridesDelegateBakedModel- A utility implementation that delegates all logic to the suppliedBakedModelMaterial#buffertakes in anotherbooleanthat handles whether to apply the glintMissingBlockModel- The missing model for a block.ModelBaker#getModelis removed, implementation inModelBakery$ModelBakerImplis privateModelBakeryonly takes in the top models, all unbacked models, and the missing modelBUILTIN_SLASH->SpecialModels#builtinModelIdBUILTIN_SLASH_GENERATED->SpecialModels#BUILTIN_GENERATEDBUILTIN_BLOCK_ENTITY->SpecialModels#BUILTIN_BLOCK_ENTITYMISSING_MODEL_LOCATION->MissingBlockModel#LOCATIONMISSING_MODEL_VARIANT->MissingBlockModel#VARIANTGENERATION_MARKER->SpecialModels#GENERATED_MARKERBLOCK_ENTITY_MARKER->SpecialModels#BLOCK_ENTITY_MARKERgetModelGroups->ModelGroupCollector
ModelDiscovery- A loader for block and item models, such as how to resolve them when reading.ModelGroupCollector- A blockstate collector meant to map states to their associated block models.ModelResourceLocation#vanillais removedMultiPartBakedModelfields are now obtained from the first model in the selector and are private$Builderclass is removed, replaced with$Selector
SimpleBakedModel,SimpleBakedModel$Builderno longer takes in theItemOverridesSpecialModels- A utility for builtin models.UnbakedModelgetDependencies,resolveParents->resolveDependenciesbakeis no longer nullable$Resolver- Determines how the unbaked model should be loaded when on top or on override.
WeightedBakedModelnow takes in aSimpleWeightedRandomListrather than a list ofWeightedEntrys
Equipments and Items, Models and All
Equipments and Items have had a major overhaul, most of which is spread throughout this documentation. This is some of the core change which, while they are important, do not deserve more than a cursory explanation due to their ease of change.
Item Names and Models
The item name and model is now set directly within the properties using the ITEM_NAME and ITEM_MODEL data components, respectively. By default, this will use the same name and model location as previously, but these can be set via Item$Properties#overrideDescription and #overrideModel. overrideDescription takes in the translation key to use. There is also useBlockDescriptionPrefix and useItemDescriptionPrefix to change it to the default block and item translation keys, respectively. overrideModel takes in the relative ResourceLocation of the model JSON. For example, a value of examplemod:example_item will map to a ModelResourceLocation of examplemod:example_item#inventory. This is intended to link to the model JSON at assets/examplemod/models/item/example_item.json.
There is a slight quirk to item models. The same key can also point to
assets/examplemod/models/example_item.jsonif the modder decides to for a special model to load at that location under theinventoryvariant. So, it is recommended to avoid having model names with the same name in the rootmodelsandmodels/itemsubdirectory.
Enchantable, Repairable Items
The enchantment value and repair item checks are being replaced with data components: DataComponents#ENCHANTABLE and DataComponents#REPAIRABLE, respectively. These can be set via the Item$Properties#enchantable and #repairable. As a result, Item#getEnchantmentValue and isValidRepairItem are removed.
Elytras -> Gliders
Any item can act similarly to an elytra if they have the DataComponents#GLIDER value equipped. This essentially functions as a flag to indicate that the item can be used to glide. This works only if the item also has a DataComponents#EQUIPPABLE entry.
new Item(
new Item.Properties()
.component(DataComponents.GLIDER, Unit.INSTANCE) // Sets as a glider
.component(DataComponents.EQUIPPABLE, /*...*/) // Determines the slot to check whether it can be used
);
Tools, via Tool Materials
Tiers within items have been replaced with ToolMaterial, which better handles the creation of tools and swords without having to implement each method manually. ToolMaterial takes in the same arguments as Tier, just as parameters to a single constructor rather than as implementable methods. From there, the ToolMaterial is passed to the DiggerItem subtypes, along with two floats representing the attack damage and attack speed. Interally, ToolMaterial#apply*Properties is called, which applies the ToolMaterial info to the DataComponents#TOOL and the attributes from the given floats.
// Some tool material
public static final ToolMaterial WOOD = new ToolMaterial(
BlockTags.INCORRECT_FOR_WOODEN_TOOL, // Tier#getIncorrectBlocksForDrops
59, // Tier#getUses
2.0F, // Tier#getSpeed
0.0F, // Tier#getAttackDamageBonus
15, // Tier#getEnchantmentValue
ItemTags.WOODEN_TOOL_MATERIALS // Tier#getRepairIngredient
);
// When constructing the digger item subtype
new PickaxeItem(
WOOD, // Tool material
1.0f, // Attack damage
-2.8f, // Attack speed
new Item.Properties()
)
Armor Materials, Equipment, and Model (Textures)
This is, by far, the largest change outside of consumables to items. ArmorMaterials have effectively been made obsolete, as almost all of the logic is handled within data components, and attached to some resource pack JSON to load the associated textures. It is annoyingly complicated to understand at first glance, but is rather intuitive once you are familiar with the process.
ArmorMaterial
ArmorMaterial is essentially a record that converts a list of properties to their proper location on the data components, NOT a registry object. This is done by passing in the item properties and an additional setting to either #humanoidProperties or #animalProperties. These settings should be familiar, as they remained unchanged from the previous version, the only difference is that they now specify a ‘model id’, which we will go into below. The armor material is used in conjunction with the ArmorType: an enum which defines the equipment slot the armor is placed into, the unit durability of each armor type, and the name (which is only used to construcct the attribute modifier id).
ArmorMaterial exampleArmorMaterial = new ArmorMaterial(
15, // The scalar durability to multiply the armor type against
// A map of ArmorType -> half armor bars to apply to the entity ARMOR attribute
// Should be set for all ArmorTypes
Util.make(new EnumMap<>(ArmorType.class), map -> {
map.put(ArmorType.BOOTS, 2);
map.put(ArmorType.LEGGINGS, 5);
map.put(ArmorType.CHESTPLATE, 6);
map.put(ArmorType.HELMET, 2);
map.put(ArmorType.BODY, 5);
},
25, // The enchantment value of the armor
SoundEvents.ARMOR_EQUIP_IRON, // The holder wrapped sound event on what sound to make when the item is equipped
0f, // The ARMOR_TOUGHNESS attribute value
2f, // The KNOCKBACK_RESISTANCE attribute value,
ItemTags.REPAIRS_DIAMOND_ARMOR, // An item tag representing the items that can repair this armor
// The relative location of the EquipmentModel JSON
// Points to assets/examplemod/models/equipment/example_armor_material.json
ResourceLocation.fromNamespaceAndPath("examplemod", "example_armor_material")
)
With the ArmorMaterial, this is either applied to the item properties by calling humanoidProperties, to apply the armor to a specific ArmorType; or animalProperties to apply the armor to the BODY and only allow specific entities to wear them.
Does this mean that ArmorItem and AnimalArmorItem are effectively pointless? For AnimalArmorItem, this can be argued. The only thing that AnimalArmorItem does is have a $BodyType parameter, which means that the armor can only be applied to a horse or a wolf, and specifies the item breaking sound. ArmorItem, on the other hand, only has one specific usecase: determining whether the item can be taken off or swapped. This implicity checks the currently wearing armor item to see whether it can’t be taken off (via PREVENT_ARMOR_CHANGE enchantment) and calculating the properties on the replacing armor material so that any hotswaps will only improve their wearer’s armor attribute values.
Let’s go one level deeper.
The Data Components
ArmorMaterial specifies eight data components to apply to item:
MAX_DAMAGE- Set to the maximum durability of the item multiplied by theArmorTypeunit durabilityMAX_STACK_SIZE- Set to 1DAMAGE- Set to 0ATTRIBUTE_MODIFIERS- SetsARMORandARMOR_TOUGHNESSattributes, andKNOCKBACK_RESISTANCEwhen greater than 0ENCHANTABLE- Set to the enchantment value (not set when callinganimalProperties)REPAIRABLE- Set to theHolderSetof the tag key representing the repairing ingredientsEQUIPPABLE- Sets the slot, equip sound, model id, what entities can wear the item, and whether it is dispensible
Everything but EQUIPPABLE has already been explained above or has been around from a prior version, so this primer will only focus on EQUIPPABLE from now on.
Equippable
Equippable, which used to be an interface, is now a data component that contains how an entity can equip this item and if the equipment should be rendered. Because of this, an item can only be equipped to a single slot. This can be done using the Equippable constructor or through the builder via Equippable#builder.
new Item(
new Item.Properties()
.component(DataComponents.EQUIPPABLE, new Equippable(
EquipmentSlot.HEAD, // The slot the item can be equipped to
SoundEvents.ARMOR_EQUIP_IRON, // The sound to play when equipping the item
// The relative location of the EquipmentModel JSON
// Points to assets/examplemod/models/equipment/example_armor_material.json
// When set to an empty optional, the item does not attempt to render as equipment
Optional.of(ResourceLocation.fromNamespaceAndPath("examplemod", "example_armor_material")),
// The relative location over the texture to overlay on the player screen when wearing
// Points to assets/examplemod/textures/example_overlay.png
// When set to an empty optional, does not render on the player screen
Optional.of(ResourceLocation.withDefaultNamespace("examplemod", "example_overlay")),
// A HolderSet of entities (direct or tag) that can equip this item
// When set to an empty optional, any entity can equip this item
Optional.of(HolderSet.direct(EntityType::builtInRegistryHolder, EntityType.ZOMBIE)),
// Whether the item can be equipped when dispensed from a dispenser
true,
// Whether the item can be swapped off the player during a quick equip
false,
// Whether the item should be damaged when attacked (for equipment typically)
// Must also be a damageable item
false
))
);
Equipment Models?
So, as mentioned previously, Equippable items, and by extension the ArmorMaterial delegate, can specify a model id to determine how the equipment should render. However, what does this id link to? Well, it points to an EquipmentModel serialized as a JSON within models/equipment of the resource pack. This JSON defines the layers and textures of the equippable item to render. This does NOT specify the model, making the record a misnomer. It is better to think of this as the equipment textures applied to the passed in model.
EquipmentModel functions as a more feature generic version of the previous ArmorMaterial$Layer, which has been removed. Each EquipmentModel is functionally a map of $LayerTypes to a list of $Layer to render.
A $LayerType is an enum representing the layer to render the equipment model as. While these are non-specific, they are implemented and read by specific entity renderer through the layer renderers. For example, HUMANOID is used by the HumanoidArmorLayer to render the head, chest, and feet; so any usage of HUMANOID will be rendered using that system. Another example is WOLF_BODY is used by WolfArmorLayer to render the body armor. As such, if using existing layer types (which is the only scenario unless your mod loader supports enum extensions), make sure that they are compatible with the existing renderers in place.
The $Layer list specifies the texture and dyeable options to use when rendering over the passed in model. The first parameter specifes the texture location, relative to textures/entity/equipment. The second parameter specifies an optional indicating whether the texture can be tinted (stored via the ItemTags#DYEABLE in conjunction with the DYED_COLOR data component). When specified, an optional color can be specified for when the item is not dyed. If empty, the armor will be invisible when not dyed. The final parameter indicates whether it should use the texture provided to the renderer instead, such as when rendering a custom elytra texture for the player.
// In assets/examplemod/models/equipment/example_armor_material.json
{
// The layer map
"layers": {
// The serialized name of the EquipmentModel$LayerType to apply to
"humanoid": [
// A list of layers to render in the order provided in the list
{
// The relative texture of the layer
// Points to assets/examplemod/textures/entity/equipment/example.png
"texture": "examplemod:example",
// When specified, allows the texture to be tinted the color in DYED_COLOR data component
// Otherwise, cannot be tinted
"dyeable": {
// An RGB value (always opaque color)
// 0x7683DE as decimal
// When not specified, set to 0 (meaning transparent or invisible)
"color_when_undyed": 7767006
},
// When true, uses the texture passed into the layer renderer instead
"use_player_texture": true
}
// ...
]
// ...
}
}
EquipmentModel.builder()
.addLayers(EquipmentModel.LayerType.HUMANOID, new EquipmentModel.Layer(
// The relative texture of the layer
// Points to assets/examplemod/textures/entity/equipment/example.png
ResourceLocation.fromNamespaceAndPath("examplemod", "example"),
// When specified, allows the texture to be tinted the color in DYED_COLOR data component
// Otherwise, cannot be tinted
Optional.of(new EquipmentModel.Dyeable(
// An RGB value (always opaque color)
// When not specified, set to 0 (meaning transparent or invisible)
Optional.of(0x7683DE)
)),
// When true, uses the texture passed into the layer renderer instead
true
)/*, ... */)
.build();
The equipment model is then rendered by calling EquipmentLayerRenderer#renderLayers in the render function of an EntityRenderer or RenderLayer. EquipementLayerRenderer is passed in as part of the render context via EntityRendererProvider$Context#getEquipmentRenderer.
// In some render method where EquipmentLayerRenderer equipmentLayerRenderer is a field
this.equipmentLayerRenderer.renderLayers(
// The layer type to render
EquipmentModel.LayerType.HUMANOID,
// The model id representing the EquipmentModel JSON
// This would be set in the `EQUIPPABLE` data component via `model`
ResourceLocation.fromNamespaceAndPath("examplemod", "example_armor_material"),
// The model to apply the textures to
// These are usually separate models from the entity model
// and are separate ModelLayers linking to a LayerDefinition
model,
// The item stack representing the item being rendered as a model
// This is only used to get the dyeable, foil, and armor trim information
stack,
// The stack used to render the model in the correct location
poseStack,
// The source of the buffers to get the vertex consumer of the render type
bufferSource,
// The packed light texture
lighting,
// An absolute path of the texture to render when use_player_texture is true for one of the layer if not null
ResourceLocation.fromNamespaceAndPath("examplemod", "textures/other_texture.png");
)
Technical Changes to Items
net.minecraft.client.Minecraft#getEquipmentModels- Gets theEquipmentModelSetthat contains the current equipment model textures.net.minecraft.client.gui.GuiGraphics#renderTooltip,renderComponentTooltipnow has a parameter to take in the relative directory of the background and frame textures of the tooltip, or the default ifnullnet.minecraft.client.gui.screens.inventory.tooltip.TooltipRenderUtil#renderTooltipBackgroundnow has a parameter to take in the relative directory of the background and frame textures of the tooltip, or the default ifnullnet.minecraft.client.renderer.block.modelItemOverrides->BakedOverrides- The construct no longer takes in the parent
BlockModel resolve->findOverride, does not take in the fallback model
- The construct no longer takes in the parent
ItemOverride,ItemOverride$Predicateis now a recordgetPredicatesis removed, usepredicatesgetModel->model
net.minecraft.client.renderer.entityEntityRenderDispatchernow takes in theEquipmentModelSetEntityRendererProvider$ContextgetEquipmentModels- Gets the current equipment textures.getEquipmentRenderer- Gets the renderer for the equipment.
ItemRendererno longer takes in theMinecraftinstance andTextureManagerTRIDENT_MODEL,SPYGLASS_MODELis now publicTRIDENT_IN_HAND_MODEL,SPYGLASS_IN_HAND_MODELis removedgetItemModelShaperis removedrenderBundleWithSelectedItem->renderBundleItem, not one-to-one
net.minecraft.client.renderer.entity.layersCapeLayernow takes in theEquipmentModelSetElytraLayer->WingsLayer- The constructor now takes in the
EquipmentLayerRenderer
- The constructor now takes in the
EquipmentLayerRenderer- A renderer for equipment layers on the provided model.HorseArmorLayernow takes in theEquipmentLayerRendererHumanoidArmorLayernow teaks in theEquipmentLayerRendererinstead of theModelManagershouldRender- Returns whether the equippable item should be rendered in the given slot.
LlamaDecorLayernow takes in theEquipmentLayerRendererWolfArmorLayernow takes in theEquipmentLayerRenderer
net.minecraft.client.renderer.entity.player.PlayerRenderer#getArmPoseis now private, replaced publically with a method that only takes in theHumanoidArmandPlayerRenderStatenet.minecraft.client.resources.modelEquipmentModelSet- A resource listener that loads theEquipmentModels frommodels/equipment.ItemModel- A model for an item.
net.minecraft.core.component.DataComponentsITEM_MODEL- Returns the model of the item. Theitem/is stripped, meaning thatminecraft:applepoints tominecraft/textures/models/item/apple.json.EQUIPPABLE- Indicates that an item is equippable in the given slot. Also contains the model to render for the equipment.GLIDER- Indicates that an item can be used to glide across the air. Must also be used in conjunction withEQUIPPABLE.TOOLTIP_STYLE- Determines the relative location representing how the tooltip should render
net.minecraft.core.dispenser.EquipmentDispenseItemBehavior- Handles how equipment is dispensed from a dispenser.net.minecraft.core.registries.BuiltInRegistries#,Registries#ARMOR_MATERIALis no longer a registry, handled purely through data componentsnet.minecraft.world.entityEquipmentSlot#getFilterFlag->getId- Also a method
getFilterBitfor converting the ID to a bit mask
- Also a method
LivingEntitycanContinueToGlide->canGlide, no longer takes in theItemStackcanTakeItemreplaced byDataComponents#EQUIPPABLEcanEquipWithDispenser- Returns whether the stack can be equipped when spat from a dispenser.canDispenserEquipIntoSlot- An entity override that specifies whether a dispenser can put eequipment into a given slot.isEquippableInSlot- Returns whether the stack can be equipped in the given slot.canGlideUsing- Whether the entity can glide with the stack in the provided slot.
MobcanReplaceCurrentItemnow takes in theEquipmentSlotisBodyArmorItemreplaced byDataComponents#EQUIPPABLE
net.minecraft.world.entity.animal.horseHorse#isBodyArmorItemreplaced byDataComponents#EQUIPPABLELlama#isBodyArmorItem,getSwagreplaced byDataComponents#EQUIPPABLE
net.minecraft.world.itemAnimalArmorItemno longer extendsArmorItem- The constructor no longer takes in a boolean indicating the overlay texture, as that is now part of the
EquipmentModel - The constructor can take in an optional
Holder<SoundEvent>of the equip sound - The constructor can take in a
booleanrepresenting whether the armor should be damaged if the entity is hurt $BodyTypeno takes in the allowed entities to wear the armor rather than the path factory to the texture
- The constructor no longer takes in a boolean indicating the overlay texture, as that is now part of the
ArmorItemis no longer equipable- Basically functions as an item class where its only remaining usage is to prevent armor change when enchanted and get the associated attributes
$Type->ArmorType
ArmorMaterial->.equipment.ArmorMaterial- Bascially a dummy record to easily handle applying the associated data components (
MAX_DAMAGE,ATTRIBUTE_MODIFIERS,ENCHANTABLE,EQUIPPABLE,REPAIRABLE)
- Bascially a dummy record to easily handle applying the associated data components (
ArmorMaterials->.equipment.ArmorMaterialsBookItem,EnchantedBookItem->DataComponents#WRITTEN_BOOK_CONTENTBundleItemnow takes in aResourceLocationfor the model rather than just strings$Mutable#setSelectedItem->toggleSelectedItem
ComplexItemclass is removedElytraItemclass is removed, now just and item withDataComponents#GLIDEREquippable->.equipment.Equippable, now a record which defines how an item can be equippedFoodOnAStackItemparameter order has been switchedInstrumentItemparameter order has been switchedItemdescriptionIdis now protectedgetDescription->getNamegetOrCreateDescriptionIdis removedgetDescriptionId(ItemStack)->DataComponents#ITEM_NAMEisEnchantable,getEnchantmentValueis removedisValidRepairItemis removedgetDefaultAttributeModifiersis removedgetDamageSource- Returns the damage source this item makes against theLivingEntityisComplexis removed$Propertiesequippable- Sets an equippable component, defining how an item can be equippedequippableUnswappable- Sets an equippable commponent that cannot be swapped via a key shortcut.overrideDescription- Sets the translation key of the item.overrideModel- Sets the model resource location.
getCraftingRemainingItem,hasCraftingRemainingItem->getCraftingRemainder
ItemNameBlockItemclass is removed, just a normalItemuseItemDescriptionPrefixas a propertyItemStackITEM_NON_AIR_CODEC->Item#CODECisValidRepairItem- Returns whether the stack can be repaired by this stack.nextDamageWillBreak- Checks if the next damage taken with break the item.getDescriptionId->getItemName, not one-to-one, as now it returns the full component
ShieldItemno longer implementsEquippable, passed in throughDataComponents#EQUIPPABLESignItemparameter order has been switchedSmithingTemplateItemparameter order has been swtiched, removesFeatureFlagsStandingAndWallBlockItemparamter order has been switchedAxeItemnow takes in two floats representing the attack damage and attack speedDiggerItemnow takes in two floats representing the attack damage and attack speedcreateAttributes->ToolMaterial#applyToolProperties
HoeItemnow takes in two floats representing the attack damage and attack speedPickaxeItemnow takes in two floats representing the attack damage and attack speedShovelItemnow takes in two floats representing the attack damage and attack speedSwordItemnow takes in two floats representing the attack damage and attack speedcreateAttributes->ToolMaterial#applySwordProperties
Tier->ToolMaterialTieredItemclass is removedTiersconstants are stored onToolMaterial
net.minecraft.world.item.alchemy.Potionname is now required -getName->name, not one-to-one as this is stored directly on the potion without any other processingnet.minecraft.world.item.armortrim.*->.equipment.trim.*net.minecraft.world.item.componentToolmethods that returnTool$Rulenow only take theHolderSetof blocks and not a list or tag keyDamageResistant- A component that holds a tag of damage types the item is resistant to as an entity or being worn
net.minecraft.world.item.enchantmentEnchantable- The data component object for the item’s enchantment value.Repairable- The data component object for the items that can repair this item.
net.minecraft.world.level.blockAbstractSkullBlockno longer implementsEquippableEquipableCarvedPumpkinBlockclass is removed, as replaced byDataComponents#EQUIPPABLEWoolCarpetBlockno longer implementsEquippable
Interaction Results
InteracitonResults have been completely modified to encompass everything to one series of sealed implementations. The new implementation of InteractionResult combines both InteractionResultHolder and ItemInteractionResult, meaning that all uses have also been replcaed.
InteractionResult is now an interface with four implementations depending on the result type. First there is $Pass, which indicates that the interaction check should be passed to the next object in the call stack. $Fail, when used for items and blocks, prevents anything further in the call stack for executing. For entities, this is ignored. Finally, $TryEmptyHandInteraction tells the call stack to try to apply the click with no item in the hand, specifically for item-block interactions.
There is also $Success, which indicates that the interaction was successful and can be consumed. A success specifies two pieces of information: the $SwingSource, which indicates where the source of the swing originated from (CLIENT or SERVER) or NONE if not specified, and $ItemContext that handles whether there was an iteraction with the item in the hand, and what the item was transformed to.
None of the objects should be directly initialized. The implementations are handled through six constants on the InteractionResult interface:
SUCCESS- A$Successobject that swings the hand on the client.SUCCESS_SERVER- A$Successobject that swings the hand on the server.CONSUME- A$Successobject that does not swing the hand.FAIL- A$Failobject.PASS- A$Passobject.TRY_WITH_EMPTY_HAND- A$TryEmptyHandInteractionobject.
// For some method that returns an InteractionResult
return InteractionResult.PASS;
For success objects, if the item interaction should transform the held stack, then you call $Success#heldItemTransformedTo, or $Success#withoutItem if no item was used for the interaction.
// For some method that returns an InteractionResult
return InteractionResult.SUCCESS.heldItemTransformedTo(new ItemStack(Items.APPLE));
// Or
return InteractionResult.SUCCESS.withoutItem();
net.minecraft.core.cauldron.CauldronInteractioninteractnow returns anInteractionResultfillBucket,emptyBucketnow returns anInteractionResult
net.minecraft.worldInteractionResultHolder,ItemInteractionResult->InteractionResult
net.minecraft.world.itemEquipable#swapWithEquipmentSlotnow returns anInteractionResultItem#use,ItemStack#usenow returns anInteractionResultItemUtils#startUsingInstantlynow returns anInteractionResultJukeboxPlayable#tryInsertIntoJukeboxnow returns anInteractionResult
net.minecraft.world.level.block.state.BlockBehaviour#useItemOn,$BlockStateBase#useItemOnnow returns anInteractionResult
Instruments, the Datapack Edition
Instruments (not NoteBlockInstruments) are now a datapack registry, meaning they must be defined in JSON or datagenned.
// In data/examplemod/instrument/example_instrument.json
{
// The registry name of the sound event
"sound_event": "minecraft:entity.arrow.hit",
// How many seconds the instrument is used for
"use_duration": 7.0,
// The block range, where each block is 16 units
"range": 256.0,
// The description of the instrument
"description": {
"translate": "instrument.examplemod.example_instrument"
},
}
// For some RegistrySetBuilder builder
builder.add(Registries.INSTRUMENT, bootstrap -> {
bootstrap.register(
ResourceKey.create(Registries.INSTRUMENT, ResourceLocation.fromNamespaceAndPath("examplemod", "example_instrument")),
new Instrument(
BuiltInRegistries.SOUND_EVENT.wrapAsHolder(SoundEvents.ARROW_HIT),
7f,
256f,
Component.translatable(Util.makeDescriptionId("instrument", ResourceLocation.fromNamespaceAndPath("examplemod", "example_instrument")))
)
)
});
net.minecraft.world.itemInstrumenttakes in afloatfor the use duration and aComponentdescription.InstrumentItem#setRandomis removed
Trial Spawner Configurations, now in Datapack Form
TrialSpawnConfig are now a datapack registry, meaning they must be defined in JSON or datagenned.
// In data/examplemod/trial_spawner/example_config.json
{
// The range the entities can spawn from the trial spawner block
"spawn_range": 2,
// The total number of mobs that can be spawned
"total_mobs": 10.0,
// The number of mobs that can be spawned at one time
"simultaneous_mobs": 4.0,
// The number of mobs that are added for each player in the trial
"total_mobs_added_per_player": 3.0,
// The number of mobs that can be spawned at one time that are added for each player in the trial
"simultaneous_mobs_added_per_player": 2.0,
// The ticks between each spawn
"ticks_between_spawn": 100,
// A weighted list of entities to select from when spawning
"spawn_potentials": [
{
// The SpawnData
"data": {
// Entity to spawn
"entity": {
"id": "minecraft:zombie"
}
},
// Weighted value
"weight": 1
}
],
// A weight list of loot tables to select from when the reward is given
"loot_tables_to_eject": [
{
// The loot key
"data": "minecraft:spawners/ominous/trial_chamber/key",
// Weight value
"weight": 1
}
],
// Returns the loot table to use when the the trial spawner is ominous
"items_to_drop_when_ominous": "minecraft:shearing/bogged"
}
// For some RegistrySetBuilder builder
builder.add(Registries.TRIAL_SPAWNER_CONFIG, bootstrap -> {
var entityTag = new CompoundTag();
entityTag.putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(EntityType.ZOMBIE).toString());
bootstrap.register(
ResourceKey.create(Registries.INSTRUMENT, ResourceLocation.fromNamespaceAndPath("examplemod", "example_config")),
TrialSpawnerConfig.builder()
.spawnRange(2)
.totalMobs(10.0)
.simultaneousMobs(4.0)
.totalMobsAddedPerPlayer(3.0)
.simultaneousMobsAddedPerPlayer(2.0)
.ticksBetweenSpawn(100)
.spawnPotentialsDefinition(
SimpleWeightedRandomList.single(new SpawnData(entityTag, Optional.empty(), Optional.empty()))
)
.lootTablesToEject(
SimpleWeightedRandomList.single(BuiltInLootTables.SPAWNER_OMINOUS_TRIAL_CHAMBER_KEY)
)
.itemsToDropWhenOminous(
BuiltInLootTables.BOGGED_SHEAR
)
.build()
)
});
net.minecraft.world.level.block.entity.trialspawnerTrialSpawnernow takes in aHolderof theTrialSpawnerConfigcanSpawnInLevelnow takes in aServerLevel
TrialSpawnerConfigCODEC->DIRECT_CODEC$Builder,builder- A builder for a trial spawner configuration
Recipe Providers, the ‘not actually’ of Data Providers
RecipeProvider is no longer a DataProvider. Instead, a RecipeProvider is constructed via a RecipeProvider$Runner by implementing createRecipeProvider. The name of the provider must also be specified.
public class MyRecipeProvider extends RecipeProvider {
// The parameters are stored in protected fields
public MyRecipeProvider(HolderLookup.Provider registries, RecipeOutput output) {
super(registries, output);
}
@Override
protected void buildRecipes() {
// Register recipes here
}
// The runner class, this should be added to the DataGenerator as a DataProvider
public static class Runner extends RecipeProvider.Runner {
public Runner(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
super(output, registries)
}
@Override
protected RecipeProvider createRecipeProvider(HolderLookup.Provider registries, RecipeOutput output) {
return new VanillaRecipeProvider(registries, output);
}
@Override
public String getName() {
return "My Recipes";
}
}
}
net.minecraft.data.recipesRecipeOutput#includeRootAdvancement- Generates the root advancement for recipes.RecipeProviderno longer extendsDataProvider- The constructor takes in the lookup provider and a
RecipeOutput, which are protected fields buildRecipesdoes not take in any parameters- All generation methods do not take in a
RecipeOutputand are instance methods $FamilyRecipeProvider- Creates a recipe for aBlockFamilyby passing in theBlockthe resulting block and the base block.$Runner- ADataProviderthat constructs theRecipeProviderviacreateRecipeProvider
- The constructor takes in the lookup provider and a
ShapedRecipeBuilder,ShapelessRecipeBuildernow have private constructors and take in a holder getter for the items
The Ingredient Shift
Ingredients have be reimplemented to use a HolderSet as its base rather that it own internal Ingredient$Value. This most changes the call to Ingredient#of as you either need to supply it with Item objects or the HolderSet representing the tag. For more information on how to do this, see the holder set section.
net.minecraft.world.item.crafting.IngredientEMPTY->Ingredient#of, though the default usecases do not allow empty ingredientsCODECis removedCODEC_NONEMPTY->CODECtestOptionalIngredient- Tests whether the stack is within the ingredient if present, or default to an empty check if not.getItems->itemsgetStackingIdsis removedof(ItemStack...),of(Stream<ItemStack>)is removedof(TagKey)->of(HolderSet), need to resolve tag key
BlockEntityTypes Privatized!
BlockEntityTypes have been completely privatized and the builder being removed! This means that if a mod loader or mod does not provide some access widening to the constructor, you will not be able to create new block entities. The only other change is that the Type for data fixers was removed, meaning that all that needs to be supplied is the client constructor and the set of valid blocks the block entity can be on.
// If the BlockEntityType constructor is made public
// MyBlockEntity(BlockPos, BlockState) constructor
BlockEntityType<MyBlockEntity> type = new BlockEntityType(MyBlockEntity::new, MyBlocks.EXAMPLE_BLOCK);
Consumables
Consuming an item has been further expanded upon, with most being transitioned into separate data component entries.
The Consumable Data Component
The Consumable data component defines how an item is used when an item is finished being used. This effectively functions as FoodProperties used to previously, except all consumable logic is consolidated in this one component. A consumable has five properties: the number of seconds it takes to consume or use the item, the animation to play while consuming, the sound to play while consuming, whether particles should appear during consumption, and the effects to apply once the consumption is complete.
A Consumable can be applied using the food item property. If only the Consumable should be added, then component should be called. A list of vanilla consumables and builders can be found in Consumables.
// For some item
Item exampleItem = new Item(new Item.Properties().component(DataComponents.CONSUMABLE,
Consumable.builder()
.consumeSeconds(1.6f) // Will use the item in 1.6 seconds, or 32 ticks
.animation(ItemUseAnimation.EAT) // The animation to play while using
.sound(SoundEvents.GENERIC_EAT) // The sound to play while using the consumable
.soundAfterConsume(SoundEvents.GENERIC_DRINK) // The sound to play after consumption (delegates to 'onConsume')
.hasConsumeParticles(true) // Sets whether to display particles
.onConsume(
// When finished consuming, applies the effects with a 30% chance
new ApplyStatusEffectsConsumeEffect(new MobEffectInstance(MobEffects.HUNGER, 600, 0), 0.3F)
)
// Can have multiple
.onConsume(
// Teleports the entity randomly in a 50 block radius
new TeleportRandomlyConsumeEffect(100f)
)
.build()
));
OnOverrideSound
Sometimes, an entity may want to play a different sound when consuming an item. In that case, the entity can implement Consumable$OverrideConsumeSound and return the sound event that should be played.
// On your own entity
public class MyEntity extends Mob implements Consumable.OverrideCustomSound {
// ...
@Override
public SoundEvent getConsumeSound(ItemStack stack) {
// Return the sound event to play
}
}
ConsumableListener
ConsumableListeners are data components that indicate an action to apply once the stack has been ‘consumed’. This means whenever Consumable#consumeTicks has passed since the player started using the consumable. An example of this would be FoodProperties. ConsumableListener only has one method #onConsume that takes in the level, entity, stack doing the consumption, and the Consumable that has finished being consumed.
// On your own data component
public record MyDataComponent() implements ConsumableListener {
// ...
@Override
public void onConsume(Level level, LivingEntity entity, ItemStack stack, Consumable consumable) {
// Perform stuff once the item has been consumed.
}
}
ConsumeEffect
There is now a data component that handles what happens when an item is consumed by an entity, aptly called a ConsumeEffect. The current effects range from adding/removing mob effects, teleporting the player randomly, or simply playing a sound. These are applied by passing in the effect to the Consumable or onConsume in the builder.
// When constructing a consumable
Consumable exampleConsumable = Consumable.builder()
.onConsume(
// When finished consuming, applies the effects with a 30% chance
new ApplyStatusEffectsConsumeEffect(new MobEffectInstance(MobEffects.HUNGER, 600, 0), 0.3F)
)
// Can have multiple
.onConsume(
// Teleports the entity randomly in a 50 block radius
// NOTE: CURRENTLY BUGGED, only allows for 8 block raidus
new TeleportRandomlyConsumeEffect(100f)
)
.build();
On Use Conversion
Converting an item into another stack on consumption is now handled through DataComponents#USE_REMAINDER. The remainder will only be converted if the stack is empty after this use. Otherwise, it will return the current stack, just with one item used.
// For some item
Item exampleItem = new Item(new Item.Properties().usingConvertsTo(
Items.APPLE // Coverts this into an apple on consumption
));
Item exampleItem2 = new Item(new Item.Properties().component(DataComponents.USE_REMAINDER,
new UseCooldown(
new ItemStack(Items.APPLE, 3) // Converts into three apples on consumption
)
));
Cooldowns
Item cooldowns are now handled through DataComponents#USE_COOLDOWN; however, they have been expanded to apply cooldowns to stacks based on their defined group. A cooldown group either refers to the Item registry name if not specified, or a custom resource location. When applying the cooldown, it will store the cooldown instance on anything that matches the defined group. This means that, if a stack has some defined cooldown group, it will not be affected when a normal item is used.
// For some item
Item exampleItem = new Item(new Item.Properties().useCooldown(
60 // Wait 60 seconds
// Will apply cooldown to items in the 'my_mod:example_item' group (assuming that's the registry name)
));
Item exampleItem2 = new Item(new Item.Properties().component(DataComponents.USE_COOLDOWN,
new UseCooldown(
60, // Wait 60 seconds
// Will apply cooldown to items in the 'my_mod:custom_group' group
Optional.of(ResourceLocation.fromNamespaceAndPath("my_mod", "custom_group"))
)
));
net.minecraft.core.component.DataComponents#FOOD->CONSUMABLEnet.minecraft.world.entity.LivingEntitygetDrinkingSound,getEatingSoundis removed, handled viaConsumeEffecttriggerItemUseEffectsis removedeatis removed
net.minecraft.world.entity.npc.WanderingTradernow implementsConsumable$OverrideConsumeSoundnet.minecraft.world.foodnet.minecraft.world.food.FoodDataticknow takes in aServerPlayergetLastFoodLevel,getExhaustionLevel,setExhaustionis removed
FoodPropertiesis now aConsumableListenereatDurationTicks,eatSeconds->Consumable#consumeSecondsusingConvertsTo->DataComponents#USE_REMAINDER,effects->ConsumeEffect
net.minecraft.world.itemChorusFruitItemclass is removedHoneyBottleItemclass is removedItemgetDrinkingSound,#getEatingSoundis removed, handled viaConsumeEffectreleaseUsingnow returns abooleanwhether it was successfully released$Properties#foodcan now take in aConsumablefor custom logic$Properties#usingConvertsTo- The item to convert to after use.$Properties#useCooldown- The amount of seconds to wait before the item can be used again.
ItemCooldownsnow take inItemStacks orResourceLocations to their methods rather than just anItemgetCooldownGroup- Returns the key representing the group the cooldown is applied to
ItemStack#getDrinkingSound,getEatingSoundis removedMilkBucketItemclass is removedOminousBottleItemclass is removedSuspiciousStewItemclass is removed
net.minecraft.world.item.alchemy.PotionContentsnow implementsConsumableListener- The constructor takes in an optional string representing the translation key suffix of the custom name
applyToLivingEntity- Applies all effects to the provided entity.getName- Gets the name component by appending the custom name to the end of the provided contents string.
net.minecraft.world.item.componentConsumable- A data component that defines when an item can be consumed.ConsumableListener- An interface applied to data components that can be consumed, executes once consumption is finished.SuspiciousStewEffectsnow implementsConsumableListenerUseCooldown- A data component that defines how the cooldown for a stack should be applied.UseRemainder- A data component that defines how the item should be replaced once used up.DeathProtection- A data component that contains a list ofConsumeEffects on what to do when using the item to survive death.
net.minecraft.world.item.consume_effects.ConsumeEffect- An effect to apply after the item has finished being consumed.
Registry Objcet Id, in the Properties?
When providing the BlockBehaviour$Properties to the Block or the Item$Properties to the Item, it must set the ResourceKey in the block directly by calling #setId. An error will be thrown if this is not set before passing in.
new Block(BlockBehaviour.Properties.of()
.setId(ResourceKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath("examplemod", "example_block"))));
new BlockItem(exampleBlock, new Item.Properties()
.useBlockDescriptionPrefix() // Makes the description id for a block item
.setId(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("examplemod", "example_item"))));
new Item(new Item.Properties()
.setId(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("examplemod", "example_item"))));
net.minecraft.world.item.Item$PropertiessetId- Sets the resource key of the item to get the default description and model from. This property must be set.useBlockDescriptionPrefix- Creates the description id using theblock.prefix.useItemDescriptionPrefix- Creates the description id using theitem.prefix.
net.minecraft.world.level.block.state.BlockBehaviour$Properties#setId- Sets the resource key of the block to get the default drops and description from. This property must be set.
Properties Changes
DirectionProperty has been removed, and must now be called and referenced via EnumProperty#create with a Direction generic. Additionally, all property classes have been made final and must be constructed through one of the exposed create methods.
net.minecraft.world.level.block.state.propertiesBooleanPropertyis now finalDirectionPropertyclass is removedEnumPropertyis now finalcreatenow takes in aListinstead of aCollection
IntegerPropertyis now finalProperty#getPossibleValuesnow returns aListinstead of aCollection
Recipes, now in Registry format
Recipes have been upgraded to a data pack registry, similar to how loot tables are handled. They are still queried in the same fashion, it just simply using a pseudo-registry-backed instance. Some of the more common changes is that RecipeHolder may be replaced by RecipeDisplayId, RecipeDisplay, or RecipeDisplayEntry if the holder itself is not needed. With this, there are a few changes to how recipe books are handled.
Recipe Books
RecipeBookComponents have been modified somewhat to hold a generic instance of the menu to render. As such, the component no longer implements PlacedRecipe and instead takes in a generic representing the RecipeBookMenu. The menu is passed into the component via its constructor instead of through the init method. This also menas that RecipeBookMenu does not have any associated generics. To create a component, the class needs to be extended.
// Assume some MyRecipeMenu extends AbstractContainerMenu
public class MyRecipeBookComponent extends RecipeBookComponent<MyRecipeMenu> {
public MyRecipeBookComponent(MyRecipeMenu menu, List<RecipeBookComponent.TabInfo> tabInfos) {
super(menu, tabInfos);
// ...
}
@Override
protected void initFilterButtonTextures() {
// ...
}
@Override
protected boolean isCraftingSlot(Slot slot) {
// ...
}
@Override
protected void selectMatchingRecipes(RecipeCollection collection, StackedItemContents contents) {
// ...
}
@Override
protected Component getRecipeFilterName() {
// ...
}
@Override
protected void fillGhostRecipe(GhostSlots slots, RecipeDisplay display, ContextMap ctx) {
}
}
public class MyContainerScreen extends AbstractContainerScreen<MyRecipeMenu> implements RecipeUpdateListener {
public MyContainerScreen(MyRecipeMenu menu, List<RecipeBookComponent.TabInfo> tabInfos, ...) {
super(menu, ...);
this.recipeBookComponent = new MyRecipeBookComponent(menu, tabInfos);
}
// See AbstractFurnaceScreen for a full implementation
}
Recipe Displays
However, how does a recipe understand what should be displayed in a recipe book? This falls under two new static registries: the RecipeDisplay and the SlotDisplay.
The SlotDisplay represents what displays in a single slot within a recipe. The display only has one method (ignoring types): resolve. resolve takes in the ContextMap holding the data and the DisplayContentsFactory which accepts the stacks and remainders that will be displayed in this slot. SlotDisplay also has a lot of helper implementations, such as $Composite that takes in a list of displays or $ItemStackSlotDisplay that takes in the stack to display. The display is registered by its $Type, which takes in the map codec and stream codec.
The slot also has methods to get for the associated stacks that can be displayed via resolveForStacks and resolveForFirstStack.
public static record MySlotDisplay() implements SlotDisplay {
@Override
public <T> Stream<T> resolve(ContextMap ctx, DisplayContentsFactory<T> output) {
// Call output.forStack(...) or addRemainder(..., ...) using instanceof to display items
if (output instanceof ForStacks<T> stacks) {
stacks.forStack(...);
} else if (output instanceof ForRemainders<T> remainders) {
remainders.addRemainder(..., ...);
}
}
@Override
public SlotDisplay.Type<? extends SlotDisplay> type() {
// Return the registered object here registered to Registries#SLOT_DISPLAY
}
}
RecipeDisplay represents how a recipe is displayed. As an implementation detail, the RecipeDisplay only needs to be aware of the result (via result slot display) and the place the recipe is being used (via craftingStation slot display) as those are the only two details the recipe book cares about. However, it is recommended to also have slot displays for the ingredients and then have those consumed by your RecipeBookComponent. The display is registered by its $Type, which takes in the map codec and stream codec.
public record MyRecipeDisplay(SlotDisplay result, SlotDisplay craftingStation, ...) implements RecipeDisplay {
@Override
public RecipeDisplay.Type<? extends RecipeDisplay> type() {
// Return the registered object here registered to Registries#RECIPE_DISPLAY
}
}
Recipe Placements
Recipe ingredients and placements within the recipe book are now handled through Recipe#placementInfo. A PlacementInfo is basically a definition of items the recipe contains and where they should be placed within the menu if supported. If the recipe cannot be placed, such as if it is not an Item or uses stack information, then it should return PlacementInfo#NOT_PLACEABLE.
A PlacementInfo can be created either from an Ingredient, a List<Ingredient>, or a List<Optional<Ingredient>> using create or createFromOptionals, respectively.
public class MyRecipe implements Recipe<RecipeInput> {
private PlacementInfo info;
public MyRecipe(Ingredient input) {
// ...
}
// ...
@Override
public PlacementInfo placementInfo() {
// This delegate is done as the HolderSet backing the ingredient may not be fully populated in the constructor
if (this.info == null) {
this.info = PlacementInfo.create(input);
}
return this.info;
}
}
If an Optional<Ingredient> is used, they can be tested via Ingredient#testOptionalIngredient.
net.minecraft.world.item.craftingIngredient#display- Returns theSlotDisplaythat shows this ingredient.PlacementInfo- Defines all ingredients necessary to construct the result of a recipe.RecipegetToastSymbol->getCategoryIconItemgetIngredients,isIncomplete->placementInfogetIngredients->PlacementInfo#stackedRecipeContents,isIncomplete->PlacementInfo#isImpossibleToPlace
RecipeManager#getSynchronizedRecipes- Returns all recipes that can be placed and sends them to the client. No other recipes are synced.ShapedRecipePatternnow takes in aList<Optional<Ingredient>>instead of aNonNullList<Ingredient>ShapelessRecipenow takes in aList<Ingredient>instead of aNonNullList<Ingredient>SmithingTransformRecipe,SmithingTrimRecipenow takes inOptional<Ingredient>s instead ofIngredientsSuspiciousStewRecipeclass is removed
Recipe Changes
There have been a few changes within the recipe class itself, which mirror all of the above changes. First, canCraftInDimensions is removed and now hardcoded into the match function. getResultItem and getCategoryIconItem has been replaced by RecipeDisplay via display. getRemainingItems has moved to CraftingRecipe. Finally, all recipes now return their RecipeBookCategory via recipeBookCategory.
public class MyRecipe implements Recipe<RecipeInput> {
@Override
public String group() {
// Return here what `getGroup` was
}
@Override
public List<RecipeDisplay> display() {
return List.of(
// Some recipe display instance
// RecipeDisplay#result should return `getResultItem`
// RecipeDisplay#craftingStation should return `getCategoryIconItem`
)
}
@Override
public RecipeBookCategory recipeBookCategory() {
// Functions similar to the book category passed into the recipe builders during data generation
return RecipeBookCategories.CRAFTING_MISC;
}
}
Creating Recipe Book Categories
Recipe book categories are unified by ExtendedRecipeBookCategory and split into two sections: RecipeBookCategory for actual categories, and SearchRecipeBookCategory for aggregate categories. While SearchRecipeBookCategorys are enums, RecipeBookCategory is like any other static registry object. This is done by creating a new RecipeBookCategory.
// Using the standard vanilla registry method
public static final RecipeBookCategory EXAMPLE_CATEGORY = Registry.register(
BuiltInRegistries.RECIPE_BOOK_CATEGORY,
// The registry object name
ResourceLocation.fromNamespaceAndPath("examplemod", "example_category"),
// This creates a new recipe book category. It functions as a marker object.
new RecipeBookCategory()
);
Technical Changes
net.minecraft.advancements.AdvancementRewardsnow takes in a list ofResourceKeys instead ofResourceLocations for the recipe$Builder#recipe,addRecipenow takes in aResourceKey
net.minecraft.advancements.critereonPlayerPredicatenow takes in aResourceKeyfor the recipe map$Builder#addRecipenow takes in aResourceKey
RecipeCraftedTriggertriggernow takes in aResourceKey$TriggerInstancenow takes in aResourceKey$TriggerInstance#craftedItem,crafterCraftedItemnow takes in aResourceKey
RecipeUnlockedTriggerunlockednow takes in aResourceKey$TriggerInstancenow takes in aResourceKey
net.minecraft.clientClientRecipeBooksetupCollections->rebuildCollections, not one-to-onegetCollection(RecipeBookCategories)->getCollection(ExtendedRecipeBookCategory)add,remove- Handles adding/removing a recipe entry to display within the recipe book.addHighLight,removeHighlight,hasHighlight- Handles if the entry is highlighted when filtered or selected by the player.clear- Clears the known and highlighted recipes.
RecipeBookCategories#*_MISC->SearchRecipeBookCategory#*- This can also be replaced within methods by
RecipeBookComponent$TabInfo,ExtendedRecipeBookCategory, orRecipeBookCategory
- This can also be replaced within methods by
net.minecraft.client.gui.components.toastsRecipeToast(RecipeHolder)->RecipeToast(), now privateaddOrUpdatenow takes in aRecipeDisplayinstead of aRecipeHolder
net.minecraft.client.gui.screens.inventory.AbstractFurnaceScreenrecipeBookComponentis now privateAbstractFurnaceScreen(T, AbstractFurnaceRecipeBookComponent, Inventory, Component, ResourceLocation, ResourceLocation, ResourceLocation)-AbstractFurnaceRecipeBookComponenthas been replaced with aComponentas the recipe book is not constructed internally and now takes in a list ofRecipeBookComponent$TabInfo
net.minecraft.client.gui.screens.recipebookAbstractFurnaceReipceBookComponent,BlastingFurnaceReipceBookComponent,SmeltingFurnaceReipceBookComponent,SmokingFurnaceReipceBookComponent->FurnaceReipceBookComponentGhostRecipe->GhostSlotsnot one-to-one, as the recipe itself is stored as a private field inRecipeBookComponentas aRecipeHolderaddResult->setResult, not one-to-oneaddIngredient->setIngredient, not one-to-onesetSlot,setInput,setResultnow take in aContextMap
OverlayRecipeComponent()->OverlayRecipeComponent(SlotSelectTime, boolean)inittakes in aContextMapcontaining registry data to display within the components and abooleanrepresenting whether the recipe book is filtering instead of computing it from theMinecraftinstancegetLastRecipeClickednow returns aRecipeDisplayId$OverlayRecipeButtonis now an abstract package-private class, taking in theContextMap$Posis now a record
RecipeBookComponentno longer implementsRecipeShownListener- The constructor takes in a list of
$TabInfos containing the tabs shown in the book initno longer takes in aRecipeBookMenuinitVisualsis now privateinitFilterButtonTexturesis now abstractupdateCollectionsnow takes in another boolean representing if the book is filteringrenderTooltipnow takes in a nullableSlotinstead of anintrepresenting the slot indexrenderGhostRecipeno longer takes in a float representing the delay timesetupGhostRecipe->fillGhostRecipe, no longer takes in theList<Slot>to place, that is stored within the component itselfselectMatchingRecipesno longer takes in theRecipeBookrecipesShownnow takes in aRecipeDisplayIdsetupGhostRecipeSlots->fillGhostRecipe, taking in theContextMap$TabInfo- A record that denotes the icons and categories of recipe to display within a recipe book page.
- The constructor takes in a list of
RecipeBookPage()->RecipeBookPage(RecipeBookComponent, SlotSelectTime, boolean)updateCollectionsnow takes in a boolean representing if the book is filteringgetMinecraftis removedaddListeneris removedgetLastRecipeClickednow returns aRecipeDisplayIdrecipesShownnow takes in aRecipeDisplayIdgetRecipeBooknow returns aClientRecipeBook
RecipeBookTabButtonnow takes in aRecipeBookComponent$TabInfostartAnimation(Minecraft)->startAnimation(ClientRecipeBook, boolean)getCategorynow returns aExtendedRecipeBookCategory
RecipeButton()->RecipeButton(SlotSelectTime)initnow takes in abooleanrepresenting if the book is filtering and aContextMapholding the registry datagetRecipe->getCurrentRecipe, not one-to-onegetDisplayStack- Returns the result stack of the recipe.getTooltipTextnow takes in theItemStack
RecipeCollection(RegistryAccess, List<RecipeHolder>)->RecipeCollection(List<RecipeDisplayEntry>)canCraft->selectRecipesgetRecipes,getDisplayRecipes->getSelectedRecipesregistryAccess,hasKnownRecipes,updateKnownRecipesis removedisCraftablenow takes in aRecipeDisplayIdhasFitting->hasAnySelectedgetRecipesnow returns a list ofRecipeDisplayEntrys
RecipeShownListenerclass is removedRecipeUpdateListenergetRecipeBookComponentis removedfillGhostRecipe-> Fills the ghost recipe given theRecipeDisplay
SearchRecipeBookCategory- An enum which holds the recipe book categories for aggregate types.SlotSelectTime- Represents the current index of the slot selected by the player.
net.minecraft.client.multiplayerClientPacketListener#getRecipeManager->recipes, returnsRecipeAccessClientRecipeContainer- A client side implementation of theRecipeAccesswhen synced from the server.MultiPlayerGameMode#handlePlaceRecipenow takes in aRecipeDisplayIdSessionSearchTrees#updateRecipesnow takes in aLevelinstead of theRegistryAccess$Frozen
net.minecraft.client.player.LocalPlayer#removeRecipeHightlightnow takes in aRecipeDisplayIdnet.minecraft.commands.SharedSuggestionProvider#getRecipeNamesis removed as it can be queried from the registry accessnet.minecraft.commands.arguments.ResourceLocationArgumentgetRecipe->ResourceKeyArgument#getRecipegetAdvancement->ResourceKeyArgument#getAdvancement
net.minecraft.commands.synchronization.SuggestionProviders#ALL_RECIPESis removednet.minecraft.core.component.DataComponents#RECIPESnow takes in a list ofResourceKeysnet.minecraft.data.recipesRecipeBuilder#savenow takes in aResourceKeyinstead of aResourceLocationRecipeOutput#acceptnow takes in aResourceKeyinstead of aResourceLocationRecipeProvider#trimSmithingnow takes in aResourceKeyinstead of aResourceLocation
net.minecraft.network.protocol.gameClientboundPlaceGhostRecipePacket- A packet that contains the container id and theRecipeDisplayClientboundRecipeBookAddPacket- A packet that adds entries to the recipe bookClientboundRecipeBookRemovePacket- A packet that removes entries to the recipe bookClientboundRecipeBookSettingsPacket- A packet that specifies the settings of the recipe bookClientboundRecipePacketclass is removedClientboundUpdateRecipesPacketis now a record, taking in the property sets of the recipes and the stonecutter recipesgetRecipesis removed
ServerboundPlaceRecipePacketis now a recordServerboundRecipeBookSeenRecipePacketis now a record
net.minecraft.recipebookPlaceRecipe->PlaceRecipeHelperaddItemToSlot->$Output#addItemToSlotplaceRecipenow takes in aRecipeinstead of theRecipeHolder- There is an overload that takes in two more ints that represent the pattern height and width for a
ShapedRecipe, or just the first two integers repeated
- There is an overload that takes in two more ints that represent the pattern height and width for a
RecipeBookadd,contains,remove->ServerRecipeBook#add,contains,removeaddHighlight,removeHighlight,willHighlight->ServerRecipeBook#addHighlight,removeHighlight,ClientRecipeBook#hasHighlightbookSettingsis now protected
RecipeBookSettings#read,writeis now privateServerPlaceRecipeis not directly accessible anymore, instead it is accessed and returned as aRecipeBookMenu$PostPlaceActionvia#placeRecipe$CraftingMenuAccess- Defines how the placable recipe menu can be interacted with.
ServerRecipeBookfromNbtnow takes in a predicate of aResourceKeyinstead of theRecipeManagercopyOverData- Reads the data from another recipe book.$DisplayResolver- Resoluves the recipes to display by passing in aRecipeDisplayEntry
net.minecraft.stats.RecipeBook#isFiltering(RecipeBookMenu)is removednet.minecraft.world.entity.playerPlayer#awardRecipesByKeynow takes in a list ofResourceKeysStackedItemContents#canCraftoverloads that take in a list of ingredient infos
net.minecraft.world.inventoryAbstractCraftingMenu- A menu for a crafting interface.AbstractFurnaceMenunow takes in theRecipePropertySetkeyCraftingMenu#slotChangedCraftingGridnow takes in aServerLevelinstead of aLevelItemCombinerMenunow takes in anItemCombinerMenuSlotDefinitionmayPickupnow defaults totrue
ItemCombinerMenuSlotDefinition#hasSlot,getInputSlotIndexesis removedRecipeBookMenuno longer takes in any genericshandlePlacementis now abstract and returns a$PostPlaceAction, taking in an additionalServerLevel- This remove all basic placement recipes calls, as that would be handled internally by the
ServerPlaceRecipe
- This remove all basic placement recipes calls, as that would be handled internally by the
RecipeCraftingHolder#setRecipeUserno longer takes in aLevelSmithingMenu#hasRecipeError- Returns whether the recipe had an error when placing items in the inventory.
net.minecraft.world.item.craftingAbstractCookingRecipenow implementsSingleItemRecipe- The constructor no longer takes in the
RecipeType, making the user override thegetTypemethod getExperience->experiencegetCookingTime->cookingTimefurnaceIcon- Returns the icon of the furnace.$Serializer- A convenience implementation for the cooking recipe serializer instance.
- The constructor no longer takes in the
CookingBookCategorynow has an integer idCraftingRecipe#defaultCrafingRemainder- Gets the stacks that should remain behind in the crafting recipe.CustomRecipe$Serializer- A convenience implementation for the custom recipe serializer instance.ExtendedRecipeBookCategory- A unifying interface that denotes a category within the recipe book.Ingredient#optionalIngredientToDisplay- Converts an optional ingredient to aSlotDisplay.Recipe#getRemainingItems->CraftingRecipe#getRemainingItemsRecipeAccess- An accessor that returns the property sets that contain the inputs of available recipes.RecipeBookCategory- An object that represents a single category within the recipe book.RecipeCache#getnow takes in aServerLevelinstead of aLevelRecipeHoldernow takes in aResourceKeyRecipeManagernow extendsSimplePreparableReloadLsitener<RecipeMap>and implementsRecipeAccessprepare- Creates the recipe map from the recipe registrylogImpossibleRecipes,hasErrorsLoadingis removedgetRecipeFornow takes in aResourceKeywhere there was aResourceLocationrepviouslygetRecipesFor,getAllRecipesFor->RecipeMap#getRecipesForbyTypeis removedgetRemainingItemsForis RemovedbyKey.byKeyTypednow takes in aResourceKeygetOrderedRecipesis revmoedgetSynchronizedRecipes->getSynchronizedItemProperties,getSynchronizedStonecutterRecipes; not one-to-onegetRecipeIdsis removedgetRecipeFromDisplay- Gets the recipe display info given its id.listDisplaysForRecipe- Accepts a list of display entries of the recipes to display.replaceRecipesis removed$CachedCheck#getRecipeFornow takes in aServerLevelinstead of aLevel$IngredientCollector- A recipe consumer that extracts the ingredient from a recipe and adds it to aRecipePropertySet$IngredientExtractor- A method that gets the ingredients of a recipe when present.$ServerDisplayInfo- A record that links a display entry to its recipe holder.
RecipeMap- A class which maps recipe holders by their recipe type and resource key.RecipePropertySet- A set of ingredients that can be used as input to a given recipe slot. Used to only allow specific inputs to slots on screens.SelectableRecipe- A record that holds the slot display and its associated recipe. Currently only used for the stonecutting menu.SimpleCookingSerializer->AbstractCookingRecipe$SerializerSingleItemRecipeno longer takes in theRecipeTypeorRecipeSerializeringredient,result,groupis now privateinput,result- The slots of the recipe.
net.minecraft.world.item.crafting.displayDisplayContentsFactory- A factory for accepting contents of a recipe. Its subtypes accepts the stacks of the recipe and the remainder.RecipeDisplay- A display handler to show the contents of a recipe.RecipeDisplayEntry- A record that links the recipe display to its identifier, category, and crafting requirements.RecipeDisplayId- An identifier for the recipe display.SlotDisplay- A display handler to show the contents of a slot within a recipe.SlotDisplayContext- Context keys used by slot displays.
net.minecraft.world.level.Level#getRecipeManager->recipeAccess, returnsRecipeAccesson level butRecipeManageronServerLevelnet.minecraft.world.level.block.CrafterBlock#getPotentialResultsnow takes in aServerLevelinstead of aLevelnet.minecraft.world.level.block.entity.CampfireBlockEntitygetCookableRecipeis removedplaceFoodnow takes in aServerLevelinstead of aLevel
Minor Migrations
The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.
Language File Removals and Renames
All removals and renames to translations keys within assets/minecraft/lang are now shown in a deprecated.json.
Critereons, Supplied with HolderGetters
All critereon builders during construction now take in a HolderGetter. While this may not be used, this is used instead of a direct call to the static registry to grab associated Holders and HolderSets.
net.minecraft.advancement.critereonBlockPredicate$Builder#ofConsumeItemTrigger$TriggerInstance#usedItemEntityEquipmentPredicate#captainPredicateEntityPredicate$Builder#ofEntityTypePredicate#ofItemPredicate$Builder#ofPlayerTrigger$TriggerInstance#walkOnBlockWithEquipmentShotCrossbowTrigger$TriggerInstance#shotCrossbowUsedTotemTrigger$TriggerInstance#usedToItem
MacosUtil#IS_MACOS
com.mojang.blaze3d.platform.MacosUtil#IS_MACOS has been added to replace specifying a boolean during the render process.
com.mojang.blaze3d.pipelineRenderTarget#clear(boolean)->clear()TextureTarget(int, int, boolean, boolean)->TextureTarget(int, int, boolean)
com.mojang.blaze3d.platform.GlStateManager#_clear(boolean)->_clear()com.mojang.blaze3d.systems.RenderSystem#clear(int, boolean)->clear(int)
Fog Parameters
Fog methods for individual values have been replaced with a FogParameters data object.
com.mojang.blaze3d.systems.RenderSystemsetShaderFogStart,setShaderFogEnd,setShaderFogColor,setShaderFogShape->setShaderFoggetShaderFogStart,getShaderFogEnd,getShaderFogColor,getShaderFogShape->getShaderFog
net.minecraft.client.renderer.FogRenderersetupColor->computeFogColor, returns aVector4fsetupNoFog->FogParameters#NO_FOGsetupFognow takes in aVector4ffor the color and returns theFogParameterslevelFogColoris removed
New Tags
minecraft:banner_patternbordure_indentedfield_masoned
minecraft:blockbats_spawnable_onpale_oak_logs
minecraft:damage_typemace_smash
minecraft:itemdiamond_tool_materialsfurnace_minecart_fuelgold_tool_materialsiron_tool_materialsnetherite_tool_materialsvillager_picks_upwooden_tool_materialspiglin_safe_armorrepairs_leather_armorrepairs_chain_armorrepairs_iron_armorrepairs_gold_armorrepairs_diamond_armorrepairs_netherite_armorrepairs_turtle_helmetrepairs_wolf_armorduplicates_allaysbrewing_fuelpanda_eats_from_groundshulker_boxesbundlesmap_invisibility_equipmentpale_oak_logsgaze_disguise_equipment
minecraft:entity_typeboat
Smarter Framerate Limiting
Instead of simply limiting the framerate when the player is not in a level or when in a screen or overlay, there is different behavior depending on different actions. This is done using the InactivityFpsLimit via the FramerateLimitTracker. This adds two additional checks. If the window is minimized, the game runs at 10 fps. If the user provides no input for a minute, then the game runs at 30 fps. 10 fps after ten minutes of no input.
com.mojang.blaze3d.platform.FramerateLimitTracker- A tracker that limits the framerate based on the set value.com.mojang.blaze3d.platform#Window#setFramerateLimit,getFramerateLimitis removednet.minecraft.clientInactivityFpsLimit- An enum that defines how the FPS should be limited when the window is minimzed or the player is away from keyboard.Minecraft#getFramerateLimitTracker- Returns the framerate limiter.
Fuel Values
FuelValues has replaced the static map within AbstractFurnaceBlockEntity. This functions the same as that map, except the fuel values are stored on the MinecraftServer itself and made available to individual Level instances. The map can be obtained with access to the MinecraftServer or Level and calling the fuelValues method.
net.minecraft.client.multiplayer.ClientPacketListener#fuelValues- Returns the burn times for fuel.net.minecraft.server.MinecraftServer#fuelValues- Returns the burn times for fuel.net.minecraft.server.level.Level#fuelValues- Returns the burn times for fuel.net.minecraft.world.level.block.entityAbstractFurnaceBlockEntityinvalidateCache,getFuel->Level#fuelValuesgetBurnDurationnow takes in theFuelValuesisFuel->FuelValues#isFuel
FuelValues- A class which holds the list of fuel items and their associated burn times
Light Emissions
Light emission data is now baked into the quad and can be added to a face using the light_emission tag.
net.minecraft.client.renderer.block.modelBakedQuadnow takes in anintrepresenting the light emissiongetLightEmission- Returns the light emission of a quad.
BlockElementnow takes in anintrepresenting the light emissionFaceBakery#bakeQuadnow takes in anintrepresenting the light emission
Map Textures
Map textures are now handled through the MapTextureManager, which handles the dynamic texture, and the MapRenderer, which handles the map rendering. Map decorations are still loaded through the map_decorations sprite folder.
net.minecraft.clientMinecraftgetMapRenderer- Gets the renderer for maps.getMapTextureManager- Gets the texture manager for maps.
net.minecraft.client.resources#MapTextureManager- Handles creating the dynamic texture for the map.net.minecraft.client.gui.MapRenderer->net.minecraft.client.renderer.MapRenderernet.minecraft.client.renderer#GameRenderer#getMapRenderer->Minecraft#getMapRenderer
Orientations
With the edition of the redstone wire experiments comes a new class provided by the neighbor changes: Orientation. Orientation is effectively a combination of two directions and a side bias. Orientation is used as a way to propogate updates relative to the connected directions and biases of the context. Currently, this means nothing for people not using the new redstone wire system as all other calls to neighbor methods set this to null. However, it does provide a simple way to propogate behavior in a stepwise manner.
net.minecraft.client.renderer.debug.RedstoneWireOrientationsRenderer- A debug renderer for redstone wires being oriented.net.minecraft.world.level.LevelupdateNeighborsAt- Updates the neighbor at the given position with the specifiedOrientation.updateNeighborsAtExceptFromFacing,neighborChangednow takes in anOrientation
net.minecraft.world.level.block.RedStoneWireBlockgetBlockSignal- Returns the strength of the block signal.
net.minecraft.world.level.block.state.BlockBehaviourneighborChanged,$BlockStateBase#handleNeighborChangednow takes in anOrientationinstead of the neighborBlockPosupdateShapenow takes in theLevelReader,ScheduledTickAccess, and aRandomSourceinstead of theLevelAccessor; theDirectionandBlockStateparameters are reordered$BlockStateBase#updateShapenow takes in theLevelReader,ScheduledTickAccess, and aRandomSourceinstead of theLevelAccessor; theDirectionandBlockStateparameters are reordered
net.minecraft.world.level.redstoneCollectingNeighborUpdater$ShapeUpdate#state->neighborStateNeighborUpdaterneighborChanged,updateNeighborsAtExceptFromFacing,executeUpdatenow takes in anOrientationinstead of the neighborBlockPosexecuteShapeUpdateswitches the order of theBlockStateand neighborBlockPos
Orientation- A group of connectedDirectionson a block along with a bias towards either the front or the up side.RedstoneWireEvaluator- A strength evaluator for incoming and outgoing signals.
Minecart Behavior
Minecarts now have a MinecartBehavior class that handles how the entity should be moved and rendered.
net.minecraft.core.dispenser.MinecartDispenseItemBehavior- Defines how a minecart should behave when dispensed from a dispenser.net.minecraft.world.entity.vehicleAbstractMinecartgetMinecartBehavior- Returns the behavior of the minecart.exitsis now publicisFirstTick- Returns whether this is the first tick the entity is alive.getCurrentBlockPosOrRailBelow- Gets the current position of the minecart or the rail beneath.moveAlongTrack->makeStepAlongTracksetOnRails- Sets whether the minecart is on rails.isFlipped,setFlipped- Returns whetherh the minecart is upside down.getRedstoneDirection- Returns the direction the redstone is powering to.isRedstoneConductoris now publicapplyNaturalSlowdownnow returns the vector to slowdown by.getPosOffs->MinecartBehavior#getPossetInitialPos- Sets the initial position of the minecart.createMinecartis now abstract in its creation, meaning it can be used to create any minecart given the provided parametersgetMinecartTypeis removedgetPickResultis now abstract$TypeandgetMinecartTypeis replaced byisRideableandisFurnace, which is not one-to-one.
AbstractMinecartContainer(EntityType, double, double, double, Level)is removedMinecartBehavior- holds how the entity should be rendered and positions during movement.MinecartFurnace#xPush,zPush->push
net.minecraft.world.level.block.state.properties.RailShape#isAscending->isSlopenet.minecraft.world.phys.shapes.MinecartCollisionContext- An entity collision context that handles the collision of a minecart with some other collision object.
EXPLOOOOSSSION!
Explosion is now an interface that defines the metadata of the explosion. It does not contain any method to actually explode itself. However, ServerExplosion is still used internally to handle level explosions and the like.
net.minecraft.world.levelExplosion->ServerExplosionExplosion- An interface that defines how an explosion should occur.getDefaultDamageSource- Returns the default damage source of the explosion instance.shouldAffectBlocklikeEntities- Returns whether block entites should be affected by the explosion.level- Gets theServerLevel
ExplosionDamageCalculator#getEntityDamageAmountnow takes in an additionalfloatrepresenting the seen percentLevel#explodeno longer returns anything
net.minecraft.world.level.block.Block#wasExplodednow takes in aServerLevelinstead of aLevelnet.minecraft.world.level.block.state.BlockBehaviour#onExplosionHit,$BlockStateBase#onExplosionHitnow takes in aServerLevelinstead of aLevel
The Removal of the Carving Generation Step
GenerationStep$Carving has been removed, meaning that all ConfiguredWorldCarvers are provided as part of a single HolderSet.
// In some BiomeGenerationSettings JSON
{
"carvers": [
// Carvers here
]
}
net.minecraft.world.level.biome.BiomeGenerationSettingsgetCarversno longer takes in aGenerationStep$Carving$Builder#addCarverno longer takes in aGenerationStep$Carving$PlainBuilder#addCarverno longer takes in aGenerationStep$Carving
net.minecraft.world.level.chunkChunkGenerator#applyCarversno longer takes in aGenerationStep$CarvingProtoChunk#getCarvingMask,getOrCreateCarvingMask,setCarvingMaskno longer takes in aGenerationStep$Carving
net.minecraft.world.level.levelgen.placementCarvingMaskPlacementclass is removedPlacementContext#getCarvingMaskno longer takes in aGenerationStep$Carving
Codecable Json Reload Listener
The SimpleJsonResourceReloadListener has been rewritten to use codecs instead of pure Gson.
public class MyJsonListener extends SimpleJsonResourceReloadListener<MyJsonObject> {
// If you do not need registry access, the HolderLookup$Provider parameter can be removed
public MyJsonListener(HolderLookup.Provider registries, Codec<T> codec, String directory) {
super(registries, codec, directory);
}
}
net.minecraft.server.packs.resources.SimpleJsonResourceReloadListenernow takes in a generic representing the data object of the JSON- The constructor is now protected, taking in the codec of the data object, the string of the directory, and an optional
HolderLookup$Providerto construct theRegistryOpsserialization context as necessary preparenow returns a map of names to objectsscanDirectorynow takes in theDynamicOpsandCodec
- The constructor is now protected, taking in the codec of the data object, the string of the directory, and an optional
Consecutive Executors
ProcessorMailbox and ProcessorHandle have been replaced with AbstractConsecutiveExecutor and TaskScheduler, respectively. These are effectively the same in their usage, just with potentially different method names.
net.minecraft.util.threadProcessorMailbox->AbstractConsecutiveExecutor, not one-to-oneConsecutiveExecutorwould be the equivalent implementation
PriorityConsecutiveExecutor- An executor that specifies the priority of the task to run when scheduling.BlockableEventLoop#wrapRunnable->AbstractConsecutiveExecutor#wrapRunnableProcessorHandle->TaskScheduler, where the generic is a subtype ofRunnabletell->scheduleask,askEither->scheduleWithResult, not one-to-oneof->wrapExecutor
StrictQueueno longer takes in anFgeneric and makesTa subtype ofRunnablepopnow returns aRunnable$IntRunnable->$RunnableWithPriority
Mob Conversions
Mobs, converted via #convertTo, have their logic handled by ConversionType, ConversionParams. ConversionType is an enum that dictates the logic to apply when copying the information from one mob to another via #convert. The common properties are handled via #convertCommon, which is called within the #convert method. There are currently two types: SINGLE, where the entity is converted one-to-one to another entity; and SPLIT_ON_DEATH, where the Mob#convertTo method is called mutiple times such as when a slime dies. ConversionParams contains the metadata about the conversion process: the type, whether the entity can keep its equipment or pick up loot, and what team the entity is on. Mob#convertTo also takes in a mob consumer to apply any finalization settings to the entity itself.
// For some Mob exampleMob
exampleMob.convertTo(
EntityType.SHEEP, // The entity to convert to
new ConversionParams(
ConversionType.SINGLE, // One-to-one
true, // Keep equipment
false // Do not preserve pick up loot
),
EntitySpawnReason.CONVERSION, // Reason entity spawned
sheep -> {
// Perform any other settings to set on the newly converted entity
},
)
net.minecraft.world.entityConversionParams- A record containing the settings of what happens when a mob is converted to another entityConversionType- An enum that defines how one mob is transformed to another. Currently eitherSINGLEfor one-to-one, orSPLIT_ON_DEATHfor one-to-many (only used for slimes)Mob#convertTonow takes in theConversionParams, an optionalEntitySpawnReasonof the entity (defaultCONVERSION), and a mob consumer to set any other information after conversion
Ender Pearl Chunk Loading
Ender pearls now load the chunks they cross through by adding a ticket to the chunk source and storing the entity on the player.
net.minecraft.server.level.ServerPlayerregisterEnderPearl,deregisterEnderPearl,getEnderPearls- Handles the ender pearls thrown by the player.registerAndUpdateEnderPearlTicket,placeEnderPearlTicket- Handles the region tickets for the thrown ender pearls.
Profilers and the Tracy Client
Profilers have been separated from the minecraft instance, now obtained through Profiler#get. A new profiler instance can be added via a try-resource block on Profiler#use. In addition, the profiler addds a new library called Tracy, made to track the current stack frame along with capturing images on the screen, if the associated --tracy argument is passed in. These sections can be split into ‘zones’ to more granularly distinguish what is happening.
Profiler.get().push("section");
// Do code here
Profiler.get().pop();
com.mojang.blaze3d.systems.RenderSystem#flipFramenow takes in aTracyFrameCapture, ornullnet.minecraft.client.Minecraft#getProfiler->Profiler#getnet.minecraft.client.main.GameConfig$GameDatanow takes in a boolean on whether to capture the screen via the tracy client.net.minecraft.client.multiplayer.ClientLevelno longer takes in theProfilerFillernet.minecraft.server.MinecraftServer#getProfiler->Profiler#getnet.minecraft.server.packs.resources.PreparableReloadListener#reloadno longer takes in theProfilerFillersnet.minecraft.util.profilingProfiler- A static handler for managing the currently activeProfilerFiller.ProfilerFilleraddZoneText- Adds text to label when profiling the current frame.addZoneValue- Adds the value of the zone when profiling the current frame.setZoneColor- Sets the color of the zone when profiling the current frame.zone- Adds a profiler section while creating a new zone to call the above methods for.tee->combine$CombinedProfileFiller- A profiler that writes to multiple profilers.
TracyZoneFiller- A profiler used by the tracy client to keep track of the currently profiling zones.Zone- A section that is current being profiled and interpreted by Tracy.
net.minecraft.world.entity.ai.goal.GoalSelectorno longer takes in the suppliedProfilerFillernet.minecraft.world.levelLevelno longer takes in theProfilerFillergetProfiler,getProfilerSupplier->Profiler#get
PathNavigationRegion#getProfiler->Profiler#get
net.minecraft.world.ticks.LevelTicksno longer takes in theProfilerFiller
Tick Throttler
To prevent the player from spamming certain actions, TickThrottler was added. The throttler takes in the threshold and the increment to add to the count. If the count is less than the threshold, the action can occur. The count is reduced every tick.
net.minecraft.util.TickThrottler- A utility for throttling certain actions from happening too often.
Context Keys
Loot context parameters have been replaced with Context keys, which is simply a more general naming scheme for the previous classes. This also caused the context keys to be used in other contexts that may have arbitrary data.
For a brief description, the context key system is effectively a general typed dictionary, where each ContextKey holds the value type, which is then stored in a backed-map within a ContextMap. To enforce required and optional parameters, a ContextMap is built with a ContextKeySet, which defines the keys of the dictionary map.
net.minecraft.advancements.critereon.CriterionValidator#validatenow takes in aContextKeySetinstead of aLootContextParamSetnet.minecraft.data.loot.LootTableProvider$SubProviderEntry#paramSetnow takes in aContextKeySetinstead of aLootContextParamSetnet.minecraft.util.contextContextKey- A key that represents an object. It can be thought of a dictionary key that specifies the value type.ContextKeySet- A key set which indicates what keys the backing dictionary must have, along with optional keys that can be specified.ContextMap- A map of context keys to their typed objects.
net.minecraft.world.item.enchantmentConditionalEffect#codecnow takes in aContextKeySetinstead of aLootContextParamSetTargetedConditionalEffect#codecnow takes in aContextKeySetinstead of aLootContextParamSet
net.minecraft.world.level.storage.lootLootContexthasParam->hasParametergetParam->getParametergetParamOrNull-getOptionalParameter$EntityTraget#getParamnow returns aContextKeyinstead of aLootContextParam
LootContextUser#getReferencedContextParamsnow takes in a set ofContextKeys rather than a set ofLootContextParamsLootParamsnow takes in aContextMapinstead of a map of params to objectshasParam,getParameter,getOptionalParameter,getParamOrNullare accessible through theContextMapunder different names$Builder#withParameter,withOptionalParameter,getParameter,getOptionalParameternow takes in aContextKeyinstead of aLootContextParam$Builder#createnow takes in aContextKeySetinstead of aLootContextParamSet
LootTablegetParameSetnow returns aContextKeySetinstead of aLootContextParamSet$Builder#setParamSetnow takes in aContextKeySetinstead of aLootContextParamSet
ValidationContextnow takes in aContextKeySetinstead of aLootContextParamSetvalidateUser->validateContextUsagesetParams-setContextKeySet
net.minecraft.world.level.storage.loot.functionsCopyComponentsFunction$Source#getReferencedContextParamsnow takes in a set ofContextKeys rather than a set ofLootContextParams
net.minecraft.world.level.storage.loot.parametersLootContextParam->net.minecraft.util.context.ContextKeyLootContextParamSet->net.minecraft.util.context.ContextKeySet
net.minecraft.world.level.storage.loot.providers.nbtContextNbtProvider$Getter#getReferencedContextParamsnow takes in a set ofContextKeys rather than a set ofLootContextParamsNbtProvider#getReferencedContextParamsnow takes in a set ofContextKeys rather than a set ofLootContextParams
net.minecraft.world.level.storage.loot.providers.score.ScoreboardNameProvider#getReferencedContextParamsnow takes in a set ofContextKeys rather than a set ofLootContextParams
List of Additions
com.mojang.blaze3d.framegraphFrameGraphBuilder- A builder that constructs the frame graph that define the resources used and the frame passes to render.FramePass- An interface that defines how to read/write resources and execute them for rendering within the frame graph.
com.mojang.blaze3d.platformClientShutdownWatchdog- A watchdog created for what happens when the client is shutdown.NativeImage#getPixelsABGR- Gets the pixels of the image in ABGR format.WindowisIconified- Returns whether the window is currently iconified (usually minimized onto the taskbar).setWindowCloseCallback- Sets the callback to run when the window is closed.
com.mojang.blaze3d.resourceCrossFrameResourcePool- Handles resources that should be rendered across multiple framesGraphicsResourceAllocator- Handles resources to be rendered and removed.RenderTargetDescriptor- Defines a render target to be allocated and freed.ResourceDescriptor- Defines a resource and how it is allocated and freed.ResourceHandle- Defines a pointer to an individual resource.
com.mojang.blaze3d.systems.RenderSystem#overlayBlendFunc- Sets the default overlay blend function between layers with transparency.com.mojang.blaze3d.vertexPoseStack#translate(Vec3)- Translates the top pose using a vectorVertexConsumer#setNormal(PoseStack$Pose, Vec3)- Sets the normal of a vertex using a vector
net.minecraftOptionull#orElse- If the first object is null, return the second object.TracingExecutor- An executor that traces the stack frames of the class references executing.UtilallOf- ANDs all predicates or a list of predicates provided. If there are no supplied predicates, the method will default totrue.anyOf- ORs all predicates or a list of predicates provided. If there are no supplied predicates, the method will default tofalse.makeEnumMap- Creates an enum map given the enum class and a function to convert the enum to a value.
net.minecraft.advancements.critereonInputPredicate- A predicate that matches the input the player is making.SheepPredicate- A predicate for when the entity is a sheep.
net.minecraft.clientMinecraftsaveReport- Saves a crash report to the given file.triggerResourcePackRecovery- A function that attempts to save the game when a compilation exception occurs, currently used by shaders when loading.
Options#highContrastBlockOutline- When enabled, provides a greater contrast when hovering over a block in range.ScrollWheelHandler- A handler for storing information when a mouse wheel is scrolled.
ItemSlotMouseAction- An interface that defines how the mouse interacts with a slot when hovering over.net.minecraft.client.gui.componentsAbstractSelectionList#setSelectedIndex- Sets the selected entry based on its index.AbstractWidget#playButtonClickSound- Plays the button click sound.DebugScreenOverlay#getProfilerPieChart- Gets the pie chart profiler renderer.
net.minecraft.client.gui.components.debugchart.AbstractDebugChart#getFullHeight- Returns the height of the rendered chart.net.minecraft.client.gui.components.toastsToastgetWantedVisbility- Returns the visbility of the toast to render.update- Updates the data within the toast.
TutorialToasthas a constructor that takes in anintto represent the time to display in milliseconds.
net.minecraft.client.gui.font.glyphs.BakedGlyphrenderChar- Renders a character in the specified color.$GlyphInstance- An instance of a glyph with the metadata of its screen location.
net.minecraft.client.gui.screensBackupConfirmScreenhas a constructor that takes in anotherComponentthat represents the prompt for erasing the cache.ScreengetFont- Returns the current font used for rendering the screen.showsActiveEffects- When true, shows the mob effects currently applied to the player, assuming that such functionality is added to the screen in question.
net.minecraft.client.gui.screens.inventoryAbstractContainerScreenBACKGROUND_TEXTURE_WIDTH,BACKGROUND_TEXTURE_HEIGHT- Both set to 256.addItemSlotMouseAction- Adds a mouse action when hovering over a slot.renderSlots- Renders all active slots within the menu.
AbstractRecipeBookScreen- A screen that has a renderable and interactableRecipeBookComponentsupplied from the constructor.
net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent#showTooltipWithItemInHand- Returns whether the tooltip should be rendered when the item is in the player’s hand.net.minecraft.client.gui.screens.worldselectionCreateWorldCallback- An interface that creates the world given the current screen, registries, level data, and path directory.CreateWorldScreen#testWorld- Tries to open the world create screen with the provided generation settings context.InitialWorldCreationOptions- Contains the options set when creating the world to generate.WorldCreationContextMapper- An interface that creates the world context from the available resource reloaders and registries.
net.minecraft.client.multiplayerClientChunkCachegetLoadedEmptySections- Returns the sections that have been loaded by the game, but has no data.
ClientLevelisTickingEntity- Returns whether the entity is ticking in the level.setSectionRangeDirty- Marks an area as dirty to update during persistence and network calls.onSectionBecomingNonEmpty- Updates the section when it has data.
PlayerInfo#setTabListOrder,getTabListOrder- Handles the order of players to cycle through in the player tab.
net.minecraft.client.multiplayer.chat.report.ReportReason#getIncompatibleCategories- Gets all reasons that cannot be reported for the given type.net.minecraft.client.particle.TrailParticle- A particle to trail from its current position to the target position.net.minecraft.client.player.LocalPlayer#getDropSpamThrottler- Returns a throttler that determines when the player can drop the next item.net.minecract.client.rendererCloudRenderer- Handles the rendering and loading of the cloud texture data.DimensionSpecialEffects#isSunriseOrSunset- Returns whether the dimension time represents sunrise or sunset in game.LevelEventHandler- Handles the events sent by theLevel#levelEventmethod.LevelRenderergetCapturedFrustrum- Returns the frustrum box of the renderer.getCloudRenderer- Returns the renderer for the clouds in the skybox.onSectionBecomingNonEmpty- Updates the section when it has data.
LevelTargetBundle- Holds the resource handles and render targets for the rendering stages.LightTexturegetBrightness- Returns the brightness of the given ambient and sky light.lightCoordsWithEmission- Returns the packed light coordinates.
RenderTypeentitySolidZOffsetForward- Gets a solid entity render type where the z is offset from the individual render objects.flatClouds- Gets the render type for flat clouds.debugTriangleFan- Gets the render type for debugging triangles.vignette- Gets the vignette type.crosshair- Gets the render type for the player crosshair.mojangLogo- Gets the render type for the mojang logo
Octree- A traversal implementation for defining the order sections should render in the frustum.ShapeRenderer- Utility for rendering basic shapes in the Minecraft level.SkyRenderer- Renders the sky.WeatherEffectRenderer- Renders weather effects.WorldBorderRenderer- Renders the world border.
net.minecraft.client.rendererSectionOcclusionGraph#getOctree- Returns the octree to handle traversal of the render sections.ViewArea#getCameraSectionPos- Gets the section position of the camera.
net.minecraft.client.renderer.culling.FrustumgetFrustumPoints- Returns the frustum matrix as an array ofVector4fs.getCamX,getCamY,getCamZ- Returns the frustum camera coordinates.
net.minecraft.client.renderer.chunk.CompileTaskDynamicQueue- A syncrhonized queue dealing with the compile task of a chunk render section.net.minecraft.client.renderer.debugChunkCullingDebugRenderer- A debug renderer for when a chunk is culled.DebugRendererrenderAfterTranslucents- Renders the chunk culling renderer after translucents have been rendered.renderVoxelShape- Renders the outline of a voxel shape.toggleRenderOctree- Toggles whetherOctreeDebugRendereris rendered.
OctreeDebugRenderer- Renders the order of the section nodes.
net.minecraft.client.renderer.texture.AbstractTexture#defaultBlur,getDefaultBlur- Returns whether the blur being applied is the default blur.net.minecraft.client.resources.DefaultPlayerSkin#getDefaultSkin- Returns the defaultPlayerSkin.net.minecraft.commands.CommandBuildContext#enabledFeatures- Returns the feature flagsnet.minecraft.commands.arguments.selector.SelectorPattern- A record that defines anEntitySelectorresolved from some pattern.net.minecraft.coreBlockPos#betweenClosed- Returns an iterable of all positions within the bounding box.DirectiongetYRot- Returns the Y rotation of a given direction.getNearest- Returns the nearest direction given some XYZ coordinate, or the fallback direction if no direction is nearer.getUnitVec3- Returns the normal unit vector.$Axis#getPositive,getNegative,getDirections- Gets the directions along the axis.
GlobalPos#isCloseEnough- Returns whether the distance from this position to another block position in a dimension is within the given radius.HolderLookup$ProviderlistRegistries- Returns the registry lookups for every registry.allRegistriesLifecycle- Returns the lifecycle of all registries combined.
HolderSet#isBound- Returns whether the set is bound to some value.Registry$PendingTags#size- Gets the number of tags to load.Vec3i#distChessboard- Gets the maximum absolute distance between the vector components.
net.minecraft.core.componentDataComponentHolder#getAllOfType- Returns all data components that are of the specific class type.DataComponentPredicatesomeOf- Constructs a data component predicate where the provided map contains the provided component types.$Builder#expect- Adds that we should expect the data component has some value.
PatchedDataComponentMap#clearPatch- Clears all patches to the data components on the object.
net.minecraft.core.particles.TargetColorParticleOption- A particle option that specifies a target location and a color of the particle.net.minecraft.data.DataProvidersaveAll- Writes all values in a resource location to value map to thePathProviderusing the provided codec.saveStable- Writes a value to the provided path given the codec.
net.minecraft.data.loot#BlockLootSubProvidercreateMossyCarpetBlockDrops- Creates a loot table for a mossy carpet block.createShearsOrSlikTouchOnlyDrop- Creates a loot table that can only drop its item when mined with shears or an item with the silk touch enchantment.
net.minecraft.data.worldgen.Pools#createKey- Creates aResourceKeyfor a template pool.net.minecraft.data.models.EquipmentModelProvider- A model provider for equipment models, only includes vanilla bootstrap.net.minecraft.data.info.DatapackStructureReport- A provider that returns the structure of the datapack.net.minecraft.gametest.frameworkGameTestHelperabsoluteAABB,relativeAABB- Moves the bounding box between absolute coordinates and relative coordinates to the test locationassertEntityData- Asserts that the entity at the provided block position matches the predicate.hurt- Hurts the entity the specified amount from a source.kill- Kills the entity.
GameTestInfo#getTestOrigin- Gets the origin of the spawn structure for the test.StructureUtils#getStartCorner- Gets the starting position of the test to run.
net.minecraft.networkFriendlyByteBufreadVec3,writeVec3- Static methods to read and write vectors.readContainerId,writeContainerId- Methods to read and write menu identifiers.readChunkPos,writeChunkPos- Methods to read and write the chunk position.
StreamCodec#composite- A composite method that takes in seven/eight parameters.
net.minecraft.network.codec.ByteBufCodecsCONTAINER_ID- A stream codec to handle menu identifiers.ROTATION_BYTE- A packed rotation into a byte.LONG- A stream codec for a long, or 64 bytes.OPTIONAL_VAR_INT- A stream codec for an optional integer, serializing0when not present, or one above the stored value.-1cannot be sent properly using this stream codec.
net.minecraft.network.protocol.gameClientboundEntityPositionSyncPacket- A packet that syncs the entity’s position.ClientboundPlayerRotationPacket- A packet that contains the player’s rotation.
net.minecraft.serverMinecraftServertickConnection- Ticks the connection for handling packets.reportPacketHandlingException- Reports a thrown exception when attempting to handle a packetpauseWhileEmptySeconds- Determines how many ticks the server should be paused for when no players are on.
SuppressedExceptionCollector- A handler for exceptions that were supressed by the server.
net.minecraft.server.commands.LookAt- An interface that defines what should happen to an entity when the command is run, typically moving it to look at another.net.minecraft.server.levelChunkHolder#hasChangesToBroadcast- Returns whether there is any updates within the chunk to send to the clients.ChunkTaskDispatcher- A task scheduler for chunks.DistanceManagergetSpawnCandidateChunks- Returns all chunks that the player can spawn within.getTickingChunks- Returns all chunks that are currently ticking.
ServerChunkCache#onChunkReadyToSend- Adds a chunk holder to broadcast to a queue.ServerEntityGetter- An entity getter interface implementation that operates upon theServerLevel.- Replcaes the missing methods from
EntityGetter
- Replcaes the missing methods from
ServerPlayergetTabListOrder- Handles the order of players to cycle through in the player tab.getLastClientInput,setLastClientInput,getLastClientMoveIntent- Handles how the server player interprets the client impulse.commandSource- Returns the player’s source of commands.createCommandSourceStack- Creates the source stack of the player issuing the command.
ThrottlingChunkTaskDispatcher- A chunk task dispatcher that sets a maximum number of chunks that can be executing at once.TickingTracker#getTickingChunks- Returns all chunks that are currently ticking.
net.minecraft.server.packs.repository.PackRepository#isAbleToClearAnyPack- Rebuilds the selected packs and returns whether it is different from the currently selected packs.net.minecraft.resources.DependantName- A reference object that maps some registry objectResourceKeyto a value. Acts similarly toHolderexcept as a functional interface.net.minecraft.tags.TagKey#streamCodec- Constructs a stream codec for the tag key.net.minecraft.utilARGB#vector3fFromRGB24- Creates aVector3fcontaining the RGB components using the low 24 bits of an integer.BinaryAnimator- A basic animator that animates between two states using an easing function.ExtraCodecsNON_NEGATIVE_FLOAT- A float codec that validates the value cannot be negative.RGB_COLOR_CODEC- An integer, float, or three vector float codec representing the RGB color.nonEmptyMap- A map codec that validates the map is not empty.
MthwrapDegrees- Sets the degrees to a value within (-180, 180].lerp- Linear interpolation between two vectors using their components.length- Gets the length of a 2D point in space.easeInOutSine- A cosine function that starts at (0,0) and alternates between 1 and 0 every pi.packDegrees,unpackDegrees- Stores and reads a degree infloatform to abyte.
RandomSource#triangle- Returns a randomfloatbetween the twofloats(inclusive, exclusive) using a trangle distribution.StringRepresentable$EnumCodec#byName- Gets the enum by its string name or the provided supplier value if null.TriState- An enum that represents three possible states: true, false, or default.
net.minecraft.util.datafix.ExtraDataFixUtilspatchSubType- Rewrites the second type to the third type within the first type.blockState- Returns a dynamic instance of the block statefixStringField- Modifies the string field within a dynamic.
net.minecraft.util.thread.BlockableEventLookupBLOCK_TIME_NANOS- Returns the amount of time in nanoseconds that an event will block the thread.isNonRecoverable- Returns whether the exception can be recovered from.
net.minecraft.world.damagesource.DamageSourcesenderPearl- Returns a damage source from when an ender pearl is hit.mace- Returns a damage source where a direct entity hits another with a mace.
net.minecraft.world.entityEntityapplyEffectsFromBlocks- Applies any effects from blocks viaBlock#entityInsideor hardcoded checks like snow or rain.isAffectedByBlocks- Returns whether the entity is affect by the blocks when inside.checkInsideBlocks- Gets all blocks that teh player has traversed and checks whether the entity is inside one and adds them to a set when present.oldPosition,setOldPosAndrot,setOldPos,setOldRot- Helpers for updating the last position and rotation of the entity.getXRot,getYRot- Returns the linearly interpolated rotation of the entity given the partial tick.isAlliedTo(Entity)- Returns whether the entity is allied to this entity.teleportSetPosition- Sets the position and rotation data of the entity being teleported via aDimensionTransitiongetLootTable- Returns theResourceKeyof the loot table the entity should use, if present.isControlledByOrIsLocalPlayer- Return whether the entity is the local player or is controlled by a local player.shouldPlayLavaHurtSound- Whentrue, plays the lava hurt sound when the entity is hurt by lava.onRemoval- A method that gets called when the entity is removed.cancelLerp- Stops any lerped movement.forceSetRotation- Sets the rotation of the entity.isControlledByClient- Returns whether the entity is controlled by client inputs.
EntityTypegetDefaultLootTablenow returns anOptionalin case the loot table is not present$Builder#noLootTable- Sets the entity type to have no loot spawn on death.$Builder#buildnow takes in the resouce key of the entity type
EntitySelector#CAN_BE_PICKED- Returns a selector that gets all pickable entities not in spectator.LivingEntitydropFromShearingLootTable- Resolves a loot table with a shearing context.getItemHeldByArm- Returns the stack held by the specific arm.getEffectiveGravity- Returns the gravity applied to the entity.canContinueToGlide- Returns whether the entity can stil glide in the sky.getItemBlockingWith- Returns the stack the player is currently blocking with.canPickUpLoot- Returns whether the entity can pick up items.dropFromGiftLootTable- Resolves a loot table with a gift context.handleExtraItemsCreatedOnUse- Handles when a living entity gets a new item as a result of using another item.isLookingAtMe- Checks whether the provided entity is looking at this entity.
PositionMoveRotation- A helper for handling the position and rotation of the entity in context.WalkAnimationState#stop- Stops the walking animation of the entity.
net.minecraft.world.entity.ai.attributesAttributeInstancegetPermanentModifiers- Returns all permanent modifiers applied to the entity.addPermanentModifiers- Adds a collection of permanent modifiers to apply.
AttributeMap#assignPermanentModifiers- Copies the permanent modifiers from another map.
net.minecraft.world.entity.ai.control.Control#rotateTowards- Returns a float that rotates to some final rotation by the provided difference within a clamped value.net.minecraft.world.entity.ai.goal.Goal#getServerLevel- Gets the server level given the entity or a level.net.minecraft.world.entity.ai.navigation.PathNavigationupdatePathfinderMaxVisitedNodes- Updates the maximum number of nodes the entity can visit.setRequiredPathLength- Sets the minimum length of the path the entity must take.getMaxPathLength- Returns the maximum length of the path the entity can take.
net.minecraft.world.entity.ai.sensingPlayerSensor#getFollowDistance- Returns the following distance of this entity.Sensor#wasEntityAttackableLastNTicks- Returns a predicate that checks whether the entity is attackable within the specified number of ticks.
net.minecraft.world.entity.ai.village.poi.PoiRecord#pack,PoiSection#pack- Packs the necessary point of interest information. This only removes the dirty runnable.net.minecraft.world.entity.animalAgeableWaterCreature- A water creature that has an age state.AnimalcreateAnimalAttributes- Creates the attribute supplier for animals.playEatingSound- Plays the sound an animal makes while eating.
Bee#isNightOrRaining- Returns whether the current level has sky light and is either at night or raining.Cat#isLyingOnTopOfSleepingPlayer- Returns whether the cat is on top of a sleeping player.Salmon#getSalmonScale- Returns the scale factor to apply to the entity’s bounding box.Wolf#DEFAULT_TAIL_ANGLE- Returns the default tail angle of the wolf.
net.minecraft.world.entity.boss.enderdragon.DragonFlightHistory- Holds the y and rotation of the dragon when flying through the sky. Used for animating better motion of the dragon’s parts.net.minecraft.world.entity.monster.Zombie#canSpawnInLiquids- When true, the zombie can spawn in a liquid.net.minecraft.world.entity.playerInventoryisUsableForCrafting- Returns whether the state can be used in a crafting recipe.createInventoryUpdatePacket- Creates the packet to update an item in the inventory.
PlayerhandleCreativeModeItemDrop- Handles what to do when a player drops an item from creative mode.shouldRotateWithMinecart- Returns whether the player should also rotate with the minecart.canDropItems- Whentrue, the player can drop items from the menu.getPermissionLevel,hasPermissions- Returns the permissions of the player.
StackedContents- Holds a list of contents along with their associated size.$Output- An interface that defines how the contents are accepted when picked.
net.minecraft.world.entity.projectile.ProjectilespawnProjectileFromRotation- Spawns a projectile and shoots from the given rotation.spawnProjectileUsingShoot- Spawns a projectile and sets the initial impulse via#shoot.spawnProjectile- Spawns a projectile.applyOnProjectileSpawned- Applies any additional configurations from the given level andItemStack.onItemBreak- Handles what happens when the item that shot the projectile breaks.shouldBounceOnWorldBorder- Returns whether the projectile should bounce off the world border.setOwnerThroughUUID- Set the owner of the projectile by querying it through its UUID.$ProjectileFactory- Defines how a projectile is spawned from someItemStackby an entity.
net.minecraft.world.entity.vehicleAbstractBoat- An entity that represents a boat.AbstractChestBoat- An entity that represent a boat with some sort of inventory.ChestRaft- An entity that represents a raft with some sort of inventory.Raft- An entity that represents a raft.
net.minecraft.world.inventory.AbstractContainerMenuaddInventoryHotbarSlots- Adds the hotbar slots for the given container at the x and y positions.addInventoryExtendedSlots- Adds the player inventory slots for the given container at the x and y positions.addStandardInventorySlots- Adds the hotbar and player inventory slots at their normal location for the given container at the x and y positions.setSelectedBundleItemIndex- Toggles the selected bundle in a slot.
net.minecraft.world.itemBundleItemgetOpenBundleModelFrontLocation,getOpenBundleModelBackLocation- Returns the model locations of the bundle.toggleSelectedItem,hasSelectedItem,getSelectedItem,getSelectedItemStack- Handles item selection within a bundle.getNumberOfItemsToShow- Determines the number of items in the bundle to show at once.getByColor- Handles the available links from bundle to dyed bundles.getAllBundleItemColors- Returns a stream of all dyed bundles.
ItemStackclearComponents- Clears the patches made to the stack, not the item components.isBroken- Returns wheter the stack has been broken.hurtWithoutBreaking- Damages the stack without breaking the stack.getStyledHoverName- Gets the stylized name component of the stack.
net.minecraft.world.item.component.BundleContentscanItemBeInBundle- Whether the item can be put into the bundle.getNumberOfItemsToShow- Determines the number of items in the bundle to show at once.hasSelectedItem,getSelectedItem- Handles item selection within a bundle.
net.minecraft.world.item.enchantment.EnchantmentHelpercreateBook- Creates an enchanted book stack.doPostAttackEffectsWithItemSourceOnBreak- Applies the enchantments after attack when the item breaks.
net.minecraft.world.levelBlockCollisionshas a constructor to take in aCollisionContextBlockGetter#boxTraverseBlocks- Returns an iterable of the positions traversed along the vector in a given bounding box.CollisionGetternoCollision- Returns whether there is no collision between the entity and blocks, entities, and liquids if thebooleanprovided istrue.getBlockAndLiquidCollisions- Returns the block and liquid collisions of the entity within the bounding box.clipIncludingBorder- Gets the block hit result for the specified clip context, clamped by the world border if necessary.
EmptyBlockAndTintGetter- A dummyBlockAndTintGetterinstance.GameType#isValidId- Checks whether the id matches an existing game type.LevelHeightAccessor#isInsideBuildHeight- Returns whether the specified Y coordinate is within the bounds of the level.
net.minecraft.world.level.blockBlock#UPDATE_SKIP_SHAPE_UPDATE_ON_WIRE- A block flag that, when enabled, does not update the shape of a redstone wire.BonemealableFeaturePlacerBlock- A block that places a configured feature and can be bonemealed.
net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData#resetStatistics- Resets the data of the spawn to an empty setting, but does not clear the current mobs or the next spawning entity.net.minecraft.world.level.block.piston.PistonMovingBlockEntity#getPushDirection- Returns the push direction of the moving piston.net.minecraft.world.level.block.stateBlockBehaviourgetEntityInsideCollisionShape,$BlockStateBase#getEntityInsideCollisionShape- Determines the voxel shape of the block when the entity is within it.$Properties#overrideDescription- Sets the translation key of the block name.
StateHoldergetValueOrElse- Returns the value of the property, else the provided default.getNullableValue- Returns the value of the property, or null if it does not exist.
net.minecraft.world.level.block.state.properties.Property#getInternalIndex- Converts the provided boolean to a 0 when true, or 1 otherwise.net.minecraft.world.level.border.WorldBorder#clampVec3ToBound- Clamps the vector to within the world border.net.minecraft.world.level.chunkChunkAccess#canBeSerialized- Returns true, allows the chunk to be written to disk.ChunkSource#onSectionEmptinessChanged- Updates the section when it has data.LevelChunkSectioncopy- Makes a shallow copy of the chunk section.setUnsavedListener- Adds a listener which takes in the chunk position whenever the chunk is marked dirty.$UnsavedListener- A consumer of a chunk position called when the chunk is marked dirty.
PalettedContainerRO#copy- Creates a shallow copy of thePalettedContainer.UpgradeData#copy- Creates a deep copy ofUpgradeData.
net.minecraft.world.level.chunk.storage.IOWorker#store- Stores the writes of the chunk to the worker.net.minecraft.world.level.levelgenSurfaceRules$Context#getSeaLevel,SurfaceSystem#getSeaLevel- Gets the sea level of the generator settings.WorldOptions#testWorldWithRandomSeed- Creates a test world with a randomly generated seed.
net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecorator$Context#checkBlock- Checks if the block at the given position matches the predicate.net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplategetJigsaws- Returns the jigsaw blocks that are at the provided position with the given rotation.getJointType- Returns the joint type of the jigsaw block.$JigsawBlockInfo- A record which contains the block info for a jigsaw block.- Most methods that involve jigsaws have replaced the
$StructureBlockInfowith a$JigsawBlockInfo.
- Most methods that involve jigsaws have replaced the
net.minecraft.world.level.lighting.LayerLightSectionStorage#lightOnInColumn- Returns whether there is light in the zero node section position.net.minecraft.world.level.pathfinder.PathFinder#setMaxVisitedNodes- Sets the maximum number of nodes that can be visited.net.minecraft.world.level.portalDimensionTransition#withRotation- Updates the entity’s spawn rotation.PortalShape#findAnyShape- Finds aPortalShapethat can be located at the given block position facing the specific direction.
net.minecraft.world.physAABBclip- Clips the vector inside the given bounding box, or returns an empty optional if there is no intersection.collidedAlongVector- Returns whether this box collided with one of the bounding boxes provided in the list along the provided movement vector.getBottomCenter- Gets the bottom center of the bounding box as a vector.
Vec3add,subtract- Translates the vector and returns a new object.horizontal- Returns the horizontal components of the vector.projectedOn- Gets the unit vector representing this vector projected onto another vector.
net.minecraft.world.phys.shapesCollisionContextof(Entity, boolean)- Creates a new entity collision context, where thebooleandetermines whether the entity can always stand on the provided fluid state.getCollisionShape- Returns the collision shape collided with.
VoxelShape#move(Vec3)- Offsets the voxel shape by the provided vector.
net.minecraft.world.ticks.ScheduledTick#toSavedTick- Converts a scheduled tick to a saved tick.
List of Changes
F3 + Fnow toggles fog renderingcom.mojang.blaze3d.platformNativeImagegetPixelRGBA,setPixelRGBAare now private. These are replaced bygetPixelandsetPixel, respectivelygetPixelsRGBA->getPixels
Window#updateDisplaynow takes in aTraceyFrrameCapture, ornull
net.minecraft.UtilbackgroundExecutor,ioPool, andnonCriticalIoPoolnow return aTracingExecutorinstead of anExecutorServicewrapThreadWithTaskName->runNamedwith its parameters flipped and no return value
net.minecraft.advancements.critereonKilledByCrossbowTrigger->KilledByArrowTrigger, not one-to-one, takes in the stack in questionPlayerPredicatecan now match the player’s input
net.minecraft.clientMinecraftdebugFpsMeterKeyPress->ProfilerPieChart#profilerPieChartKeyPressobtained viaMinecraft#getDebugOverlayand thenDebugScreenOverlay#getProfilerPieChartgetTimer->getDeltaTrackergetToasts->getToastManager
Options#setModelPartis now public, replacestoggleModelPartbut without broadcasting the changeParticleStatus->net.minecraft.server.level.ParticleStatus
net.minecraft.client.animation.KeyframeAnimations#animatenow takes in aModelinstead of aHierarchicalModelnet.minecraft.client.gui.FontdrawInBatch(String, float, float, int, boolean, Matrix4f, MultiBufferSource, Font.DisplayMode, int, int, boolean)is removed and should use theComponentreplacement- There is also a delegate that sets the inverse depth boolean to true by default for the
ComponentdrawInBatchmethod
- There is also a delegate that sets the inverse depth boolean to true by default for the
$StringRenderOutputnow takes in theFont, an optional background color, and a boolean representing if inverse depth should be use when drawing the text$StringRenderOutput#finishis now package private
net.minecraft.client.gui.componentsAbstractSelectionListreplaceEntriesis now publicgetRowTop,getRowBottomis now public
PlayerFaceRenderer#draw(GuiGraphics, ResourceLocation, int, int, int, int)takes in aPlayerSkininstead of aResourceLocation
net.minecraft.client.gui.components.toastsToastToast$Visibility render(GuiGraphics, ToastComponent, long)->void render(GuiGraphics, Font, long)slotCount-occupiedSlotCount
ToastComponent->ToastManager
net.minecraft.client.gui.font.glyphs.BakedGlyphrendernow takes in a single integer representing the color instead of four floats and is privaterenderCharis the public replacement, taking in the$GlyphInstance, theMatrix4f,VertexConsumer, and color integer
$Effectis a record, now taking in a single integer representing the color instead of four floats
net.minecraft.client.gui.screensLoadingOverlay#MOJANG_STUDIOS_LOGO_LOCATIONis now publicScreenrenderBlurredBackground(float)->renderBlurredBackground()wrapScreenError->fillCrashDetails, not one to one as it only adds the relevant crash information and not actually throw the error
net.minecraft.client.gui.screens.inventoryAbstractContainerScreen#renderSlotHighlight->renderSlotHighlightBack,renderSlotHighlightFront, now privateBookEditScreennow takes in theWritableBookContentAbstractSignEditScreensignis now protectedrenderSignBackgroundno longer takes in theBlockState
EffectRenderingInventoryScreen->Screen#hasActiveEffects,EffectsInInventory. Not one-to-one asEffectsInInventorynow acts as a helper class to a screen to render its effects at the specified location.
net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponentgetHeight()->getHeight(Font)renderImagenow takes in theintwidth and height of the rendering tooltip
net.minecraft.client.gui.screens.recipebookGhostSlots#renderno longer takes in an x and y offset.RecipeBookComponentno longer takes in an x and y offset.
net.minecraft.client.gui.screens.reporting.ReportReasonSelectionScreennow takes in aReportTypenet.minecraft.client.gui.screens.worldselectionCreateWorldScreen$DataPackReloadCookie->DataPackReloadCookieopenFreshnow has an overload that takes in theCreateWorldCallback
WorldCreationContextnow takes in theInitialWorldCreationOptionsWorldOpenFlows#createFreshLeveltakes in aFunction<HolderLookup.Provider, WorldDimensions>instead ofFunction<RegistryAccess, WorldDimensions>
net.minecraft.client.gui.spectator.SpectatorMenuItem#renderIconnow takes in afloatinstead of anintto represent the alpha valuenet.minecraft.client.multiplayerClientLevelnow takes in anintrepresenting the sea levelgetSkyColornow returns a singleintinstead of aVec3getCloudColornow returns a singleintinstead of aVec3setGameTime,setDayTime->setTimeFromServer
TagCollector->RegistryDataCollector$TagCollector, now package-private
net.minecraft.client.playerAbstractClientPlayer#getFieldOfViewModifiernow takes in a boolean representing whether the camera is in first person and a float representing the partial tickInput->ClientInputandnet.minecraft.world.entity.player.InputKeyboardInputnow extendsClientInputLocalPlayer#inputis nowClientInput
net.minecraft.client.rendererDimensionSpecialEffects#getSunriseColor->getSunriseOrSunsetColorGameRendererprocessBlurEffectno longer takes in the partial tickfloatgetFovreturns afloatinstead of adoublegetProjectionMatrixnow takes in afloatinstead of adouble
ItemModelShapershapesis now privategetItemModel(Item)is removedgetItemModel(ResourceLocation)- Gets the baked model associated with the providedResourceLocation.registeris removedgetModelManageris removedinvalidateCache- Clears the model map.
LevelRendererrenderSnowAndRain->WeatherEffectRenderertickRain->tickParticlesrenderLevelnow takes in aGraphicsResourceAllocatorrenderClouds->CloudRendereraddParticleis now publicglobalLevelEvent->LevelEventHandlerentityTarget->entityOutlineTarget$TransparencyShaderExceptionno longer takes in the throwable cause
SectionOcclusionGraphonSectionCompiled->schedulePropagationFromupdatenow takes in aLongOpenHashSetthat holds the currently loaded section nodes$GraphStateis now package-privateaddSectionsInFrustumnow takes in a list to add the render sections to
ShapeRenderer#renderShapenow takes in a single integer for the color instead of four floatsViewArearepositionCameranow takes in theSectionPosinstead of twodoublesgetRenderSectionAt->getRenderSection
net.minecraft.client.renderer.blockentityBannerRenderer#renderPatternsnow takes in abooleandetermining the glint render type to use*Rendererclasses that constructedLayerDefinitions have now been moved to their associated*ModelclassSignRenderer$SignModel->SignModel
net.minecraft.client.renderer.chunk.SectionRenderDispatchernow takes in aTracingExecutorrather than just aExecutor$CompiledSection#hasNoRenderableLayers->hasRenderableLayers$RenderSectionnow takes in a compiledlongof the section nodesetOrigin->setSectionNodegetRelativeOrigin->getNeighborSectionNodecancelTasksnow returns nothingpointOfView- A reference to the location of where the translucent render type is rendered from.resortTransparencyno longer takes in theRenderTypeand returns nothinghasTranslucentGeometry- Returns whether the compiled blocks have a translucent render type.transparencyResortingScheduled- Returns whether the last task was scheduled but not completed.isAxisAlignedWith->$TranslucencyPointOfView#isAxisAligned
$CompileTaskis now public- No longer
Comparable - The constructor no longer takes in the distance at creation
isHighPriority->isRecompile
- No longer
$TranslucencyPointOfView- Returns the coordinate representing the view point of the tranlucent render type in this section.
net.minecraft.client.renderer.culling.Frustum#cubeInFrustumnow returns anintrepresenting the index of the first plane that culled the boxnet.minecraft.client.renderer.DebugRenderer#rendernow takes in theFrustumnet.minecraft.client.renderer.texture.atlas.sources.PalettedPermutations#loadPaletteEntryFromImageis now privatenet.minecraft.client.tutorialTutorialaddTimedToast,#removeTimedToast,$TimedToast->TutorialToastparameteronInputtakes in aClientInputinstead of anInput
TutorialStepInstanceonInputtakes in aClientInputinstead of anInput
net.minecraft.coreDirectiongetNearest->getApproximateNearestgetNormal->getUnitVec3i
HolderGetter$Provider#getno longer takes in the registry key, instead reading it from theResourceKeyHolderLookup$Providernow implementsHolderGetter$ProviderasGetterLookupis removed as the interface is aHolderGetter$ProviderlistRegistries->listRegistryKeys
Registrynow implementsHolderLookup$RegistryLookupgetTagsonly returns a stream of named holder setsasTagAddingLookup->prepareTagReloadbindTags->WritabelRegistry#bindTagget->getValuegetOrThrow->getValueOrThrowgetHolder->getgetHolderOrThrow->getOrThrowholders->listElementsgetTag->getholderOwner,asLookupis removed asRegistryis an instance of them
RegistryAccessregistry->lookupregistryOrThrow->lookupOrThrow
RegistrySynchronization#NETWORKABLE_REGISTRIES->isNetworkable
net.minecraft.core.cauldron.CauldronInteractionFILL_WATER->fillWaterInteraction, now privateFILL_LAVA->fillLavaInteraction, now privateFILL_POWDER_SNOW->fillPowderSnowInteraction, now privateSHULKER_BOX->shulkerBoxInteraction, now privateBANNER->bannerInteraction, now privateDYED_ITEM->dyedItemIteration, now private
net.minecraft.core.dispenser.BoatDispenseItemBehaviornow takes in theEntityTypeto spawn rather that the variant and chest boat booleannet.minecraft.core.particles.DustColorTransitionOptions,DustParticleOptionsnow takes in integers representing an RGB value instead ofVector3fs.net.minecraft.data.lootBlockLootSubProviderHAS_SHEARS->hasShearscreateShearsOnlyDropis now an instance method
EntityLootSubProviderkilledByFrog,killedByFrogVariantnow take in the getter for theEntityTyperegistrycreateSheepTable->createSheepDispatchPool, not one-to-one as the table was replaced with a pool builder given a map of dye colors to loot tables
net.minecraft.gametest.frameworkGameTestHelper#assertEntityPresent,assertEntityNotPresenttakes in a bounding box instead of two vectorsGameTestInfo#getOrCalculateNorthwestCorneris now public
net.minecraft.network.chat.Component#scorenow takes in aSelectorPatternnet.minecraft.network.chat.contents.ScoreContents,SelectorContentsis now a recordnet.minecraft.network.protocol.login.ClientboundGameProfilePacket->ClientboundLoginFinishedPacketnet.minecraft.network.protocol.gameClientboundMoveEntityPacket#getyRot,getxRotnow returns afloatof the degreesClientboundPlayerPositionPacketis now a record, taking in aPositionMoverotationrepresenting the changerelativeArguments->relativesyRot,xRot->ClientboundPalyerRotationPacket
ClientboundSetTimePacketis now a recordClientboundRotateHeadPacket#getYHeadRotnow returns afloatof the degreesClientboundTeleportEntityPacketis now a record, where the necessary parameters are passed into the packet instead of the entityServerboundPlayerInputPacketis now a record, taking in anInput
net.minecraft.resources.RegistryDataLoader$Loader#loadFromNetworknow takes in a$NetworkedRegistryData, which contains the packed registry entriesnet.minecraft.serverMinecraftServerno longer implementsAutoCloseabletickChildrenis now protectedwrapRunnableis now public
ReloadableServerRegistries#reloadnow takes in a list of pending tags and returns a$LoadResultinstead of a layered registry accessReloadableServerResourcesloadResourcesnow takes in a list of pending tags and the serverExecutorupdateRegistryTags->updateStaticRegistryTags
ServerFunctionLibrary#getTag,ServerFunctionManager#getTagreturns a list of command functions
net.minecraft.server.levelChunkHolderblockChanged,sectionLightChangednow returnsbooleanif the information has changedaddSaveDependencyis now protected, a method withinGenerationChunkHolder
ChunkTaskPriorityQueueno longer takes in a generic- The constructor no longer takes in the maximum number of tasks to do
submitnow takes in aRunnablerather than anOptionalpopreturns a$TasksForChunkinstead of a rawStream
ChunkTaskPriorityQueueSorter->ChunkTaskDispatcherServerPlayerteleportTotakes in abooleanthat determines whether the camera should be setINTERACTION_DISTANCE_VERIFICATION_BUFFER->BLOCK_INTERACTION_DISTANCE_VERIFICATION_BUFFER- Also splits into
ENTITY_INTERACTION_DISTANCE_VERIFICATION_BUFFERset to 3.0
- Also splits into
findRespawnPositionAndUseSpawnBlocknow deals withTeleportTransition
TextFilterClient->ServerTextFilterThreadedLevelLightEnginenow takes in aConsecutiveExecutorandChunkTaskDispatcherinstead of aProcessorMailboxand aProcessorHandle, respectively
net.minecraft.server.packs.resources.ProfiledReloadInstance$Stateis now a recordnet.minecraft.sounds.SoundEventis now a recordnet.minecraft.tagsTagEntry$Lookup#elementnow takes in abooleanrepresenting if the element is requiredTagLoadernow takes in an$ElementLookup, which functions the same as its previous function parameterbuildnow returns a value of listsloadAndBuild->loadTagsFromNetwork,loadTagsForExistingRegistries,loadTagsForRegistry,buildUpdatedLookups
TagNetworkSerialization$NetworkPayloadsize->isEmptyapplyToRegistry->resolve
net.minecraft.utilFastColor->ARGBscaleRGBoverload with an alpha integer and three floats.
Mth#color->ARGB#color
net.minecraft.util.profiling.metrics.MetricCategory#MAIL_BOXES->CONSECUTIVE_EXECUTORSnet.minecraft.util.threadBlockableEventLoop#waitForTasksis now protectedProcessorMailboxno longer implementsAutoCloseable
net.minecraft.util.worldupdate.WorldUpgraderimplementsAutoCloseablenet.minecraft.world.LockCodenow takes in anItemPredicateinstead of aStringrepresenting the item nameaddToTag,fromTagnow takes in aHolderLookup$Provider
net.minecraft.world.effectMobEffect#applyEffectTick,applyInstantenousEffect,onMobRemoved,onMobHurtnow takes in theServerLevelMobEffectInstance#onMobRemoved,onMobHurtnow takes in theServerLevel
net.minecraft.world.entityAgeableMob$AgeableMobGroupDatanow has a public constructorAnimationState#getAccumulatedTime->getTimeInMillisEntityno longer implementsCommandSourcesetOnGroundWithMovementnow takes in an additionalbooleanrepresenting whether there is any horizontal collision.getInputVectoris now protectedisAlliedTo(Entity)->considersEntityAsAllyteleportTonow takes in an additionalbooleanthat determines whether the camera should be setcheckInsideBlocks()->recordMovementThroughBlocks, not one-to-one as it takes in the movement vectorscheckInsideBlocks(Set<BlockState>)->collectBlockCollidedWith, now privatekillnow takes in theServerLevelhurthas been marked as deprecated, to be replaced byhurtServerandhurtClienthurtOrSimulateacts as a helper to determine which to call, also marked as deprecated
spawnAtLocationnow takes in aServerLevelisInvulnerableTo->isInvulnerableToBase, now protected and finalisInvulnerableTois moved toLivingEntity#isInvulnerableTo
teleportSetPositionnow public and takes in aPositionMoveRotationandRelativeset instead of theDimensionTransitioncreateCommandSourceStack->createCommandSourceStackForNameResolution, not one to one as it takes in theServerLevelmayInteractnow takes in theServerLevelinstead of just theLevelsetOldRotis now publicchangeDimension->teleport, returnsServerPlayergivenTeleportTransitioncanChangeDimensions->canTeleport
EntitySpawnReason#SPAWN_EGG->SPAWN_ITEM_USE, not one-to-one as this indicates the entity can be spawned from any itemEntityTypecreate,loadEntityRecursive,loadEntitiesRecursive,loadStaticEntitynow takes in anEntitySpawnReason*StackConfignow takes in aLevelinstead of aServerLevel
EquipmentTablenow has a constructor that takes in a single float representing the slot drop chance for all equipment slotsMobSpawnType->EntitySpawnReasonLeashable#tickLeashnow takes in theServerLevelLivingEntitygetScaleis now finalonAttributeUpdatedis now protectedactiveLocationDependentEnchantmentsnow takes in anEquipmentSlothandleRelativeFrictionAndCalculateMovementis now privateupdateFallFlyingis now protectedonEffectRemoved->onEffectsRemovedspawnItemParticlesis now publicgetLootTable->Entity#getLootTable, wrapped in optionalgetBaseExperienceRewardnow takes in theServerLeveltriggerOnDeathMobEffectsnow takes in theServerLevelcanAttackis removeddropEquipmentnow takes in theServerLeveldropExperiencenow takes in theServerLeveldropFromLootTablenow takes in theServerLevelactuallyHurt,doHurtTargetnow takes in theServerLevelhasLineOfSightoverload with clip contexts and a eye y suppliermakePoofParticlesis now public
MobpickUpItem,wantsToPickUpnow takes in theServerLevelequipItemIfPossiblenow takes in theServerLevelcustomServerAiStepnow takes in theServerLeveldropPreservedEquipmentnow takes in theServerLevel
NeutralMobisAngryAt,isAngryAtAllPlayersnow takes in theServerLevelplayerDiednow takes in theServerLevel
PortalProcessor#getPortalDestinationnow returns aTeleportTransitionPositionMoveRotationof(ClientboundPlayerPositionPacket)->ofEntityUsingLerpTarget(Entity)of(DimensionTransition)->of(TeleportTransition)
Shearable#shearnow takes in theServerLevelandItemStackthat is shearing the entityRelativeMovement->Relative, expanded to contain delta movementWalkAnimationState#updatenow takes in an additionalfloatrepresenting the position scale when moving.
net.minecraft.world.entity.ai.behaviorStartAttackingnow takes in a$TargetFinderand additionally a$StartAttackingCondition- Both are functional interfaces that replace the previous functions/predicates, though with an extra
ServerLevelparameter
- Both are functional interfaces that replace the previous functions/predicates, though with an extra
StopAttackingIfTargetInvalidnow takes in a$TargetErasedCallbackand/or a$StopAttackCondition- Both are functional interfaces that replace the previous consumers/predicates, though with an extra
ServerLevelparameter
- Both are functional interfaces that replace the previous consumers/predicates, though with an extra
MeleeAttack#createcan now take in a predicate to test the mob forSwimnow takes in a generic representing the mob
net.minecraft.world.entity.ai.control.LookControl#rotateTowards->Control#rotateTowardsnet.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoalnow takes in a$Selector- It is a functional interface that replaces the previous predicate, though with an extra
ServerLevelparameter
- It is a functional interface that replaces the previous predicate, though with an extra
net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntitiesnow takes in aServerLevelnet.minecraft.world.entity.ai.sensingNearestLivingEntitySensorradiusXZ,radiusY->Attributes#FOLLOW_RANGEisMatchingEntitynow takes in aServerLevel
SensorTARGETING_RANGEis now privateisEntityTargetable,isEntityAttackable,isEntityAttackableIgnoringLineOfSightnow take in aServerLevelwasEntityAttackableLastNTicks,rememberPositivesnow delas withBiPredicates instead ofPredicates
net.minecraft.world.entity.ai.targeting.TargetingConditionsselectornow takes in a$Selector- It is a functional interface that replaces the previous predicate, though with an extra
ServerLevelparameter
- It is a functional interface that replaces the previous predicate, though with an extra
testnow takes in aServerLevel
net.minecraft.world.entity.ai.village.poi.PoiRecord#codec,PoiSection#codec->$Packed#CODECnet.minecraft.world.entity.animalFox$Type->$VariantMushroomCow$MushroomType->$Variant$Variantno longer takes in the loot table
Salmonnow has a variant for its sizeWolfgetBodyRollAngle->#getShakeAnim, not one-to-one as the angle is calculated within the render statehasArmoris removed
net.minecraft.world.entity.animal.horse.AbstractHorse#followMommynow takes in aServerLevelnet.minecraft.world.entity.boss.enderdragon.EnderDragon#onCrystalDestroyednow takes in aServerLevelnet.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance#doServerTicknow takes in aServerLevelnet.minecraft.world.entity.boss.wither.WitherBoss#getHead*Rot->getHead*Rots, returns all rotations rather than just the provided indexnet.minecraft.world.entity.decorationArmorStanddefault rotations are now publicisShowArms->showArmsisNoBasePlate->showBasePlate
PaintingVariantnow takes in a title and authorComponent
net.minecraft.world.entity.item.ItemEntity#getSpinis now staticnet.minecraft.world.entity.monster.Monster#isPreventingPlayerRestnow takes in aServerLevelnet.minecraft.world.entity.monster.breeze.Breeze#getSnoutYPosition->getFiringYPositionnet.minecraft.world.entity.monster.hoglin.HoglinBase#hurtAndThrowTargetnow takes in aServerLevelnet.minecraft.world.entity.monster.piglin.PiglinAi#isWearingGold->#isWearingSafeArmornet.minecraft.world.entity.npc.InventoryCarrier#pickUpItemnow takes in aServerLevelnet.minecraft.world.entity.playerPlayer#disableShieldnow takes in the stack to apply the cooldown toInventoryfindSlotMatchingUnusedItem->findSlotMatchingCraftingIngredientswapPaint->setSelectedHotbarSlotStackedContents->StackedItemContents
net.minecraft.world.entity.projectileAbstractArrow#inGround->IN_GROUND, now anEntityDataAccessor- Protected accessible via
isInGroundandsetInGround
- Protected accessible via
ThrowableItemProjectilecan now take in anItemStackof the item thrown
net.minecraft.world.entity.raid.Raid#getLeaderBannerInstance->getOminousBannerInstancenet.minecraft.world.entity.vehicleBoat$Typenow takes in the supplied boat item and the translation key for the item, but no longer take in the planks they are made fromContainerEntity*LootTable*->ContainerLootTablechestVehicleDestroyednow takes in aServerLevel
VehicleEntitydestroynow takes in aseerverLevelgetDropItemis now protected
net.minecraft.world.itemBoatItemnow takes in anEntityTypeinstead of the variant and chest booleanItemStack#hurtEnemy,postHurtEnemynow take in aLivingEntityinstead of aPlayerSmithingTemplateItemnow takes in theItem.Propertiesinstead of hardcoding it, also true for static initializersUseAnim->ItemUseAnimation
net.minecraft.world.item.crafting.ShulkerBoxColoring->TransmuteRecipe, expanded to copy any data stored on the item to the result itemnet.minecraft.world.item.enchantment.EnchantmentHelperonProjectileSpawnednow takes in aProjectileinstead of anAbstractArrow
net.minecraft.world.item.enchantment.effects.DamageItem->ChangeItemDamagenet.minecraft.world.levelGameRulestakes in aFeatureFlagSetduring any kind of construction$IntegerValue#createtakes in aFeatureFlagSet$Typetakes in aFeatureFlagSet
LevelsetSpawnSettingsno longer takes in abooleanto determine whether to spawn friendliesgetGameRules->ServerLevel#getGameRules
LevelAccessornow implementsScheduledTickAccess, an interface that now contains the tick scheduling methods that were originally onLevelAccessorneighborShapeChangedswitches the order of theBlockStateand neighborBlockPosparameters
LevelHeightAccessorgetMinBuildHeight->getMinYgetMaxBuildHeight->getMaxY, this value is one less than the previous versiongetMinSection->getMinSectionYgetMaxSection->getMaxSectionY, this value is one less than the previous version
NaturalSpawner#spawnForChunkhas been split into two methods:getFilteredSpawningCategories, andspawnForChunk
net.minecraft.world.level.biome#Biome#getPrecipitationAt,coldEnoughToSnow,warmEnoughToRain,shouldMeltFrozenOceanIcebergSlightlynow takes in anintrepresenting the the base height of the biomenet.minecraft.world.level.blockBlockshouldRenderFacetakes in the relative state for the face being checked, no longer passing in theBlockGetterorBlockPoss.updateEntityAfterFallOn->updateEntityMovementAfterFallOn$BlockStatePairKey->FlowingFluid$BlockStatePairKey, now package privategetDescriptionId->BlockBehaviour#getDescriptionId, also a protected fielddescriptionId
ChestBlockconstructor switched its parameter orderPortal#getPortalDestinationnow returnsTeleportTransition
net.minecraft.world.level.block.entityAbstractFurnaceBlockEntity#serverTicknow takes in aServerLevelinstead of aLevelBrushableBlockEntitybrushnow takes in the level and stack performing the brushing behaviorunpackLootTableis now privatecheckResetnow takes in the server level
net.minecraft.world.level.block.stateBlockBehaviourgetOcclusionShape,getLightBlock,propagatesSkylightDownonly takes in theBlockState, not theBlockGetterorBlockPosgetLootTablenow returns anOptional, also a protected fielddrops$BlockStateBase#getOcclusionShape,getLightBlock,getFaceOcclusionShape,propagatesSkylightDown,isSolidRenderno longer takes in theBlockGetterorBlockPos$BlockStateBase#getOffsetno longer takes in theBlockGetter$OffsetFunction#evaluateno longer takes in theBlockGetter$Properties#dropsLike->overrideLootTable
StateHolder#findNextInCollectionnow takes in aListinstead of aCollection
net.minecraft.world.level.chunkChunkAccessaddPackedPostProcessnow takes in aShortListinstead of a singleshortgetTicksForSerializationnow takes in alongof the game timeunsavedis now privatesetUnsaved->markUnsaved,tryMarkSaved$TicksToSave->$PackedTicks
ChunkSource#setSpawnSettingsno longer takes in abooleanto determine whether to spawn friendliesLevelChunk#postProcessGenerationnow takes in aServerLevelPalette#copynow takes in aPaletteResize
net.minecraft.world.level.chunk.status.WorldGenContextnow takes in anExecutoror the main thread rather than a processor handle mail box- The construtor also takes in a
LevelChunk$UnsavedListenerfor when a chunk is marked as dirty
- The construtor also takes in a
net.minecraft.world.level.chunk.storageChunkSerializer->SerializableChunkDataChunkStorage#writenow takes in a suppliedCompoundTaginstead of the instance itselfSectionStoragenow takes in a second generic representing the packed form of the storage data- The constructor now takes in the packed codec, a function to convert the storage to a packed format, and a function to convert the packed and dirty runnable back into the storage.
net.minecraft.world.level.levelgenAquifer$FluidStatusis now a recordWorldDimensions#withOverworldnow takes in aHolderLookupinstead of theRegistryitselfBlendingDatanow has a packed and unpacked state for serializing the interal data as a simple object
net.minecraft.world.level.levelgen.material.MaterialRuleListnow takes in an array instead of a listnet.minecraft.world.level.levelgen.placement.PlacementContext#getMinBuildHeight->getMinYnet.minecraft.world.level.levelgen.structure.pools.StructurePoolElement#getShuffledJigsawBlocksnow returns aStructureTemplate$JigsawBlockInfonet.minecraft.world.level.lightingLevelLightEngine#lightOnInSection->lightOnInColumnLightEnginehasDifferentLightProperties,getOcclusionShapeno longer takes in theBlockGetterorBlockPosgetOpacityno longer takes in theBlockPosshapeOccludesno longer takes in the twolongsrepresenting the packed positions
net.minecraft.world.level.materialFlowingFluidspreadnow takes in theBlockStateat the current positiongetSlopeDistanceprevious parameters have been merged into a$SpreadContextobjectspread,getNewLiquid,canConvertToSource,getSpreadnow takes in aServerLevel
Fluidticknow takes in theBlockStateat the current positiontickandrandomTicknow take in theServerLevel
FluidStateticknow takes in theBlockStateat the current positiontickandrandomTicknow take in theServerLevel
MapColor#calculateRGBColor->calculateARGBColor
net.minecraft.world.level.portalDimensionTransition->TeleportTransitionpos->positionspeed->deltaMovement- The constructor can now take in a set of
Relativesto indicate in what motions should the positions be moved relative to another
PortalShape#createPortalBlocksnow takes in aLevelAccessor
net.minecraft.world.level.saveddata.SavedData#save(File, HolderLookup$Provider)now returnsCompoundTag, not writing the data to file in the methodnet.minecraft.world.level.storageDimensionDataStoragenow implementsAutoCloseable- The constructor takes in a
Pathinstead of aFile save->scheduleSaveandsaveAndJoin
- The constructor takes in a
LevelData#getGameRules->ServerLevelData#getGameRules
net.minecraft.world.phys.BlockHitResultnow takes in a boolean representing if the world border was hit- Adds in two helpers
hitBorder,isWorldBorderHit
- Adds in two helpers
net.minecraft.world.ticksProtoChunkTicks#loadnow takes in a list of saved ticksSavedTick#loadTickListnow returns a list of saved ticks, rather than consuming themSerializableTickContainer#save->pack
List of Removals
com.mojang.blaze3d.Blaze3Dprocessrender
com.mojang.blaze3d.pipeline.RenderPipeline- Replaced by
com.mojang.blaze3d.framegraph.*andcom.mojang.blaze3d.resources.*
- Replaced by
com.mojang.blaze3d.platform.NativeImagesetPixelLuminancegetRedOrLuminance,getGreenOrLuminance,getBlueOrLuminanceblendPixelasByteArray
com.mojang.blaze3d.systems.RenderSystemglGenBuffersglGenVertexArrays_setShaderTextureapplyModelViewMatrix
net.minecraft.Util#wrapThreadWithTaskName(String, Supplier)net.minecraft.advancements.critereon.EntitySubPredicates#BOATnet.minecraft.client.Options#setKeynet.minecraft.client.gui.screens.inventory.EnchantmentScreen#timenet.minecraft.client.multiplayerClientCommonPacketListenerImpl#strictErrorHandlingClientLevel#isLightUpdateQueueEmptyCommonListenerCookie#strictErrorHandling
net.minecraft.client.particle.ParticleRenderType#PARTICLE_SHEET_LITnet.minecraft.client.rendererGameRenderer#resetProjectionMatrixLevelRendererplayJukeboxSongclear
PostChaingetTempTarget,addTempTarget
PostPasssetOrthoMatrixgetFilterMode
net.minecraft.client.renderer.block.model.BlockModel#fromStringnet.minecraft.client.renderer.textureAbstractTexture#blur,mipmapTextureManager#bindForSetup
net.minecraft.commands.arguments.coordinates.WorldCoordinates#currentnet.minecraft.coreDirection#fromDeltaRegistry#getOrCreateTag,getTagNames,resetTags
net.minecraft.server.MinecraftServerisSpawningAnimalsareNpcsEnabled
net.minecraft.server.levelGenerationChunkHolder#getGenerationRefCountServerPlayersetPlayerInputteleportTo(ServerLevel, double, double, double, float, float, boolean)
net.minecraft.tagsTagManagerTagManagerSerialization$TagOutput
net.minecraft.world.entityAnimationState#updateTimeEntitywalkDist0,walkDistwasOnFiretryCheckInsideBlocks
EntitySelector$MobCanWearArmorEntitySelector
net.minecraft.world.entity.ai.sensingBreezeAttackEntitySensor#BREEZE_SENSOR_RADIUSTemptingSensor#TEMPTATION_RANGE
net.minecraft.world.entity.animalCat#getTextureIdSquid#setMovementVectorWolf#isWet
net.minecraft.world.entity.boss.dragon.EnderDragongetLatencyPosgetHeadPartYOffset
net.minecraft.world.entity.monster.Zombie#supportsBreakDoorGoalnet.minecraft.world.entity.npc.Villager#setChasing,isChasingnet.minecraft.world.entity.projectileAbstractArrow#shotFromCrossbowThrowableProjectile(EntityType, LivingEntity, Level)
net.minecraft.world.itemBannerPatternItem#getDisplayNameItemStack#LIST_STREAM_CODEC
net.minecraft.world.level.BlockGetter#getMaxLightLevelnet.minecraft.world.level.block.entity.JigsawBlockEntity$JointType#byNamenet.minecraft.world.level.block.state.BlockBehaviour#isOcclusionShapeFullBlocknet.minecraft.world.level.chunk.ChunkAccess#setBlendingDatanet.minecraft.world.level.storage.loot.LootDataType#deserializenet.minecraft.world.phys.AABB#getBottomCenternet.minecraft.world.phys.shapes.Shapes#getFaceShapenet.minecraft.world.ticks.SavedTick#saveTick
Minecraft 1.21.2/3 -> 1.21.4 Mod Migration Primer
This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.2/3 to 1.21.4. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.
This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.
If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.
Pack Changes
There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.
Client Items
Minecraft has moved the lookup and definition of how an item should be rendered to its own data generated system, which will be referred to as Client Items, located at assets/<namespace>/items/<path>.json. Client Items is similar to the block state model definition, but has the potential to have more information enscribed in the future. Currently, it functions as simply a linker to the models used for rendering.
All client items contain some ItemModel$Unbaked using the model field. Each unbaked model has an associated type, which defines how the item should be set up for rendering, or rendered in one specific case. These types can be found within ItemModels. This primer will review all but one type, as that unbaked model type is specifically for bundles when selecting an item.
The item also contains a properties field which holds some metadata-related parameters. Currently, it only specifies a boolean that, when false, make the hand swap the currently held item instantly rather than animate the hand coming up.
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "" // Set type here
// Add additional parameters
},
"properties": {
// When false, disables animation when swapping this item into the hand
"hand_animation_on_swap": false
}
}
A Basic Model
The basic model definition is handled by the minecraft:model type. This contains two fields: model, to define the relative location of the model JSON, and an optional list of tints, to define how to tint each index.
model points to the model JSON, relative to assets/<namespace>/models/<path>.json. In most instances, a client item defintion will look something like this:
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "minecraft:model",
// Points to 'assets/examplemod/models/item/example_item.json'
"model": "examplemod:item/example_item"
}
}
Tint Sources
In model JSONs, some element faces will have a tintindex field which references some index into the tints list in the minecraft:model unbaked model type. The list of tints are ItemTintSources, which are all defined in net.minecraft.client.color.item.*. All defined tint sources can be found within ItemTintSources, like minecraft:constant for a constant color, or minecraft:dye, to use the color of the DataComponents#DYED_COLOR or default if not present. All tint sources must return an opaque color, though all sources typically apply this by calling ARGB#opaque.
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "minecraft:model",
// Points to 'assets/examplemod/models/item/example_item.json'
"model": "examplemod:item/example_item",
// A list of tints to apply
"tints": [
{
// For when tintindex: 0
"type": "minecraft:constant",
// 0x00FF00 (or pure green)
"value": 65280
},
{
// For when tintindex: 1
"type": "minecraft:dye",
// 0x0000FF (or pure blue)
// Only is called if `DataComponents#DYED_COLOR` is not set
"default": 255
}
]
}
}
To create your own ItemTintSource, you need to implement the calculate method register the MapCodec associated for the type field. calculate takes in the current ItemStack, level, and holding entity and returns an RGB integer with an opaque alpha, defining how the layer should be tinted.
Then, the MapCodec needs to be registered to ItemTintSources#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied.
// The item source class
public record FromDamage(int defaultColor) implements ItemTintSource {
public static final MapCodec<FromDamage> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
instance.group(
ExtraCodecs.RGB_COLOR_CODEC.fieldOf("default").forGetter(FromDamage::defaultColor)
).apply(instance, FromDamage::new)
);
public FromDamage(int defaultColor) {
this.defaultColor = ARGB.opaque(defaultColor);
}
@Override
public int calculate(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity) {
return stack.isDamaged() ? ARGB.opaque(stack.getBarColor()) : defaultColor;
}
@Override
public MapCodec<FromDamage> type() {
return MAP_CODEC;
}
}
// Then, in some initialization location where ItemTintSources#ID_MAPPER is exposed
ItemTintSources.ID_MAPPER.put(
// The registry name
ResourceLocation.fromNamespaceAndPath("examplemod", "from_damage"),
// The map codec
FromDamage.MAP_CODEC
);
// For some object in the 'tints' array
{
"type": "examplemod:from_damage",
// 0x0000FF (or pure blue)
// Only is called if the item has not been damaged yet
"default": 255
}
Ranged Property Model
Ranged property models, as defined by the minecraft:range_dispatch unbaked model type, are the most similar to the previous item override system. Essentially, the type defines some item property that can be scaled along with a list of thresholds and associated models. The model chosen is the one with the closest threshold value that is not over the property (e.g. if the property value is 4 and we have thresholds 3 and 5, 3 would be chosen as it is the cloest without going over). The item property is defined via a RangeSelectItemModelProperty, which takes in the stack, level, entity, and some seeded value to get a float, usually scaled betwen 0 and 1 depending on the implementation. All properties can be found within net.minecraft.client.renderer.item.properties.numeric.* and are registered in RangeSelectItemModelProperties, such as minecraft:cooldown, for the cooldown percentage, or minecraft:count, for the current number of items in the stack or percentage of the max stack size when normalized.
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "minecraft:range_dispatch",
// The `RangeSelectItemModelProperty` to use
"property": "minecraft:count",
// A scalar to multiply to the computed property value
// If count was 0.3 and scale was 0.2, then the threshold checked would be 0.3*0.2=0.06
"scale": 1,
"fallback": {
// The fallback model to use if no threshold matches
// Can be any unbaked model type
"type": "minecraft:model",
"model": "examplemod:item/example_item"
},
// ~~ Properties defined by `Count` ~~
// When true, normalizes the count using its max stack size
"normalize": true,
// ~~ Entries with threshold information ~~
"entries": [
{
// When the count is a third of its current max stack size
"threshold": 0.33,
"model": {
// Can be any unbaked model type
}
},
{
// When the count is two thirds of its current max stack size
"threshold": 0.66,
"model": {
// Can be any unbaked model type
}
}
]
}
}
To create your own RangeSelectItemModelProperty, you need to implement the get method register the MapCodec associated for the type field. get takes in the stack, level, entity, and seeded value and returns an arbitrary float to be interpreted by the ranged dispatch model.
Then, the MapCodec needs to be registered to RangeSelectItemModelProperties#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied.
// The ranged property class
public record AppliedEnchantments() implements RangeSelectItemModelProperty {
public static final MapCodec<AppliedEnchantments> MAP_CODEC = MapCodec.unit(new AppliedEnchantments());
@Override
public float get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) {
return (float) stack.getEnchantments().size();
}
@Override
public MapCodec<AppliedEnchantments> type() {
return MAP_CODEC;
}
}
// Then, in some initialization location where RangeSelectItemModelProperties#ID_MAPPER is exposed
RangeSelectItemModelProperties.ID_MAPPER.put(
// The registry name
ResourceLocation.fromNamespaceAndPath("examplemod", "applied_enchantments"),
// The map codec
AppliedEnchantments.MAP_CODEC
);
// For some client item in 'model'
{
"type": "minecraft:range_dispatch",
// The `RangeSelectItemModelProperty` to use
"property": "examplemod:applied_enchantments",
// A scalar to multiply to the computed property value
"scale": 0.5,
"fallback": {
// The fallback model to use if no threshold matches
// Can be any unbaked model type
"type": "minecraft:model",
"model": "examplemod:item/example_item"
},
// ~~ Properties defined by `AppliedEnchantments` ~~
// N/A (no arguments to constructor)
// ~~ Entries with threshold information ~~
"entries": [
{
// When there is one enchantment present
// Since 1 * the scale 0.5 = 0.5
"threshold": 0.5,
"model": {
// Can be any unbaked model type
}
},
{
// When there are two enchantments present
"threshold": 1,
"model": {
// Can be any unbaked model type
}
}
]
}
Select Property Model
Select property models, as defined by the minecraft:select unbaked model type, are functionally similar to ranged property models, except now it switches on some property, typically an enum. The item property is defined via a SelectItemModelProperty, which takes in the stack, level, entity, some seeded value, and the current display context to get one of the property values. All properties can be found within net.minecraft.client.renderer.item.properties.select.* and are registered in SelectItemModelProperties, such as minecraft:block_state, for the stringified value of a specified block state property, or minecraft:display_context, for the current ItemDisplayContext.
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "minecraft:select",
// The `SelectItemModelProperty` to use
"property": "minecraft:display_context",
"fallback": {
// The fallback model to use if no threshold matches
// Can be any unbaked model type
"type": "minecraft:model",
"model": "examplemod:item/example_item"
},
// ~~ Properties defined by `DisplayContext` ~~
// N/A (no arguments to constructor)
// ~~ Switch cases based on Selectable Property ~~
"cases": [
{
// When the display context is `ItemDisplayContext#GUI`
"when": "gui",
"model": {
// Can be any unbaked model type
}
},
{
// When the display context is `ItemDisplayContext#FIRST_PERSON_RIGHT_HAND`
"when": "firstperson_righthand",
"model": {
// Can be any unbaked model type
}
}
]
}
}
To create your own SelectItemModelProperty, you need to implement the get method register the SelectItemModelProperty$Type associated for the type field. get takes in the stack, level, entity, seeded value, and display context and returns an encodable object to be interpreted by the select model.
Then, the MapCodec needs to be registered to SelectItemModelProperties#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied.
// The select property class
public record StackRarity() implements SelectItemModelProperty<Rarity> {
public static final SelectItemModelProperty.Type<StackRarity, Rarity> TYPE = SelectItemModelProperty.Type.create(
// The map codec for this property
MapCodec.unit(new StackRarity()),
// The codec for the object being selected
Rarity.CODEC
);
@Nullable
@Override
public Rarity get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed, ItemDisplayContext displayContext) {
// When null, uses the fallback model
return stack.get(DataComponents.RARITY);
}
@Override
public SelectItemModelProperty.Type<StackRarity, Rarity> type() {
return TYPE;
}
}
// Then, in some initialization location where SelectItemModelProperties#ID_MAPPER is exposed
SelectItemModelProperties.ID_MAPPER.put(
// The registry name
ResourceLocation.fromNamespaceAndPath("examplemod", "rarity"),
// The property type
StackRarity.TYPE
);
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "minecraft:select",
// The `SelectItemModelProperty` to use
"property": "examplemod:rarity",
"fallback": {
// The fallback model to use if no threshold matches
// Can be any unbaked model type
"type": "minecraft:model",
"model": "examplemod:item/example_item"
},
// ~~ Properties defined by `StackRarity` ~~
// N/A (no arguments to constructor)
// ~~ Switch cases based on Selectable Property ~~
"cases": [
{
// When rarity is `Rarity#UNCOMMON`
"when": "uncommon",
"model": {
// Can be any unbaked model type
}
},
{
// When rarity is `Rarity#RARE`
"when": "rare",
"model": {
// Can be any unbaked model type
}
}
]
}
}
Conditional Property Model
Conditional property models, as defined by the minecraft:condition unbaked model type, are functionally similar to ranged property models, except now it switches on boolean. These are usually combined with range dispatch, such as when pulling the bow. The item property is defined via a ConditionalItemModelProperty, which takes in the stack, level, entity, some seeded value, and the current display context to get a true of false statement. All properties can be found within net.minecraft.client.renderer.item.properties.conditional.* and are registered in ConditionalItemModelProperties, such as minecraft:damaged, for if the item is damaged, or minecraft:has_component, if it has a given data component.
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "minecraft:condition",
// The `SelectItemModelProperty` to use
"property": "minecraft:damaged",
// ~~ Properties defined by `Damaged` ~~
// N/A (no arguments to constructor)
// ~~ What the boolean outcome is ~~
"on_true": {
// Can be any unbaked model type
},
"on_false": {
// Can be any unbaked model type
}
}
}
To create your own ConditionalItemModelProperty, you need to implement the get method register the MapCodec associated for the type field. get takes in the stack, level, entity, seeded value, and display context and returns a boolean to be interpreted by on_true and on_false, respectively.
Then, the MapCodec needs to be registered to ConditionalItemModelProperties#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied.
// The predicate property class
public record TimePeriod(int month, MinMaxBounds.Ints dates, boolean enabled) implements ConditionalItemModelProperty {
public static final MapCodec<TimePeriod> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
instance.group(
Codec.intRange(1, 12).fieldOf("month").forGetter(TimePeriod::month),
MinMaxBounds.Ints.CODEC.fieldOf("dates").forGetter(TimePeriod::dates)
).apply(instance, TimePeriod::new)
);
public TimePeriod(int month, MinMaxBounds.Ints dates) {
this.month = month;
this.dates = dates;
Calendar cal = Calendar.getInstance();
this.enabled = cal.get(Calendar.MONTH) + 1 == this.month
&& this.dates.matches(cal.get(Calendar.DATE));
}
@Override
public boolean get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed, ItemDisplayContext context) {
return this.enabled;
}
@Override
public MapCodec<TimePeriod> type() {
return MAP_CODEC;
}
}
// Then, in some initialization location where ConditionalItemModelProperties#ID_MAPPER is exposed
ConditionalItemModelProperties.ID_MAPPER.put(
// The registry name
ResourceLocation.fromNamespaceAndPath("examplemod", "time_period"),
// The map codec
TimePeriod.MAP_CODEC
);
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "minecraft:condition",
// The `SelectItemModelProperty` to use
"property": "examplemod:time_period",
// ~~ Properties defined by `TimePeriod` ~~
// Month of July
"month": 7,
"dates": {
// Between July 1st - 14th
"min": 1,
"max": 14
},
// ~~ What the boolean outcome is ~~
"on_true": {
// Can be any unbaked model type
},
"on_false": {
// Can be any unbaked model type
}
}
}
Composite Model
Composite models, defined by minecraft:composite, are essentially a combination of other model types to render. Specifically, this sets up multiple players to overlay models on top of one another when rendering.
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "minecraft:composite",
// Will render in the order they appear in the list
"models": [
{
// Can be any unbaked model type
},
{
// Can be any unbaked model type
}
]
}
}
Special Dynamic Models
Special dynamic models, as defined by the minecraft:special unbaked model type, are the new system for block entity without level renderers (e.g., chests, banners, and the like). Instead of storing a baked model, these provide a render method to call. The special model wrapper takes in a base model used for grabbing the basic model settings (not the elements) and a SpecialModelRenderer. All special model renderers can be found within net.minecraft.client.renderer.special.* and are registered in SpecialModelRenderers.
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "minecraft:special",
// The model to read the particle texture and display transformation from
"base": "minecraft:item/template_skull",
"model": {
// The special model renderer to use
"type": "minecraft:head",
// ~~ Properties defined by `SkullSpecialRenderer.Unbaked` ~~
// The type of the skull block
"kind": "wither_skeleton"
}
}
}
To create your own SpecialModelRenderer, you need to implement both the renderer and the $Unbaked model to read the data from the JSON. The $Unbaked model creates the SpecialModelRenderer via bake and is registered using a MapCodec for its type. The SpecialModelRenderer then extracts the necessary data from the stack needed to render via extractArgument and passes that to the render method. If you do not need any information from the stack, you can implement NoDataSpecialModelRenderer instead.
Then, the MapCodec needs to be registered to SpecialModelRenderers#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied.
If your item is a held block, it also needs to be added to the SpecialModelRenderers#STATIC_BLOCK_MAPPING for specific rendering scenarios via BlockRenderDispatcher#renderSingleBLock (e.g. in minecart, or picked up by endermen). Both the default model renderer and the special model renderer are called in this method; allowing for both the static block model and the dynamic special model to be rendered at the same time. As this map is immutable, you will either need to replace it or hook into SpecialBlockModelRenderer and somehow add to the stored map there.
// The special renderer
public record SignSpecialRenderer(WoodType defaultType, Model model) implements SpecialModelRenderer<WoodType> {
// Render the model
@Override
public void render(@Nullable WoodType type, ItemDisplayContext displayContext, PoseStack pose, MultiBufferSource bufferSource, int light, int overlay, boolean hasFoil) {
VertexConsumer consumer = Sheets.getSignMaterial(type).buffer(bufferSource, this.model::renderType);
this.model.renderToBuffer(pose, consumer, light, overlay);
}
// Get the wood type from the stack
@Nullable
@Override
public WoodType extractArgument(ItemStack stack) {
return (stack.getItem() instanceof BlockItem item && item.getBlock() instanceof SignBlock sign)
? sign.type() : this.defaultType;
}
// The model to read the json from
public static record Unbaked(WoodType defaultType) implements SpecialModelRenderer.Unbaked {
public static final MapCodec<SignSpecialRenderer.Unbaked> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
instance.group(
WoodType.CODEC.fieldOf("default").forGetter(SignSpecialRenderer.Unbaked::defaultType)
).apply(instance, SignSpecialRenderer.Unbaked::new)
);
// Create the special model renderer, or null if it fails
@Nullable
@Override
public SpecialModelRenderer<?> bake(EntityModelSet modelSet) {
return new SignSpecialRenderer(
this.defaultType,
SignRenderer.createSignModel(modelSet, defaultType, true)
)
}
@Overrides
public MapCodec<SignSpecialRenderer.Unbaked> type() {
return MAP_CODEC;
}
}
}
// Then, in some initialization location where SpecialModelRenderers#ID_MAPPER is exposed
SpecialModelRenderers.ID_MAPPER.put(
// The registry name
ResourceLocation.fromNamespaceAndPath("examplemod", "sign"),
// The map codec
SignSpecialRenderer.Unbaked.MAP_CODEC
);
// Let assume we can add directly to SpecialModelRenderers#STATIC_BLOCK_MAPPING as well
// We'll have a Block EXAMPLE_SIGN
SpecialModelRenderers.STATIC_BLOCK_MAPPING.put(
// The block with a special rendering as an item
EXAMPLE_SIGN,
// The unbaked renderer to use
new SignSpecialRenderer.Unbaked(WoodType.BAMBOO)
);
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "minecraft:special",
// The model to read the particle texture and display transformation from
"base": "minecraft:item/bamboo_sign",
"model": {
// The special model renderer to use
"type": "examplemod:sign",
// ~~ Properties defined by `SignSpecialRenderer.Unbaked` ~~
// The default wood type if none can be found
"default": "bamboo"
}
}
}
Rendering an Item
Rendering an item is now done through the ItemModelResolver and ItemStackRenderState. This is similar to how the EntityRenderState works: first, the ItemModelResolver sets up the ItemStackRenderState, then the state is rendered via ItemStackRenderState#render.
Let’s start with the ItemStackRenderState. For rendering, the only one we care about the following methods: isEmpty, isGui3d, usesBlockLight, transform, and render. isEmpty is used to determine whether the stack should render at all. Then isGui3d, usesBlockLight, and transform are used in their associated contexts to properly position the stack to render. Finally, render takes in the pose stack, buffer source, packed light, and overlay texture to render the item in its appropriate location.
ItemModelResolver is responsible for setting the information on the ItemStackRenderState needed to render. This is done through updateForLiving for items held by living entities, updateForNonLiving for items held by other kinds of entities, and updateforTopItem, for all other scenarios. updateForItem, which the previous two methods delegate to, take in the render state, the stack, the display context, if the stack is in the left hand, the level, the entity, and some seeded value. This will effectively clear the previous state via ItemStackRenderState#clear and then set up the new state via a delegate to ItemModel#update. The ItemModelResolver can always be obtained via Minecraft#getItemModelResolver, if you are not within a renderer context (e.g., block entity, entity).
// In its most simple form, assuming you are not doing any transformations (which you should as necessary)
public class ExampleRenderer {
private final ItemStackRenderState state = new ItemStackRenderState();
public void render(ItemStack stack, Level level, PoseStack pose, MultiBufferSource bufferSource) {
// First update the render state
Minecraft.getInstance().getItemModelResolver().updateForTopItem(
// The render state
this.state,
// The stack to update the state with
stack,
// The display context to render within
ItemDisplayContext.NONE,
// Whether it is in the left hand of the entity (use false when unknown)
false,
// The current level (can be null)
level,
// The holding entity (can be null)
null,
// An arbitrary seed value
0
);
// Perform any desired transformations here
// Then render the state
this.state.render(
// The pose stack with the required transformations
pose,
// The buffer sources
bufferSource,
// The packed light value
LightTexture.FULL_BRIGHT,
// The overlay texture value
OverlayTexture.NO_OVERLAY
);
}
}
Custom Item Model Defintions
To make a custom item model definition, we need to look at a few more methods in ItemStackRenderState which, although you won’t typically use, is useful to understand: ensureCapacity and newLayer. Both of these are responsible for ensuring there are enough ItemStackRenderState$LayerRenderStates if you happen to be overlaying multiple models at once. Effectively, every time you are planning to render something in an unbaked model, newLayer should be called. If you plan on rendering multiple things on top of one another, then ensureCapacity should be set with the number of layers that you plan to render before calling newLayer.
An item model definition is made up of the ItemModel, which functionally defines a ‘baked model’ and its ItemModel$Unbaked, used for serialization.
The unbaked variant has two methods: bake, which is used to create the ItemModel, and type, which references the MapCodec to be registered to ItemModels#ID_MAPPER, though this field is private by default, so some access changes or reflection needs to be applied. bake takes in the $BakingContext, which contains the ModelBaker to get BakedModels, the EntityModelSet for entity models, and the missing ItemModel.
The baked variant only has one method update, which is responsible for setting up everything necessary on the ItemStackRenderState. The model does no rendering itself.
public record RenderTypeModelWrapper(BakedModel model, RenderType type) implements ItemModel {
// Update the render state
@Override
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext displayContext, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) {
ItemStackRenderState.LayerRenderState layerState = state.newLayer();
if (stack.hasFoil()) {
layerState.setFoilType(ItemStackRenderState.FoilType.STANDARD);
}
layerState.setupBlockModel(this.model, this.type);
}
public static record Unbaked(ResourceLocation model, RenderType type) implements ItemModel.Unbaked {
// Create a render type map for the codec
private static final BiMap<String, RenderType> RENDER_TYPES = Util.make(HashBiMap.create(), map -> {
map.put("translucent_item", Sheets.translucentItemSheet());
map.put("cutout_block", Sheets.cutoutBlockSheet());
});
private static final Codec<RenderType> RENDER_TYPE_CODEC = ExtraCodecs.idResolverCodec(Codec.STRING, RENDER_TYPES::get, RENDER_TYPES.inverse()::get);
// The map codec to register
public static final MapCodec<RenderTypeModelWrapper.Unbaked> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
instance.group(
ResourceLocation.CODEC.fieldOf("model").forGetter(RenderTypeModelWrapper.Unbaked::model),
RENDER_TYPE_CODEC.fieldOf("render_type").forGetter(RenderTypeModelWrapper.Unbaked::type)
)
.apply(instance, RenderTypeModelWrapper.Unbaked::new)
);
@Override
public void resolveDependencies(ResolvableModel.Resolver resolver) {
// Resolve model dependencies, so pass in all known resource locations
resolver.resolve(this.model);
}
@Override
public ItemModel bake(ItemModel.BakingContext context) {
// Get the baked model and return
BakedModel baked = context.bake(this.model);
return new RenderTypeModelWrapper(baked, this.type);
}
@Override
public MapCodec<RenderTypeModelWrapper.Unbaked> type() {
return MAP_CODEC;
}
}
}
// Then, in some initialization location where ItemModels#ID_MAPPER is exposed
ItemModels.ID_MAPPER.put(
// The registry name
ResourceLocation.fromNamespaceAndPath("examplemod", "render_type"),
// The map codec
RenderTypeModelWrapper.Unbaked.MAP_CODEC
);
// For some item 'examplemod:example_item'
// JSON at 'assets/examplemod/items/example_item.json'
{
"model": {
"type": "examplemod:render_type",
// Points to 'assets/examplemod/models/item/example_item.json'
"model": "examplemod:item/example_item",
// Set the render type to use when rendering
"render_type": "cutout_block"
}
}
net.minecraft.clientClientBootstrap- Registers the maps backing the client; currently used for item model definitions.MinecraftgetEquipmentModelsis removed, only directly accessible in theEntityRendererProvider$Context#getEquipmentAssetsgetItemModelResolver- Returns the updater for resolving the current model to be rendered in theItemStackRenderState$LayerRenderState.
KeyMapping#get- Gets a key mapping based on its translation key.
net.minecraft.client.color.itemConstant- A constant to tint the item texture.CustomModelDataSource- Gets the color to tint based on an index in theDataComponent#CUSTOM_MODEL_DATAdata component. If no index is found or is out of bounds, then the default color is used.Dye- Gets the color to tint using theDataComponent#DYED_COLORdata component.Firework- Gets the color to tint using theDataComponent#FIRE_EXPLOSIONdata component.GrassColorSource- Gets the color to tint based on the provided temperature and downfall values.ItemColor->ItemTintSource, not one-to-one as indexing is setup by providing multipleItemTintSources in the model list.ItemColorsclass is removed, now data generated asItemTintSourcesItemTintSources- A registry of sources for tinting an item texture in a model.MapColor- Gets the color to tint using theDataComponent#MAP_COLORdata component.Potion- Gets the color to tint using theDataComponent#POTION_CONTENTSdata component.TeamColor- Gets the color based on the holding entity’s team color.
net.minecraft.client.data.Main- The entrypoint for client data generation.net.minecraft.client.particle.BreakingItemParticlenow takes in anItemStackRenderStateinstead of anItemStack$ItemParticleProvider- An abstract particle provide that provides a simple method to calculate theItemStackRenderState.
net.minecraft.client.rendererBlockEntityWithoutLevelRendererclass is removed, replaced by theNoDataSpecialModelRendererdatagen systemItemInHandRenderernow takes in anItemModelResolverItemModelShaperis removed, as the methods are available within theModelManagerSheetsgetBedMaterial- Gets the bed material from the dye color.colorToResourceMaterial- Gets the resource location of the dye color.createBedMaterial- Creates the bed material from the dye color or resource location.getShulkerBoxMaterial- Gets the shulker box material from the dye color.colorToShulkerMaterial- Gets the resource location of the dye color for the shulker box.createShulkerMaterial- Creates the shulker box material from the dye color or resource location.chestMaterial- Creates a new material for a chest with the given resource location.
SpecialBlockModelRenderer- A map of blocks to special renderers for item variants.
net.minecraft.client.renderer.block.BlockRenderDispatchernow takes in a suppliedSpecialBlockModelRendererinstead of aBlockEntityWithoutLevelRenderernet.minecraft.client.renderer.block.modelBakedOverridesclass is removed, replaced by theRangeSelectItemModelPropertydatagen systemBlockModelnow takes in aTextureSlots$Datainstead of just a material map, and no longer takes in a list ofItemOverridesMISSING_MATERIALis removed, replaced byminecraft:missingnotextureMap->textureSlots, now private, not one-to-oneparentis now private, not one-to-oneparentLocationis now privatehasAmbientOcclusion->getAmbientOcclusionisResolvedis removedgetOverridesis removedgetParent- Returns the unbaked parent model.getTextureSlots- Returns the texture data for the model.getElementsis now package-private$GuiLight->UnbakedModel$GuiLight
FaceBakerybakeQuadis now staticcalculateFacingis now private
ItemModelGeneratornow implementsUnbakedModelItemOverrideclass is removed, replaced by theRangeSelectItemModelPropertydatagen systemItemTransformsis now a recordhasTransformis removed
TextureSlots- A class which handles the texture mapping within a model. The data is read from$Dataand stored as$SlotContentsuntil it is resolved during the baking process intoMaterials.UnbakedBlockStateModelnow extendsResolvableModelinstead ofUnbakedModelbake- Bakes the block state into its selectable models.
Variantis now a record
net.minecraft.client.renderer.blockentityBannerRenderernow has an overload constructor which takes in theEntityModelSetrenderInHand- Renders the item model of the banner.
BedRenderernow has an overload constructor which takes in theEntityModelSetrenderInHand- Renders the item model of the bed.
BlockEntityRenderDispatcher(Font, EntityModelSet, Supplier<BlockRenderDispatcher>, Supplier<ItemRenderer>, Supplier<EntityRenderDispatcher>)->BlockEntityRenderDispatcher(Font, Supplier<EntityModelSet>, BlockRenderDispatcher, ItemModelResolver, ItemRenderer, EntityRenderDispatcher)renderItemis removed, implemented in their specific classes
BlockEntityRendererProvidernow takes in anItemModelResolvergetItemModelResolver- Gets the resolver which returns the item models.
ChestRenderer#xmasTextures- Returns whether christmas textures should render on a chest.DecoratedPotRenderernow has an overload constructor which takes in theEntityModelSetrenderInHand- Renders the item model of the pot.
ShulkerBoxRenderernow has an overload constructor which takes in theEntityModelSetrender- Renders the shulker box.$ShulkerBoxModel#animateno longer takes in theShulkerBoxBlockEntity
SkullblockRenderer#createSkullRenderers->createModel, not one-to-one
net.minecraft.client.renderer.entityEntityRenderDispatchernow takes in anIteModelResolver, a suppliedEntityModelSetinstead of the instance, and anEquipmentAssetManagerinstead of aEquipmentModelSetEntityRendererProvider$Contextnow takes in anItemModelResolverinstead of anItemRenderer, and anEquipmentAssetManagerinstead of aEquipmentModelSetgetItemRenderer->getItemModelResolver, not one-to-onegetEquipmentModels->getEquipmentAssets
FishingHookRenderer- Returns the holding arm of the fishing hook.HumanoidMobRenderergetArmPose- Returns the arm pose of the entity.extractHumanoidRenderStatenow takes in anItemModelResolver
ItemEntityRenderergetSeedForItemStackis removedrenderMultipleFromCountnow takes in theItemClusterRenderState, and removes theItemRenderer,ItemStack,BakedModel, and 3d boolean
ItemRendererno longer implementsResourceManagerReloadListener- The constructor now only takes in the
ItemModelResolver render->renderItem, not one-to-onerenderBundleItemis removedgetModel,resolveItemModelis removed
- The constructor now only takes in the
LivingEntityRenderer#itemRenderer->itemModelResolver, not one-to-oneOminousItemSpawnerRenderernow uses theItemClusterRenderStateSkeletonRenderer#getArmPose->AbstractSkeletonRenderer#getArmPoseSnowGolemRenderernow uses theSnowGolemRenderState
net.minecraft.client.renderer.entity.layersCrossArmsItemLayernow uses theHoldingEntityRenderStateCustomHeadLayerno longer takes in theItemRendererDolphinCarryingItemLayerno longer takes in theItemRendererEquipmentLayerRenderer$TrimSpriteKeynow takes in aResourceKey<EquipmentAsset>textureId- Gets the texture id for the trim.
FoxHeldItemLayerno longer takes in theItemRendererItemInHandLayernow uses theArmedEntityRenderState- The constructor no longer takes in the
ItemRenderer renderArmWithItemno longer takes in theBakedModel,ItemStack, orItemDisplayContextand instead theItemStackRenderState
- The constructor no longer takes in the
LivingEntityEmissiveLayernow takes in a boolean which determines whether the layer is always visiblePandaHoldsItemLayerno longer takes in theItemRendererPlayerItemInHandLayerno longer takes in theItemRendererrenderArmWithItemno longer takes in theBakedModel,ItemStack, orItemDisplayContextand instead theItemStackRenderState
SnowGolemHeadLayernow uses theSnowGolemRenderStateWitchItemLayerno longer takes in theItemRenderer
net.minecraft.client.renderer.entity.player.PlayerRenderer#getArmPoseis now privatenet.minecraft.client.renderer.entity.stateArmedEntityRenderState- A render state for an entity that holds items in their right and left hands.HoldingEntityRenderState- A render state for an entity that holds a single item.ItemClusterRenderState- A render state for an item that should be rendered multiple times.ItemDisplayEntityRenderState#itemRenderState,itemModel->item, not one-to-oneItemEntityRenderState#itemModel,item->ItemClusterRenderState#item, not one-to-oneItemFrameRenderState#itemStack,itemModel->item, not one-to-oneLivingEntityRenderStateheadItemModel,headItem->headItem, not one-to-one- Arm and Hand methods moved to
ArmedEntityRenderState
OminousItemSpawnerRenderState->ItemClusterRenderStatePlayerRenderStatemainHandState,offHandState->ArmedEntityRenderStatemethodsheldOnHead- Represents the item stack on the head of the player.
SkeletonRenderState#isHoldingBow- Represents if the skeleton is holding a bow.SnowGolemRenderState- The render state for the snow golem.ThrownItemRenderState#item,itemModel->item, not one-to-oneWitchRenderState#isHoldingPotion- Whether the witch is holding a potion or not.
net.minecraft.client.renderer.itemBlockModelWrapper- The basic model definition that contains the model and its associated tints.BundleSelectedItemSpecialRenderer- A special renderer for a stack selected by a bundle.ClampedItemPropertyFunction,ItemPropertyFunction->.properties.numeric.*classes depending on the situation and propertyClientItem- The base item that represents the model definition inassets/<modid>/items.CompositeModel- Overlays multiple models together.ConditionalItemModel- A model that shows a different model based on a boolean.EmptyModel- A model that renders nothing.ItemModel- The base item model that updates the stack render state as necessary.ItemModelResolver- The resolver that updates the stack render state.ItemModels- Contains all potential item models for aClientItem.ItemPropertiesclass is removedItemStackRenderState- The render state representing the stack to render.MissingItemModel- A model that represents the missing model.RangeSelectItemModel- A model that contains some range of values that applies the associated model that meets the threshold.SelectItemModel- An item model that switches based on the provided property.SpecialModelWrapper- An item model for models that are rendered dynamically, such as chests.
net.minecraft.client.renderer.item.properties.conditionalBroken- If the item only has one durability left.BundleHasSelectedItem- If the bundle is holding the selected item.ConditionalItemModelProperties- Contains all potential conditional property types.ConditionalItemModelProperty- Represents a property that returns some boolean.CustomModelDataProperty- If the current index is set to true withinDataComponents#CUSTOM_MODEL_DATA.Damaged- If the item is damaged.ExtendedView- If the display context is a gui and the shift key is down.FishingRodCast- If the fishing rod is being used.HasComponent- Whether it has the associated data component.IsCarried- If the item is being carried in the current menu.IsKeybindDown- If the key mapping is being pressed.IsSelected- If the item is selected in the hotbar.IsUsingItem- If the item is being used.IsViewEntity- Whether the holding entity is the current camera entity.
net.minecraft.client.renderer.item.properties.numericBundleFullness- A threshold based on the bundle contents.CompassAngle- A threshold on the currrent angle state.CompassAngleState- A threshold based on the current compass angle towards its target.Cooldown- A threshold based on the current cooldown percentage.Count- A threshold based on the stack count.CrossbowPull- A threshold based on the crossbow being pulled.CustomModelDataProperty- If the current index has set theshold value withinDataComponents#CUSTOM_MODEL_DATA.Damage- A threshold based on the durability percentage remaining.NeedleDirectionHelper- An abstract class which help point the position needle in the correct direction.RangeSelectItemModelProperties- Contains all potential ranged property types.RangeSelectItemModelProperty- Represents a property that returns some threshold of a float.Time- A threshold based on the current time of day.UseCycle- A threshold based on the remaining time left normalized to some period modulo in the stack being used.UseDuration- A threshold based on the remaining time left in the stack being used.
net.minecraft.client.renderer.item.properties.selectCharge- A case based on the charge type of a crowssbow.ContextDimension- A case based on the dimension the item is currently within.ContextEntityType- A case based on the holding entity’s type.CustomModelDataProperty- If the current index is set to the string withinDataComponents#CUSTOM_MODEL_DATA.DisplayContext- A case based on the display context.ItemBlockState- A case based on getting a property value from an item holding the block state properties.LocalTime- A case based on a simple date format pattern.MainHand- A case based on the arm holding the item.SelectItemModelProperties- Contains all potential select-cased property types.SelectItemModelProperty- Represents a property that returns some cased selection.TrimMaterialProperty- A case based on the trim material on the item.
net.minecraft.client.renderer.specialBannerSpecialRenderer- An item renderer for a banner.BedSpecialRenderer- An item renderer for a bed.ChestSpecialRenderer- An item renderer for a chest.ConduitSpecialRenderer- An item renderer for a conduit.DecoratedPotSpecialRenderer- An item renderer for a decorated pot.HangingSignSpecialRenderer- An item renderer for a hanging sign.NoDataSpecialModelRenderer- An item renderer that does not need to read any data from the stack.ShieldSpecialRenderer- An item renderer for a shield.ShulkerBoxSpecialRenderer- An item renderer for a shulker box.SkullSpecialRenderer- An item renderer for a skull.SpecialModelRenderer- Represents a model that reads data from the stack and renders the object without needing the render state.SpecialModelRenderers- Contains all potential special renderers.StandingSignSpecialRenderer- An item renderer for a standing sign.TridentSpecialRenderer- An item renderer for a trident.
net.minecraft.client.resources.modelBakedModelisCustomRendereris removed, replaced by the special renderer systemoverridesis removed, replaced by the properties renderer system
BlockStateModelLoaderno longer takes in the missing modeldefinitionLocationToBlockMapperis now privateloadBlockStateDefinitionStackis now privateloadBlockStates- Gets the loaded models for the block state.$LoadedBlockModelDefinitionis now package-private$LoadedModelnow takes in anUnbakedBlockStateModelinstead of aUnbakedModel$LoadedModelsforResolving- Returns all models hat need to be resolved.plainModels- Returns a map from the model location to the unbaked model.
BuiltInModelclass is removedClientItemInfoLoader- Loads all models for all item stacks.EquipmentModelSet->EquipmentAssetManagerItemModel->net.minecraft.client.renderer.item.ItemModelMissingBlockModel#MISSINGis now privateModelBakersprites- Returns the getter to get sprites.rootName- Gets the name of the model for debugging.
ModelBakery(Map<ModelResourceLocation, UnbakedModel>, Map<ResourceLocation, UnbakedModel>, UnbakedModel)->ModelBakery(EntityModelSet, Map<ModelResourceLocation, UnbakedBlockStateModel>, Map<ResourceLocation, ClientItem>, Map<ResourceLocation, UnbakedModel>, UnbakedModel)bakeModelsnow returns a$BakingResultgetBakedTopLevelModelsis removed$BakingResult- Holds all models that have been lodaded.$TextureGettergetnow takes in theModelDebugNameinstead of theModelResourceLocationreportingMissingReference- Handles how a texture is reported when not set.bind- Creates a spriate getter bound to the current model.
ModelDebugName- Returns the name of the model for debugging.ModelDiscoveryregisterStandardModelsis removedregisterSpecialModels- Adds the internal models loaded by the system.addRoot- Adds a new model that can be resolved.getUnreferencedModels- Returns the difference between the models loaded vs the models used.getTopModelsis removed
ModelGroupCollector$GroupKey#createnow takes in anUnbakedBlockStateModelinstead of aUnbakedModelModelManagerspecialBlockModelRenderer- Returns the renderer for special block models.entityModels- Returns the model set for the entities.getItemProeprties- Returns the properties for the client item based on its resource location.
ModelResourceLocation#inventoryis removedResolvableModel- The base model, usually unbaked, that have references to resolve.SimpleBakedModelfields are now all privatebakeElements- Bakes a model given the block elements.$Builderno longer has an overload that takes in theBlockModel
SpecialModelsclass is removedSpriteGetter- A getter for atlas sprites for the associated materials.UnbakedModelis now aResolvableModelbake(ModelBaker, Function<Material, TextureAtlasSprite>, ModelState)->bake(TextureSlots, ModelBaker, ModelState, boolean, boolean, ItemTransforms)getAmbientOcclusion,getTopAmbientOcclusion- Returns whether ambient occlusion should be enabled on the item.getGuiLight,getTopGuiLight- Returns the lighting side within a gui.getTransforms,getTopTransform,getTopTransforms- Returns the transformations to apply based on the display context.getTextureSlots,getTopTextureSlots- Returns the texture data for the model.getParent- Returns the parent of this model.bakeWithTopModelValues- Bakes the model.
net.minecraft.data.models.*->net.minecraft.client.data.models.*net.minecraft.world.itemBundleItemno longer takes in anyResourceLocationsopenFrontModel,openBackModelis removed
CrossbowItem$ChargeType- The item being charged by the crossbow.DyeColor#getMixedColor- Returns the dye most closely representing the mixed color.Item$Properties#overrideModelis removedSpawnEggItemno longer takes in its tint colorsgetColoris removed
net.minecraft.world.item.alchemy.PotionContentsgetColor(*)is removedgetColorOr- Gets a custom color fro the potion or the default if not present.
net.minecraft.world.item.component.CustomModelDatanow takes in a list of floats, flags, strings, and colors to use in the custom model properties based on the provided indexnet.minecraft.world.item.equipmentArmorMaterialnow takes in aResourceKey<EquipmentAsset>instead of just the model idEquipmentAsset- A marker to represent the equipment client info keyEquipmentAssets- All vanilla equipment assets.EquipmentModel->net.minecraft.client.resources.model.EquipmentClientInfoEquipmentModels->net.minecraft.client.data.models.EquipmentAssetProvider, not one-to-oneEquippablenow takes in aResourceKey<EquipmentAsset>instead of just the model id$Builder#setModel->setAsset
net.minecraft.world.item.equipment.trimArmorTrim#getTextureis removedTrimMaterialno longer takes in an item model index, and the key over the override armor materials points toResourceKey<EquipmentAsset>
net.minecraft.world.level.FoliageColorgetEvergreenColor->FOLIAGE_EVERGREENgetBirchColor->FOLIAGE_BIRCHgetDefaultColor->FOLIAGE_DEFAULTgetMangroveColor->FOLIAGE_MANGROVE
net.minecraft.world.level.block.RenderShape#ENTITYBLOCK_ANIMATEDis removednet.minecraft.world.level.block.entityBannerBlockEntity#fromItemis removedBedBlockEntitty#setColoris removedBlockEntity#saveToItemis removedDecoratedPotBlockEntity#setFromItem,getPotAsItemis removed
net.minecraft.world.level.storage.loot.functions.SetCustomModelDataFunctionnow takes in a list of floats, flags, strings, and colors to use in the custom model properties based on the provided index
Mob Replacing Current Items
One of the last hardcoded instances relating to tools and armor being subtypes of DiggerItem and ArmorItem, respectively, have been reworked: Mob#canReplaceCurrentItem. Now, it reads the EquipmentSlot of the stack from the DataComponents#EQUIPPABLE data component. Then, using that, different logic occurs depending on the situation.
For armor slots, it cannot be changed if the armor is enchanted with a EnchantmentEffectComponents#PREVENT_ARMOR_CHANGE effect component. Otherwise, it will attempt to compare the armor attributes first, then armor toughness if equal.
For weapons (via hand slots), it will first check if the mob has a preferred weapon type tag. If so, it will switch the item to the weapon in the tag, provided one item is in the tag and the other is not. Otherwise, it will attempt to compare attack damage attributes.
If all attributes are equal, then they will both default to the following logic. First, it will try to pick the item with the most enchantments. Then, it will attempt to pick the item with the most durability remaining (the raw value, not the percentage). Finally, it will check whether one of the items hsa a custom name via the DataComponents#CUSTOM_NAME.
As a small caveat,
BambooSaplingBlockandBambooStalkBLockstill hardcode a check for check if the mainhand item is aSwordItem, though this could probably be replaced with a change toToolMaterial#applySwordPropertiesin the future.
Particles, rendered through Render Types
Particles are now rendered using a RenderType, rather than setting a buffer builder themselves. The only special cases are ParticleRenderType#CUSTOM, which allows the modder to implement their own rendering via Particle#renderCustom; and ParticleRenderType#NO_RENDER, which renders nothing.
To create a new ParticleRenderType, it can be created by passing in its name for logging and the RenderType to use. Then, the type is returned in Particle#getRenderType.
public static final ParticleRenderType TERRAIN_SHEET_OPAQUE = new ParticleRenderType(
"TERRAIN_SHEET_OPAQUE", // Typically something recognizable, like the name of the field
RenderType.opaqueParticle(TextureAtlas.LOCATION_BLOCKS) // The Render Type to use
);
net.minecraft.client.particleCherryParticle->FallingLeavesParticle, not one-to-one as the new class has greater configuration for its generalizationItemPickupParticleno longer takes in theRenderBuffersParticle#renderCustom- Renders particles with theParticleRenderType#CUSTOMrender type.ParticleEngine#render(LightTexture, Camera, float)->render(Camera, float, MutliBufferSource$BufferSource)ParticleRenderTypeis now a record which takes in the name and theRenderTypeit uses.
Minor Migrations
The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.
SimpleJsonResourceReloadListener
SimpleJsonResourceReloadListeners now take in a converter to map some key to a resource location. An abstract has been provided for registry keys. This is done through a FileToIdConverter, which essentially holds a prefix and extension to apply to some ResourceLocation.
// We will assume this is a server reload listener (meaning in the 'data' folder)
public class MyLoader extends SimpleJsonResourceReloadListener<ExampleObject> {
public MyLoader() {
super(
// The codec to encode/decode the object
ExampleObject.CODEC,
// The file converter
// Will place files in data/<namespace>/example/object/<path>.json
FileToIdConverter.json(
// The prefix
"example/object"
)
);
}
// Below is the same
}
net.minecraft.server.packs.resources.SimpleJsonResourceReloadListenernow takes in a resource key for a registry, or a file to id converter instead of just a stringscanDirectorynow takes in a resource key for a registry, or a file to id converter instead of just a string
MetadataSectionSerializer, replaced by Codecs
MetadataSectionSerializer has been removed in favor of using Codecs to serialize the metadata sections. As such all MetadataSectionSerializers have been replaced by its MetadataSectionType instead, which holds the name of the section and the codec for the metadata section.
net.minecraft.client.renderer.textureHttpTexture->SkinTextureDownloader, not one-to-one as the new class is just a utility that returns the content to storeMissingTextureAtlasSpritegetTexture->generateMissingImage, not one-to-onegetMissingImage(int, int)is now public
SpriteLoader#loadAndStitchnow takes in a collection ofMetadataSectionTypes rather thanMetadataSectionSerializers
net.minecraft.client.resources.SkinManagerno longer takes in theTextureManagergetOrLoadnow returns anOptional<PlayerSkin>future instead of just thePlayerSkin
net.minecraft.client.resources.metadata.animationAnimationFrameis now a recordAnimationMetadataSectionis now a recordAnimationMetadataSectionSerializerclass is removedVillagerMetaDataSection->VillagerMetadataSectionVillagerMetadataSectionSerializerclass is removed
net.minecraft.client.resources.metadata.textureTextureMetadataSectionis now a recordTextureMetadataSectionSerializerclass is removed
net.minecraft.server.packs.PackResources#getMetadataSectionnow takes in aMetadataSectionTypeinstead of aMetadataSectionSerializernet.minecraft.server.packs.metadataMetadataSectionSerializeris removed in favor of section codecsMetadataSectionTypeis a now a record instead of aMetadataSectionSerializerextension
net.minecraft.server.packs.resources.ResourceMetadatagetSectionnow takes in aMetadataSectionTypeinstead of aMetadataSectionSerializercopySectionsnow takes in a collection ofMetadataSectionTypes instead of aMetadataSectionSerializers
Music, now with Volume Controls
The background music is now handled through a MusicInfo class, which also stores the volume along with the associated Music.
net.minecraft.client.Minecraft#getSituationalMusicnow returns aMusicInfoinstead of aMusicnet.minecraft.client.soundsMusicInfo- A record that holds the currently playingMusicand the volume its at.MusicManager#startPlayingnow takes in aMusicInfoinstead of aMusicSoundEngine#setVolume,SoundManager#setVolume- Sets the volume of the associated sound instance.
net.minecraft.world.level.biomeBiomegetBackgroundMusicnow returns a optionalSimpleWeightedRandomListof music.getBackgroundMusicVolume- Gets the volume of the background music.
BiomeSpecialEffects$Builder#silenceAllBackgroundMusic,backgroundMusic(SimpleWeightedRandomList<Music>)- Handles setting the background music for the biome.
Tag Changes
minecraft:blocktall_flowers->bee_attractive
minecraft:itemtall_flowers,flowersis removedtrim_templatesis removedskeleton_preferred_weaponsdrowned_preferred_weaponspiglin_preferred_weaponspillager_preferred_weaponswither_skeleton_disliked_weapons
List of Additions
com.mojang.blaze3d.platform.Window#isMinimized- Returns whether the application window is minimized.com.mojang.blaze3d.vertex.VertexBufferuploadStatic- Immediately uploads the provided vertex data via theConsumer<VertexConsumer>using theTesselatorwith aSTATIC_WRITEVertexBuffer.drawWithRenderType- Draws the current buffer to the screen with the givenRenderType.
com.mojang.math.MatrixUtil#isIdentity- Checks whether the currentMatrix4fis an identity matrix.net.minecraftSuppressForbidden- An annotation that holds some reason, usually related to needing the sysout stream.Util#maxAllowedExecutorThreads- Returns the number of available processors clamped between one and the maximum number of threads.
net.minecraft.client.gui.components.events.GuiEventListener#getBorderForArrowNavigation- Returns theScreenRectanglebound to the current direction.net.minecraft.client.gui.navigation.ScreenRectangle#transformAxisAligned- Creates a newScreenRectangleby transforming the position using the providedMatrix4f.net.minecraft.client.gui.narration.NarratableEntry#getNarratables- Returns the list of narratable objects within the current object.net.minecraft.client.gui.screens.recipebook.RecipeCollection#EMPTY- An empty collection of recipes.net.minecraft.client.gui.screens.worldselectionExperimentsScreen$ScrollArea- Represents a narratable scroll area of the currently available experiments.SwitchGrid#layout- Returns the layout of the grid to visit.
net.minecraft.client.modelBannerFlagModel,BannerModel- Models for the banner and hanging banner.VillagerLikeModel#translateToArms- Translates the pose stack such that the current relative position is at the entity’s arms.
net.minecraft.client.model.geom.EntityModelSet#vanilla- Creates a new model set with all vanilla models.net.minecraft.client.multiplayer.PlayerInfo#setShowHat,showHat- Handles showing the hat layer of the player in the tab overlay.net.minecraft.client.renderer.blockentityAbstractSignRenderer- How a sign should render as a block entity.HangingSignRenderercreateSignModel- Creates a sign model given the wood and the attachment location.renderInHand- Renders the model in the entity’s hand.$AttachmentType- An enum which represents where the model is attached to, given its properies.$ModelKey- A key for the model that combines theWoodTypewith its$AttachmentType.
SignRendererrenderInHand- Renders the model in the entity’s hand.
net.minecraft.client.renderer.entity.EntityRenderer#getShadowStrength- Returns the raw opacity of the display’s shadow.net.minecraft.client.renderer.entity.layers.CrossedArmsItemLayer#applyTranslation- Applies the translation to render the item in the model’s arms.net.minecraft.client.renderer.textureReloadableTexture- A texture that can be reloaded from its associated contents.TextureContents- Holds the image and metadata associated with a given texture.TextureManagerregisterAndLoad- Registers a reloadable texture with the given name.registerForNextReload- Registers a texture by its resource location to be loaded on next reload.
net.minecraft.commands.SharedSuggestionProvider#MATCH_SPLITTER- Defines a matcher that matches a period, underscore, or forward slash.net.minecraft.core.BlockPos$TraversalNodeStatus- A marker indicating whether theBlockPosshould be used, skipped, or stopped from any further traversal.net.minecraft.core.component.PatchedDataComponentMaptoImmutableMap- Returns either the immutable patch or a copy of the current map.hasNonDefault- Returns whether there is a custom value for the data component instead of just the default.
net.minecraft.data.PackOutput$PathProvider#json- Gets the JSON path from a resource key.net.minecraft.data.loot.BlockLootSubProvider#createMultifaceBlockDrops- Drops a block depending on the block face mined.net.minecraft.data.worldgen.placement.PlacementUtils#HEIGHTMAP_NO_LEAVES- Creates a y placement using theHeightmap$Types#MOTION_BLOCKING_NO_LEAVESheightmap.net.minecraft.network.chat.Style#getShadowColor,withShadowColor- Methods for handling the shadow color of a component.net.minecraft.network.protocol.game.ServerboundPlayerLoadedPacket- A packet for when the client player loads into a client world.net.minecraft.resources.FileToIdConverter#registry- Gets the file converter from a registry key.net.minecraft.util.ExtraCodecsidResolverCodec- Creates a codec that maps some key to some value.compactListCodec- Creates a codec that can either be an element of a list of elements.floatRange- Creates a codec that must be between two float values.$LateBoundIdMapper- A mapper that functionally acts like a registry with an associated codec.
net.minecraft.util.profiling.jfr.JvmProfiler#onStructureGenerate- Returns the profiled duration on when a structure attempts to generate in the world.net.minecraft.util.profiling.jfr.event.StructureGenerationEvent- A profiler event when a structure is being generated.net.minecraft.util.profiling.jfr.stats.StructureGenStat- A result of a profiled structure generation.net.minecraft.world.entityLivingEntityresolvePlayerResponsibleForDamage- Gets the player responsible for hurting the current entity.canBeNameTagged- When true, the entity’s can be set with a name tag.
Mob#getPreferredWeaponType- Gets the tag that represents the weapons the entity wants to pick up.
net.minecraft.world.entity.ai.attributes.AttributeMap#resetBaseValue- Resets the attribute instance to its default value.net.minecraft.world.entity.monster.creakingCreakingactivate,deactivate- Handles the activateion of the brain logic for the creaking.setTransient,isHeartBound,setHomePos,getHomePos- Handles the home position.blameSourceForDamage- Finds the player responsible for the damage.tearDown- Handles when the creaking is destroyed.creakingDeathEffects- Handles the death of a creaking.playerIsStuckInYou- Checks whether there are at least four players stuck in a creaking.setTearingDown,isTearingDown- Handles the tearing down state.hasGlowingEyes,checkEyeBlink- Handles the eye state.
net.minecraft.world.entity.player.PlayerhasClientLoaded,setClientLoaded- Whether the client player has been loaded.tickClientLoadTimeout- Ticks the timer on how long to wait before kicking out the client player if not loaded.
net.minecraft.world.itemItem#shouldPrintOpWarning- Whether a warning should be printed to the player based on stored block entity data and adminstrator permissions.ItemStackgetCustomName- Returns the custom name of the item, ornullif no component exists.immutableComponents- Returns either the immutable patch or a copy of the stack component map.hasNonDefault- Returns whether there is a custom value for the data component instead of just the default.
net.minecraft.world.item.component.CustomDataparseEntityId- Reads the entity id off of the component.parseEntityType- Reads the entity type from the id and maps it to its registry object.
net.minecraft.world.item.crafting.Ingredient#isEmpty- Returns whether the ingredient has no values.net.minecraft.world.item.trading.Merchant#stillValid- Checks whether the merchant can still be accessed by the player.net.minecraft.world.levelLevel#dragonParts- Returns the list of entities that are the parts of the ender dragon.ServerExplosion#getDamageSource- Returns the damage source of the explosion.
net.minecraft.world.level.blockEyeblossomBlock$Typeblock- Gets the block for the current type.state- Gets the block state for the current type.transform- Returns the opposiate state of this type.
FlowerBlock#getBeeInteractionEffect- Returns the effect that bees obtain when interacting with the flower.FlowerPotBlock#opposite- Returns the opposite state of the block, only for potted eyeblossoms.MultifaceBlock#canAttachTo- Returns whether this block can attach to another block.MultifaceSpreadeableBlock- A multiface block that can naturally spread.
net.minecraft.world.level.block.entity.trialspawnerTrialSpawner#overrideEntityToSpawn- Changes the entity to spawn in the trial.TrialSpawnerConfig#withSpawning- Sets the entity to spawn within the trial.
List of Changes
com.mojang.blaze3d.platform.NativeImage#uploadno longer takes in three booleans that set the filter mode or texture wrap clamping forTEXTURE_2D- This has been moved to
AbstractTexture#setClampand#setFilter
- This has been moved to
net.minecraft.client.guiGui#clear->clearTitlesGuiGraphics#drawWordWraphas a new overload that takes in whether a drop shadow should be applied to the text- The default version enables drop shadows instead of disabling it
net.minecraft.client.gui.componentsAbstractContainerWidgetnow implementsAbstractScrollAreaAbstractScrollWidget->AbstractScrollAreaorAbstractTextAreaWidgetdepending on use-case, not one-to-oneAbstractSelectionListsetRenderHeaderis now bundled into a new constructor with an extra integergetMaxScroll->AbstractScrollArea#maxScrollAmountgetScrollAmount->AbstractScrollArea#scrollAmountscrollbarVisible->AbstractScrollArea#scrollbarVisiblesetClampedScrollAmount,setScrollAmount->AbstractScrollArea#setScrollAmountclampScrollAmount->refreshScrollAmountupdateScrollingState->AbstractScrollArea#updateScrollinggetScrollbarPosition,getDefaultScrollbarPosition->scrollBarY, not one-to-one
AbstractWidget#clicked->isMouseOver, already exists
net.minecraft.client.gui.components.toasts.TutorialToastnow requires aFontas the first argument in its constructornet.minecraft.client.gui.font.glyphs.BakedGlyph$Effectand$GlyphInstancenow take in the color and offset of the text shadownet.minecraft.client.gui.screensLoadingOverlay#registerTexturesnow takes in aTextureManagerinstead of theMinecraftinstanceTitleScreen#preloadResources->registerTextures, not one-to-one
net.minecraft.client.gui.screens.debug.GameModeSwitcherScreen$GameModeSlotis now a static inner classnet.minecraft.client.gui.screens.reporting.ChatSelectionScreen$Entry,$PaddingEntryare now static inner classesnet.minecraft.client.gui.screens.worldselection.SwitchGrid$Builder#buildno longer takes in aConsumer<LayoutElement>net.minecraft.client.modelDonkeyModel#createBodyLayer,createBabyLayernow take in a scaling factorVillagerHeadModel->VillagerLikeModel
net.minecraft.client.model.geom.EntityModelSetis no longer aResourceManagerReloadListenernet.minecraft.client.multiplayer.MultiPlayerGameMode#handlePickItem->handlePickItemFromBlockorhandlePickItemFromEntity, providing both the actual object data to sync and abooleanabout whether to include the data of the object being pickednet.minecraft.client.particle.CherryParticle->FallingLeavesParticle, not one-to-one as the new class has greater configuration for its generalizationnet.minecraft.client.player.ClientInput#tickno longer takes in any parametersnet.minecraft.client.rendererCubeMap#preload->registerTextures, not one-to-oneLevelRendererrenderLevelno longer takes in theLightTextureonChunkLoaded->onChunkReadyToRender
PostChainConfig$Pass#program->programIdprogramnow returns theShaderProgramwith the givenprogramId
ScreenEffectRenderer#renderScreenEffectnow takes in aMultiBufferSourceSectionOcclusionGraph#onChunkLoaded->onChunkReadyToRenderSheets#createSignMaterial,createHangingSignMaterialnow has an overload that takes in aResourceLocationSkyRendererrenderSunMoonAndStars,renderSunriseAndSunsetnow takes in aMultiBufferSource$BufferSourceinstead of aTesselatorrenderEndSkyno longer takes in thePoseStack
WeatherEffectRenderer#rendernow takes in aMultiBufferSource$BufferSourceinstead of aLightTexture
net.minecraft.client.renderer.blockentityBannerRenderer#createBodyLayer->BannerModel#createBodyLayer, not one-to-oneHangingSignRenderercreateHangingSignLayernow takes in aHangingSignRenderer$AttachmentType$HangingSignModelis now replaced with aModel$Simple, though its fields can be obtained from the root
SkullBlockRenderer#getRenderTypenow has an overload that takes in aResourceLocationto override representing the player’s texture
net.minecraft.client.renderer.entity.AbstractHorseRenderer,DonkeyRendererno longer takes in a float scalenet.minecraft.client.renderer.entity.layers.CrossedArmsItemLayernow requires the genericMto be aVillagerLikeModelnet.minecraft.client.renderer.entity.state.CreakingRenderState#isActive->eyesGlowing- The original parameter still exists on the
Creaking, but is not necessary for rendering
- The original parameter still exists on the
net.minecraft.core.BlockPos#breadthFirstTraversalnow takes in a function that returns a$TraversalNodeStatusinstead of a simple predicate to allow certain positions to be skippednet.minecraft.core.particles.TargetColorParticleOption->TrailParticleOption, not one-to-onenet.minecraft.data.DataProvider#savelAllnow has overloads for maps with a key function to get the associated pathnet.minecraft.networkNoOpFrameEncoderreplaced byLocalFrameEncoder, not one-to-oneNoOpFrameDecoderreplaced byLocalFrameDecoder, not one-to-oneMonitorFrameDecoderreplaced byMonitoredLocalFrameDecoder, not one-to-one
net.minecraft.network.protocol.gameClientboundLevelParticlesPacketnow takes in a boolean that determines whether the particle should always renderClientboundMoveVehiclePacketis now a recordClientboundPlayerInfoUpdatePacket$Entrynow takes in a boolean representing whether the hat should be shownClientboundSetHeldSlotPacketis now a recordServerboundMoveVehiclePacketis now a recordServerboundPickItemPacket->ServerboundPickItemFromBlockPacket,ServerboundPickItemFromEntityPacket; not one-to-one
- `net.minecraft.server.level
ServerLevel#sendParticlesnow has an overload that takes in the override limiter distance and whether the particle should always be shown- Other overloads that take in the override limiter now also take in the boolean for if the particle should always be shown
ServerPlayer#doCheckFallDamage->Entity#doCheckFallDamage, now final
net.minecraft.utilARGB#from8BitChannelis now private, with individual float components obtained fromalphaFloat,redFloat,greenFloat, andblueFloatSpawnUtil#trySpawnMobnow takes in a boolean that, when false, allows the entity to spawn regardless of collision status with the surrounding area
net.minecraft.util.profiling.jfr.callback.ProfiledDuration#finishnow takes in a boolean that indicates whether the profiled event was successfulnet.minecraft.util.profiling.jfr.parse.JfrStatsResultsnow takes in a list of structure generation statisticsnet.minecraft.world.effect.PoisonMobEffect,WitherMobEffectis now publicnet.minecraft.world.entityEntitysetOnGroundWithMovementhas an overload that sets the horizontal collision to whatever the entity’s current state is.awardKillScoreno longer takes in an integermakeBoundingBox()is now finalmakeBoundingBox(Vec3)is now
onlyOpCanSetNbt->EntityType#onlyOpCanSetNbt
LeashablereadLeashDatais now private, replaced by a method that returns nothingdropLeash(boolean, boolean)->dropLeash(),removeLeash,onLeashRemoved; not one-to-one, as they all internally call the privatedropLeash
LivingEntityisLookingAtMeno longer takes in aPredicate<LivingEntity>, and array ofDoubleSuppliers is now an array ofdoubleshasLineOfSighttakes in a double instead of aDoubleSupplier
net.minecraft.world.entity.ai.behavior.AcquirePoi#createnow has overloads which take in aBiPredicate<ServerLevel, BlockPos>for filtering POI locationsnet.minecraft.world.entity.animal.Bee#attractsBeesis now publicnet.minecraft.world.entity.monster.Shulker#getProgressAabb,getProgressDeltaAabbnow take in a movementVec3net.minecraft.world.entity.playerInventorysetPickedItem->addAndPickItemfindSlotMatchingCraftingIngredientnow takes in anItemStackto compare against
Player#getPermissionLevelis now publicStackedContents$IngredientInfois now an interface that acts like a predicate for accepting some item
net.minecraft.world.entity.projectile.FishingHookno longer takes in theItemStacknet.minecraft.world.inventory.Slot#getNoItemIconnow returns a singleResourceLocationrather than a pair of themnet.minecraft.world.itemItem$TooltipContext#ofnow takes in thePlayerviewing the itemMobBucketItemnow requires aMobentity type -SpawnEggItem#spawnsEntity,getTypenow takes in aHolderLookup$Provider
net.minecraft.world.item.craftingIngredientnow implementsStackedContents$IngredientInfo<Holder<Item>>itemsnow returns a stream instead of a list
PlacementInfo#slotInfo->slotsToIngredientIndex, not one-to-one
net.minecraft.world.level.Level#addParticlenow takes in a boolean representing if the particle should always be shownnet.minecraft.world.level.blockBlock#getCloneItemStack->state.BlockBehaviour#getCloneItemStack, now protectedCherryLeavesBlock->ParticleLeavesBlockCreakingHeartBlock#canSummonCreaking->isNaturalNightMultifaceBlockis no longer abstract and implementsSimpleWaterloggedBlockgetSpreader->MultifaceSpreadeableBlock#getSpreader
SculkVeinBlockis now an instance ofMultifaceSpreadeableBlockSnowyDirtBlock#isSnowySettingis now protected
net.minecraft.world.level.block.entityAbstractFurnaceBlockEntitylitTime->litTimeRemaininglitDuration->litTotalTimecookingProgress->cookingTimer
BeehiveBlockEntity#addOccupantnow takes in aBeerather than anEntityCreakingHeartBlockEntity#setCreakingInfo- Sets the creaking the block entity is attached to.
net.minecraft.world.level.block.state.BlockBehaviour#getCloneItemStack,$BlockStateBase#getCloneItemStacknow takes in a boolean representing if there is infinite materials and whether the current block data should be saved.net.minecraft.world.level.chunk.ChunkGenerator#createStructuresnow takes in theLevelresource key, only used for profilingnet.minecraft.world.level.levelgen.feature.configurationsMultifaceGrowthConfigurationnow takes in aMultifaceSpreadableBlockinstead of aMultifaceBlockSimpleBlockConfigurationnow takes in a boolean on whether to schedule a tick update
net.minecraft.world.level.levelgen.structure.Structure#generatenow takes in theStructureholder and aLevelresource key, only used for profiling
List of Removals
com.mojang.blaze3d.systems.RenderSystem#overlayBlendFuncnet.minecraft.client.gui.components.AbstractSelectionListclickedHeaderisValidMouseClick
net.minecraft.client.gui.screens.recipebook.RecipeCollection#hasSingleResultItemnet.minecraft.client.modelDrownedModel#getArmPose, now part of theArmedEntityRenderStateFelineModel#CAT_TRANSFORMERHumanoidModel#getArmPose, now part of theArmedEntityRenderStatePlayerModel#getArmPose, now part of theArmedEntityRenderStateSkeletonModel#getArmPose, now part of theArmedEntityRenderStateVillagerModel#BABY_TRANSFORMER
net.minecraft.client.renderer.textureAbstractTextureloadresetgetDefaultBlur
PreloadedTextureTextureManagergetTexture(ResourceLocation, AbstractTexture)register(String, DynamicTexture)preload
net.minecraft.server.level.TicketType#POST_TELEPORTnet.minecraft.world.entity.LivingEntity#deathScorenet.minecraft.world.entity.ai.navigation.FlyingPathNavigation,GroundPathNavigationcanPassDoors,setCanPassDoorscanOpenDoors
net.minecraft.world.entity.monster.creaking.CreakingTransientnet.minecraft.world.entity.player.StackedItemContents#convertIngredientContentsnet.minecraft.world.itemCompassItem#getSpawnPositionItemStack#clearComponents
net.minecraft.world.item.crafting.PlacementInfoingredientToContentsunpackedIngredients$SlotInfo
net.minecraft.world.level.block.CreakingHeartBlock$CreakingHeartStatenet.minecraft.world.level.block.entity.BlockEntity#onlyOpCanSetNbtnet.minecraft.world.level.block.entity.trialspawner.TrialSpawnerData#setEntityId
Minecraft 1.21.4 -> 1.21.5 Mod Migration Primer
This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.4 to 1.21.5. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.
This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.
If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.
Thank you to:
- @TelepathicGrunt for the information within the ‘Very Technical Changes’ section
- @RogueLogix for their review and comments on the ‘Render Pipeline Rework’ section
- @Tslat for catching an error about
equipOnInteract
Pack Changes
There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.
Handling the Removal of Block Entities Properly
Previously, BlockEntity would handle all of their removal logic within BlockBehaviour#onRemove, including both dropping any stored items and removing the block entity itself. However, depending on how the method is used, it can cause some strange behaviors due to the mutable state of the block entity. For this reason, the logic that makes up the removal process has been split between two methods: BlockEntity#preRemoveSideEffects and BlockBehaviour#affectNeighborsAfterRemoval.
BlockEntity#preRemoveSideEffects is now responsible for removing anything from the block entity before it is removed from the level. By default, if the BlockEntity is a Container instance, it will drop the contents of the container into the level. Other logic can be handled within here, but it should generally avoid removing the BlockEntity itself, unless the position of the block entity tends to change dynamically, like for a piston.
From there, the LevelChunk logic will call removeBlockEntity before calling BlockBehaviour#affectNeighborsAfterRemoval. This should only send the updates to other blocks indicating that this block has been removed from the level. For BlockEntity holders, this can be done easily by calling Containers#updateNeighboursAfterDestroy. Otherwise may want to call Level#updateNeighborsAt themselves, depending on the situation.
net.minecraft.world.ContainersupdateNeighboursAfterDestroy- Updates the neighbor state aftering destroying the block at the specified position.dropContentsOnDestroyis removed, handled withinBlockEntity#preRemoveSideEffectsforContainerinstances
net.minecraft.world.level.block.entity.BlockEntity#preRemoveSideEffects- Handles logic on the block entity that should happen before being removed from the level.net.minecraft.world.level.block.state.BlockBehaviour#onRemove,$BlockStateBase#onRemove->affectNeighborsAfterRemoval, should only handle logic to update the surrounding neighbors rather than dropping container data
Voxel Shape Helpers
VoxelShapes have received numerous helpers for more common transformations of its base state. There are the Block methods for creating a centered (if desired) box and the Shapes methods for rotating a VoxelShape to its appropriate axis or direction. There is also a Shapes#rotateAttachFace method for rotating some VoxelShape that is attached to a face of a different block. The results are either stored in a Map of some key to a VoxelShape, or when using Block#getShapeForEachState, a Function<BlockState, VoxelShape>.
Most of the Block subclasses that had previous public or protected VoxelShapes are now private, renamed to a field typically called SHAPE or SHAPES. Stored VoxelShapes may also be in a Function instead of directly storing the map itself.
com.mojang.math.OctahedralGrouppermute- Returns the axis that the given axis is permuted to within the specified group.fromAngles- Creates a group with the provided X and Y rotations.
net.minecraft.core.Direction$Axis#choosenow has an overload that takes in three booleansnet.minecraft.world.level.block.Blockboxes- Creates one more than the specified number of boxes, using the index as part of the function to create theVoxelShapes.cube- Creates a centered cube of the specified size.column- Creates a horizontally centered column of the specified size.boxZ- Creates a vertically centered (around the X axis) cube/column of the specified size.getShapeForEachStatenow returns aFunctionwhich wraps theImmutableMap, there is also a method that only considers the specified properties instead of all possible states.
net.minecraft.world.phys.shapesDiscreteVoxelShape#rotate- Rotates a voxel shape according to the permutation of theOctahedralGroup.ShapesblockOccudes->blockOccludesrotate- Rotates a given voxel shape according to the permutation of theOctahedralGrouparound the provided vector, or block center if not specified.equal- Checks if two voxel shapes are equivalent.rotateHorizontalAxis- Creates a map of axes toVoxelShapes of a block being rotated around the y axis.rotateAllAxis- Creates a map of axes toVoxelShapes of a block being rotated around any axis.rotateHorizontal- Creates a map of directions toVoxelShapes of a block being rotated around the y axis.rotateAll- Creates a map of directions toVoxelShapes of a block being rotated around the any axis.rotateAttachFace- Creates a map of faces to a map of directions toVoxelShapes of a block being rotated around the y axis when attaching to the faces of other blocks.
VoxelShape#movenow has an overload to take in aVec3i
Weapons, Tools, and Armor: Removing the Redundancies
There have been a lot of updates to weapons, tools, and armor that removes the reliance on the hardcoded base classes of SwordItem, DiggerItem, and ArmorItem, respectively. These have been replaced with their associated data components WEAPON for damage, TOOL for mining, ARMOR for protection, and BLOCKS_ATTACKS for shields. Additionally, the missing attributes are usually specified by setting the ATTRIBUTE_MODIFIERS, MAX_DAMAGE, MAX_STACK_SIZE, DAMAGE, REPAIRABLE, and ENCHANTABLE. Given that pretty much all of the non-specific logic has moved to a data component, these classes have now been completely removed. Use one of the available item property methods or call Item$Properties#component directly to set up each item as a weapon, tool, armor, or some combination of the three.
Constructing a BlockAttacks component for a shield-like item:
var blocker = new BlocksAttacks(
// The number of seconds to wait when the item is being used
// before the blocking effect is applied.
1.2f,
// A scalar to change how many ticks the blocker is disabled
// for. If negative, the blocker cannot normally be disabled.
0.5f,
// A list of reductions for what type and how much of a damage type
// is blocked by this blocker.
List.of(
new DamageReduction(
// The horizontal blocking angle of the shield required to apply
// the reduction
90f,
// A set of damage types this reduction should apply for.
// When empty, it applies for all damage types.
Optional.empty(),
// The base damage to reduce the attack by.
1f,
// A scalar representing the fraction of the damage blocked.
0.5f
)
),
// A function that determines how much durability to remove to the blocker.
new ItemDamageFunction(
// A threshold that specifies the minimum amount of damage required
// to remove durability from the blocker.
4f,
// The base durability to remove from the blocker.
1f,
// A scalar representing the fraction of the damage to convert into
// removed durability.
0.5f
),
// A tag key containing the items that can bypass the blocker and deal
// damage directly to the wielding entity. If empty, no item can bypass
// the blocker.
Optional.of(DamageTypeTags.BYPASSES_SHIELD),
// The sound to play when the blocker successfully mitigates some damage.
Optional.of(SoundEvents.SHIELD_BLOCK),
// The sound to play when the blocker is disabled by a weapon.
Optional.of(SoundEvents.SHIELD_BREAK)
);
Constructing a Weapon component for a sword-like item:
var weapon = new Weapon(
// The amount of durability to remove from the item.
3,
// The number of seconds a `BlocksAttack`s component item should
// be disabled for when hit with this weapon.
5f
);
net.minecraft.core.component.DataComponentsUNBREAKABLEis now aUnitinstanceHIDE_ADDITIONAL_TOOLTIP,HIDE_TOOLTIPhave been bundled inTOOLTIP_DISPLAY, taking in aTooltipDisplayBLOCKS_ATTACKS- A component that determines whether a held item can block an attack from some damage sourceINSTRUMENTnow takes in anInstrumentComponentPROVIDES_TRIM_MATERIAL,PROVIDES_BANNER_PATTERNShandles a provider for their associated types.BEESnow takes in aBeescomponentBREAK_SOUND- The sound to play when the item breaks.
net.minecraft.data.recipesRecipeProvider#trimSmithingnow takes in the key for theTrimPatternSmithingTrimRecipeBuildernow takes in a holder for theTrimPattern
net.minecraft.world.entity.LivingEntityblockUsingShield->blockUsingItemblockedByShield->blockedByItemhurtCurrentlyUsedShieldis removedcanDisableBlocking->getSecondsToDisableBlocking, not one-to-oneapplyItemBlocking- Applies the damage reduction done when blocking an attack with an item.isDamageSourceBlockedis removed
net.minecraft.world.entity.player.Player#disableShield->net.minecraft.world.item.component.BlocksAttacks#disablenet.minecraft.world.itemAnimalArmorItemclass is removedArmorItemclass is removedAxeItemnow extendsItemBannerPatternItemclass is removedDiggerItemclass is removedFireworkStarItemclass is removedHoeItemnow extendsItemInstrumentItemno longer takes in the tag keyItemgetBreakingSoundis removed$Propertiestool- Sets the item as a tool.pickaxe- Sets the item as a pickaxe.sword- Sets the item as a sword.axe- Sets the item as an axe.hoe- Sets the item as a hoe.shovel- Sets the item as a shovel.trimMaterial- Sets the item as providing a trim material.
ItemStack#getBreakingSoundis removedPickaxeItemclass is removedShovelItemnow extendsItemSwordItemclass is removedToolMaterial#applyToolPropertiesnow takes in a boolean of whether the weapon can disable a blocker (e.g., shield)
net.minecraft.world.item.componentBees- A component that holds the occupants of a beehive.BlocksAttacks- A component for blocking an attack with a held item.InstrumentComponent- A component that holds the sound an instrument plays.ProvidesTrimMaterial- A component that provides a trim material to use on some armor.Toolnow takes in a boolean representing if the tool can destroy blocks in creativeUnbreakableclass is removedWeapon- A data component that holds how much damage the item can do and for how long it disables blockers (e.g., shield).
net.minecraft.world.item.equipmentAllowedEntitiesProvider- A functional interface for getting the entities that are allowed to handle the associated logic.ArmorMaterialhumanoidProperties->Item$Properties#humanoidArmoranimalProperties->Item$Properties#wolfArmor,horseArmorcreateAttributesis now public
EquippableequipOnInteract- When true, the item can be equipped to another entity when interacting with them.saddle- Creates an equippable for a saddle.equipOnTarget- Equips the item onto the target entity.
Extrapolating the Saddles: Equipment Changes
A new EquipmentSlot has been added for saddles, which brings with it new changes for genercizing slot logic.
First, rendering an equipment slot for an entity can now be handled as an additional RenderLayer called SimpleEquipmentLayer. This takes in the entity renderer, the EquipmentLayerRenderer, the layer type to render, a function to get the ItemStack from the entity state, and the adult and baby models. The renderer will attempt to look up the client info from the associated equippable data component and use that to render the laters as necessary.
Next, instead of having individual lists for each equipment slot on the entity, there is now a general EntityEquipment object that holds a delegate to a map of slots to ItemStacks. This simplifies the storage logic greatly.
Finally, equippables can now specify whether an item should be equipped to a mob on interact (usually right-click) by setting equipOnInteract.
net.minecraft.client.modelCamelModelheadis now publiccreateBodyMesh- Creates the mesh definition for a camel.
CamelSaddleModel- A model for a camel with a saddle.DonkeyModel#createSaddleLayer- Creates the layer definition for a donkey with a saddle.EquineSaddleModel- A model for an equine animal with a saddle.PolarBearModel#createBodyLayernow takes in a boolean for if the entity is a baby
net.minecraft.client.renderer.entity.layers.HorseArmorLayer,SaddleLayer->SimpleEquipmentLayernet.minecraft.client.renderer.entity.stateCamelRenderState#isSaddled->saddle, not one-to-oneEquineRenderState#isSaddled->saddle, not one-to-onePigRenderState#isSaddled->saddle, not one-to-oneSaddleableRenderStateclass is removedStriderRenderState#isSaddled->saddle, not one-to-oneCamelRenderState#isSaddled->saddle, not one-to-one
net.minecraft.client.resources.model.EquipmentClientInfo$LayerTypenow has:PIG_SADDLESTRIDER_SADDLECAMEL_SADDLEHORSE_SADDLEDONKEY_SADDLEMULE_SADDLEZOMBIE_HORSE_SADDLESKELETON_HORSE_SADDLEtrimAssetPrefix- Returns the prefix applied to the texture containing the armor trims for the associated type.
net.minecraft.world.entityEntityEquipment- A map of slots to item stacks representing the equipment of the entity.EquipmentSlotSADDLE,$Type#SADDLEcanIncreaseExperience- Whether the slot can increase the amount of experience earned when killing a mob.
EquipmentSlotGroupis now an iterableSADDLEslots- Returns the slots within the group.
LivingEntitygetEquipSound- Gets the sound to play when equipping an item into a slot.getArmorSlots,getHandSlots,getArmorAndBodyArmorSlots,getAllSlotsare removedequipment- The equipment worn by the entity.createEquipment- Sets the default equipment worn by the entity.drop- Drops the specified stack.getItemBySlot,setItemBySlotare no longer abstract.verfiyEquippedItemis removed
MobisSaddled- Checks if an item is in the saddle slot.createEquipmentSlotContainer- Creates a single item container for the equipment slot.
OwnableEntity#getRootOwner- Gets the highest level owner of the entity.Saddleableinterface is removed
net.minecraft.world.entity.animal.horse.AbstractHorsesyncSaddletoClientsis removedgetBodyArmorAccessis removed
net.minecraft.world.entity.playerInventoryarmor,offhand->EQUIPMENT_SLOT_MAPPING, not one-to-oneselectedis now privatesetSelectedHotbarSlot->setSelectedSlot- Getter also exists
getSelectedSlot
- Getter also exists
getSelected->getSelectedItem- Setter also exists
setSelectedItem
- Setter also exists
getNonEquipmentItems- Returns the list of non-equipment items in the inventory.getDestroySpeedis removedgetArmoris removed
PlayerEquipment- Equipment that is worn by the player.
net.minecraft.world.itemItem#inventoryTick(ItemStack, Level, Entity, int, boolean)->inventoryTick(ItemStack, ServerLevel, Entity, EquipmentSlot)SaddleItemclass is removed
Weighted List Rework
The weighted random lists have been redesigned into a basic class that hold weighted entries, and a helper class that can obtain weights from the objects themselves.
First there is WeightedList. It is effectively the replacement for SimpleWeightedRandomList, working the exact same way by storing Weighted (replacement for WeightedEntry) entries in the list itself. Internally, the list is either stored as a flat array of object entries, or the compact weighted list if the total weight is greater than 64. Then, to get a random element, either getRandom or getRandomOrThrow can be called to obtain an entry. Both of these methods will either return some form of an empty object or exception if there are no elements in the list.
Then there are the static helpers within WeightedRandom. These take in raw lists and some ToIntFunction that gets the weight from the list’s object. Some methods also take in an integer either representing the largest index to choose from or the entry associated with the weighted index.
net.minecraft.client.resources.model.WeightedBakedModelnow takes in aWeightedListinstead of aSimpleWeightedRandomListnet.minecraft.util.randomSimpleWeightedRandomList,WeightedRandomList->WeightedList, now final and not one-to-onecontains- Checks if the list contains this element.
Weightclass is removedWeightedEntry->Weighted- All
WeightedRandomstatic methods now take in aToIntFunctionto get the weight of some entry within the provided list
net.minecraft.util.valueproviders.WeightedListIntnow takes in aWeightedListnet.minecraft.world.level.SpawnData#LIST_CODECis now aWeightedListofSpawnDatanet.minecraft.world.level.biomeBiome#getBackgroundMusicis now aWeightedListofMusicBiomeSpecialEffects#getBackgroundMusic,$Builder#backgroundMusicis now aWeightedListofMusicMobSpawnSettings#EMPTY_MOB_LIST,getMobsis now aWeightedList
net.minecraft.world.level.block.entity.trialspawner.TrialSpawnerConfig#spawnPotentialsDefinition,lootTablesToEjectnow takes in aWeightedListnet.minecraft.world.level.chunk.ChunkGenerator#getMobsAtnow returns aWeightedListnet.minecraft.world.level.levelgen.feature.stateproviders.WeightedStateProvidernow works withWeightedListsnet.minecraft.world.level.levelgen.heightproviders.WeightedListHeightnow works withWeightedListsnet.minecraft.world.level.levelgen.structure.StructureSpawnOverridenow takes in aWeightedListnet.minecraft.world.level.levelgen.structure.pools.aliasPoolAliasBinding#random,randomGroupnow takes in aWeightedListRandomnow takes in aWeightedListRandomGroupnow takes in aWeightedList
net.minecraft.world.level.levelgen.structure.structures.NetherFortressStructure#FORTRESS_ENEMIESis now aWeightedList
Tickets
Tickets have been reimplemented into a half type registry-like, half hardcoded system. The underlying logic of keeping a chunk loaded or simulated for a certain period of time still exists; however, the logic associated with each ticket is hardcoded into their appropriate locations, such as the forced or player loading tickets.
Tickets begin with their registered TicketType, which contains information about how many ticks should the ticket should last for (or 0 when permanent), whether the ticket should be saved to disk, and what the ticket is used for. A ticket has two potential uses: one for loading the chunk and keeping it loaded, and one for simulating the chunk based on the expected movement of the ticket creator. Most ticks specify that they are for both loading and simulation.
There are two special types that have additional behavior associated with them. TicketType#FORCED has some logic for immediately loading the chunk and keeping it loaded. TicketType#UNKNOWN cannot be automatically timed out, meaning they are never removed unless explicitly specified.
// You need to register the ticket type to `BuiltInRegistries#TICKET_TYPE`
public static final TicketType EXAMPLE = new TicketType(
// The amount of ticks before the ticket is removed
// Set to 0 if it should not be removed
0L,
// Whether the ticket should be saved to disk
true,
// What the ticket will be used for
TicketType.TicketUse.LOADING_AND_SIMULATION
);
Then there is the Ticket class, which are actually stored and handled within the TicketStorage. The Ticket class takes in the type of the ticket and uses it to automatically populate how long until it expires. It also takes in the ticket level, which is a generally a value of 31 (for entity ticking and block ticking), 32 (for block ticking), or 33 (only can access static or modify, not naturally update) minus the radius of chunks that can be loaded. A ticket is then added to the process by calling TicketStorage#addTicketWithRadius or its delegate ServerChunkCache#addTicketWithRadius. There is also addTicket if you wish to specify the ticket manually rather than having it computed based on its radius.
net.minecraft.server.levelChunkMapnow takes in aTicketStorage$TrackedEntity#broadcastIgnorePlayers- Broadcasts the packet to all player but those within the UUID list.
DistanceManagerchunksToUpdateFuturesis now protected and takes in aTicketStoragepurgeStaleTickets->net.minecraft.world.level.TicketStorage#purgeStaleTicketsgetTicketDebugString->net.minecraft.world.level.TicketStorage#getTicketDebugStringgetChunkLevel- Returns the current chunk level or the simulated level when the provided boolean is true.getTickingChunksis removedremoveTicketsOnClosingis removed$ChunkTicketTracker->LoadingChunkTracker, orSimulationChunkTracker
ServerChunkCacheaddRegionTicket->addTicketWithRadius, oraddTicketremoveRegionTicket->removeTicketWithRadiusremoveTicketsOnClosing->deactivateTicketsOnClosing
Ticketis no longer final or implementsComparable- The constructor no longer takes in a key
CODECsetCreatedTick,timedOut->resetTicksLeft,decreaseTicksLeft,isTimedOut; not one-to-one
TicketTypeis now a record and no longer has a genericgetComparatoris removeddoesLoad,doesSimulate- Checks whether the ticket use is for their particular instance.$TicketUse- What a ticket can be used for.
TickingTracker->SimulationChunkTracker
net.minecraft.world.level.ForcedChunksSavedData->TicketStoragenet.minecraft.world.level.chunk.ChunkSourceupdateChunkForcednow returns a boolean indicating if the chunk has been forcefully loadedgetForceLoadedChunks- Returns all chunks that have been forcefully loaded.
The Game Test Overhaul
Game tests have been completely overhauled into a registry based system, completely revamped from the previous automatic annotation-driven system. However, most implementations required to use the system must be implemented yourself rather than provided by vanilla. As such, this explanation will go over the entire system, including which parts need substantial work to use it similarly to the annotation-driven system of the previous version.
The Environment
All game tests happen within some environment. Most of the time, a test can occur independent of the area, but sometimes, the environment needs to be curated in some fashion, such as checking whether an entity or block does something at a given time or whether. To facilitate the setup and teardown of the environment for a given test instance, a TestEnvironmentDefinition is created.
A TestEnvironmentDefinition works similarly to the BeforeBatch and AfterBatch annotations. The environment contains two methods setup and teardown that manage the ServerLevel for the test. The environments are structured in a type-based registry system, meaning that every environment registers a MapCodec to built-in registry minecraft:test_environment_definition_type that is then consumed via the TestEnvironmentDefinition in a datapack registry minecraft:test_environment.
Vanilla, by default, provides the minecraft:default test environment which does not do anything. However, additional test environments can be created using the available test definition types.
Game Rules
This environment type sets the game rules to use for the test. During teardown, the game rules are set back to their default value.
// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
"type": "minecraft:game_rules",
// A list of game rules with boolean values to set
"bool_rules": [
{
// The name of the rule
"rule": "doFireTick",
"value": false
}
// ...
],
// A list of game rules with integer values to set
"int_rules": [
{
"rule": "playersSleepingPercentage",
"value": 50
}
// ...
]
}
Time of Day
This environment type sets the time to some non-negative integer, similar to how the /time set <number> command is used.
// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
"type": "minecraft:time_of_day",
// Sets the time of day in the world
// Common values:
// - Day -> 1000
// - Noon -> 6000
// - Night -> 13000
// - Midnight -> 18000
"time": 13000
}
Weather
This environment type sets the weather, similar to how the /weather command is used.
// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
"type": "minecraft:weather",
// Can be one of three values:
// - clear (No weather)
// - rain (Rain)
// - thunder (Rain and thunder)
"weather": "thunder"
}
Function
This environment type provides two ResourceLocations to mcfunctions to setup and teardown the level, respectively.
// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
"type": "minecraft:function",
// The setup mcfunction to use
// If not specified, nothing will be ran
// Points to 'data/examplemod/function/example/setup.mcfunction'
"setup": "examplemod:example/setup",
// The teardown mcfunction to use
// If not specified, nothing will be ran
// Points to 'data/examplemod/function/example/teardown.mcfunction'
"teardown": "examplemod:example/teardown"
}
Composite
If multiple combinations are required, then the composite environment type (aptly named all_of) can be used to string multiple of the above environment types together.
// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
"type": "minecraft:all_of",
// A list of test environments to use
// Can either specified the registry name or the environment itself
"definitions": [
// Points to 'data/minecraft/test_environment/default.json'
"minecraft:default",
{
// A raw environment definition
"type": "..."
}
// ...
]
}
Custom Types
If none of the types above work, then a custom definition can be created by implementing TestEnvironmentDefinition and creating an associated MapCodec:
public record ExampleEnvironmentType(int value1, boolean value2) implements TestEnvironmentDefinition {
// Construct the map codec to register
public static final MapCodec<ExampleEnvironmentType> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
Codec.INT.fieldOf("value1").forGetter(ExampleEnvironmentType::value1),
Codec.BOOL.fieldOf("value2").forGetter(ExampleEnvironmentType::value2)
).apply(instance, ExampleEnvironmentType::new)
);
@Override
public void setup(ServerLevel level) {
// Setup whatever is necessary here
}
@Override
public void teardown(ServerLevel level) {
// Undo whatever was changed within the setup method
// This should either return to default or the previous value
}
@Override
public MapCodec<ExampleEnvironmentType> codec() {
return CODEC;
}
}
Then register the MapCodec using whatever registry method is required by your mod loader:
Registry.register(
BuiltInRegistries.TEST_ENVIRONMENT_DEFINITION_TYPE,
ResourceLocation.fromNamespaceAndPath("examplemod", "example_environment_type"),
ExampleEnvironmentType.CODEC
);
Finally, you can use it in your environment definition:
// examplemod:example_environment
// In 'data/examplemod/test_environment/example_environment.json'
{
"type": "examplemod:example_environment_type",
"value1": 0,
"value2": true
}
Test Functions
The initial concept of game tests were structured around running functions from GameTestHelper determining whether the test succeeds or fails. Test functions are the registry-driven representation of those. Essentially, every test function is a method that takes in a GameTestHelper.
At the moment, vanilla only provides minecraft:always_pass, which just calls GameTestHelper#succeed. Test functions are also not generated, meaning it simply runs the value with whatever is provided. As such, a test function should generally represent a single old game test:
Registry.register(
BuiltInRegistries.TEST_FUNCTION,
ResourceLocation.fromNamespaceAndPath("examplemod", "example_function"),
(GameTestHelper helper) -> {
// Run whatever game test commands you want
helper.assertBlockPresent(...);
// Make sure you have some way to succeed
helper.succeedIf(() -> ...);
}
);
Test Data
Now that we have environments and test functions, we can get into defining our game test. This is done through TestData, which is the equivalent of the GameTest annotation. The only things changed are that structures are now referenced by their ResourceLocation via structure, GameTest#timeoutTicks is now renamed to TestData#maxTicks, and instead of specifying GameTest#rotationSteps, you simply provide the Rotation via TestData#rotation. Everything else remains the same, just represented in a different format.
The Game Test Instance
With the TestData in hand, we can now link everything together through the GameTestInstance. This instance is what actually represents a single test. Once again, vanilla only provides the default minecraft:always_pass, so we will need to construct the instance ourselves.
The Original Instance
The previous game tests are implemented using minecraft:function, which links a test function to the test data.
// examplemod:example_test
// In 'data/examplemod/test_instance/example_test.json'
{
"type": "minecraft:function",
// Points to a 'Consumer<GameTestHelper>' in the test function registry
"function": "examplemod:example_function",
// The 'TestData' information
// The environment to run the test in
// Points to 'data/examplemod/test_environment/example_environment.json'
"environment": "examplemod:example_environment",
// The structure used for the game test
// Points to 'data/examplemod/structure/example_structure.nbt'
"structure": "examplemod:example_structure",
// The number of ticks that the game test will run until it automatically fails
"max_ticks": 400,
// The number of ticks that are used to setup everying required for the game test
// This is not counted towards the maximum number of ticks the test can take
// If not specified, defaults to 0
"setup_ticks": 50,
// Whether the test is required to succeed to mark the batch run as successful
// If not specified, defaults to true
"required": true,
// Specifies how the structure and all subsequent helper methods should be rotated for the test
// If not specified, nothing is rotated
"rotation": "clockwise_90",
// When true, the test can only be ran through the `/test` command
// If not specified, defaults to false
"manual_only": true,
// Specifies the maximum number of times that the test can be reran
// If not specified, defaults to 1
"max_attempts": 3,
// Specifies the minimum number of successes that must occur for a test to be marked as successful
// This must be less than or equal to the maximum number of attempts allowed
// If not specified, defaults to 1
"required_successes": 1,
// Returns whether the structure boundary should keep the top empty
// This is currently only used in block-based test instances
// If not specified, defaults to false
"sky_access": false
}
Block-Based Instances
Vanilla also provides a block-based test instance via minecraft:block_based. This is handled through via structures with test blocks receiving signals via Level#hasNeighborSignal. To start, a structure must have one test block which is set to its start mode. This block is then triggered, sending a fifteen signal pulse for one tick. Structures may then have as many test blocks with either a log, accept, or fail mode set. Log test blocks also send a fifteen signal pulse when activated. Accept and fail test blocks either succeed or fail the game test if any of them are activated (success takes precedent over failure).
As this test relies on test blocks in the structure, no additional information is required other than the test data:
// examplemod:example_test
// In 'data/examplemod/test_instance/example_test.json'
{
"type": "minecraft:block_based",
// The 'TestData' information
// Points to 'data/examplemod/test_environment/example_environment.json'
"environment": "examplemod:example_environment",
// Points to 'data/examplemod/structure/example_structure.nbt'
"structure": "examplemod:example_structure",
"max_ticks": 400,
"setup_ticks": 50,
"required": true,
"rotation": "clockwise_90",
"manual_only": true,
"max_attempts": 3,
"required_successes": 1,
"sky_access": false
}
Custom Tests
If you need to implement your own test-based logic, whether using a more dynamic feature or because you can’t be bothered to migrated all of your data logic to the new systems, you can create your own custom test instance by extending GameTestInstance and creating an associated MapCodec:
public class ExampleTestInstance extends GameTestInstance {
// Construct the map codec to register
public static final MapCodec<ExampleTestInstance> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
Codec.INT.fieldOf("value1").forGetter(test -> test.value1),
Codec.BOOL.fieldOf("value2").forGetter(test -> test.value2),
TestData.CODEC.forGetter(ExampleTestInstance::info)
).apply(instance, ExampleTestInstance::new)
);
public ExampleTestInstance(int value1, boolean value2, TestData<Holder<TestEnvironmentDefinition>> info) {
super(info);
}
@Override
public void run(GameTestHelper helper) {
// Run whatever game test commands you want
helper.assertBlockPresent(...);
// Make sure you have some way to succeed
helper.succeedIf(() -> ...);
}
@Override
public MapCodec<ExampleTestInstance> codec() {
return CODEC;
}
@Override
protected MutableComponent typeDescription() {
// Provides a description about what this test is supposed to be
// Should use a translatable component
return Component.literal("Example Test Instance");
}
}
Then register the MapCodec using whatever registry method is required by your mod loader:
Registry.register(
BuiltInRegistries.TEST_INSTANCE_TYPE,
ResourceLocation.fromNamespaceAndPath("examplemod", "example_test_instance"),
ExampleTestInstance.CODEC
);
Finally, you can use it in your test instance:
// examplemod:example_test
// In 'data/examplemod/test_instance/example_test.json'
{
"type": "examplemod:example_test_instance",
"value1": 0,
"value2": true,
// The 'TestData' information
// Points to 'data/examplemod/test_environment/example_environment.json'
"environment": "examplemod:example_environment",
// Points to 'data/examplemod/structure/example_structure.nbt'
"structure": "examplemod:example_structure",
"max_ticks": 400,
"setup_ticks": 50,
"required": true,
"rotation": "clockwise_90",
"manual_only": true,
"max_attempts": 3,
"required_successes": 1,
"sky_access": false
}
net.minecraft.client.renderer.blockentityBeaconRenderernow has a generic that takes in a subtype ofBlockEntityandBeaconBeamOwnerStructureBlockRenderer->BlockEntityWithBoundingBoxRenderer, not one-to-one
net.minecraft.core.registries.Registries#TEST_FUNCTION,TEST_ENVIRONMENT_DEFINITION_TYPE,TEST_INSTANCE_TYPEnet.minecraft.gametest.Main- The entrypoint for the game test server.net.minecraft.gametest.frameworkAfterBatch,BeforeBatchannotations are removedBlockBasedTestInstance- A test instance for testing the test block.BuiltinTestFunctions- Contains all registered test functions.FailedTestTracker- An object for holding all game tests that failed.FunctionGameTestInstance- A test instance for running a test function.GameTestannotation is removedGameTestAssertExceptionnow extendsGameTestExceptionGameTestException- An exception thrown during the execution of a game test.GameTestBatchnow takes in an index and environment definition instead of a name and batch setupsGameTestBatchFactoryfromTestFunction->divideIntoBatches, not one-to-onetoGameTestInfois removedtoGameTestBatchnow takes in an environment definition and an index$TestDecorator- Creates a list of test infos from a test instance and level.
GameTestEnvironments- Contains all environments used for batching game test instances.GameTestGeneratorannotation is removedGameTestHelpertickBlock- Ticks the block at the specific position.assertionException- Returns a new exception to throw on error.getBlockEntitynow takes in aClassto cast the block entity toassertBlockTag- Checks whether the block at the position is within the provided tag.assertBlocknow takes in a block -> component function for the error message.assertBlockPropertynow takes in aComponentinstead of a stringassertBlockStatenow takes in either nothing, a blockstate -> component function, or a supplied componentassertRedstoneSignalnow takes in a supplied componentassertContainerSingle- Asserts that a container contains exactly one of the item specified.assertEntityPosition,assertEntityPropertynow takes in a componentfailnow takes in aComponentfor the error messageassertTrue,assertValueEqual,assertFalsenow takes in a component
GameTestInfonow takes in a holder-wrappedGameTestInstanceinstead of aTestFunctionsetStructureBlockPos->setTestBlockPosplaceStructurenow returns nothinggetTestName-id, not one-to-onegetStructureBlockPos->getTestBlockPosgetStructureBlockEntity->getTestInstanceBlockEntitygetStructureName->getStructuregetTestFunction->getTest,getTestHolder, not one-to-onegetOrCalculateNorthwestCorner,setNorthwestCornerare removedfailnow takes in aComponentorGameTestExceptioninstead of aThrowablegetErrornow returns aGameTestExceptioninstead of aThrowable
GameTestInstance- Defines a test to run.GameTestInstances- Contains all registered tests.GameTestMainUtil- A utility for running the game test server.GameTestRegistryclass is removedGameTestSequencetickAndContinue,tickAndFailIfNotCompletenow take in an integer for the tick instead of a longthenFailnow takes in a suppliedGameTestExceptioninstead of aThrowable
GameTestServer#createnow takes in an optional string and boolean instead of the collection of test functions and the starting positionGeneratedTest- A object holding the test to run for the given environment and the function to applyGameTestTicker$State- An enum containing what state the game test ticker is currently executing.GameTestTimeoutExceptionnow extendsGameTestExceptionReportGameListener#spawnBeaconis removedStructureBlockPosFinder->TestPosFinderStructureUtilstestStructuresDiris now a pathgetStructureBounds,getStructureBoundingBox,getStructureOrigin,addCommandBlockAndButtonToStartTestare removedcreateNewEmptyStructureBlock->createNewEmptyTest, not one-to-onegetStartCorner,prepareTestStructure,encaseStructure,removeBarriersare removedfindStructureBlockContainingPos->findTestContainingPosfindNearestStructureBlock->findNearestTestfindStructureByTestFunction,createStructureBlockare removedfindStructureBlocks->findTestBlockslookedAtStructureBlockPos->lookedAtTestPos
TestClassNameArgumentis removedTestEnvironmentDefinition- Defines the environment that the test is run on by setting the data on the level appropriately.TestFinderno longer contains a generic for the context$Builder#allTests,allTestsInClass,locateByNameare removed$Builder#byArgument->byResourceSelection
TestFunction->TestData, not one-to-oneTestFunctionArgument->net.minecraft.commands.arguments.ResourceSelectorArgumentTestFunctionFinder->TestInstanceFinderTestFunctionLoader- Holds the list of test functions to load and run.UnknownGameTestException- An exception that is thrown when the error of the game test is unknown.
net.minecraft.network.protocol.gameClientboundTestInstanceBlockState- A packet sent to the client containing the status of a test along with its size.ServerboundSetTestBlockPacket- A packet sent to the server to set the information within the test block to run.ServerboundTestInstanceBlockActionPacket- A packet sent to the server to set up the test instance within the test block.
net.minecraft.world.entity.player.PlayeropenTestBlock- Opens a test block.openTestInstanceBlock- Opens a test block for a game test instance.
net.minecraft.world.level.blockTestBlock- A block used for running game tests.TestInstanceBlock- A block used for managing a single game test.
net.minecraft.world.level.block.entityBeaconBeamOwner- An interface that represents a block entity with a beacon beam.BeaconBlockEntitynow implementsBeaconBeamOwnerBeaconBeamSection->BeaconBeamOwner$Section
BoundingBoxRenderable- An interface that represents a block entity that can render an arbitrarily-sized bounding box.StructureBlockEntitynow implementsBoundingBoxRenderableTestBlockEntity- A block entity used for running game tests.TestInstanceBlockEntity- A block entity used for managing a single game test.
net.minecraft.world.level.block.state.properties.TestBlockMode- A property for representing the current state of the game tests associated with a test block.
Data Component Getters
The data component system can now be represented on arbitrary objects through the use of the DataComponentGetter. As the name implies, the getter is responsible for getting the component from the associated type key. Both block entities and entities use the DataComponentGetter to allow querying the internal data, such as variant information or custom names. They both also have methods for collecting the data components from another holder (via applyImplicitComponents or applyImplicitComponent). Block entities also contain a method for collection to another holder via collectImplicitComponents.
Items
ItemSubPredicates have been completely replaced with DataComponentPredicates. Each sub predicate has its appropriate analog within the system.
net.minecraft.advancements.critereon.*->net.minecraft.core.component.predicates.*ItemAttributeModifiersPredicate->AttributeModifiersPredicateItemBundlePredicate->BundlePredicateItemContainerPredicate->ContainerPredicateItemCustomDataPredicate->CustomDataPredicateItemDamagePredicate->DamagePredicateItemEnchantmentsPredicate->EnchantmentsPredicateItemFireworkExplosionPredicate->FireworkExplosionPredicateItemFireworksPredicate->FireworksPredicateItemJukeboxPlayablePredicate->JukeboxPlayablePredicateItemPotionsPredicate->PotionsPredicateItemSubPredicate->DataComponentPredicate, not one-to-oneSINGLE_STREAM_CODEC
ItemSubPredicates->DataComponentPredicates, not one-to-oneItemTrimPredicate->TrimPredicateItemWritableBookPredicate->WritableBookPredicateItemWrittenBookPredicate->WrittenBookPredicate
net.minecraft.advancements.critereonBlockPredicatenow takes in aDataComponentMatchersfor matching any delegated component dataDataComponentMatchers- A predicate that operates on aDataComponentGetter, matching any exact and partial component data on the provider.EntityPredicatenow takes in aDataComponentMatchersinstead of aOptional<DataComponentExactPredicate>ItemPredicatenow takes in aDataComponentMatchersfor matching any delegated component dataNbtPredicate#matchesnow takes in aDataComponentGetterinstead of anItemStackSingleComponentItemPredicatenow implementsDataComponentPredicateinstead ofItemSubPredicatematches(ItemStack, T)->matches(T)
net.minecraft.core.componentDataComponentPatchDELIMITED_STREAM_CODEC$CodecGetter- Gets the codec for a given component type.
DataComponentPredicate->DataComponentExactPredicateisEmpty- Checks if the expected components list within the predicate is empty.
net.minecraft.core.registries.Registries#ITEM_SUB_PREDICATE_TYPE->DATA_COMPONENT_PREDICATE_TYPE, not one-to-onenet.minecraft.world.item.AdventureModePredicateno longer takes in a boolean to show in tooltipnet.minecraft.world.itemBannerItem#appendHoverTextFromBannerBlockEntityTagis removedItem#appendHoverText(ItemStack, Item.TooltipContext, List<Component>, TooltipFlag)->appendHoverText(ItemStack, Item.TooltipContext, TooltipDisplay, Consumer<Component>, TooltipFlag), now deprecatedItemStackaddToTooltipis now publicaddDetailsToTooltip- Appends the component details of an item to the tooltip.
JukeboxPlayable#showInTooltipis removed
net.minecraft.world.item.componentBlockItemStatePropertiesnow implementsTooltipProviderChargedProjectilesnow implementsTooltipProviderCustomData#itemMatcheris removedDyedItemColor#showInTooltipis removedFireworkExplosion#addShapeNameTooltipis removedItemAttributeModifiers#showInTooltipis removedItemContainerContentsnow implementsTooltipProviderSeededContainerLootnow implementsTooltipProviderTooltipDisplay- A component that handles what should be hidden within an item’s tooltip.TooltipProvider#addToTooltipnow takes in aDataComponentGetter
net.minecraft.world.item.enchantment.ItemEnchantments#showInTooltipis removednet.minecraft.world.item.equipment.trim.ArmorTrim#showInTooltipis removednet.minecraft.world.item.trading.ItemCostnow takes in aDataComponentExactPredicateinstead of aDataComponentPredicatenet.minecraft.world.level.block.Block#appendHoverTextis removednet.minecraft.world.level.block.entityBannerPatternLayersnow implementsTooltipProviderPotDecorationsnow implementsTooltipProvider
net.minecraft.world.level.saveddata.maps.MapIdnow implementsTooltipProvider
Entities
Some EntitySubPredicates for entity variants have been transformed into data components stored on the held item due to a recent change on EntityPredicate now taking in a DataComponentExactPredicate for matching the slots on an entity.
net.minecraft.advancements.critereonEntityPredicatenow takes in aDataComponentExactPredicateto match the equipment slots checkedEntitySubPredicateAXOLTOL->DataComponents#AXOLOTL_VARIANTFOX->DataComponents#FOX_VARIANTMOOSHROOM->DataComponents#MOOSHROOM_VARIANTRABBIT->DataComponents#RABBIT_VARIANTHORSE->DataComponents#HORSE_VARIANTLLAMA->DataComponents#LLAMA_VARIANTVILLAGER->DataComponents#VILLAGER_VARIANTPARROT->DataComponents#PARROT_VARIANTSALMON->DataComponents#SALMON_SIZETROPICAL_FISH->DataComponents#TROPICAL_FISH_PATTERN,TROPICAL_FISH_BASE_COLOR,TROPICAL_FISH_PATTERN_COLORPAINTING->DataComponents#PAINTING_VARIANTCAT->DataComponents#CAT_VARIANT,CAT_COLLARFROG->DataComponents#FROG_VARIANTWOLF->DataComponents#WOLF_VARIANT,WOLF_COLLARPIG->DataComponents#PIG_VARIANTregisterwith variant subpredicates have been removedcatVariant,frogVariant,wolfVariantare removed$EntityHolderVariantPredicateType,$EntityVariantPredicateTypeare removed
SheepPredicateno longer takes in theDyeColor
net.minecraft.client.renderer.entity.state.TropicalFishRenderState#variant->patternnet.minecraft.core.componentDataComponentGetter- A getter that obtains data components from some object.DataComponentHolder,DataComponentMapnow extendsDataComponentGetterDataComponentExactPredicateis now a predicate of aDataComponentGetterexpect- A predicate that expects a certain value for a data component.test(DataComponentHolder)is removed
DataComponentsSHEEP_COLOR- The dye color of a sheep.SHULKER_COLOR- The dye color of a shulker (box).COW_VARIANT- The variant of a cow.CHICKEN_VARIANT- The variant of a chicken.WOLF_SOUND_VARIANT- The sounds played by a wolf.
net.minecraft.world.entityEntitynow implementsDataComponentGetterapplyImplicitComponents- Applies the components from the getter onto the entity. This should be overriden by the modder.applyComponentsFromItemStack- Applies the components from the stack onto the entity.castComponentValue- Casts the type of the object to the component type.setComponent- Sets the component data onto the entity.applyImplicitComponent- Applies the component data to the entity. This should be overriden by the modder.applyImplicitComponentIfPresent- Applies the component if it is present on the getter.
EntityType#appendCustomNameConfig->appendComponentsConfigVariantHolderinterface is removed- As such, all
setVariantmethods on relevant entities are private while the associated data can also be obtained from theDataComponentGetter
- As such, all
net.minecraft.world.entity.animalCatVariant#CODECFox$Variant#STREAM_CODECFrogVariant#CODECMushroomCow$Variant#STREAM_CODECParrot$Variant#STREAM_CODECRabbit$Variant#STREAM_CODECSalmon$Variant#STREAM_CODECTropicalFishgetVariant->getPattern$Patternnow implementsTooltipProvider
Wolf->.wolf.WolfWolfVariant->.wolf.WolfVariant, now a record, taking in an$AssetInfoand aSpawnPrioritySelectorsWolfVariants->.wolf.WolfVariants
net.minecraft.world.entity.animal.axolotl.Axolotl$Variant#STREAM_CODECnet.minecraft.world.entity.animal.horseLlama$Variant#STREAM_CODECVariant#STREAM_CODEC
net.minecraft.world.entity.animal.wolfWolfSoundVariant- The sounds played by a wolf.WolfSoundVariants- All vanilla wolf sound variants.
net.minecraft.world.entity.decoration.PaintingVARIANT_MAP_CODECis removedVARIANT_CODECis now private
net.minecraft.world.entity.npc.VillagerDataHolder#getVariant,setVariantare removednet.minecraft.world.entity.variant.VariantUtils- A utility for getting the variant info of an entity.net.minecraft.world.itemItemStack#copyFrom- Copies the component from the getter.MobBucketItem#VARIANT_FIELD_CODEC->TropicalFish$Pattern#STREAM_CODEC
net.minecraft.world.level.block.entity.BlockEntity#applyImplicitComponentsnow takes in aDataComponentGetter$DataComponentInput->DataComponentGetter
net.minecraft.world.level.Spawnermethods now takes in aCustomDatainstead of theItemStackitself
Spawn Conditions
To allow entities to spawn variants randomly but within given conditions, a new registry called SPAWN_CONDITION_TYPE was added. These take in SpawnConditions: a selector that acts like a predicate to take in the context to see whether the given variant can spawn there. All of the variants are thrown into a list and then ordered based on the selected priorty stored in the SpawnProritySelectors. Those with a higher priority will be checked first, with multiple of the same priority selected in the order they are provided. Then, all variants on the same priority level where a condition has been met is selected at random.
// For some object where there are spawn conditions
[
{
// The spawn condition being checked
"condition": {
"type": "minecraft:biome",
// Will check that the biome the variant is attempting to spawn in is in the forest
"biomes": "#minecraft:is_forest"
},
// Will check this condition first
"priority": 1
},
{
// States that the condition will always be true
"priority": 0
}
]
net.minecraft.core.registries.Registries#SPAWN_CONDITION_TYPEnet.minecraft.world.entity.variantBiomeCheck- A spawn condition that checks whether the entity is in one of the given biomes.MoonBrightnessCheck- A spawn condition that checks the brightness of the moon.PriorityProvider- An interface which orders the condition selectors based on some priority integer.SpawnCondition- Checks whether an entity can spawn at this location.SpawnConditions- The available spawn conditions to choose from.SpawnContext- An object holding the current position, level, and biome the entity is being spawned within.SpawnPrioritySelectors- A list of spawn conditions to check against the entity. Used to select a random variant to spawn in a given location.StructureCheck- A spawn condition that checks whether the entity is within a structure.
Variant Datapack Registries
Frog, cat, cow, chicken, pig, and wolf, and wolf sound variants are datapack registry objects, meaning that most references now need to be referred to through the RegistryAccess or HolderLookup$Provider instance.
For a frog, cat, or wolf:
// A file located at:
// - `data/examplemod/frog_variant/example_frog.json`
// - `data/examplemod/cat_variant/example_cat.json`
// - `data/examplemod/wolf_variant/example_wolf.json`
{
// Points to a texture at `assets/examplemod/textures/entity/cat/example_cat.png`
"asset_id": "examplemod:entity/cat/example_cat",
"spawn_conditions": [
// The conditions for this variant to spawn
{
"priority": 0
}
]
}
For a pig, cow, or chicken:
// A file located at:
// - `data/examplemod/pig_variant/example_pig.json`
// - `data/examplemod/cow_variant/example_cow.json`
// - `data/examplemod/chicken_variant/example_chicken.json`
{
// Points to a texture at `assets/examplemod/textures/entity/pig/example_pig.png`
"asset_id": "examplemod:entity/pig/example_pig",
// Defines the `PigVariant$ModelType` that's used to select what entity model to render the pig variant with
"model": "cold",
"spawn_conditions": [
// The conditions for this variant to spawn
{
"priority": 0
}
]
}
For a wolf sound variant:
// A file located at:
// - `data/examplemod/wolf_sound_variant/example_wolf_sound.json``
{
// The registry name of the sound event to play randomly on idle
"ambient_sound": "minecraft:entity.wolf.ambient",
// The registry name of the sound event to play when killed
"death_sound": "minecraft:entity.wolf.death",
// The registry name of the sound event to play randomly when angry on idle
"growl_sound": "minecraft:entity.wolf.growl",
// The registry name of the sound event to play when hurt
"hurt_sound": "minecraft:entity.wolf.hurt",
// The registry name of the sound event to play randomly
// 1/3 of the time on idle when health is max
"pant_sound": "minecraft:entity.wolf.pant",
// The registry name of the sound event to play randomly
// 1/3 of the time on idle when health is below max
"whine_sound": "minecraft:entity.wolf.whine"
}
Client Assets
Raw ResourceLocations within client-facing files for identifiers or textures are being replaced with objects defining an idenfitier along with a potential texture path. There are three main objects to be aware of: ClientAsset, ModelAndTexture, and MaterialAssetGroup.
ClientAsset is an id/texture pair used to point to a texture location. By default, the texture path is contructed from the id, with the path prefixed with textures and suffixed with the PNG extension.
ModelAndTexture is a object/client asset pair used when a renderer should select between multiple models. Usually, the renderer creates a map of the object type to the model, and the object provided to the ModelAndTexture is used as a lookup into the map.
MaterialAssetGroup is a handler for rendering an equipment asset with some trim material. It takes in the base texture used to overlay onto the armor along with any overrides for a given equipment asset.
net.minecraft.advancements.DisplayInfonow takes in aClientAssetinstead of only aResourceLocationfor the background texturenet.minecraft.client.modelAdultAndBabyModelPair- Holds twoModelinstances that represents the adult and baby of some entity.ChickenModel#createBaseChickenModel- Creates the default chicken model.ColdChickenModel- A variant model for a chicken in cold temperatures.ColdCowModel- A variant model for a cow in cold temperatures.ColdPigModel- A variant model for a big in cold temperatures.CowModel#createBaseCowModel- Creates the base model for a cow.PigModel#createBasePigModel- Creates the default pig model.WarmCowModel- A variant model for a cow in warm temperatures.
net.minecraft.client.renderer.entityChickenRenderernow extendsMobRendererinstead ofAgeableMobRendererCowRenderernow extendsMobRendererinstead ofAgeableMobRendererPigRenderernow extendsMobRendererinstead ofAgeableMobRenderer
net.minecraft.client.renderer.entity.layers.SheepWoolUndercoatLayer- A layer that renders the wool undercoat of a sheep.net.minecraft.client.renderer.entity.stateCowRenderState- A render state for a cow entity.SheepRenderStategetWoolColor- Returns the integer color of the sheep wool.isJebSheep- Returns whether the sheep’s name contains thejeb_prefix.
net.minecraft.core.ClientAsset- An object that holds an identifier and a path to some texture.net.minecraft.data.loot.EntityLootSubProvider#killedByFrogVariantnow takes in aHolderGetterfor theFrogVariantnet.minecraft.data.tags.CatVariantTagsProviderclass is removednet.minecraft.tags.CatVariantTagsclass is removednet.minecraft.world.entity.animalAbstractCow- An abstract animal that represents a cow.Chicken#setVariant,getVariant- Handles the variant information of the chicken.ChickenVariant- A class which defines the common-sideable rendering information and biome spawns of a given chicken.ChickenVariants- Holds the keys for all vanilla chicken variants.Cownow extendsAbstractCow.CowVariant- A class which defines the common-sideable rendering information and biome spawns of a given cow.CowVariants- Holds the keys for all vanilla cow variants.CatVariant(ResourceLocation)->CatVariant(ClientAsset, SpawnPrioritySelectors)CatVariants- Holds the keys for all vanilla cat variants.FrogVariant->.frog.FrogVariantFrogVariant(ResourceLocation)->FrogVariant(ClientAsset, SpawnPrioritySelectors)
MushroomCownow extendsAbstractCowPigVariant- A class which defines the common-sideable rendering information and biome spawns of a given pig.TemperatureVariants- An interface which holds theResourceLocations that indicate an entity within a different temperature.
net.minecraft.world.entity.variant.ModelAndTexture- Defines a model with its associated texture.net.minecraft.world.item.equipment.trimMaterialAssetGroup- An asset defines some base and the permutations based on the equipment worn.TrimMaterialnow takes in aMaterialAssetGroupinstead of the raw base and overrides
Tags and Parsing
Tags have received a rewrite, removing any direct references to types while also sealing and finalizing related classes. Getting a value from the tag now returns an Optional-wrapped entry, unless you call one of the get*Or, where you specify the default value. Objects, on the other hand, do not take in a default, instead returning an empty variant of the desired tag.
// For some `CompoundTag` tag
// Read a value
Optional<Integer> value1 = tag.getInt("value1");
int value1Raw = tag.getIntOr("value1", 0);
// Reading another object
Optional<CompoundTag> childTag = tag.getCompound("childTag");
CompoundTag childTagRaw = tag.getCopmoundOrEmpty("childTag");
Writing with Codecs
CompoundTags now have methods to write and read using a Codec or MapCodec. For a Codec, it will store the serialized data inside the key specified. For a MapCodec, it will merge the fields onto the top level tag.
// For some Codec<ExampleObject> CODEC and MapCodec<ExampleObject> MAP_CODEC
// We will also have ExampleObject example
CompoundTag tag = new CompoundTag();
// For a codec
tag.store("example_key", CODEC, example);
Optional<ExampleObject> fromCodec = tag.read("example_key", CODEC);
// For a map codec
tag.store(MAP_CODEC, example);
Optional<ExampleObject> fromMapCodec = tag.read(MAP_CODEC);
Command Parsers
The packrat parser has been updated with new rules and systems, allowing commands to have parser-based arguments. This comes from the CommandArgumentParser, which parses some grammar to return the desired object. The parser is then consumed by the ParserBasedArgument, where it attempts to parse a string and build any suggestions based on what you’re currently typing. These are both handled through the Grammar class, which implements CommandArgumentParser, constructed using a combination of atoms, dictionaries, rules, and terms.
net.minecraft.commands.ParserUtils#parseJsonnet.minecraft.commands.argumentsComponentArgumentnow extendsParserBasedArgumentNbtTagArgumentnow extendsParserBasedArgumentStyleArgumentnow extendsParserBasedArgument
net.minecraft.commands.arguments.item.ItemPredicateArgumentnow extendsParserBasedArgumentnet.minecraft.nbtByteArrayTag, now final, no longer takes in a list objectByteTagis now a recordCollectionTagis now a sealed interface, no longer extendingAbstractListor has a genericset,addis removedremovenow returns aTagget- Returns the tag at the specified index.getElementTypeis removedsize- Returns the size of the collection.isEmpty- Returns whether the collection has no elements.stream- Streams the elements of the collection.
CompoundTagis now finalstore- Writes a codec or map codec to the tag.read- Reads the codec or map codec-encoded value from the tag.getFloatOrDefault,getIntOrDefault,getLongOrDefault- Gets the value with the associated key, or the default if not present or an exception is thrown.storeNullable- When not null, uses the codec to write the value to the tag.putUUID,getUUID,hasUUIDis removedgetAllKeys->keySetvalues,forEach- Implements the standard map operations.putByteArray,putIntArraywith list objects are removedgetTagTypeis removedcontainsis removedget*,get*Or- Returns an optional wrapped object for the key, or the default value specified is using theOrmethods.
DoubleTagis now a recordEndTagis now a recordFloatTagis now a recordIntArrayTag, now final, no longer takes in a list objectIntTagis now a recordListTag, now final, extendsAbstractListaddAndUnwrap- Adds the tag to the list where, if a compound with one element, adds the inner tag instead.get*,get*Or- Returns an optional wrapped object for the key, or the default value specified is using theOrmethods.compoundStream- Returns a flat map of allCompoundTags within the list.
LongArrayTag, now final, no longer takes in a list objectLongTagis now a recordNbtIo#readUnnamedTagis now public, visible for testingNbtOpsnow has a private constructorNbtUtilsgetDataVersionnow has an overload that takes in aDynamiccreateUUID,loadUUIDis removedreadBlockPos,writeBlockPosis removed
NumericTagis now a sealed interface that implementsPrimitiveTaggetAsLong->longValuegetAsInt->intValuegetAsShort->shortValuegetAsByte->byteValuegetAsDouble->doubleValuegetAsFloat->floatValuegetAsNumber->boxas*- Returns an optional wrapped of the numeric value.
PrimitiveTag- A sealed interface that represents the tag data as being a primitive object.ShortTagis now a recordSnbtGrammar- A parser creater for stringified NBTs.SnbtOperations- A helper that contains the built in operations for parsing some value.StringTagis now a recordStringTagVisitorvisit->build, not one-to-onehandleEscape->handleKeyEscape, now private
Tagis now a sealed interfaceas*-> Attempts to cast the tag as one of its subtypes, returning an empty optional on failure.getAsString->asString, not one-to-one
TagParsernow holds a generic referncing the type of the intermediate object to parse to- The constructor now takes in a grammar, or
createconstructs the grammar from aDynamicOps AS_CODEC->FLATTENED_CODECparseTag->parseCompoundFullyorparseCompoundAsArgument- Additional methods such as
parseFully,parseAsArgumentparse to some intermediary object - These are all instance methods
- Additional methods such as
readKey,readTypedValueis removed
- The constructor now takes in a grammar, or
TagType#isValueis removed
net.minecraft.util.parsing.packratCachedParseState- A parse state that caches the parsed positions and controls when reading.Control#hasCut- Returns whether the control flow for the grammar has a cut for the reading object.DelayedException- An interface that creates an exception to throw.Dictionaryputnow returns aNamedRuleput(Atom<T>, Term<S>, Rule.RuleAction<S, T>)->putComplexget->getOtThrow, not one-to-oneforward- Gets or writes the term to the dictionary.namedWithAlias- Creates a new reference to the named atom or its alias.
ErrorCollector$Nop- A error collector that does nothing.NamedRule- A rule that has an associated name.ParseStateis now an interface- Caching logic has moved to
CachedParseState scope- Returns the current scope being analyzed within the parsing object.parsenow takes in aNamedRuleinstead of anAtomacquireControl,releaseControl- Handles obtaining theControlused during parsing.silent- Returns aParseStatethat does not collect any errors.
- Caching logic has moved to
Ruleparse,$RuleAction#runnow returns a nullable value rather than an optionalSimpleRuleActionnow implements$RuleAction
Scope#pushFrame,popFrame,splitFrame,clearFrameValues,mergeFrame- Handles the management of parsing terms into sections called frames.Termnamed->Dictionary#named, not one-to-onerepeated,repeatedWithTrailingSeparator,repeatedWithoutTrailingSeparator- Handles terms similar to varargs that are repeated and sticks them into a list.positiveLookahead,negativeLookahead- Handles a term that matches information based on what is following.fail- Mark a term as having failed during parsing.
net.minecraft.util.parsing.packrat.commandsCommandArgumentParser- Parses a string into an argument for use with a command.Grammarnow takes in aNamedRulefor the top rather than anAtomGreedyPatternParseRule- A rule that attempts to match the provided pattern greedily, assuming that if a region matches, that the matched group can be obtained.GreedyPredicateParseRule- A rule that attempts to match the accepted characters greedily, making sure that the string reaches a minimum size.NumberRunParseRule- A rule that attempts to parse a number from the string.ParserBasedArgument- A command argument that uses a parser to extract the value.ResourceLookupRulenow takes in aNamedRulefor the id parser rather than anAtomStringReaderParserStatenow extendsCachedParsedState- The
Dictoionaryis no longer taken in
- The
StringReaderTerms#characters- Matches multiple characters in a string, usually for catching both the lowercase and uppercase variant.UnquotedStringParseRule- A rule that reads part of the sequence as an unquoted string, making sure it reaches a minimum size.
Saved Data, now with Types
SavedData has been reworked to abstract most of its save and loading logic into a separate SavedDataType. This means that the save override and additional load and factory methods are now handled within the SavedDataType itself.
To construct a SavedDataType, you need to pass in four paramters. First is the string identifier, used to resolve the .dat file holding your information. This must be a vaild path. Then there is the constructor, which takes in the SavedData$Context to return an instance of your data object when no information is present. Following that is the codec, which takes in the SavedData$Context and returns a Codec to read and write your saved data. Finally, there is the DataFixTypes used for data fixers. As this is a static enum, you will either need to inject into the enum itself, if you plan on using vanilla data fixers, or patch out the update call within DimensionDataStorage#readTagFromDisk to pass in a null value.
// Our saved data instance
public class ExampleSavedData extends SavedData {
// The saved data type
public static final SavedDataType<ExampleSavedData> TYPE = new SavedDataType<>(
// Best to preface the identifier with your mod id followed by an underscore
// Slashes will throw an error as the folders are not present
// Will resolve to `saves/<world_name>/data/examplemod_example.dat`
"examplemod_example",
// Constructor for the new instance
ExampleSavedData::new,
// Codec factory to encode and decode the data
ctx -> RecordCodecBuilder.create(instance -> instance.group(
RecordCodecBuilder.point(ctx.levelOrThrow()),
Codec.INT.fieldOf("value1").forGetter(data -> data.value1),
Codec.BOOL.fieldOf("value2").forGetter(data -> data.value2)
).apply(instance, ExampleSavedData::new));
);
private final ServerLevel level;
private final int value1;
private final boolean value2;
// For the new instance
private ExampleSavedData(ServerLevel.Context ctx) {
this(ctx.levelOrThrow(), 0, false);
}
// For the codec
// The constructors don't need to be public if not using `DimensionDataStorage#set`
private ExampleSavedData(ServerLevel level, int value1, boolean value2) {
this.level = level;
this.value1 = value1;
this.value2 = value2;
}
// Other methods here
}
// With access to the DimensionDataStorage storage
ExampleSavedData data = storage.computeIfAbsent(ExampleSavedData.TYPE);
net.minecraft.server.ServerScoreboarddataFactoryis removedcreateDatanow takes in a$Packedinstance
net.minecraft.world.RandomSequencesfactory,loadis removedcodec- Constructs a codec for the random sequence given the current world seed.
net.minecraft.world.entity.raid.Raidsno longer takes in anythinggetType- Returns the saved data type based on the current dimension.factoryis removedticknow takes in theServerLevelgetId- Gets the identifier for the raid instance.canJoinRaidno longer takes in the raid instanceloadno longer takes in theServerLevel
net.minecraft.world.level.levelgen.structure.structures.StructureFeatureIndexSavedDatafactory,loadis removedtype- Returns the feature saved data type with its specified id.
net.minecraft.world.level.saveddataSavedDatasaveis removed$Factoryrecord is removed$Context- Holds the current context that the saved data is being written to.
SavedDataType- A record that represents the type of the saved data, including information on how to construct, save, and load the data.
net.minecraft.world.level.saveddata.mapsMapIndexnow has a constructor to take in the last map idfactory,loadis removedgetFreeAuxValueForMap->getNextMapId
MapItemSavedDatafactory,loadis removedtype- Returns the saved data type using the map id’s key.
net.minecraft.world.level.storage.DimensionDataStoragenow takes in aSavedData$ContextcomputeIfAbsent,getnow take in only theSavedDataTypesetnow takes in theSavedDataTypealong with the data instance
net.minecraft.world.scores.ScoreboardSaveDataload->loadFrompack- Packs the data into its saved data format.$Packed- Represents the serializable packed data.
Render Pipeline Rework
Rendering an object to the screen, whether through a shader or a RenderType, has been fully or partially reworked, depending on what systems you were using previously. As such, a lot of things need to be reexplained, which a more in-depth look will be below. However, for the people who don’t care, here’s the TL;DR.
First, shader JSONs no longer exist. This is replaced by a RenderPipeline, which is effectively an in-code substitute. Second, the RenderPipelines forcibly make most abtrarily values into objects. For example, instead of storing the blend function mode id, you store a BlendFunction object. Similarly, you no longer store or setup the direct texture objects, but instead manage it through a GpuTexture. Finally, the VertexBuffer can either draw to the framebuffer by directly passing in the RenderPipeline, updating any necessary uniforms in the consumer, or by passing in the RenderType.
Now, for those who need the details, let’s jump into them.
Abstracting Open GL
As many are aware, Minecraft has been abstracting away their OpenGL calls and constants, and this release is no different. All of the calls to GL codes, except BufferUsage, have been moved out of object references, to be obtained typically by calling GlConst$toGl. However, with all of the other rendering reworks, there are numerous changes and complexities that require learning an entirely new system, assuming you’re not using RenderTypes.
Starting from the top, all calls to the underlying render system goes through GpuDevice, an interface that acts like a general implementation of a render library like OpenGL or Vulkan. The device is responsible for creating buffers and textures, executing whatever commands are desired. Getting the current GpuDevice can be accessed through the RenderSystem via getDevice like so:
GpuDevice device = RenderSystem.getDevice();
The GpuDevice can the create either buffers with the desired data or a texture containing information on what to render using createBuffer and createTexture, respectively. Just for redundancy, buffers hold the vertex data while textures hold the texture (color and depth) data. You should generally cache the buffer or texture object for later use with any additional data updated as needed. For reference, buffers are typically created by using a BufferBuilder with a ByteBufferBuilder to build the MeshData first, before passing that into createBuffer.
With the desired buffers and textures set up, how do we actually modify render them to the screen? Well, this is handled through the CommandEncoder, which can also be optained from the device via GpuDevice#createCommandEncoder. The encoder contain the familiar read and write methods along with a few extra to clear texture to a given color or simply blit the the texture immediately to the screen (presentTexture). However, the most important method here is createRenderPass. This takes in the GpuTexture to draw to the screen along with a default ARGB color for the background. Additionally, it can take in a depth texture as well. This should be created using a try with resources block like so:
// We will assume you have constructed a `GpuTexture` texture for the color data
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(this.texture, OptionalInt.of(0xFFFFFFFF))) {
// Setup things here
}
Within the RenderPass, you can set the RenderPipeline to use, which defines the associated shaders, bind any samplers from other targets or set uniforms, scissor a part of a screen to render, and set the vertex and index buffers used to define the vertices to render. Finally, everything can be drawn to the screen using one of the draw methods, providing the starting index and the vertex count.
// If the buffers/textures are not created or cached, create them here
// Any methods ran from `CommandEncoder` cannot be run while a render pass is open
RenderSystem.AutoStorageIndexBuffer indices = RenderSystem.getSequentialBuffer(VertexFormat.Mode.QUADS);
GpuBuffer vertexBuffer = RenderSystem.getQuadVertexBuffer();
GpuBuffer indexBuffer = indices.getBuffer(6);
// We will assume you have constructed a `GpuTexture` texture for the color data
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(this.texture, OptionalInt.of(0xFFFFFFFF))) {
// Set pipeline information along with any samplers and uniforms
pass.setPipeline(EXAMPLE_PIPELINE);
pass.setVertexBuffer(0, vertexBuffer);
pass.setIndexBuffer(indexBuffer, indices.type());
pass.bindSampler("Sampler0", RenderSystem.getShaderTexture(0));
// Then, draw everything to the screen
// In this example, the buffer just contains a single quad
// For those unaware, the vertex count is 6 as a quad is made up of 2 triangles, so 2 vertices overlap
pass.drawIndexed(0, 6);
}
However, unless you need such fine control, it is recommended to use a RenderType with the MultiBufferSource when necessary as that sets up most things for you.
Object References
Most raw references to GL codes used for determining the mode and handling the texture have been replaced with objects. As the TL;DR previously mentioned, these are stored typically as some sort of enum or object that can then be resolved to their GL counterparts. Some objects contain their reference identifier directly, like BlendFunction. Others are simply placeholders that are resolved in their appropriate location, like DepthTestFunction whose enum values are converted via RenderPipeline#toGl.
However, the biggest change is the addition of the GpuTexture. This is responsible for managing anything to do with creating, writing, and releasing a texture written to some buffer. At initialization, the texture is created and bound, with any necessary parameters set for mipmaps and texture formats. These GpuTextures are stored and referenced everywhere, from the depth and color targets for a RenderTarget to the texture backing a TextureAtlas. Then, once no longer need, the texture is released by calling #close. Note that although technically #bind can be called again, the texture is already considered deleted and should not be used.
If, for some reason, you need to use a GpuTexture, it’s actually quite simple to use. First, you just construct the GpuTexture via GpuDevice#createTexture. Then, if you need to change any of the addressing or texture mipmap filters, you can apply them whenever before writing.
public class MyTextureManager {
private final GpuTexture texture;
public MyTextureManager() {
this.texture = RenderSystem.getDevice().createTexture(
// The texture name, used for logging and debugging
"Example Texture",
// The format of the texture pixels, can be one of three values that
// Values: (texture internal format, texel data format, texel data type, pixel size)
// - RGBA8 (GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, 4)
// - RED8 (GL_R8, GL_RED, GL_UNSIGNED_BYTE, 1)
// - DEPTH32 (GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT, 4)
TextureFormat.RGBA8,
// Width of the texture
16,
// Height of the texture
16,
// The mipmap level and maximum level-of-detail (minimum of 1)
1
);
// Set the texture mode for the UV component
// Values:
// - REPEAT (GL_REPEAT)
// - CLAMP_TO_EDGE (GL_CLAMP_TO_EDGE)
this.texture.setAddressMode(
// The mode to use for the U component (GL_TEXTURE_WRAP_S)
AddressMode.CLAMP_TO_EDGE,
// The mode to use for the V component (GL_TEXTURE_WRAP_R)
AddressMode.REPEAT
);
// Sets the filter functions used for scaling the texture on the screen
// Values (default, for mipmaps):
// - NEAREST (GL_NEAREST, GL_NEAREST_MIPMAP_LINEAR)
// - LINEAR (GL_LINEAR, GL_LINEAR_MIPMAP_LINEAR)
this.texture.setTextureFilter(
// The mode to use for the texture minifying function (GL_TEXTURE_MIN_FILTER)
FilterMode.LINEAR,
// The mode to use for the texture magnifying function (GL_TEXTURE_MAG_FILTER)
FilterMode.NEAREST,
// Whether mipmaps should be used for the minifying function (should have a higher mipmap level than 1 when true)
false
);
}
}
Then, whenever you want to upload something to the texture, you call CommandEncoder#writeToTexture or CommandEncoder#copyTextureToTexture. This either takes in the NativeImage to write from or an IntBuffer with the texture data and a NativeImage$Format to use.
// Like other buffer/texture modification methods, this must be done outside of a render pass
// We will assume you have some `NativeImage` image to load into the texture
RenderSystem.getDevice().createCommandEncoder().writeToTexture(
// The texture (destination) being written to
this.texture,
// The image (source) being read from
image,
// The mipmap level
0,
// The starting destination x offset
0,
// The starting destination y offset
0,
// The destination width (x size)
16,
// The desintation height (y size)
16,
// The starting source x offset
0,
// The starting source y offset
0
)
Finally, once you’re done with the texture, don’t forget to release it via #close if it’s not already handled for you.
Render Pipelines
Previously, a pipeline was constructed using a JSON that contained all metadata from the vertex and fragement shader to their defined values, samplers, and uniforms. However, this has all been replaced with an in-code solution that more localizes some parts of the JSON and some parts that were relegated to the RenderType. This is known as a RenderPipeline.
A RenderPipeline can be constructed using its builder via RenderPipeline#builder. A pipeline can then be built by calling build. If you want the shader to be pre-compiled without any additional work, the final pipeline can be passed to RenderPipeline#register. However, you can also handle the compilation yourself if more graceful fail states are desired. If you have snippets that are used across multiple pipelines, then a partial pipeline can be built via $Builder#buildSnippet and then passed to the constructing pipelines in the builder method.
The following enums described in the examples have their GL codes provided with them as they have been abstracted away.
// This assumes that RenderPipeline#register has been made public through some form
public static final RenderPipeline EXAMPLE_PIPELINE = RenderPipelines.register(
RenderPipeline.builder()
// The name of the pipeline (required)
.withLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "pipeline/example"))
// The location of the vertex shader, relative to 'shaders' (required)
// Points to 'assets/examplemod/shaders/example.vsh'
.withVertexShader(ResourceLocation.fromNamespaceAndPath("examplemod", "example"))
// The location of the fragment shader, relative to 'shaders' (required)
// Points to 'assets/examplemod/shaders/example.fsh'
.withFragmentShader(ResourceLocation.fromNamespaceAndPath("examplemod", "example"))
// The format of the vertices within the shader (required)
.withVertexFormat(
// The vertex format
DefaultVertexFormat.POSITION_TEX_COLOR,
// The mode of the format
VertexFormat.Mode.QUADS
)
// Adds constants that can be referenced within the shaders
// Can specify a name in addition to an int / float to represent its value
// If no value is specified, then it should be gated with a #ifdef / #endif block
.withShaderDefines("ALPHA_CUTOUT", 0.5)
// Adds the texture sampler2Ds that can be referenced within the shaders
// Typically, the shader textures stored in the `RenderSystem` is referenced via `Sampler0` - `Sampler11`
// - `Sampler0` is usually always present, but these should be set up beforehand
// Additionally, for render targets, `InSampler` is typically present, along with any defined in a postpass
.withSampler("Sampler0")
// Adds uniforms that can be referenced within the shaders
// These are just definitions which are then populated by default or by the caller depending on the scenario
// Defaults can be found in `CompiledShaderProgram#setupUniforms`
.withUniform("ModelOffset", UniformType.VEC3)
// Custom uniforms must be set manually as the vanilla batching system does not support such an operation
.withUniform("CustomUniform", UniformType.INT)
// Sets the depth test functions used rendering objects at varying distances from the camera
// Values:
// - NO_DEPTH_TEST (GL_ALWAYS)
// - EQUAL_DEPTH_TEST (GL_EQUAL)
// - LEQUAL_DEPTH_TEST (GL_LEQUAL)
// - LESS_DEPTH_TEST (GL_LESS)
// - GREATER_DEPTH_TEST (GL_GREATER)
.withDepthTestFunction(DepthTestFunction.LEQUAL_DEPTH_TEST)
// Sets how the polygons should render
// Values:
// - FILL (GL_FILL)
// - WIREFRAME (GL_LINE)
.withPolygonMode(PolygonMode.FILL)
// When true, can cull front or back-facing polygons
.withCull(false)
// Specifies the functions to use when blending two colors with alphas together
// Made up of the `GlStateManager$SourceFactor` and `GlStateManager$DestFactor`
// First two are for RGB, the last two are for alphas
// If nothing is specified, then blending is disabled
.withBlend(BlendFunction.TRANSLUCENT)
// Determines whether to mask writing colors and alpha to the draw buffer
.withColorWrite(
// Mask RGB
false,
// Mask alpha
false
)
// Determines whether to mask writing values to the depth buffer
.withDepthWrite(false)
// Determines the logical operation to apply when applying an RGBA color to the framebuffer
.withColorLogic(LogicOp.NONE)
// Sets the scale and units used to calculate the depth values for the polygon.
// This takes the place of the polygon offset.
.withDepthBias(0f, 0f)
.build()
);
From there, the pipeline can either be used directly or through some RenderType:
// This will assume that RenderType#create is made public
public static final RenderType EXAMPLE_RENDER_TYPE = RenderType.create(
// The name of the render type
"examplemod:example",
// The size of the buffer
// Or 4MB
4194304,
// Whether it effects crumbling that is applied to block entities
false,
// Whether the vertices should be sorted before upload
true,
// The pipeline to use
EXAMPLE_PIPIELINE,
// Any additional composite state settings to apply
RenderType.CompositeState.builder().createCompositeState(RenderType.OutlineProperty.NONE)
);
The pipeline can then be drawn by creating the RenderPass and setting the RenderPipeline to use your pipeline. As for the RenderType, the associated buffer can be obtained using MultiBufferSource#getBuffer. Note that custom uniforms should not be used within RenderTypes as they cannot be set easily.
// Since we are using a custom uniform, we must handle it ourselves
// We will assume we have some `GpuTexture` texture to write to
// Create the render pass to use
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(
// The GPU color texture to write to
this.texture,
// The clear color in ARGB format
OptionalInt.of(0xFFFFFFFF),
// The depth texture and the clear depth value can also be constructed here
)
) {
// Add the pipeline and our uniform
pass.setPipeline(EXAMPLE_PIPELINE);
pass.setUniform("CustomUniform", 1);
// Set any additional sampler and the vertex/index buffers to use
// Finally, call one of the draw functions
// Takes in the first index and the index count to draw for the vertices
pass.draw(...);
}
Post Effects
Given that the pipeline JSONs have been stripped, this also effects the post effects. The program is replaced with directly specifying the vertex_shader and the fragment_shader. Additionally, uniforms must specify their type.
// Before 1.21.5 (for some pass in 'passes')
{
// Same as before
"inputs": [ /*...*/ ],
"output": "swap",
// Replaced by 'vertex_shader', 'fragement_shader'
"program": "minecraft:post/box_blur",
"uniforms": [
{
"name": "BlurDir",
// Required
"values": [ 1.0, 0.0 ]
},
{
"name": "Radius",
// Required
"values": [ 0.0 ]
}
]
}
// 1.21.1 (for some pass in 'passes')
{
// Same as before
"inputs": [ /*...*/ ],
"output": "swap",
// Relative to 'shaders'
// Points to 'assets/minecraft/shaders/post/blur.vsh'
"vertex_shader": "minecraft:post/blur",
// Points to 'assets/minecraft/shaders/post/box_blur.fsh'
"fragment_shader": "minecraft:post/box_blur",
"uniforms": [
{
"name": "BlurDir",
// Specifies the type to use for this uniform
// One of `Uniform$Type`:
// - int
// - ivec3
// - float
// - vec2
// - vec3
// - vec4
// - matrix4x4
"type": "vec2",
"values": [ 1.0, 0.0 ]
},
{
"name": "Radius",
"type": "float"
// Values are no longer required
}
]
}
Note that if you do not define a value for a uniform, they still must be specified before processing the PostChain by calling #setUniform within the RenderPass consumer of PostChain#process.
// Assume we already got the `PostChain` post
post.process(Minecraft.getInstance().getMainRenderTarget(), GraphicsResourceAllocator.UNPOOLED, pass -> {
pass.setUniform("Radius", 0.4f);
});
com.mojang.blaze3d.GpuOutOfMemoryException- An exception thrown when a texture could not be allocated on the GPU.com.mojang.blaze3d.buffersBufferTypeno longer stores the GL codes, now inGlConst#toGlBufferUsageno longer stores the GL codes, now inGlConst#toGlisReadable,isWritable- Returns whether the buffer can be read from or written to.
GpuBufferis now abstract- Constructor with
ByteBufferis removed size- Returns the size of the buffer.type- Returns the type of the buffer.resize,write,read,bindis removedusage- Returns the usage of the buffer.closeis now abstractisClosed- Returns whether the buffer has been closed.$ReadViewis now an interface that defines the buffer data and how to close the view
- Constructor with
com.mojang.blaze3d.font.SheetGlyphInfo#uploadnow takes in aGpuTexturecom.mojang.blaze3d.openglDirectStateAccess- An interface that creates and binds data to some framebuffer.$Core- An implementation of DSA that modifies the framebuffer without binding them to the context.$Emulated- An abstraction over DSA that still binds the context.
GlBuffer- An implementation of theGpuBufferfor OpenGL.GlCommandEncoder- An implementation of theCommandEncoderfor OpenGL.GlDebugLabel- A labeler for handling debug references to GL-specified data structures.GlDevice- An implementation ofGpuDevicefor OpenGL.GlRenderPass- An implementation ofRenderPassfor OpenGL.GlRenderPipeline- An implementation ofCompiledRenderPipelinefor OpenGL.GlTexture- An implementation ofGpuTexturefor OpenGL.VertexArrayCache- A cache for binding and uploading a vertex array to the OpenGL pipeline.
com.mojang.blaze3d.pipelineBlendFunction- A class that holds the source and destination colors and alphas to apply when overlaying pixels in a target. This also holds all vanilla blend functions.CompiledRenderPipeline- An interface that holds the pipeline with all necessary information to render to the screen.RenderPipeline- A class that contains everything required to render some object to the screen. It acts similarly to a render state before being applied.RenderTargetnow takes in a string representing the name of the targetcolorTextureId->colorTexture, now aGpuTexture- Same with
getColorTextureId->getColorTexture
- Same with
depthBufferId->depthTexture, now aGpuTexture- Same with
getDepthTextureId->getDepthTexture
- Same with
filterModeis now aFilterMode- Same with
setFilterModefor the int parameter
- Same with
blitAndBlendToScreenno longer takes in the viewport size parametersframebufferIdis removedcheckStatusis removedbindWrite,unbindWrite,setClearColoris removedblitToScreenno longer takes in any parametersblitAndBlendToScreen->blitAndBlendToTexture, not one-to-oneclearis removedunbindReadis removed
com.mojang.blaze3d.platformDepthTestFunction- An enum representing the supported depth tests to apply when rendering a sample to the framebuffer.DisplayDatais now a recordwithSize- Creates a new instance with the specified width/height.withFullscreen- Creates a new instance with the specified fullscreen flag.
FramerateLimitTrackergetThrottleReason- Returns the reason that the framerate of the game was throttled.isHeavilyThrottled- Returns whether the current throttle significantly impacts the game speed.$FramerateThrottleReason- The reason the framerate is throttled.
GlConst->com.mojang.blaze3d.opengl.GlConst#toGl- Maps some reference object to its associated OpenGL code.
GlDebug->com.mojang.blaze3d.opengl.GlDebugenableDebugCallbacknow takes in a set of the enabled extensions.
GlStateManager->com.mojang.blaze3d.opengl.GlStateManager_blendFunc,_blendEquationis removed_glUniform2(int, IntBuffer),_glUniform4(int, IntBuffer)is removed_glUniformMatrix2(int, boolean, FloatBuffer),_glUniformMatrix3(int, boolean, FloatBuffer)is removed_glUniformMatrix4(int, boolean, FloatBuffer)->_glUniformMatrix4(int, FloatBuffer), transpose is now always false_glGetAttribLocationis removed_glMapBufferis removed_glCopyTexSubImage2Dis removed_glBindRenderbuffer,_glDeleteRenderbuffersis removedglGenRenderbuffers,_glRenderbufferStorage,_glFramebufferRenderbufferis removed_texParameter(int, int, float)is removed_genTextures,_deleteTexturesis removed_texSubImage2Dnow has an overload that takes in anIntBufferinstead of alongfor the pixel datauploadis removed_stencilFunc,_stencilMask,_stencilOp,_clearStencilis removed_getTexImageis removed_glDrawPixels,_readPixelsis removed$CullState#modeis removed$DestFactor->DestFactor, codes are removed to be called throughGlConst#toGl$FramebufferStateenum is removed$LogicOp->LogicOp, codes are removed to be called throughGlConst#toGl- All but
OR_REVERSEis removed NONE- Performs no logic operation.
- All but
$PolygonOffsetState#lineis removed$SourceFactor->SourceFactor, codes are removed to be called throughGlConst#toGl$StencilFunc,$StencilStateclass is removed$Viewportenum is removed
GlUtilclass is removedgetVendor,getRenderer,getOpenGlVersion(nowgetVersion) have been moved to instance abstract methods onGpuDevicegetCpuInfo->GLX#_getCpuInfo
GLXgetOpenGLVersionStringis removed_init->_getCpuInfo, not one-to-one_renderCrosshair,com.mojang.blaze3d.systems.RenderSystem#renderCrosshair->net.minecraft.client.gui.components.DebugScreenOverlay#render3dCrosshair, not one-to-one
PolygonMode- A enum that defines how the polygons will render in the buffer.NativeImageconstructor is now publicuploadis removedgetPointer- Returns the pointer to the image data.setPixelABGRis now publicapplyToAllPixelsis removeddownloadTexture,downloadDepthBufferis removedflipYis removedsetPackPixelStoreState,setUnpackPixelStoreStateis removed$InternalGlFormatenum is removed$Formatno longer contains the GL codes, now inGlConst#toGl
TextureUtilgenerateTextureId,releaseTextureIdis removedprepareImageis removedwriteAsPNGnow takes in aGpuTextureinstead of the direct three integers- The overload without the
IntUnaryOperatoris removed
- The overload without the
com.mojang.blaze3d.resourceRenderTargetDescriptornow takes in an integer representing the color to clear toResourceDescriptorprepare- Prepares the resource for use after allocation.canUsePhysicalResource- Typically returns whether a descriptor is already allocated with the same information.
com.mojang.blaze3d.shadersAbstractUniform->com.mojang.blaze3d.opengl.AbstractUniformsetSafemethods are removedsetMat*methods are removedset(Matrix3f)is removed
CompiledShader->com.mojang.blaze3d.opengl.GlShaderModule$Type->com.mojang.blaze3d.shaders.ShaderType
Uniform->com.mojang.blaze3d.opengl.Uniform- Constructor now takes in a
$Typeinstead of the count and an integer representing the type UT_*fields are removedsetFromConfig(ShaderProgramConfig.Uniform)is removedgetTypeFromStringis removedgetTypenow returns a$Typeset(int, float)is removedsetSafeis now private$Type- Holds the type name as well as how many values it holds.getLocationis removedgetCount->$Type#countgetIntBuffer,getFloatBufferis removed$Type->com.mojang.blaze3d.shaders.UniformType
- Constructor now takes in a
com.mojang.blaze3d.systemsCommandEncoder- An interface that defines how to encode various commands to the underlying render system, such as creating a pass, clearing and writing textures, or reading from the buffer.GpuDevice- An interface that defines the device or underlying render system used to draw to the screen. This is responsible for creating the buffers and textures while compiling any pipelines.RenderPass- An interface that defines how a given pass is rendered to some buffer using the underlying render system. This allows binding any samplers and setting the required uniforms.RenderSystemisOnRenderThreadOrInit,assertOnRenderThreadOrInitis removedrecordRenderCall,replayQueueis removedblendFunc,blendFuncSeparate,blendEquationis removedtexParameter,deleteTexture,bindTextureForSetupis removedstencilFunc,stencilMask,stencilOpis removedclearDepthis removedglBindBuffer,glBindVertexArray,glBufferData,glDeleteBuffersis removedglUniform1iis removedglUniform1,glUniform2,glUniform3,glUniform4is removedglUniformMatrix2,glUniformMatrix3,glUniformMatrix4is removedsetupOverlayColornow takes in aGpuTextureinstead of two intsbeginInitialization,finishInitializationis removedrenderThreadTesselatoris removedsetShader,clearShader,getShaderis removedsetShaderTexturenow takes in aGpuTextureinstead of a bind addressgetShaderTexturenow returns aGpuTextureor null if not presentpixelStore,readPixelsis removedqueueFencedTask,executePendingTasks- Handles sending tasks that run on the GPU asyncronously.SCISSOR_STATE- Holds the main scissor state.disableDepthTest,enableDepthTestis removeddepthFunc,depthMaskis removedenableBlend,disableBlendis removedneableCull,disableCullis removedpolygonMode,enablePolygonOffset,disablePolygonOffset,polygonOffsetis removedenableColorLogicOp,disableColorLogicOp,logicOpis removedbindTexture,viewportis removedcolorMask,clearColor,clearis removedsetupShaderLights(CompiledShaderProgram)is removedgetShaderLights- Returns the vectors representing the block and sky lights.drawElements,getStringis removedinitRenderernow takes in the window pointer, the default shader source, and a boolean of whether to use debug labelssetupDefaultStateno longer takes in any parametersmaxSupportTextureSizeis removedglDeleteVertexArraysis removeddefaultBlendFuncis removedsetShaderTextureis removedgetQuadVertexBuffer- Returns a vertex buffer with a quad bound to it.getDevice,tryGetDevice- Returns theGpuDevicerepresenting the underlying render system to use.getCapsStringis removedactiveTextureis removedsetModelOffset,resetModelOffset,getModelOffset- Handles the offset to apply to a model when rendering for the uniformModelOffset. Typically for clouds and world borders.$AutoStorageIndexBuffer#bind->getBuffer, not one-to-one$GpuAsyncTask- A record that holds the callback and fence object used to sync information to the GPU.
ScissorState- A class which holds the part of the screen to render.
com.mojang.blaze3d.texturesAddressMode- The mode set for how to render a texture to a specific location.FilterMode- The mode set for how to render a texture whenever the level-of-detail function determines how the texture should be maximized or minimized.GpuTexture- A texture that is bound and written to the GPU as required.TextureFormat- Specifies the format that the texture should be allocated with.
com.mojang.blaze3d.vertexPoseStackmulPose(Quaternionf),rotateAroundnow takes in aQuaternionfcinstead of aQuaternionfclear->isEmptymulPose(Matrix4f)->mulPose(Matrix4fc)$PosecomputeNormalMatrixis now privatetransformNormalnow takes in aVector3fcas its first parametertranslate,scale,rotate,rotateAround,setIdentity,mulPoseare now available on the pose itself in addition to the stack
VertexBuffer->com.mojang.blaze3d.buffers.GpuBuffer, not one-to-one- Some logic is also moved to
VertexFormat
- Some logic is also moved to
VertexFormatbindAttributesis removedsetupBufferState,clearBufferState,getImmediateDrawVertexBuffer->uploadImmediateVertexBuffer,uploadImmediateIndexBuffer; not one-to-one$IndexTypeno longer stores the GL codes, now inGlConst#toGl$Modeno longer stores the GL codes, now inGlConst#toGl
VertexFormatElementsetupBufferStateis removed$Typeno longer stores the GL codes, now inGlConst#toGl$Usageno longer stores the GL function calls, now inVertexArrayCache#setupCombinedAttributes
com.mojang.mathMatrixUtilisIdentity,isPureTranslation,isOrthonormalnow take in aMatrix4fccheckProperty- Checks if the provided property is represented within the matrix.
OctahedralGrouptransformationnow returns aMatrix3fcfromAnges->fromXYAngles, not one-to-one
Quadrant- An enum that contains rotations in 90 degree increments.SymmetricGroup3#transformationnow returns aMatrix3fcTransformationnow takes in aMatrix4fcgetMatrixnow returns aMatrix4fcgetMatrixCopy- Returns a deep copy of the current matrix.
net.minecraft.client.gui.font.FontTexturenow takes in a supplied label stringnet.minecraft.client.main.GameConfignow takes in a boolean representing whether to render debug labelsnet.minecraft.client.rendererCloudRenderer#renderno longer takes in theMatrix4fs used for projection or posingCompiledShaderProgram->com.mojang.blaze3d.opengl.GlProgramlinknow takes in a string for the shader namesetupUniformsnow take in the list of$UniformDescriptions along with a list of names used by the samplersgetUniformConfigis removedbindSamplernow takes in aGpuTextureinstead of the integer bind identifierparseUniformNodeis removed
CoreShaders->RenderPipelines, not one-to-oneLightTexture#getTarget- Returns theGpuTexturethat contains the light texture for the current level based on the player.PostChainloadno longer takes in theShaderManager, now taking in aResourceLocationrepresenting the name of the chainaddToFrame,processnow takes in aRenderPassconsumer to apply any additional settings to the pass to rendersetUniformis removedsetOnRenderPass- Sets the uniform within the post chain on theRenderPassfor use in the shaders.
PostChainConfig$Passnow takes in the ids of the vertex and fragment shader instead of the program idreferencedTargets- Returns the targets referenced in the pass to apply.programis removed
$Uniformnow takes in the type of the uniform along with an optional list of floats if the value does not need to be overridden
PostPassno longer takes in theCompiledShaderProgram, now taking in theRenderPipelineinstead of a string representing the name of the passaddToFramenow takes in aRenderPassconsumer to apply any additional settings to the pass to rendergetShaderis removed$Input#bindTonow takes in aRenderPassinstead of theCompiledShaderProgram
RenderStateShard$LayerStateShards using polygon offsets have been removedgetName- Returns the name of the shard.$TransparencyStateShardclass is removed- Now handled through
BlendFunction
- Now handled through
$ShaderStateShardclass is removed- Directly referred to by the
VertexBuffer
- Directly referred to by the
$CullStateShardclass is removed- Now handled as a setting on the
RenderPipeline
- Now handled as a setting on the
$DepthTestStateShardclass is removed- Now handled through
DepthTestFunction
- Now handled through
$WriteMaskStateShardclass is removed- Now handled as a setting on the
RenderPipeline
- Now handled as a setting on the
$ColorLogicStateShardclass is removed- Now handled as a setting on the
RenderPipeline
- Now handled as a setting on the
$OutputStateShardnow takes in a suppliedRenderTargetinstead of the runnables for the startup and teardown states
RenderTypeno longer takes in theVertexFormatorVertexFormat$ModeSKY,END_SKY,sky,endSky,starsis removedENTITY_OUTLINE_BLIT,entityOutlineBlitis removedPANORAMA,panoramais removedCREATE_LIGHTMAP,createLightmapis removedcreateClouds,flatClouds,clouds,cloudsDepthOnlyis removedworldBorderis removeddebugLine- Returns theRenderTypeassociated with the debug line.entityOutlineBlit- Returns theRenderTypeused for rendering an entity outline.panorama- Returns theRenderTypeused for rendering panorama mode.createLightmap- Returns theRenderTypeused for rendering the lightmap texture.createno longer takes in theVertexFormatorVertexFormat$Mode, instead theRenderPipelinegetRenderTarget,getRenderPipeline- Returns the target and pipeline used for rendering.format,mode,draware now abstract$CompositeStateBuildermethods are now protected$OutlinePropertyis now protected
ShaderDefines$Builder#definenow has an overload that takes in an integerShaderManagerSHADER_INCLUDE_PATHis now privateMAX_LOG_LENGTHis removedpreloadForStartupis removed, replaced byGpuDevice#precompilePipelinegetProgram,getProgramForLoading->getShader, not one-to-onelinkProgramnow takes in aRenderPipelineinstead of aShaderProgramandShaderProgramConfig$CompilationCache#getOrCompileProgram,getOrCompileShader->getShaderSource, not one-to-one$Configsno longer takes in the map of programs$ShaderCompilationKeyrecord is removed
ShaderProgram,ShaderProgramConfig->RenderPipeline, not one-to-oneSkyRenderer#renderDarkDiscno longer takes in thePoseStack
net.minecraft.client.renderer.chunk.SectionRenderDispatcheruploadSectionLayer,uploadSectionIndexBuffer->$RenderSection#uploadSectionLayer,uploadSectionIndexBuffer$SectionBuffers- A class that holds the buffers used to render the sections.
net.minecraft.client.renderer.textureAbstractTextureNOT_ASSIGNEDis removedtexture,getTexture- Holds the reference to the texture to render.getId,releaseIdis removedbindis removed
DynamicTexturenow takes in the label of the textureSpriteContents#uploadFirstFrame,$AnimatedTexture#uploadFirstFramenow takes in aGpuTextureSpriteTicker#tickAndUploadnow takes in theGpuTextureTextureAtlasSprite#uploadFirstFrame,$Ticker#tickAndUploadnow takes in theGpuTexture
Model Rework
The model system has been further separated into models for block states, blocks, and items. As such, the unifying BakedModel has been completely removed and separated into their own sections, loaded in three steps: from JSON, resolving dependencies, and then baking for use with the associated block state model or item model. For reference, everything discussed below is what’s happenening within ModelManager#reload in parallel.
First, let’s start from the base model JSON used between blocks and items. These are loaded into an UnbakedModel (specifically BlockModel) which contains the familiar properties such as gui light and texture slots. However, one change is the splitting of the elements from their render settings. These elements that hold the render quads are stored in an UnbakedGeometry. The UnbakedGeometry is responsible for baking the model into a QuadCollection, which effectively holds the list of BakedQuads to render. Currently, vanilla only has the SimpleUnbakedGeometry, which holds the familiar list of BlockElements. These UnbakedModel, once loaded, are then passed to the ModelDiscovery for resolving the block state and item models.
Next we have the ResolvableModels, which is the base of both block state and item models. These models essentially function as markers requesting the UnbakedModels that they will be using. From there, we have their subtypes BlockStateModel$UnbakedRoot for the block state JSON and ItemModel$Unbaked for the model referenced in the client item JSON. Each of these implement resolveDependencies in some way to call ResolvableModel$Resolver#markDependency with the model location they would like to use.
Technically,
BlockStateModels are a bit more complex as variants useBlockStateModel$Unbakedduring loading which are then transformed into an$UnbakedRootduring initialization.
Now that we know what models that should be loaded, they now have to be put into a usable state for baking. This is the job of the ModelDiscovery, which takes in a ResolvableModel and loads the UnbakedModels into a ResolvedModel on first reference. ResolvedModels are functionally wrappers around UnbakedModels used to resolve all dependency chains, as the name implies.
From there, model groups are built for BlockStates and the textures are loaded, leading to the final step of actually baking the BlockStateModel and the ItemModel. This is handled through the bake methods provided on the $UnbakedRoot (or $Unbaked) and the ModelBakery. In a nutshell, bake constructs the list of BakedQuads stored with whatever additional information is desired by the block state or item model itself. The ResolvedModels are obtained from the baker, from which the instance methods are called. For BlockStateModels, this is resolved via SimpleModelWrapper#bake, from which the ModelState is obtained from the Variant data. They stored the baked quads in a BlockModelPart. For ItemModels, it just consumes the BakedQuads list directly along with information provided by ModelRenderProperties#fromResolvedModel. This does mean that each BlockStateModel and ItemModel may contain duplicated (but unique) BakedQuads if the same model is referenced in multiple locations.
Block Generators: The Variant Mutator
Given all the changes that separated out the block state JSON loading, there have also been a number of changes to the BlockModelGenerators. While most of them are simply renames (e.g., BlockStateGenerator -> BlockModelDefinitionGenerator), the major change is the addition of the VariantMutator. The VariantMutator is functionally a UnaryOperator on a Variant used to set some setting. This addition has simplified (or more like codec construction) the use of the PropertyDispatch for more quickly dispatching blocks with variants based on their properties.
// Creates a property dispatch on the horizontal facing property
// Applies the associated variants, though if desired, a functional interface can be provided instead
public static final PropertyDispatch<VariantMutator> ROTATION_HORIZONTAL_FACING = PropertyDispatch.modify(BlockStateProperties.HORIZONTAL_FACING)
.select(Direction.EAST, BlockModelGenerators.Y_ROT_90)
.select(Direction.SOUTH, BlockModelGenerators.Y_ROT_180)
.select(Direction.WEST, BlockModelGenerators.Y_ROT_270)
.select(Direction.NORTH, BlockModelGenerators.NOP);
// Then, with access to the `Consumer<BlockModelDefinitionGenerator>` blockStateOutput
this.blockStateOutput.accept(
MultiVariantGenerator.dispatch(EXAMPLE_BLOCK).with(ROTATION_HORIZONTAL_FACING)
);
net.minecraft.client.data.modelsBlockModelGeneratorsnonOrientableTrapdoor->NON_ORIENTABLE_TRAPDOOR, now static- Constants are now available for common
VariantMutators, like rotating the block model some number of degrees texturedModels->TEXTURED_MODELS, now staticMULTIFACE_GENERATORis now privateplainModel- Creates a variant from the model location.variant,variants- Creates a regularMultiVariantfrom some number ofVariantsplainVariant- Creates aMultiVariantwith only one model from its location.condition- Creates a new condition builder for multipart modelsor- ORs multiple conditions together.- Most generator methods now return the
BlockModelDefinitionGenerator,Variant, orMultiVariantand take in aVariantorMultiVariantinstead of aResourceLocationpointing to the desired modelVariantPropertieshave been replaced withVariantMutatorsCondition$TerminalConditionis replaced withCondition
createHorizontalFacingDispatch,createHorizontalFacingDispatchAlt,createTorchHorizontalDispatchis removedcreateFacingDispatchis removedcreateRotatedVariant(Block, ResourceLocation)is removedselectMultifaceProperties- Creates a map of properties toVariantMutators based on the providedBlockStateand direction to property function.applyRotationno longer takes in theVariantand returns aVariantMutator
ItemModelGenerators#generateSpawnEggis removedModelProvider#saveAllis removed
net.minecraft.client.data.models.blockstatesBlockStateGenerator->BlockModelDefinitionGenerator, not one-to-oneCondition->net.minecraft.client.renderer.block.model.multipart.Condition, not one-to-onevalidate->instantiate, not one-to-one
ConditionBuilder- Builds a condition using property valuesMultiPartGeneratornow implementsBlockModelDefinitionGeneratorwith(List<Variant>)->with(MultiVariant)with(Variant)is removedwith(Condition, ...)->with(Condition, MultiVariant)- Overload taking in
ConditionBuilder
- Overload taking in
$ConditionalEntry,$Entryis removed
MultiVariantGeneratornow implementsBlockModelDefinitionGeneratormultiVariant->dispatchmultiVariant(Block, ...)->dispatch(Block, MultiVariant)$Empty- A multi variant entry that matches every block state.
PropertyDispatchhas a generic containing the value of the dispatch- The generic
Vreplaces all values ofList<Variant> property,properties->initialormodify$C*#generateListmethods are removed$*Functionare removed
- The generic
Selector->PropertyValueList, not one-to-oneVariant->net.minecraft.client.renderer.block.model.Variant, not one-to-oneVariantProperties->net.minecraft.client.renderer.block.model.VariantMutator, not one-to-oneVariantProperty->net.minecraft.client.renderer.block.model.VariantMutator$VariantProperty, not one-to-one
net.minecraft.client.renderer.ItemInHandRenderer#renderItemno longer takes in the boolean representing if the item is held in the left handnet.minecraft.client.renderer.blockBlockModelShaper#stateToModelLocation,statePropertiesToStringis removedBlockRenderDispatcher#renderBatchednow takes in a list ofBlockModelParts instead of aRandomSourceModelBlockRenderertesselateBlock,tesselateWithAO,tesselateWithoutAOno longer takes in aRandomSourceand replacesBlockStateModelwith a list ofBlockModelPartsrenderModelis now static and no longer takes in theBlockState$AmbientOcclusionFace->$AmbientOcclusionRenderStorage$CommonRenderStorage- A class that holds some metadata used to render a block at its given position.$SizeInfonow takes in the direct index rather than computing the info from its direction and a flipped boolean
net.minecraft.client.renderer.block.modelBakedQuadis now a recordBlockElementis now a recordfrom,toare nowVector3fc
BlockElementFacenow takes in aQuadrantfor the face rotationgetU,getV- Returns the texture coordinate after rotation.$Deserializer#getTintIndexis now private and static
BlockFaceUV->BlockElementFace$UVs, not one-to-oneBlockModelis now a record, taking in anUnbakedGeometryinstead of the direct list ofBlockElements$Deserializer#getElementsnow returns anUnbakedGeometry
BlockModelDefinitionis now a record, taking in$SimpleModelSelectorsand$MultiPartDefinitionsGSON,fromStream,fromJsonElement->CODEC, not one-to-oneinstantiatenow takes in a supplied string instead of the string directly$Deserializeris removed$MultiPartDefinition- A record that holds a list of selectors to get for the multi part model.$SimpleModelSelectors- A record that holds a map of variants to their unbaked model instances.
BlockModelPart- A baked model representation of a block.BlockStateModel- A baked representation of a block state.collectParts- Obtains the list of baked models used to render this state.$SimpleCachedUnbakedRoot- A class that represents a delegate of some$Unbakedmodel.$Unbaked- An extension over$UnbakedRootthat can create a$SimpleCachedUnbakedRoot
FaceBakerybakeQuadnow takes inVector3fcs instead ofVector3fsrecomputeUVsis removedextractPositions- Extracts the face positions and passes them to a consumer for use.
ItemTransformis now a record, vectors areVector3fcsMultiVariant->net.minecraft.client.data.models.MultiVariantCODECwith- Creates aMultiVariantwith the specified mutators.$Deserializerclass is removed
SimpleModelWrappernow implementsBlockModelPartSimpleUnbakedGeometry- An unbaked geometry that holds a list ofBlockElements to bake.SingleVariant- ABlockStateModelimplementation with only one model for its state.UnbakedBlockStateModel->BlockStateModel$UnbakedRootVariantno longer implementsModelState, now taking in a$SimpleModelStateinstead of the direct rotation and uv lock- The constructor now has an overload for only providing the
ResourceLocationand no longer takes in the weight, leaving that to theMultiVariant CODECwithXRot,withYRot,withUvLock,withModel,withState,with- Mutates the variant into a new object with the given setting applied.$Deserializerclass is removed$SimpleModelState- A record that holds the x/y rotations and uv lock.
- The constructor now has an overload for only providing the
VariantMutator- A unary operator on a variant that applies the specified setting to the variant. Used during state generation.
net.minecraft.client.renderer.block.model.multipartAndCondition,OrCondition->CombinedCondition, not one-to-oneKeyValueConditionis now a record that takes in a map of keys to terms to testMultiPart->MultiPartModel$Unbaked$DefinitionCODECgetMultiVariantsis removed
$Deserializerclass is removed
Selectoris now a record, taking in aBlockStateModel$Unbakedinstead of aMultiVariant$Deserializerclass is removed
net.minecraft.client.renderer.entity.ItemRendererrenderItemnow takes in aList<BakedQuad>instead of aBakedModelrenderStaticno longer takes in a boolean indicating what hand the item was held in
net.minecraft.client.renderer.itemBlockModelWrappernow has a public constructor that takes in the list of tint sources, the list of quads, and theModelRenderProperties- The list of quads and
ModelRenderPropertiesreplaces the directBakedModel, or nowBlockStateModel computeExtents- Extracts the vertices of the baked quads into an array.
- The list of quads and
ItemModel$BakingContext#bakeis removedItemModelResolver#updateForLiving,updateForTopItemno longer takes in a boolean representing if the item is in the left handItemStackReenderStateisGui3dis removedtransformis removedvisitExtents- Visits all vertices of the model to render and passes them into the provided consumer.$LayerRenderStateNO_EXTENTS_SUPPLIER- An empty list of vertices.setupBlockModelhas been broken intoprepareQuadList,setRenderType,setUsesBlockLight,setExtents,setParticleIcon,setTransformsetupSpecialModelno longer takes in the baseBakedModel
MissingItemModelnow takes in a list ofBakedQuads andModelRenderPropertiesinstead of the directBakedModelModelRenderProperties- The properties used to render a model, typically retrieved from theResolvedModel.SpecialModelRenderernow takes in theModelRenderPropertiesinsetad of the baseBakedModel
net.minecraft.client.resources.modelBakedModel->net.minecraft.client.resources.model.QuadCollection, not one-to-oneBlockModelRotationbynow takes inQuadrants instead of integerswithUvLock- Returns the model state with the rotation and a mention that it locks the UV for the rotation.
BlockStateDefinitions- A manager for creating the mapper of block names to their state defintions.BlockStateModelLoaderModelResourceLocationfields are removedloadBlockStateno longer takes in the missing model$LoadedModelclass is removed$LoadedModelsnow takes in aBlockStateModel$UnbakedRootinstead of an$UnbakedforResolving,plainModelsis removed
DelegateBakedModel->net.minecraft.client.renderer.block.model.SimpleModelWrapper, not one-to-oneMissingBlockModel#VARIANTis removedModelBakerbake->getModel, not one-to-one- The baker is simply retrieving the
ResolvedModel
- The baker is simply retrieving the
rootNameis removedcompute- Computes the provided key that contains theModelBaker. Typically used for bakingBlockStateModels$SharedOperationKey- An interface which typically computes some baking process for an unbaked model.
ModelBakerynow takes in aMap<BlockState, BlockStateModel$UnbakedRoot>for the unbaked block state models, aMap<ResourceLocation, ResolvedModel>for the loaded models, and aResolvedModelfor the missing modelbakeModelsnow takes in aSpriteGetterand anExecutorwhile returning aCompletableFuturefor parallel loading and baking$BakingResultnow takes in a$MissingModelsfor the missing block state and item model and aMap<BlockState, BlockStateModel>for the baked block state models; the missing item model is stored within$MissingModels$MissingModels- Holds the missing models for a block state and item.$TextureGetterinterface is removed
ModelDebugNameno longer extendsSupplier<String>, instead usingdebugNameModelDiscoveryregisterSpecialModelsis removeddiscoverDependenciesis now privategetReferencedModels,getUnreferencedModelsis removedaddSpecialModel- Adds a root model to the list of arbitrarily loaded models.missingModel- Returns the missing modelresolve- Resolves all model dependencies, returning a map of model names to their models.
ModelGroupCollector$GroupKey#createnow takes in aBlockStateModel$UnbakedRootinstead of an$UnbakedModelManagergetModelis removedgetMissingModel->getMissingBlockStateModel$ResolvedModels- A map of models with their dependencies resolved.
ModelResourceLocationrecord is removedModelStategetRotation->transformationisUvLockedis removedfaceTransfomration,inverseFaceTransformation- Handles returning the transformedMatrix4fcfor baking the face vertices.
MultiPartBakedModel->net.minecraft.client.renderer.block.model.multipart.MultiPartModel- Now implements
BlockStateModelinstead of extendingDelegateBakedModel $SharedBlockState- A holder that contains theBlockStateModels mapped to their$Selectors.
- Now implements
QuadCollection- A data object containing the list of quads to render based on the associated direction and culling.ResolvableModel$Resolver#resolve->markDependency, not one-to-one- Instead of directly resolving, the dependency is marked for a later post processing step
ResolvedModel- AnUnbakedModelwhose model and texture dependencies have been completely resolved.SimpleBakedModel->net.minecraft.client.renderer.block.model.SimpleModelWrapperornet.minecraft.client.renderer.block.model.SimpleUnbakedGeometry, not one-to-oneSpriteGetterget,reportMissingReferencenow take in theModelDebugNameresolveSlot- Resolves the key from theTextureSlots into itsTextureAtlasSprite.
UnbakedGeometry- An interface that constructs a collection of quads the render when baked.UnbakedModelno longer implementsResolvableModelDEFAULT_AMBIENT_OCCLUSION,DEFAULT_GUI_LIGHTis removedPARTICLE_TEXTURE_REFERENCE- Holds the key representing the particle texture.bakeis removedgetAmbientOcclusion->ambientOcclusiongetGuiLight->guiLightgetTransforms-transformsgetTextureSlots-textureSlotsgeometry- Holds the unbaked geometry representing the model elements.getParent->parent, not one-to-onebakeWithTopModelValuesis removedgetTopTextureSlots,getTopAmbientOcclusion,getTopGuiLight,getTopTransform,getTopTransformsis removed
WeightedBakedModel->WeightedVariants- Now implements
BlockStateModelinstead of extendingDelegateBakedModel
- Now implements
net.minecraft.world.item.ItemDisplayContext#leftHand- Returns whether the display context is rendering with the entity’s left hand.
Minor Migrations
The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.
Entity References
Generally, the point of storing the UUID of another entity was to later grab that entity to perform some logic. However, storing the raw entity could lead to issues if the entity was removed at some point in time. As such, the EntityReference was added to handle resolving the entity from its UUID while also making sure it still existed at the time of query.
An EntityReference is simply a wrapped Either which either holds the entity instance or the UUID. When resolving via getEntity, it will attempt to verify that the stored entity, when present, isn’t removed. If it is, it grabs the UUID to perform another lookup for the entity itself. If that entity does exist, it will be return, or otherwise null.
Most references to a UUID within an entity have been replaced with an EntityReference to facilitate this change.
net.minecraft.network.syncher.EntityDataSerializers#OPTIONAL_UUID->OPTIONAL_LIVING_ENTITY_REFERENCE, not one to one as it can hold the entity referencenet.minecraft.server.level.ServerLevel#getEntity(UUID)->Level#getEntity(UUID)net.minecraft.world.entityEntityReference- A reference to an entity either by its entity instance when present in the world, or a UUID.LivingEntity#lastHurtByPlayer,lastHurtByMobare nowEntityReferencesOwnableEntitygetOwnerUUID->getOwnerReference, not one-to-onelevelnow returns aLevelinstead of anEntityGetter
TamableAnimal#setOwnerUUID->setOwner, orsetOwnerReference; not one-to-one
net.minecraft.world.entity.animal.horse.AbstractHorse#setOwnerUUID->setOwner, not one-to-onenet.minecraft.world.level.Levelnow implementsUUIDLookup<Entity>net.minecraft.world.level.entityEntityAccessnow implementsUniquelyIdentifyableUniquelyIdentifyable- An interface that claims the object as a UUID and keeps tracks of whether the object is removed or not.UUIDLookup- An interface that looks up a type by its UUID.
Descoping Player Arguments
Many methods that take in the Player has been descoped to take in a LivingEntity or Entity depending on the usecase. The following methods below are a non-exhaustive list of this.
net.minecraft.world.entity.EntityTypespawncreateDefaultStackConfig,appendDefaultStackConfigappendCustomEntityStackConfig,updateCustomEntityTag
net.minecraft.world.itemBucketItem#playEmptySoundDispensibleContainerItem#checkExtraContent,emptyContents
net.minecraft.world.levelLevelplaySeededSoundmayInteract
LevelAccessorplaySoundlevelEvent
net.minecraft.world.level.blockBucketPickup#pickupBlockLiquidBlockContainer#canPlaceLiquid
net.minecraft.world.level.block.entity.BrushableBlockEntity#brush
Component Interaction Events
Click and hover events on a MutableComponent have been reworked into MapCodec registry-like system. They are both now interfaces that register their codecs to an $Action enum. The implementation then creates a codec that references the $Action type and stores any necessary information that is needed for the logic to apply. However, there is no direct ‘action’ logic associated with the component interactions. Instead, they are hardcoded into their use locations. For click events, this is within Screen#handleComponentClicked. For hover events, this is in GuiGraphics#renderComponentHoverEffect. As such, any additional events added will need to inject into both the enum and one or both of these locations.
net.minecraft.network.chatClickEventis now an interfacegetAction->actiongetValueis now on the subclasses as necessary for their individual types
HoverEventis now an interfacegetAction->action$EntityTooltipInfoCODECis now aMapCodeclegacyCreateis removed
$ItemStackInfois removed, replaced by$ShowItem$LegacyConverterinterface is removed
Texture Atlas Reworks
The texture atlas logic has been finalized into a registry codec system; however, the querying of the atlas data has changed. First, all atlas identifiers are stored within AtlasIds while the corresponding texture location is stored within Sheets. To get a material from an atlas, a MaterialMapper is used as a wrapper around the texture location and the associated prefix to append to the material. The Material can then be obtained using apply by passing in the id of the material you would like to use.
For example:
// Found in sheets
public static final MaterialMapper ITEMS_MAPPER = new MaterialMapper(TextureAtlas.LOCATION_BLOCKS, "item");
public static final MaterialMapper BLOCKS_MAPPER = new MaterialMapper(TextureAtlas.LOCATION_BLOCKS, "block");
// Finds the texture for the material at `assets/examplemod/textures/item/example_item.png`
public static final Material EXAMPLE_ITEM = ITEMS_MAPPER.apply(ResourceLocation.fromNamespaceAndPath("examplemod", "example_item"));
// Finds the texture for the material at `assets/examplemod/textures/block/example/block.png`
public static final Material EXAMPLE_BLOCK = ITEMS_MAPPER.apply(ResourceLocation.fromNamespaceAndPath("examplemod", "example/block"));
net.minecraft.client.data.AtlasProvider- A data provider for generating the providers of a texture atlas.net.minecraft.client.data.models.ItemModelGeneratorsSLOT_*->TRIM_PREFIX_*, now public andResourceLocationsTRIM_MATERIAL_MODELSis now publicgenerateTrimmableItemnow takes in aResourceLocationinstead of aString$TrimMaterialDatais now public, taking in aMaterialAssetGroupinstead of the name and override materials
net.minecraft.client.rendererMaterialMapper- An object that stores the location of the atlas texture and the prefix applied to the ids within the texture.Sheets*_MAPPER-MaterialMappers for each texture atlas texture.createBedMaterial(ResourceLocation)is removedcreateShulkerMaterial(ResourceLocation)is removedcreateSignMaterial(ResourceLocation)is removedchestMaterial(String),chestMaterial(ResourceLocation)are removedcreateDecoratedPotMaterial(ResourceLocation)is removed
net.minecraft.client.renderer.blockentity.ConduitRenderer#MAPPER- A mapper to get the conduit textures from the block atlas.net.minecraft.client.renderer.texture.atlasSpriteSource#type->codec, not one-to-oneSpriteSourcesnow contains logic similar to client registries via their id mapperSpriteSourceTyperecord is removed
net.minecraft.client.renderer.texture.atlas.sourcesDirectoryListeris now a recordPalettedPermutationsis now a recordSingleFileis now a recordSourceFilteris now a recordUnstitcheris now a record$Regionis now public
net.minecraft.client.resources.model.AtlasIds- A class which holds theResourceLocations of all vanilla texture atlases.
Registry Context Swapper
Client items now store a RegistryContextSwapper, which is used to properly check client item information that accesses registry objects. Before level load, this is provided a placeholder to avoid crashing and populated with the correct value during rendering.
net.minecraft.client.multiplayerCacheSlot- An object that contains a value computed from some context. When updated, the previous value is overwritten and the context registers the slot to be cleaned.ClientLevelnow implementsCacheSlot$Cleaner
net.minecraft.client.renderer.itemClientItemcan now take in a nullableRegistryContextSwapperwithRegistrySwapper- Sets theRegistryContextSwapperwithin aClientItem
ItemModel$BakingContextnow takes in aRegistryContextSwapper
net.minecraft.utilPlaceholderLookupProvider- A provider that contains placeholders for referenced objects. Used within client items as they will be loaded before theRegistyAccessis populated.RegistryContextSwapper- An interface used to swap out some object for a different one. Used by client items to swap the placeholders for the loadedRegistryAccess.
Reload Instance Creation
Reload instances have been slightly rearranged. The SimpleReloadInstance base now only takes in the List<PreparableReloadListener>, where the other fields are passed into the of function such that #startTasks can be called immediately.
net.minecraft.server.packs.resourcesProfiledReloadInstanceconstruct is now private, accessed throughofSimpleReloadInstanceonly takes in theList<PreparableReloadListener>ofnow returns aReloadInstance, not one-to-oneallPreparationsis now package privateallDoneis now privatestartTasks- Begins the reload of the listener.prepareTasks- Runs the executor and sets up the futures needed to read and load all desired data.StateFactory$SIMPLE- A factory that callsPreparableReloadListener#reload
Block Effect Appliers
Effects that are applied to entities when inside a block are now handled through the InsideBlockEffectApplier and InsideBlockEffectType. The InsideBlockEffectType is an enum that contains a consumer on what to apply to an entity when called. InsideBlockEffectApplier, on the other hand, is stored on the entity has a way to apply an effect in a ordered manner based on the enum ordinals.
To call one of the effect types, you must override BlockBehaviour#entityInside or Fluid#entityInside and call InsideBlockEffectApplier#apply. If something should apply before the effect type, like entinguishing fire before freezing in powder snow, then InsideBlockEffectApplier#runBefore should be called before apply. Similarly, if something should run afterward, like hurting an enemy after being placed in lava, then runAfter should be called.
// In some block or fluid subclass
@Override
protected void entityInside(Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier applier) {
applier.runBefore(InsideBlockEffectType.EXTINGUISH, entity -> {
// Modify entity here.
});
// Do the base application logic stored on the type
applier.apply(InsideBlockEffectType.FIRE_IGNITE);
applier.runAfter(InsideBlockEffectType.FIRE_IGNITE, entity -> {
// Perform any final checks that are as a result of the effect being applied
entity.hurt(...);
});
}
net.minecraft.world.entityInsideBlockEffectApplier- An interface that defines how an entity should interact when within a given block.InsideBlockEffectType- An enum that defines what behavior to perform when side the specific block that references the type.
net.minecraft.world.level.block.state.BlockBehaviour#entityInside,$BlockStateBase#entityInsidenow takes in anInsideBlockEffectAppliernet.minecraft.world.level.material.Fluid#entityInside,FluidState#entityInside- A method called whenever the entity is considered inside the bounding box of the fluid.
Timer Callbacks, joining the codec club!
TimerCallbacks, used in the server schedule for executing events, typically mcfunctions in datapacks, have now been reworked into a codec form. This means that a callback can be registered to the list of available callbacks by passing in the MapCodec to TimerCallbacks#register (via TimerCallbacks#SERVER_CALLBACKS) instead of the serializer.
net.minecraft.world.level.timersFunctionCallbackis now a recordFunctionTagCallbackis now a recordTimerCallbackcodec- Returns the codec used for serialization.$Serializerclass is removed
TimerCallbacksserialize,deserialize->codec, not one-to-one
The JOML Backing Interfaces
Mojang has opted to lessen the restriction on JOML objects by passing around the implementing interface of their logic objects (usually implemented with a tacked on c). For example, Vector3f becomes Vector3fc or Matrix4f becomes Matrix4fc. This does not change any logic itself as the c interfaces are implemented by the class components.
Tag Changes
minecraft:worldgen/biomespawns_cold_variant_farm_animalsspawns_warm_variant_farm_animals
minecraft:blocksword_instantly_minesreplaceable_by_mushroomsplays_ambient_desert_block_soundsedible_for_sheepdead_bush_may_place_on->dry_vegetation_may_place_oncamels_spawnable_on
minecraft:cat_variantare removedminecraft:entity_typecan_equip_saddlecan_wear_horse_armor
minecraft:itembook_cloning_targeteggsflowers
Mob Effects Field Renames
Some mob effects have been renamed to their in-game name, rather than some internal descriptor.
MOVEMENT_SPEED->SPEEDMOVEMENT_SLOWDOWN->SLOWNESSDIG_SPEED->HASTEDIG_SLOWDOWN->MINING_FATIGUEDAMAGE_BOOST->STRENGTHHEAL->INSTANT_HEALTHHARM->INSTANT_DAMAGEJUMP->JUMP_BOOSTCONFUSION->NAUSEADAMAGE_RESISTANCE->RESISTANCE
Very Technical Changes
This is a list of technical changes that could cause highly specific errors depending on your specific setup.
-
The order of the
minecraft:patch_sugar_canefeature andminecraft:patch_pumpkinfeature have swapped orders (first pumpkin, then sugar cane), meaning modded biomes that generate both of these features will need to update their JSONs to the new ordering. -
Serveral vanilla oak tree and tree selector features now have
_leaf_litterappended at the end.- For example:
trees_birch_and_oak->trees_birch_and_oak_leaf_litter
- For example:
List of Additions
net.minecraftChatFormatting#COLOR_CODECCrashReportCategory#populateBlockLocationDetails- Adds the block location details to a crash report.
net.minecraft.advancements.critereon.MinMaxBounds#createStreamCodec- Constructs a stream codec for aMinMaxBoundsimplementation.net.minecraft.client.Options#startedCleanly- Sets whether the game started cleanly on last startup.net.minecraft.client.data.modelsBlockModelGenerators#createSegmentedBlock- Generates a multipart blockstate definition with horizontal rotation that displays up to four models based on some integer property.ItemModelGenerators#prefixForSlotTrim- Generates a vanillaResourceLocationfor a trim in some slot.
net.minecraft.client.MouseHandlerfillMousePositionDetails- Adds details about the current mouse location and screen size to a crash report.getScaledXPos- Gets the current x position scaled by the gui scaling option.getScaledYPos- Gets the current y position scaled by the gui scaling option.drawDebugMouseInfo- Draws information about the scaled position of the mouse to the screen.
net.minecraft.client.gui.components.toasts.Toast#getSoundEvent- Returns the sound to play when the toast is displayed.net.minecraft.client.gui.screens.options.VideoSettingsScreen#updateFullscreenButton- Sets the fullscreen option to the specified boolean.net.minecraft.client.model.geom.buildersMeshDefinition#apply- Applies the given transformer to the mesh before returning a new instance.MeshTransformer#IDENTITY- Performs the identity transformation.
net.minecraft.client.multiplayer.ClientPacketListener#decoratedHashOpsGenenerator- Returns the generator used to create a hash of a data component and its value.net.minecraft.client.particleFallingLeavesParticle$TintedLeavesProvider- A provider for aFallingLeavesParticlethat uses the color specified by the block above the particle the spawn location.FireflyParticle- A particle that spawns fireflies around a given non-air block position.
net.minecraft.client.rendererBiomeColors#getAverageDryFoliageColor- Returns the average foliage color for dry biomes.LevelRenderer$BrightnessGetter- An interfaces which obtains the packed brightness at a given block position.WorldBorderRenderer#invalidate- Invalidates the current render of the world border to be rerendered.
net.minecraft.client.renderer.entityEntityRenderDispatcher#getRenderer- Gets the renderer to use from the data stored on the render state.EntityRenderer#extractAdditionalHitboxes- Gets any additional hitboxes to render when the ‘show hitboxes’ debug state is enabled.
net.minecraft.client.renderer.entity.stateEntityRenderStateentityType- The type of the entity.hitboxesRenderState- The hitbox information of the entity relative to the entity’s position.serverHitboxesRenderState- The hitbox information of the entity synced from the server.fillCrashReportCategory- Sets the details for any crashes related to the render state.
HitboxesRenderState- The render state of the hitboxes for the entity relative to the entity’s position.HitboxRenderState- The render state of a single hitbox to render along with its color, such as the eye height of an entity.ServerHitboxesRenderState- The render state containing the last synced information from the related server entity.PigRenderState#variant- The variant of the pig.
net.minecraft.client.renderer.item.SelectItemModel$ModelSelector- A functional interface that selects the item model based on the switch case and level.net.minecraft.client.renderer.item.properties.conditional.ComponentMatches- A conditional property that checks whether the given predicate matches the component data.net.minecraft.client.renderer.item.properties.selectComponentContents- A switch case property that operates on the contents within a data component.SelectItemModelProperty#valueCodec- Returns theCodecfor the property type.
net.minecraft.client.resources.DryFoliageColorReloadListener- A reload listener that loads the colormap for dry foliage.net.minecraft.commands.arguments.ComponentArgument#getResolvedComponent- Constructs a component with the resolved information of its contents.net.minecraft.coreDirection#getUnitVec3f- Returns the float unit vector of the direction.HolderGetter$Provider#getOrThrow- Gets a holder reference from a resource key.SectionPos#sectionToChunk- Converts a compressed section position to a compressed chunk position.Vec3i#STREAM_CODEC
net.minecraft.networkHashedPatchMap- A record containing a map of components to their hashed type/value along with a set of removed components.HashedStack- AnItemStackrepresentation that hashes the stored components.ProtocolInfo$DetailsProvider- Provides the details for a given protocol.SkipPacketDecoderException- An exception thrown when an error occurs during decoding before having its data ignored.SkipPacketEncoderException- An exception thrown when an error occurs during encoding before having its data ignored.
net.minecraft.network.chatLastSeenMessagescomputeChecksum- Computes a byte representing the merged checksums of all message signatures.$Update#verifyChecksum- Verifies that the update checksum matches those within the last seen messages.
LastSeenMessagesValidator$ValidationException- An exception thrown if the messages can not be validated.MessageSignaturedescribe- Returns a stringified version of the message signature.checksum- Hashes the bytes within the signature into a single integer.
PlayerChatMessage#describeSigned- Returns a stringified version of the chat message.
net.minecraft.network.codecByteBufCodecsLONG_ARRAYlengthPrefixed- Returns an operation that limits the size of the buffer to the given size.
IdDispatchCodec$DontDecorateException- An interface that tells the exception handler to rethrow the raw exception rather than wrap it within anEncoderException.
net.minecraft.network.protocolCodecModifier- A function that modifies some codec using a given object.ProtocolInfoBuilder#context*Protocol- Builds anUnboundProtocolwith the given context used to modify the codecs to send.
net.minecraft.network.protocol.game.GameProtocolsHAS_INFINITE_MATERIALS- A modifier that checks theServerboundSetCreativeModeSlotPacketfor if the player has the necessary settings. If not, the packet is discarded.$Context- Returns the context used by the packet to modify the incoming codec.
net.minecraft.resources.DelegatingOps$DelegateListBuilder- A list builder that can be subclassed if needed.$DelegateRecordBuilder- A record builder that can be subclassed if needed.
net.minecraft.server.bossevents.CustomBossEvent$Packed- A record that backs the event information for serialization.net.minecraft.server.commands.InCommandFunction- A command function that takes in some input and returns a result.net.minecraft.server.levelDistanceManager#forEachBlockTickingChucnks- Applies the provided consumer for each chunk with block ticking enabled.ServerLevelareEntitiesActuallyLoadedAndTicking- Returns whether the entity manager is actually ticking and loading entities in the given chunk.tickThunder- Ticks the thunger logic within a given level.anyPlayerCloseEnoughForSpawning- Returns if a player is close enough to spawn the entity at the given location.
ServerPlayer$RespawnConfig- A record containing the respawn information for the player.
net.minecraft.utilAbstractListBuilder- A ops list builder which boils the implementation down to three methods which initializes, appends, and builds the final list.Brightnessblock- Returns the block light from a packed value.sky- Returns the sky light from a packed value.
HashOps- A dynamic ops that generates a hashcode for the data.ExtraCodecsUNTRUSTED_URI- A codec for a URI that is not trusted by the game.CHAT_STRING- A codec for a string in a chat message.legacyEnum- A codec that maps an enum to its output inEnum#toString.
FileSystemUtil- A utility for interacting with the file system.GsonHelper#encodesLongerThan- Returns whether the provided element can be written in the specified number of characters.Unit#STREAM_CODEC- A stream codec for a unit instance.UtilmapValues- Updates the values of a map with the given function.mapValuesLazy- Updates the values of a map with the given function, but each value is resolved when first accessed.growByHalf- Returns an integer multiplied by 1.5, rounding down, clamping the value to some minimum and the max integer size.
net.minecraft.util.random.Weighted#map,WeightedList#map- Transforms the stored object(s) to a new type.net.minecraft.util.thread.ParallelMapTransform- A helper that handles scheduling and batching tasks in parallel.net.minecraft.world.effect.MobEffectInstance#withScaledDuration- Constructs a new instance with the duration scaled by some float value.net.minecraft.world.entityAreaEffectCloud#setPotionDurationScale- Sets the scale of how long the potion should apply for.DropChances- A map of slots to probabilities indicating how likely it is for an entity to drop that piece of equipment.EntityisInterpolating- Returns whether the entity is interpolating between two steps.sendBubbleColumnParticles- Spawns bubble column particles from the server.canSimulateMovement- Whether the entity’s movement can be simulated, usually from being the player.propagateFallToPassengers- Propogates the fall damage of a vehicle to its passengers.lavaIgnite- Ignites the entity for 15 seconds if not immune.clearFreeze- Sets the number of ticks the entity is frozen for to 0.removeLatestMovementRecordingBatch- Removes the last element from all movements performed this tick.
InterpolationHandler- A class meant to easily handle the interpolation of the position and rotation of the given entity as necessary.LivingEntitygetLuck- Returns the luck of the entity for random events.getLastHurtByPlayer,setLastHurtByPlayer- Handles the last player to hurt this entity.getEffectBlendFactor- Gets the blend factor of an applied mob effect.applyInput- Applies the entity’s input as its AI, typically for local players.INPUT_FRICTION- The scalar to apply to the movements of the entity.
net.minecraft.world.entity.animal.camel.Camel#checkCamelSpawnRules- Checks if a camel can spawn at a particular position.net.minecraft.world.entity.animal.sheep.SheepColorSpawnRules- A class that contains the color spawn configurations for a sheep’s wool when spawning within a given climate.net.minecraft.world.entity.npc.Villager#createDefaultVillagerData- Returns the default type and profession of the villager to use when no data is set.net.minecraft.world.entity.player.PlayerpreventsBlockDrops- Whether the player cannot drop any blocks on destruction.gameMode- Returns the current game mode of the player.debugInfo- Returns the common information about the player as a single string.
net.minecraft.world.inventoryContainerSynchronizer#createSlot- Creates aRemoteSlotthat represents a slot on the opposite side.RemoteSlot- A slot that represents the data on the opposing side, syncing when the data is not consistent.
net.minecraft.world.itemEitherHolder#key- Returns the resource key of the held registry object.Item#STREAM_CODECItemStackOPTIONAL_UNTRUSTED_STREAM_CODECMAP_CODECcanDestroyBlock- Returns whether this item can destroy the provided block state.
net.minecraft.world.item.alchemy.PotionContents#getPotionDescription- Returns the description of the mob effect with some amplifier.net.minecraft.world.item.craftingRecipe#KEY_CODECTransmuteResult- A recipe result object that represents an item, count, and the applied components.
net.minecraft.world.item.equipment.trim.ArmorTrim#layerAssetId- Returns the location of the the trim asset.net.minecraft.world.levelBlockGetter$BlockStepVisitor- A consumer that takes in the current position and how many collisions within the desired path of travel.ColorMapColorUtil- A helper for getting the color from a map given the biome’s temperature, downfall, colormap, and default color.DryFoliageColor- A color resolver for biomes with dry foliage.GameRulesgetType- Gets the game rule type from its key.keyCodec- Creates the codec for the key of a game rule type.
LevelisMoonVisible- Returns wehther the moon is currently visible in the sky.getPushableEntities- Gets all entities except the specified target within the provided bounding box.getClientLeafTintColor- Returns the color of the leaf tint at the specified location.playPlayerSound- Plays a sound to the current player on the client.
LevelReader#getHeight- Returns the height of the map at the given position.NaturalSpawner#INSCRIBED_SQUARE_SPAWN_DISTANCE_CHUNK- Provides the minimum distance that the player is close enough for spawning to occur.
net.minecraft.world.level.biomeBiomegetDryFoliageColor,getDryFoliageColorFromTexture- Gets the dry foliage color of the biome, either from the effects or from the climate settings.
BiomeSpecialEffects#getDryFoliageColorOverride,$Builder#dryFoliageColorOverride- Returns the default dry foliage color when not pulling from a colormap texture.
net.minecraft.world.level.blockBaseFireBlock#fireIgnite- Lights an entity on fire.BlockUPDATE_SKIP_BLOCK_ENTITY_SIDEEFFECTS- A flag that skips all potential sideeffects when updating a block entity.UPDATE_SKIP_ALL_SIDEEFFECTS- A flag that skips all sideeffects by skipping certain block entity logic, supressing drops, and updating the known shape.UPDATE_SKIP_ON_PLACE- A flag that skips callingBlockState#onPlacewhen set.
BonemealableBlock#hasSpreadableNeighbourPos,findSpreadableNeighbourPos- Handles finding other positions that the vegetation can spread to on bonemeal.CactusFlowerBlock- A flower that grows on a cactus.FireflyBushBlock- A bush that spawns firefly particles around it.SandBlock- A colored sand block that can play ambient sounds.SegmentableBlock- A block that can typically be broken up into segments with unique sizes and placements.ShortDryGrassBlock- A single grass block that has been dried out.TallDryGrassBlock- A double grass block that has been dried out.TerracottaBlock- A terracotta block that can play ambient sounds.TintParticleLeavesBlock- A leaves block whose particles are tinted.UntintedParticleLeavesBlock- A leaves block whose particles are not tinted.VegetationBlock- A block that represents some sort of vegetation that can propogate light and need some sort of farmland or dirt to survive.
net.minecraft.world.level.block.entity.StructureBlockEntity#isStrict,setStrict- Sets strict mode when generating structures.net.minecraft.world.level.block.sounds.AmbientDesertBlockSoundsPlayer- A helper to play sounds for a given block, typically duringanimateTick.net.minecraft.world.level.block.state.BlockBehaviour#getEntityInsideCollisionShape- Gets the collision shape of the block when the entity is within it.net.minecraft.world.level.border.WorldBorderclosestBorder- Returns a list of the closest borders to the player based on their horizontal direction.$DistancePerDirection- A record containing the distance from the entity of the world border in a given direction.
net.minecraft.world.level.chunk.status.ChunkStatus#CODECnet.minecraft.world.level.entity.PersistentEntitySectionManager#isTicking- Returns whether the specified chunk is currently ticking.net.minecraft.world.level.levelgen.Heightmap$Types#STREAM_CODECnet.minecraft.world.level.levelgen.featureAbstractHugeMushroomFeature#placeMushroomBlock- Places a mushroom block that specified location, replacing a block if it can.FallenTreeFeature- A feature that generates flane trees with a stump of given lengths.TreeFeature#getLowestTrunkOrRootOfTree- Retruns the lowest block positions of the tree decorator.
net.minecraft.world.level.levelgen.feature.configurations.FallenTreeConfiguration- A configuration for fallen trees with stumps.net.minecraft.world.level.levelgen.feature.treedecoratorsAttachedToLogsDecorator- A decorator that attaches a random block to a given direction on a log with a set probability.PlaceOnGroundDecorator- A decorator that places the tree on a valid block position.
net.minecraft.world.level.levelgen.structure.poolsListPoolElement#getElements- Returns the elements of the structure pool.SinglePoolElement#getTemplateLocation- Returns the location of the template used by the element.StructureTemplatePool#getTemplates- Returns a list of elements with their weights.
net.minecraft.world.level.levelgen.structure.structures.JigsawStructuregetStartPool- Returns the starting pool of the jigsaw to generate.getPoolAliases- Returns all pools used by the jigsaw.
net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate#getDefaultJointType- Returns the default join type between two jigsaw pieces if none is specified or an error occurs during loading.net.minecraft.world.level.material.Fluid#getAABB,FluidState#getAABB- Returns the bounding box of the fluid.net.minecraft.world.scoresObjective#pack,$Packed- Handles the serializable form of the objective data.PlayerTeam#pack,$Packed- Handles the serializable form of the player team data.ScoreboardloadPlayerTeam,loadObjective- Loads the data from the packed object.$PackedScore- Handles the serializable form of the scoreboard data.
net.minecraft.world.level.storage.loot.LootTable#KEY_CODECnet.minecraft.world.physAABB$Builder- A builder for constructing a bounding box by providing the vectors within.Vec2#CODEC
net.minecraft.world.phys.shapes.CollisionContextplacementContext- Constructs the context when placing a block from its item.isPlacement- Returns whether the context is being used for placing a block.
net.minecraft.world.ticks.TickPriority#CODEC
List of Changes
net.minecraft.client.Screenshotis now a utility instead of an instance class, meaning all instance methods are removedtakeScreenshot(RenderTarget)->takeScreenshot(RenderTarget, Consumer<NativeImage>), not returning anything
net.minecraft.client.multiplayerClientChunkCache#replaceWithPacketDatanow takes in aMap<Heightmap$Types, long[]>instead of aCompoundTagMultiPlayerGameMode#hasInfiniteItems->net.minecraft.world.entity.LivingEntity#hasInfiniteMaterialsClientPacketListener#markMessageAsProcessednow takes in aMessageSignatureinstead of aPlayerChatMessage
net.minecraft.client.multiplayer.chat.ChatListener#handleChatMessageErrornow takes in a nullableMessageSignaturenet.minecraft.client.playerClientInput#leftImpulse,forwardImpulse->moveVector, now protectedLocalPlayer#spinningEffectIntensity,oSpinningEffectIntensity->portalEffectIntensity,oPortalEffectIntensity
net.minecraft.client.renderer.LevelRenderer#getLightColor(BlockAndTintGetter, BlockState, BlockPos)->getLightColor(LevelRenderer$BrightnessGetter, BlockAndTintGetter, BlockState, BlockPos)net.minecraft.client.renderer.blockentity.BlockEntityRenderer#rendernow takes in aVec3representing the camera’s positionnet.minecraft.client.renderer.chunk.SectionRenderDispatcher$RenderSectiongetOrigin->getRenderOriginresetis now publicreleaseBuffersis removed
$CompileTask#getOrigin->getRenderOrigin
net.minecraft.client.renderer.entityDonkeyRenderernow takes in aDonekyRenderer$Typecontaining the textures, model layers, and equipment informationItemEntityRenderer#renderMultipleFromCountnow has an overload that takes in the model bounding boxUndeadHorseRenderernow takes in aUndeadHorseRenderer$Typecontaining the textures, model layers, and equipment information
net.minecraft.client.renderer.entity.layersEquipmentLayerRenderer$TrimSpriteKey#textureId->spriteIdVillagerProfessionLayer#getHatDatanow takes in a map of resource keys to metadata sections and swaps the registry and value for a holder instance
net.minecraft.client.renderer.itemConditionalItemModelnow takes in aItemModelPropertyTestinstead of aConditionalItemModelPropertySelectItemModelnow takes in a$ModelSelectorinstead of an object map
net.minecraft.client.renderer.item.properties.conditional.ConditionalItemModelPropertynow implementsItemModelPropertyTestItemModelPropertyTestholds thegetmethod previously withinConditionalItemModelProperty
net.minecraft.commands.argumentsComponentArgumentERROR_INVALID_JSON->ERROR_INVALID_COMPONENTgetComponent->getRawComponent
ResourceKeyArgument#getRegistryKeyis now publicStyleArgument#ERROR_INVALID_JSON->ERROR_INVALID_STYLE
net.minecraft.commands.arguments.itemComponentPredicateParser$Context#createComponentTest,createPredicateTestnow takes in aDynamicinstead of aTagItemPredicateArgument$ComponentWrapper#decodenow takes in aDynamicinstead of aRegistryOps,Tagpair$PredicateWrapper#decodenow takes in aDynamicinstead of aRegistryOps,Tagpair
net.minecraft.coreBlockMathVANILLA_UV_TRANSFORM_LOCAL_TO_GLOBAL,VANILLA_UV_TRANSFORM_GLOBAL_TO_LOCALis now privategetUVLockTransform->getFaceTransformation
Direction#rotatenow takes in aMatrix4fcinstead of aMatrix4fRotationsis now a record
net.minecraft.data.loot.BlockLootSubProvider#createPetalDrops->createSegmentedBlockDropsnet.minecraft.networkFriendlyByteBufwriteLongArray,readLongArraynow have static delegates which take in theByteBufand*Fixed*versions for fixed size arrays
ProtocolInfo$Unbound->$Details,net.minecraft.network.protocol.SimpleUnboundProtocol,net.minecraft.network.protocol.UnboundProtocol; not one-to-one#bind->net.minecraft.network.protocol.SimpleUnboundProtocol#bind,UnboundProtocol#bind; not one-to-one
SkipPacketExceptionis now an interface instead of a subclass ofEncoderException
net.minecraft.network.chatComponentSerialization#flatCodec->flatRestrictedCodecLastSeenMessages$Updatenow takes in a byte representing the checksum valueLastSeenMessagesValidatorapplyOffsetnow returns nothing and can throw a$ValidationExceptionapplyUpdatenow returns the raw messages and can throw a$ValidationException
net.minecraft.network.codec.StreamCodec#compositenow has an overload for nine parametersnet.minecraft.network.protocol.ProtocolInfoBuildernow takes in a third generic representing how to modify the provided codec.addPacketnow has an overload that takes in aCodecModifierbuild->buildUnbound, not one-to-oneprotocol,serverboundProtocol,clientboundProtocolnow returns aSimpleUnboundProtocol
net.minecraft.network.protocol.ConfigurationProtocolsnow containSimpleUnboundProtocolconstantsnet.minecraft.network.protocol.gameClientboundContainerSetContentPacketis now a recordClientboundMoveEntityPacket#getyRot,getxRot->getYRot,getXRotClientboundPlayerChatPacketnow takes in a global index for the chat messageClientboundLevelChunkPacketdata#getHeightmapsnow returns aMap<Heightmap.Types, long[]>ClientboundUpdateAdvancementsPacketnow takes in a boolean representing whether to show the adavncements as a toastGameProtocolsconstants are now eitherSimpleUnboundProtocols orUnboundProtocolsServerboundContainerClickPacketis now a recordServerboundMovePlayerPacket$Pos,$PosRotnow has an overload that takes in aVec3for the positionServerboundSetStructureBlockPacketnow takes in an additional boolean representing whether the structure should be generated in strict mode
net.minecraft.network.protocol.handshake.HandshakeProtocols#SERVERBOUND_TEMPLATEis now aSimpleUnboundProtocolnet.minecraft.network.protocol.login.LoginProtocols#SERVERBOUND_TEMPLATEconstants are nowSimpleUnboundProtocolsnet.minecraft.network.protocol.status.StatusProtocols#SERVERBOUND_TEMPLATEconstants are nowSimpleUnboundProtocolsnet.minecraft.server.PlayerAdvancements#flushDirtynow takes in a boolean that represents whether the advancements show display as a toastnet.minecraft.server.bossevents.CustomBossEventsave->pack, not one-to-oneloadnow takes in the id and the packed variant to unpack
net.minecraft.server.levelDistanceManagerhasPlayersNearbynow returns aTriStateforEachBlockTickingChunks->forEachEntityTickingChunk, not one-to-one
ServerEntitynow takes in a consumer for broadcasting a packet to all players but those in the ignore listServerLevelgetForcedChunks->getForceLoadedChunksisPositionTickingWithEntitiesLoadedis now publicisNaturalSpawningAllowed->canSpawnEntitiesInChunk,BlockPosvariant is removed
ServerPlayergetRespawnPosition,getRespawnAngle,getRespawnDimension,isRespawnForced->getRespawnConfig, not one-to-onesetRespawnPositionnow takes in a$RespawnConfiginstead of the individual respawn informationloadAndSpawnParentVehicle,loadAndSpawnEnderpearlsnow takes in aCompoundTagwithout the optional wrapping\
net.minecraft.server.network.ServerGamePacketListenerImplnow implementsGameProtocols$Contextnet.minecraft.sounds.SoundEventshave the following sounds nowHolderwrapped:ITEM_BREAKSHIELD_BLOCK,SHIELD_BREAK,WOLF_ARMOR_BREAK
net.minecraft.utilBrightnessFULL_BRIGHTis now finalpacknow has a static overload that takes in the block and sky light.
ExtraCodecs#MATRIX4fnow is aCodec<Matrix4fc>Util#makeEnumMapreturns theMapsuperinstance rather than the specificEnumMap
net.minecraft.util.parsing.packrat.commands.TagParseRulenow takes in a generic for the tag type- The construct is now public, taking in a
DynamicOps
- The construct is now public, taking in a
net.minecraft.util.profilingActiveProfilernow takes in aBooleanSupplierinstead of a booleanContinuousProfilernow takes in aBooleanSupplierinstead of a boolean
net.minecraft.util.worldupdate.WorldUpgradernow takes in the currentWorldDatanet.minecraft.worldBossEvent$BossBarColor,$BossBarOverlaynow implementsStringRepresentableContainernow implementsIterable<ItemStack>
net.minecraft.world.effectMobEffectgetBlendDurationTicks->getBlendInDurationTicks,getBlendOutDurationTicks,getBlendOutAdvanceTicks; not one-to-onesetBlendDurationnow has an overload that takes in three integers to set the blend in, blend out, and blend out advance ticks
MobEffectInstance#tick->tickServer,tickClient; not one-to-one
net.minecraft.world.entityEntitycancelLerp->InterpolationHandler#cancellerpTo->moveOrInterpolateTolerpTargetX,lerpTargetY,lerpTargetZ,lerpTargetXRot,lerpTargetYRot->getInterpolationonAboveBubbleCol->onAboveBubbleColumnnow takes in aBlockPosfor the bubble column particles spawn location- Logic delegates to the protected static
handleOnAboveBubbleColumn
- Logic delegates to the protected static
isControlledByOrIsLocalPlayer->isLocalInstanceAuthoritative, now finalisControlledByLocalInstance->isLocalClientAuthoritative, now protectedisControlledByClient->isClientAuthoritativefallDistance,causeFallDamageis now a doubleabsMoveto->absSnapToabsRotateTo->asbSnapRotationTomoveTo->snapTosendBubbleColumnParticlesis now static, taking in theLevelonInsideBubbleColumnlogic delegates to the protected statichandleOnInsideBubbleColumn
EntityTypePOTION->SPLASH_POTION,LINGERING_POTION, not one-to-one$EntityFactory#createcan now return a null instance
ExperienceOrb#value->DATA_VALUEItemBasedSteeringno longer takes in the accessor for having a saddleLivingEntitylastHurtByPlayerTime->lastHurtByPlayerMemoryTimelerpSteps,lerpX,lerpY,lerpZ,lerpYRot,lerpXRot->interpolation, not one-to-oneisAffectedByFluidsis now publicremoveEffectNoUpdateis now finaltickHeadTurnnow returns nothingcanDisableShield->canDisableBlocking, now set via theWEAPONdata componentcalculateFallDamagenow takes in a double instead of a float
MobhandDropChances,armorDropChances,bodyArmorDropChance->dropChances, not one-to-onegetEquipmentDropChance->getDropChances, not one-to-one
net.minecraft.world.entity.ai.Brain#addActivityWithConditionsnow has an overload that takes in an integer indiciating the starting prioritynet.minecraft.world.entity.ai.behaviorLongJumpToRandomPos$PossibleJumpis now a recordVillagerGoalPackages#get*Packagenow takes in a holder-wrapped profession
net.minecraft.world.entity.ai.gossip.GossipContainer#store,update->clear,putAll,copy; not one-to-onenet.minecraft.world.entity.animalPigis now aVariantHolderSheep->.sheep.SheepWaterAnimal#handleAirSupplynow takes in aServerLevel
net.minecraft.world.entity.animal.axolotl.Axolotl#handleAirSupplynow takes in aServerLevelnet.minecraft.world.entity.monster.ZombieVillager#setGossipsnow takes in aGossipContainernet.minecraft.world.entity.monster.warden.WardenSpawnTrackernow has an overload which sets the initial parameters to zeronet.minecraft.world.entity.npcVillagernow takes in either a key or a holder of theVillagerTypesetGossipsnow takes in aGossipContainer
VillagerDatais now a recordset*->with*
VillagerProfessionnow takes in aComponentfor the nameVillagerTradesTRADESnow takes in a resource key as the key of the map- This is similar for all other type specific trades
$FailureItemListingis now private
net.minecraft.world.entity.player.PlayerstopFallFlying->LivingEntity#stopFallFlyingisSpectator,isCreativeno longer abstract in thePlayerclass
net.minecraft.world.entity.projectile.ThrownPotion->AbstractThrownPotion, implemented inThrownLingeringPotionandThrownSplashPotionnet.minecraft.world.entity.raid.Raid(int, ServerLevel, BlockPos)->Raid(BlockPos, Difficulty)tick,addWaveMobnow takes in theServerLevel
net.minecraft.world.entity.vehicleAbstractMinecart#setDisplayBlockState->setCustomDisplayBlockStateMinecartBehaviorcancelLerp->InterpolationHandler#cancellerpTargetX,lerpTargetY,lerpTargetZ,lerpTargetXRot,lerpTargetYRot->getInterpolation
MinecartTNT#primeFusenow takes in theDamageSourcecause
net.minecraft.world.inventoryAbstractContainerMenusetRemoteSlotNoCopy->setRemoteSlotUnsafe, not one-to-onesetRemoteCarriednow takes in aHashedStack
ClickTypenow takes in an id for its representationsContainerSynchronizer#sendInitialDatanow takes in a list of stacks rather than aNonNullList
net.minecraft.world.itemEitherHoldernow takes in anEitherinstance rather than just anOptionalholder andResourceKeyItemcanAttackBlock->canDestroyBlockhurtEnemyno longer returns anythingonCraftedByno longer takes in a separateLevelinstance, now relying on the one provided by thePlayer
ItemStackvalidateStrictis now publiconCraftedByno longer takes in a separateLevelinstance, now relying on the one provided by thePlayer
MapItemcreatenow takes in aServerLevelinstead of aLevellockMapis now private
ThrowablePotionItemis now abstract, containing two methods to create theAbstractThrownPotionentityWrittenBookItem#resolveBookComponents->WrittenBookContent#resolveForItem
net.minecraft.world.item.alchemy.PotionContentsnow implementsTooltipProviderforEachEffect,applyToLivingEntitynow takes in a float representing a scalar for the duration
net.minecraft.world.item.component.WrittenBookContentnow implementsTooltipProvidernet.minecraft.world.item.craftingSmithingRecipe#baseIngredientnow returns anIngredientSmithingTransformRecipenow takes in aTransmuteResultinstead of anItemStackand anIngredientfor the baseSmithingTrimRecipenow takes inIngredients instead ofOptionalwrapped entries along with aTrimPatternholderTransmuteRecipenow takes in aTransmuteResultinstead of anItemholder
net.minecraft.world.item.crafting.display.SlotDisplay$SmithingTrimDemoSlotDisplaynow takes in aTrimPatternholdernet.minecraft.world.item.enchantment.EnchantmentInstanceis now a recordnet.minecraft.world.levelBlockGetter#boxTraverseBlocks->forEachBlockIntersectedBetween, not one-to-oneCustomSpawner#tickno longer returns anythingGameRules$Typenow takes in a value classLevelonBlockStateChange->updatePOIOnBlockStateChangeisDay->isBrightOutsideisNight->isDarkOutsidesetMapData->net.minecraft.server.level.ServerLevel#setMapDatagetFreeMapId->net.minecraft.server.level.ServerLevel#getFreeMapId
LevelAccessor#blockUpdated->updateNeighborsAt
net.minecraft.world.level.biome.MobSpawnSettings$SpawnerDatais now a recordnet.minecraft.world.level.blockAttachedStemBlocknow extendsVegetationBlockAzaleaBlocknow extendsVegetationBlockBlock#fallOnnow takes a double for the fall damage instead of a floatBushBlocknow extendsVegetationBlockand implementsBonemealableBlockColoredFallingBlock#dustColoris now protectedCropBlocknow extendsVegetationBlockDeadBushBlock->DryVegetationBlockDoublePlantBlocknow extendsVegetationBlockFallingBlock#getDustColoris now abstractFlowerBedBlocknow extendsVegetationBlockFlowerBlocknow extendsVegetationBlockFungusBlocknow extendsVegetationBlockLeafLitterBlocknow extendsVegetationBlockLeavesBlockis now abstract, taking in the chance for a particle to spawn- Particles are spawned via
spawnFallingLeavesParticle
- Particles are spawned via
MangroveLeavesBlocknow extendsTintedParticleLeavesBlockMushroomBlocknow extendsVegetationBlockNetherSproutsBlocknow extendsVegetationBlockNetherWartBlocknow extendsVegetationBlockParticleLeavesBlock->LeafLitterBlockPinkPetalsBlock->FlowerBedBlockRootsBlocknow extendsVegetationBlockRotationnow has an index used for syncing across the networkSaplingBlocknow extendsVegetationBlockSeagrassBlocknow extendsVegetationBlockSeaPickleBlocknow extendsVegetationBlockStemBlocknow extendsVegetationBlockSweetBerryBushBlocknow extendsVegetationBlockTallGrassBlocknow extendsVegetationBlockTntBlock#primenow returns whether the primed tnt was spawned.WaterlilyBlocknow extendsVegetationBlock
net.minecraft.world.level.block.entityBlockEntityparseCustomNameSafenow takes in a nullableTaginstead of a stringgetPosFromTagnow takes in theChunkPos$ComponentHolder#COMPONENTS_CODECis now aMapCodec
BLockEntityType#createis no longer nullable
net.minecraft.world.level.block.entity.trialspawner.TrialSpawner#codecnow returns aMapCodecnet.minecraft.world.level.block.state.StateHoldergetNullableValueis now privatehasPropertyno longer contains a generic
net.minecraft.world.level.chunkChunkAccess#setBlockStatenow takes in the block flags instead of a boolean, and has an overload to update all setLevelChunk#replaceWithPacketDatanow takes in aMap<Heightmap$Types, long[]>instead of aCompoundTag
net.minecraft.world.level.chunk.storage.SerializableChunkData#getChunkTypeFromTag->getChunkStatusFromTag, not one-to-onenet.minecraft.world.level.gameevent.vibrations.VibrationSystem#DEFAULT_VIBRATION_FREQUENCY->NO_VIBRATION_FREQUENCYnet.minecraft.world.level.levelgen.feature.TreeFeature#isVineis now publicnet.minecraft.world.level.levelgen.structure.pools.aliasDirect->DirectPoolAliasRandom->RandomPoolAliasRandomGroup->RandomGroupPoolAlias
net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate$JigsawBlockInfonow takes in aResourceKeyto theStructureTemplatePoolinstead of a rawResourceLocationnet.minecraft.world.level.saveddata.maps.MapFrameis now a recordsave,load->CODEC, not one-to-one
net.minecraft.world.level.storage.loot.functions.SetWrittenBookPagesFunction#PAGE_CODEC->WrittenBookContent#PAGES_CODECnet.minecraft.world.scoresScore#write->CODEC, not one-to-oneScoreboardsavePlayerScores->packPlayerScores, not one-to-oneloadPlayerScores->loadPlayerScore, not one-to-one
Team$CollisionRule,$Visibilityare nowStringRepresentable
net.minecraft.world.phys.shapes.EntityCollisionContextnow takes in a boolean representing if it is used for placing a blocknet.minecraft.world.ticks.SavedTickloadTick,saveTick,save->codec, not one-to-oneloadTickList->filterTickListForChunk, not one-to-one
List of Removals
com.mojang.blaze3d.vertex.BufferUploadernet.minecraft.core.Rotations#getWrapped*net.minecraft.network.chat.ComponentSerialization#FLAT_CODECnet.minecraft.network.protocol.gameClientboundAddExperimentOrbPacketClientGamePacketListener#handleAddExperienceOrb
net.minecraft.resources.ResourceLocation$Serializernet.minecraft.server.network.ServerGamePacketListenerImpl#addPendingMessagenet.minecraft.worldBossEvent$BossBarColor#byName,$BossBarOverlay#byNameClearable#tryClear
net.minecraft.world.effect.MobEffectInstance#save,loadnet.minecraft.world.entityEntityisInBubbleColumnisInWaterRainOrBubble,isInWaterOrBubblenewDoubleList,newFloatListrecordMovementThroughBlocks
EntityEvent#ATTACK_BLOCKED,SHIELD_DISABLEDItemBasedSteeringaddAdditionalSaveData,readAdditionalSaveDatasetSaddle,hasSadddle
LivingEntitytimeOffs,rotOffsrotAoRun,runanimStep,animStep0appliedScalecanBeNameTagged
MobDEFAULT_EQUIPMENT_DROP_CHANCEPRESERVE_ITEM_DROP_CHANCE_THRESHOLD,PRESERVE_ITEM_DROP_CHANCE
NeutralMob#setLastHurtByPlayerPositionMoveRotation#ofEntityUsingLerpTarget
net.minecraft.world.entity.ai.attributes.AttributeModifier#save,loadnet.minecraft.world.entity.animalDolphin#setTreasurePos,getTreasurePosFox$Variant#byNameMushroomCow$Variant#byNamePanda$Gene#byNameSalmon$Variant#byNameTurtlegetHomePossetTravelPos,getTravelPosisGoingHome,setGoingHomeisTravelling,setTravelling
net.minecraft.world.entity.animal.armadillo.Armadillo$ArmadilloState#fromNamenet.minecraft.world.entity.npc.VillagerTrades#EXPERIMENTAL_WANDERING_TRADER_TRADESnet.minecraft.world.entity.projectile.AbstractArrow#getBaseDamagenet.minecraft.world.entity.raid.RaidgetLevel,getIdsave
net.minecraft.world.entity.vehicle.AbstractMinecart#hasCustomDisplay,setCustomDisplaynet.minecraft.world.item.ItemStack#parseOptional,saveOptionalnet.minecraft.world.item.equipment.trim.TrimPattern#templateItemnet.minecraft.world.level.Level#updateNeighborsAt(BlockPos, Block)net.minecraft.world.level.block.entityCampfireBlockEntity#dowsePotDecorations#save,load
net.minecraft.world.level.levelgen.BelowZeroRetrogen#readnet.minecraft.world.level.levelgen.structure.structures.RuinedPortalPiece$VerticalPlacement#byNamenet.minecraft.world.level.saveddata.maps.MapBanner#LIST_CODECnet.minecraft.world.scores.Team$CollisionRule#byName$Visibility#getAllNames,byName
net.minecraft.world.ticks.LevelChunkTicks#save,load
Minecraft 1.21.5 -> 1.21.6 Mod Migration Primer
This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.5 to 1.21.6. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.
This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.
If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.
Thank you to:
- @Soaryn for some
ItemStackbest practices and typo fixes - @earthcomputer for color changes when drawing strings
Pack Changes
There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.
GUI Changes
The GUI rendering system has significantly changed from the previous version. While it may seem somewhat similar on the surface, the actual implementation details are much more complex and roundabout. This will explain a high-level overview of the new system with some basic examples.
Prepare and Render
Rendering a GUI has been broken into two phases: ‘prepare’ and ‘render’.
The prepare phase is what we typically consider the GUI render methods (e.g., Gui#render, AbstractContainerScreen#renderBg, etc.). These methods, instead of actually rendering the components, now submit them to the GuiRenderState to be stored for use during the ‘render’ phase. The GuiRenderState is stored on the GameRenderer and passed to the GuiGraphics which uses the previous methods to add the desired objects to the render state.
The render phase is what actually handles the rendering of all the objects. This is handled through the GuiRenderer, which reads the data from the GuiRenderState and, after a bit of delegated preparation and sorting, renders the objects to the screen. The GuiRenderer is also stored on the GameRenderer.
Element Ordering
Now, how are elements rendered onto screen? In the previous versions, this happened mainly based on the order of the render calls. However, the new system using two different methods of sorting. The first method handles the depth using strata and a linear tree. The second method uses a comparator based on three things (in order of priorty): the ScreenRectangle scissor, the RenderPipeline order, and the TextureSetup’s hash code. These are all stored on the GuiElementRenderState passed to the GuiRenderState via GuiRenderState#submitGuiElement.
Once the elements have been ordered, they are rendered starting at a Z of 0, with each element rendered 0.01 ahead of the previous.
As a warning, due to the element sort order, certain custom configurations may result in incorrect screen renders. As such, it is imperative that you understand how the methods and their assigned values work when sorting elements.
Strata and Trees
The first method of sorting handles the z-depth an object is rendered at.
First let’s start with the linear tree. As the name implies, it is basically a doubly-linked GuiRenderState$Node list. Each node contains its own list of elements to render. Navigating the node list is handled using GuiRenderState#up or down, where each either gets the next node, or creates a new one if it doesn’t exist. Nodes within a given tree are rendered from bottom to top, meaning that down will render any elements submitted before the current node, while up will render any elements submitted after the current node.
Determining what node an object is added to is computed automatically when submitting an element using its ScreenArea. The ScreenArea defines the bounds of your element to be rendered. Essentially, a node will be added in the up direction if the bounds of the element intersect with any other element on the current node.
Then there are strata. A stratum is essentially a linear tree. Strata are rendered in the order they are created, which means calling nextStratum will render all elements after the previous stratum. This can be used if you want to group elements into a specific layer. Note: you cannot navigate to a prior stratum.
The Comparator
The comparator handles sorting the elements within a given node in a linear tree in a strata.
Screen Rectangle Scissor
The ScreenRectangle is simply the area that the element is allowed to draw to, stored via GuiElementRenderState#scissorArea. Elements with no specified ScreenRectangle will be ordered first, followed by the minimum Y, the maximum Y, the minimum X, and the maximum X.
Render Pipeline
RenderPipelines define the pipeline used to render some object to the screen, including its shaders, format, uniforms, etc. This is stored via GuiElementRenderState#pipeline. Pipelines are sorted in the order they are built. This means that RenderPipelines#ENTITY_TRANSLUCENT will be rendered before RenderPipelines#GUI if on the same layer and scissor rectangle. As this is a system that relies on classloading constants, if you want to add new elements, make sure your mod loader supports some kind of dynamic pipeline ordering.
Texture Hash Code
TextureSetup defines Sampler0, Sampler1, and Sampler2 for use in the render pipelines, stored via GuiElementRenderState#textureSetup. Elements with no textures will be ordered first, followed by getSortKey of the record object. Note that, at the moment, this returns the hashCode of the TextureSetup, which may be non-deterministic as GpuTextureView does not implement hashCode, relying instead on the identity object hash.
GuiElementRenderState
Now that we understand ordering, what exactly is the GuiElementRenderState that we’ve been using? Well essentially, every object rendered to the screen is represented by a GuiElementRenderState, from the player seen in the inventory menu to each individual item. A GuiElementRenderState defines four methods. First, there are the common ones used for ordering and how to render to the screen (pipeline, scissorArea, textureSetup, bounds). Then there is buildVertices, which takes in the VertexConsumer to write the vertices to and the z-depth. For GUIs, this typically calls VertexConsumer#addVertexWith2DPose.
There are three types of GuiElementRenderStates provided by vanilla: BlitRenderState, ColoredRectangleRenderState, GlyphEffectRenderState, and GlyphRenderState. ColoredRectangleRenderState and GlyphRenderState/GlyphEffectRenderState are simple cases for handling a basic color rectangle and text character, respectively. BlitRenderState covers every other case as almost every method eventually writes to a GpuTexture which is then consumed by this.
GuiElementRenderStates are added to the GuiRenderState via GuiRenderState$Node#submitGuiElement. The GuiRenderState makes submitBlitToCurrentLayer and submitGlyphToCurrentLayer available to add textures and glyphs. For example, these are called by GuiGraphics#*line, fill, and blit* methods.
GuiItemRenderState
GuiItemRenderState is a special case used to render an item to the screen. It takes in the stringified name of the item, the current pose, its XY coordinates, and its scissor area. The ItemStackRenderState it holds is what defines how the item is rendered. The rendering bounds are computed based on the item model bounding box when ClientItem$Properties#oversizedInGui is true; otherwise, using a 16x16 square when false.
Just before the ‘render’ phase, the GuiRenderer effectively turns the GuiItemRenderState into a GuiElementRenderState, more specifically a BlitRenderState. This is done by constructing an item atlas GpuTexture which the item is drawn to, and then that texture is submitted as a BlitRenderState. All GuiItemRenderStates use RenderPipelines#GUI_TEXTURED_PREMULTIPLIED_ALPHA.
GuiElementRenderStates are added to the GuiRenderState via GuiRenderState#submitItem. This is called by GuiGraphics#render*Item* methods.
GuiTextRenderState
GuiTextRenderState is a special case used to render text to the screen. It takes in the Font, FormattedCharSequence, current pose, its XY coordinates, color, background color, whether it has a drop shadow, and its rendering bounds.
Just before the ‘render’ phase, the GuiRenderer turns the GuiTextRenderState into a GuiElementRenderState, more specifically a GlyphRenderState or GlyphEffectRenderState depending on what should be rendered via GuiTextRenderState#ensurePrepared. This performs a similar process as the item render state where the text is written to a GpuTexture to be consumed. Any backgrounds are rendered first, followed by the background effects, then the character, then finally the foreground effects.
GuiElementRenderStates are added to the GuiRenderState via GuiRenderState#submitText. This is called by GuiGraphics#draw*String and render*Tooltip methods.
Picture-in-Picture
Picture-in-Picture is a special case used to render arbitrary objects to a GpuTexture to be passed into a BlitRenderState. A Picture-in-Picture is made up of two components the PictureInPictureRenderState, and the PictureInPictureRenderer.
PictureInPictureRenderState is an interface which can store some data used to render the object to the texture. By default, it must supply the minimum and maximum XY coordinates, the texture scale, its scissor area, and its rendering bounds. You can also choose to specify the transformation matrix via pose. Any other data can be added by the implementor.
public record ExamplePIPRenderState(boolean data, int x0, int x1, int y0, int y1, float scale, @Nullable ScreenRectangle scissorArea, @Nullable ScreenRectangle bounds)
implements PictureInPictureRenderState {}
PictureInPictureRenderer is the renderer which writes the data to the GpuTexture. It does this by taking advantage of the fact that the RenderSystem#output*Override textures are written to in a BufferSource if they are not null. A PictureInPictureRenderer method must implement three methods. getRenderStateClass returns the class of the PictureInPictureRenderState implementation. getTextureLabel returns the texture label for debugging purposes. renderToTexture is where the render logic is called to write the data to the texture.
public class ExamplePIPRenderer extends PictureInPictureRenderer<ExamplePIPRenderState> {
// Takes in the buffer source from `RenderBuffers`
public ExamplePIPRenderer(MultiBufferSource.BufferSource bufferSource) {
super(bufferSource);
}
@Override
public Class<ExamplePIPRenderState> getRenderStateClass() {
// The class of the render state
return ExamplePIPRenderState.class;
}
@Override
protected void renderToTexture(ExamplePIPRenderState renderState, PoseStack pose) {
// Render whatever you want here
// You can make use of the buffer source via `this.bufferSource`
}
@Override
protected void blitTexture(ExamplePIPRenderState renderState, GuiRenderState guiState) {
// You can override this if you want to change how your layer is submitted to the render state
// By default, this uses the `BlitRenderState`
// Remove this if you want to handle submission yourself
super.blitTexture(renderState, guiState);
}
@Override
protected boolean textureIsReadyToBlit(ExamplePIPRenderState renderState) {
// When true, this will skip setting up the textures and projection matrices and use whatever is currently available
return false;
}
@Override
protected String getTextureLabel() {
// This can be anything, but it should be unique
return "examplemod: example pip";
}
}
To be able to use the renderer, is must be added to GuiRenderer#pictureInPictureRenderers. As the constructor takes in an immutable list while the renderer stores an immutable map, use whatever method is provided by your mod loader.
// We will assume:
// - `GuiRenderer#bufferSource` is accessible
// - The map is made mutable
// For some GuiRenderer renderer
var examplePIP = new ExamplePIPRenderer(renderer.bufferSource);
renderer.pictureInPictureRenderers.put(
examplePIP.getRenderStateClass(),
examplePIP
);
PictureInPictureRenderStates are added to the GuiRenderState via GuiRenderState#submitPicturesInPictureState. This is called by GuiGraphics#submit*RenderState methods.
Logic Changes
GuiGraphics#drawString now joins the rest of the GuiGraphics methods by allowing the int color argument to accept an alpha channel (upper eight bits). This means that any color string without an alpha specified will not be rendered. Previous behavior can be replicated by ORing your int color with 0xFF000000 or by passing your color into ARGB#opaque.
Contextual Bars
Many HUD elements on the screen take over where the experience bar is rendered. However, how these are rendered and which one is prioritized is handled through the contextual bar system. A contextual bar is made up of two parts, the ContextualBarRenderer, responsible for rendering the bar to the screen, and the Gui$ContextualInfo, which is used as the bar’s identifier.
A ContextualBarRenderer requires two methods to be implemented: renderBackground, which renders the bar itself, and render, which renders elements that appear on top of the bar.
public class ExampleContextualBarRenderer implements ContextualBarRenderer {
@Override
public void renderBackground(GuiGraphics graphics, DeltaTracker delta) {
// Render background bar sprites here
}
@Override
public void render(GuiGraphics graphics, DeltaTracker delta) {
// Render anything that might sit on top of the bar
}
}
Gui$ContextInfo is an enum, so your mod loader will need to either allow extensions or some other method of identifying a bar renderer. Then, the renderer needs to be added to map of renderers stored in Gui#contextualInfoBarRenderers. As this is an immutable map, use whatever method is provided by your mod loader.
// We will assume:
// - Created a new enum value `EXAMPLEMOD_EXAMPLE`
// - The map is made mutable
// For some Gui gui
gui.contextualInfoBarRenderers.put(
EXAMPLEMOD_EXAMPLE,
ExampleContextualBarRenderer::new
);
Finally, to get your bar to be called and prioritized, you need to modify Gui#nextContextualInfoState to return your enum value, or whatever method is provided by your mod loader.
Dialogs
To more generally handle screens which provide some basic functionalities – such as confirmation screens, button selection, or user input, Vanilla has provided a generic dialog system. These dialogs can be constructed in a datapack and delivered on the client by calling Player#openDialog. The basic JSON description is documented in Minecraft Snapshot 25w20a.
For a quick overview, a basic Dialog contains the following components: a title, an optional external title for navigation, whether the screen can be closed by pressing ‘esc’, and its DialogBody contents. Everything else is determined by the dialog itself, but it has functionality for user inputs via InputControls. Buttons are typically added through ClickActions which hold the common button data and an event to execute on click. If the dialog is canceled (e.g., closed), then onCancel is run.
DialogBody and InputControl are simply generic interfaces that have no defined structure. Implementing them, or any dialog for that matter, requires some registration to the available types on both the client and server.
Custom Bodies
A DialogBody is simply the contents of a dialog screen. This is generally immutable information that should be displayed at all times. Every dialog holds a list of these DialogBodys as every screen has some text to explain what it is for. It only contains one method mapCodec, which is used as the registry key and encoder for the body information.
// Obviously, a body would have actual contents, but this is simply an example implementation
public record ExampleDialogBody(boolean val1, int val2) implements DialogBody {
public static final MapCodec<ExampleDialogBody> BODY_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
Codec.BOOL.fieldOf("val1").forGetter(ExampleDialogBody::val1),
Codec.INT.fieldOf("val2").forGetter(ExampleDialogBody::val2)
).apply(ExampleDialogBody::new));
@Override
public MapCodec<? extends DialogBody> mapCodec() {
return BODY_CODEC;
}
}
// Register the codec to the registry
Registry.register(BuiltInRegistries.DIALOG_BODY_TYPE, "examplemod:example_body", ExampleDialogBody.BODY_CODEC);
// For some dialog
{
// ...
"body": [
{
// Our body
"type": "examplemod:example_body",
"val1": true,
"val2": 0
},
// ...
]
}
How does this body actually render then? Well, that is done via a DialogBodyHandler. This contains a single method createControls that generates the LayoutElement to render given the DialogScreen and the dialog data. This body handler can be linked to the MapCodec via DialogBodyHandlers#register.
public class ExampleDialogBodyHandler implements DialogBodyHandler<ExampleDialogBody> {
@Override
public LayoutElement createControls(DialogScreen<?> screen, ExampleDialogBody body) {
// Create the element (widgets, layouts, etc.)
return new StringWidget(...);
}
}
// Note that `register` is not public, so this needs to be access widened
DialogBodyHandlers.register(BODY_CODEC, new ExampleDialogBodyHandler());
Custom Inputs
An InputControl represents some input a user can provide, whether that would be some text or a button submission click. This is generally made up of components that can accept or provide some string value or tag based on a state. All dialogs can provide these inputs; through the DialogControlSet. It only contains one method mapCodec, which is used as the registry key and encoder for the input control.
public record ExampleInputControl(int value) implements InputControl {
public static final MapCodec<ExampleInputControl> INPUT_CODEC = Codec.INT.fieldOf("value").xmap(
ExampleInputControl::new, ExampleInputControl::value
);
@Override
public MapCodec<? extends InputControl> mapCodec() {
return INPUT_CODEC;
}
}
// Register the codec to the registry
Registry.register(BuiltInRegistries.INPUT_CONTROL_TYPE, "examplemod:example_input", ExampleInputControl.INPUT_CODEC);
// For some dialog (assume `minecraft:simple_input_form`)
{
"inputs": [
{
// Our input
"type": "examplemod:example_input",
// The identifier for the data of this input
"key": "example_input",
"value": 0
},
// ...
]
}
Like above, the input is rendered via a InputControlHandler. This contains a single method addControl, which provides the Screen and input control and creates the LayoutElement and its associated Action$ValueGetter via $Output. This input handler can be linked to the MapCodec via InputControlHandlers#register.
public class ExampleInputControlHandler implements InputControlHandler<ExampleInputControl> {
@Override
public void addControl(ExampleInputControl control, Screen screen, InputControlHandler.Output output) {
EditBox box = new EditBox(...);
box.setValue(String.valueOf(control.value()));
// Add the elements to the output
output.accept(
// The element to render
box,
// The value output of the input
Action.ValueGetter.of(box::getValue)
);
}
}
// Note that `register` is not public, so this needs to be access widened
InputControlHandlers.register(INPUT_CODEC, new ExampleInputControlHandler());
Custom Actions
As shown above, an input can provide some value to pass to an Action. The former is known as a $ValueGetter, which essentially gets a stringified or tagged input to use. The latter, meanwhile, ends up creating the ClickEvent that is sent to the server. These are typically created through ActionButtons which defines some common button data along with the Action to perform.
A custom action contains two methods: one which returns the MapCodec (codec) to use during encoding, while the other creates the ClickEvent based on the map of input strings to their $ValueGetters.
public record ExampleAction() implements Action {
public static final MapCodec<ExampleAction> ACTION_CODEC = MapCodec.unit(new ExampleAction());
@Override
public MapCodec<? extends Action> codec() {
return ACTION_CODEC;
}
@Override
public Optional<ClickEvent> createAction(Map<String, Action.ValueGetter> keysToGetters) {
// Handle how you want to map the key input map to some click event
return Optional.empty();
}
}
// Register the codec to the registry
Registry.register(BuiltInRegistries.DIALOG_ACTION_TYPE, "examplemod:example_action", ExampleAction.ACTION_CODEC);
// For some dialog (assume `minecraft:notice`)
{
"action": {
// Button data
"label": "Example!",
"tooltip": "This is an example!",
"width": 80,
// The action to perform
"action": {
// Out action type
"type": "examplemod:example_action"
}
}
}
Depending on how you implement your Dialog below, the action button will automatically be added to the screen, or you will need to add it in one of the methods via DialogControlSet#createActionButton:
// For some DialogScreen implementation, we will assume some `SimpleDialog`
@Override
protected void updateHeaderAndFooter(HeaderAndFooterLayout layout, DialogControlSet controls, SimpleDialog dialog, DialogConnectionAccess access) {
dialog.mainActions().forEach(actionButton -> layout.addToFooter(controls.createActionButton(actionButton).build()));
}
Custom Dialogs
A Dialog is pretty much all of the above components put together as desired. It is up to the user to choose how to implement them. Every Dialog must provide its CommonDialogData, which defines the basic title, body contents, and functionality. In additional, a Dialog may choose to execute an Action on close via onCancel.
// `common` is already implemented by the record
public record ExampleDialog(CommonDialogData common, boolean val1, int val2) implements Dialog {
public static final MapCodec<ExampleDialog> DIALOG_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
CommonDialogData.MAP_CODEC.forGetter(ExampleDialog::common),
Codec.BOOL.fieldOf("val1").forGetter(ExampleDialog::val1),
Codec.INT.fieldOf("val2").forGetter(ExampleDialog::val2)
).apply(ExampleDialog::new));
@Override
public MapCodec<? extends Dialog> codec() {
return DIALOG_CODEC;
}
@Override
public Optional<Action> onCancel() {
// You can choose to return something here, or empty if nothing should be done
return Optional.empty();
}
}
// Register the codec to the registry
Registry.register(BuiltInRegistries.DIALOG_TYPE, "examplemod:example_dialog", ExampleDialog.DIALOG_CODEC);
// For some dialog in `data/examplemod/dialog/example.json`
{
// Our dialog type
"type": "examplemod:example_dialog",
// Common button data
"title": "Example dialog!",
"can_close_with_escape": true,
"after_action": "wait_for_response",
// Our custom params
"val1": true,
"val2": 0
}
Like the others, a dialog type can only be rendered through a DialogScreen$Factory. This interface constructs a DialogScreen given the parent Screen, Dialog instance, and DialogConnectionAccess used to communicate to the server. This dialog screen can then be linked to the MapCodec via DialogScreens#register.
public class ExampleDialogScreen extends DialogScreen<ExampleDialog> {
public ExampleDialogScreen(@Nullable Screen previousScreen, ExampleDialog dialog, DialogConnectionAccess connectionAccess) {
super(previousScreen, dialog, connectionAccess);
}
// You can choose to implement the other methods as you wish
// See existing dialog screens for an example
@Override
protected void populateBodyElements(LinearLayout layout, DialogControlSet controls, ExampleDialog dialog, DialogConnectionAccess access) {
// Add elements and actions to the body of the screen (usually the center)
}
@Override
protected void updateHeaderAndFooter(HeaderAndFooterLayout layout, DialogControlSet controls, ExampleDialog dialog, DialogConnectionAccess access) {
// Add elements and actions to the header and footer of the screen (top and bottom)
}
}
// Note that `register` is not public, so this needs to be access widened
DialogScreens.register(DIALOG_CODEC, ExampleDialogScreen::new);
com.mojang.blaze3d.vertex.VertexConsumer#addVertexWith2DPose- Adds a vertex to be rendered in 2d space.net.minecraft.client.guiFontdrawInBatchno longer returns anythingprepareText- Prepares the text to be rendered to the screen.splitIgnoringLanguage- Splits the text in the order provided without being processed by the language handler.ALPHA_CUTOFFis removed$GlyphVisitor- An interface that handles a glyph or effect to be rendered.$PreparedText- An interface that defines how a piece of text should be rendered by visiting each glyph.$StringRenderOutput->$PreparedTextBuilder, no longer takes in theMultiBufferSource,Matrix4f,$DisplayMode, packed light coords, and the inverse depth boolean
GuishouldRenderDebugCrosshair- Returns true if the debug crosshair should be rendered.$RenderFunction- An interface that defines how a certain section or element is rendered on the gui.
GuiGraphicsnow takes in aGuiRenderStateinstead of theMultiBufferSource$BufferSourceMAX_GUI_Z,MIN_GUI_Zare removedposenow returns aMatrix3x2fStackflushis removednextStratum- Adds another layer to traverse through that renders after all nodes in the previous tree.- All methods no longer take in a
RenderType,VertexConsumer, orFunction<ResourceLocation, RenderType>, instead specifying aRenderPipelineand aTextureSetupdepending on the call drawString,drawStringWithBackdropno longer returns anythingdraw*Stringmethods must now pass in an ARGB value, where A cannot be 0.renderItem(ItemStack, int, int, int, int)is removeddrawSpecialis removed, replaced by individualsubmit*RenderStatedepending on the special caseblurBeforeThisStratum- Notifies the render state that a blur effect should render between this strata and all previously rendered ones. This can only be applied between once per frame.render*Tooltip->set*TooltipForNextFrame, does not directly add to the render state, instead waiting forrenderDeferredTooltipto be called when not present or overriddenrenderDeferredTooltip- Adds the tooltip information to be rendered on a new stratum.blitSpritenow has an overload that takes in a float R tint color$ScissorStack#peek- Gets the last rectangle on the stack.
LayeredDrawclass is removed
net.minecraft.client.gui.componentsAbstractTextAreaWidgetnow has an overload which takes in two additional booleans of whether to show the background or decorationsAbstractWidget#getTooltipis removedCycleButton$Builder#displayOnlyValuenow has an overload that takes in thebooleanto setEditBoxsetCentered- Sets whether the text position should be centered.setTextShadow- Sets whether the text should have a drop shadow effect.
FocusableTextWidgetcan now take in a boolean indicating whether to fill the backgroundDEFAULT_PADDINGis now public
ImageWidget#updateResource- Updates the sprite of the image on the component.ItemDisplayWidget- A widget that displays anItemStack.LogoRenderer#keepLogoThroughFade- When true, keeps the logo visible even when the title screen is fading.MultiLineEditBoxis now package private and should be constructed viabuilder, calling the$Builder#set*methodssetLineLimit- Sets the line limit of the text field.setValuenow has an overload that takes in thebooleanto determine whether it should force pass the max line limit
MultiLineLabelgetStyleAtCentered- Computes the component style for centered text.getStyleAtLeftAligned- Computes the component style for left aligned text.
MultilineTextField#NO_CHARACTER_LIMIT->NO_LIMITsetLineLimit- Sets the maximum number of lines that can be written on the text field.hasLineLimit- Returns whether the text field has some line limit.setValuenow has an overload that takes in thebooleanto determine whether it should force pass the max line limit
MultiLineTextWidget#configureStyleHandling- Sets whether something is displayed when hovering over components and what to do on click.ScrollableLayout- A layout with some defined bounds that can be scrolled through.SplashRenderer#rendernow takes in a float for the R color instead of an intWidgetTooltipHolder#refreshTooltipForNextRenderPassnow takes in theGuiGraphicsand the XY position
net.minecraft.client.gui.components.spectator.SpectatorGui#renderTooltip->renderActionnet.minecraft.client.gui.components.tabsLoadingTab- A tab that indicates information is currently being loaded.Tab#getTabExtraNarration- Returns the hint narration of the tab.TabManagercan now take in twoConsumers on what to do when a tab is selected or deselectedTabNavigationBargetTabs- Returns the list of tabs on the navigation bar.setTabActiveState- Sets the active state of the given tab index.setTabTooltip- Sets the tooltip information of the given tab index.
net.minecraft.client.gui.components.toastsNowPlayingToast- A toast that displays the currently playing background music.ToastxPos,yPos- Gets the x and y position in relation to the current toast index.onFinishedRendering- A method called once the toast has finished rendered on screen.
ToastManagernow takes in theOptionsshowNowPlayingToast,hideNowPlayingToast,createNowPlayingToast,removeNowPlayingToast- Handles the ‘Now Playing’ music toast.$ToastInstance#resetToast- Resets the toast.
net.minecraft.client.gui.contextualbarContextualBarRenderer- An interface which defines an object with some background to render.ExperienceBarRenderer- Draws the experience bar.JumpableVehicleBarRenderer- Draws the jump power bar (e.g. horse jumping).LocatorBarRenderer- Draws the bar that points to given waypoints.
net.minecraft.client.gui.font.GlyphRenderTypesnow takes in aRenderPipelinefor the gui renderingnet.minecraft.client.gui.font.glyphs.BakedGlyphnow takes in aGpuTextureViewextractEffect- Extracts a glyph effect (e.g. drop shadow) submits the element to be rendered.extractBackground- Extracts a glyph effect and submits the element to be rendered on the background Z.left,top,right,bottom- Computes the bounds of the glyph.textureView- Returns the view of the texture making up the glyph.guiPipeline- Returns the pipeline to render the glyph.renderChar,renderEffectnow takes in an additional boolean that sets the Z offset to0when true and0.001when false$Effect#left,top,right,bottom- Computes the bounds of the glyph effect.$GlyphInstance#left,top,right,bottom- Computes the bounds of the glyph instance.
net.minecraft.client.gui.navigation.ScreenRectangletransformAxisAlignednow takes in aMatrix3x2finstead of aMatrix4fintersects- Returns whether this rectangle overlaps with another rectangle.encompasses- Returns whether this rectangle contains the entirety of another rectangle.transformMaxBounds- Returns a new rectangle that is moved into a given position by the provided matrix.
net.minecraft.client.gui.renderGuiRenderer- A class that renders all submitted elements to the screen.TextureSetup- A record that specifies samplers 0-2 for use in a render pipeline. The first two textures views are arbitrary with the third being for the current lightmap texture.
net.minecraft.client.gui.render.pipGuiBannerResultRenderer- A renderer for the banner result preview.GuiBookModelRenderer- A renderer for the book model in the enchantment screen.GuiEntityRenderer- A renderer for a given entity.GuiProfilerChartRenderer- A renderer for the profiler chart.GuiSignRenderer- A renderer for the sign background in the edit screen.GuiSkinRenderer- A renderer for a player with a given skin.OversizedItemRenderer- A rendered for when an item model should be rendered larger than its item slot.PictureInPictureRenderer- An abstract class meant for rendering dynamic elements that are not standard 2d elements, items, or text.
net.minecraft.client.gui.render.stateBlitRenderState- An element state for a basic 2d texture blit.ColoredRectangleRenderState- An element state for a simple rectangle with a tint.GlyphEffectRenderState- An element state for a glyph effect (e.g., font text drop shadow).GlyphRenderState- An element state for a glyph (font text).GuiElementRenderState- An interface representing the state of a element to render.GuiItemRenderState- A record representing the state of an item to render.GuiRenderState- The state of the GUI to render to the screen.GuiTextRenderState- A record representing the state of the text and its location to render.ScreenArea- An interface which defines the render area of an element. This does not affect scissoring, instead layer orders.
net.minecraft.client.gui.render.state.pipGuiBannerResultRenderState- The state of the banner result preview.GuiBookModelRenderState- The state of the book model in the enchantment screen.GuiEntityRenderState- The state of a given entity.GuiProfilerChartRenderState- The state of the profiler chart.GuiSignRenderState- The state of the sign background in the edit screen.GuiSkinRenderState- The state of a player with a given skin.OversizedItemRenderState- The state of an item model that can be rendered at an arbitrary size.PictureInPictureRenderState- An interfaces that defines the basic state necessary to render the picture-in-picture to the screen.
net.minecraft.client.gui.screensConfirmScreenlayout- Defines a vertical list of elements spaced by eight units.yesButton,noButton->yesButtonComponent,noButtonComponentyesButton,noButtonnow represent the actual buttons
addAdditionalText- Adds any additional text before the buttons in the layout.addButtons- Adds the buttons in the layout.
PauseScreenrendersNowPlayingToast- Returns whether the ‘Now Playing’ toast should be rendered.onDisconnect->disconnectFromWorld, now public and static; not one-to-one
ScreenCUBE_MAP->net.minecraft.client.renderer.GameRenderer#cubeMapPANORAMA->net.minecraft.client.renderer.GameRenderer#panoramarenderBlurredBackgroundnow takes in theGuiGraphics*TooltipForNextRenderPassmethods are either removed or moved toGuiGraphicsFADE_IN_TIME- Represents how much time in milliseconds does it take for some element to fade in.fadeWidgets- Sets the alpha of theAbstractWidgets added as children to the screen.handleClickEvent- Handles the event to play when the component is clicked.defaultHandleClickEvent- The default logic to execute when the component is clicked.clickUrlAction- The logic to perform when a URL is clicked (has the Open URL style).clickCommandAction- The logic to perform when a command should be executed (has the * Command style).
net.minecraft.client.gui.screens.dialogButtonListDialogScreen- A dialog screen that contains some list of buttons.DialogConnectionAccess- A client side interface that processes general interaction information from the dialog.DialogControlSet- An input handler for a dialog screen.DialogListDialogScreen- A button list ofDialogListDialogs.DialogScreen- A screen for some dialog modal.DialogScreens- A factory registry of dialog modals to their associated screen.MultiButtonDialogScreen- A button list ofMultiActionDialogs.ServerLinksDialogScreen- A button list ofServerLinksDialogs.SimpleDialogScreen- A dialog screen for some simple dialog.WaitingForResponseScreen- A screen that handles the downtime between client/server communication of dialog submissions.
net.minecraft.client.gui.screens.dialog.bodyDialogBodyHandler- A list of body elements describing the contents between the title and actions/inputs.DialogBodyHandlers- A registry ofDialogBodys to theirDialogBodyHandlers.
net.minecraft.client.gui.screens.dialog.inputInputControlHandler- A user input handler.InputControlHandlers- A registry ofInputControls to theirInputControlHandlers.
net.minecraft.client.gui.screens.inventoryAbstractContainerScreenSLOT_ITEM_BLIT_OFFSETis removedrenderContents- Renders the slot and labels of an inventory.renderCarriedItem- Renders the held item.renderSnapbackItem- Renders the swapped item with the held item.$SnapbackData- Holds the information about the dragging or swapped item as it moves from the held location to its slot location.
AbstractSignEditScreen#offsetSign->getSignYOffset, not one-to-oneBookEditScreenTEXT_*,IMAGE_*,BACKGROUND_TEXTURE_*are now public
BookSignScreen- A screen for signing a book.BookViewScreencloseScreen->closeContainerOnServer, not one-to-one$BookAccess#getPagenow returns aComponent
EffectsInInventoryrenderEffectsis now publicrenderTooltiphas been overloaded to a public method
InventoryScreen#renderEntityInInventoryno longer takes in the XY offset, instead taking in 4ints to represent the region to render toItemCombinerScreen#renderFgis removed
net.minecraft.client.gui.screens.inventory.tooltipClientTooltipComponent#renderTextno longer takes in the pose and buffer, instead theGuiGraphicsto submit the text for renderingTooltipRenderUtil#renderTooltipBackgroundno longer takes in a Z offset
net.minecraft.client.gui.screens.multiplayer.ServerLinksScreenclass is removed, replaced by dialog modalnet.minecraft.client.gui.screens.socialPlayerEntry#refreshHasDraftReport- Sets whether the current context as a report for this player.SocialInteractionsPlayerList#refreshHasDraftReport- Refreshes whether the current context as a report for all players.
net.minecraft.client.gui.screens.worldselection.ExperimentsScreen$ScrollAreaclass is removed, replaced by theScrollableLayoutnet.minecraft.client.model.geom.ModelPart#getExtentsForGui- Gets the set of vectors representing the part transformed into their appropriate space.net.minecraft.client.multiplayer.ClientCommonPacketListenerImplshowDialog- Shows the current dialog, creating the screen dynamically.serverLinks- Returns the entries of server links the client can access.createDialogAccess- Creates the dialog handler on the client used for communication.clearDialog- Closes the current dialog screen.
net.minecraft.client.player.LocalPlayer#experienceDisplayStartTick- Represents the start tick of when the experience display should be prioritized.net.minecraft.client.rendererGameRendererno longer takes in aResourceManagerITEM_ACTIVATION_ANIMATION_LENGTHis removedsetRenderHandis removedrenderZoomedis removedgetPanorama- Returns the panorama renderer.
LightTexture#getTexture->getTextureView, not one-to-oneMapRenderer#WIDTH,HEIGHTare now publicPanoramaRenderer#registerTextures- Registers the texture for use by the cube map.PostPass$Input#texturenow returns aGpuTextureViewinstead of aGpuTextureRenderPipelinesGUI_OVERLAY,GUI_GHOST_RECIPE_OVERLAY,GUI_TEXTURED_OVERLAYare removedGUI_TEXTURED_PREMULTIPLIED_ALPHA- A pipeline that assumes the textures have already had their transparency premultiplied during the composite stage.
RenderStateShard$Builder#addno longer takes in whether the shard should be blurred$TextureStateShardno longer takes in aTriStateto set the blur mode
RenderTypedebugLineis removedgui,guiOverlay,guiTexturedOverlay,guiOpaqueTexturedBackground,guiNauseaOverlay,guiTextHighlight,guiGhostRecipeOverlay,guiTexturedare removedvignetteis removedcrosshairis removedmojangLogois removed
ScreenEffectRendereris now an instance implementation instead of simply a static method- The constructor takes in the current
Minecraftinstance and aMultiBufferSource renderScreenEffectis now an instance method, taking in whether the entity is sleeping and the partial tickresetItemActivation,displayItemActivation- Handles when an item is automatically activated (e.g., totem).
- The constructor takes in the current
net.minecraft.client.renderer.blockentity*Renderer#getExtents- Adds the transformed vectors representing all models to a set.HangingSignRendererMODEL_RENDER_SCALEis now publictranslateBaseis now public
SignRendererRENDER_SCALEis now publicapplyInHandTransforms- Transforms the stack to properly represent the held sign’s position.
SkullBlockRenderer#getRenderType(SkullBlock$Type, ResolvableProfile, ResourceLocation)->getSkullRenderType,getPlayerSkinRenderType; not one-to-one
net.minecraft.client.renderer.entity.ItemRendererGUI_SLOT_CENTER_X,GUI_SLOT_CENTER_Y,ITEM_DECORATION_BLIT_OFFSETare removedCOMPASS_*->SPECIAL_*
net.minecraft.client.renderer.itemClientItem$Properties#oversizedInGui- When true, allows an item to render outside the 16x16 box in a GUI; otherwise, clips the size to the box.ItemStackRenderStatesetAnimated,isAnimated- Returns whether the item is animated (e.g., foil).appendModelIdentityElement,getModelIdentity,clearModelIdentity- Handles the identity component being rendered.getModelBoundingBox- Computes the bounding box of the model.setOversizedInGui,isOversizedInGui- Handles when the item can be oversized in the GUI based on its property.
net.minecraft.client.renderer.specialPlayerHeadSpecialRenderer- Renders an player head based on its render info.SkullSpecialRenderernow implementsNoDataSpecialModelRenderer, no longer taking in the model or texture override, instead just theRenderTypeto useSpecialModelRenderer#getExtents- Adds the transformed vectors representing all models used by this renderer to a set.
net.minecraft.client.renderer.texture.TextureAtlasSprite#isAnimated- Returns whether the sprite has any animation.net.minecraft.commands.arguments.ResourceOrIdArgument#dialog,getDialog,$DialogArgument- Handles command arguments for dialog screens.net.minecraft.core.registriesBuiltInRegistries#DIALOG_TYPE,DIALOG_ACTION_TYPE,INPUT_CONTROL_TYPE,DIALOG_BODY_TYPERegistries#DIALOG_TYPE,DIALOG_ACTION_TYPE,INPUT_CONTROL_TYPE,DIALOG_BODY_TYPE,DIALOG
net.minecraft.data.tags.DialogTagsProvider- A tags provider for dialogs.net.minecraft.network.chatClientEvent$Action#SHOW_DIALOG,CUSTOMvalueCodec- Returns the map codec used to encode this action.
$Custom- An event that contains some nbt payload to send to the server, currently does nothing.$ShowDialog- An event that shows the specified dialog.
CommonComponentsGUI_RETURN_TO_MENU- The component that displays the ‘Return to Menu’ text.disconnectButtonLabel- Returns the component based on whether the server is local.
net.minecraft.network.protocol.commonClientboundClearDialogPacket- Closes the current dialog screen.ClientboundShowDialogPacket- Opens a new dialog screen.ServerboundCustomClickActionPacket- Sends a custom action to the server.
net.minecraft.server.dialogActionButton- A button that can perform someActionon click.ButtonListDialog- A dialog modal that has some number of columns to click buttons of.CommonButtonData- The data that is associated with every button within a dialog modal.CommonDialogData- The data that is associated with every dialog modal.ConfirmationDialog- A dialog modal whether you can either click yes or no.Dialog- The base interface that defines some dialog modal.DialogAction- The action to perform typically after some action button is clicked.DialogListDialog- A scrollable list of buttons that lead to other dialogs.Dialogs- A datapack bootstrap registeringDialogs.DialogTypes- A registry of map codecs to encode some dialog model.Input- A handler that maps some key to anInputControl.MultiActionDialog- A scrollable list of actions arrange in columns.NoticeDialog- A simple screen with one action in the footer.ServerLinksDialog- A scrollable list of links received from the server, arrange in columns.SimpleDialog- A dialog that defines the main actions that can be taken.
net.minecraft.server.dialog.actionAction- A general operation to perform on some input, usually a button click.ActionTypes- A registry of map codecs to encode some action.CustomTemplate- Builds a command and requests the server to run it.CustomAll- Builds a custom server click action from all inputs and requests the server to run it.ParsedTemplate- A template that encodes some string similar to how function macros work.StaticAction- An action that fires aClickEventon activation.
net.minecraft.server.dialog.bodyDialogBody- A body element describing the content between the title and actions/inputs.DialogBodyTypes- A registry of map codecs to encode some body.ItemBody- An item with an optional description.PlainMessage- A multiline label.
net.minecraft.server.dialog.inputBooleanInput- A plain checkbox with a label.InputControl- A control mechanism to accept user input.InputControlTypes- A registry of map codecs to encode some input control.NumberRangeInput- A slider for picking a numeric value from some range.SingleOptionInput- A button that cycles between a set of options.TextInput- Simple text input.
net.minecraft.world.entity.player.Player#openDialog- Opens the specified dialog screen.
Waypoints
Waypoints are simply a method to track the position of some object in the game. The underlying system is handled by the WaypointManager, responsible for holding the waypoints it is tracking while also allowing updates and removals as necessary. The server handles waypoints through the ServerWaypointManager (obtained via ServerLevel#getWaypointManager), which holds an active connect to the transmitter to receive live updates. The client receives these waypoints via the ClientWaypointManager (obtained via ClientPacketListener#getWaypointManager), which simply holds some identifier along with an exact position, a chunk if the position is not within the view distance, or an angle if the distance is further than the stored Waypoint$Fade#farDist, which is over 332 blocks away by default.
Entities track waypoints by default.
Styles and Icons
Every waypoint is represents by an icon of some kind, which is defined by its WaypointStyle and the color of the icon. A WaypointStyle is similar to a client item or a equipment model, where it has some key pointed to by a WaypointStyleAsset that’s located in assets/<modid>/waypoint_style/<path>.json. This contains a list of sprites located within assets/<modid>/textures/gui/sprites/hud/locator_bar_dot/<path>.png which is chosen based upon the distance from the tracker. The sprites change between the range specified by the near and far distance.
// For some style examplemod:example_style
// It will be found in `assets/examplemod/waypoint_style/example_style.json`
{
// Represents that any value closer will use the first sprite when rendering the bar
// Defaults to 128 when not specified
"near_distance": 100,
// Represents that any value further will use the last sprite when rendering the bar
// Defaults to 332 when not specified
// Must be greater than near distance
"far_distance": 400,
// A non-empty list of textures relative to `assets/<modid>/textures/gui/sprites/hud/locator_bar_dot/<path>.png`
// This is what's used to lerp between the two distances
"sprites": [
// Points to `assets/examplemod/textures/gui/sprites/hud/locator_bar_dot/example_style_0.png`
"examplemod:example_style_0",
"examplemod:example_style_1",
"examplemod:example_style_2"
]
}
The icon can then be constructed using its constructor and referenced via WaypointTransmitter#waypointIcon or TrackedWaypoint#icon on the server or client, respectively.
// We will assume that this constructor is made public for a more dynamic usage
// Currently, it can only be set on a `LivingEntity` through its `CompoundTag` via `locator_bar_icon`
public static Waypoint.Icon EXAMPLE_ICON = new Waypoint.Icon(
// The registry key of the waypoint style
// Points to `assets/examplemod/waypoint_style/example_style.json`
ResourceKey.create(WaypointStyleAssets.ROOT_ID, ResourceLocation.fromNamespaceAndPath("examplemod", "example_style")),
// The color of the waypoint
// When not present, uses the hashcode of the waypoint identifier
Optional.of(0xFFFFFF)
);
Connections
Waypoints, when tracked, are managed through their connections via WaypointTransmitter$Connection. A connection is responsible for syncing information to the client, whether connecting, disconnecting, or updating.
public class ExampleBlockConnection implements WaypointTransmitter.Connection {
private final BlockState state;
private final BlockPos pos;
private final Waypoint.Icon icon;
private final ServerPlayer receiver;
public ExampleBlockConnection(BlockState state, BlockPos pos, Waypoint.Icon icon, ServerPlayer receiver) {
this.state = state;
this.pos = pos;
this.icon = icon;
this.recevier = receiver;
}
public static boolean doesSourceIgnoreReceiver(BlockPos pos, ServerPlayer player) {
double receiveRange = player.getAttributeValue(Attributes.WAYPOINT_RECEIVE_RANGE);
return pos.distSqr(player.blockPosition()) >= receiveRange * receiveRange;
}
@Override
public boolean isBroken() {
// When true, it will attempt to remake the connection to this transmitter
// This is only called when updating the position
return ExampleBlockConnection.doesSourceIgnoreReceiver(this.pos, this.receiver);
}
@Override
public void connect() {
// This sends the tracking packet to the client
this.receiver.connection.send(ClientboundTrackedWaypointPacket.addWaypointPosition(this.state.toString() + ": " + this.pos.toString(), this.icon, this.pos));
}
@Override
public void disconnect() {
// This sends the removal packet to the client
this.receiver.connection.send(ClientboundTrackedWaypointPacket.removeWaypoint(this.state.toString() + ": " + this.pos.toString()));
}
@Override
public void update() {
// This updates the tracked value on the client assuming that the connect has not broken
// In our case, we can assume this never changes as the position of a block should remain consistent
}
}
Transmitters
A WaypointTransmitter is responsible for constructing the connection between it and the server. For your object to transmit a location, it must implement WaypointTransmitter and its three methods. waypointIcon simply returns the icon to display. isTransmittingWaypoint will determine whether the waypoint can be transmitted from this object. makeWaypointConnectionWith actually handles constructing the connection used to track the position or angle of the connection.
public class ExampleWaypointBlock extends BlockEntity implements WaypointTransmitter {
// ...
@Override
public boolean isTransmittingWaypoint() {
// This should return false if no connection should be made
return true;
}
@Override
public Optional<WaypointTransmitter.Connection> makeWaypointConnectionWith(ServerPlayer player) {
// Make a connection if nothing is ignored
return ExampleBlockConnection.doesSourceIgnoreReceiver(this.getBlockPos(), player)
? Optional.empty()
: Optional.of(new ExampleBlockConnection(this.getBlockState(), this.getBlockPos(), this.waypointIcon(), player));
}
@Override
public Waypoint.Icon waypointIcon() {
return EXAMPLE_ICON;
}
}
Then, all you need to do is track, update, or untrack the transmitter as necessary. This can be done using the methods provided by ServerWaypointManager:
// We will assume we have access to:
// - ServerLevel serverLevel
// - ExampleWaypointBlock be
// Tracking the waypoint, such as on some initialization
serverLevel.getWaypointManager().trackWaypoint(be);
// Update the waypoint if the position changes
serverLevel.getWaypointManager().updateWaypoint(be);
// Remove the waypoint once it no longer exists
serverLevel.getWaypointManager().untrackWaypoint(be);
net.minecraft.clientCameranow implementsTrackedWaypoint$CameraMinecraft#getWaypointStyles- Returns a manager of keys to the style of a waypoint.
net.minecraft.client.data.models.WaypointStyleProvider- A data provider that generates waypoint styles.net.minecraft.client.multiplayer.ClientPacketListener#getWaypointManager- Gets the client manager used for tracking waypoints.net.minecraft.client.renderer.GameRenderernow implementsTrackedWaypoint$Projectornet.minecraft.client.resourcesWaypointStyle- Defines the style used to render a waypoint.WaypointStyleManager- The manager that maps some key to the style of a waypoint.
net.minecraft.client.waypoints.ClientWaypointManager- A client-side manager for tracked waypoints.net.minecraft.commands.arguments.WaypointArgument- A static method holder that gets some waypoint transmitter from an entity.net.minecraft.network.protocol.gameClientboundTrackedWaypointPacket- A packet that sends some operation for a waypoint to the client.ClientGamePacketListener#handleWaypoint- Handles the waypoint packet on the client.
net.minecraft.server.ServerScoreboard$Methodenum is removednet.minecraft.server.level.ServerLevel#getWaypointManager- Gets the server manager used for tracking waypoints.net.minecraft.server.level.ServerPlayer#isReceivingWaypoints- Whether the player is receiving waypoints from other locations or entities.net.minecraft.server.waypoints.ServerWaypointManager- A server-side manager for tracked waypoints (e.g., players and transmitters).net.minecraft.world.entityEntity#getRequiresPrecisePosition,setRequiresPrecisePosition- Handles when a more precise position is needed for tracking.LivingEntitynow implementsWaypointTransmitter
net.minecraft.world.waypointsTrackedWaypoint- A waypoint that is identified by some UUID or string, displayed via aWaypoint$Icon, and specified via$Type.TrackedWaypointManager- A waypoint manager forTrackedWaypoints.Waypoint- An interface that represents some positional location. This holds no information, and is typically used in the context ofTrackedWaypoint.WaypointManager- An interface that tracks and updates waypoints.WaypointStyleAsset- A class that indicates a style asset.WaypointStyleAssets- A class that defines all vanilla style assets.WaypointTransmitter- An object that transmits some position that can be connected to and tracked.
Blaze3d Changes
Just like the previous update Blaze3d has new redesigns that change how rendering is handled.
Buffer Slices
The most important change within the rendering system is the use of GpuBufferSlices. As the name implies, it simply takes some slice of a GpuBuffer, using an offset to indicate the starting index, and the length to indicate its size. When dealing with anything rendering related, even when passing to a shader, you will almost always be dealing with a GpuBufferSlice. A way to think about it is that the buffer is just some arbitrary list of object where a slice represents a specific object.
To create a slice, simply call GpuBuffer#slice, optionally providing the starting index and length. In most instances, you will not be calling this method directly, instead dealing with other methods that call it for you. Note that as you are generally writing data to these slices, they should be constructed before a try-with-resources RenderPass is created.
Uniform Rework
The uniform system has been completely overhauled such that, unless you are familiar with specific features, it might seem completely foreign. In a nutshell, uniforms are now stored as either interface objects, a texel buffer, or a sampler. These are populated either by GpuBuffers or GpuBufferSlices.
Uniform Types
A uniform is currently represented as one of two UniformTypes: either as an UNIFORM_BUFFER/interface block, or a TEXEL_BUFFER. When setting up a pipeline and calling withUniform, you must specify your uniform with one of the above types. If you choose to use a texel buffer, you must also specify the format of the texture data. Samplers have not changed.
public static final RenderPipeline EXAMPLE_PIPELINE = RenderPipeline.builder(...)
// Uses a uniform interface block called 'ExampleUniform'
.withUniform("ExampleUniform", UniformType.UNIFORM_BUFFER)
// Uses a buffer called 'ExampleTexel' that stores texture data as a 8-bit R value
.withUniform("ExampleTexel", UniformType.TEXEL_BUFFER, TextureFormat.RED8I)
// Perform other setups
.build();
Interface Blocks
A UNIFORM_BUFFER is stored as a std140 interface block. In GLSL, this is represented like so:
// In assets/examplemod/shaders/core/example_shader.json
// ExampleUniform is the name of the block
layout(std140) uniform ExampleUniform {
// The data within the block
// Post Effects can only use int, float, vec2, vec3, ivec3, vec4, or mat4
vec4 Param1;
float Param2;
};
The values can be used freely inside the main block like so:
// In assets/examplemod/shaders/core/example_shader.json
out vec4 fragColor;
void main() {
fragColor = Param1;
}
The uniform block can either be inside the same file as the main function or, if it will be reused, as a moj_import, where the uniform file is within assets/<modid>/shaders/include/<path>. Note that any shaders used before resource packs are loaded cannot use moj_import.
Post Effects define their interface blocks in the uniform input:
// In assets/examplemod/post_effect/example_post_effect.json
// Inside a 'passes' object
{
"vertex_shader": "...",
// ...
"uniforms": {
// The name of the interface block
"ExampleUniform": [
// A parameter within the uniform block
// See `UniformValue` for codec formats
{
// The name of the parameter
"name": "Param1",
// The parameter type, one of:
// - int
// - ivec3
// - float
// - vec2
// - vec3
// - vec4
// - matrix4x4 (mat4)
"type": "vec4",
// The value stored in the uniform
// Dynamic values from the codebase are no longer supported
"value": [ 0.0, 0.0, 0.0, 0.0 ]
},
{
"name": "Param2",
"type": "float",
"value": 0
}
]
}
}
Texel Buffers
Texel buffers are typically represented as a isamplerBuffer to be queried from, typically using texelFetch:
// In assets/examplemod/shaders/core/example_shader.json
uniform isamplerBuffer ExampleTexel;
void main() {
// Read the documentation to understand how texel fetch works
texelFetch(ExampleTexel, gl_InstanceID);
}
Writing Custom Uniforms
Writing custom uniforms can only happen when you are the one responsible for creating the RenderPass. Like before, you create and cache the object before opening the RenderPass, then you set the uniform by calling RenderPass#withUniform. The only difference is that, instead of providing arbitrary objects, you must now either provide a GpuBuffer or GpuBufferSlice with the uniform data written to it. For a texel buffer, this is usually some encoded data in the desired texture format (such as a mesh). For an interface block, the easiest method is to use the Std140Builder to populate the buffer with the correct values.
There are many different methods of writing to a GpuBuffer or GpuBufferSlice, such as using the newly created MappableRingBuffer. It is up to you to figure out what method works best in your scenario. The following is simply one solution out of many.
// Buffer for 'ExampleUniform'
// Takes in the name of the buffer, its usage, and the size
private final MappableRingBuffer ubo = new MappableRingBuffer(
// Buffer name
() -> "Example UBO",
// Buffer Usage
// We set 128 as its used for a uniform and 2 since we are writing to it
// Other bits can be found as constants in `GpuBuffer`
GpuBuffer.USAGE_UNIFORM | GpuBuffer.USAGE_MAP_WRITE,
// The size of the buffer
// Easiest method is to use Std140SizeCalculator to properly calculate this
new Std140SizeCalculator()
// Param1
.putVec4()
// Param2
.putFloat()
.get()
);
// Buffer for 'ExampleTexel'
private final MappableRingBuffer utb = new MappableRingBuffer(
// Buffer name
() -> "Example UTB",
// We set 256 as its used for a texel buffer and 2 since we are writing to it
GpuBuffer.USAGE_UNIFORM_TEXEL_BUFFER | GpuBuffer.USAGE_MAP_WRITE,
// The size of the buffer
// It will likely be larger than this for you
3
);
// In some render method
// Populate the buffers as required
// As we are using a ring buffer, this simply uses the next available buffer in the list
this.ubo.rotate();
// Write the data to the buffer
try (GpuBuffer.MappedView view = RenderSystem.getDevice().createCommandEncoder().mapBuffer(this.ubo.currentBuffer(), false, true)) {
Std140Builder.intoBuffer(view.data())
.putVec4(0f, 0f, 0f, 0f)
.putFloat(0f);
}
// Similar thing here
this.utb.rotate();
try (GpuBuffer.MappedView view = RenderSystem.getDevice().createCommandEncoder().mapBuffer(this.utb.currentBuffer(), false, true)) {
view.data()
.put((byte) 0)
.put((byte) 0)
.put((byte) 0);
}
// Create the render pass and pass in the buffers as part of the uniform
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(...)) {
// ..
pass.setUniform("ExampleUniform", this.ubo.currentBuffer());
pass.setUniform("ExampleTexel", this.utb.currentBuffer());
// ...
}
Fog Environments
The fog system has been reworked into an environment/render state-like handler. Each environment mostly handles setting up the fog data and color. Some additional processing is provided for the individual FogTypes and special mob effects.
All environments are handled through the FogEnvironment. A environment is setup via the setupFog method, which is responsible for mutating the passed in FogData to the values associated with that environment. If the fog colors its surroundings, then providesColor should return true, with the base color tint applied in getBaseColor. Likewise, if the fog darkens its surroundings, then modifiesDarkness should return true, with the modified darkness returned via getModifiedDarkness. To determine whether an environment should apply, isApplicable is checked. If not applicable, then onNotApplicable is called.
All environments are registered to FogRenderer#FOG_ENVIRONMENTS; however, what environment to use is based on isApplicable and the list order. For the color and darkness, the fog environment chosen is the last one in the list where one of the provides* methods return true. For the actual fog setup, the fog environment chosen is the first one in the list.
Render Pass Scissoring now only OpenGL
The scissoring state has been removed from the generic pipeline code, now only accessible through the OpenGL implementation. Generic region handling has been delegated to CommandEncoder#clearColorAndDepthTextures. Note that this does not affect the existing ScreenRectangle system that handles the blit facing scissoring.
com.mojang.blaze3d.buffersBufferTypeenum is removedBufferUsageenum is removedGpuBuffernow takes two ints represent the size and usage, the type is no longer specifiedtypeis removedusagenow returns an intslice- Returns a record representing a slice of some buffer. The actual buffer is not modified in any way.$ReadView->$MappedView
GpuBufferSlice- A record that represents a slice of some buffer by holding a reference to the entire buffer, an offset index of the starting point, and the length of the slice.GpuFenceis now an interface, with its OpenGL implementation moved toblaze3d.opengl.GlFenceStd140Builder- A buffer inserter for an interface block laid out in thestd140format. This is used for the uniform blocks within shaders.Std140SizeCalculator- An object used for keeping track of the size of some interface block.
com.mojang.blaze3d.openglAbstractUniformis removed, replaced by theStd140*classesBufferStorage- A class that create buffers given its types. Its implementations define its general usage.DirectStateAccesscreateBuffer- Creates a buffer.bufferData- Initializes a buffer’s data store.bufferSubData- Updates a subset of a buffer’s data store.bufferStorage- Creates the data store of a buffer.mapBufferRange- Maps a section of a buffer’s data store.unmapBuffer- Relinguishes the mapping of a buffer and invalidates the pointer to its data store.
GlBuffernow takes in aDirectStateAccess, two ints, and aByteBufferinstead of aGlDebugLabeland itsBuffer*enumsinitializedis removedpersistentBuffer- Holds a reference to an immutable section of some buffer.$ReadView->$GlMappedView
GlCommandEncoderexecuteDrawMultiplenow takes in a collection of strings that defines the list of required uniforms and a generic indicating the object of the draw callexecuteDrawnow takes in twoint, the number of instances of the specified range of indices to be rendered and the base vertex
GlConst#toGlforBufferTypeandBufferUsage->bufferUsageToGlFlag,bufferUsageToGlEnumGlDebugLabel#pushDebugGroup,popDebugGroup- Profiler commands for grouping similar calls.GlDeviceUSE_GL_ARB_buffer_storage- Sets the extension flag forGL_ARB_buffer_storage.getBufferStorage- Returns the storage responsible for creating buffers.
GlProgramUniformfields have been removedsafeGetUniform,setDefaultUniformsare removedbindSampleris removedgetSamplerLocations,getSamplers,getUniforms->getUniformswhich returns a map of names to theirUniformobjects
GlRenderPassuniformsnow is aHashMap<String, GpuBufferSlice>dirtSamplersis removedsamplersmap now holds aGpuTextureViewvaluepushedDebugGroups- Returns the number of groups pushed onto the stack. No debug groups must be open for the render pass to be closed.isScissorEnabled- Returns whether the scissoring state is enabled which crops the area that is rendered to the screen.getScissorX,getScissorY,getScissorWidth,getScissorHeight- Returns the values representing the scissored rectangle.
GlTexturenow takes in an additional integer for the usage and depth/layersflushModeChangesnow takes in anintwhich represents the texture targetaddViews,removeViews- Manages the views looking at a texture for some mip levels.
GlTextureView- A view implementation of a texture for some mip levels.Uniformis now a sealed interface which is implemented as either a buffer object, texel buffer, or a sampler
com.mojang.blaze3d.pipelineBlendFunction#PANORAMAis removedCompiledRenderPipeline#containsUniformis removedRenderPipeline$Builder#withUniformnow has an overload that can take in aTextureFormat$UniformDescriptionnow takes in a nullableTextureFormat
RenderTargetcolorTextureView,depthTextureView,getColorTextureView,getDepthTextureView- A view of the current color and depth textures.blitAndBlendToTexturenow takes in aGpuTextureViewinstead of aGpuTexture
com.mojang.blaze3d.platform.Lightningis nowAutoCloseablesetup*->setupFor, an instance method that takes in an$EntryupdateLevel- Updates the lighting buffer, taking in whether to use the nether diffused lighting.
com.mojang.blaze3d.shadersFogShape->net.minecraft.client.renderer.fog.FogData, not one-to-oneUniformTypenow only holds two types:UNIFORM_BUFFER, orTEXEL_BUFFER, and no longer takes in a count
com.mojang.blaze3d.systemsCommandEncoderclearColorAndDepthTexturesnow has an overload that takes in fourints representing the region to clear the texture information withinwriteToBuffer,mapBuffer(GpuBuffer, int, int)now take in aGpuBufferSliceinstead of aGpuBuffercreateFence- Creates a new sync fence.createRenderPassnow takes in aSupplier<String>, used for determining the name of the pass to use as a debug group, andGpuTextureViews instead ofGpuTextureswriteToTexturenow takes in an additionalintrepresenting the depth or layer to write topresentTexturenow takes in aGpuTextureViewinstead of aGpuTexture
GpuDevicecreateBufferno longer takes in aBufferUsage, withBufferTypereplaced by anintgetUniformOffsetAlignment- Returns the uniform buffer offset alignment.createTexturenow takes in additionalsintfor the usage and the number of depth/layers, seeGpuTextureconstantscreateTextureView- Creates a view of a texture for a certain range of mip levels.
RenderPassenableScissoris removedbindSamplercan now take in a nullableGpuTextureViewsetUniformcan either take in aGpuBufferorGpuBufferSliceinstead of the raw inputsdrawIndexednow takes the followingints: the base vertex, the start index, the number of elements, and the prim countdrawMultipleIndexednow takes in a collection of strings that defines the list of required uniforms and a generic indicating the object of the draw callpushDebugGroup,popDebugGroup- Profiler commands for grouping similar calls.$UniformUploader#uploadnow takes in aGpuBufferSliceinstead of an array offloats$Drawnow has a generic that passed in to upload any uniforms to the buffer
RenderSystemSCISSOR_STATE->scissorStateForRenderTypeDraws, now private- Accessible through
getScissorStateForRenderTypeDraws
- Accessible through
enableScissor,disableScissor->enableScissorForRenderTypeDraws,disableScissorForRenderTypeDraws, not one to onePROJECTION_MATRIX_UBO_SIZE- Returns the size of the projection matrix uniformsetShaderFog,getShaderFognow deals with aGpuBufferSlicesetShaderGlintAlpha,getShaderGlintAlphais removedsetShaderLights,getShaderLightsnow deals with aGpuBufferSlicesetShaderColor,getShaderColorsetup*Lightingmethods are removedsetProjectionMatrix,getProjectionMatrix(nowgetProjectionMatrixBuffer) now deals with aGpuBufferSlicesetShaderGameTime,getShaderGameTime->setGlobalSettingsUniform,getGlobalSettingsUniform; not one-to-onegetDynamicUniforms- Returns a list of uniforms to write for the shader.bindDefaultUniforms- Binds the default uniforms to be used within aRenderPassoutputColorTextureOverride,outputDepthTextureOverrideare nowGpuTextureViewssetupOverlayColor,setShaderTexture,getShaderTexturenow operate onGpuTextureViews instead ofGpuTextures
com.mojang.blaze3d.texturesGpuTexturenow takes in an int representing the usage flags and number of depth/layersusage- The flags that define how the texture can be used.depthOrLayers,getDepthOrLayers- Defines how many layers or depths are available for a given texture. This is meant as a generic count for available texture encodings. Only cubemap support is currently available (meaning the layer count must be a multiple of 6).
GpuTextureView- A view of some texture for a range of mip levels.TextureFormat#RED8I- An 8-bit signed integer handling the red color channel.
com.mojang.blaze3d.vertexByteBufferBuildernow takes in a long for the maximum capacityexactlySized- Returns a buffer that is its maximum capacity. This should be called over the public constructor.
DefaultVertexFormat#EMPTY- A vertex format with no elements.
net.minecraft.client.rendererCachedOrthoProjectionMatrixBuffer- An object that caches the orthographic projection matrix, rebuilding if the width or height of the screen changes.CachedPerspectiveProjectionMatrixBuffer- An object that caches the perspective projection matrix, rebuilding if the width, height, or field of view changes.CloudRendererFLAG_INSIDE_FACE,FLAG_USE_TOP_COLORare now privateRADIUS_BLOCKSis removedendFrame- Ends the current frame being rendered to by constructing a fence.
CubeMapis nowAutoCloseablerenderno longer takes in the float for the partial tick.
DynamicUniforms- A class that writes the uniform interface blocks to the buffer for use in shaders.DynamicUniformStorage- A class that holds the uniforms within a slice of a mappable ring buffer.FogParametersrecord is removed, now stored in a generalGpuBufferSliceFogRenderernow implementsAutoCloseable->.fog.FogRendererendFrame- Ends the current frame being rendered to by constructing a fence.getBuffer- Gets the buffer slice that holds the uniform for the current fog mode.setupFogno longer takes in theFogMode, returning nothing$FogData#modeis removed, replaced byskyEnd,cloudEnd$FogModeenums have been replaced withNONEandWORLD, not one-to-one
GameRenderergetGlobalSettingsUniform- Returns the uniform for the game settings.getLighting- Gets the lighting renderer.setLevel- Sets the current level the renderer is rendering.
GlobalSettingsUniform- An object fod handling the uniform holding the current game settings.LevelRendererendFrame- Ends the current frame being rendered to by constructing a fence.renderLevelnow takes in aGpuBufferSlice, the fog vector, and whether the current position is foggy instead of theGameRenderer
MappableRingBuffer- An object that contains three buffers that are written to as required, then rotates to the next buffer to use on end. These are synced using fences.PanoramaRenderer#rendernow takes in a boolean for whether to change the spin up the spin rather than two floats.PerspectiveProjectionMatrixBuffer- An object that holds the projection matrix uniform.PostChainloadnow takes in theCachedOrthoProjectionMatrixBufferaddToFrameno longer takes in theConsumer<RenderPass>processno longer takes in theConsumer<RenderPass>
PostChainConfig$FixedSizedTargetrecord is removed$FullScreenTargetrecord is removed$InternalTargetis now a record which can take in an optional width, height, whether the target is persistent, and the clear color to use$Pass#uniformsis now aMap<String, List<UniformValue>>$Uniformrecord is removed
PostPassis nowAutoCloseable, taking in aMap<String, List<UniformValue>>for the uniforms along with a list ofPostPass$InputsaddToFrameno longer takes in theConsumer<RenderPass>, with theMatrix4fpassed in as aGpuBufferSlice$InputbindTois removedtexture- Constructs aGpuTexturefor the input given the map of resources.samplerName- Returns the name of the sampler.
SkyRenderer#renderSunMoonAndStarsno longer takes in theFogParametersUniformValue- An interface that represents a uniform stored within an interface block.
net.minecraft.client.renderer.chunk.SectionRendererDispatcher$RenderSection#setDynamicTransformIndex,getDynamicTransformIndex- Handles the index used to query the correct dynamic transforms for a given section.net.minecraft.client.renderer.fog.environmentAirBasedFogEnvironment- An environment whose color is derived from the air of the biomeAtmosphericFogEnvironment- The default fog environment if no other special cases match.BlindessFogEnvironment- An environment that activates if the entity has the blindness effect.DarknessFogEnvironment- An environment that activates if the entity has the darkness effect.DimensionOrBossFogEnvrionment- An environment that activates based on if there are any bosses or the dimension special effects.FogEnvironment- An abstract class that determines how the fog should render at a given location for an entity.LavaFogEnvironment- An environment that activates if the entity is within lava.MobEffectFogEnvironment- An environment that activates based on if the entity has a given mob effect.PowderedSnowFogEnvironment- An environment that activates if the entity is within powdered snow.WaterFogEnvironment- An environment that activates if the entity is within water.
net.minecraft.client.renderer.textureAbstractTexturesetUseMipmaps- Sets whether the texture should use mipmapping.textureView,getTextureView- Represents the current texture view.
CubeMapTexture- A cubemap compatible texture, textures are expected to have suffixes_0to_5.ReloadableTexture#doLoadis now protected
net.minecraft.world.level.material.FogTypeDIMENSION_OR_BOSS- Fog for dimension special effects or bosses.ATMOSPHERIC- Default fog type.
Tag Providers: Appender Rewrite
The TagAppender has been rewritten to a degree, changing the basic implementations of TagsProviders.
By default, the TagsProvider no longer provides any useful methods for adding content to a TagBuilder. The most you can do is construct the builder using TagsProvider#getOrCreateRawBuilder and add elements or tags via their ResourceLocation using one of the available add* methods.
// We will assume there is some TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends TagsProvider<Item> {
public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries, CompletableFuture<TagsProvider.TagLookup<Item>> parentProvider) {
super(
// The output location of the pack
output,
// The registry key to generate tags for
Registries.ITEM,
// The registry of registries
registries,
// Optional: A parent provider to use the generate tags of
// Typically obtained from TagsProvider#contentsGetter
parentProvider
);
}
@Override
protected void addTags(HolderLookup.Provider registries) {
// Add tags here
TagBuilder builder = this.getOrCreateRawBuilder(EXAMPLE_TAG);
builder
// Add single element
.addElement(ResourceLocation.fromNamespaceAndPath("minecraft", "apple"))
// Add tag to builder
.addTag(ItemTags.WOOL.location());
}
}
But what if we want to reference tags by their ResourceKey? Or registry object? This is where the rewritten TagAppender comes in. TagAppender is an interface with two generics, E which represents the type of the entry to add, and T which represents the type of the objects within the tag. A TagAppender has five common methods: three that add entries (add, addAll, addOptional), and two that add tags (addTag, addOptionalTag). A TagAppender can be created via forBuilder, which accepts ResourceKeys for entries.
KeyTagProvider provides this for you by adding a tag method, creating the appender from a TagKey. Generally, datapack registry objects have their tags generated using this provider:
// We will assume there is some TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends KeyTagProvider<Item> {
public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
super(
// The output location of the pack
output,
// The registry key to generate tags for
Registries.ITEM,
// The registry of registries
registries
);
}
@Override
protected void addTags(HolderLookup.Provider registries) {
// Add tags here
TagAppender<ResourceKey<Item>, Item> builder = this.tag(EXAMPLE_TAG);
builder
// Add single element
.add(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath("minecraft", "apple")))
// Add tag to builder
.addTag(ItemTags.WOOL);
}
}
TagAppenders can also be mapped to change their entry type using the map method. This takes in a function which maps the new entry type to the original entry type. IntrinsicHolderTagsProvider provides this for you via a tag method, creating the appender from a TagKey and mapping it using a key extractor. Generally, built-in registry objects have their tags generated using this provider:
// We will assume there is some TagKey<Item> EXAMPLE_TAG
public class ExampleTagsProvider extends IntrinsicHolderTagsProvider<Item> {
public ExampleTagsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
super(
// The output location of the pack
output,
// The registry key to generate tags for
Registries.ITEM,
// The registry of registries
registries,
// Maps the registry object to its resource key
item -> item.builtInRegistryHolder().key()
);
}
@Override
protected void addTags(HolderLookup.Provider registries) {
// Add tags here
TagAppender<Item, Item> builder = this.tag(EXAMPLE_TAG);
builder
// Add single element
.add(Items.APPLE)
// Add tag to builder
.addTag(ItemTags.WOOL);
}
}
Copying Tags: Block and Item
Copying tags no longer exists in the traditional sense, where it loops through the elements of an existing tag. Instead, the implementation has been narrowed down to a general BlockItemTagsProvider. This method provides a TagAppender<Block, Block> by taking in both a block and an item tag, and then converting them appropriately within the Vanilla*TagsProvider. As such, it is less copying and more mapping blocks to their associated items.
The one drawback is that tags that are used within other tags (calling addTag) must have the same name. For example, adding BlockTags#LOGS only works because there is a minecraft:logs for both block and item tags. Meanwhile, adding BlockTags#CEILING_HANGING_SIGNS would fail as the associated item tag is minecraft:hanging_signs instead of minecraft:ceiling_hanging_signs.
// We will assume there is some TagKey<Block> BLOCK_EXAMPLE_TAG
// We will assume there is some TagKey<Item> ITEM_EXAMPLE_TAG
public class ExampleBlockItemTagsProvider extends BlockItemTagsProvider {
@Override
public void run() {
// Add block item tags here
// Will add entries to block or item tag depending on the provider
TagAppender<Block, Block> builder = this.tag(BLOCK_EXAMPLE_TAG, ITEM_EXAMPLE_TAG);
builder
// Add single element
.add(Blocks.TERRACOTTA)
// Add tag to builder
// There exists both `minecraft:logs` in block and item tags
.addTag(BlockTags.LOGS);
}
}
// For some IntrinsicHolderTagsProvider<Item> or IntrinsicHolderTagsProvider<Block>
@Override
protected void addTags(HolderLookup.Provider registries) {
// Add tags here
new ExampleBlockItemTagsProvider() {
// Or <Item, Item> depending on the situation
protected TagAppender<Block, Block> tag(TagKey<Block> blockTag, TagKey<Item> itemTag) {
// Return a TagAppender
// See VanillaItemTagsProvider$BlockToItemConverter for an item example
// See VanillaBlockTagsProvider for a block example
}
}.run();
}
net.minecraft.data.tagsBlockItemTagsProvider- A provider that generates tags for block items, using the block and item tag equivalents as a starting point.IntrinsicHolderTagsProvidertagnow returns the rawTagAppender$IntrinsicTagAppenderclass is removed
ItemTagsProviderclass is removedKeyTagProvider- A provider which appends elements via theirResourceKey.TagsProvidertagis removed$TagAppender->TagAppender, not one-to-one
VanillaItemTagsProvidernow implementsIntrinsicHolderTagsProviderBlockToItemConverter- A tag appender that adds a block to an item tag.
Generic Encoding and Decoding: Replacing Direct NBT Access
Direct access to get data out of some NBT has been removed completely from higher level objects like entities and block entities. This means that, generally, you cannot directly touch the CompoundTag during the serialization process. Instead, indirect access is provided to nbt tags via ValueInput and ValueOutput. As their name implies, these read values from and write values to the data object, respectively. The methods available are similar to those on CompoundTags. For ValueInput, there’s the get* methods by providing the associated key, and get*Or for a get-or-default if not present. There is also read for handling Codecs. For ValueOutput, there’s the put* methods by providing the associated key and value, and also a store for Codecs. List variants exists separately on the input/output access.
As such, most methods that take in a CompoundTag now instead take in a ValueInput for read/load or ValueOutput for write/save.
// For some Entity with an ItemStack stack
@Override
protected void readAdditionalSaveData(ValueInput in) {
super.readAdditionalSaveData(in);
// By default, the input uses a registry ops
this.stack = in.read("example_stack", ItemStack.CODEC).orElse(ItemStack.EMPTY);
}
@Override
protected void addAdditionalSaveData(ValueOutput out) {
super.addAdditionalSaveData(out);
// By default, the output uses a registry ops
in.storeNullable("example_stack", ItemStack.CODEC, this.stack);
}
// For some BlockEntity with an int value
@Override
protected void loadAdditional(ValueInput in) {
super.loadAdditional(in);
this.value = in.getIntOr("value", 0);
}
@Override
protected void saveAdditional(ValueOutput out) {
super.saveAdditional(out);
out.putInt("value", this.value);
}
NBT Implementations
To provide indirect access to CompoundTags, there are implementations of ValueInput and ValueOutput called TagValueInput and TagValueOutput respectively.
A TagValueOutput can be created using either createWithContext or createWithoutContext. ‘With context’ means that the output has access to the HolderLookup$Provider for registry objects while ‘without context’ does not. Currently, no location uses createWithoutContext. Internally, this creates a new CompoundTag. Then, this output is passed around to be populated before finally returning the NBT for writing via buildResult.
A TagValueInput, on the other hand, can be created via create, taking in the HolderLookup$Provider and the CompoundTag to read from. If the data is stored as a list of objects rather than a single object, you can pass in a List<CompoundTag> and get back a ValueInputList. Note this does not handle indicies, only providing an iterable or stream associated implementation.
Problem Reporter
In addition to what’s mentioned above, the create* methods also take in a ProblemReporter, used for collecting all problems encountered when attempting to serialize/deserialize the data. It is up to the implementation to determine whether this report causes a crash or gives a warning. A ProblemReporter contains two methods: report, which reports a $Problem; and forChild, which further groups $Problems using a $PathElement. Both problems and path elements are simply interface objects that return a string indicating what the problem is or the grouping, respectively.
There are two common ProblemReporters that are used: $Collector, which is typically used with data providers, and $ScopedCollector, which is used with disk objects (e.g., entities, block entities, chunks, etc.). A $Collector typiccally uses either forEach to report each problem one by one, getReport/getTreeReport to return a stringified problems, or isEmpty to list if there are any problems. A $ScopedCollector does the same, except this is AutoCloseable, in case nothing is done with the output. In these scenarios, the reports are written to a logger.
Each collector takes in an initial $PathElement. This typically comes from the object itself containing some method called problemPath, which implements the interface. The HolderLookup$Provider is provided in the same fashion.
// For some object with HolderLookup.Provider registries
// There is also a Logger LOGGER
// Let's assume our root path element is implemented like so
public record ExamplePathElement(String name) implements ProblemReporter.PathElement {
@Override
public String get() {
return "Example: " + this.name();
}
}
// For a data provider
ProblemReporter.Collector problems = new ProblemReporter.Collector(
// Can be empty for a non-specified root
new ExamplePathElement("data_provider")
);
// Pass around the provider
// For a disk-based object
try (ProblemReporter.ScopedCollector problems = new ProblemReporter.ScopedCollector(new ExamplePathElement("EXAMPLE TEST"), LOGGER)) {
TagValueOutput out = TagValueOutput.createWithContext(problems, this.registries);
// Pass around the output to write data
// For the input
// The last parameter can be whatever CompoundTag, using the output as an example
TagValueInput in = TagValueInput.create(problems, this.registries, out.buildResult());
// Pass around the input to read data
}
net.minecraft.nbt.StringTag#escapeWithoutQuotes- Creates a string that escapes control characters, quotations, apostrophes, and backslashes.net.minecraft.server.level.ServerPlayerloadAndSpawnParentVehiclenow takes in aValueInputloadAndSpawnEnderPearlsnow takes in aValueInputloadGameTypesnow takes in aValueInput
net.minecraft.server.players.PlayerList#loadtakes in aProblemReporter, returning an optionalValueInputnet.minecraft.util.ProblemReporterDISCARDING- A reporter which discards all reporters.forChildnow takes in a$PathElementreportnow takes in a$Problem$Collectornow has a constructor that takes in the root$PathElementisEmpty- Returns whether there are no reports.forEach- Loops through all available problems.getReportnow returns a regularStringgetTreeReport- Gets the report and all its children using DFS.
$ElementReferencePathElement- A path element that references someResourceKey.$FieldPathElement- A path element that references some string.$IndexedFieldPathElement- A path element that references some string at an index.$IndexedPathElement- A path element that references some index.$PathElement- An interface that defines the grouping or element.$Problem- An interface that defines a problem with an element.$RootElementPathElement- A path element that references someResourceKeyas the root.$RootFieldPathElement- A path element that references some string as the root.$ScopedCollector- A collector that logs warnings when problems arise.
net.minecraft.worldContainerHelpersaveAllItemsnow takes in aValueOutputinstead of aCompoundTag, and no longer takes in aHolderLookup$Providerwhile returning nothingloadAllItemsnow takes in aValueInputinstead of aCompoundTag, and no longer takes in aHolderLookup$Provider
LockCode#addToTag,fromTagnow takes in aValueOutput/ValueInputinstead of aCompoundTag, and no longer takes in aHolderLookup$ProviderRandomziableContainer#tryLoadLootTable,trySaveLootTablenow takes in aValueOutput/ValueInputinstead of aCompoundTagSimpleContainerfromTag->fromItemList, not one-to-onecreateTag->storeAsItemList, not one-to-one
net.minecraft.world.entityEntitysaveAsPassengernow takes in aValueOutputinstead of aCompoundTagsavenow takes in aValueOutputinstead of aCompoundTagsaveWithoutIdnow takes in aValueOutputinstead of aCompoundTag, returning nothingloadnow takes in aValueInputinstead of aCompoundTagreadAdditionalSaveDatanow takes in aValueInputinstead of aCompoundTagaddAdditionalSaveDatanow takes in aValueOutputinstead of aCompoundTagproblemPath- Returns the path element to report problems from.
EntityRenferencestorenow takes in aValueOutputinstead of aCompoundTagread,readWithOldOwnerConversionnow take in aValueInputinstead of aCompoundTag
EntityUUID_TAG->TAG_UUIDcreate,bynow take in aValueInputinstead of aCompoundTagloadEntityRecursivenow takes in aValueInputinstead of aCompoundTagloadEntitiesRecursivenow takes in aValueInput$ValueInputListinstead of a list of nbt tagsloadStaticEntitynow takes in aValueInputinstead of aCompoundTag
EntityReference#store- Writes the reference data to theValueOutput.Leashable#readLeashData,writeLeashDatanow take in aValueInput/ValueOutputinstead of aCompoundTagLivingEntity#ATTRIBUTES_FIELD->TAG_ATTRIBUTESNeutralMob#addPersistentAngerSaveData,readPersistentAngerSaveDatanow take in aValueOutput/ValueInputinstead of aCompoundTag
net.minecraft.world.entity.npc.InventoryCarrier#readInventoryFromTag,writeInventoryToTagnow take in aValueInput/ValueOutputinstead of aCompoundTagnet.minecraft.world.entity.player.Inventorysavenow takes in aValueOutput$TypedOutputList, returning nothingloadnow takes in aValueOutput$TypedInputList
net.minecraft.world.entity.variant.VariantUtilswriteVariantnow takes in aValueOutputinstead of aCompoundTagreadVariantnow takes in aValueInputinstead of aCompoundTag, and no longer takes in aRegistryAccess
net.minecraft.world.entity.vehicle.ContainerEntity#addChestVehicleSaveData,readChestVehicleSaveDatanow take in aValueOutput/ValueInputinstead of aCompoundTag, and no longer takes in aHolderLookup$Providernet.minecraft.world.inventory.PlayerEnderChestContainerfromTag->fromSlots, not one-to-onecreateTag->storeAsSlots, not one-to-one
net.minecraft.world.itemBlockItem#setBlockEntityDatanow takes in aTagValueOutputinstead of aCompoundTagItemStack#parse,saveare removed
net.minecraft.world.levelBaseCommandBlock#save,loadnow take in aValueOutput/ValueInputinstead of aCompoundTag, and no longer takes in aHolderLookup$Provider, returning nothingBaseSpawner#save,loadnow take in aValueOutput/ValueInputinstead of aCompoundTag, returning nothing
net.minecraft.world.level.block.SculkSpreader#save,loadnow take in aValueOutput/ValueInputinstead of aCompoundTagnet.minecraft.world.level.block.entity.BlockEntityload*methods now take in aValueInputinstead of aCompoundTag, and no longer takes in aHolderLookup$Providersave*methods now take in aValueOutputinstead of aCompoundTag, and no longer takes in aHolderLookup$ProviderremoveComponentsFromTagnow takes in aValueOutputinstead of aCompoundTagparseCustomNameSafenow takes in aValueInputand key instead of a tag andHolderLookup$ProviderproblemPath- Returns the path element to report problems from.
net.minecraft.world.level.block.entity.trialspawner.TrialSpawner#load,store- Handles writing the spawner data.net.minecraft.world.level.chunk.ChunkAccess#problemPath- Returns the path element to report problems from.net.minecraft.world.level.storagePlayerDataStorage#loadnow returns aValueInputinstead of aCompoundTag, taking in aProblemReporterTagValueInput- A compound tag input.TagValueOutput- A compound tag output.ValueInput- An interface that defines how to read data from some object.ValueInputContextHelper- A class that contains the context used to read object data.ValueOutput- An interface that defines how to write data to some object.
net.minecraft.world.level.storage.loot.ValidationContextforChild,enterElementnow takes in aProblemReporter$PathElementinstead of aStringreportProblemnow takes in aProblemReporter$Probleminstead of aString$MissingReferenceProblem- A problem where the referenced object is missing.$ParametersNotProvidedProblem- A problem where the loot context params are missing.$RecursiveReferenceProblem- A problem where the referenced object is referencing itself.$ReferenceNotAllowedProblem- A problem where the referenced object is not allowed to be referenced.
net.minecraft.world.level.storage.loot.entriesAlternativesEntry#UNREACHABLE_PROBLEM- A problem where the altnerative entry can never be executed.CompositeEntryBase#NO_CHILDREN_PROBLEM- A problem where the composite has no entries.NestedLootTable#INLINE_LOOT_TABLE_PATH_ELEMENT- An element which indicates that a table is inlined.
Server Player Changes
MinecraftServer is no longer publicly exposed on the ServerPlayer. Additionally, serverLevel has been removed, now replaced with overloading level to return the ServerLevel.
net.minecraft.server.level.ServerPlayerserverfield is now privateserverLevel->level, still returnsServerLevel
Minor Migrations
The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.
Leashes
The leash system has been updated to support up to four on enabled entities. Additionally, the physics have been updated to more properly handle real-world elasicity of some stretchable object.
net.minecraft.client.renderer.entity.state.EntityRenderStateleashStatenow returns a list of$LeashStates$LeashState#slack- Whether the leash has any slack.
net.minecraft.world.entityEntityshearOffAllLeashConnections- Handles when shears are used to removed a leash.dropAllLeashConnections- Handles when all leashes should be removed from an entity.getQuadLeashHolderOffsets- Gets the offsets when four leashes attached to an entity.supportQuadLeashAsHolder- Returns whether the entity can be leashed up to four times.notifyLeashHolder,notifyLeasheeRemoved- Handles when the leash is ticked on an entity and when its removed.setLeashOffsetis removedgetLeashOffset->Leashable#getLeashOffset
LeashableMAXIMUM_ALLOWED_LEASHED_DIST- The maximum distance a leash can be attached to an entity.AXIS_SPECIFIC_ELASTICITY- The resistance of the leash along each axis.SPRING_DAMPENING- The loss of energy when the leash is oscillating on stretch.TORSIONAL_ELASTICITY- The resistance of the leash under torque.STIFFNESS- The stiffness of the leash.ENTITY_ATTACHMENT_POINT- Specifies the attachment point of the leash on the entity.LEASHER_ATTACHMENT_POINT- Specifies the attachment point of the leash on the holder.SHARED_QUAD_ATTACHMENT_POINTS- Specifies the attachment points of the leashes on an entity.canHaveALeashAttachedToIt->canHaveALeashAttachedTo, not one-to-oneleashDistanceTo- Returns the distance of the leash traveled between the holder and leashee.onElasticLeashPull- Handles when the leash is being pulled upon.leashSnapDistance- Returns when the leash will attempt to remove itself from the entity.leashElasticDistance- Returns the max distance before the elasticity of the leash becomes a physics factor.handleLeashAtDistanceis removedangularFriction- Returns the angular friction of the entity on a block or within a liquid.whenLeashedTo- Notifies the entity that the leash is attached.elasticRangeLeashBehaviour,legacyElasticRangeLeashBehaviour->checkElasticInteractions, not one-to-onesupportQuadLeash- Whether the entity can be leashed up to four times.getQuadLeashOffsets- Returns the offsets of each leash attached to the entity.createQuadLeashOffsets- Creates the offsets for each of the four possible leash positions.leashableLeashedTo- Gets all entities within a 32-block radius that are leashed to this holder.$LeashData#angularMomentum- Returns the angular momentum of the entity when leashed.$Wrench- A record which handles the force and torque applied to the leash.
net.minecraft.world.item.LeadItem#leashableInArea->Leashable#leashableInArea
Removal of Mob Effects Atlas
The mob effect atlas has been removed and merged with the gui altas.
net.minecraft.client.Minecraft#getMobEffectTexturesis removednet.minecraft.client.gui.Gui#getMobEffectSprite- Gets the location of the mob effect sprite.net.minecraft.client.resources.MobEffectTextureManageclass is removedAtlasIds#MOB_EFFECTSis removed
Permission Sources
The permission checks for commands have been abstracted into its own PermissionSource interface. This provides the previously provided hasPermission method, in addition to a new method allowsSelectors, which returns whether the source has the necessary permission to select other entities (defaults to level 2 perms). You can incoporate the permission check into your commands by calling Commands#hasPermission with the desired level in ArgumentBuilder#requires.
net.minecraft.client.multiplayerClientPacketListenergetCommandsnow returns aClientSuggestionProvidergenericsendUnattendedCommandnow takes in aScreeninstead of aboolean
ClientSuggestionListenernow implementsPermissionSource, taking in a boolean of whether it allows restricted commandsallowRestrictedCommands- Returns whether restricted commands can be suggested.
net.minecraft.commandsCommands#hasPermission- Returns a permission check for the given level.CommandSourceStacknow implementsPermissionSourceExecutionCommandSourcenow implementsPermissionSourcePermissionSource- Returns the source of the permission to run a command.SharedSuggestionProvidersuggestResgitryElementsnow takes in aHolderLookupinstead of aRegistrylistSuggestions- Lists the suggestion for some registry elements.hasPermissionis removed
net.minecraft.commands.synchronization.SuggestionProvidersAVAILABLE_SOUNDS,SUMMONABLE_ENTITIESnow take in aSharedSuggestionProviderfor their genericcast- Casts the suggestion provider to the correct type.safelySwapis removed$Wrapper->$RegisteredSuggestion
net.minecraft.world.entity.Entity#getCommandSenderWorldis removed
Animation Baking
Animations are now baked into KeyframeAnimation. Each KeyframeAnimation is made up of entries that apply the keyframes to a given ModelPart. To create an animation, the definition should be baked via AnimationDefinition#bake in the model constructor, then calling #apply or #applyWalk as required during EntityModel#setupAnim.
// For some entity model
// Assume some AnimationDefinition EXAMPLE_DEFN
// Assume our ExampleEntityState has some AnimationState exampleAnimState
public class ExampleModel extends EntityModel<ExampleEntityState> {
private final KeyframeAnimation exampleAnim;
public ExampleModel(ModelPart root) {
// We pass in whatever 'root' that can apply all animations
this.exampleAnim = EXAMPLE_DEFN.bake(root);
}
@Override
public void setupAnim(ExampleEntityState state) {
super.setupAnim(state);
this.exampleAnim.apply(state.exampleAnimState, state.ageInTicks);
}
}
net.minecraft.client.animationAnimationDefinition#bake- Bakes a defined animation to be used on aModel.KeyframeAnimation- A baked animation used to moveModelParts on a givenModel.KeyframeAnimations#animate->KeyframeAnimation$Entry#apply
net.minecraft.client.model.ModelgetAnyDescendantWithNameis removedanimate->KeyframeAnimation#applyanimateWalk-KeyframeAnimation#applyWalkapplyStatic->KeyframeAnimation#applyStatic
net.minecraft.client.model.geom.ModelPartgetAllPartsnow returns aListcreatePartLookup- Creates a lookup of part names to theirModelPart, any duplicate names are ignored.
ChunkSectionLayers
RenderTypes used for defining how a block or fluid should render are now replaced with ChunkSectionLayers. These functionally do the same thing as the RenderType; however, they only specify the RenderPipeline to use along with the buffer information. This also means that certain RenderTypes are removed, like TRANSLUCENT, as they were only used for the block chunk rendering.
This also means that adding to ItemBlockRenderTypes#TYPE_BY_BLOCK must specify the ChunkSectionLayer instead of the associated RenderType.
net.minecraft.client.rendererItemBlockRenderTypesgetChunkRenderTypenow returns aChunkSectionLayergetRenderLayer(FluidState)now returns aChunkSectionLayer
RenderTypetranslucentis removedgetRenderTarget,getRenderPipelineis removedchunkBufferLayersis removed
net.minecraft.client.renderer.chunkChunkSectionLayer- An enum that defines how an individual chunk layer (e.g., solid blocks, translucent blocks) is rendered.ChunkSectionLayerGroup- An enum that groups the layers for rendering.ChunkSectionsToRender- A record that contains the draws of a given chunk, allowing them to be rendered per layer group.RenderChunk->SectionCopyRenderChunkRegion->RenderSectionRegionRenderRegionCache#createRegionnow takes in alonginstead of aSectionPosSectionCompiler$ResultsglobalBlockEntities-> -net.minecraft.client.multiplayer.ClientLevel#getGloballyRenderedBlockEntitiesrenderedLayersnow takes in aChunkSectionLayerfor the key
SectionMesh- An interface that defines the mesh of a given section within a chunkSectionRenderDispatchergetBatchToCount->getCompileQueueSizesetCamera,getCameraPositionare removedblockUntilClearis removedclearBatchQueue->clearCompileQueue, now public$CompiledSection->CompiledSectionMesh$RenderSectiongetBuffersis removeduploadSectionLayer(RenderType, MeshData)->upload(Map, CompiledSectionMesh), not one-to-oneuploadSectionIndexBuffernow takes in aCompiledSectionMeshand aChunkSectionLayerinstead of aRenderTypegetDistToPlayerSqris removedgetCompiled->getSectionMesh, not one-to-onerebuildSectionAsyncno longer takes in theSectionRenderDispatchersetDynamicTransformIndex,getDynamicTransformIndexare removed
$SectionBuffers->SectionBuffers$TranslucencyPointOfView->TranslucencyPointOfView
net.minecraft.server.level.ChunkMap#getUpdatingChunkIfPresentis now publicnet.minecraft.world.level.TicketStoragepurgeStaleTicketsnow takes in theChunkMapremoveTicketIfnow takes in aBiPredicateinstead of aPredicate, taking in the chunk position and the ticket
net.minecraft.world.level.chunk.ChunkAccess#isSectionEmptyis removed
Tag Changes
minecraft:blockplays_ambient_desert_block_soundsis split intotriggers_ambient_desert_sand_block_sounds,triggers_ambient_desert_dry_vegetation_block_soundshappy_ghast_avoidstriggers_ambient_dried_ghast_block_sounds
minecraft:dialogpause_screen_additionsquick_actions
minecraft:entity_typecan_equip_harnessfollowable_friendly_mobs
minecraft:itemharnesseshappy_ghast_foodhappy_ghast_tempt_items
List of Additions
com.mojang.blaze3d.pipelineBlendFunction#TRANSLUCENT_PREMULTIPLIED_ALPHA- A blend function that assumes the target has a premultiplied alpha from the composite step.RenderPipelinegetSortKey- Returns a value representing how the element should be sorted for rendering. Used for layer sorting.updateSortKeySeed- Updates the seed of the sort key, currently unused.
com.mojang.blaze3d.systems.RenderSystemoutputColorTextureOverride- Holds a texture containing the override color used instead of whatever is specified in theRenderTypetarget.outputDepthTextureOverride- Holds a texture containing the override depth used instead of whatever is specified in theRenderTypetarget.
com.mojang.blaze3d.textures.GpuTexture#setUseMipmaps- Sets whether the texture should use mipmaps at different distances.net.minecraftFileUtil#isPathPartPortable- Returns whether the provided string does not match any of the windows reserved filenames.WorldVersion$Simple- A simple implementation of the current world version.
net.minecraft.advancements.critereonItemUsedOnLocationTrigger$TriggerInstance#placedBlockWithProperties- Creates a trigger where a block was placed with the specified property.PlayerInteractTrigger$TriggerInstance#equipmentSheared- Creates a criterion trigger that actus upon a player taking off an item on some entity.
net.minecraft.clientGameNarrator#saySystemChatQueued- Narrates a component if either system or chat message narration is enabled.Minecraft#disconnectWithSavingScreen- Disconnects the current client instance and shows the ‘Saving Level’ screen.OptionskeyQuickActions- A key mapping for showing the quick actions dialog.cloudRange- Returns the maximum distance clouds can render at.musicFrequency- Returns how frequency the background music handled by theMusicManagershould play.showNowPlayingToast- Returns whether the ‘Now Playing’ toast is shown.getFinalSoundSourceVolume- Computes the volume for the given sound source, with non-master sources being scaled by the master source.
NarratorStatus#shouldNarrateSystemOrChat- Returns whether the current narration status is anything butOFF.
net.minecraft.client.color.ColorLerper- A utility class for lerping between color types based on some partial tick.net.minecraft.client.data.models.BlockModelGenerators#createDriedGhastBlock- Creates the dired ghast block model definition.net.minecraft.client.data.models.modelModelTemplates#DRIED_GHAST- A template that uses theminecraft:block/dried_ghastparent.TextureMapping#driedGhast- Creates the default texture mapping for the dried ghast model.TextureSlot#TENTACLES- Provides a texture keytentacles.
net.minecraft.client.modelGhastModel#animateTentacles- Animates the tentacles of a ghast.HappyGhastHarnessModel- A model representing the a ghast harness.HappyGhastModel- A model representing a ‘tamed’ ghast.QuadrupedModel#createBodyMeshnow takes in two booleans for handling if the left and right hind leg textures are mirrored, respectively.
net.minecraft.client.multiplayer.ClientLevelDEFAULT_QUIT_MESSAGE- The component holding the quit game text.disconnect(Copmonent)- Disconnects from the current level instance, showing the associated component.
net.minecraft.client.renderer.entity.HappyGhastRenderer- The renderer for a ‘tamed’ ghast.net.minecraft.client.renderer.entity.layers.RopesLayer- The render layer for the ropes used on a ‘tamed’ ghast.net.mienecraft.client.renderer.entity.state.HappyGhastRenderState- The state of a ‘tamed’ ghast.net.minecraft.client.resources.model.EquipmentclientInfo$LayerType#HAPPY_GHAST_BODY- A layer representing the body of a happy ghast.net.minecraft.client.resources.sounds.RidingHappyGhastSoundInstance- A tickable sound instance that plays when riding a happy ghast.net.minecraft.client.soundsMusicManagergetCurrentMusicTranslationKey- Returns the translation key of the currently playing music.setMinutesBetweenSongs- Sets the frequency between the background tracks.showNowPlayingToastIfNeeded- Shows the now playing toast if it needs to be seen.$MusicFrequency- The frequency of the background tracks being played.
SoundEngine$PlayResult- The starting state of the sound trying to be played.
net.minecraft.commands.argumentsHexColorArgument- An integer argument that takes in a hexadecimal color.ResourceOrIdArgumentcreateGrammar- Creates the grammar used to parse the argument.$InlineResult- A result that returns a direct holder.$ReferenceResult- A result that returns a reference holder.$Result- An interface that represents the result of some argument parsing.
net.minecraft.data.loot.LootTableProvider$MissingTableProblem- A record that holds the key of some missing built-in table generator.net.minecraft.data.recipes.RecipeProviderdryGhast- The recipe for a dried ghast.harness- The recipe for a colored harness.
net.minecraft.gametest.framework.GameTestTicker#startTicking- Starts ticking the runner for the game tests.net.minecraft.nbt.NbtUtilsaddCurrentDataVersion,addDataVersion, adds the data version to some nbt tag.
net.minecraft.network.FriendlyByteBuf#writeEither,readEither- Handles anEitherwith the given stream encoders/decoders.net.minecraft.network.codec.ByteBufCodecsRGB_COLOR- A stream codec that writes the RGB using three bytes.lenientJson- Creates a stream codec that parses a json in lenient mode.optionalTagCodec- Creates a stream codec that parses anOptional-wrappedTagusing the suppliedNbtAccounter.
net.minecraft.network.protocol.gameServerboundChangeGameModePacket- Changes the current gamemode.ServerboundCustomClickActionPacket- Executes a custom action on the server, currently does nothing.
net.minecraft.server.MinecraftServer#handleCustomClickAction- Handles a custom action sent from a click event.net.minecraft.server.level.ServerLevelupdateNeighboursOnBlockSet- Updates the neighbors of the current position. If the blocks are not the same (not including their properties), thenBlockState#affectNeighborsAfterRemovalis called.waitForChunkAndEntities- Adds a task that causes the server to wait until entities are loaded in the provided chunk range.
net.minecraft.sources.SoundSource#UI- Sounds that come from some user interface.net.minecraft.statsRecipeBookSettings#MAP_CODECServerRecipeBook#pack,loadUntrusted,$Packed- Handles encoding and decoding the data of the recipe book.
net.minecraft.utilARGBsetBrightness- Returns the brightness of some color using a float between 0 and 1.color- Returns a ARGB color from a float red and integer alpha.
ExtraCodecsVECTOR2FVECTOR3INBT
LenientJsonParser- A json parser using lenient rules.Mth#smallestSquareSide- Takes the ceiled square root of a number.StrictJsonParser- A json parser using strict rules.
net.minecraft.worldDifficulty#STREAM_CODECItemStackWithSlot- A record which holds a stack along with its slot index.
net.minecraft.world.entityEntityMAX_MOVEMENTS_HANDELED_PER_TICK- The maximum number of movements that can be applied to an entity in a given tick.isInClouds- Returns whether the entity’s Y position is between the cloud height and four units above.teleportSpectators- Teleports the spectators currently viewing from the player’s perspective.isFlyingVehicle- Returns whether the vehicle can fly.clearMovementThisTick- Clears all movement the entity will make this tick.
EntityAttachments#getAverage- Returns the average location of all attachment points.ExperienceOrbawardWithDirection- Adds an experience orb that moves via the specified vector.unstuckIfPossible- Attempts to find and move the orb to a free position.
MobisWithinHome- Returns whether the position is within the entity’s restriction radius.canShearEquipment- Returns whether the current player can shear the equipment off of this mob.
net.minecraft.world.entity.ai.control.MoveControl#setWait- Sets the operation toWAIT.net.minecraft.world.entity.ai.goal.TemptGoalstopNavigation,navigateTowards- Handles navigation towards the player.$ForNonPathfinders- A tempt goal that navigates towards a wanted position rather than immediately pathfinding.
net.minecraft.world.entity.ai.navigation.PathNavigation#canNavigateGround- Returns whether the entity can pathfind while on the ground.net.minecraft.world.entity.ai.sensing.AdultSensorAnyType- An adult sensor that ignores whether the entity is the same type as the child.net.minecraft.world.entity.animalHappyGhast- An entity representing a happy ghast.HappyGhastAi- The brain of the happy ghast.
net.minecraft.world.entity.decoration.ArmorStandsetArmorStandPose,getArmorStandPose,$ArmorStandPose- Handles the pose of the armor stand.
net.minecraft.world.entity.monster.GhastfaceMovementDirection- Rotates the entity to face its current movement direction.$RandomFloatAroundGoal#getSuitableFlyToPosition- Gets a position that the ghast should fly to.
net.minecraft.world.entity.player.Inventory#SLOT_BODY_ARMOR,SLOT_SADDLE- The indicies for the corresponding slot.net.minecraft.world.entity.projectile.ProjectileUtil#computeMargin- Computes the bounding box margin to check for a given entity based on its tick count.net.minecraft.world.item.componentItemAttributeModifiersforEach- Applies the consumer to all attributes within the slot group.$Builder#add- Adds an attribute to apply for a given slot group with a display.$Display- Defines how an attribute modifier should be displayed within its tooltip.$Default- Shows the default attribute display.$Hidden- Does not show any attribute info.$OverrideText- Overrides the attribute text with the component provided.
Equippable$BuildersetCanBeSheared- Sets whether the equipment can be sheared off the entity.setShearingSound- Sets the sound to play when a piece of equipment is sheared off an entity.
ResolvableProfile#pollResolve- Returns the profile of the stored id or name.
net.minecraft.world.item.equipment.Equippable#harness- Represents a harness to equip.net.minecraft.world.levelCollisionGettergetPreMoveCollisions- Returns an iterable of shapes containing the entity and block collisions at the given bounding box and futue movement direction.getBlockCollisionsFromContext- Gets the block shapes from the given collision context.
GameType#STREAM_CODECLevelprecipitationAt- Returns the precipitation at a given position.onBlockEntityAdded- Logic to run when a block entity is added to the level.
net.minecraft.world.level.blockBaseRailBlock#rotate- Rotates the current rail shape in the associated direction.DriedGhastBlock- A block that represents a dried ghast.
net.minecraft.world.level.block.entity.trialspawner.TrialSpawner$FullConfig- Represents the entire configuration of a trial.net.minecraft.world.level.dimension.DimensionDefaultsCLOUD_THICKNESS- The block thickness of the clouds.OVERWORLD_CLOUD_HEIGHT- The cloud height level in the overworld.
net.minecraft.world.level.levelgen.flat.FlatLayerInfo#heightLimited- Returns a new layer info whether the current height is limited to the specified value, as long as that value is not within the maximum range already.net.minecraft.world.physAABBintersects- Returns whether theBlockPosintersects with this box.distanceToSqr- Returns the squared distance of the bounding boxes from their furthest point.
Vec3#rotateClockwise90- Rotates the vector 90 degrees clockwise (flip x and z and invert new x value).
net.minecraft.world.phys.shapes.CollisionContextwithPosition- Returns the collision context of an entity with its bottom y position.
List of Changes
com.mojang.blaze3d.platform.Window#setGuiScale,getGuiScalenow deals with anintinstead of adoublenet.mineraftDetectedVersionno longer implementsWorldVersionWorldVersionmethods now use record naming schema due toWorldVersion$SimpleusagegetDataVersion->dataVersiongetId->idgetName->namegetProtocolVersion->protocolVersiongetPackVersion->packVersiongetBuildTime->buildTimeisStable->stable
net.minecraft.clientGameNarratorsayChat->sayChatQueuedsay->saySystemQueuedsayNow->saySystemNow
MinecraftgrabPanoramixScreenshotno longer takes in the window width and height to setdisconnect()->disconnectWithProgressScreen
Screenshot#grab,takeScreenshotnow takes in anintrepresenting the downscale factor
net.minecraft.client.main.GameConfig$QuickPlayDatanow takes in a$QuickPlayVariantpath->logPathsingleplayer->variantwith$QuickPlaySinglePlayerDatamultiplayer->variantwith$QuickPlayMultiplayerDatarealms->variantwith$QuickPlayRealmsData- null for
singleplayer,multiplayer,realmsis represented byvariantwith$QuickPlayDisabled
net.minecraft.client.data.models.ItemModelGenerators#generateWolfArmor->generateTwoLayerDyedItemnet.minecraft.client.gui.components.DebugScreenOverlay#render3dCrosshairnow takes in the currentCameranet.minecraft.client.gui.components.debugchart.ProfilerPieChartRADIUSis now publicCHART_Z_OFFSET->PIE_CHART_THICKNESS, now public
net.minecraft.client.multiplayerClientLevel$ClientLevelData#getClearColorScale->voidDarknessOnsetRange, not one-to-oneMultiPlayerGameMode#createPlayernow takes in anInputinstead of aboolean
net.minecraft.client.player.LocalPlayernow takes in the last sentInputinstead of abooleanfor the shift keygetLastSentInput- Gets the last sent input from the server.
net.minecraft.client.quickplay.QuickPlay#connectnow takes in aGameConfig$QuickPlayVariantinstead of aGameConfig$QuickPlayDatanet.minecraft.client.rendererDimensionSpecialEffectsno longer takes in the current cloud level and whether there is a groundLightTexture#getTarget->getTexture
net.minecraft.client.renderer.blockentity.BlockEntityRenderer#shouldRenderOffscreenno longer takes in theBlockEntitynet.minecraft.client.resourcesAbstractSoundInstance#soundis nowNullableSoundInstance#getSoundis nowNullable
net.minecraft.client.soundsSimpleSoundInstance#forMusicnow also takes in thefloatvolumeSoundEnginenow takes in theMusicManagerpause->pauseAllExcept, not one-to-oneplaynow returns a$PlayResult
SoundManagernow takes in theMusicManagerpause->pauseAllExcept, not one-to-oneplaynow returns aSoundEngine$PlayResult
net.minecraft.commands.argumentsResourceOrIdArgumentnow takes in an arbitrary codec rather than aHolder-wrapped valueERROR_INVALID->ERROR_NO_SUCH_ELEMENT, now public, not one-to-oneVALUE_PARSER->OPS, now public, not one-toe
ResourceSelectorArgument#getSelectedResourcesno longer takes in theResourceKey
net.minecraft.commands.functions.StringTemplatefromStringno longer takes in the line numberisValidVariableNameis now public
net.minecraft.data.recipes.RecipeProvider#colorBlockWithDye->colorItemWithDye, now takes in theRecipeCategorynet.minecraft.gametest.framework.GameTestInfo#prepareTestStructureis now nullablenet.minecraft.networkConnection#sendnow takes in aChannelFutureListenerinstead of aPacketSendListenerFriendlyByteBuf#readJsonWithCodec->readLenientJsonWithCodecPacketSendListeneris now a class whose methods returnChannelFutureListeners instead ofPacketSendListenersonSuccess,onFailureare removed
net.minecraft.network.codecByteBufCodecs#fromCodecnow has an overload that takes in some ops and a codecStreamCodec#compositenow has an overload that takes in ten parameters
net.minecraft.network.protocol.login.ClientboundLoginDisconnectPacketis now a recordnet.minecraft.network.protocol.gameClientboundChangeDifficultyPacketis now a recordClientboundCommandsPacketnow takes in a$NodeInspectorgetRootis now generic, taking in a$NodeBuilder$NodeBuilder- A builder for a given command.$NodeInspector- An agent that checks the information of a given command node.
ServerboundChangeDifficultyPacketis now a record
net.minecraft.server.ReloadableServerRegistries$Holder#lookupreturns aHolderLookup$Providernet.minecraft.server.network.ServerCommonPacketListenerImpl#sendnow takes in aChannelFutureListenerinstead of aPacketSendListenernet.minecraft.sounds.Musicis now a recordnet.minecraft.stats.RecipeBookSettingsgetSettingsis now public$TypeSettingsis now public
net.minecraft.world.entityAreaEffectCloud#setParticle->setCustomParticleEntitycheckSlowFallDistance->checkFallDistanceAccumulationcollidedWithFluid,collidedWithShapeMovingFromare now publiccanBeCollidedWithnow takes the entity its colliding withspawnAtLocationnow has an overload that takes in aVec3for the offset positionremoveLatestMovementRecordingBatch->removeLatestMovementRecording
EntityReferenceis now finalExperienceOrbnow has an overload that takes in two vectors for the position and movementFlyingMobis replaced by callingLivingEntity#travelFlyingLivingEntity#canBreatheUnderwateris no longerfinalMobrestrictTo->setHomeTogetRestrictCenter->getHomePositiongetRestrictRadius->getHomeRadiusclearRestriction->clearHomehasRestriction->hasHome
net.minecraft.world.entity.ai.attributesAttributeInstancesave->pack,$Packed; not one-to-oneload->apply, not one-to-one
AttributeMapsave->pack; not one-to-oneload->apply, not one-to-one
net.minecraft.world.entity.ai.behaviorAnimalPanicnow has overloads that take in a radius or a position getterBabyFollowAdult#createnow returns aOneShot<LivingEntity>and can take in abooleanof whether to target the eye positionEntityTrackercan now take in abooleanof whether to target the eye positionFollowTemptationnow has an overload that checks whether the entity needs to track the entity’s eye height.
net.minecraft.world.entity.ai.goal.TemptGoalnow has an overload that takes in the stop distancemobis now aMobspeedModifieris nowprotected
net.minecraft.world.entity.ai.memory.MemoryModuleType#NEAREST_VISIBLE_ADULTnow holds aLivingEntitynet.minecraft.world.entity.ai.navigationFlyingPathNavigation,GroundPathNavigation#setCanOpenDoors->PathNavigation#setCanOpenDoors
net.minecraft.world.entity.ai.sensing.AdultSensornow looks for aLivingEntitysetNearestVisibleAdultis nowprotected
net.minecraft.world.entity.animal.*Variants#selectVariantToSpawn->entity.variant.VariantUtils#selectVariantToSpawn, not one-to-onenet.minecraft.world.entity.animal.Fox#isJumping->LivingEntity#isJumpingnet.minecraft.world.entity.animal.horse.AbstractHorseisJumping->LivingEntity#isJumpingsetStandingnow takes in anintinstead of abooleanfor the stand counter- the
falselogic is moved toclearStanding
- the
net.minecraft.world.entity.monsterGhastnow implementsMob$GhastLookGoalis now public, taking in aMob$GhastMoveControlis now public, taking in whether it should be careful when moving and a supplied boolean of whether the ghast should stop moving$RandomFloatAroundGoalis nowpublic, taking in aMoband a block distance
Phantomnow implementsMob
net.minecraft.world.entity.playerAbilitiesaddSaveData->pack,$Packed; not one-to-oneloadSaveData->apply, not one-to-one
Playerno longer takes in theBlockPosand y rotation
net.minecraft.world.entity.projectileAbstractThrownPotion#onHitAsPostionnow takes in aHitResultinstead of a nullableEntityEyeOfEnder#signalTonow takes in aVec3instead of aBlockPosProjectileownerUUID.cachedOwner->owner, now protected; not one-to-onesetOwnernow has an overload to take in anEntityReference
ProjectileUtilDEFAULT_ENTITY_HIT_RESULT_MARGINis now publicgetEntityHitResultnow takes in aProjectileinstead of anEntity
net.minecraft.world.item.ItemStackforEachModifiernow takes in aTriConsumerthat provides the modifier displayhurtAndBreaknow has an overload which gets theEquipmentSlotfrom theInteractionHand
net.minecraft.world.item.equipment.Equippablenow takes in whether the equipment can be sheared off an entity and the sound to play when doing sonet.minecraft.world.level.BlockGetterforEachBlockIntersectedBetweennow returns a boolean indicating that each block visited in the intersected area can be successfully visited$BlockStepVisitor#visitnow returns whether the location can be successfully moved to
net.minecraft.world.level.block.AbstractCauldronBlock#SHAPEis now protectednet.minecraft.world.level.block.entityBlockEntity#getNameForReportingis now publicSignBlockEntity#executeClickCommandsIfPresentnow takes in aServerLevelinstead of theLevel, parameters are reorderedStructureBlockEntity#saveStructurenow takes in a list of blocks to ignore
net.minecraft.world.level.block.entity.trialspawnerTrialSpawnernow takes in a$FullConfiggetConfig->activeConfigget*Config->*configgetData->getStateData
TrialSpawnerData->TrialSpawnerStateData, serialized form asTrialSpawnerStateData$Packed, not one-to-one
net.minecraft.world.level.block.sounds.AmbientDesertBlockSoundsPlayer#playAmbientBlockSoundshas been split intoplayAmbientSandSounds,playAmbientDryGrassSounds,playAmbientDeadBushSounds,shouldPlayDesertDryVegetationBlockSounds; not one-to-onenet.minecraft.world.level.dimension.DimensionTypenow takes in an optional integer representing the cloud height levelnet.minecraft.world.level.entityPersistentEntitySectionManager#processPendingLoadsis now publicUUIDLookup#getEntitycan now return null
net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate#fillFromWorldnow takes in a list of blocks to ignore rather than a singleBlocknet.minecraft.world.level.storage.DataVersionis now a recordnet.minecraft.world.phys.shapes.CollisionContext#placementContextnow takes in aPlayerinstead of anEntity
List of Removals
net.minecraft.client.Minecraft#disconnect(Screen)net.minecraft.client.rendererDimensionSpecialEffects#getCloudHeight,hasGroundLevelRenderer#updateGlobalBlockEntities
net.minecraft.client.renderer.texture.AbstractTexturedefaultBlursetFilter
net.minecraft.network.chat.Component$Serializer,$SerializerAdapternet.minecraft.network.protocol.game.ServerboundPlayerCommandPacket$Action#*_SHIFT_KEYnet.minecraft.server.ReloadableServerRegistries$Holder#getKeysnet.minecraft.server.players.PlayerList#getPlayerForLoginnet.minecraft.statsRecipeBookSettings#read,writeServerRecipeBook#toNbt,fromNbt
net.minecraft.utilGsonHelper#fromNullableJson(..., boolean),fromJson(..., boolean)LowerCaseEnumTypeAdapterFactory
net.minecraft.world.entity.ai.attributes.AttributeInstance#ID_FIELD,TYPE_CODECnet.minecraft.world.entity.animal.horse.AbstractHorse#setIsJumpingnet.minecraft.world.entity.animal.sheep.Sheep#getColornet.minecraft.world.entity.monster.Drowned#waterNavigation,groundNavigationnet.minecraft.world.entity.projectile.Projectile#findOwner,setOwnerThroughUUIDnet.minecraft.world.level.Level#disconnect()net.minecraft.world.level.blockAbstractCauldronBlock#isEntityInsideContentTerracottaBlock
net.minecraft.world.level.block.entity.trialspawner.TrialSpawner*_CONFIG_TAG_NAMEcodec
net.minecraft.world.level.dimension.DimensionType#parseLegacy
Minecraft 1.21.6 -> 1.21.7 Mod Migration Primer
This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.6 to 1.21.7. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.
This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.
If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.
Pack Changes
There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.
Minor Migrations
The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.
List of Additions
com.mojang.blaze3d.opengl.DirectStateAccess#copyBufferSubData- Copies all or part of one buffer object’s data store to the data store of another buffer object.com.mojang.blaze3d.pipeline.BlendFunction#INVERT- Inverts the blend factors of the RGB source and destination. Alpha uses the default one from source and zero from destination.com.mojang.blaze3d.systems.CommandEncoder#copyToBuffer- Copies the data store of one buffer slice to another buffer slice.net.minecraft.Util#isAarch64- Returns whether the OS architecture uses aarch64.net.minecraft.client.gui.GuiGraphics#textHighlight- Adds a highlighted box around the provided bounds.net.minecraft.client.renderer.RenderPipelines#GUI_INVERT- A render pipeline for drawing a gui element with inverted colors.net.minecraft.client.renderer.item.TrackingItemRenderState- A render state that tracks the model sources being used to render the item stack.
List of Changes
com.mojang.blaze3d.pipeline.RenderPipeline$Builder#withColorLogicis now deprecatednet.minecraft.client.gui.renderer.GuiRenderer#MIN_GUI_Zis now privatenet.minecraft.client.gui.render.state.GuiItemRenderStatenow takes in aTrackingItemRenderStateinstead of aItemStackRenderStateitemStackRenderStatenow returns aTrackingItemRenderState
net.minecraft.client.renderer.RenderPipelines#GUI_TEXT_HIGHLIGHTnow uses theADDITIVEblend function instead of theOR_REVERSEcolor logicnet.minecraft.client.renderer.item.ItemStackRenderState#getModelIdentity->TrackingItemRenderState#getModelIdentity
List of Removals
net.minecraft.client.renderer.item.ItemStackRenderState#clearModelIdentity
Minecraft 1.21.7 -> 1.21.8 Mod Migration Primer
This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.7 to 1.21.8. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.
This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.
If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.
Pack Changes
There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.
Minor Migrations
The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.
List of Additions
com.mojang.blaze3d.GraphicsWorkarounds- A helper for working around issues with specific graphics hardware.
Minecraft 1.21.8 -> 1.21.9 Mod Migration Primer
This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.8 to 1.21.9. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.
This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.
If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.
Thank you to:
- @Soaryn for pointing out some non-recommended rendering usages
- @Deximus-Maximus for some typos
Pack Changes
There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.
The Debugging Overhaul
The entirety of the debug system has been completely overhauled, from exposing the internal debugging tools to the debug screen. This documentation aims to provide a high level overview for handling your own debug screen and renderer additions.
Debug Renderers
Vanilla now allows users to see the debug renderers provided by the internal API by enabling them through the JVM properties via -DMC_DEBUG_ENABLED with whatever other desired flags. Users can take advantage of these exposed features to handle their own renderers through the vanilla provided pipeline. This overview will explain via patching the existing renderers and subscribers as needed, but these can generally be set up wherever needed. The benefit vanilla provides is its integration into existing objects (e.g. entities, block entities) and the general synchronization across the network. Of course, you can always use a simple boolean instead. After all, although the flags in SharedConstants are final, they are still checked every tick.
Subscribe to Debuggers
In most cases, information that you want to render and debug are stored on the server side. Sometimes, the information in question will be synced on the client, but in most cases it is usually some kind of partial state only necessary for rendering.
// An example object on the server
public record ExampleObject(Block held, int count) {}
// An example on the client
// Count is not used for rendering, only for server logic
public class ExampleRenderState {
Block held;
}
Therefore, if we want to see the additional data from the server, we need some method to not only synchronize it to the client, but also update it whenever the value changes. To do so, vanilla provides DebugSubscriptions: a class that stores the information required to sync an object if it has changed. The constructor contains two fields: the StreamCodec to sync the object across the network, and an optional int that, when greater than zero, will purge the synced value from the client if there were no more updates within the specified time.
To handle the logic associated with synchronization, the server makes use of TrackingDebugSynchronizers to handle player listeners and sync the object when necessary, and LevelDebugSynchronizers to handle the general tracking and ticking of the synchronizers. This data is then sent to the ClientDebugSubscriber for storage and the DebugRenderer for rendering. Note that clients can only see the debug information if they are either the owner of a singleplayer world or is an operator of the server. Additionally, the client can only request subscriptions that are added to the set provided by ClientDebugSubscriber#requestedSubscriptions.
DebugSubscriptions must be registered to BuiltInRegistries#DEBUG_SUBSCRIPTION:
public static final DebugSubscription<ExampleObject> EXAMPLE_OBJECt = Registry.register(
BuiltInRegistries.DEBUG_SUBSCRIPTION
ResourceLocation.withNamespaceAndPath("examplemod", "example_object"),
new DebugSubscription<>(
// The stream codec to sync the example object
StreamCodec.composite(
ByteBufCodecs.registry(Registries.BLOCK), ExampleObject::block,
ByteBufCodecs.VAR_INT, ExampleObject::count,
ExampleObject::new
),
// The maximum number of ticks between updates
// before the data is purged from the client
// Set to zero if it should never expire
0
)
);
To be able to check for updates properly, the object used must correctly implement hashCode and equals, not relying on the object identity.
Debug Sources
So, how do we tell the synchronizer to track and update our DebugSubscription? Well, you can extend TrackingDebugSynchronizer or use its subclasses and implement the tracking and syncing logic yourself, either by patching LevelDebugSynchronizers or creating your own. However, if the data you would like to track is directly attached to a LevelChunk, Entity, or BlockEntity and can be updated from their associated server object, you can make use of the DebugValueSource.
DebugValueSource is a way to register DebugSubscriptions as a TrackingDebugSynchronizer$SourceSynchronizer. This will poll and send updates to every player tracking the source with the subscription enabled every tick. Registering a DebugSubscription is done via DebugValueSource#registerDebugValues, taking in the server level and the $Registration interface. The registration is then handled via $Registration#register by passing in the subscription and a supplier to construct the subscription value.
// Assume we have some ExampleObject exampleObject in the below classes
// For some BlockEntity, Entity, or LevelChunk subclass
@Override
public void registerDebugValues(ServerLevel level, DebugValueSource.Registration registrar) {
super.registerDebugValues(level, registrar);
// Register our subscription
registrar.register(
// The subscription
EXAMPLE_OBJECT,
// The supplied subscription object
() -> this.exampleObject
);
}
Rendering the Debug Information
Once the information has been synced to the client and stored within ClientDebugSubscriber (assuming you are using the above method), we now need to render that information to the screen. This is typically handled through DebugRenderer#render, which checks the enabled debug renderers via refreshRendererList before running the associated renderers. Technically, it doesn’t particularly matter where as the data can be obtained at any point in the render process, but this will assume you are patching refreshRendererList to add your own renderer to either the opaque or translucent renderers.
All renderers implement DebugRenderer$SimpleDebugRenderer to call render, which provides the current PoseStack, buffer source, camera XYZ, and Frustum. In addition, vanilla passes in a DebugValueAccess via Connection#createDebugValueAccess to get the synched debug information from the ClientDebugSubscriber. DebugRenderer provides simple methods to render text or boxes in specific locations using render*.
The DebugValueAccess contains two types of methods: get*Value to obtain the debug object for that specific source (e.g. position, entity); and forEach*, which loops through all sources sending out the debug object. Which you use depends on which source you registered your DebugSubscription to.
// We will assume that our example object was registered to an entity
public class ExampleObjectRenderer implements DebugRenderer.SimpleDebugRenderer {
@Override
public void render(PoseStack poseStack, MultiBufferSource bufferSource, double x, double y, double z, DebugValueAccess access, Frustum frustum) {
// Loop through all blocks with our example object
access.forEachEntity(EXAMPLE_OBJECT, (entity, exampleObject) -> {
// Render the debug info
DebugRenderer.renderTextOverMob(
poseStack, bufferSource, entity,
// Text Y offset (entities display a lot of information)
100,
// Text to render
"Held Count: " + exampleObject.count(),
// Text color
0xFFFFFFFF,
// The scale of the text
1f
);
});
}
}
Debug Screens
The debug screens allows for users to to enable, disable, or only show in F3 specific components. This modular system allows for modders to add their own debug entries to the screen. Not all parts of this explanation is accessible without a bit more modding work, so those areas will be specifically pointed out.
DebugScreenEntry
Every debug option has its own entry that either defines what is being displayed (e.g., fps, memory), or no-ops to be handled by a separate implementation (e.g., entity hitboxes, chunk borders). This is known as a DebugScreenEntry, which defines three methods.
First is the category. In vanilla, this is almost always DebugEntryCategory#SCREEN_TEXT, as all a debug entry does is draw text to the screen. The other available option RENDERER is only for no-op as the rendering options always rendered independent from the debug screen. DebugEntryCategory is simply a record with a label and some sort of sort key value, so more can be added by calling the constructor. All the category is used for is searching in the debug options screen.
Next is isAllowed. This method determines whether the debug option should render on the screen independent of the entry status. By default, this is true only when the Minecraft#showOnlyReducedInfo accessibility option is false. Some debug entries override this method to always return true, or if some other check passes.
Finally, there is the display method. This is responsible for drawing the text to the screen using the DebugScreenDisplayer. It also takes in the current Level, client chunk, and server chunk. The DebugScreenDisplayer has four methods that each draw text to the screen. First, there is the standard addLine class, which just adds the string to either the left or right side depending on what element its rendered as. These will always come one right after the other. Then, there is addPriorityLine, which will always be added to the top of either the left or the right side. Finally, there is addToGroup, which takes an additional key to render the lines as one separate group with an extra new line added at the end.
public class ExampleDebugEntry implements DebugScreenEntry {
public static final ResourceLocation GROUP_ONE = ResourceLocation.fromNamespaceAndPath("examplemod", "group_one");
public static final ResourceLocation GROUP_TWO = ResourceLocation.fromNamespaceAndPath("examplemod", "group_two");
@Override
public void display(DebugScreenDisplayer displayer, @Nullable Level level, @Nullable LevelChunk clientChunk, @Nullable LevelChunk serverChunk) {
// The following will display like so if it is the only entry on the screen:
// First left! First Right!
//
// Hello world! Random text!
// Lorem ipsum.
// I am another group!
// I am one group This will appear after with no line breaks!
// All in a row
// Provided in a list.
//
displayer.addLine("Hello world!");
displayer.addLine("Lorem ipsum.");
displayer.addLine("Random text!");
// These will be displayed first
displayer.addPriorityLine("First left!");
displayer.addPriorityLine("First right!");
// These will be grouped separately based on the key
displayer.addToGroup(GROUP_ONE, List.of(
"I am one group",
"All in a row",
"Provided in a list."
));
displayer.addToGroup(GROUP_TWO, "I am another group!");
displayer.addToGroup(GROUP_TWO, "This will appear after with no line breaks!");
}
@Override
public boolean isAllowed(boolean reducedDebugInfo) {
// Always show regardless of accessibility option
return true;
}
}
Then, simply register your entry to DebugScreenEntries to have it display. It can be toggled on through the debug menu using the provided key
// This method is private, so its access will need to be widened
DebugScreenEntries.register(
// The id, this will be displayed on the options screen
ResourceLocation.fromNamespaceAndPath("examplemod", "example_entry"),
// The screen entry
new ExampleScreenEntry();
);
External Toggles and Checks
What if you want to toggle the active status separately from the options menu? What if you want to check is an entry is enabled to display debug data in-game? This can be done by accessing the DebugScreenEntryList through the Minecraft instance.
Toggling the current status can be done via DebugScreenEntryList#toggleStatus. How this behaves changes depending on what screen is active. Basically, calling toggle will always flip the debug entry on or off: if it’s not currently on screen, it will render on screen and vice versa. If in F3, then toggling on will only render that debug entry when F3 is on.
The status of the entry can then be checked using DebugScreenEntryList#isCurrentlyEnabled. This will only check if the debug screen is in the currently on list and not check DebugScreenEntry#isAllowed.
// Lets create another entry
public static final ResourceLocation EXAMPLE_TOGGLE = DebugScreenEntries.register(
ResourceLocation.fromNamespaceAndPath("examplemod", "example_toggle"),
// We're using noop as nothing is being displayed as text
new DebugEntryNoop();
);
// To toggle:
Minecraft.getInstance().debugEntries.toggleStatus(EXAMPLE_TOGGLE);
// To check if enabled:
if (Minecraft.getInstance().debugEntries.isCurrentlyEnabled(EXAMPLE_TOGGLE)) {
// ...
}
Profiles
Profiles are defined presets that can be configured to the user’s desire. Currently, profiles are hardcoded to either default or performance. To extend the system, you need to be able to dynamically add an entry to the DebugScreenProfile enum, make the DebugScreenEntries#PROFILES map mutable to add your profile and preset, and modify the debug option screen with your profile button.
net.minecraft.SharedConstantsDEBUG_SHUFFLE_MODELS- A flag that likely shuffles the model loading order.DEBUG_FLAG_PREFIX- A prefix put in front of every debug flag.USE_DEBUG_FEATURES->DEBUG_ENABLEDDEBUG_RENDERis removedDEBUG_WORLDGENATTEMPTis removeddebugGenerateStripedTerrainWithoutNoiseis removedDEBUG_RESOURCE_GENERATION_OVERRIDEis removedDEBUG_POI- Enables the POI debug renderer.DEBUG_PANORAMA_SCREENSHOT- When enabled, allows the user to take a panorama screenshot.DEBUG_CHASE_COMMAND- When enabled, adds the chase command.FAKE_MS_LATENCY->DEBUG_FAKE_LATENCY_MSFAKE_MS_JITTER->DEBUG_FAKE_JITTER_MSDEBUG_VERBOSE_COMMAND_ERRORS- When enabled, outputs verbose errors through the chat box.DEBUG_DEV_COMMANDS- When enabled, adds the commands used for debugging the game.
net.minecraft.client.MinecraftdebugEntries- Returns a list of debug features and what should be shown on screen.fpsString,sectionPath,sectionVisibilityare removeddebugRenderer->LevelRenderer#debugRenderer
net.minecraft.client.gui.GuirenderDebugOverlayis now publicshouldRenderDebugCrosshairis removed
net.minecraft.client.gui.components.DebugScreenOverlaydrawGameInformation,drawSystemInformationare removedgetGameInformation,getSystemInformationare removedtoggleOverlayis removed
net.minecraft.client.gui.components.debugDebugEntryBiome- A debug entry displaying the biome the camera entity is within.DebugEntryCategory- A category that describes how a debug entry is displayed.DebugEntryChunkGeneration- A debug entry displaying the current chunk generation info.DebugEntryChunkRenderStats- A debug entry displaying the current section statistics.DebugEntryChunkSourceStats- A debug entry displaying the general metadata of the chunk sources.DebugEntryEntityRenderStats- A debug entry displaying the general metadata of the entity storage.DebugEntryFps- A debug entry displaying the frames per second and vsync info.DebugEntryGpuUtilization- A debug entry displaying the GPU utilization.DebugEntryHeightmap- A debug entry displaying the height maps at the current position.DebugEntryLight- A debug entry displaying the client light information.DebugEntryLocalDifficulty- A debug entry displaying the current world difficulty and time.DebugEntryLookingAtBlock- A debug entry displaying the block the camera is currently looking at.DebugEntryLookingAtEntity- A debug entry displaying the entity the camera is currently looking at.DebugEntryLookingAtFluid- A debug entry displaying the fluid the camera is currently looking at.DebugEntryMemory- A debug entry displaying the memory allocated and used by the game.DebugEntryNoop- A debug entry displaying nothing.DebugEntryParticleRenderState- A debug entry displaying the number of particles being rendered.DebugEntryPosition- A debug entry displaying the current position and rotation of the camera entity.DebugEntryPostEffect- A debug entry displaying the currently applied post effect.DebugEntrySectionPosition- A debug entry displaying the current section position.DebugEntrySimplePerformanceImpactors- A debug entry displaying the graphics mod, cloud status, and biome blend radius.DebugEntrySoundMood- A debug entry displaying the current sound played and player mood.DebugEntrySpawnCounts- A debug entry displaying the entity spawn counts per mob category.DebugEntrySystemSpecs- A debug entry displaying the specs of the running machine.DebugEntryTps- A debug entry displaying the general ticks per second.DebugEntryVersion- A debug entry displaying the current Minecraft version.DebugScreenDisplayer- An interface that the debug entries use to display elements to the screen.DebugScreenEntries- The debug entries registered by Minecraft.DebugScreenEntry- An element that shows up, if enabled, when the debug overlay is enabled.DebugScreenEntryList- The options information for what debug elements are displayed on screen.DebugScreenEntryStatus- The status of when a debug entry should be displayed.DebugScreenProfile- An enum denoting the profiles that the debug screen can set when deciding what entries to show.
net.minecraft.client.gui.screen.debug.DebugOptionsScreen- A screen that allows the user to change the displayed debug entries for a profile.net.minecraft.client.renderer.LevelRenderergetSectionStatisticsis now nullablegetEntityStatisticsis now nullablegameTestBlockHighlightRenderer- The renderer for the block highlight within a game test.
net.minecraft.client.renderer.debug.DebugRendererswitchRenderChunkborder->DebugScreenEntries#CHUNK_BORDERS, not one-to-onetoggleRenderOctree->DebugScreenEntries#CHUNK_SECTION_OCTREE, not one-to-one
net.minecraft.client.multiplayerDebugSampleSubscriber->ClientDebugSubscriber, not one-to-oneClientPacketListener#createDebugValueAccess- Creates the access to get the current debug values.
net.minecraft.client.renderer.debugBeeDebugRenderer#addOrUpdateHiveInfo,addOrUpdateBeeInfo,removeBeeInfoare removedBrainDebugRendereraddPoi,removePoi,$PoiInfoare removedsetFreeTicketCountis removedaddOrUpdateBrainDump,removeBrainDumpare removed
BreezeDebugRenderernow implementsDebugRenderer$SimpleDebugRendererrendernow takes in aDebugValueAccessclear,addare removed
DebugRendererno longer takes in theMinecraftinstance- All field renderers have been removed from public access, instead being store in on of the
*Rendererslists worldGenAttemptRendereris removedrenderTextOverBlock- Renders the given stream above the provided block position.renderTextOverMob- Renders the given string over the provided entity.refreshRendererList- Populates the renderer lists with the enabled debug renderers.render,renderAfterTranslucentshave been merged intorender, where abooleandetermines whether to render the translucent or opaque renderers$SimpleDebugRendererrendernow takes in aDebugValueAccessandFrustumclearis removed
- All field renderers have been removed from public access, instead being store in on of the
EntityBlockIntersectionDebugRenderer- A debug renderer for displaying the blocks the entity is intersecting with.GameEventListenerRendererno longer takes in theMinecraftinstancetrackGameEvent,trackListenerare removed
GameTestDebugRenderer->GameTestBlockHighlightRenderer, not one-to-oneaddMarker->highlightPos, not one-to-one
GoalSelectorDebugRenderer#addGoalSelector,removeGoalSelectorare removedNeighborsUpdateRendererno longer takes in theMinecraftinstanceaddUpdateis removed
OctreeDebugRenderernow implementsDebugRenderer$SimpleDebugRendererPathfindingRenderer#addPathis removedPoiDebugRenderer- A debug renderer for displaying the point of interests.RaidDebugRenderer#setRaidCentersis removedRedstoneWireOrientationsRendererno longer takes in theMinecraftinstanceaddWireOrientationis removed
StructureRendererno longer takes in theMinecraftinstanceaddBoundingBoxis removed
VillagerSectionsDebugRenderer#setVillageSection,setNotVillageSectionare removedWorldGenAttemptRendererclass is removed
net.minecraft.core.registries.BuiltInRegistries,Registries#DEBUG_SUBSCRIPTION- A registry for subscriptions to debug handlers.net.minecraft.gametest.frameworkGameTestAssertPosException#getMessageToShowAtBlocknow returns aComponentGameTestRunner#clearMarkersis removed
net.minecraft.network.protocol.common.custom- All classes have been moved to
net.minecraft.util.debug - They are no longer payloads, instead just records containing the object info and an associated stream codec
- If the payload class had an associated object inner class, then that class was moved and the payload class removed
- Otherwise the payload class was added without the
*Payloadsuffix, most of the time with an*Infosuffix
- All classes have been moved to
net.minecraft.network.protocol.gameClientboundDebugBlockValuePacket- A packet sent to the client about a debug value change on a block position.ClientboundDebugChunkValuePacket- A packet sent to the client about a debug value change on a chunk position.ClientboundDebugEntityValuePacket- A packet sent to the client about a debug value change on an entity.ClientboundDebugEventPacket- A packet sent to the client about the debug event fired.ClientboundGameTestHighlightPosPacket- A packet sent to the client about the game test position to highlight.ClientGamePacketListenerhandleDebugChunkValue- Handles the debug chunk position packet.handleDebugBlockValue- Handles the debug block position packet.handleDebugEntityValue- Handles the debug entity packet.handleDebugEvent- Handles the firing debug event.handleGameTestHighlightPos- Handles the provided position being highlighted.
DebugPacketsclass is removedServerboundDebugSampleSubscriptionPacket->ServerboundDebugSubscriptionRequestPacket, not one-to-oneServerGamePacketListener#handleDebugSampleSubscription->handleDebugSubscriptionRequest, not one-to-one
net.minecraft.server.MinecraftServersubscribeToDebugSampleis removeddebugSubscribers- Returns a map of the tracked subscriptions to the list of players that have it enabled.
net.minecraft.server.levelChunkMapisChunkTrackedis now publicgetChunksis removed
ServerLevel#debugSynchronizers- Returns the debugger handler and synchronizer for the level.ServerPlayerrequestDebugSubscriptions- Sets the debuggers that the player is listening for.debugSubscriptions- Returns the debuggers that the player is listening for.
net.minecraft.util.debugDebugSubscription- A tracked data point that can be listened or subscribed to.DebugSubscriptions- Vanilla debug subscriptions.DebugValueAccess- Accesses the values tracked by the debug subscription, used on the client for the debug renderers.DebugValueSource- Defines a source object that provides debug values to track, such as an entity.LevelDebugSynchronizers- Handles sending the subscription data across the network to the tracking clients.ServerDebugSubscribers- Handles the global state of players subscribed to the currently enabled subscriptions.TrackingDebugSynchronizer- Handles the list of players subscribed to a subscription.
net.minecraft.util.debugchartDebugSampleSubscriptionTrackerclass is removedRemoteDebugSampleTypenow takes in aDebugSubscriptionsubscription- Returns the subscription reported by the sample type.
RemoteSampleLoggernow takes inServerDebugSubscribersinstead ofDebugSampleSubscriptionTracker
net.minecraft.world.entityEntitynow implementsDebugValueSourceMob#sendDebugPacketsis removed
net.minecraft.world.entity.ai.village.poiPoiManager#getFreeTickets->getDebugPoiInfo, not one-to-onePoiSection#getDebugPoiInfo- Returns the debug poi info for the given position.
net.minecraft.world.level.block.entityBlockEntitynow implementsDebugValueSourceTestInstanceBlockEntity#markError,clearErrorMarkers,getErrorMarkers,$ErrorMarker- Handles the error markers set by the test instance.
net.minecraft.world.level.chunk.LevelChunknow implementsDebugValueSourcenet.minecraft.world.level.pathfinder.PathFinder#setCaptureDebug- Sets whether the path should be captured for debugging.net.minecraft.world.level.redstone.CollectingNeighborUpdater#setDebugListener- Sets the listener for block location changes for debugging.
Feature Submissions: The Movie
The entirety of the rendering pipeline, from entities to block entities to particles, has been reworked into a submission / render phase system known as features. This guide will go over the basics of the feature system itself followed by how each major type are implemented using it.
Submission and Rendering
The feature system, like GUIs, is broken into two phases: submission and rendering. The submission phase is handled by the SubmitNodeCollector, which basically collects the data required to abstractly render an object to the screen. This is all done through the submit* methods, which generally take a PoseStack to place the object in 3D space, and any other required data such as the model, state, render type, etc.
Here is a quick overview of what each method takes in:
| Method | Parameters |
|---|---|
submitHitbox | A pose stack, render state of the entity, and the hitboxes render state |
submitShadow | A pose stack, the shadow radius, and the shadow pieces |
submitNameTag | A pose stack, an optional position, the Y offset, the text component, if the text should be seethrough (like when sneaking), light coordinates, and the camera render state |
submitText | A pose stack, the XY offset, the text sequence, whether to add a drop shadow, the font display mode, light coordinates, color, background color, and outline color |
submitFlame | A pose stack, render state of the entity, and a rotation quaternion |
submitLeash | A pose stack and the leash state |
submitModel | A pose stack, entity model, render state, render type, light coordinates, overlay coordinates, tint color, an optional texture, outline color, and an optional crumbling overlay |
submitModelPart | A pose stack, model part, render type, light coordinates, overlay coordinates, an optional texture, whether to use item glint over entity glint if render type is not transparent, whether to render the glint overlay, tint color, an optional crumbling overlay, and an outline color |
submitBlock | A pose stack, block state, light coordinates, overlay coordinates, and outline color |
submitMovingBlock | A pose stack and the moving block render state |
submitBlockModel | A pose stack, the render type, block state model, RGB floats, light coordinates, overlay coordinates, and outline color |
submitItem | A pose stack, item display context, light coordinates, overlay coordinates, outline color, tint layers, quads, render type, and foil type |
submitCustomGeometry | A pose stack, render type, and a function that takes in the current pose and VertexConsumer to create the mesh |
submitParticleGroup | A SubmitNodeCollector$ParticleGroupRenderer |
Technically, the submit* methods are provided by the OrderedSubmitNodeCollector, of which the SubmitNodeCollector extends. This is because features can be submitted to different orders, which function similarly to strata in GUIs. By default, all submit calls are pushed onto order 0. Using SubmitNodeCollector#order with some integer and then calling the submit* method, you can have an object render before or after all features on a given order. This is stored as an AVL tree, where each order’s data is stored in a SubmitNodeCollection. With the current default feature rendering order, this is only used in very specific circumstances, such as rendering a slime’s outer body or equipment layers.
// Assume we have access to the `SubmitNodeCollector` collector
// This will render in order 0
collector.submitModel(...);
// This will render before the `submitModel` call
collector.order(-1).submitShadow(...);
// This will render after the `submitModel` call
collector.order(1).submitNameTag(...);
The render phase is handled through the FeatureRenderDispatcher, which renders the object using their submitted feature renderers. What are feature renderers? Quite literally an arbitrary method that loops through the node contents its going to push to the buffer. Currently, for a given order, the features push their vertices like so: shadows, models, model parts, flame animations, entity name tags, arbitrary text, hitboxes, leashes, items, blocks, custom render pipelines, and finally particles. Each order, starting from the smallest number to the largest, will rerun all of the feature renders until it reaches the end of the tree. All submissions are then cleared for next use.
Most of the feature dispatchers are simply run a loop over its collection. Those that store the render type batch the render calls into one buffer. ModelFeatureRenderer, meanwhile, goes one step further, sorting its translucent models by distance from the camera and sends them to the buffer after all opaque models.
Entity Models
So, how does this affect entities? Let’s start with the root Model that makes up all entity models. Model now has a generic which is used to pass in the state of the backing object to setupAnim, which has also been moved to Model. This means that the base model class is rarely passed around, instead opting for some subtype, like Model$Simple for signs. Given that most EntityModels already require a generic of EntityRenderState, this does not affect anything.
The main change comes from how model part visibility work, such as armors and capes. Every single individual part (e.g. helmet, chestplate) now has their own separate model, meaning that the general part visibility system has been completely removed. You can still provide visibility through the mutable model part in setupAnim, but the general movement is to simply have parts that should be separate models as separate models.
To facilitate this, PartDefinitions now has methods to selectively keep certain parts of models and remove the others. This is done through the clear* and retain* methods. Basically, all of these methods are doing are keeping the part pose while removing any cubes associated with the children queries. retain* allows for certain parts and potentially subparts to keep their cubes. This addition provides a twofold benefit: model layers can deterministically use setupAnim to setup the parts similarly to the base model, and the model texture will only need to contain the retained elements.
Here is an example for creating the armor models for a creeper:
// Deformations for humanoid armor
private static final CubeDeformation OUTER_ARMOR_DEFORMATION = new CubeDeformation(1.0F);
private static final CubeDeformation INNER_ARMOR_DEFORMATION = new CubeDeformation(0.5F);
// Creeper has the following parts:
// - head
// - body
// - right_hind_leg, left_hind_leg
// - right_front_leg, left_front_leg
// We use separate meshes as we are basically isolating the parts we want to keep in each
public static ArmorModelSet<MeshDefinition> createCreeperArmor() {
// Helmet
// Create mesh
MeshDefinition helmetMesh = CreeperModel.createBodyLayer(OUTER_ARMOR_DEFORMATION);
// Only retain the desired parts
// Note that body and the legs still exist, they simply have no cubes
helmetMesh.getRoot().retainExactParts(Set.of("head"));
// Chestplate
// Create mesh
var chestplateMesh = CreeperModel.createBodyLayer(OUTER_ARMOR_DEFORMATION);
// Only retain the desired parts
chestplateMesh.getRoot().retainExactParts(Set.of("body"));
// Leggings
// Create mesh
var leggingsMesh = CreeperModel.createBodyLayer(INNER_ARMOR_DEFORMATION);
// Only retain the desired parts
leggingsMesh.getRoot().retainExactParts(Set.of("right_hind_leg", "left_hind_leg", "right_front_leg", "left_front_leg"));
// Boots
// Create mesh
var bootsMesh = CreeperModel.createBodyLayer(OUTER_ARMOR_DEFORMATION);
// Only retain the desired parts
bootsMesh.getRoot().retainExactParts(Set.of("right_hind_leg", "left_hind_leg", "right_front_leg", "left_front_leg"));
// Store this all in an ArmorModelSet, which is basically just object holder and mapper
return new ArmorModelSet<>(
helmetMesh,
chestplateMesh,
leggingsMesh,
bootsMesh
);
}
// To register the layer definitions, basically the same process of using the ArmorModelSet
public static final ArmorModelSet<ModelLayerLocation> CREEPER_ARMOR = new ArmorModelSet<>(
new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "helmet"),
new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "chestplate"),
new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "leggings"),
new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "creeper"), "boots")
);
// In some method where you have access to the Map<ModelLayerLocation, LayerDefinition> builder
ArmorModelSet<LayerDefinition> creeperArmorLayers = createCreeperArmor().map(mesh -> LayerDefinition.create(mesh, 64, 32));
CREEPER_ARMOR.putFrom(creeperArmorLayers, builder);
Entity Renderer
With the change to submission, the EntityRenderer and its associated RenderLayers have also changed. Basically, you can assume almost every method that has the word render has been changed to submit, and MultiBufferSource and light coordinates integer have generally been replaced by SubmitNodeCollector and the associated entity render state.
The new submit method that replaces render in EntityRenderer now takes in the render state of the entity, the PoseStack, the SubmitNodeCollector, and the CameraRenderState. When submitting any element, the location in 3D space is taken by getting the last pose on the PoseStack and storing that for future use.
// A basic entity renderer
// We will assume all the classes listed exist
public class ExampleEntityRenderer extends MobRenderer<ExampleEntity, ExampleEntityRenderState, ExampleModel> {
public ExampleEntityRenderer(EntityRendererProvider.Context ctx) {
super(ctx, ctx.bakeLayer(EXAMPLE_MODEL_LAYER), 0.5f);
}
@Override
public void submit(ExampleEntityRenderState renderState, PoseStack poseStack, SubmitNodeCollector collector, CameraRenderState cameraState) {
super.submit(renderState, poseStack, collector, cameraState);
// An example of submitting something
collector.submitCustomGeometry(
poseStack, // The current pose
RenderType.solid(), // The render type to use
ExampleEntityRenderer::addVertices // The method to write the geometry data
);
}
private static void addVertices(PoseStack.Pose pose, VertexConsumer consumer) {
// Add custom geometry
}
}
// A render layer
public class CreeperArmorLayer extends RenderLayer<CreeperRenderState, CreeperModel> {
private final ArmorModelSet<CreeperModel> modelSet;
private final EquipmentLayerRenderer equipment;
public CreeperArmorLayer(RenderLayerParent<CreeperRenderState, CreeperModel> parent, ArmorModelSet<CreeperModel> modelSet, EquipmentLayerRenderer equipment) {
super(parent);
this.modelSet = modelSet;
this.equipment = equipment;
}
// We will assume we added headEquipment, chestEquipment, legsEquipment, feetEquipment to the CreeperRenderState somehow
@Override
public void submit(PoseStack poseStack, SubmitNodeCollector collector, int lightCoords, CreeperRenderState renderState, float yRot, float xRot) {
this.renderArmorPiece(poseStack, collector, renderState.chestEquipment, EquipmentSlot.CHEST, lightCoords, renderState);
this.renderArmorPiece(poseStack, collector, renderState.legsEquipment, EquipmentSlot.LEGS, lightCoords, renderState);
this.renderArmorPiece(poseStack, collector, renderState.feetEquipment, EquipmentSlot.FEET, lightCoords, renderState);
this.renderArmorPiece(poseStack, collector, renderState.headEquipment, EquipmentSlot.HEAD, lightCoords, renderState);
}
// Taken from humanoid armor layer
private void renderArmorPiece(PoseStack poseStack, SubmitNodeCollector collector, ItemStack stack, EquipmentSlot slot, int lightCoords, CreeperRenderState renderState) {
Equippable equippable = stack.get(DataComponents.EQUIPPABLE);
if (equippable != null && equippable.assetId().isPresent() && equippable.slot() == slot) {
CreeperModel model = this.modelSet.get(slot);
EquipmentClientInfo.LayerType layer = slot == EquipmentSlot.LEGS
? EquipmentClientInfo.LayerType.HUMANOID_LEGGINGS
: EquipmentClientInfo.LayerType.HUMANOID;
this.equipmentRenderer.renderLayers(
layer, // The equipment layer to use
equippable.assetId().orElseThrow(), // The equipment asset to pull
model, // The armor model
renderState, // The entity render state
stack, // The armor stack
poseStack, // The pose stack
collector, // The collector to add the model data to
lightCoords, // The light coordinates
renderState.outlineColor // The outline color of the entity
);
}
}
}
// Then, to add it to the creeper renderer constructor
public CreeperRenderer(EntityRendererProvider.Context ctx) {
// ...
this.addLayer(new CreeperArmorLayer(
this, // The parent is the renderer itself
ArmorModelSet.bake( // Baking the model set
CREEPER_ARMOR, // The model layer locations
ctx.getModelSet(), // The model set to map the models from the layer locations
CreeperModel::new // The mapper for the root part to the model
),
ctx.getEquipmentRenderer() // The renderer for the equipment
));
}
Block Entity Renderer
BlockEntityRenderers also use the new submission method, replacing almost every render* with submit. They have taken a play from entities, now having their own BlockEntityRenderState which is extracted from the BlockEntity. As such, BlockEntityRenderer now has a new generic S for the BlockEntityRenderState.
The BlockEntityRenderState, by default, contains information about its position, block state, type, light coordinates, and the current break progress as a ModelFeatureRenderer$CrumblingOverlay. These are all populated through BlockEntityRenderState#extractBase, which is called in BlockEntityRenderer#extractRenderState. Like entities, the render state is first constructed via BlockEntityRenderer#createRenderState before the values are extracted from the block entity. extractRenderState does contain the partial tick and camera position, but this is not passed to the BlockEntityRenderState by default.
As such, the submit method that takes over the render method takes in the render state, a PoseStack for the location in 3D space, the SubmitNodeCollector for pushing the elements to render, and the CameraRenderState.
// We will assume all the classes not specified here exist
// A simple render state
public class ExampleRenderState extends BlockEntityRenderState {
public float partialTick;
}
// A basic block entity renderer
public class ExampleBlockEntityRenderer implements BlockEntityRenderer<ExampleBlockEntity, ExampleRenderState> {
public ExampleBlockEntityRenderer(BlockEntityRendererProvider.Context ctx) {
// Get anything you need from the context
}
@Override
public ExampleRenderState createRenderState() {
// Create the render state used to submit the block entity to the feature renderer
return new ExampleRenderState();
}
@Override
public void extractRenderState(ExampleBlockEntity blockEntity, ExampleRenderState renderState, float partialTick, Vec3 cameraPos, @Nullable ModelFeatureRenderer.CrumblingOverlay crumblingOverlay) {
// Extract the necessary rendering values from the block entity to the render state
// Always call super or BlockEntityRenderState#extractBase
super.extractRenderState(blockEntity, renderState, partialTick, cameraPos, crumblingOverlay);
// Populate any desired values
renderState.partialTick = partialTick;
}
@Override
public void submit(ExampleRenderState renderState, PoseStack poseStack, SubmitNodeCollector collector, CameraRenderState cameraState) {
// An example of submitting something
collector.submitModel(..., renderState.breakProgress);
}
}
Special Item Models
Since special item models also make use of custom rendering, they have been updated to with the submit change, only replacing MultiBufferSource with the SubmitNodeCollector.
// A basic special item model
// We will assume all the classes listed exist
public class ExampleSpecialModelRenderer implements NoDataSpecialModelRenderer {
public ExampleSpecialModelRenderer() {}
@Override
public void submit(ItemDisplayContext displayContext, PoseStack poseStack, SubmitNodeCollector collector, int lightCoords, int overlayCoords, boolean hasFoil, int outlineColor) {
// An example of submitting something
collector.submitModelPart(...);
}
@Override
public void getExtents(Set<Vector3f> extents) {}
}
Particles
Particles have been added to the submission process; however, there are multiple paths depending on how complicated your particle is. A few classes and general names have been reused for an additional purpose as well, sometimes making it difficult to understand how each part works. As such, this document will go over two methods of creating a particle: one more familiar with the old system, and one that explains the underlying nuances from the ground up.
The Separation of Engines and Resources
Before we discuss the two methods, first, let’s go with the overarching changes. ParticleEngine has been functionally split up into two classes: ParticleEngine, which handle the actual ticking and extraction, not submission, of the render state; and ParticleResources, which is the reload listener that registers the ParticleProvider and optionally ParticleResources$SpriteParticleRegistration and reloads the SpriteSet from its ParticleDescription. This underlying behavior hasn’t change (besides the whole extract and submission process), the methods have simply been moved.
ParticleProvider#createParticle also now provides a RandomSource, which can be used as needed.
As for the actual submission and rendering process, this is handled outside of ParticleEngine. More specifically, the LevelRenderer extracts all the particles to submit in ParticlesRenderState via ParticleEngine#extract. Then, in LevelRenderer#addParticlesPass, the resource handles are set to the particle FramePass, to which on execution the particles are submitted via ParticlesRenderState#submit and then rendered through the feature dispatcher via ParticleFeatureRenderer.
A Single Quad
Many particles in the old system were simply made up of a single quad with a texture(s) slapped on it. These particles are SingleQuadParticles, which merges both the previous SingleQuadParticle and TextureSheetParticle into one. The SingleQuadParticle now takes in an initial TextureAtlasSprite to set the first texture, which can then be updated by overriding Particle#tick and calling SingleQuadParticle#setSpriteFromAge for a SpriteSet or directly with setSprite. The tint can also be modified in the tick using setColor and setAlpha. Some also set these directly in SingleQuadParticle#extract, but which to use depends on if you need to override the entire tick or not.
To determine the RenderType that is used to render the quad, SingleQuadParticle#getLayer must be set to the desired $Layer. A $Layer is basically a record defining whether the quad can have translucency, what texture atlas it pulls from, and the render pipeline to use. Vanilla provides TERRAIN, OPAQUE, and TRANSLUCENT similar to the old Particle#getRenderType which it replaces. TERRAIN and TRANSLUCENT both allow transparency, and OPAQUE and TRANSLUCENT pull from the particle atlas while TERRAIN uses the block atlas. A custom $Layer can be created using the constructor.
public static final SingleQuadParticle.Layer EXAMPLE_LAYER = new SingleQuadParticle.Layer(true, TextureAtlas.LOCATION_PARTICLES, RenderPipelines.WEATHER_DEPTH_WRITE);
In addition to all this, you can also set how the particle is rotated by overriding SingleQuadParticle#getFacingCameraMode. $FacingCameraMode is a functional interface that sets the rotation of the particle whenever it is extracted. By default, this means that the texture will always face the camera. Any other method changes and additions are in the list below.
From there, everything else is the same to create the ParticleProvider and register it.
// We will assume we have some SimpleParticleType EXAMPLE_QUAD for our particle
// Additionally, we will assume there is some particle description with our textures to use
public class ExampleQuadParticle extends SingleQuadParticle {
private final SpriteSet spriteSet;
// This can be package-private, protected, or public
// public should be used if the particle will be constructed outside of the provider
ExampleQuadParticle(ClientLevel level, double x, double y, double z, SpriteSet spriteSet) {
// We use first to set the initial particle texture
super(level, x, y, z, spriteSet.first());
}
@Override
public void tick() {
super.tick();
// Update the particle image
this.setSpriteFromAge(spriteSet);
}
@Override
public SingleQuadParticle.Layer getLayer() {
return EXAMPLE_LAYER;
}
// Create the provider
public static class Provider implements ParticleProvider<SimpleParticleType> {
private final SpriteSet spriteSet;
public Provider(SpriteSet spriteSet) {
this.spriteSet = spriteSet;
}
@Override
public Particle createParticle(SimpleParticleType options, ClientLevel level, double x, double y, double z, double xd, double yd, double zd, RandomSource random) {
// Create the particle
return new ExampleQuadParticle(level, x, y, z, this.spriteSet);
}
}
}
// Register the provider to `ParticleResources#register`
// Assume access to ParticleResources resources and register has been made public
resources.register(EXAMPLE_QUAD, ExampleQuadParticle.Provider::new);
From the Ground Up
What about rendering some more complex or custom? Well, in those instances, we need to take a deeper dive into how particles are extracted by the ParticleEngine. The Particle class, by itself actually does no extraction, submission, or rendering itself. It simply handles the physics update every tick. The actual extraction logic is handled through a ParticleGroup, while the submission is handled by a ParticleGroupRenderState.
So, what is a ParticleGroup? Well, as the name implies, a particle group holds a group of particles and is responsible for keeping track of, ticking, and extracting the render state of its particles. The generic represents the type of Particle it can keep track of up to the maximum of 16,384 per group (though individual particles can set their own subgroup limit via Particle#getParticleLimit). All SingleQuadParticles are part of the QuadParticleGroup. To extract the render state, the ParticleEngine calls ParticleGroup#extractRenderState, which takes in the current frustum, camera, and partial tick to return a ParticleGroupRenderState.
ParticleGroupRenderState is sort of a mix between a render state, submission handler, and cache. It contains two methods: submit, which takes in the SubmitNodeCollector and submits the group; and clear, which clears all previous cached particle states. Technically, anything can be submitted using the collector, but particles have SubmitNodeCollector$ParticleGroupRenderer: an additional utility to help with caching and rendering. The group renderer contains two methods: prepare, to write the mesh data to a ring buffer; and render, which typically uses the cached buffer to write the data to the shared sequential buffer using the provided RenderPass and draw it to the screen. Only QuadParticleRenderState makes use of the cache and ParticleGroupRenderer as the render states are currently cleared immediately after rendering.
To link the ParticleGroup to a Particle for use, we must set the ParticleRenderType using Particle#getGroup. ParticleRenderType, unlike the previous version, is simply a key for a ParticleGroup. This key is mapped to the group via ParticleEngine#createParticleGroup, and the submission/render order is determined by ParticleEngine#RENDER_ORDER. Both the method and the list must be patched for the particle to be properly managed by your group and extracted for submission.
// We will assume we have some SimpleParticleType EXAMPLE_ONE, EXAMPLE_TWO for our particles
// This example with construct two particles with the same base type to show how the group works
// Create the particle type
public static final ParticleRenderType EXAMPLE_TYPE = new ParticleRenderType("examplemod:example_type");
// Create our particles
public abstract class ExampleParticle extends Particle {
// You can handle passing to the particle group however you want
// Making the fields accessible or having a dedicated method
public final Model<Unit> model;
protected ExampleParticle(ClientLevel level, double x, double y, double z, Function<EntityModelSet, Model<Unit>> modelFactory) {
super(level, x, y, z);
this.model = modelFactory.apply(Minecraft.getInstance().getEntityModels());
}
@Override
public ParticleRenderType getGroup() {
// Set the particle type to our group
return EXAMPLE_TYPE;
}
@FunctionalInterface
public interface ExampleParticleFactory<P extends ExampleParticle> {
P create(ClientLevel level, double x, double y, double z);
}
protected static <P extends ExampleParticle> ParticleProvider<SimpleParticleType> createProvider(ExampleParticleFactory<P> factory) {
return (options, level, x, y, z, xd, yd, zd, random) -> factory.create(level, x, y, z);
}
}
public class ExampleOneParticle extends ExampleParticle {
ExampleOneParticle(ClientLevel level, double x, double y, double z) {
super(level, x, y, z, modelSet -> new Model.Simple(new ModelPart(Collections.emptyList(), Collections.emptyMap()), RenderType::entityCutoutNoCull));
}
public static ParticleProvider<SimpleParticleType> provider() {
return ExampleParticle.createProvider(ExampleOneParticle::new);
}
}
public class ExampleTwoParticle extends ExampleParticle {
private static final ParticleLimit LIMIT = new ParticleLimit(5);
ExampleTwoParticle(ClientLevel level, double x, double y, double z) {
super(level, x, y, z, modelSet -> new Model.Simple(new ModelPart(Collections.emptyList(), Collections.emptyMap()), RenderType::entityCutoutNoCull));
}
@Override
public Optional<ParticleLimit> getParticleLimit() {
// Limits the number of particles using the LIMIT subgroup to 5
// Note that since ParticleLimit is a record, any with the same limit will be considered as the same key
return Optional.of(LIMIT);
}
public static ParticleProvider<SimpleParticleType> provider() {
return ExampleParticle.createProvider(ExampleTwoParticle::new);
}
}
// Register the providers to `ParticleResources#register`
// Assume access to ParticleResources resources and register has been made public
resources.register(EXAMPLE_ONE, ExampleOneParticle.provider());
resources.register(EXAMPLE_TWO, ExampleTwoParticle.provider());
// Create the render state to submit all particles in the group
// Store whatever you need to submit to the node collector
public record ExampleGroupRenderState(List<Model<Unit>> models) implements ParticleGroupRenderState {
@Override
public void submit(SubmitNodeCollector collector) {
// Submit every particle
for (var model : this.models) {
collector.submitModel(model, ...);
}
}
}
// Create the particle group to keep track of the particles and create the render state
// Both EXAMPLE_ONE and EXAMPLE_TWO will be added to this group
public class ExampleParticleGroup extends ParticleGroup<ExampleParticle> {
public ExampleParticleGroup(ParticleEngine engine) {
super(engine);
}
@Override
public ParticleGroupRenderState extractRenderState(Frustum frustum, Camera camera, float partialTick) {
// Create the particle group to submit the particles
return new ExampleGroupRenderState(
this.particles.stream().map(particle -> particle.model).toList()
);
}
}
// Link the ParticleRenderType to its ParticleGroup
// Assume we have access to ParticleEngine engine
// Assume that ParticleEngine#RENDER_ORDER is made mutable and public
// Assume we can patch ParticleEngine#createParticleGroup
engine.RENDER_ORDER.add(EXAMPLE_TYPE);
// In ParticleEngine
private ParticleGroup<?> createParticleGroup(ParticleRenderType renderType) {
if (renderType == EXAMPLE_TYPE) {
// this is referring to the ParticleEngine
return new ExampleParticleGroup(this);
}
// ...
}
Atlas Handler Consolidation
The atlas handler has had some of its logic modified to consolidate other sprites and change how to obtain a TextureAtlasSprite.
First, map decorations, paintings, and GUI sprites are now proper atlases with their own sheets: Sheets#MAP_DECORATIONS_SHEET, PAINTINGS_SHEET, and GUI_SHEET respectively.
Obtaining the TextureAtlasSprite from said sheets are now completely routed through the MaterialSet: a functional interface that takes in a Material (basically a sheet location and texture location), and returns the associated TextureAtlasSprite. The MaterialSet handles texture grabs for item models, block entity renderers, and entity renderers:
// Here is an example material to grab the apple texture from the appropriate sheet
public static final Material APPLE = new Material(
TextureAtlas.LOCATION_BLOCKS, // The sheet where the item textures are stored
ResourceLocation.fromNamespaceAndPath("minecraft", "item/apple") // The texture name according to the sprite contents
);
// You can also do the same using Sheets.ITEMS_MAPPER.defaultNamespaceApply("apple")
// For some item model
public class ExampleUnbakedItemModel implements ItemModel.Unbaked {
// ...
@Override
public ItemModel bake(ItemModel.BakingContext ctx) {
TextureAtlasSprite appleTexture = ctx.materials().get(APPLE);
// ...
}
}
// For some special item model
public class ExampleUnbakedSpecialModel implements SpecialModelRenderer.Unbaked {
// ...
@Override
@Nullable
public SpecialModelRenderer<?> bake(SpecialModelRenderer.BakingContext ctx) {
TextureAtlasSprite appleTexture = ctx.materials().get(APPLE);
// ...
}
}
// For some block entity renderer
public class ExampleBlockEntityRenderer implements BlockEntityRenderer<ExampleBlockEntity> {
public ExampleBlockEntityRenderer(BlockEntityRendererProvider.Context ctx) {
TextureAtlasSprite appleTexture = ctx.materials().get(APPLE);
// ...
}
// ...
}
// For some entity renderer
public class ExampleEntityRenderer implements EntityRenderer<ExampleEntity, ExampleEntityState> {
public ExampleEntityRenderer(EntityRendererProvider.Context ctx) {
TextureAtlasSprite appleTexture = ctx.getMaterials().get(APPLE);
// ...
}
// ...
}
assets/minecraft/shaders/coreblit_screen.json->screenquad.json, using no-format triangles instead of positioned quadsposition_color_lightmap.*are removedposition_color_tex_lightmap.*are removed
com.mojang.blaze3d.vertexCompactVectorArray- An holder that smashes a list of float vectors into a single sequential array.MeshData$SortState#centroidsnow returns aCompactVectorArrayVertexSortingbyDistancenow takes in aVector3fcinstead of aVector3fsortnow takes in aCompactVectorArrayinstead of aVector3f[]
net.minecraft.client.MinecraftgetTextureAtlas->AtlasManager#getAtlasOrThrow, not one-to-onegetPaintingTextures,getMapDecorationTextures,getGuiSprites->getAtlasManager, not one-to-one
net.minecraft.client.animation.Keyframenow has an overload that takes in thepreTargetandpostTargetinstead of one simpletarget, taking in aVector3fcinstead of aVector3fnet.minecraft.client.entityClientAvatarEntity- The client data of the avatar.ClientAvatarState- The movement state of the avatar.ClientMannequin- The client version of theMannequinentity.
net.minecraft.client.guiGuiGraphicsrenderOutline->submitOutlinerenderDeferredTooltip->renderDeferredElements, not one-to-onesubmitBannerPatternRenderStatenow takes in aBannerFlagModelinstead of aModelPartGuiSpriteManagerclass is removed
net.minecraft.client.gui.render.GuiRenderernow takes in theSubmitNodeCollectorandFeatureRenderDispatcherMIN_GUI_Zis now public
net.minecraft.client.gui.render.pipGuiBannerResultRenderernow takes in aMaterialSetGuiSignRenderernow takes in aMaterialSet
net.minecraft.client.gui.render.state.TiledBlitRenderState- A render state for building a sprite using tiling, usually for tile or nine slice textures.net.minecraft.client.gui.render.state.pip.GuiBannerResultRenderStatenow takes in aBannerFlagModelinstead of aModelPartnet.minecraft.client.modelAbstractPiglinModel#createArmorMeshSet- Creates the model meshes for each of the humanoid armor slots.ArmedModelnow has a generic of theEntityRenderStatetranslateToHandnow takes in the entity render state
ArmorStandArmorModel#createBodyLayer->createArmorLayerSet, not one-to-oneBellModel$State- Represents the state of the backing object.BookModel$State- Represents the state of the backing object.BreezeModelcreateBodyLayer->createBaseMesh, now private- Replaced by
createBodyLayer,createWindLayer,createEyesLayer
- Replaced by
CopperGolemModel- A model for the copper golem entity.CopperGolemStatueModel- A model for the coper golem statue.CreakingModelNO_PARTS,getHeadModelPartsare removedcreateEyesLayer- Creates the eyes of the model.
EntityModel#setupAnim->Model#setupAnimGuardianParticleModel- The particle spawned from a guardian.HeadedModel#translateToHead- Transforms the pose stack to the head’s position and rotation.HumanoidArmorModel->HumanoidModel#createArmorMeshSet, not one-to-oneHumanoidModel#copyPropertiesTois removedModelnow takes in a generic representing the render statePlayerCapeModelnow extendsPlayerModelPlayerEarsModelnow extendsPlayerModelPlayerModelrender state has been broadened toAvatarRenderState- Static fields are now
protected createArmorMeshSet- Creates the model meshes for each of the humanoid armor slots.
- Static fields are now
SkullModelBase$State- Represents the state of the backing object.SpinAttackEffectModelgeneric has been broadened toAvatarRenderStateVillagerLikeModelnow takes in a generic for the render statehatVisibleis removed- Replaced by
VillagerModel#createNoHatModel
- Replaced by
translateToArmsnow takes in the render state
WardenModelcreateTendrilsLayer,createHeartLayer,createBioluminescentLayer,createPulsatingSpotsLayer- Creates the layers used by the warden’sRenderLayers.getTendrilsLayerModelParts,getHeartLayerModelParts,getBioluminescentLayerModelParts,getPulsatingSpotsLayerModelPartsare removed
ZombieVillagerModelcreateArmorLayer->createArmorLayerSet, not one-to-onecreateNoHatLayer- Creates the model without the hat layer.
net.minecraft.client.model.geom.ModelPartcopyFromis removed$Polygon#normalis now aVector3fcinstead of aVector3f$Vertexpos->x,y,zworldX,worldY,worldZ- Returns the coordinates scaled down by a factor of 16.
net.minecraft.client.model.geom.builders.PartDefinitionclearRecursively- Clears all children parts and its sub-children.retainPartsAndChildren- Retains the specified parts from its root and any sub-children.retainExactParts- Retains only the top level part, clearing out all others and sub-children.
net.minecraft.client.particleAttackSweepParticlenow extendsSingleQuadParticleBaseAshSmokeParticlenow extendsSingleQuadParticleand isabstractBlockMarkernow extendsSingleQuadParticleBreakingItemParticlenow extendsSingleQuadParticle- The constructor takes in a
TextureAtlasSpriteinstead of theItemStackRenderState $ItemParticleProvider#calculateState->getSprite, not one-to-one
- The constructor takes in a
BubbleColumnUpParticlenow extendsSingleQuadParticleBubbleParticlenow extendsSingleQuadParticleBubblePopParticlenow extendsSingleQuadParticleCampfireSmokeParticlenow extendsSingleQuadParticleCritParticlenow extendsSingleQuadParticleDragonBreathParticlenow extendsSingleQuadParticle$Providergeneric now uses aPowerParticleOption
DripParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpritecreate*Particlemethods ->$*Providerclasses
DustParticleBasenow extendsSingleQuadParticleElderGuardianParticleGroup- The particle group responsible for setting up and submitting the elder guardian particle.ExplodeParticlenow extendsSingleQuadParticleFallingDustParticlenow extendsSingleQuadParticleFallingLeavesParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteinstead of aSpriteSetFireflyParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteFireworkParticles$FlashProvidergeneric now usesColorParticleOption$OverlayParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSprite
FlameParticlenow takes in aTextureAtlasSpriteFlyStraightTowardsParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteFlyTowardsPositionParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteGlowParticlenow extendsSingleQuadParticleGustParticlenow extendsSingleQuadParticleHeartParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteHugeExplosionParticlenow extendsSingleQuadParticleItemPickupParticlenow takes in theEntityRenderStateinstead of theEntityRenderDispatcher- Fields are now all
protectedaside from the target entity
- Fields are now all
ItemPickupParticleGroup- The particle group responsible for setting up and submitting the item pickup particle.LavaParticlenow extendsSingleQuadParticleMobAppearanceParticle->ElderGuardianParticleNoRenderParticleGroup- The particle group that does nothing.NoteParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteParticlerCol,gCol,bCol,alpha->SingleQuadParticle#rCol,gCol,bCol,alpharoll,oRoll->SingleQuadParticle#roll,oRollsetColor,setAlpha->SingleQuadParticle#setColor,setAlpharender,renderCustom->ParticleGroupRenderState#submit, not one-to-onegetRenderType->getGroup- The original purpose of this method has been moved to
SingleQuadParticle#getLayer
- The original purpose of this method has been moved to
getParticleGroup->getParticleLimit, not one-to-one
ParticleEngineno longer implementsPreparableReloadListener- The constructor now takes in the
ParticleResourcesinstead of theTextureManager closeis removedupdateCountis nowprotectedrender->extract, not one-to-onedestroy->ClientLevel#addDestroyBlockEffectcrack->ClientLevel#addBreakingBlockEffectclearParticlesis nowpublic$MutableSpriteSet->ParticleResources$MutableSpriteSet$SpriteParticleRegistration->ParticleResources$SpriteParticleRegistration
- The constructor now takes in the
ParticleGroup- A holder of particles for a specificParticleRenderType, responsible for ticking and extracting the general render state.ParticleProvidercreateParticlenow takes in theRandomSource$Sprite#createParticlenow takes in theRandomSourceand returns aSingleQuadParticleinstead of aTextureSheetParticle
ParticleRenderTypeno longer takes in theRenderType- This record has been repurposed to represent a key for the particle groups
TERRAIN_SHEET->SingleQuadParticle$Layer#TERRAINPARTICLE_SHEET_OPAQUE->SingleQuadParticle$Layer#OPAQUEPARTICLE_SHEET_TRANSLUCENT->SingleQuadParticle$Layer#TRANSLUCENTCUSTOMis replaced by a particle group that is not forParticleRenderType#SINGLE_QUADS
ParticleResources- Loads the particle providers, any necessary descriptions, and computes them into their desired sprite set.PlayerCloudParticlenow extendsSingleQuadParticlePortalParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteQuadParticleGroup- The particle group responsible for setting up and submitting single quad particles.ReversePortalParticlenow takes in aTextureAtlasSpriteRisingParticlenow extendsSingleQuadParticleSculkChargeParticlenow extendsSingleQuadParticleSculkChargePopParticlenow extendsSingleQuadParticleSculkChargePopParticlenow extendsSingleQuadParticleShriekParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteSimpleAnimatedParticlenow extendsSingleQuadParticleand isabstractSingleQuadParticlenow takes in aTextureAtlasSpritesprite- The texture of the particle.render->extract, not one-to-one, now taking in theQuadParticleRenderStateinstead of aVertexConsumerrenderRotatedQuad->extractRotatedQuad, not one-to-one, now taking in theQuadParticleRenderStateinstead of aVertexConsumergetU0,getU1,getV0,getV1are no longer abstractgetLayer- Sets the render layer of the single quad.$Layer- The layer the single quad should render in.
SnowflakeParticlenow extendsSingleQuadParticleSpellParticlenow extendsSingleQuadParticleInstantProvidergeneric now usesSpellParticleOption
SplashParticlenow takes in aTextureAtlasSpriteSpriteSet#first- Returns the first texture in the sprite set.SuspendedParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteSuspendedTownParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteTerrainParticlenow extendsSingleQuadParticleTextureSheetParticleclass is removed, useSingleQuadParticleinsteadTrailParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteTrialSpawnerDetectionParticlenow extendsSingleQuadParticleVibrationSignalParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteWakeParticlenow extendsSingleQuadParticleWaterCurrentDownParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSpriteWaterDropParticlenow extendsSingleQuadParticleand takes in aTextureAtlasSprite
net.minecraft.client.player.AbstractClientPlayerfields are now stored withinClientAvatarStateelytraRot*->*CloakclientLevelis removedgetDeltaMovementLerped->addWalkedDistance, not one-to-oneupdateBob- Updates the bobbing motion of the camera.
net.minecraft.client.rendererEndFlashState- The render state of the end flashes.GameRenderernow takes in theBlockRenderDispatchergetSubmitNodeStorage- Gets the node submission for feature-like objects.getFeatureRenderDispatcher- Gets the dispatcher for rendering feature-like objects.getLevelRenderState- Gets the render state of dynamic features in a level.
ItemInHandRendererrenderItemnow takes in aSubmitNodeCollectorinstead of aMultiBufferSourcerenderHandsWithItemsnow takes in aSubmitNodeCollectorinstead of aMultiBufferSource$BufferSource
LevelRenderernow takes in theLevelRenderStateandFeatureRenderDispatchergetSectionRenderDispatcheris now nullabletickParticlesis removedaddParticleis removed
MapRenderernow takes in anAtlasManagerinstead of aMapDecorationTextureManagerrendernow takes in aSubmitNodeCollectorinstead of aMultiBufferSource
OrderedSubmitNodeCollector- A submission handler for holding elements to be drawn in a given order to the screen whenever the features are dispatched.OutlineBufferSourceno longer takes in any parameterssetColornow takes in a single integer
ParticleGroupRenderState- The render state for a group of particles.ParticlesRenderState- The render state for all particles.QuadParticleRenderState- The render group state for all single quad particles.RenderPipelinesGUI_TEXT- The pipeline for text in a gui.GUI_TEXT_INTENSITY- The pipeline for text intensity when not colored in a gui.
RenderStateShard#TRANSLUCENT_TARGET,PARTICLES_TARGETare removedRenderTypepipeline- TheRenderPipelinethe type uses.opaqueParticle,translucentParticleare removedsunriseSunset,celestialare removed
ScreenEffectRenderernow takes in aMaterialSetrenderScreenEffectnow takes in aSubmitNodeCollector
ShapeRendererrenderLineBoxnow takes in aPoseStack$Poseinstead of aPoseStackrenderFacenow takes in aMatrix4finstead of aPoseStack
SheetsGUI_SHEET,MAP_DECORATIONS_SHEET,PAINTINGS_SHEET- Atlas textures.BLOCK_ENTITIES_MAPPER- A mapper for block textures onto block entities.*COPPER*- Materials for copper chests.chooseMaterialnow takes in aChestRenderState$ChestMaterialTypeinstead of aBlockEntityandboolean
SkyRendererEND_SKY_LOCATIONis now privaterenderSunMoonAndStarsno longer takes in the buffer sourcerenderEndFlashno longer takes in the buffer sourcerenderSunriseAndSunsetno longer takes in the buffer source
SpecialBlockModelRenderervanillanow takes in aSpecialModelRenderer$BakingContextinstead of anEntityModelSetrenderByBlocknow takes in aSubmitNodeCollectorinstead of aMultiBufferSource, and an outline color
SubmitNodeCollection- An implementation ofOrderedSubmitNodeCollectorthat holds the submitted features in separate lists.SubmitNodeCollector- AnOrderedSubmitNodeCollectorthat provides a method to change the current order that an element will be rendered in.SubmitNodeStorage- A storage of collections held by some order.SkyRendererrenderEndFlash- Renders the end flashes.initTextures- Gets the texture for the used elements.extractRenderState- Extracts theSkyRenderStatefrom the current level.
WeatherEffectRendererrendernow takes in theWeatherRenderStateinstead of anint,float, andLevel- Those fields have moved to
extractRenderState
- Those fields have moved to
extractRenderState- Extracts theWeatherRenderStatefrom the current level.$ColumnInstanceis now public
WorldBorderRendererrendernow takes in theWorldBorderRenderStateinstead of theWorldBorderextract- Extracts theWorldBorderRenderStatefrom the current world border.
net.minecraft.client.renderer.blockBlockRenderDispatchernow takes in aMaterialSetMovingBlockRenderState- A render state for a moving block that implementsBlockAndTintGetter.LiquidBlockRenderer#setupSpritesnow take in theBlockModelShaperandMaterialSet
net.minecraft.client.renderer.blockentity- Most methods here that take in the
MultiBufferSourcehave been replaced by aSubmitNodeCollector, and aModelFeatureRenderer$CrumblingOverlayif the method is not used for item rendering - Most methods change their name from
render*tosubmit*, with the main submit method now using aBlockEntityRenderState - All
BlockEntityRenderers now have aBlockEntityRenderStategeneric AbstractEndPortalRenderer- A block entity renderer for the end portal.AbstractSignRenderergetSignModelnow returns aModel$SimplerenderSign->submitSign, now takes in aModel$Simpleand no longer takes in a tint color
BannerRendererhas an overload that takes in aSpecialModelRenderer$BakingContext- The
EntityModelSetconstructor now takes in theMaterialSet renderPatterns->submitPatternsnow takes in theMaterialSetandModelFeatureRenderer$CrumblingOverlay, theModelParthas been replaced with theModeland its render state, abooleanfor whether to use the entity glint, and an outline color- The overload with two additional
booleans has been removed
- The overload with two additional
renderSpecial->submitSpecial, now takes in the outline color
- The
BeaconRenderer#renderBeaconBeam->submitBeaconBeam, no longer takes in the game timelongBedRendererhas an overload that takes in aSpecialModelRenderer$BakingContext- The
EntityModelSetconstructor now takes in theMaterialSet renderSpecial->submitSpecial, now takes in the outline color
- The
BlockEntityRenderDispatchernow takes in theMaterialSetandPlayerSkinRenderCacherender->submit, now takes in theBlockEntityRenderStateinstead of aBlockEntity, no longer takes in the partial tickfloat, and takes in theCameraRenderStategetRenderernow has an overload that can get the renderer from itsBlockEntityRenderStatetryExtractRenderState- Gets theBlockEntityRenderStatefrom itsBlockEntitylevel,camera,cameraHitResultis removedpreparenow only takes in theCamerasetLevelis removed
BlockEntityRenderernow has another genericSrepresenting theBlockEntityRenderStaterender->submit, taking in theBlockEntityRenderState, thePoseStack, theSubmitNodeCollector, and theCameraRenderStatecreateRenderState- Creates the render state object.extractRenderState- Extracts the render state from the block entity.
BlockEntityRendererProvider$Contextis now a record, taking in aMaterialSetandPlayerSkinRenderCache- It now has another generic
Srepresenting theBlockEntityRenderState
- It now has another generic
CopperGolemStatueBlockRenderer- A block entity renderer for the copper golem statue.DecoratedPotRendererhas an overload that takes in aSpecialModelRenderer$BakingContext- The
EntityModelSetconstructor now takes in theMaterialSet renderoverload ->submit, now takes in the outline color
- The
HangingSignRenderercreateSignModelnow returns aModel$SimplerenderInHandnow takes in aMaterialSet
ShelfRenderer- A block entity renderer for a shelf.ShulkerBoxRendererhas an overload that takes in aSpecialModelRenderer$BakingContext- The
EntityModelSetconstructor now takes in theMaterialSet renderoverload ->submit, now takes in the outline color
- The
SignRenderercreateSignModelnow returns aModel$SimplerenderInHandnow takes in aMaterialSet
SkullBlockRenderer#submitSkull- Submits the skull model to the collector.SpawnerRenderer#renderEntityInSpawner->submitEntityInSpawner, now takes in theCameraRenderStateTestInstanceREnderernow takes in theBlockEntityRendererProvider$Context
- Most methods here that take in the
net.minecraft.client.renderer.blockentity.stateBannerRenderState- The render state for the banner block entity.BeaconRenderState- The render state for the beacon block entity.BedRenderState- The render state for the bed block entity.BellRenderState- The render state for the bell block entity.BlockEntityRenderState- The base render state for all block entities.BlockEntityWithBoundingBoxRenderState- The render state for a block entity with a custom bounding box.BrushableBlockRenderState- The render state for a brushable block entity.CampfireRenderState- The render state for the campfire block entity.ChestRenderState- The render state for the chest block entity.CondiutRenderState- The render state for the conduit block entity.CopperGolemStatueRenderState- The render state for the copper golem block entity.DecoratedPotRenderState- The render state for the decorated pot block entity.EnchantTableRenderState- The render state for the enchantment table block entity.EndGatewayRenderState- The render state for the end gateway block entity.EndPortalRenderState- The render state for the end portal block entity.LecternRenderState- The render state for the lectern block entity.PistonHeadRenderState- The render state for the piston head block entity.ShelfRenderState- The render state for the shelf block entity.ShulkerBoxRenderState- The render state for the shulker box block entity.SignRenderState- The render state for the sign block entity.SkullBlockRenderState- The render state for the skull block entity.SpawnerRenderState- The render state for the spawner block entity.TestInstanceRenderState- The render state for the test instance block entity.VaultRenderState- The render state for the vault block entity.
net.minecraft.client.renderer.culling.Frustumoffset- Offsets the position.pointInFrustum- Checks whether the provided coordinate is within the frustum.
net.minecraft.client.renderer.entity- Most methods here that take in the
MultiBufferSourceand light coordinates integer have been replaced bySubmitNodeCollectorand a render state param - Most methods change their name from
render*tosubmit* AbstractBoatRenderer#renderTypeAdditions->submitTypeAdditionsAbstractMinecartRenderer#renderMinecartContents->submitMinecartContentsAbstractSkeletonRenderertakes in aArmorModelSetinstead of aModelLayerLocationAbstractZombieRenderertakes in aArmorModelSetinstead of a modelArmorModelSet- A holder that maps some object to each humanoid armor slot. Typically holds the layer definitions, which are then baked into their associated models.BreezeRenderer#enableis removedCopperGolemRenderer- The renderer for the copper golem entity.DisplayRenderer#renderInner->submitInnerEnderDragonRenderer#renderCrystalBeams->submitCrystalBeamsEntityRenderDispatchernow takes in theAtlasManagerprepareno longer takes in theLevelsetRenderShadow,setRenderHitBoxes,shouldRenderHitBoxesare removedextractEntity- Creates the render state from the entity and the partial tick.render->submit, now takes in theCameraRenderStatesetLevel->resetCamera, not one-to-onegetPlayerRenderer- Gets theAvatarRendererfrom the given client player.overrideCameraOrientation,distanceToSqr,cameraOrientationare removed
EntityRendererNAMETAG_SCALEis now publicrender(S, PoseStack, MultiBufferSource, int)->submit(S, PoseStack, SubmitNodeCollector, CameraRenderState)renderNameTag->submitNameTag, now takes in aCameraRenderStatefinalizeRenderState- Extracts the information of the render state as a last step afterextractRenderState, such as shadows.
EntityRendererProvider$Contextnow takes in thePlayerSkinRenderCacheandAtlasManagergetModelManageris removedgetMaterials- Returns a mapper of material to atlas sprite.getPlayerSkinRenderCache- Gets the render cache of player skins.getAtlas- Returns the atlas for that location.
EntityRenderers#createPlayerRenderersnow returns a map ofPlayerModelTypes toAvatarRenderersItemEntityRendererrenderMultipleFromCount->submitMultipleFromCountrenderMultipleFromCount(PoseStack, MultiBufferSource, int, ItemClusterRenderState, RandomSource)->renderMultipleFromCount(PoseStack, SubmitNodeCollector, int, ItemClusterRenderState, RandomSource)
ItemRendererno longer takes in theItemModelResolvergetArmorFoilBuffer->getFoilRenderTypes, not one-to-onerenderStaticmethods are removed
MobRenderer#checkMagicName- Returns whether the custom name matches the given string.PiglinRenderertakes in aArmorModelSetinstead of aModelLayerLocationTntMinecartRenderer#renderWhiteSolidBlock->submitWhiteSolidBlock, now takes in an outline colorZombieRenderertakes in aArmorModelSetinstead of aModelLayerLocationZombifiedPiglinPiglinRenderertakes in aArmorModelSetinstead of aModelLayerLocation
- Most methods here that take in the
net.minecraft.client.renderer.entity.layersArrowLayernow deals withAvatarRenderStateinstead ofPlayerRenderStateBeeStingerLayernow deals withAvatarRenderStateinstead ofPlayerRenderStateBlockDecorationLayer- A layer that handles a block model transformed by an entity.BreezeWindLayernow takes in theEntityModelSetinstead of theEntityRendererProvider$ContextCapeLayernow deals withAvatarRenderStateinstead ofPlayerRenderStateCustomHeadLayernow takes in thePlayerSkinRenderCacheDeadmau5EarsLayernow deals withAvatarRenderStateinstead ofPlayerRenderStateEquipmentLayerRenderer#renderLayersnow takes in the render state,SubmitNodeCollector, outline color, and an initial order instead of aMultiBufferSourceHumanoidArmorLayernow takes inArmorModelSets instead of modelssetPartVisibilityis removed
ItemInHandLayer#renderArmWithItem->submitArmWithItemLivingEntityEmissiveLayernow takes in a function for the texture instead of aResourceLocationand a model instead of the$DrawSelector$DrawSelectoris removed
ParrotOnShoulderLayernow deals withAvatarRenderStateinstead ofPlayerRenderStatePlayerItemInHandLayernow deals withAvatarRenderStateinstead ofPlayerRenderStateRenderLayerrenderColoredCutoutModel,coloredCutoutModelCopyLayerRendernow takes in aModelinstead of anEntityModel, aSubmitNodeCollectorinstead of aMultiBufferSource, and an integer representing the order layer for renderingrender->submit, taking in aSubmitNodeCollectorinstead of aMultiBufferSource
SimpleEquipmentLayernow takes in an order integerSpinAttackEffectLayernow deals withAvatarRenderStateinstead ofPlayerRenderStateStuckInBodyLayernow has an additional generic for the render state, also taking in the render state in the constructornumStucknow takes in anAvatarRenderStateinstead of thePlayerRenderState
VillagerProfessionLayernow takes in two models
net.minecraft.client.renderer.entity.player.PlayerRenderer->AvatarRendererrender*Handnow takes in aSubmitNodeCollectorinstead of aMultiBufferSource
net.minecraft.client.renderer.entity.stateCopperGolemRenderState- The render state for the copper golem entity.DisplayEntityRenderState#cameraYRot,cameraXRot- The rotation of the camera.EntityRenderStateNO_OUTLINE- A constant that represents the color for no outline.outlineColor- The outline color of the entity.lightCoords- The packed light coordinates used to light the entity.shadowPieces,$ShadowPiece- Represents the relative coordinates of the shadow(s) the entity is casting.
FallingBlockRenderStatefields and implementations have all been moved toMovingBlockRenderStateLivingEntityRenderStateappearsGlowing->EntityRenderState#appearsGlowing, now a methodcustomNameis removed
PaintingRenderState#lightCoords->lightCoordsPerBlockPlayerRenderState->AvatarRenderStateuseItemRemainingTicks,swingingare removedshowDeadMouseEars->showExtraEars
SheepRenderStateidis removedisJebSheepis now a field instead of a method
WitherSkullRenderState#xRot,yRot->modeState, not one-to-one
net.minecraft.client.renderer.featureBlockFeatureRenderer- Renders the submitted blocks, block models, or falling blocks.CustomFeatureRenderer- Renders the submitted geometry via a passed function.FeatureRenderDispatcher- Dispatches all features to render from the submitted node collector objects.FlameFeatureRenderer- Renders the submitted entity on fire animation.HitboxFeatureRenderer- Renders the submitted entity hitbox.ItemFeatureRenderer- Renders the submitted items.LeashFeatureRenderer- Renders the submitted leash attached to entities.ModelFeatureRenderer- Renders the submittedModels.ModelPartFeatureRenderer- Renders the submittedModelParts.NameTagFeatureRenderer- Renders the submitted name tags.ParticleFeatureRenderer- Renders the submitted particles.ShadowFeatureRenderer- Render the submitted entity shadow.TextFeatureRenderer- Renders the submitted text.
net.minecraft.client.renderer.itemItemModel$BakingContextnow takes in aMaterialSetandPlayerSkinRenderCache, and implementsSpecialModelRenderer$BakingContextItemStackRenderState#render->submit, taking in aSubmitNodeCollectorinstead of aMultiBufferSourceand an outline color
net.minecraft.client.renderer.special- Most methods here that take in the
MultiBufferSourcehave been replaced bySubmitNodeCollector ChestSpecialRenderernow takes in aMaterialSet*COPPER*- Textures for the copper chest.
ConduitSpecialRenderernow takes in aMaterialSetCopperGolemStatueSpecialRenderer- A special renderer for the copper golem statue as an item.HangingSignSpecialRenderernow takes in aMaterialSetand aModel$Simpleinstead of aModelNoDataSpecialModelRenderer#render->submit, now takes in an outline colorPlayerHeadSpecialRenderernow takes in thePlayerSkinRenderCacheShieldSpecialRenderernow takes in aMaterialSetSpecialModelRendererrender->submit, now takes in an outline color$BakingContext- The context used to bake a special item model.$Unbaked#bakenow takes in aSpecialModelRenderer$BakingContextinstead of anEntityModelSet
SpecialModelRenderers#createBlockRenderersnow takes in aSpecialModelRenderer$BakingContextinstead of anEntityModelSetStandingSignSpecialRenderernow takes in aMaterialSetand aModel$Simpleinstead of aModel
- Most methods here that take in the
net.minecraft.client.renderer.stateBlockBreakingRenderState- The render state for how far the current block has been broken.BlockOutlineRenderState- The render state for the outline of a block via itsVoxelShapes.CameraRenderState- The render state of the camera.LevelRenderState- The render state of the dynamic features in a level.ParticleGroupRenderState- The render state for a group of particles.ParticlesRenderState- The render state for all particles.QuadParticleRenderState- The render group state for all single quad particles.SkyRenderState- The render state of the sky, including the moon and stars.WeatherRenderState- The render state of the current weather.WorldBorderRenderState- The render state of the world border.
net.minecraft.client.renderer.textureSkinTextureDownloaderis now an instance class rather than a static method holder, taking in aProxy,TextureManager, and the main threadExecutor- Most methods that were previously static are now instance methods
SpriteContentsnow takes in an optionalAnimationMetadataSectionandMetadataSectionType$WithValuelist instead of aResourceMetadatametadata->getAdditionalMetadata, not one-to-one
SpriteLoaderDEFAULT_METADATA_SECTIONSis removedstitchis now privaterunSpriteSuppliersis now privateloadAndStitch(ResourceManager, ResourceLocation, int, Executor)isn removedloadAndStitchnow takes a set ofMetadataSectionTypes instead of a collection$PreparationswaitForUploadis removedgetSprite- Returns the atlas sprite for a given resource location.
TextureAtlasSprite#isAnimated->SpriteContents#isAnimated
net.minecraft.client.renderer.texture.atlas.SpriteResourceLoader#createnow takes a set ofMetadataSectionTypes instead of a collectionnet.minecraft.client.resourcesMapDecorationTextureManagerclass is removedPaintingTextureManagerclass is removedPlayerSkin$Model->PlayerModelType, not one-to-one- The constructor not takes in the legacy service name
byName->byLegacyServicesName
SkinManagernow takes inServicesinstead of aMinecraftSessionService, and aSkinTextureDownloaderlookupInsecure->createLookup, now taking in a boolean of whether to check for insecure skinsgetOrLoad->get
TextureAtlasHolderclass is removed
net.minecraft.client.resources.modelAtlasIds->net.minecraft.data.AtlasIdsAtlasSet->AtlasManager, not one-to-oneforEach- Iterates through each of the atlas sheets.
Materialsprite->MaterialSet#getbuffernow takes in aMaterialSet
MaterialSet- A map of material to its atlas sprite.ModelBakerynow takes in aMaterialSetandPlayerSkinRenderCacheModelManageris no longerAutoCloseable- The constructor takes in the
PlayerSkinRenderCache,AtlasManagerinstead of theTextureManager, and the max mipmap levels integer getAtlas->MaterialSet#getupdateMaxMipLevel->AtlasManager#updateMaxMipLevel
- The constructor takes in the
net.minecraft.core.particlesParticleGroup->ParticleLimitParticleTypesDRAGON_BREATHnow uses aPowerParticleOptionEFFECTnow uses aSpellParticleOptionFLASHnow uses aColorParticleOptionINSTANT_EFFECTnow uses aSpellParticleOption
PowerParticleOption- A particle option for the dragon’s breath.SpellParticleOption- A particle option for potion effects.
The Font Glyph Pipeline
Glyphs have been partially reworked in the backend to both unify both characters and their effects to a single renderable and add a baking flow, albeit delayed. This will provide a brief overview of this new flow.
Let’s start from the top when the assets are reloaded, causing the FontManager to run. The font definitions are loaded and passed to their appropriate GlyphProviderDefinition, which for this example with immediately unpack into a GlyphProvider$Loader. The loader reads whatever information it needs (most likely a texture) and maps it to an associated codepoint as an UnbakedGlyph. An UnbakedGlyph represents a single character containing its GlyphInfo with the position metadata and a bake method to write it to a texture. bake takes in a UnbakedGlyph$Stitcher, which itself takes in a GlyphBitmap to correctly position and upload the glyph along with the GlyphInfo for any offset adjustments. Then, after and resolving and finalizing, the FontSets are created using FontSet#reload. This resets the textures and cache and calls FontSet#selectProviders to store the active list of GlyphProviders and populates the glyphsByWidth by mapping the character advance to a list of matching codepoints. At this point, all of the loading has been done. While the glyphs are stored in their unbaked format, they are not baked and cached until that specific character is rendered.
Now, let’s move onto the FontDescription. A FontDescription provides a one-to-one map to a GlyphSource, which is responsible for obtaining the glyphs. Vanilla provides three FontDescriptions: $Resource for mapping to the FontSet (the font JSON name) as mentioned above, $AtlasSprite to interpret an atlas as a bunch of glyphs, and $PlayerSprite for rendering the player head and hat. For a given Component, the FontDescription used can be set as its Style via Style#withFont.
So, let’s assume you are drawing text to the screen using FontDescription#DEFAULT, which uses the defined assets/minecraft/font/default.json. Eventually, this will either call Font#drawInBatch or drawInBatch8xOutline. Then, whether through the StringSplitter or directly, the GlyphSource is obtained from the FontDescription. Then, GlyphSource#getGlyph is called. For the FontDescription$AtlasSprite and $PlayerSprite, this just returns a wrapper around the texture in question. For the $Resource though, this internally calls FontSet#getGlyph, which stores the UnbakedGlyph as part of a FontSet$DelayedBake, which it then immediately resolves to the BakedGlyph by calling UnbakedGlyph#bake to write the glyph to some texture.
A BakedGlyph contains two methods: the GlyphInfo for the position metadata like before, and a method called createGlyph, which returns a TextRenderable: a renderer to draw the glyph to the screen. TextRenderable also has a subinterface called PlainTextRenderable for help with texture sprites. Internally, all resource BakedGlyphs are BakedSheetGlyphs, as the UnbakedGlyph$Stitcher#stitch called just wraps around GlyphStitcher#stitch. You can think of the BakedSheetGlyph as a view onto a 256x256 FontTextures, where if there is not enough space on one FontTexture, then a new FontTexture is created.
BakedSheetGlyph also implements EffectGlyph, which is likely supposed to render some sort of effect on the text. This functionality, while it is currently implemented as just another object, is only used for the white glyph, which goes unused.
Object Info
ObjectInfos are the server side implementations to construct the FontDescription used to render an arbitrary object through the glyph pipeline. Each info takes in the FontDescription and a regular String to display a simple description. Additionally, it takes in a MapCodec to encode and decode from the object contents.
Note that for custom FontDescriptions to map to a source properly, you will need to somehow modify FontManager$CachedFontProvider#getGlyphSource or implement a custom Font$Provider.
// A basic font description
public static record BlockDescription(Block block) implements FontDescription {}
// A simple object info
public record BlockInfo(Block block) implements ObjectInfo {
// The codec to send the information over the network
public static final MapCodec<BlockInfo> MAP_CODEC = BuiltInRegistries.BLOCK.byNameCodec().fieldOf("block");
@Override
public FontDescription fontDescription() {
// The font description to render
return new BlockDescription(this.block);
}
@Override
public String description() {
// Just a text description of the object
return Objects.toString(BuiltInRegistries.BLOCK.getKey(this.block));
}
@Override
public MapCodec<? extends ObjectInfo> codec() {
return MAP_CODEC;
}
}
// Create the `GlyphSource` and `PlainTextRenderable` used to render the object
public record BlockRenderable(...) implements PlainTextRenderable {
// ...
}
public static GlyphSource create(Block block) {
return new SingleSpriteSource(...);
}
The ObjectInfo also needs to be rendered to ObjectInfos#ID_MAPPER:
// Assumes the the mapper has been made public
ObjectInfos.ID_MAPPER.put("examplemod:block", BlockInfo.MAP_CODEC);
Component Contents
Component contents also now use an id mapper instead of holding the id on the type. This means that creating a custom component is done by somehow hooking into ComponentSerialization#bootstrap and registering the map codec of your ComponentContents implementation to the mapper.
Data Sources
Data sources has received a similar treatment to component contents, now using an id mapper instead of holding the id on the type. The data source is then registered by registering to DataSources#ID_MAPPER the map codec of your DataSource. Note that the mapper field is private, so you will probably need to use an available workaround.
com.mojang.blaze3d.fontGlyphInfobake->UnbakedGlyph#bake, now takes in aUnbakedGlyph$Stitcherinstead of a function- The function behavior is replaced by
UnbakedGlyph$Stitcher#stitch
- The function behavior is replaced by
$SpaceGlyphInfo->GlyphInfo#simpleandEmptyGlyph, not one-to-one$Stitched->UnbakedGlyph, not one-to-one
GlyphProvider#getGlyphnow returns anUnbakedGlyphSheetGlyphInfo->GlyphBitmap
net.minecraft.client.guiFontno longer takes in a function and boolean, instead aFont$Providerrandomis now private$GlyphVisitoracceptGlyphnow takes in aTextRenderableinstead of aBakedGlyph$GlyphInstanceacceptEffectnow only takes in aTextRenderable
$PreparedTextBuilder#acceptnow has an override that takes in aBakedGlyphinstead of its codepoint$Provider- A simple interface for providing the glyph source based on its description, along with the empty glyph.
GlyphSource- An interface that holds the baked glyphs based on its codepoint.
net.minecraft.client.gui.fontAtlasGlyphProvider- A glyph provider based off a texture atlas.FontManagernow takes in theAtlasManagerandPlayerSkinRenderCacheFontSetnow takes in aGlyphStitcherinstead of aTextureManagerand no longer takes in the namenameis removedsource- Returns the glyph source depending given whether only non-fishy glyphs should be seen.getGlyphInfo,getGlyph->getGlyph, now package-private, not one-to-onegetRandomGlyphnow takes in aRandomSourceand a codepoint instead of theGlyphInfo, returning aBakedGlyphwhiteGlyphnow returns anEffectGlyph$GlyphSource- A source that can get the glyphs to bake.
FontTexture#addnow takes in aGlyphInfoandGlyphBitmap, returning aBakedSheetGlyphGlyphStitcher- A class that createsBakedGlyphs from its glyph information.PlainTextRenderable- An implementation ofTextRenderablethat determines how a sprite is rendered.PlayerGlyphProvider- A glyph provider for rendering the player head and hat.SingleSpriteSource- A glyph source that only contains one glyph, such as a texture.TextRenderable- Represents how a text representation, like a glyph in a font, is rendered.
net.minecraft.client.gui.font.glyphsBakedGlyphis now an interface that creates the renderable object- It original purpose has been moved to
BakedSheetGlyph
- It original purpose has been moved to
EffectGlyph- An interface that creates the renderable effect of some glyph.EmptyGlyphnow implementsUnbakedGlyphinstead of extendingBakedGlyph- The constructor takes in the text advance of the glyph.
SpecialGlyphs#bakenow returns aBakedSheetGlyph- This method is technically new.
net.minecraft.client.gui.font.providersBitmapProvider$Glyphnow implementsUnbakedGlyphinstead ofGlyphInfo$StitchedUnihexProvider$Glyphnow implementsUnbakedGlyphinstead ofGlyphInfo$Stitched
net.minecraft.client.gui.render.stateGlyphEffectRenderStateis removed- Use
GlyphRenderState
- Use
GlyphRenderStatenow takes in aTextRenderableinstead of aBakedGlyph$Instance
net.minecraft.network.chatComponent#object- Creates a mutable component with object contents.ComponentContents#type->codec, dropping the string id$Typeis removed
ComponentSerializationcreateLegacyComponentMatcherno longer requires aStringRepresentablegeneric, instead taking in a id mapper usingStringkeys$FuzzyCodecnow takes in a collection of map codecs instead of a list
FontDescription- An identifier that describes a font, typically as a location or sprite.Styleis now finalgetFontnow returns aFontDescriptionwithFontnow takes in aFontDescriptioninstead of aResourceLocationDEFAULT_FONTis removed
net.minecraft.network.chat.contentsBlockDataSource->.data.BlockDataSourceDataSource->.data.DataSourcetype->codec, dropping the string id
EntityDataSource->.data.EntityDataSource*ContentsCODEC->MAP_CODECTYPEis removed
ObjectContents- An arbitrary piece of content that can be written as part of a component, like a sprite.StorageDataSource->.data.StorageDataSource
net.minecraft.network.chat.contents.data.DataSources- All vanilla-registered data sources.net.minecraft.network.chat.contents.objectsAtlasSprite- An object info for a sprite in a texture atlas.ObjectInfo- Information relating the references for an arbitrary object through the glyph pipeline.ObjectInfos- All vanilla object infos.PlayerSprite- An object info for a player head and hat texture.
The JSON-RPC Management Servers
Minecraft has introduced support for remotely managing dedicated servers through a JSON-RPC websocket. This can be enabled through the management-server-enabled property, which listens for a server on localhost:25585 by default. The entire system handles not only constructing the network requests sent via JsonElements, but also the schemas each request uses. These schemas can then be generated through the JsonRpcApiSchema data provider.
There are two types of RPC methods supported by the system: IncomingRpcMethods for requests from the management server, and OutgoingRpcMethods to either notify or request information from the management server. Both of these are static registry objects, but rather than implementing the interfaces, they are typically constructed and registered through their associated builders.
Schemas
Schemas, as the name implies, are the specification of the JSON objects. They are constructed in a similar fashion JsonElements. Most are constructed as Schema#records, with their field and types being populated via withField, before being stored in a SchemaComponent, which maps a reference name to the schema. Then the Schemas can be obtained via asRef or asArray to get the object or array implementation, respectively. The SchemaComponents themselves and registered to the list Schema#SCHEMA_REGISTRY for reference resolving.
// An example json for changing the weather:
{
"weather": "clear|rain|thunder",
"duration": -1,
}
Here is what the associated schema component would look like:
public static final SchemaComponent WEATHER_SCHEMA = new SchemaComponent(
// The reference name
// While we can use colon, it would need to be percent encoded as defined by RFC 3986
"examplemod_weather",
// The schema to use
Schema.record()
.withField("weather", Schema.ofEnum(List.of("clear", "rain", "thunder")))
.withField("duration", Schema.INT_SCHEMA)
);
// Register the schema to the registry
Schema.getSchemaRegistry().add(WEATHER_SCHEMA);
Note that schemas currently cannot specify whether an individual property is optional or not.
IncomingRpcMethod
IncomingRpcMethods are constructed and registered through the method builder. These methods take in the handler function to update the minecraft server, a codec for the result, and an optional codec for the parameters sent from the management server. From there, the builder contains methods towards the discovery service and how to execute the method. $IncomingRpcMethodBuilder#response and param define the parameters and response sent by the management server. description is used by the discovery service for the schemas. undiscoverable hides the route by default. Finally, notOnMainThread tells the method that it can run off the main thread. Once the desired methods are called, then either build or register can be used to construct the object, taking in the route endpoint as a namespace and path.
The methods passed in take in the MinecraftApi for communicating with the dedicated server through specified ‘services’, and the current ClientInfo connection. It also takes in the parameter object if it exists.
// Construct the dto object
public record WeatherDto(String weather, int duration) {
public static final Codec<WeatherDto> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
Codec.STRING.fieldOf("weather").forGetter(WeatherDto::weather),
Codec.INT.fieldOf("duration").forGetter(WeatherDto::duration),
)
.apply(instance, WeatherDto::new)
);
// Create the incoming method handler
public static WeatherDto handleWeather(MinecraftApi api, WeatherDto params, ClientInfo info) {
// Note that the api makes the server private since it expects the
// logic to be handled through one of the middle layer services.
// We will assume the `server` field was made public somehow.
if (params.weather().equals("clear")) {
api.server.overworld().setWeatherParameters(params.duration(), 0, false, false);
} else if (params.weather().equals("rain")) {
api.server.overworld().setWeatherParameters(0, params.duration(), true, false);
} else if (params.weather().equals("thunder")) {
api.server.overworld().setWeatherParameters(0, params.duration(), true, true);
}
return params;
}
}
// Construct and register the method endpoint
IncomingRpcMethod.method(
// The handler method
WeatherDto::handleWeather,
// The codec for the parameters
WeatherDto.CODEC,
// The codec for the result
WeatherDto.CODEC
)
// Sets the description of the route
.description("Sets the weather")
// The parameters
.param(new ParamInfo(
// The name of the object
"weather",
// The schema
WEATHER_SCHEMA.asRef()
))
// The response
.response(new ResultInfo(
// The name of the object
"weather",
// The schema
WEATHER_SCHEMA.asRef()
))
// Build and register the route
.register(
BuiltInRegistries.INCOMING_RPC_METHOD,
// The endpoint namespace
"examplemod",
// The endpoint path
"weather/update"
);
OutgoingRpcMethod
OutgoingRpcMethods are constructed and registered through the notification or request builder. Notifications typically only send parameters with no returned result, while requests provide a result as well. In either case, they just take in codecs for the params or result when present. $OutgoingRpcMethod#response and param define the parameters and response sent by the minecraft server. description is used by the discovery service for the schemas. Once the desired methods are called, then register can be used to construct the object, taking in the route endpoint as a namespace and path and wrapping it in a Holder$Reference.
Currently, vanilla only broadcasts notifications through the NotificationService: a remote logger for specific method actions, like player join or changing game rule. While there are results, they must be read via Connection#sendRequest and handled asynchronously.
// Construct the outgoing method
// Since the minecraft server will be sending these, we need to hold the object
public static final Holder.Reference<OutgoingRpcMethod.ParmeterlessNotification> SOMETHING_HAPPENED = OutgoingRpcMethod.notification()
.description("Something happened!")
.register("examplemod", "something");
// Send notification, assume we have access to the `ManagementServer` managementServer
managementServer.forEachConnection(connection -> connection.sendNotification(SOMETHING_HAPPENED));
net.minecraft.SharedConstants#RPC_MANAGEMENT_SERVER_API_VERSION- The API version for JSON RPC server management.net.minecraft.core.registriesBuiltInRegistries,RegistriesINCOMING_RPC_METHOD- Registry for queries to the RPC service.OUTGOING_RPC_METHOD- Registry for broadcasts from the RPC service.
net.minecraft.serverMinecraftServernotificationManager- Returns the current notification manager.onGameRuleChanged- Handles what happens when the game rule of the current server changes.getOperatorUserPermissionLevel->operatorUserPermissionLevelisLevelEnabled->isAllowedToEnterPortal, not one-to-onesetPvpAllowedreplaced byGameRules#RULE_PVPsetFlightAllowedreplaced byDedicatedServerProperties#allowFlightisCommandBlockEnabledis no longer abstractisSpawnerBlockEnabled- Returns whether spawner blocks can spawn entities.getPlayerIdleTimeout->playerIdleTimeoutkickUnlistedPlayersno longer takes in theCommandSourceStackpauseWhileEmptySeconds->pauseWhenEmptySecondsgetSpawnProtectionRadius->DedicatedServer#spawnProtectionRadiusisUsingWhiteList- Handles enabling whitelist users for the server.setAutoSave,isAutoSave- Handles whether the server should auto save every so often.
net.minecraft.server.dedicatedDedicatedServernow takes in aLevelLoadListenerinstead of aChunkProgressListenerFactorysetAllowFlight- Sets whether the players can fly in the server.setDifficulty- Sets the game difficulty of the server.viewDistance,setViewDistance- Handles the view distance of the server (renderable chunks).simulationDistance,setSimulationDistance- Handles the simulation distance of the server (logic running chunks).setMaxPlayers- Sets the maximum number of players that can join the server.setSpawnProtectionRadius- Sets the radius of chunks that should be under spawn protection.setRepliesToStatus- Sets whether the game uses the legacy query handler.setHidesOnlinePlayers- Sets whether online players should be hidden from other players.setOperatorUserPermissionLevel- Sets the permission level of operator users.statusHeartbeatInterval,setStatusHeartbeatInterval- Handles the interval that the management server will check the minecraft server is still alive.entityBroadcastRangePercentage,setEntityBroadcastRangePercentage- Handles the broadcast range scalar for entity tracking.forceGameMode,setForceGameMode- Handles forcing all game modes for the users.gameMode,setGameMode- Sets the default game mode of the server.setAcceptsTransfers- Sets whether the server accepts client transfers from other servers.setPauseWhenEmptySeconds- Sets the number of seconds that the server should wait until it stops ticking when there are no players.
DedicatedServerPropertiespvpreplaced byGameRules#RULE_PVPallowFlight,motd,forceGameMode,enforceWhitelist,difficulty,gameMode,spawnProtection,opPermissionLevel,viewDistance,simulationDistance,enableStatus,hideOnlinePlayers,entityBroadcastRangePercentage,pauseWhenEmptySeconds,acceptsTransfersare now mutable propertiesallowNetherreplaced byGameRules#RULE_ALLOW_NETHERspawnMonstersreplaced byGameRules#RULE_SPAWN_MONSTERSenabledCommandBlockreplaced byGameRules#RULE_COMMAND_BLOCKS_ENABLEDmanagementServerEnabled- Returns whether a management server is enabled.managementServerHost- Returns the host the management server is communicating on.managementServerPort- Returns the port the management server is communicating on.statusHeartbeatInterval- Returns the heartbeat interval the management server sends to make sure the minecraft server is still alive.MANAGEMENT_SERVER_TLS_ENABLED_KEY,MANAGEMENT_SERVER_TLS_KEYSTORE_KEY,MANAGEMENT_SERVER_TLS_KEYSTORE_PASSWORD_KEY- TLS keystore setup for communication with the management server.managementServerSecret- The authorization token secret.managementServerTlsEnabled- If TLS should be used as the communication protocol.managementServerTlsKeystore- Specifies the filepath used for the TLS keystore.managementServerTlsKeystorePassword- Specifies the password for the keystore file.
Settings#getMutable- Gets a mutable property for the settings key and default.
net.minecraft.server.jsonrpcConnection- The inbound handler for json elements sent by the management server.IncomingRpcMethod- A definition and handler for the incoming message sent by the management server.IncomingRpcMethods- All vanilla incoming RPC handlers.JsonRPCErrors- An enum of errors that can be thrown when attempting to read, parse, or execute the method.JsonRpcLogger- A general logger for things performed by the minecraft server, whether communication or logic.JsonRpcNotificationService- A notification service that broadcasts to all connected minecraft servers.JsonRPCUtils- A utility for request objects and errors.ManagementServer- A basic websocket comms for the minecraft server to communicate with the management server.OutgoingRpcMethod- A definition and handler for outgoing requests to the management server.OutgoingRpcMethods- All vanilla outgoing RPC handlers.PendingRpcRequest- A pending request made by the minecraft server to the management server.
net.minecraft.server.jsonrpc.apiMethodInfo- Defines a method that is handled by the management server, either inbound or outbound.ParamInfo- Defines the parameters a specific method takes in.PlayerDto- A data transfer object representing the player.ReferenceUtil- A utility for creating a local reference URI.ResultInfo- Defines the response a specific method returns.Schema- An implementation of the json schema used the discovery service, parameters, and results.SchemaComponent- A reference definition of some component within a schema.
net.minecraft.server.jsonrpc.dataprovider.JsonRpcApiSchema- A data provider that generates the json schema from the discovery service.net.minecraft.server.jsonrpc.internalapiGameRules- An api that gets the current game rule value.MinecraftAllowListService- A minecraft middle layer that handles communication from the management server about the allow list.MinecraftAllowListServiceImpl- The allow list implementation.MinecraftApi- A minecraft api that handles all the services that communicate with the management server.MinecraftBanListService- A minecraft middle layer that handles communication from the management server about the ban list.MinecraftBanListServiceImpl- The ban list implementation.MinecraftExecutorService- A minecraft middle layer that submits an arbitrary runnable or supplier to execute on the server.MinecraftExecutorServiceImpl- The executor implementation.MinecraftGameRuleService- A minecraft middle layer that handles communication from the management server about the game rules.MinecraftExecutorServiceImpl- The executor implementation.MinecraftOperatorListService- A minecraft middle layer that handles communication from the management server about the operator commands.MinecraftOperatorListServiceImpl- The operator list implementation.MinecraftPlayerListService- A minecraft middle layer that handles communication from the management server about the player list.MinecraftPlayerListServiceImpl- The player list implementation.MinecraftServerSettingsService- A minecraft middle layer that handles communication from the management server about the server settings.MinecraftServerSettingsServiceImpl- The server settings implementation.MinecraftServerStateService- A minecraft middle layer that handles communication from the management server about the current server state and send messages.MinecraftServerStateServiceImpl- The server state implementation.
net.minecraft.server.jsonrpc.methodsAllowlistService- A service that handles communication from the management server about the allow list.BanlistService- A service that handles communication from the management server about the player ban list.ClientInfo- An identifier for the current minecraft server connection to the management server.DiscoveryService- A service that displays the schemas of all services supported by the management server.EncodeJsonRpcException- An exception thrown when attempting to encode the json packet.GameRulesService- A service that handles communication from the management server about the game rules.IllegalMethodDefinitionException- An exception thrown when the method definition provided is illegal.InvalidParameterJsonRpcException- An exception thrown when the parameters to the method are invalid.InvalidRequestJsonRpcException- An exception thrown when the request is invalid.IpBanlistService- A service that handles communication from the management server about the ip ban list.Message- A data transfer object representing a literal or translatable component.MethodNotFoundJsonRpcException- An exception thrown when a 404 error occurs, indicating that the method doesn’t exist.OperatorService- A service that handles communication from the management server about the operator commands.PlayerService- A service that handles communication from the management server about the player list.RemoteRpcErrorException- An exception thrown when something goes wrong on the management server.ServerSettingsService- A service that handles communication from the management server about the server settings.ServerStateService- A service that handles communication from the management server about the current server state and send messages.
net.minecraft.server.jsonrpc.securityAuthenticationHandler- Handles the validation of the authentication token bearer in the request.JsonRpcSslContextProvider- Provides the keystore context for the TLS communication.SecurityConfig- Handles the secret key, from checking basic validaty to generating a new one.
net.minecraft.server.jsonrpc.websocketJsonToWebSocketEncoder- A message to message encoder for a json.WebSocketToJsonCodec- A message to message decoder for a json.
net.minecraft.server.notificationsEmptyNotificationService- A notification service that does nothing.NotificationManager- A manager for handling multiple notification services.NotificationService- A service that defines prospective actions taken by a listener, like a management server.
net.minecraft.server.playersBanListEntrygetReasoncan now benullgetReasonMessage- Returns the translatable component of the ban reason.
IpBanListnow takes in theNotificationServiceadd,remove- Handles entries on the list.
PlayerListnow takes in theNotificationServiceinstead of the max playersmaxPlayersis removedopnow has an override for the permission level and bypass limit booleansetUsingWhiteList->MinecraftServer#setUsingWhiteListgetPlayer- Gets a player by their name.
ServerOpListnow takes in theNotificationServiceadd,remove- Handles entries on the list.
StoredUserEntry#getUseris now publicStoredUserListnow takes in theNotificationServiceadd,removenow return a boolean if successfulremove(StoredUserEntry<K>)is removedclear- Clears all stored users.
UserBanListnow takes in theNotificationServiceadd,remove- Handles entries on the list.
UserWhiteListnow takes in theNotificationServiceadd,remove- Handles entries on the list.
Input Handling Consolidation
Input handling has previously passed around the raw values, each in their own separate argument, provided by GLFW. However, a good bit of the handling logic is redundant, as specific keys are commonly checked, or all values are passed around in a game of hot potato from one method to the next. With this in mind, the input handlers in GuiEventListener and other calls, are now handled through event objects. These objects still contain the info GLFW passed through; however, now they have a lot of common checks through the super InputWithModifiers interface.
There are two types of events: KeyEvents for key presses, and MouseButtonEvents for mouse presses. Key, scancode, and modifiers are wrapped into the KeyEvent. Button, modifiers, and the XY screen position are wrapped into the MouseButtonEvent. As such, it is generally a drag-and-drop replacement of just removing any of the parameters mentioned above and replacing them with their appropriate event.
Key Mapping Categories
Key mappings have changed slightly, no longer taking in a raw string for its category, and instead using a KeyMapping$Category record, which is essentially a namspaced string. Categories can be created using KeyMapping$Category#register; otherwise, an error will be thrown whenever the mapping is used as part of a comparator.
public static final KeyMapping.Category EXAMPLE = KeyMapping.Category.register(ResourceLocation.withNamespaceAndPath("examplemod", "example"));
Double-Click Expansion
GuiEventListener#mouseClicked now takes in whether the click was in fact a double-click as a boolean.
// For some Screen subclass (or AbstractWidget or any GUI object rendering)
@Override
public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
// ...
return false;
}
com.mojang.blaze3d.platform.InputConstantsMOD_SHIFT,MOD_ALT,MOD_SUPER,MOD_CAPS_LOCK,MOD_NUM_LOCK- Modifier keys to transform a key input.KEY_LWIN,KEY_RWIN->KEY_LSUPER,KEY_RSUPERgetKeynow takes in aKeyEventinstead of the key and scancodeintsisKeyDown,setupKeyboardCallbacks,setupMouseCallbacks,grabOrReleaseMouse,updateRawMouseInputnow take in aWindowinstead of thelonghandle
net.minecraft.clientKeyboardHandlerkeyPressis now privatesetupnow takes in aWindowinstead of thelonghandle
KeyMappingnow takes in a$Categoryinstead of aStringshouldSetOnIngameFocus- Returns whether the key is mapped to some value on the keyboard.restoreToggleStatesOnScreenClosed- Restores the toggled keys to its state during in-game actions.keyis now protectedreleaseis now protectedCATEGORY_*->$Category#*- Key can be obtained via
$Category#id - Component is available through
$Category#label
- Key can be obtained via
getCategorynow returns a$Categoryinstead of aStringmatchesnow takes in aKeyEventinstead of the key and scancodeintsmatchesMousenow takes in aMouseButtonEventinstead of the buttonint
Minecraft#ON_OSX->InputQuirks#ON_OSXMouseHandler#setupnow takes in aWindowinstead of thelonghandleToggleKeyMappingnow has an overload that takes in an input type- The constructor now takes in a
KeyMapping$Categoryinstead of aString, and abooleanthat represents if the previous state of the key binding should be restored
- The constructor now takes in a
net.minecraft.client.gui.componentsAbstractButton#onPressnow takes in anInputWithModifiersAbstractScrollArea#updateScrollingnow takes in aMouseButtonEventinstead of the button info and XY positionsAbstractWidgetonClicknow takes in aMouseButtonEventinstead of the XY positions and whether the button was double-clickedonReleasenow takes in aMouseButtonEventinstead of the XY positionsonDragnow takes in aMouseButtonEventinstead of the XY positionsisValidClickButtonnow takes in theMouseButtonInfoinstead of the buttonint
CommandSuggestionskeyPressednow takes in aKeyEventinstead of the key, scancode, modifiersintmouseClickednow takes in aMouseButtonEventinstead of the button info and XY positions$SuggestionsListmouseClickedno longer takes in the buttonintkeyPressednow takes in aKeyEventinstead of the key, scancode, modifiersint
MultilineTextField#keyPressednow takes in aKeyEventinstead of the keyint
net.minecraft.client.gui.components.events.GuiEventListenerDOUBLE_CLICK_THRESHOLD_MS->MouseHandler#DOUBLE_CLICK_THRESHOLD_MSmouseClickednow takes in aMouseButtonEventinstead of the button info and XY positions, and whether the button was double-clickedmouseReleasednow takes in aMouseButtonEventinstead of the button info and XY positionsmouseDraggednow takes in aMouseButtonEventinstead of the button info and XY positionskeyPressednow takes in aKeyEventinstead of the key, scancode, modifiersintkeyReleasednow takes in aKeyEventinstead of the key, scancode, modifiersintcharTypednow takes in aCharacterEventinstead of the codepointcharand modifiersint
net.minecraft.client.gui.font.TextFieldHelpercharTypednow takes in aCharacterEventinstead of the codepointcharkeyPressednow takes in aKeyEventinstead of the keyint
net.minecraft.client.gui.navigation.CommonInputsclass is removedselected->InputWithModifiers#isSelectionconfirm->InputWithModifiers#isConfirmation
net.minecraft.client.gui.screens.ScreenhasControlDown->Minecraft#hasControlDown,InputWithModifiers#hasControlDownhasShiftDown->Minecraft#hasShiftDown,InputWithModifiers#hasShiftDownhasAltDown->Minecraft#hasAltDown,InputWithModifiers#hasAltDownisCut->InputWithModifiers#isCutisPaste->InputWithModifiers#isPasteisCopy->InputWithModifiers#isCopyisSelectAll->InputWithModifiers#isSelectAll
net.minecraft.client.gui.screens.inventory.AbstractContainerScreenhasClickedOutsideno longer takes in the buttonintcheckHotbarKeyPressednow takes in aKeyEventinstead of the key and modifiersint
net.minecraft.client.gui.screens.options.controls.KeyBindsList$CategoryEntrynow takes in aKeyMapping$Categoryinstead of theComponentnet.minecraft.client.gui.screens.recipebookhasClickedOutsideno longer takes in the buttonintRecipeBookPage#mouseClickednow takes in aMouseButtonEventinstead of the button info and XY positions, and whether the button was double-clicked
net.minecraft.client.inputCharacterEvent- Some kind of input interaction generates a codepoint with the currently active modifiers.InputQuirks- A utility for quirks between operating systems when handling inputs.InputWithModifiers- Defines an input with the currently active modifiers, along with some common input checks.KeyEvent- Some kind of input interaction generates a key by the scancode with the currently active modifiers.MouseButtonEvent- Some kind of input interaction generates a button at the XY position.MouseButtonInfo- Some kind of input interaction generates a button with the currently active modifiers.
Level#isClientSide now private
The Level#isClientSide field is now private, so all queries must be made to the method version:
// For some Level level
level.isClientSide();
net.minecraft.world.level.Level#isClientSidefield is now private
Minor Migrations
The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.
Item Owner
Minecraft has further abstracted the holder of an item in item models to its own interface: ItemOwner. An ItemOwner is defined by three things: the level the owner is in, the position of the owner, and the Y rotation (in degrees) of the owner to indicate the facing direction. ItemOwners are implemented on every Entity; however, their position can be offset by using ItemOwner#offsetFromOwner or creating a ItemOwner$OffsetFromOwner.
Currently, only the new shelf block uses the offset owner so that compasses are not randomly spinning when placed.
net.minecraft.client.renderer.entity.ItemRenderer#renderStaticnow takes in an optionalItemOwnerinstead of aLivingEntitynet.minecraft.client.renderer.itemItemModel#updatenow takes in anItemOwnerinstead of aLivingEntityItemModelResolver#updateForTopItem,appendItemLayersnow takes in anItemOwnerinstead of aLivingEntity
net.minecraft.client.renderer.item.properties.numericNeedleDirectionHelper#get,calculatenow takes in anItemOwnerinstead of aLivingEntityRangeSelectItemModelProperty#getnow takes in anItemOwnerinstead of aLivingEntityTime$TimeSource#getnow takes in anItemOwnerinstead of aEntity
net.minecraft.world.entityEntitynow implementsItemOwnerItemOwner- Represents the owner of the item being rendered.
Container User
As this new version of Minecraft introduces the copper golem (a vanilla mob that can interact with inventories), the concept of an entity that can use a container has been abstracted into its own interface: ContainerUser. ContainerUsers are expected to be implemented on some LivingEntity subclass. Since the actual inventory logic is handled elsewhere, ContainerUser only has two methods: hasContainerOpen, which checks whether the living entity is currently opening some container (e.g., barrel, chest); and getContainerInteractionRange, which determines the radius in blocks that the entity can interact with some container.
net.minecraft.world.ContainerstartOpen,stopOpennow take in aContainerUserinstead of aPlayergetEntitiesWithContainerOpen- Returns the list ofContainerUsers that are interacting with this container.
net.minecraft.world.entity.ContainerUser- Typically an entity that can interact with and open a container.net.minecraft.world.entity.player.Playernow implementsContainerUsernet.minecraft.world.level.block.entity.EnderChestBlockEntity#startOpen,stopOpennow take in aContainerUserinstead of aPlayer
Name And Id
Unless a GameProfile is needed, Minecraft now passes around a NameAndId for every player instead. As the name implies, NameAndId contains the UUID and name of the player, as that is usually all that’s necessary for most logic involving a player entity.
net.minecraft.commands.arguments.GameProfileArgumentgetGameProfilesnow return a collections ofNameAndIds$Result#getNamesnow return a collections ofNameAndIds
net.minecraft.network.codec.ByteBufCodecs#PLAYER_NAME- A 16 byte string stream codec of the player name.net.minecraft.network.protocol.status.ServerStatus$Players#Samplenow is a list ofNameAndIds rather thanGameProfilesnet.minecraft.serverMinecraftServergetProfilePermissionsnow takes in aNameAndIdinstead of aGameProfileisSingleplayerOwnernow takes in aNameAndIdinstead of aGameProfileANONYMOUS_PLAYER_PROFILEis now aNameAndId
Servicesnow takes in aUserNameToIdResolverinstead of aGameProfileCache, and aProfileResolver
net.minecraft.server.playersGameProfileCache->UserNameToIdResolver,CachedUserNameToIdResolver; not one-to-onegetAsyncis removedadd(GameProfile)is removed
NameAndId- An object that holds the UUID and name of a profile.PlayerListload->loadPlayerData, not one-to-onecanPlayerLoginnow takes in aNameAndIdinstead of aGameProfiledisconnectAllPlayersWithProfilenow takes in aUUIDinstead of aGameProfileop,deopnow take in aNameAndIdinstead of aGameProfileisWhiteListed,isOpnow take in aNameAndIdinstead of aGameProfilecanBypassPlayerLimitnow takes in aNameAndIdinstead of aGameProfile
ServerOpListnow takes inNameAndIdas its first genericcanBypassPlayerLimitnow takes in aNameAndIdinstead of aGameProfile
ServerOpListEntrynow takes inNameAndIdas its generic and for the constructorUserBanListnow takes inNameAndIdas its first genericisBannednow takes in aNameAndIdinstead of aGameProfile
UserBanListEntrynow takes inNameAndIdas its generic and for the constructorUserWhiteListnow takes inNameAndIdas its first genericisWhiteListednow takes in aNameAndIdinstead of aGameProfile
UserWhiteListEntrynow takes inNameAndIdas its generic and for the constructor
net.minecraft.world.entity.player.Player#nameAndId- Returns the name and id of the player.net.minecraft.world.level.storage.PlayerDataStorage#load(Player, ProblemReporter)->load(NameAndId), returns anOptional<CompoundTag>
Typed Entity Data
Data components for storing block and entity data have been changed from using CustomData to the type safe variant TypedEntityData. TypedEntityData is pretty much the same as CustomData, storing a CompoundTag, except that it is represented by some IdType generic like EntityType or BlockEntityType. All of the methods within CustomData relating to block entities and entities have moved to TypedEntityData.
Spawn eggs use the TypedEntityData to store the EntityType that it will spawn. The logic of spawning is still tied to the SpawnEggItem subclass.
net.minecraft.core.component.DataComponents#ENTITY_DATA,BLOCK_ENTITY_DATAare nowTypeEntityDatawithEntityTypeandBlockEntityTypeids, respectivelynet.minecraft.world.entity.EntityType#updateCustomEntityTagnow takes in aTypedEntityDatainstead ofCustomDatanet.minecraft.world.item.Item$Properties#spawnEgg- Adds theENTITY_DATAcomponent with the entity type.net.minecraft.world.item.componentCustomDataCODEC_WITH_IDis removedCOMPOUND_TAG_CODEC- A codec for a flattened compound tag.parseEntityId,parseEntityTypeare removedloadInto->TypedEntityData#loadIntoupdate,read,sizeare removedcontains->TypedEntityData#containsgetUnsafe->TypedEntityData#getUnsafe
TypedEntityData- A custom data that provides a type-safe identifier.
net.minecraft.world.level.Spawner#appendHoverText,getSpawnEntityDisplayNamenow take in aTypedEntityDatainstead of aCustomDatanet.minecraft.world.level.block.entity.BeehiveBlockEntity$Occupant#entityDatais now aTypedEntityData
Reload Listener Shared State
PreparableReloadListener now have an option to share their data between other reload listeners through the use of the PreparableReloadListener#prepareSharedState. prepareSharedState is ran on the main thread before reload is called, which can store arbitrary values to some $SharedKey as basically a dictionary lookup. Then, once reload is called, the stored data can be obtained and used via the key. Normally, the shared values used are some kind of CompletableFuture and joined within.
public class FirstExampleListener implements PreparableReloadListener {
// Create the key to write the shared data to
public static final PreparableReloadListener.StateKey<CompletableFuture<Void>> EXAMPLE = new PreparableReloadListener.StateKey<>();
@Override
public void prepareSharedState(PreparableReloadListener.SharedState state) {
// Add the data to the shared state
state.set(EXAMPLE, CompletableFuture.allOf());
}
@Override
public CompletableFuture<Void> reload(PreparableReloadListener.SharedState state, Executor tasksExecutor, PreparableReloadListener.PreparationBarrier barrier, Executor reloadExecutor) {
// Use the shared state
var example = state.get(EXAMPLE);
}
}
public class SecondExampleListener implements PreparableReloadListener {
@Override
public CompletableFuture<Void> reload(PreparableReloadListener.SharedState state, Executor tasksExecutor, PreparableReloadListener.PreparationBarrier barrier, Executor reloadExecutor) {
// Use the shared state in a different listener
var example = state.get(FirstExampleListener.EXAMPLE);
}
}
net.minecraft.server.packs.resourcesPreparableReloadListenerreloadnow takes in aPreparableReloadListener$SharedStateinstead of aResourceManagerprepareSharedState- A method called before the reload listener is reloaded to share data between reloading listeners.$SharedState- A general dictionary that can provide resources between reload listeners, though they should typically be in the form ofCompletableFutures.$StateKey- A key into the shared state.
SimpleReloadInstance$StateFactory#createnow takes in aPreparableReloadListener$SharedStateinstead of aResourceManager
Ticket Flags
TicketType has been updated to take a bit flag representing the flag’s properties rather than a boolean and enum.
// This needs to be registered to BuiltInRegistries#TICKET_TYPE
public static final TicketType EXAMPLE = new TicketType(
20L, // The number of ticks before the ticket is timed out and removed, set to 0 if the ticket should never time out
// The bit flags to set, see below for replacements and explanations of the new flags
TicketType.FLAG_SIMULATION | TicketType.FLAG_LOADING
);
net.minecraft.server.level.TicketTypenow takes in a bitmask of flags rather than a boolean and ticket useFLAG_PERSIST,persistreplace the booleanFLAG_LOADINGreplaces$TicketUse#LOADINGFLAG_SIMULATIONreplaces$TicketUse#SIMULATIONFLAG_KEEP_DIMENSION_ACTIVE,shouldKeepDimensionActive- When set, prevents the level from unloading.FLAG_CAN_EXPIRE_IF_UNLOADED,canExpireIfUnloaded- When set, the ticket expires if the chunk is unloaded.START->PLAYER_SPAWN,SPAWN_SEARCH$TicketUseclass is removed
net.minecraft.world.level.TicketStorageshouldKeepDimensionActive- Checks if the dimension active flag is set on any tickets in the storage.removeTicketIfnow takes a$TicketPredicateinstead of aBiPredicate$TicketPredicate- Tests the ticket at a given chunk position.
Respawn Data
The respawn logic has been consolidated into a single object known as LevelData$RespawnData. The respawn data holds the global position (a level key and block position) and the rotation of the entity. All calls to the original angle and position methods have been replaced by Level#setRespawnData or getRespawnData, which delegates to the MinecraftServer and eventually the level data.
net.minecraft.client.multiplayer.ClientLevel#setDefaultSpawnPos->Level#setRespawnDatanet.minecraft.network.protocol.game.ClientboundSetDefaultSpawnPositionPacketis now a record- The parameters have been replaced with a
LevelData$RespawnDataobject
- The parameters have been replaced with a
net.minecraft.server.MinecraftServerfindRespawnDimension- Gets the defaultServerLevelthat the player should respawn in.setRespawnData- Sets the default spawn position.getRespawnData- Gets the default spawn position.
net.minecraft.server.levelServerLevel#setDefaultSpawnPos->Level#setRespawnDataServerPlayer$RespawnConfignow takes in aLevelData$RespawnDatainstead of the dimension, position, and angle- Fields are still accessible from the respawn data
net.minecraft.world.level.Level#getSharedSpawnPos,getSharedSpawnAngle->getRespawnData,getWorldBorderAdjustedRespawnData, not one-to-onenet.minecraft.world.level.storageLevelDatagetSpawnPos,getSpawnAngle->getRespawnData, not one-to-one$RespawnData- Defines the global position, yaw, and pitch of where to respawn the players by default.
WritableLevelData#setSpawnnow only takes in theLevelData$RespawnData
The ‘On Shelf’ Transform
Models now have a new transform for determining how an item sits on a shelf called on_shelf.
net.minecraft.client.renderer.block.model.ItemTransforms#fixedFromBottom- A transform that expects the item to be sitting on some fixed bottom, like a shelf.net.minecraft.world.item.ItemDisplayContext#ON_SHELF- When an item is placed on a shelf.
Client Asset Split
ClientAsset has been reworked to better specify what the asset is referencing. Currently, vanilla adds ClientAsset$Texture to specify that the asset is a texture, which further subclasses to $DownloadedTexture for textures downloaded from the internet, and $ResourceTexture for textures accessible from some existing resource on the disk.
net.minecraft.advancements.DisplayInfonow takes in an optionalClientAsset$ResourceTexturefor the background instead of aClientAssetnet.miencraft.client.renderer.texture.SkinTextureDownloader#downloadAndRegisterSkinnow returns a future for theClientAsset$Textureinstead of aResourceLocationnet.minecraft.client.resourcesPlayerSkin->net.minecraft.world.entity.player.PlayerSkin- The constructor now takes in
ClientAsset$Textures instead ofResourceLocationandStrings texture,textureUrl->bodycapeTexture->capeelytraTexture->elytrainsecure- Constructs aPlayerSkinwithinsecureset to false.with- Builds aPlayerSkinfrom its$Patch.$Patch- A packed object representing the skin in other files or when sending across the network.
- The constructor now takes in
SkinManager$TextureCache#getOrLoadnow returns a future for theClientAsset$Textureinstead of aResourceLocation
net.minecraft.core.ClientAssetis now an interface instead of a record- Original implementation moved to
$ResourceTexture idstill exists as a methodtexturePath->$Texture#texturePathCODEC,DEFAULT_FIELD_CODEC,STREAM_CODEC->$ResourceTexture#*$DownloadedTexture- A texture downloaded from the internet.$Texture- A client asset which defines a texture.
- Original implementation moved to
net.minecraft.world.entity.animal.CatVariant#assetInfonow takes in aClientAsset$ResourceTextureinstead of aClientAssetnet.minecraft.world.entity.animal.frog.FrogVariant#assetInfonow takes in aClientAsset$ResourceTextureinstead of aClientAssetnet.minecraft.world.entity.animal.wolf.WolfVariant$AssetInfo#*now take in aClientAsset$ResourceTextureinstead of aClientAssetnet.minecraft.world.entity.variant.ModelAndTexture#assetnow takes in aClientAsset$ResourceTextureinstead of aClientAsset
Cursor Types
The current cursor on screen can now change to a native CursorType, via GLFW#glfwCreateStandardCursor in a GUI via GuiGraphics#requestCursor, or Window#selectCursor anywhere else. Note that Window#setAllowCursorChanges must be true, which can be set through the options menu.
com.mojang.blaze3d.platform.WindowsetAllowCursorChanges- Sets whether the cursor can be changed to a different standard shape.selectCursor- Sets the current cursor to the specified type.
com.mojang.blaze3d.platform.cursorCursorType- A definition of a GLFW standard cursor shape.createStandardCursor- Creates a standard cursor from its shape, name, and fallback.
CursorTypes- Blaze3d’s cursor types.
net.minecraft.client.Options#allowCursorChanges- Sets whether the cursor can be changed to a different standard shape.net.minecraft.client.gui.GuiGraphicsrequestCursor- Requests the cursor to submit to be rendered.applyCursor- Applies the cursor change for rendering.
New Tags
minecraft:blockwooden_shelvescopper_chestslightning_rodscoppercopper_golem_statuesincorrect_for_copper_toolchainslanternsbars
minecraft:entity_typescannot_be_pushed_onto_boatsaccepts_iron_golem_giftcandidate_for_iron_golem_gift
minecraft:itemwooden_shelvescopper_chestslightning_rodscoppercopper_golem_statuescopper_tool_materialsrepairs_copper_armorchainslanternsbarsshearable_from_copper_golem
List of Additions
com.mojang.blaze3d.GraphicsWorkarounds#isGlOnDx12- Returns whether the renderer is using DirectX 12.com.mojang.blaze3d.opengl.GlStateManager#incrementTrackedBuffers- Increments the number of buffers used by the game.com.mojang.blaze3d.systems.TimerQuery#isRecording- Returns whether there is a query that’s currently active.net.minecraft.SharedConstants#RESOURCE_PACK_FORMAT_MINOR,DATA_PACK_FORMAT_MINOR- The minor component of the pack version.net.minecraft.advancements.critereon.MinMaxBoundsbounds- Returns the bounds of the value.$FloatDegrees- A bounds for a float representing the degree of some angle.
net.minecraft.clientMinecraftisOfflineDevelopedMode- Returns whether the game is in offline developer mode.canSwitchGameMode- Whether the player entity exists and has a game mode.playerSkinRenderCache- Returns the cache holding the player’s render texture.canInterruptScreen- Whether the current screen can be closed by another screen.packetProcessor- Returns the processor that schedules and handles packets.
OptionsinvertMouseX- When true, inverts the X mouse movement.toggleAttack- When true, sets the attack key to be toggleable.toggleUse- When true, sets the use key to be toggleable.sprintWindow- Time window in ticks where double-tapping the forward key activates sprint.saveChatDrafts- Returns whether the message being typed in chat should be retained if the box is closed.keySpectatorHotbar- A key that pulls up the spectator hotbar menu.
ToggleKeyMapping#shouldRestoreStateOnScreenClosed- Whether the previous toggle state should be restored after screen close.
net.minecraft.client.animation.definitions.CopperGolemAnimation- The animations for the copper golem.net.minecraft.client.data.models.BlockModelGeneratorsand- ANDs the given conditions together.createShelf- Creates a shelf block state from a base and a particle texture.addShelfPart- Adds a variant for a model for all the shelf’s states.forEachHorizontalDirection- Performs an operation for a pair of directions and rotations.shelfCondition- Constructs a condition based on the state of the shelf.createCopperGolemStatues- Creates all copper golem statues.createCopperGolemStatue- Creates a copper golem statue for the provided block, copper block, and weathered state.createCopperChests- Creates all copper chests.createCopperLantern- Creates a lantern and hanging lantern.createCopperChain- Creates a chain.createCopperChainItem- Creates a chain item model.
net.minecraft.client.data.models.modelModelTemplateSHELF_*- Model templates for constructing a shelf into a multipart.LIGHTNING_ROD- Model template for a lightning rod.CHAIN- Model template for a chain.BARS_*- Model templates for constructing a bars-like block.
TexturedModel#CHAIN- A model provider for a chain.TextureMapping#bars- A texture mapping for a bars-like block.TextureSlot#BARS- A reference to the#barstexture.
net.minecraft.client.guiGui#renderDeferredSubtitles- Renders the subtitles on screen.GuiGraphics#getSprite- Gets aTextureAtlasSpritefrom its material.
net.minecraft.client.gui.componentsAbstractScrollArea#isOverScrollbar- Returns whether the current cursor position is over the scroll bar.AbstractSelectionListsort- Sorts the entries within the list.swap- Swaps the position of two entries in the listclearEntriesExcept- Removes all entries that don’t match the provided element.getNextY- Returns the Y component to render the scrolled component.entriesCanBeSelected- Whether the entries in the list can be selected.scrollToEntry- Scrolls the bar such that the selected entry is on screen.removeEntries- Removes all entries that are in the provided list.$Entryset*- Sets the component size.getContent*- Get the content size and positions.
ChatComponentsaveAsDraft,discardDraft- Handles the draft message in the chat box.createScreen,openScreen,preserveCurrentChatScreen,restoreChatScreen- Handles screen behavior depending on the draft chat option.$ChatMethod- Defines what type of message is the chat.$Draft- Defines a draft message in the chat box.
EditBoxDEFAULT_HINT_STYLE- The style of the default hints.SEARCH_HINT_STYLE- The style of the searchable hints, such as in a recipe book.$TextFormatter- An interface used to format the string in the box.
FittingMultiLineTextWidget#minimizeHeight- Sets the height of the widget to the inner height and padding.FocusableTextWidget$BackgroundFill- An enum that represents when the background should be filled.ItemDisplayWidget#renderTooltip- Submits the tooltip to render.MultiLineLabel$Align- Handles the alignment of the label.MultilineTextField#selectWordAtCursor- Selects the word whether the cursor is currently located.SpriteIconButton$Builder#withTooltip- Sets the tooltip to display the message.StringWidgetsetMaxWidth- Sets the max width of the string and how to handle the extra width.$TextOverflow- What to do if the text is longer than the max width.
net.minecraft.client.gui.components.events.GuiEventListener#shouldTakeFocusAfterInteraction- When true, sets the element as focused when clicked.net.minecraft.client.gui.screensChatScreenisDraft- Whether there is a message that hasn’t been sent in the box.exitReason- The reason the chat screen was closed.shouldDiscardDraft- Whether the current draft message should be discarded.$ChatConstructor- A constructor for the chat screen based on the draft state.$ExitReason- The reason the chat screen was closed.
FaviconTexture#isClosed- Returns whether the texture has been closed.LevelLoadingScreenupdate- Updates the current load tracker and reason.$Reason- The reason for changing the level loading screen.
Overlay#tick- Ticks the overlay.ScreenpanoramaShouldSpin- Returns whether the rendered panorama should spin its camera.setNarrationSuppressTime- Sets until when the narration should be suppressed for.isInGameUi- Returns whether the screen is opened while playing the game, not the pause menu.isAllowedInPortal- Whether this screen can be open during the portal transition effect.canInterruptWithAnotherScreen- Whether this screen can be closed by another screen, defaults to ‘close on escape’ screens.
net.minecraft.client.gui.screens.inventory.AbstractCommandBlockScreen#addExtraControls- Adds any extra widgets to the command block screen.net.minecraft.client.gui.screens.multiplayerCodeOfConductScreen- A screens that displays the code of conduct text for a server.ServerSelectionList$Entrymatches- Returns whether the provided entry matches this one.join- Handles how the client joins to the server entry.
net.minecraft.client.gui.screens.reporting.ChatSelectionScreen$ChatSelectionList#ITEM_HEIGHT- The height of each entry in the list.net.minecraft.client.gui.screens.worldselection.WorldSelectionListreturnToScreen- Returns to the previous screen after reloading the world list.$Builder- Creates a newWorldSelectionList.$Entry#getLevelSummary- Returns the summary of the selected world.$EntryType- A enum representing what type of world the entry is.$NoWorldsEntry- An entry where there are no worlds to select from.
net.minecraft.client.main.GameConfig$GameData#offlineDeveloperMode- Whether the game is offline and is ran for development.net.minecraft.client.multiplayerClientCommonPacketListenerImplseenPlayers- All players that have been seen, regardless of if they are currently online, by this player.seenInsecureChatWarning- If the player has seen the insecure chat warning.$CommonDialogAccess- A dialog access used by the client network.
ClientConfigurationPacketListenerImpl#DISCONNECTED_MESSAGE- The message to display on disconnect because of not accepting the code of conduct.ClientExplosionTracker- Tracks the explosions made on the client, specifically to handle particles.ClientLevelendFlashState- Handles the state of the flashes of light that appear in the end.trackExplosionEffects- Tracks an explosion to handle its particles.
ClientPacketListenergetSeenPlayers- Returns all players seen by this player.getPlayerInfoIgnoreCase- Gets the player info for the provided profile name.
net.minecraft.client.player.LocalPlayerResolver- A profile resolver for the local player.net.minecraft.client.resources.WaypointStyle#ICON_LOCATION_PREFIX- The prefix for waypoint icons.net.minecraft.client.server.IntegratedServer#MAX_PLAYERS- The maximum number of players allowed in an locally hosted server.net.minecraft.client.soundsDirectionalSoundInstance- A sound that changes position based on the direction of the camera.SoundEngineExecutor#startUp- Creates the thread to run the engine on.SoundPreviewHandler- A utility for previewing how some event would sound like with the given settings.
net.minecraft.coreBlockPos#betweenCornersInDirection- An iterable that iterates through the provided bounds in the direction provided by the vector.Direction#axisStepOrder- Returns a list of directions that the given vector should be checked in.
net.minecraft.core.particles.ExplosionParticleInfo- The particle that used as part of an explosion.net.minecraft.data.loot.BlockLootSubProvider#createCopperGolemStatueBlock- The loot table for a copper golem statue.net.minecraft.data.loot.packsVanillaBlockInteractLoot- A sub provider for vanilla block loot from entity interaction.VanillaChargedCreeperExplosionLoot- A sub provider for vanilla entity loot from charged creeper explosions.VanillaEntityInteractLoot- A sub provider for vanilla entity loot from entity interaction.
net.minecraft.data.recipes.RecipeProvider#shelf- Constructs a shelf recipe from one item.net.minecraft.data.worldgen.BiomeDefaultFeatures#addNearWaterVegetation- Adds the vegetation when near a body of water.net.minecraft.gametest.framework.GameTestHelper#getTestDirection- Gets the direction that the test is facing.net.minecraft.networkFriendlyByteBuf#readLpVec3,writeLpVec3- Handles syncing a compressedVec3.LpVec3- A vec3 network handler that compresses and decompresses a vector into at most two bytes and two integers.PacketProcessor- A processor for packets to be scheduled and handled.
net.minecraft.network.chat.CommonComponents#GUI_COPY_TO_CLIPBOARD- The message to display when copying a chat to the clipboard.net.minecraft.network.protocol.configurationClientboundCodeOfConductPacket- A packet the sends the code of conduct of a server to the joining client.ClientConfigurationPacketListener#handleCodeOfConduct- Handles the code of conduct sent from the server.ServerboundAcceptCodeOfConductPacket- A packet that sends the acceptance response of a client reading the code of conduct from a server.ServerConfigurationPacketListener#handleAcceptCodeOfConduct- Handles the acceptance of the code of conduct from the client.
net.minecraft.network.syncher.EntityDataSerializersWEATHERING_COPPER_STATE- The weather state of the copper on the golem.COPPER_GOLEM_STATE- The logic state of the copper golem.RESOLVABLE_PROFILE- The resovlable profile of an entity.
net.minecraft.server.MinecraftServerselectLevelLoadFocusPos- Returns the loading center position of the server, usually the shared spawn position.getLevelLoadListener- Returns the listener used to track level loading.getCodeOfConducts- Returns a map of file names to their code of conduct text.enforceGameTypeForPlayers- Sets the game type of all players.packetProcessor- Returns the packet processor for the server.
net.minecraft.server.commands.FetchProfileCommand- Fetches the profile of a given user.net.minecraft.server.dedicated.DedicatedServerProperties#codeOfConduct- Whether the server has a code of conduct.net.minecraft.server.levelChunkLoadCounter- Keeps track of chunk loading when a level is loading or the player spawns.ChunkMapgetLatestStatus- Returns the latest status for the given chunk position.isTrackedByAnyPlayer- Checks whether the entity is tracked by any player.forEachEntityTrackedBy- Loops through each entity tracked by the given player.forEachReadyToSendChunk- Loops through each chunk that is ready to be sent to the client.
ServerChunkCachehasActiveTickets- Checks whether the current level has any active tickets keeping it loaded.addTicketAndLoadWithRadius- Adds a ticket to some location and loads the chunk and radius around that location.
ServerEntity$Synchronizer- Handles sending packets to tracking entities.ServerLevel#isSpawningMonsters- Returns whether the server can spawn monsters.ServerPlayer$SavedPosition- Holds the current position of the player on disk.
net.minecraft.server.level.progress.ChunkLoadStatusView- A status view for the loading chunks.net.minecraft.server.network.ConfigurationTask#tick- Calls the task every tick until it returns true, then finishes the task.net.minecraft.server.network.configPrepareSpawnTask- A configuration task that finds the spawn of the player.ServerCodeOfConductConfigurationTask- A configuration task that sends the code of conduct to the client.
net.minecraft.server.packs.OverlayMetadataSectioncodecForPackType- Constructs a codec for the section given the pack type.forPackType- Gets the metadata section type from the pack type.
net.minecraft.server.packs.metadata.MetadataSectionType#withValue,$WithValue- Holds a metadata section along with its provided value.net.minecraft.server.packs.metadata.packPackFormat- Represents the major and minor revision of a pack.PackMetadataSection#forPackType- Gets the metadata section type from the pack type.
net.minecraft.server.packs.repository.PackCompatibility#UNKNOWN- The compatibility of the pack with the game is unknown as the major version is set to the max integer value.net.minecraft.server.packs.resources.ResourceMetadata#getTypedSection,getTypedSections- Gets the metadata sections for the provided types.net.minecraft.server.players.ProfileResolver- Resolves a game profile from its name or UUID.net.minecraft.utilExtraCodecsgameProfileCodec- Creates a codec for aGameProfilegiven the UUID codec.$LateBoundIdMapper#values- Returns a set of values within the mapper.
InclusiveRange#map- Maps a range from one generic to another.Mth#ceilLong- Returns the double rounded up to the nearest long.
net.minecraft.util.randomWeighted#streamCodec- Constructs a stream codec for the weighted entry.WeightedList#streamCodec- Constructs a stream codec for the weighted list.
net.minecraft.util.thread.BlockableEventLoop#shouldRunAllTasks- Returns if there are any blocked tasks.net.minecraft.world.Nameable#getPlainTextName- Returns the string of the name component.net.minecraft.world.entityAvatar- An entity that makes up the base of a player.EntityReferencegetEntity- Returns the entity given the type class and the level.- Static
getEntity,getLivingEntity,getPlayer- Returns the entity given itsEntityReferenceand level.
EntityTypeMANNEQUIN- The mannequin entity type.STREAM_CODEC- The stream codec for an entity type.$Builder#notInPeaceful- Sets the entity to not spawn in peaceful mode.
EntitycanInteractWithLevel- Whether the entity can interact with the current level.isInShallowWater- Returns whether the player is in water but not underwater.getAvailableSpaceBelow- Returns the amount of space in the Y direction between the entity and the collider, offset by the given value.collectAllColliders- Returns all entity collisions.
InsideBlockEffectType#CLEAR_FREEZE- A in-block effect that clears the frozen ticks.LivingEntitydropFromEntityInteractLootTable- Drops loot from a table from an entity interaction.shouldTakeDrowningDamage- Whether the entity should take damage from drowning.
Mob#WEARING_ARMOR_UPGRADE_MATERIAL_CHANCE,WEARING_ARMOR_UPGRADE_MATERIAL_ATTEMPTS- Constants for the armor material upgrade.PositionMoveRotation#withRotation- Creates a new object with the provided XY rotation.Relativerotation- Gets the set of relative rotations from the XY booleans.position- Gets the set of relative positions from the XYZ booleans.direction- Gets the set of relative deltas from the XYZ booleans.
net.minecraft.world.entity.ai.Brain#isBrainDead- Returns whether the brain does not have any memories, snesors, or behaviors.net.minecraft.world.entity.ai.behavior.TransportItemsBetweenContainers- A behavior where an entity will move items between visited containers.net.minecraft.world.entity.ai.memory.MemoryModuleTypeVISITED_BLOCK_POSITIONS- Important block positions visited.TRANSPORT_ITEMS_COOLDOWN_TICKS- How many ticks to wait before transporting items.UNREACHABLE_TRANSPORT_BLOCK_POSITIONS- Holds a list of positions that are impossible to get to.
net.minecraft.world.entity.ai.navigation.GroundPathNavigation#setCanPathToTargetsBelowSurface- Sets whether the entity can target other entities that are underneath a non-air block below the starting position.net.minecraft.world.entity.animal.coppergolemCopperGolem- The copper golem entity.CopperGolemAi- The brain logic for the copper golem.CopperGolemOxidationLevel- A record holding the source events and textures for a given oxidation level.CopperGolemOxidationLevels- All vanilla oxidation levels.CopperGolemState- The current logic state the copper golem is in.
net.minecraft.world.entity.decorationHangingEntity#canCoexist- Whether any other hanging entities are in the same position as this one. By default, makes sure that the entities are not the same entity type and not facing the same direction.Mannequin- An avatar that does not have a connected player.
net.minecraft.world.entity.playerPlayerisMobilityRestricted- Returns whether the player has the blindness effect.handleShoulderEntities- Handles the entities on the player’s shoulders.extractParrotVariant,convertParrotVariant,*ShoulderParrot*- Handles the parrot on the player’s shoulders.
PlayerModelPart#CODEC- The codec for the model part.
net.minecraft.world.entity.raid.Raids#getRaidCentersInChunk- Returns the number of raid centers in the given chunk.net.minecraft.world.entity.vehicle.MinecartFurnace#addFuel- Adds fuel to the furnace to push the entity.net.minecraft.world.itemBucketItem#getContent- Returns the fluid held in the bucket.Item$TooltipContext#isPeaceful- Returns true if the difficulty is set to peaceful.ToolMaterial#COPPER- The copper tool material.WeatheringCopperItems- A record of items that represent each of the weathering copper states.
net.minecraft.world.item.equipmentArmorMaterials#COPPER- The copper armor material.EquipmentAssets#COPPER- The key reference to the copper equipment asset.ResolvableProfileskinPatch- Returns the player skin reference.$Static- Uses the already resolved game profile.$Dynamic- Dynamically resolves the game profile on use.$Partial- Represents part of the game profile depending on whatever information is provided to the component.
net.minecraft.world.levelBaseCommandBlock$CloseableCommandBlockSource- A command source typically for a command block.ChunkPos#contains- Whether the given block position is in the chunk.GameRules#RULE_SPAWNER_BLOCKS_ENABLED- Whether spawner blocks should spawn entities.LevelgetEntityInAnyDimension- Gets the entity by UUID.getPlayerInAnyDimension- Gets the player by UUID.hasEntities- Returns whether the provided bounds has entities matching the type and predicate.palettedContainerFactory- Returns the factory used to create paletted containers.
net.minecraft.world.level.border.WorldBorder$Settings#toWorldBorder- Constructs a world border from the settings.net.minecraft.world.level.blockBlock#dropFromBlockInteractLootTable- Drops the loot when interacting with a block.ChestBlockchestCanConnectTo- Returns whether the chest can merge with another block.getConnectedBlockPos- Gets the connected block position of the chest.getOpenChestSound,getCloseChestSound- Returns the sounds played on chest open / close.getChestType- Returns the type of the chest based on the surrounding chests.
ChiseledBookShelfBlock#FACING,SLOT_*_OCCUPIED- The block state properties of the chiseled bookshelf.CopperChestBlock- The block for the copper chest.CopperGolemStatueBlock- The block for the copper golem statue.SelectableSlotContainer- A container whose slot can be selected based on in-game interaction.ShelfBlock- A block for the shelf.SideChainPartBlock- A helper for providing how the chain of a shelf should be displayed.WeatheringCopper$WeatherStateBY_ID- The mapper of enum ordinal to state.STREAM_CODEC- The stream codec for the state.next- Gets the next state in the ordinal.previous- Gets the previous state in the ordinal.
WeatheringCopperBarsBlock- The block for weathering copper bars.WeatheringCopperBlocks- A record of blocks that represent each of the weathering copper states.WeatheringCopperChainBlock- The block for weathering copper chains.WeatheringCopperChestBlock- The block for the weathering copper chest.WeatheringCopperGolemStatueBlock- The block for the weathering copper golem statue.WeatheringLanternBlock- The block for weathering lanterns.WeatheringLightningRodBlock- The block for the weathering lightning rod.
net.minecraft.world.level.block.entityBaseContainerBlockEntity#isLocked- Returns whether the block entity has a lock.CopperGolemStatueBlockEntity- The block entity for the copper golem statue.ListBackedContainer- A container that is baked by a list of items.ShelfBlockEntity- The block entity for the shelf.
net.minecraft.world.level.block.entity.vault.VaultConfig#playerDetector- Returns the detector used to detect specific entities.net.minecraft.world.level.block.state.BlockBehaviour#shouldChangedStateKeepBlockEntity,$BlockStateBase#shouldChangedStateKeepBlockEntity- Returns whether the block entity should be kept if the block is changed to a different block.net.minecraft.world.level.block.state.properties.SideChainPart- The location of where the chain of an object is connected to.net.minecraft.world.level.chunkConfiguration- Configures what type of pallete should be created.PalettedContainerFactory- A factory for constructing paletted containers using the provided strategies.PalettedContainerRO#bitsPerEntry- Returns the number of bits needed to represent an entry.PaletteResize#noResizeExpected- Returns a resizer that throws an exception.
net.minecraft.world.level.levelgenBeardifier#EMPTY- An instance with no pieces or junctions.DensityFunction#invert- Inverts the density output by putting the result one over the value.DensityFunctions#findTopSurface- Finds the top surface between the two bounds.NoiseChunk#maxPreliminarySurfaceLevel- Returns the largest preliminary surface level.NoiseRouterData#NOISE_ZERO- A constant containing the base noise level for layer zero in the overworld.
net.minecraft.world.level.levelgen.blending.Blender#isEmpty- Returns whether there is no blending data present.net.minecraft.world.level.levelgen.structure.BoundingBoxencapsulating- Returns the smallest box that includes the given boxes.STREAM_CODEC- The stream codec for the bounding box.
net.minecraft.world.level.levelgen.structure.structures.JigsawStructure$MaxDistance- The maximum horizontal and vertical distance the jigsaw can expand to.net.minecraft.world.level.pathfinder.Path#STREAM_CODEC- The stream codec of the path.net.minecraft.world.level.portal.TeleportTransition#createDefault- Creates the default teleport transition.net.minecraft.world.level.storage.loot.LootContext$BlockEntityTarget- Specifies targets when interacting with a block entity.$EntityTargetTARGET_ENTITY- The entity being targeted by another, typically the object dropping the loot.INTERACTING_ENTITY- The entity interacting with the object dropping the loot.
$ItemStackTarget- Specifies targets when interacting or using an item stack.
net.minecraft.world.level.storage.loot.parametersLootContextParamsTARGET_ENTITY- The entity being targeted by another, typically the object dropping the loot.INTERACTING_ENTITY- The entity interacting with the object dropping the loot.
LootContextParamSetsENTITY_INTERACT- An entity being interacted with.BLOCK_INTERACT- A block being interacted with.
net.minecraft.world.phys.Vec3#X_AXIS,Y_AXIS,Z_AXIS- The unit vector in the positive direction of each axis.net.minecraft.world.phys.shapes.CollisionContextalwaysCollideWithFluid- Whether the collision detector should always collide with a fluid in its path.emptyWithFluidCollisions- Returns an empty collision context while checking for any fluid collisions.
net.minecraft.world.waypoints.PartialTickSupplier- Gets the partial tick given the provided entity.
List of Changes
com.mojang.blaze3d.buffers.GpuBuffer#sizeis now privatecom.mojang.blaze3d.openglDirectStateAccessbufferSubData,mapBufferRange,unmapBuffer,flushMappedBufferRangenow take in the buffer usage bit maskcreatenow takes in theGraphicsWorkarounds
GlStateManager#_texImage2D,_texSubImage2Dnow takes in aByteBufferinstead of anIntBufferVertexArrayCache#bindVertexArraycan now take in a nullableGlBuffer
com.mojang.blaze3d.platformClipboardManager#getClipboard,setClipboardnow take in aWindowinstead of thelonghandleMacosUtil#exitNativeFullscreen,clearResizableBit,getNsWindownow take in aWindowinstead of thelonghandleWindow#getWindow->handle
com.mojang.blaze3d.systemsCommandEncoder#writeToTexturenow takes in aByteBufferinstead of anIntBufferRenderSystem#flipFramenow takes in aWindowinstead of thelonghandleTimerQuery#getInstancenow returns the raw instance rather than an optional-wrapped instance
com.mojang.blaze3d.vertexPoseStack$Pose#setis now publicVertexConsumer#addVertexWith2DPoseno longer takes in the z component
net.minecraftCrashReportCategory#formatLocationnow has an overload that doesn’t take in theLevelHeightAccessorDetectedVersion#createFromConstants->createBuiltIn, now public, taking in the id, name, and optional stablebooleanSharedConstants#*_PACK_FORMAT->*_PACK_FORMAT_MAJORWorldVersionpackVersionnow returns aPackFormat$Simplenow takes in aPackFormatfor theresourcePackVersionanddatapackVersion
net.minecraft.advancements.critereonMinMaxBoundsnow requires its generic to beComparablemin,maxare now defaultunwrapPoint->$Bounds#asPointfromReaderis now public$Doubles,$Intsnow take in$Boundsfor its values
WrappedMinMaxBounds->MinMaxBounds$Bounds, not one-to-one
net.minecraft.clientMinecraftsetLevelno longer takes in theReceivingLevelScreen$ReasoncameraEntityis now privateopenChatScreenis now public, taking in theChatComponent$ChatMethodsetCamerEntitycan now take in a null entityforceSetScreen->setScreenAndShowgetMinecraftSessionService->services, now returning aServiceinstance- The
MinecraftSessionServicecan be obtained viaService#sessionService
- The
Options#invertYMouse->invertMouseYUserno longer takes in the user type
net.minecraft.client.data.models.BlockModelGeneratorsconditionnow has an overload that takes in an enum or boolean propertycreateLightningRodnow takes in the regular and waxed blockscreateIronBars->createBarsAndItem,createBars; not one-to-one
net.minecraft.client.gui.GuiGraphics#submitSignRenderStatenow takes in aModel$Simpleinstead of aModelnet.minecraft.client.gui.componentsAbstractScrollArea#renderScrollbarnow takes in the current XY position of the cursor.AbstractSelectionListno longer takes in the header heightitemHeight->defaultEntryHeightaddEntry,addEntryToTopnow takes in the height of the elementremoveEntryFromTopno longer returns anythingupdateSizeAndPositioncan now take in an X componentrenderItemnow takes in the entry instead of five integersrenderSelectionnow takes in the entry instead of four integersremoveEntryno longer returns anything$Entrynow implementsLayoutElementrender,renderBack->renderContent
ContainerObjectSelectionListno longer takes in the headerh heightEditBox#setFormatter->addFormatter, not one-to-oneFocusableTextWidgetnow takes in a$BackgroundFillinstead of a booleanMultiLineLabelrenderCentered,renderLeftAligned,renderLeftAlignedNoShadow->render, not one-to-onegetStyleAtCentered,getStyleAtLeftAligned->getStyle, not one-to-one
ObjectSelectionListno longer takes in the headerh heightSpriteIconButtonnow takes in aWidgetSpritesinstead of aResourceLocation, and toolipComponentspriteis now aWidgetSprites$Builder#spritenow has an overload that takes in aWidgetSprites$CenteredIconnow takes in aWidgetSpritesinstead of aResourceLocation, and toolipComponent$TextAndIconnow takes in aWidgetSpritesinstead of aResourceLocation, and toolipComponent
WidgetSpritesnow has an overload with a singleResourceLocation
net.minecraft.client.gui.components.spectator.SpectatorGui#onMouseMiddleClick->onHotbarActionKeyPressednet.minecraft.client.gui.render.stateGuiElementRenderState#buildVerticesno longer takes in thezcomponentGuiRenderState#forEachElementnow takes in aConsumer<GuiElementRenderState>instead of aGuiRenderState$LayeredElementConsumer
net.minecraft.client.gui.render.state.pip.GuiSignRenderStatenow takes in aModel$Simpleinstead of aModelnet.minecraft.client.gui.screensChatScreennow takes in a boolean representing whether the message is a draftinitialis now protected
EditServerScreen->ManageServerScreenInBedChatScreennow takes in the initial text and whether there is a draft mesage in the boxLevelLoadingScreennow takes in aLevelLoadTrackerandLevelLoadingScreen$ReasonPauseScreen#disconnectFromWorld->Minecraft#disconnectFromWorldReceivingLevelScreenhas been merged intoLevelLoadingScreenScreenrenderWithTooltip->renderWithTooltipAndSubtitles$NarratableSearchResultis now a recordisValidCharacterForNamenow takes in a codepointintinstead of achar
net.minecraft.client.gui.screens.achievement.StatsScreeninitLists,initButtonsmerged intoonStatsUpdated$ItemRow#getItemis now protected
net.minecraft.client.gui.screens.dialog.DialogScreen$WarningScreen#createnow takes in aDialogConnectionAccessnet.minecraft.client.gui.screens.inventory.tooltip.ClientActivePlayersTooltip$ActivePlayersTooltip#profilesnow is a list ofPlayerSkinRenderCache$RenderInfos instead ofProfileResultsnet.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreen*_BUTTON_WIDTHare now privatejoinis now public
net.minecraft.client.gui.screens.options.OptionsScreen#CONTROLSis now publicnet.minecraft.client.gui.screens.packsPackSelectionModelnow takes in aConsumer<PackSelectionModel$EntryBase>instead of aRunnable$EntryBaseis now public
TransferableSelectionListnow is a list of$Entrys instead of$PackEntrys$PackEntryis no longer static and extends$Entry
net.minecraft.client.gui.screens.worldselectionCreateWorldScreen#openFresh,testWorld,createFromExistingnow take in aRunnableinstead of aScreenWorldSelectionListnow has a package-private constructorgetScreennow returns a basicScreen$WorldListEntryis now staticcanJoin->canInteract, not one-to-one
net.minecraft.client.gui.spectator.PlayerMenuItemnow only takes in thePlayerInfonet.minecraft.client.main.GameConfig$UserDatano longer takes in thePropertyMapsnet.minecraft.client.multiplayerClientHandshakePacketListenerImplnow takes in aLevelLoadTrackerCommonListenerCookienow takes in aLevelLoadTracker, map of seen players, and whether the insecure chat warning has been shownLevelLoadStatusManager->LevelLoadTracker, not one-to-oneCLOSE_DELAY_MS->LEVEL_LOAD_CLOSE_DELAY_MS, now public
TransferStatenow takes in a map of seen players and whether the insecure chat warning has been shown
net.minecraft.client.multiplayer.chat.ChatListener#clearQueue->flushQueuenet.minecraft.client.rendererDimensionSpecialEffects#forceBrightLightmap->hasEndFlashes, not one-to-oneLevelEventHandlernow takes in aClientLevelinstead of theLevelandLevelRendererLevelRendererprepareCullFrustumis now privaterenderLevelnow takes in an additionalMatrix4ffor the frustum
net.minecraft.client.resources.WaypointStyle#validateis now publicnet.minecraft.client.server.IntegratedServernow takes in aLevelLoadListenerinstead of aChunkProgressListenerFactorynet.minecraft.client.soundsSoundEngine#updateCategoryVolumeno longer takes in the gainSoundEngineExecutor#flush->shutDown, not one-to-oneSoundManager#updateSourceVolumeno longer takes in the gain
net.minecraft.commands.arguments.coordinatesLocalCoordinatesis now a recordWorldCoordinateis now a recordWorldCoordinatesis now a record
net.minecraft.commands.arguments.selector.EntitySelectorParsergetDistance,getLevelcan now benull*Rot*methods now return or useMinMaxBounds$FloatDegrees- Return values can be
null
- Return values can be
net.minecraft.core.RegistrygetRandomElementOf->HolderGetter#getRandomElementOfregisterForHoldernow has an additional generic, making theHolder$Referencereturned hold the actual object type instead of the registry type
net.minecraft.core.component.PatchedDataComponentMap#setnow has an overload that takes in aTypedDataComponentnet.minecraft.data.worldgen.TerrainProvidermethods now use aBoundedFloatFunctiongeneric instead ofToFloatFunctionnet.minecraft.gametest.frameworkGameTestHelperspawnnow has overloads that take in some number of entities to spawnsetBlocknow has overloads to take in a direction for block facingfailnow has an overload that takes in a string
GameTestRunnernow takes in whether the level should be cleared for more space to spawn between batches$Builder#haltOnErrorno longer takes in any parameters
net.minecraft.nbt.NbtUtils#addDataVersion,addCurrentDataVersionnow has an overload that takes in aDynamicinstead of aCompoundTagorValueOutputnet.minecraft.networkFriendlyByteBuf#readSectionPos,writeSectionPos->SectionPos#STREAM_CODECVarInt#MAX_VARINT_SIZEis now public
net.minecraft.network.protocol.PacketUtils#ensureRunningOnSameThreadnow takes in aPacketProcessorinstead of aBlockableEventLoopnet.minecraft.network.protocol.gameClientboundAddEntityPacket#getXa,getYa,getZa->getMovementClientboundExplodePacketnow takes in a radius, block count, and the block particles to displayClientboundPlayerRotationPacketnow takes in whether the XY rotation is relativeClientboundSetEntityMotionPacket#getXa,getYa,getZa->getMovement
net.minecraft.serverSPAWN_POSITION_SEARCH_RADIUSis now publicMinecraftServernow takes in aLevelLoadListenerinstead of aChunkProgressListenerFactorycreateLevelsno longer takes in aChunkProgressListenergetSessionService,getProfileKeySignatureValidator,getProfileRepository,getProfileCache->services, not one-to-onegetProfileCacheis nownameToIdCache, not one-to-one
updateMobSpawningFlagsis now public
net.minecraft.server.levelChunkMapno longer takes in theChunkProgressListenergetTickingGenerated->allChunksWithAtLeastStatus, not one-to-onebroadcast,broadcastAndSend->sendToTrackingPlayers,sendToTrackingPlayersFiltered,sendToTrackingPlayersAndSelf; not one-to-one
PlayerRespawnLogic->PlayerSpawnFinder, not one-to-oneServerChunkCacheno longer takes in theChunkProgressListenerbroadcastAndSend->sendToTrackingPlayersAndSelf, not one-to-onebroadcast->sendToTrackingPlayers, not one-to-one
ServerEntitynow takes in a$Synchronizerinstead of the brodcast method referencesServerEntityGetter#getNearestEntitynow has an overload that takes in aTagKeyof entities instead of a classServerLevelno longer takes in theChunkProgressListenerwaitForChunkAndEntities->waitForEntities, not one-to-onetickCustomSpawnersno longer takes in the tick friendliesboplean
net.minecraft.server.level.chunkChunkAccessnow takes in aPalettedContainerFactoryinstead of aRegistry<Biome>
net.minecraft.server.level.progressChunkProgressListener->LevelLoadListener, not one-to-oneChunkProgressListenerFactory->MinecraftServer#createChunkLoadStatusView, not one-to-oneLoggerChunkProgressListener->LoggingLevelLoadListener, not one-to-oneProcessorChunkProgressListener,StoringChunkProgressListener->LevelLoadProgressListener, not one-to-one
net.minecraft.server.packsAbstractPackResources#getMetadataFromStreamnow takes in aPackLocationInfoOverlayMetadataSectionTYPE->CLIENT_TYPE,SERVER_TYPEoverlaysForVersionnow takes in aPackFormatinstead of an integer$OverlayEntrynow takes in anInclusiveRange<PackFormat>instead of anInclusiveRange<Integer>isApplicablenow takes in aPackFormatinstead of an integer
net.minecraft.server.packs.metadata.pack.PackMetadataSectionnow takes in anInclusiveRange<PackFormat>instead of the raw pack format and integer pack.CODEC->FALLBACK_CODEC, now privateTYPE->CLIENT_TYPE,SERVER_TYPE,FALLBACK_TYPE
net.minecraft.server.packs.repositoryPack#readPackMetadatanow takes in aPackFormatandPackTypeinstead of an integerPackCompatibility#forVersionnow takes inPackFormats instead of integers
net.minecraft.utilCubicSplinemethods and inner classes now useBoundedFloatFunctioninstead ofToFloatFunctionExtraCodecsGAME_PROFILE_WITHOUT_PROPERTIES->AUTHLIB_GAME_PROFILE, now aCodecand publicGAME_PROFILE->STORED_GAME_PROFILE, now aMapCodec
StringRepresentable#createNameLookupnow can take in an arbitrary object and return a string- The base overload that takes in the object array uses
getSerializedName
- The base overload that takes in the object array uses
StringUtil#isAllowedChatCharacternow takes in anintcodepoint instead of acharToFloatFunction->BoundedFloatFunction- This still exists as a standard interface to convert some object to a
float
- This still exists as a standard interface to convert some object to a
net.minecraft.world.entityAgeableMob#finalizeSpawnis now nullableEntitystartRiding(Entity)is now finalstartRiding(Entity, boolean)now takes in an additional boolean of whether to trigger the game event and criteria triggerskilledEntitynow takes in theDamageSourcemoveOrInterpolateTonow has overloads that take in an XY rotation, aVec3position, or all three as optionalslerpMotionnow takes in aVec3instead of three doublesforceSetRotationnow takes in whether the XY rotation is relativeteleportSetPositionnow has an overload that takes in both the starting and end position
EntityReferenceis now private, constructed using theofstatic constructorsgetEntitynow takes in aUUIDLookup<? extends UniquelyIdentifyable>instead of aUUIDLookup<? super StoredEntityType>getnow takes in aLevelinstead of aUUIDLookup
EntityTypenow takes in whether the entity is allowed in peaceful modecreate,loadEntityRecursivenow has an overload that takes in anEntityType
LivingEntityshouldDropLootnow takes in theServerLeveldropFromLootTablenow has overloads to take in a specific loot table key and how the items should be dispensedgetSlotForHand->InteractionHand#asEquipmentSlot
Mob#shouldDespawnInPeaceful->EntityType#isAllowedInPeaceful, not one-to-onePosenow implementsStringRepresentable, has an associatedCodec
net.minecraft.world.entity.ai.village.poiPoiManager#addnow returns aPoiRecordPoiSection#addnow returns aPoiRecord
net.minecraft.world.entity.animal.Animal#usePlayerItem->Mob#usePlayerItemnet.minecraft.world.entity.animal.armadillo.Armadillo#brushOffScutenow takes in anEntityandItemStacknet.minecraft.world.entity.playerPlayernow extendsAvatarinstead ofLivingEntityDATA_SHOULDER_*->DATA_SHOULDER_PARROT_*, now privateoBob,bob->ClientAvatarState#bob0,bob*Cloak*->ClientAvatarState#*Cloak*setEntityOnShoulder->ServerPlayer#setEntityOnShoulder*ShoulderEntity*->ServerPlayer#*ShoulderEntity*setMainArm->Avatar#setMainArmCROUCH_BB_HEIGHT,SWIMMING_BB_WIDTH,SWIMMING_BB_HEIGHT,STANDING_DIMENSIONShave been moved toAvatarPOSES->Avatar#POSES, now protected
PlayerModelPartnow implementsStringRepresentable
net.minecraft.world.entity.projectile.Projectiledeflectnow takes in anEntityReferenceof the owner instead of theEntityitselfonDeflectionno longer takes in the directEntitycheckLeftOwnernow checks if the projectile is outside the collision range only whenleftOwnerandleftOwnerCheckedare both false- The original logic pertaining to this method has been moved to
isOutsideOwnerCollisionRange, which is still private
- The original logic pertaining to this method has been moved to
net.minecraft.world.entity.vehicle.MinecartBehavior#lerpMotionnow takes in aVec3instead of three doublesnet.minecraft.world.itemItemStack#setnow has an overload that takes in aTypedDataComponentSpawnEggItemno longer takes in theEntityTypespawnsEntityno longer takes in theHolderLookup$ProvidergetTypeno longer takes in theHolderLookup$Provider
net.minecraft.world.item.componentBees#STREAM_CODECnow requires aRegistryFriendlyByteBufResolvableProfileis now a sealed class with a protected constructor, created through the staticcreateResolved,createUnresolvedpollResolve,resolve,isResolved->resolveProfile, not one-to-one
net.minecraft.world.item.enchantment.effects.ExplodeEffectnow takes in a list of block particles to displaynet.minecraft.world.levelBaseCommandBlockno longer implementsCommandSourcecreateCommandSourceStacknow takes in aCommandSource
BaseSpawner#getoSpin->getOSpinCustomSpawner#tickno longer takes in the tick friendliesbooleanGameRulesavailableRulesis now public$BooleanValue#createis now public$IntegerValue#createis now public
Levelno longer implementsUUIDLookupexplodenow takes in a weighter list of explosion particles to displayneighborUpdateris now aCollectingNeighborUpdatertickBlockEntitiesis now public
ServerExplosion#explodenow returns the number of blocks exploded
net.minecraft.world.level.borderBorderChangeListeneronBorderSizeSet->onSetSizeonBorderSizeLerping->onLerpSizeonBorderCenterSet->onSetCenteronBorderSetWarningTime->onSetWarningTimeonBorderSetWarningBlocks->onSetWarningBlocksonBorderSetDamagePerBlock->onSetDamagePerBlockonBorderSetDamageSafeZone->onSetSafeZone
WorldBordernow extendsSavedDatagetLerpRemainingTime->getLerpTime*DamageSafeZone->*SafeZoneDEFAULT_SETTINGS->$Settings#DEFAULTcreateSettingshas been replaced with the$Settingsconstructor$BorderExtent#getLerpRemainingTime->getLerpTime$Settingsis now a record, meaning all getters now use the record format
net.minecraft.world.level.blockBeehiveBlock#dropHoneycomb(Level, BlockPos)->dropHoneyComb(ServerLevel, ItemStack, BlockState, BlockEntity, Entity, BlockPos)CaveVines#useentity is no longer nullableChestBlocknow takes in an open and close soundChiseledBookShelfBlocknow implementsSelectableSlotContainerBOOKS_PER_ROWis now private
net.minecraft.world.level.block.entityChiseledBookShelfBlockEntitynow implementsListBackedContainercount->ListBackedContainer#count
ContainerOpenersCounterisOwnContaineris now publicincrementOpeners,decrementOpenersnow takes in aLivingEntityinstead of aPlayergetPlayersWithContainerOpen->getEntitiesWithContainerOpen, now public, not one-to-one
net.minecraft.world.level.block.state.BlockBehaviourgetAnalogOutputSignal,$BlockStateBase#getAnalogOutputSignalnow takes in the direction the signal is coming from$Properties#noCollission->noCollision
net.minecraft.world.level.block.state.properties.BlockStateProperties#CHISELED_BOOKSHELF_SLOT_*_OCCUPIED->SLOT_*_OCCUPIEDnet.minecraft.world.level.chunkGlobalPalette#create->Configuration#createPaletteHashMapPaletteno longer takes in theIdMapcreateno longer takes in theIdMapandPaletteResize
LevelChunkSectionnow takes in aPalettedContainerFactoryinstead of aRegistry<Biome>LinearPaletteno longer takes in theIdMapcreateno longer takes in theIdMapandPaletteResize
PaletteidFor,read,write,getSerializedSizenow takes in anIdMapcopyno longer takes in thePaletteResize$Factory#createno longer takes in theIdMapandPaletteResize
PalettedContainerno longer takes in theIdMapcodec*no longer takes in theIdMapunpackis nowpublic, visible for testing$Configuration->Configuration$Simple$Strategy->StrategygetConfigurationnow takes in anintinstead of anIdMap, now protected
PalettedContainerROpackno longer takes in theIdMap$PackedDatanow takes in the bits per entryint$Unpacker#readno longer takes in theIdMap
PaletteResizeis nowpublicProtoChunknow takes in aPalettedContainerFactoryinstead of aRegistry<Biome>SingleValuePaletteno longer takes in theIdMapandPaletteResizecreateno longer takes in theIdMapandPaletteResize
net.minecraft.world.level.chunk.storage.SerializableChunkData#containerFactorynow takes in aPalettedContainerFactoryinstead of aRegistry<Biome>parsenow takes in aPalettedContainerFactoryinstead of aRegistryAccess
net.minecraft.world.level.entity.UUIDLookup#getEntity->lookupnet.minecraft.world.level.gameeventBlockPositionSourceis now a recordEntityPositionSource#getUuidis now public
net.minecraft.world.level.levelgenBeardifiernow takes in lists instead of iterators and a nullableBoundingBoxDensityFunctions%Coordinatenow implementsBoundedFloatFunctioninstead ofToFloatFunctionNoiseRouter#initialDensityWithoutJaggedness->preliminarySurfaceLevel
net.minecraft.world.level.levelgen.structure.pools.JigsawPlacement#addPiecesnow takes in aJigsawStructure$MaxDistanceinstead of an integernet.minecraft.world.level.levelgen.structure.structures.JigsawStructurenow takes in aJigsawStructure$MaxDistanceinstead of an integernet.minecraft.world.level.pathfinder.Pathis now finalnet.minecraft.world.level.portal.TeleportTransition#missingRespawnBlockno longer takes in theEntityto get the respawn data fromnet.minecraft.world.level.storagePrimaryLevelDatanow takes in an optional wrappedWorldBorder$SettingsServerLevelData#*WorldBorder->*LegacyWorldBorderSettings, now dealing with optional wrappedWorldBorder$Settings
net.minecraft.world.level.storage.loot.functionsCopyComponentsFunctioncopyComponentshas been split tocopyComponentsFromEntity,copyComponentsFromBlockEntity$Sourceis now an interface- Original implementation is in
$BlockEntitySource getReferencedContextParams->contextParam, not one-to-one
- Original implementation is in
CopyNameFunctioncopyNamenow takes in a$Sourceinstead of a$NameSource$NameSource->$Source, now a record, not one-to-one
net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProviderCODEC->MAP_CODEC, not one-to-one$Getter->$Sourcegetnow has an overload that takes in the genericgetReferencedContextParams->contextParam, not one-to-one
net.minecraft.world.phys.shapes.EntityCollisionContextnow takes in abooleaninstead of aPredicate<FluidState>EMPTY->$Empty, not one-to-one
net.minecraft.world.waypoints.TrackedWaypointSTREAM_CODECis now finalyawAngleToCameranow takes in aPartialTickSupplierpitchDirectionToCameranow takes in aPartialTickSupplier
List of Removals
com.mojang.blaze3d.audio.Listener#setGain,getGaincom.mojang.blaze3d.openglGlShaderModule#compileGlStateManager_glUniform1,_glUniform2,_glUniform3,_glUniform4_glUniformMatrix4glActiveTexture,_getActiveTexture
com.mojang.blaze3d.pipeline.RenderTarget#viewWidth,viewHeightcom.mojang.blaze3d.systems.RenderSystemgetQuadVertexBuffersetModelOffset,resetModelOffset,getModelOffset
com.mojang.blaze3d.vertexDefaultVertexFormat#BLIT_SCREENVertexConsumer#setWhiteAlpha
net.minecraftSharedConstants#VERSION_STRINGUtil#getVmArguments
net.miencraft.advancements.critereon.MinMaxBounds$BoundsFactory,$BoundsFromReaderFactorynet.minecraft.clientCamera#FOG_DISTANCE_SCALEMinecraftgetProgressListenergetProfileKeySignatureValidator,canValidateProfileKeys
Options#RENDER_DISTANCE_TINY,RENDER_DISTANCE_NORMALUser#getType,$Type
net.minecraft.client.gui.componentsAbstractSelectionListheaderHeight, associated constructor has been removedsetSelectedIndex,getFirstElement,getEntryisSelectedItemrenderHeader,renderDecorationsensureVisibleremove
OptionsList#getMouseOverStringWidget#alignLeft,alignCenter, alignRight`
net.minecraft.client.gui.render.state.GuiRenderStatedown,$Node#down$LayeredElementConsumer
net.minecraft.client.gui.screens.LevelLoadingScreen#renderChunksnet.minecraft.client.gui.screens.achievement.StatsScreen#setActiveListnet.minecraft.client.gui.screens.multiplayer.JoinMultiplayerScreenBUTTON_ROW_WIDTH,FOOTER_HEIGHTsetSelectedjoinSelectedServer
net.minecraft.client.main.GameConfig$UserData#userProperties,profilePropertiesnet.minecraft.client.renderer.chunk.ChunkSectionLayer#outputTargetnet.minecraft.client.resources.SkinManager#getInsecureSkinnet.minecraft.gametest.framework.GameTestTicker#startTickingnet.minecraft.network.syncher.EntityDataSerializers#COMPOUND_TAGnet.minecraft.server.MinecraftServer#getSpawnRadiusnet.minecraft.server.dedicated.DedicatedServer#storeUsingWhiteListnet.minecraft.server.levelServerChunkCache#getTickingGeneratedServerPlayer#loadGameTypes
net.minecraft.server.packs.resources.ResourceMetadatacopySections$Builder
net.minecraft.world.entity.EntityspawnAtLocation(ServerLevel, ItemLike, int)getServer
net.minecraft.world.entity.decoration.HangingEntity#HANGING_ENTITYnet.minecraft.world.entity.item.ItemEntity#copynet.minecraft.world.entity.monsterCreeper#canDropMobsSkull,increaseDroppedSkullsZombie#getSkull
net.minecraft.world.entity.player.PlayergetScoreboardisModelPartShown
net.minecraft.world.entity.vehicle.MinecartTNT#explode(double)net.minecraft.world.item.Item#verifyComponentsAfterLoadnet.minecraft.world.levelBlockGetter#MAX_BLOCK_ITERATIONS_ALONG_TRAVELGameRules#RULE_SPAWN_CHUNK_RADIUS
net.minecraft.world.level.borderBorderChangeListener$DelegateBorderChangeListenerWorldBorderclosestBorder$DistancePerDirection$Settings#read,write
net.minecraft.world.level.block.FletchingTableBlocknet.minecraft.world.level.block.entity.SkullBlockEntityCHECKED_MAIN_THREAD_EXECUTORsetup,clearfetchGameProfilesetOwner
net.minecraft.world.level.portal.TeleportTransition(ServerLevel, Entity, TeleportTransition.PostTeleportTransition)net.minecraft.world.level.storage.loot.providers.nbt.ContextNbtProviderBLOCK_ENTITY$Getter#getId
Minecraft 1.21.9 -> 1.21.10 Mod Migration Primer
This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.9 to 1.21.10. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.
This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.
If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.
Thank you to:
- @melanx for a typo
Pack Changes
There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.
Minor Migrations
The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.
List of Additions
net.minecraft.world.entity.decoration.HangingEntity#getPopBox- Returns the bounding box indicating where the entity will pop off if colliding.
List of Changes
net.minecraft.world.level.block.state.BlockBehaviour#entityInside now takes in a boolean indicating whether the entity is intersecting or inside the block
Minecraft 1.21.10 -> 1.21.11 Mod Migration Primer
This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.10 to 1.21.11. This does not look at any specific mod loader, just the changes to the vanilla classes. All provided names use the official mojang mappings.
This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.
If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.
Thank you to:
- @xfacthd for some educated guesses regarding the usage annotations
- @dinnerbone for pointing out gizmos can also be submitted on the server in singleplayer worlds
- @thatgravyboat for pointing out the change in parameter orders for
Mth#clampedLerp
Pack Changes
There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.
The Rename Shuffle
Many core classes, method, and parameters have been shuffled around and renamed while still retaining their individual function. The following is a list of the most important changes
ResourceLocation to Identifier
All references to ResourceLocation, whether in method names, parameters, or other classes, have been replaced with Identifier.
The util Package
Most utility classes have been moved to net.minecraft.util. These will need to be reimported.
critereon to criterion
net.minecraft.advancements.critereon has been renamed to net.minecraft.advancements.criterion. These will need to be reimported.
Entity and Object Subpackages
Both net.minecraft.client.model and net.minecraft.world.entity have been reorganized into additional subpackages based on the type of backing object. These will need to be reimported.
net.minecraftBlockUtil->.util.BlockUtilFileUtil->.util.FileUtilResourceLocationException->IdentifierExceptionUtil->.util.Util
net.minecraft.advancements.critereon->.advancements.criterionnet.minecraft.client.gui.screens.inventory.JigsawBlockEditScreen#isValidResourceLocation->isValidIdentifiernet.minecraft.client.modelAbstractBoatModel->.object.boat.AbstractBoatModelAbstractEquineModel->.animal.equine.AbstractEquineModelAbstractPiglinModel->.monster.piglin.AbstractPiglinModelAbstractZombieModel->.monster.zombie.AbstractZombieModelAllayModel->.animal.allay.AllayModelArmadilloModel->.animal.armadillo.ArmadilloModelArmorStandArmorModel->.object.armorstand.ArmorStandArmorModelArmorStandModel->.object.armorstand.ArmorStandModelArrowModel->.object.projectile.ArrowModelAxolotlModel->.animal.axolotl.AxolotlModelBannerFlagModel->.object.banner.BannerFlagModelBannerModel->.object.banner.BannerModelBatModel->.ambient.BatModelBeeModel->.animal.bee.BeeModelBeeStingerModel->.animal.bee.BeeStingerModelBellModel->.object.bell.BellModelBlazeModel->.monster.blaze.BlazeModelBoatModel->.object.boat.BoatModelBoggedModel->.monster.skeleton.BoggedModelBookModel->.object.book.BookModelBreezeModel->.monster.breeze.BreezeModelCamelModel->.animal.camel.CamelModelCamelSaddleModel->.animal.camel.CamelSaddleModelCatModel->.animal.feline.CatModelChestModel->.object.chest.ChestModelChickenModel->.animal.chicken.ChickenModelCodModel->.animal.fish.CodModelColdChickenModel->.animal.chicken.ColdChickenModelColdCowModel->.animal.cow.ColdCowModelColdPigModel->.animal.pig.ColdPigModelCopperGolemModel->.animal.golem.CopperGolemModelCopperGolemStatueModel->.object.statue.CopperGolemStatueModelCowModel->.animal.cow.CowModelCreakingModel->.monster.creaking.CreakingModelCreeperModel->.monster.creeper.CreeperModelDolphinModel->.animal.dolphin.DolphinModelDonkeyModel->.animal.equine.DonkeyModelDrownedModel->.monster.zombie.DrownedModelElytraModel->.object.equipment.ElytraModelEndCrystalModel->.object.crystal.EndCrystalModelEndermanModel->.monster.enderman.EndermanModelEndermiteModel->.monster.endermite.EndermiteModelEquineSaddleModel->.animal.equine.EquineSaddleModelEvokerFangsModel->.effects.EvokerFangsModelFelineModel->.animal.feline.FelineModelFoxModel->.animal.fox.FoxModelFrogModel->.animal.frog.FrogModelGhastModel->.monster.ghast.GhastModelGiantZombieModel->.monster.zombie.GiantZombieModelGoatModel->.animal.goat.GoatModelGuardianModel->.monster.guardian.GuardianModelGuardianParticleModel->.monster.guardian.GuardianParticleModelHappyGhastHarnessModel->.animal.ghast.HappyGhastHarnessModelHappyGhastModel->.animal.ghast.HappyGhastModelHoglinModel->.monster.hoglin.HoglinModelHorseModel->.animal.equine.HorseModelIllagerModel->.monster.illager.IllagerModelIronGolemModel->.animal.golem.IronGolemModelLavaSlimeModel->.monster.slime.MagmaCubeModelLeashKnotModel->.object.leash.LeashKnotModelLlamaModel->.animal.llama.LlamaModelLlamaSpitModel->.animal.llama.LlamaSpitModelMinecartModel->.object.cart.MinecartModelOcelotModel->.animal.feline.OcelotModelPandaModel->.animal.panda.PandaModelParrotModel->.animal.parrot.ParrotModelPhantomModel->.monster.phantom.PhantomModelPiglinHeadModel->.object.skull.PiglinHeadModelPiglinModel->.monster.piglin.PiglinModelPigModel->.animal.pig.PigModelPlayerCapeModel->.player.PlayerCapeModelPlayerEarsModel->.player.PlayerEarsModelPlayerModel->.player.PlayerModelPolarBearModel->.animal.polarbear.PolarBearModelPufferfishBigModel->.animal.fish.PufferfishBigModelPufferfishMidModel->.animal.fish.PufferfishMidModelPufferfishSmallModel->.animal.fish.PufferfishSmallModelRabbitModel->.animal.rabbit.RabbitModelRaftModel->.object.boat.RaftModelRavagerModel->.monster.ravager.RavagerModelSalmonModel->.animal.fish.SalmonModelSheepFurModel->.animal.sheep.SheepFurModelSheepModel->.animal.sheep.SheepModelShieldModel->.object.equipment.ShieldModelShulkerBulletModel->.object.projectile.ShulkerBulletModelShulkerModel->.monster.shulker.ShulkerModelSilverfishModel->.monster.silverfish.SilverfishModelSkeletonModel->.monster.skeleton.SkeletonModelSkullModel->.object.skull.SkullModelSkullModelBase->.object.skull.SkullModelBaseSlimeModel->.monster.slime.SlimeModelSnifferModel->.animal.sniffer.SnifferModelSnowGolemModel->.animal.golem.SnowGolemModelSpiderModel->.monster.spider.SpiderModelSpinAttackEffectModel->.effects.SpinAttackEffectModelSquidModel->.animal.squid.SquidModelStriderModel->.monster.strider.StriderModelTadpoleModel->.animal.frog.TadpoleModelTridentModel->.object.projectile.TridentModelTropicalFishModelA->.animal.fish.TropicalFishSmallModelTropicalFishModelB->.animal.fish.TropicalFishLargeModelTurtleModel->.animal.turtle.TurtleModelVexModel->.monster.vex.VexModelVillagerModel->.npc.VillagerModelWardenModel->.monster.warden.WardenModelWarmCowModel->.animal.cow.WarmCowModelWindChargeModel->.object.projectile.WindChargeModelWitchModel->.monster.witch.WitchModelWitherBossModel->.monster.wither.WitherBossModelWolfModel->.animal.wolf.WolfModelZombieModel->.monster.zombie.ZombieModelZombieVillagerModel->.monster.zombie.ZombieVillagerModelZombifiedPiglinModel->.monster.piglin.ZombifiedPiglinModel
net.minecraft.client.model.dragonDragonHeadModel->.model.object.skull.DragonHeadModelEnderDragonModel->.model.monster.dragon.EnderDragonModel
net.minecraft.client.resources.soundsAbstractSoundInstance#location->identifierSoundInstance#getLocation->getIdentifier
net.minecraft.client.searchtreeIdSearchTreeresourceLocationSearchTree->identifierSearchTreesearchResourceLocation->searchIdentifier
ResourceLocationSearchTree->IdentifierSearchTree
net.minecraft.commands.arguments.ResourceLocationArgument->IdentifierArgumentnet.minecraft.network.FriendlyByteBuf#readResourceLocation,writeResourceLocation->readIdentifier,writeIdentifiernet.minecraft.resourcesResourceKey#location->identifierResourceLocation->Identifier
net.minecraft.util.ResourceLocationPattern->IdentifierPatternnet.minecraft.util.parsing.packrat.commands.ResourceLocationParseRule->IdentifierParseRulenet.minecraft.world.entity.GlowSquid->.animal.squid.GlowSquidnet.minecraft.world.entity.animalAbstractCow->.cow.AbstractCowAbstractFish->.fish.AbstractFishAbstractGolem->.golem.AbstractGolemAbstractSchoolingFish->.fish.AbstractSchoolingFishBee->.bee.BeeCat->.feline.CatCatVariant->.feline.CatVariantCatVariants->.feline.CatVariantsChicken->.chicken.ChickenChickenVariant->.chicken.ChickenVariantChickenVariants->.chicken.ChickenVariantsCod->.fish.CodCow->.cow.CowCowVariant->.cow.CowVariantCowVariants->.cow.CowVariantsDolphin->.dolphin.DolphinFox->.fox.FoxHappyGhast->.happyghast.HappyGhastHappyGhastAi->.happyghast.HappyGhastAiIronGolem->.golem.IronGolemMushroomCow->.cow.MushroomCowOcelot->.feline.OcelotPanda->.panda.PandaParrot->.parrot.ParrotPig->.pig.PigPigVariant->.pig.PigVariantPigVariants->.pig.PigVariantsPolarBear->.polarbear.PolarBearPufferfish->.fish.PufferfishRabbit->.rabbit.RabbitSalmon->.fish.SalmonShoulderRidingEntity->.parrot.ShoulderRidingEntitySnowGolem->.golem.SnowGolemSquid->.squid.SquidTropicalFish->.fish.TropicalFishTurtle->.turtle.TurtleWaterAnimal->.fish.WaterAnimal
net.minecraft.world.entity.animal.coppergolem.*->.animal.golem.*net.minecraft.world.entity.animal.horse.*->.animal.equine.*net.minecraft.world.entity.boss.EnderDragonPart->.enderdragon.EnderDragonPartnet.minecraft.world.entity.decorationPainting->.painting.PaintingPaintingVariant->.painting.PaintingVariantPaintingVariants->.painting.PaintingVariants
net.minecraft.world.entity.monsterAbstractIllager->.illager.AbstractIllagerAbstractSkeleton->.skeleton.AbstractSkeletonBogged->.skeleton.BoggedCaveSpider->.spider.CaveSpiderDrowned->.zombie.DrownedEvoker->.illager.EvokerHusk->.zombie.HuskIllusioner->.illager.IllusionerParched->.skeleton.ParchedPillager->.illager.PillagerSkeleton->.skeleton.SkeletonSpellcasterIllager->.illager.SpellcasterIllagerSpider->.spider.SpiderStray->.skeleton.StrayVindicator->.illager.VindicatorWitherSkeleton->.skeleton.WitherSkeletonZombie->.zombie.ZombieZombieVillager->.zombie.ZombieVillagerZombifiedPiglin->.zombie.ZombifiedPiglin
net.minecraft.world.entity.npcAbstractVillager->.villager.AbstractVillagerVillager->.villager.VillagerVillagerData->.villager.VillagerDataVillagerDataHolder->.villager.VillagerDataHolderVillagerProfession->.villager.VillagerProfessionVillagerTrades->.villager.VillagerTradesVillagerType->.villager.VillagerTypeWanderingTrader->.wanderingtrader.WanderingTraderWanderingTraderSpawner->.wanderingtrader.WanderingTraderSpawner
net.minecraft.world.entity.projectileAbstractArrow->.arrow.AbstractArrowAbstractHurtingProjectile->.hurtingprojectile.AbstractHurtingProjectileAbstractThrownPotion->.throwableitemprojectile.AbstractThrownPotionArrow->.arrow.ArrowDragonFireball->.hurtingprojectile.DragonFireballFireball->.hurtingprojectile.FireballLargeFireball->.hurtingprojectile.LargeFireballSmallFireball->.hurtingprojectile.SmallFireballSnowball->.throwableitemprojectile.SnowballSpectralArrow->.arrow.SpectralArrowThrowableItemProjectile->.throwableitemprojectile.ThrowableItemProjectileThrownEgg->.throwableitemprojectile.ThrownEggThrownEnderpearl->.throwableitemprojectile.ThrownEnderpearlThrownExperienceBottle->.throwableitemprojectile.ThrownExperienceBottleThrownLingeringPotion->.throwableitemprojectile.ThrownLingeringPotionThrownSplashPotion->.throwableitemprojectile.ThrownSplashPotionThrownTrident->.arrow.ThrownTridentWitherSkull->.hurtingprojectile.WitherSkull
net.minecraft.world.entity.projectile.windcharge.*->.projectile.hurtingprojectile.windcharge.*net.minecraft.world.entity.vehicleAbstractBoat->.boat.AbstractBoatAbstractChestBoat->.boat.AbstractChestBoatAbstractMinecart->.minecart.AbstractMinecartAbstractMinecartContainer->.minecart.AbstractMinecartContainerBoat->.boat.BoatChestBoat->.boat.ChestBoatChestRaft->.boat.ChestRaftMinecart->.minecart.MinecartMinecartBehavior->.minecart.MinecartBehaviorMinecartChest->.minecart.MinecartChestMinecartCommandBlock->.minecart.MinecartCommandBlockMinecartFurnace->.minecart.MinecartFurnaceMinecartHopper->.minecart.MinecartHopperMinecartSpawner->.minecart.MinecartSpawnerMinecartTNT->.minecart.MinecartTNTNewMinecartBehavior->.minecart.NewMinecartBehaviorOldMinecartBehavior->.minecart.OldMinecartBehaviorRaft->.boat.Raft
net.minecraft.world.level.gamerules.GameRule#getResourceLocation->getIdentifier
Oh Hey, Another Rendering Rewrite
More of the rendering pipeline has been rewritten, with the majority focused on samplers, RenderType creation, and mipmaps.
The Separation of Samplers
Blaze3d has separated setting the AddressModes and FilterModes when reading texture data into GpuSampler. As the name implies, a GpuSampler defines how to sample data from a buffer, such as a texture. GpuSampler contains four methods: getAddressModeU / getAddressModeV for determining how the sampler should behave when reading the UV positions (either repeat or clamp), getMinFilter / getMagFilter for determining how to minify or magnify the texture respectively (either nearest neighbor or linear), getMaxAnisotropy for the largest anisotropic filtering level that can be used, and getMaxLod for the maximum level-of-detail on a texture.
Samplers can be created via GpuDevice#createSampler, but that is not necessary unless you want to specify a different anisotropic filtering level greater than 1, or a maximum level-of-detail that is not 0 or 1000. If the default, as there are only 32 possible combinations, vanilla creates all GpuSamplers and stores them in a cache, accessible via RenderSystem#getSamplerCache, followed by SamplerCache#getSampler:
// Raw call
GpuSampler sampler = RenderSystem.getDevice().createSampler(
// U address mode
AddressMode.CLAMP_TO_EDGE,
// V address mode
AddressMode.CLAMP_TO_EDGE,
// Minification filter
FilterMode.LINEAR,
// Magnification filter
FilterMode.NEAREST,
// The maximum anisotropic filtering level
// Vanilla uses either 1, 2, 4, or 8 for level rendering
4f,
// The maximum level of detail for a texture
// Vanilla either uses an 0 for the default,
// or an empty optional for moving objects and
// uploading to an atlas.
OptionalDouble.of(0.0)
);
// Sampler cache method
GpuSampler sampler = RenderSystem.getSamplerCache().getSampler(
// U address mode
AddressMode.CLAMP_TO_EDGE,
// V address mode
AddressMode.CLAMP_TO_EDGE,
// Minification filter
FilterMode.LINEAR,
// Magnification filter
FilterMode.NEAREST,
// Whether to use 1000 or 0 for the maximum level-of-detail
true
);
To make user of the sampler for a texture, when binding the texture in a render pass (via RenderPass#bindTexture), you must now specify the sampler to use in addition to the texture view:
try (RenderPass pass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(...)) {
// Set other parameters
pass.bindTexture(
// The name of the sampler2D uniform, usually in the fragment shader
"Sampler0",
// The texture to sample
...,
// The sampler to use
sampler
);
// Draw buffer
}
Setting up the post processor has not changed from the user perspective as only clamp to edge address modes may be selected.
The RenderType Shuffle
Creating a RenderType has been reworked to some degree. While most of the features from the previous implementation still exist, they have been changed to match the new rendering system where direct OpenGL is abstracted away and only accessed through their defined pipelines and RenderSystem.
Existing Types
Existing types have been moved from RenderType to RenderTypes (e.g., RenderType#solid -> RenderTypes#solid).
Custom Types
Originally, to create a RenderType, you would construct a $CompositeState using RenderStateShards. Each RenderStateShard would define how the pass should be setup and teardown when building some mesh, whether that was setting textures, the render target, model transforms, etc. Then, the $CompositeState would be built for use in whatever rendering application was needed.
The new system splits the render definition in two: the RenderSetup, and our RenderType. The RenderSetup, as the name implies, sets up the renderer to be used when drawing to a texture. Teardown is completely removed as it is either handled directly when drawing the RenderType or uses newly constructed states that can just be thrown away. RenderType, on the other hand, is simply a named RenderSetup. It only handles drawing the mesh data and making some fields of the setup public for use in other buffer implementations. Multiple types can have the same RenderSetup as a number of existing types dynamically populate the texture used by the sampler and/or the outline of the object.
A RenderSetup can be created through its builder via RenderSetup#Builder, supply the RenderPipeline to use. Once the builder properties are set, the actual setup can be created via RenderSetup$RenderSetupBuilder#createRenderSetup:
public static final RenderSetup EXAMPLE_SETUP = RenderSetup.builder(
// The pipeline to use.
// This can affect what settings are allowed from the setup.
RenderPipelines.ITEM_ENTITY_TRANSLUCENT_CULL
)
// Specifies the texture to bind to the provided sampler.
// The sampler must be defined by the pipeline via `RenderPipeline$Builder#withSampler`.
// The texture is represented as an absolute location.
.withTexture(
// 'Sampler0' is defined by the pipeline.
"Sampler0",
// Points to 'assets/minecraft/entity/wolf/wolf_armor_crackiness_low.png'.
Identifier.withDefaultNamespace("textures/entity/wolf/wolf_armor_crackiness_low.png"),
// An optional supplied `GpuSampler` to sample the texture with.
// The returned value with be cached after first resolution.
() -> RenderSystem.getSamplerCache().getClampToEdge(FilterMode.NEAREST)
)
// When set, allows the pipeline to use the light texture.
// 'Sampler2' must be defined by the pipeline via `RenderPipeline$Builder#withSampler`.
.useLightmap()
// When set, allows the pipeline to use the overlay texture.
// 'Sampler1' must be defined by the pipeline via `RenderPipeline$Builder#withSampler`.
.useOverlay()
// When set, uses `RenderTypes#crumbling` to overlay the block destroy stages
// based on the crumbling progress for an entity model.
// This is only implemented in `ModelFeatureRenderer`.
.affectsCrumbling()
// When set, sorts the quads based on the set `ProjectionType` in
// `RenderSystem#getProjectionType`.
// This is only implemented when getting the buffers from `MultiBufferSource$BufferSource`.
.sortOnUpload()
// Sets the initial capacity of the used buffer.
// This is only used when constructing the initial buffers in `RenderBuffers`
// All custom applications of sources already have some defined buffer with the determined size.
.bufferSize(786432)
// An object-wrapped consumer that transforms the model view matrix.
// Vanilla implementations exist in `LayeringTransform`, applying
// the transformation through the projection type:
// - `NO_LAYERING`: Do nothing.
// - `VIEW_OFFSET_Z_LAYERING`: Offsets the Z by 1 based on its `ProjectionType`
// - `VIEW_OFFSET_Z_LAYERING_FORWARD`: Offsets the Z by -11 based on its `ProjectionType`
.setLayeringTransform(
// We can also construct a new transform
new LayeringTransform(
// The name of the transform
"examplemod:example_layer",
// The transform should not push or pop to the stack
// Only translate, scale, or rotate
stack -> stack.translate(0f, 0.1f, 0f)
)
)
// Sets the output target that this setup should write to,
// unless overridden by the `RenderSystem#output*Override` textures.
// This is typically the main target, though it can be other vanilla
// targets or a custom one if you plan to handle it.
.setOutputTarget(OutputTarget.MAIN_TARGET)
// An object-wrapped supplier that provides the texture matrix.
// This is typically used to modify the texture UV coordinates
// in the vertex shader before sampling in the fragment shader.
// Vanilla only uses this for the glint effect and breeze/energy:
// - `DEFAULT_TEXTURING`: Do nothing.
// - `GLINT_TEXTURING`: Translates based on the glint speed, rotates pi/18, and scales by 8.
// - `ENTITY_GLINT_TEXTURING`: Translates based on the glint speed, rotates pi/18, and scales by 0.5.
// - `ARMOR_ENTITY_GLINT_TEXTURING`: Translates based on the glint speed, rotates pi/18, and scales by 0.16.
// - `$OffsetTextureTransform`: Translates the texture by the provided XY coordinates.
.setTextureTransform(
// We can also construct a new transform
new TextureTransform(
// The name of the transform
"examplemod:example_texture",
// The transform to apply to the texture
() -> new Matrix4f().translation(0f, 1f, 0f).scale(1.5f)
)
)
// Sets how an outline of the mesh should be handled:
// - `NONE`: Do nothing.
// - `IS_OUTLINE`: This is an outline and should write to the outline buffer source.
// - `AFFECTS_OUTLINE`: This defines the shape of the outline and should use `RenderTypes#OUTLINE` to draw it.
// Checked when writing to the outline buffer source or,
// if the outline color for a feature is not 0
.setOutline(RenderSetup.OutlineProperty.AFFECTS_OUTLINE)
// Builds the setup for use in a render type.
.createRenderSetup();
Then, the RenderType can be created via create.
public static final RenderType EXAMPLE_TYPE = RenderType.create(
// The name of the type for debugging
"examplemod:example_type",
// The render setup to use
EXAMPLE_SETUP
);
MeshData can be written to the output target using RenderType#draw.
Mipmap Strategy Metadata
A texture’s mcmeta can now specify the mipmap_strategy to use in the textures section. There are four available strategies, with auto defaulting to mean if there is no transparency, an cutout when there is transparency.
| Strategy | Description |
|---|---|
mean | The default that averages the color between four pixels for the current mipmap level. |
cutout | mean, except that all levels are generated from the original texture, with alpha snapped to 0 or 1 using a threshold of 0.2. |
strict_cutout | cutout, except that it sets the alpha snaps using a threshold of 0.6. |
dark_cutout | mean, except that the surrounding pixels are only included in the average if their alpha is not 0. |
// In `assets/examplemod/textures/block/example/example_block.png.mcmeta
{
"texture": {
// Uses the chosen strategy
"mipmap_strategy": "cutout",
// Determines how much the cutoff should be biased
// when determining whether a pixel is either fully
// opaque or transparent.
// Larger numbers means higher alpha cutoff while
// lower values use a lower alpha cutoff.
"alpha_cutoff_bias": 0.2
}
}
Block and Terrain Split
RenderPipelines that were used by both a standalone block and the terrain has been split into separate pipelines: one with prefix _BLOCK and _TERRAIN, respectively. This includes the solid, cutout, translucent, and tripwire pipelines. No block variant exists for the translucent pipeline.
Item Atlases
The block atlas no longer contains textures specifically for items. Those have been moved to their own atlas named minecraft:items, with the id stored at AtlasIds#ITEMS.
If a given Material can use both block and item textures, then it should be supplied with the ModelManager#BLOCK_OR_ITEM special case.
com.mojang.blaze3d.buffersGpuBuffer,sizenow uses alongfor the sizeslicenow useslongs for the length and offset
GpuBufferSlicenow useslongs for the length and offset
com.mojang.blaze3d.openglBufferStoragecreateBuffernow uses in alongfor the sizemapBuffernow useslongs for the length and offset
DirectStateAccessbufferSubDatanow uses in alongfor the offsetmapBufferRange,flushMappedBufferRange,copyBufferSubDatanow uselongs for the length and offset
GlBuffernow uses alongfor the sizeGlDevicenow takes in aShaderSourceinstead of aBiFunctiongetOrCompileShadernow takes in aShaderSourceinstead of aBiFunction
GlRenderPasssamplersnow is a hash map of strings toGlRenderPass$TextureViewAndSamplers$TextureViewAndSampler- A record that defines a sampler with its sampled texture.
GlSampler- The OpenGL implementation of a gpu sampler.GlStateManager_glBufferSubDatanow uses in alongfor the offset_glMapBufferRangenow useslongs for the length and offset
GlTexture#modesDirty,flushModeChangesare removedGlTextureView#getFbo- Gets the framebuffer object of a texture, using the cache if present.
com.mojang.blaze3d.pipeline.RenderTarget#filterMode,setFilterModeare removedcom.mojang.blaze3d.platform.TextureUtilsolidify- Modifies the texture by packing and unpacking the pixels to better help with non-darkened interiors within mipmaps.fillEmptyAreasWithDarkColor- Sets empty pixels to an empty pixel whose RGB value is the darkest color in the image.
com.mojang.blaze3d.shaders.ShaderSource- A functional interface that gets the shader source from its id and type as a string.com.mojang.blaze3d.systemsCommandEncoder#copyTextureToBuffernow uses alongfor the offsetGpuDevicecreateSampler- Creates a sampler for some source to destination with the desired address and filter modes.precompilePipelinenow takes in aShaderSourceinstead of aBiFunctiongetMaxSupportedAnisotropy- The maximum anisotropic filtering level supported by the hardware.createBuffernow uses in alongfor the size
RenderPass#bindTexturenow takes in aGpuSamplerRenderSystemnow uses in alongfor the sizesamplerCache- Returns a cache of samples containing all possible combinations.TEXTURE_COUNTis removedsetupOverlayColor,teardownOverlayColorare removedsetShaderTexture,getShaderTextureare removedsetTextureMatrix,resetTextureMatrix,getTextureMatrixare removedlineWidth->VertexConsumer#setLineWidthgetShaderLineWidth->Window#getAppropriateLineWidthinitRenderernow takes in aShaderSourceinstead of aBiFunction
SamplerCache- A cache of all possible samplers that may be used by the renderer.
com.mojang.blaze3d.texturesGpuSampler- A buffer sampler with the specified UV address modes and minification and magnification filters.GpuTextureaddressModeU->GpuSampler#getAddressModeUaddressModeV->GpuSampler#getAddressModeVminFilter->GpuSampler#getMinFiltermagFilter->GpuSampler#getMagFiltersetAddressMode,setTextureFilterhave been replaced bySamplerCache#getSampler, not one-to-oneuseMipmaps,setUseMipmapsare removed
net.minecraft.clientOptions#textureFiltering- The chosen texture sampling method when viewed at an angle or from a distance.TextureFilteringMethod- The sampling method when viewing a texture at an angle or from a distance.
net.minecraft.client.gui.render.TextureSetupnow takes in theGpuSamplers for each of the textures- This also includes the static constructors
net.minecraft.client.particle.SingleQuadParticle$Layer#ITEMS- A layer for particles with item textures.net.minecraft.client.rendererFaceInfo$Constants->$Extent$VertexInfois now a record
ItemBlockRenderTypes#getRenderType(ItemStack)LightTexture#turnOffLightLayer,turnOnLightLayerare removedLevelRenderer#resetSampler- Resets the chunk layer sampler.PostPass$Input#bilinear- Whether to use a bilinear filter.$TextureInputnow takes in abooleanrepresenting whether to use a bilinear filter
RenderPipelinesSOLID->SOLID_BLOCK,SOLID_TERRAINCUTOUT->CUTOUT_BLOCK,CUTOUT_TERRAINCUTOUT_MIPPEDis removedTRANSLUCENT->TRANSLUCENT_TERRAINTRIPWIRE->TRIPWIRE_BLOCK,TRIPWIRE_TERRAINANIMATE_SPRITE_SNIPPET,ANIMATE_SPRITE_BLIT,ANIMATE_SPRITE_INTERPOLATION- Pipelines for animated sprites.
RenderStateShardhas been replaced withRenderSetup, not one-to-one$LightmapStateShard->RenderSetup#useLightmap$OverlayStateShard->RenderSetup#useOverlay$MultiTextureStateShard,$TextureStateShard->RenderSetup#textures$LayeringStateShard->RenderSetup#layeringTransform,LayeringTransform$LineStateShard->VertexConsumer#setLineWidth$OutputStateShard->RenderSetup#outputTarget,OutputTarget$TexturingStateShard,$OffsetTexturingStateShard->RenderSetup#textureTransform,TextureTransform
RenderTypehas been split into two separate concepts, not one-to-one- All of the stored
RenderTypes have been moved toRenderTypes - The actual class usage has moved to
.rendertype.RenderType, where it does the work of$CompositeRenderType
- All of the stored
Sheets#translucentBlockItemSheet- A render type for translucent block items.
net.minecraft.client.renderer.blockBlockRenderDispatcherno longer takes in the suppliedSpecialBlockModelRendererLiquidBlockRenderernow takes in aMaterialSetsetupSpriteshas been moved into theLiquidBlockRendererconstructor
net.minecraft.client.renderer.block.modelBakedQuadvertices->position*,packedUV*, not one-to-oneposition- Gets the position vector given the index.packedUV- Gets the packed UV given the index.
BlockElementRotationnow takes in aVector3fcfor the origin and aMatrix4fctransform- The constructor also takes in a
$RotationValueinstead of aDirection$Axisand anglefloat $EulerXYZRotation- A XYZ rotation in degrees.$RotationValue- An interface that defines the rotation transformation.$SingleAxisRotation- A rotation in degrees around a single axis.
- The constructor also takes in a
FaceBakeryVERTEX_COUNT->BakedQuad#VERTEX_COUNTVERTEX_INT_SIZE,COLOR_INDEX,UV_INDEXare removedbakeQuadnow takes in aModelBaker$PartCacheextractPositionsis removed
SimpleModelWrapper#bakenow returns aBlockModelPartSimpleUnbakedGeometry#bakenow takes in aModelBakerinstead of aSpriteGetterTextureSlots$parseTextureMapno longer takes in anIdentifierVariantwithZRot- Rotates the model state around the Z axis.$SimpleModelStatenow takes in a ZQuadrantwithZ- Sets the Z quadrant of the model state.
VariantMutator#Z_ROT- Rotates a model around the Z axis.
net.minecraft.client.renderer.chunkChunkSectionLayerno longer takes in whether to use mipmapsCUTOUT_MIPPEDis removedtextureis removed
ChunkSectionsToRendernow takes in theGpuTextureViewdynamicTransforms->chunkSectionInfosrenderGroupnow takes in theGpuSampler
net.minecraft.client.renderer.itemBlockModelWrapperconstructor is now package-privatecomputeExtentsnow returns an array ofVector3fcs
ItemStackRenderState$LayerRenderStateNO_EXTENTS_SUPPLIERis now a supplied array ofVector3fcssetExtentsnow takes in a supplied array ofVector3fcs
net.minecraft.client.renderer.rendertype.RenderTypesMOVING_BLOCK_SAMPLER- A sampler for blocks that are in motion.solid->solidMovingBlockcutout->cutoutMovingBlocktripwire->tripwireMovingBlock
net.minecraft.client.renderer.textureAbstractTexture#setUseMipmapsis removedMipmapGenerator#generateMipLevelsnow takes in the name of the texture, aMipmapStrategyto determine how a specific texture should be mip mapped, and afloatfor the alpha cutoff biasMipmapStrategy- A enum defines the strategies used when constructing a mipmap for a texture.OverlayTexture#setupOverlayColor,teardownOverlayColorreplaced bygetTextureView, not one-to-oneSpriteContentsnow takes in an optionalTextureMetadataSectionto determine the sprite’s metadataUBO_SIZE- The uniform buffer object size of the sprite contents.createTicker->createAnimationState, not one-to-oneuploadFirstFrameno longer takes in the textureints, instead a mip levelint$AnimatedTexture#createTicker,uploadFirstFrame->createAnimationState, not one-to-one$Ticker->$AnimationState, not one-to-onetickAndUpload->tick,getDrawUbo,needsToDraw,drawToAtlas; not one-to-one
SpriteTickerinterface is removedStitchernow takes in the anisotropic filtering level$Holder(T, int)is removed$Region#walknow takes in a paddingint$SpriteLoaderno longer takes in the minimum width/heightloadnow takes in a paddingint
TextureAtlasnow implementsTickableTextureinstead ofTickableTextureAtlasSpritenow implementsAutoCloseable- The constructor takes in a padding
int createTicker->createAnimationState, not one-to-onegetUOffset,getVOffset,uvShrinkRatioare removeduploadFirstFramenow takes in the mip levelintuploadSpriteUbo- Uploads the atlas sprite to the to the buffer.$Tickerinterface is removed
- The constructor takes in a padding
TextureManagerno longer implementsTickableTickable->TickableTexture
net.minecraft.client.renderer.texture.atlasSpriteSource$SpriteSupplier->$DiscardableLoaderFunctionsuperinterface is now represented as$Loaderapply->get
SpriteSourceList#listnow returns a list ofSpriteSource$Loaders
net.minecraft.client.resources.metadata.texture.TextureMetadataSectionnow takes in aMipmapStrategyto determine how a specific texture should be mip mapped, and afloatfor the alpha cutoff biasnet.minecraft.client.resources.modelModelBakermissingBlockModelPart- The missing block model.parts- A cache of previously constructed vectors.$PartCache- A cache that interns previously constructed vertices in a quad.
ModelBakery*_STILL- Fluid still texture locations.$MissingModelsnow takes in aBlockModelPartmissing model
ModelManagerBLOCK_OR_ITEM- A special case that causes the model manager to check both the item and block atlas.specialBlockModelRenderernow returns the raw renderer instead of a supplied value.
net.minecraft.data.AtlasIds#ITEMS- The item atlas identifier.net.minecraft.world.level.block.LeavesBlock#setCutoutLeaves- Sets whether the leaves is using cutout rendering.
Gizmos
Gizmos are the newest iteration in the submission and rendering decoupling, this time for debug renderers. However, the underlying structure to submit gizmos for rendering is much more complex since debug renderers can submit objects at nearly any point during the client’s process.
What is a Gizmo?
A Gizmo is basically an object that submits some object primitives – specifically points, lines, triangle fans, quads, and text – for rendering. Each gizmo essentially strings together these primitives via emit into its desired shape. During the render process, these make use of the RenderPipelines#DEBUG_* pipelines to render their primitives to the screen. Creating a new gizmo is as simple as extending the interface:
// Store some parameters like a render state to submit the element primitives
public record ExampleGizmo(Vec3 start, Vec3 end) implements Gizmo {
@Override
public void emit(GizmoPrimitives gizmos, float alphaMultiplier) {
// Submit any elements here
gizmos.addLine(this.start, this.end, ARGB.multiplyAlpha(0, alphaMultiplier), 3f);
}
}
Actually submitting the elements happens through Gizmos#addGizmo. This stores the gizmo to be emitted and drawn to the screen, as long as it is called during Minecraft#tick or any rendering on the client – which is how the debug renderers emit theirs, IntegratedServer#tickServer in a singleplayer world, or packet processing on either side. All of the methods in Gizmos call addGizmo internally, which is why the method is typically absent outside its class:
// Somewhere in GameRenderer#render
Gizmos.addGizmo(new ExampleGizmo(Vec3.ZERO, Vec3.X_AXIS));
// Calls addGizmo internally
Gizmos.point(Vec3.ZERO, 0, 5f);
Calling addGizmo returns a GizmoProperties, which sets some properties for when the element is drawn, assuming that GizmoCollector is not a NOOP. GizmoProperties provides three methods:
| Method | Description |
|---|---|
setAlwaysOnTop | Clears the depth texture before rendering. |
persistForMillis | Keeps the gizmo on screen for the specified amount of time before disappearing. |
fadeOut | Fades the disappearing when persisted for a certain amount of time. |
Putting it Together
With that, how can you submit gizmos for rendering pretty much anywhere in the client pipeline? Well, this all starts from Gizmos#withCollector and SimpleGizmoCollector.
SimpleGizmoCollector is basically just a list that holds the collected gizmos to render. During the rendering process, SimpleGizmoCollector#drainGizmos is called, copying the gizmos over to a separate list for the renderer to Gizmo#emit, before drawing to the screen through the familiar frame pass and buffer source. drainGizmos then clears the internal list based on GizmoProperties#persistForMillis, or immediately if not specified, for the next frame.
To actually collect these elements, there is a rather convoluted process. Minecraft, LevelRenderer, and IntegratedServer have their own SimpleGizmoCollector. This is done by setting the collector using Gizmo#withCollector, which returns a Gizmos$TemporaryCollection. The collection is AutoCloseable that, when closed, releases the held collector on the local thread. So, the collectors are wrapped in a try-with-resources to facilitate the submission during these periods. Then, during the debug pass, the per tick gizmos are merged with the per frame gizmos and drawn to the screen via addTemporaryGizmos, quite literally at the last moment in LevelRenderer#renderLevel. The IntegratedServer gizmos in a singleplayer world are stored in a volatile field, allowing it to be accessed from the client thread.
net.minecraft.client.MinecraftcollectPerTickGizmos- Returns a collection of all gizmos to emit.getPerTickGizmos- Gets the gizmos to draw to the screen.
net.minecraft.client.rendererLevelRenderer#collectPerFrameGizmos- Returns a collection of all gizmos to emit.OrderedSubmitNodeCollector#submitHitboxis removedShapeRendererrenderShapenow takes in a line widthfloatrenderLineBox->Gizmos#cuboid, not one-to-oneaddChainedFilledBoxVertices->Gizmos#cuboid, not one-to-onerenderFace->Gizmos#rect, not one-to-onerenderVector->Gizmos#line, not one-to-one
SubmitNodeCollection#getHitboxSubmitsis removedSubmitNodeStorage$HitboxSubmitrecord is removed
net.minecraft.client.renderer.debugDebugRendererrender->emitGizmos, no longer takes in thePoseStack,BufferSourceorboolean, now taking in the partial tickfloatrenderFilledUnitCube->Gizmos#cuboid, not one-to-onerenderFilledBox->Gizmos#cuboid, not one-to-onerenderTextOverBlock->Gizmos#billboardTextOverBlock, not one-to-onerenderTextOverMob->Gizmos#billboardTextOverMob, not one-to-onerenderFloatingText->Gizmos#billboardText, not one-to-onerenderVoxelShape->LevelRenderer#renderHitOutline, now private, not one-to-oneSimpleDebugRenderer$render->emitGizmos, no longer takes in thePoseStack,BufferSourceorboolean, now taking in the partial tickfloat
GameTestBlockHighlightRendererrender->emitGizmos, taking in no parametersrenderMarkerno longer takes in thePoseStackor buffer source$Marker#get*are removed
LightDebugRenderernow takes in two flags determining whether to show the block or sky lightPathfindingRenderer#renderPath,renderPathLineno longer take in thePoseStackor buffer source
net.minecraft.client.renderer.entity.EntityRenderer#extractAdditionalHitboxesis removednet.minecraft.client.renderer.entity.stateEntityRenderState#hitboxesRenderState,serverHitboxesRenderStateare removedHitboxesRenderStateclass is removedServerHitboxesRenderStateclass is removed
net.minecraft.client.renderer.feature.HitboxFeatureRenderer->EntityHitboxDebugRenderer, not one-to-onenet.minecraft.client.renderer.gizmos.DrawableGizmoPrimitives- A storage and renderer for primitive shapes. or gizmos.net.minecraft.client.renderer.textureAbstractTexturesampler,getSampler- Returns theGpuSamplerused by the texture.setClamp->GpuSampler#getAddressMode*, not one-to-onesetFilter->GpuSampler#get*Filter, not one-to-one
ReloadableTextureno longer takes in the address mode and filterbooleans
net.minecraft.client.server.IntegratedServer#getPerTickGizmos- Gets the gizmos to draw to the screen for the current tick.net.minecraft.gizmosArrowGizmo- A gizmo that draws an arrow.CircleGizmo- A gizmo that draws an approximate circle with twenty vertices.CuboidGizmo- A gizmo that draws a rectangular prism.Gizmo- An object that can emit simple shape primitives to draw.GizmoCollector- An add-only collector.GizmoPrimitives- Shape primitives that can be drawn.GizmoProperties- Properties that apply to how the gizmo should be drawn.Gizmos- A collection of static methods for creating gizmos and collecting them.GizmoStyle- A property holder to define how a gizmo should be drawn. These are used by the gizmos themselves and not the actual primitives.LineGizmo- A gizmo that draws a line.PointGizmo- A gizmo that draws a point.RectGizmo- A gizmo that draws a rectangle.SimpleGizmoCollector- A collector implementation for adding gizmos before sending them off for rendering.TextGizmo- A gizmo that draws text.
net.minecraft.server.MinecraftServer#processPacketsAndTick- Handles server ticking and packet processing.
Permission Overhaul
The permission level integer has been expanded into an entirely new system that is both simple yet complicated. There are three main parts: Permissions, PermissionSets, and PermissionChecks.
Permissions
Permissions are functionally data objects that define some sort of state. Vanilla provides two types of permissions: Permission$Atom, which just is a unique unit object; and Permission$HasCommandLevel, which holds the desired PermissionLevel for a command. Both of the data objects are registered as map codecs for dumping the command report.
// Attempts to query moderator level permissions.
public static final Permission COMMANDS_MODERATOR = new Permission.HasCommandLevel(PermissionLevel.MODERATORS);
A custom permission can be created through some class or record that extends Permission with an associated MapCodec registered to its static registry:
// This does not check whether the user has the given permission
// It is literally just holding data representing the permission state
public record HasExamplePermission(int state) implements Permission {
public static final MapCodec<HasExamplePermission> MAP_CODEC = Codec.INT.fieldOf("state")
.xmap(HasExamplePermission::new, HasExamplePermission::state);
@Override
public MapCodec<HasExamplePermission> codec() {
return HasExamplePermission.MAP_CODEC;
}
}
// In some registration handler
Registry.register(
BuiltInRegistries.PERMISSION_TYPE
Identifier.withNamespaceAndPath("examplemod", "has_example_permission"),
HasExamplePermission.MAP_CODEC
);
// Storing the permission for use
public static final Permission HAS_STATE_ONE = new HasExamplePermission(1);
Permission Sets
If Permissions define the queryable state, then PermissionSets are the permissions the user actually has. PermissionSet is a functional interface that checks whether the user has the desired permission state (via hasPermission). Vanilla uses a LevelBasedPermissionSet for checking whether the permission queried matches the current PermissionLevel. As a permission set is usually checked against some swathe of permissions, multiple permission sets can be combined into one via PermissionSet#union. It functionally performs an OR operation, meaning that if a set does not check a permission, it should default to false.
public interface ExamplePermissionSet extends PermissionSet {
// Keep track of the user's state for our permissions
int state();
@Override
default boolean hasPermission(Permission permission) {
// Check our permission
if (permission instanceof HasExamplePermission example) {
return this.state() >= example.state();
}
// Otherwise ignore
return false;
}
}
// Storing a permission set
// Could also be implemented or stored on the desired target
public static ExamplePermissionSet STATE_ONE = () -> 1;
// Check whether the permission set has the desired permission
STATE_ONE.hasPermission(HAS_STATE_ONE);
Currently, there is no simple method to store custom permission sets on the desired user. CommandSourceStack does have a method to union other permission sets via withMaximumPermission, but that would need to be handled within the associated createCommandSourceStack method. The normal LevelBasedPermissionSet can typically be queried through a permissions method, though there is no common interface across objects, even though PermissionSetSupplier seems to exist for that purpose.
Permission Checks
Now, a PermissionSet never directly checks a Permission within the codebase. That would require having the object accessible at all times. Instead, a PermissionCheck object is created, which takes in the PermissionSet and checks whether the user has the desired data to continue execution. Vanilla provides two types of checks: $AlwaysPass, which means it will always return true; and $Require, which requires the set to have the desired Permission. The checks also have a map codec for dumping the command report.
// Requires the permission set has acccess to moderator commands
public static final PermissionCheck LEVEL_MODERATORS = new PermissionCheck.Require(COMMANDS_MODERATOR);
Custom permission checks can be created through some class or record that implements check and registers the map codec to its static registry:
public static record AnyOf(List<Permission> permissions) implements PermissionCheck {
public static final MapCodec<AnyOf> MAP_CODEC = Permission.CODEC.listOf().fieldOf("permissions")
.xmap(AnyOf::new, AnyOf::permissions);
@Override
public boolean check(PermissionSet permissionSet) {
return this.permissions.stream().filter(perm -> permissionSet.hasPermission(perm)).findAny().isPresent();
}
@Override
public MapCodec<AnyOf> codec() {
return MAP_CODEC;
}
}
// In some registration handler
Registry.register(
BuiltInRegistries.PERMISSION_CHECK_TYPE
Identifier.withNamespaceAndPath("examplemod", "any_of"),
AnyOf.MAP_CODEC
);
// Storing the check for use in a command
public static final PermissionCheck CHECK_STATE_ONE = new AnyOf(List.of(
HAS_STATE_ONE,
Permissions.COMMANDS_GAMEMASTER
));
// For some command
Commands.literal("example").requires(Commands.hasPermission(CHECK_STATE_ONE));
net.minecraft.client.multiplayer.ClientSuggestionProviderno longer implementsPermissionSource- The constructor now takes in a
PermissionSetinstead of aboolean allowsRestrictedCommands->ClientPacketListener#ALLOW_RESTRICTED_COMMANDS, now private, not one-to-one
- The constructor now takes in a
net.minecraft.client.player.LocalPlayer#setPermissionLevel->setPermissions, not one-to-onenet.minecraft.commandsCommandsLEVEL_*are nowPermissionChecks instead ofintshasPermissionnow takes in aPermissionCheckinstead of anint, and returns aPermissionProviderCheckinstead of aPermissionCheckcreateCompilationContext- Creates a source stack with the given permissions.
CommandSourceStackno longer implementsPermissionSource- The constructor now takes in a
PermissionSetinstead of anint - The
protectedconstructor is nowprivate withPermissionnow takes in aPermissionSetinstead of anintwithMaximumPermissionnow takes in aPermissionSetinstead of anint
- The constructor now takes in a
ExecutionCommandSourcenow extendsPermissionSetSupplierinstead ofPermissionSourcePermissionSourceinterface is removedSharedSuggestionProvidernow extendsPermissionSetSupplier
net.minecraft.commands.arguments.selector.EntitySelectorParser#allowSelectorsnow has an overload that takes in aPermissionSetSuppliernet.minecraft.core.registriesBuiltInRegistries#PERMISSION_TYPE,Registries#PERMISSION_TYPE- An object that defines some data requirement.BuiltInRegistries#PERMISSION_CHECK_TYPE,Registries#PERMISSION_CHECK_TYPE- A predicate that checks whether the set has the required data.
net.minecraft.serverMinecraftServeroperatorUserPermissionLevel->operatorUserPermissions, not one-to-onegetFunctionCompilationLevel->getFunctionCompilationPermissions, not one-to-onegetProfilePermissionsnow returns aLevelBasedPermissionSet
ReloadableServerResources#loadResourcesnow takes in aPermissionSetinstead of anintServerFunctionLibrarynow takes in aPermissionSetinstead of anintWorldLoader$InitConfignow takes in aPermissionSetinstead of anint
net.minecraft.server.commands.PermissionCheck->.server.permissions.PermissionCheck, not one-to-onenet.minecraft.server.dedicated.DedicatedServerPropertiesopPermissionLevel->opPermissions, not one-to-onefunctionPermissionLevel->functionPermissions, not one-to-onedeserializePermissions,serializePermission- Reads and writes the chosen level permission set.
net.minecraft.server.jsonrpc.internalapiMinecraftOperatorListService#opnow takes in an optionalPermissionLevelinstead of anintMinecraftServerSettingsServicegetOperatorUserPermissionLevel->getOperatorUserPermissions, not one-to-onesetOperatorUserPermissionLevel->setOperatorUserPermissions, not one-to-one
net.minecraft.server.jsonrpc.methodsOperatorService$OperatorDto#permissionLevelnow takes in an optionalPermissionLevelinstead of anintServerSettingsServiceoperatorUserPermissionLevelnow returns aPermissionLevelinstead of anintsetOperatorUserPermissionLevelnow takes in and returns aPermissionLevelinstead of anint
net.minecraft.server.permissionsLevelBasedPermissionSet- A set of permissions that checks whether the user has an equal or higher command permission level.Permission- Data related to the user’s permissions, such as command level.PermissionCheckTypes- The types of permission checks vanilla provides.PermissionLevel- Defines a level sequence for a permission.PermissionProviderCheck- A predicate that checks that tests the supplier’s permission set against a check.Permissions- The permissions vanilla provides.PermissionSet- A set of a permissions to user has, but mostly defines a method to determine whether a user has the desired permission.PermissionSetSupplier- An object that supplies aPermissionSet.PermissionSetUnion- A union of multiple permission sets.PermissionTypes- The types of permissions vanilla provides.
net.minecraft.server.playersPlayersList#opnow takes in an optionalLevelBasedPermissionSetinstead of anintServerOpListEntrynow takes in aLevelBasedPermissionSetinstead of anintgetLevel->permissions, not one-to-one
net.minecraft.world.entity.player.Player#getPermissionLevel,hasPermissions->permissions, not one-to-onenet.minecraft.world.entity.projectile.ProjectileUtilsgetHitEntitiesAlong- Gets the entities hit along the provided path.getManyEntityHitResult- Gets all entities hit along the path of the two points within the bounding box.
net.minecraft.world.entity.projectile.arrow.AbstractArrow#findHitEntities- Gets all entities hit by the vector.
New Data Components
With the addition of the spear, a number of data components have been added to provide the associated functionality. The following is an brief overview of these components.
Use Effects
DataComponents#USE_EFFECTS defines some effects to apply to the player that is using (e.g., right-clicking) an item. Currently, there are only three types of effects: whether the player can sprint when using the item, whether the use interaction causes vibrations, and the scalar that is applied to the player’s horizontal movement.
// For some item registration
new Item(new Item.Properties.component(
DataComponents.USE_EFFECTS,
new UseEffects(
// Whether the player can sprint while using the item
true,
// Whether on item use that a vibration is sent from the player
false
// The scalar applied to the player's horizontal movement
0.5f
)
));
Damage Type
DataComponents#DAMAGE_TYPE defines the damage type applied to an entity when hit with this item. It takes in either the ResourceKey of the damage type or the DamageType object itself.
// For some item registration
new Item(new Item.Properties.component(
DataComponents.DAMAGE_TYPE,
new EitherHolder<>(
// The damage type this item applies to the attacked entity
DamageTypes.FALLING_ANVIL
)
));
Swing Animation
DataComponents#SWING_ANIMATION defines the animation to play when swinging or attacking (e.g., left-clicking) with the item. There are three types of animation to play: SwingAnimationType#NONE, which does nothing; WHACK, which plays the standard swing animation; and STAB, which plays the spear thrust animation. The length of the animation can also be specified.
// For some item registration
new Item(new Item.Properties.component(
DataComponents.SWING_ANIMATION,
new SwingAnimation(
// The animation to play
SwingAnimationType.NONE,
// The amount of time to play the animation for, in ticks
20
)
));
Minimum Attack Charge
DataComponents#MINIMUM_ATTACK_CHARGE determines how long the player must wait before making another attack with the item. The charge is a value between 0 and 1, which determines percentage of the delay to wait before making another attack. The delay is determined by the player’s attack speed. This is checked twice if the player’s action is a stab.
// For some item registration
new Item(new Item.Properties.component(
DataComponents.MINIMUM_ATTACK_CHARGE,
// The percentage of time the player must wait before making another attack with this item
0.5f
));
Attack Range
DataComponents#ATTACK_RANGE determines the range that an entity can attack another entity from when attacking with this item. If not set, it defaults to the entity’s interaction range attribute. The range specified is for the player, with mob reach determined by the range times the mob factor. A range can also be specified for the player when in creative mode, overriding the default range.
// For some item registration
new Item(new Item.Properties.component(
DataComponents.ATTACK_RANGE,
new AttackRange(
// The minimum range in blocks for this item to hit the entity.
// Must be between [0, 64]; defaults to 0.
0.4f,
// The maximum range in blocks for this item to hit the entity.
// Must be between [0,64]; defaults to 3.
4.5f,
// The minimum range in blocks for this item to hit the entity,
// provided the holding entity is a player in creative mode.
// This supercedes the minimum range.
// Must be between [0, 64]; defaults to 0.
0f,
// The maximum range in blocks for this item to hit the entity,
// provided the holding entity is a player in creative mode.
// This supercedes the maximum range.
// Must be between [0,64]; defaults to 3.
5f,
// The margin to inflate the hitbox by in blocks, compensating
// for potential precision issues.
// Must be between [0,1]; defaults to 0.3.
0.25f,
// A scalar to multiply the minimum and maximum range by to determine
// a non-player entity's reach.
// Must be between [0,2]; defaults to 1.
1.1f
)
));
Piercing Weapon
DataComponents#PIERCING_WEAPON sets the player’s attack as not an attack, but as a stab or piercing attack. This is a separate action than swinging, which either attacks the entity or breaks a block. A piercing weapon can attack an entity, but is unable to break blocks. It also applies any enchantment effects for lunging. Piercing weapons are only applied to the player.
The logic pipeline flows like so:
- If
Player#cannotAttackWithItemreturns true, then the pipeline is terminated - Piercing attack is handled via:
- Client -
MultiPlayerGameMode#piercingAttack - Server -
PiercingWeapon#attack
- Client -
- Server-only:
- Get all entities that:
- Are within the entity’s attack range
DataComponents#ATTACK_RANGE - Are within the hitbox constructed from the reach starting at the player’s eye position
- If
PiercingWeapon#canHitEntityreturns true:- Player is not invulnerable or dead, and
- Either:
- Entity is an
Interactionentity
- Entity is an
- Or:
- Entity can be hit by a projectile
- If both players, that this player can harm the other player
- Is not a passenger of the same vehicle
- Are within the entity’s attack range
- Call
LivingEntity#stabAttackon each entity
- Get all entities that:
LivingEntity#onAttackis firedLivingEntity#lungeForwardMaybeis fired- Server-only:
PiercingWeapon#makeHitSoundis played if at least one entity was hitPiercingWeapon#makeSoundis played
LivingEntity#swingis fired
// For some item registration
new Item(new Item.Properties.component(
DataComponents.PIERCING_WEAPON,
new PiercingWeapon(
// Whether being hit by this item deals knockback to the entity.
true,
// Whether being hit by this item dismounts the entity from its vehicle.
true,
// The sound to play when attacking with this item.
// If the optional is empty, no sound is played.
Optional.of(SoundEvents.LLAMA_SWAG),
// The sound to play when this item hits an entity.
// If the optional is empty, no sound is played.
Optional.of(SoundEvents.ITEM_BREAK)
)
));
Kinetic Weapon
DataComponents#KINETIC_WEAPON affects an entity’s use (e.g., right-click) behavior. On right-click, if an item has the component, then KineticWeapon#damageEntities is called every tick instead of Item#onUseTick, only on the server. The kinetic weapon also calls LivingEntity#stabAttack to damage its entities similar to piercing attack. In fact, the component itself is similar to PiercingWeapon, except with a few additional fields to handle the kinetic damage applied and to make it accessible to all living entities instead of only the player.
For the stab attack to occur, one of the conditions (dismount, knockback, damage) must be present and return true. The attack range is obtained from the DataComponents#ATTACK_RANGE component. If a stab attack occurs, then the SPEAR_MOBS_TRIGGER criteria will be fired on the server.
// For some item registration
new Item(new Item.Properties.component(
DataComponents.KINETIC_WEAPON,
new KineticWeapon(
// The number of ticks to wait before this entity can attempt to contact
// (e.g., damage) another entity.
10,
// The number of ticks to wait before attempting to stab any entities in range.
20,
// The condition to check whether an attack from this item will dismount
// an entity in a vehicle.
// If the optional is not present, then it will default to false.
Optional.of(new KineticWeapon.Condition(
// The maximum number of ticks from first use plus delay that this
// condition may return true.
100,
// The minimum speed the entity must be traveling for this condition
// to succeed.
// The speed is calculated as the dot product of the delta movement
// and the view vector multiplied by 20.
// Vanilla spears use values from 7-14 for dismount and 5.1 for knockback.
9f,
// The minimum speed relative to the attacking entity that this entity
// must be traveling for this condition to succeed.
// Vanilla spears use 4.6 for damage.
5f
)),
// The condition to check whether an attack from this item will cause knockback
// to an entity.
// If the optional is not present, then it will default to false.
Optional.of(KineticWeapon.Condition.ofAttackerSpeed(
// Maximum ticks
100,
// Entity traveling speed
5.1f
)),
// The condition to check whether an attack from this item will damage an
// entity.
// If the optional is not present, then it will default to false.
Optional.of(KineticWeapon.Condition.ofRelativeSpeed(
// Maximum ticks
100,
// Relative traveling speed
4.6f
)),
// The movement of the item during the third person attack animation
// Vanilla spears use 0.38.
0.38f,
// A multiplier to apply to the damage of an entity
// The damage is calculated as the relative traveling speed of this entity
// to its target.
4f,
// The sound to play when first using this item.
// If the optional is empty, no sound is played.
Optional.of(SoundEvents.LLAMA_SWAG),
// The sound to play when this item hits an entity.
// If the optional is empty, no sound is played.
Optiona.of(SoundEvents.ITEM_BREAK)
)
));
net.minecraft.core.componentsDataComponentsUSE_EFFECTS- The effects to apply to the entity when using the item.MINIMUM_ATTACK_CHARGE- The minimum amount of time to attack with the item.DAMAGE_TYPE- TheDamageTypethe item dealsPIERCING_WEAPON- A weapon with some hitbox range that lunges towards the entity.KINETIC_WEAPON- A weapon with some hitbox range that requires some amount of forward momentum.SWING_ANIMATION- The animation applied when swinging an item.ATTACK_RANGE- Sets a custom attack range when using the item, overriding the normal entity interaction range.
net.minecraft.core.component.DataComponentType#ignoreSwapAnimation,$Builder#ignoreSwapAnimation- When true, the swap animation does not affect the data component ‘usage’.net.minecraft.core.component.predicatesAnyValue- A predicate that checks if the component exists on the getter.DataComponentPredicate$Typeis now an interface- Its original implementation has been replaced by
$TypeBase
- Its original implementation has been replaced by
$AnyValueType- A type that uses theAnyValuepredicate.$ConcreteType- A type that defines a specific predicate.
net.minecraft.network.protocol.game.ServerboundInteractPacket#isWithinRange- Whether the interaction from the player is within the valid range to execute.net.minecraft.world.entityLivingEntitySWING_DURATION->SwingAnimation#duration, not one-to-onestabbedEntities- The number of recent entities attacked by a kinetic weapon.entityAttackRange- The range that this entity can attack.getActiveItem- The currently used item, or the mainhand item.
MobchargeSpeedModifier- The modifier applied to the movement speed when charging.canFireProjectileWeapon->canUseNonMeleeWeapon, now taking in anItemStackinstead of aProjectileWeaponItemgetAttackBoundingBoxnow takes in a horizontal inflation offset
net.minecraft.world.entity.ai.behaviorChargeAttack- Handles a charge attack performed by a mob.SpearApproach- Approaches the enemy when holding a kinetic weapon.SpearAttack- Attacks the enemy with a kinetic weapon.SpearRetreat- Flees from the attacked target after using a kinetic weapon.
net.minecraft.world.entity.ai.goal.SpearUseGoal- Handles a mob using a spear.net.minecraft.world.entity.ai.memory.MemoryModuleTypeSPEAR_FLEEING_TIME- The number of ticks the entity has been fleeing for after using a kinetic weapon.SPEAR_FLEEING_POSITION- The position the entity flees to after using a kinetic weapon.SPEAR_CHARGE_POSITION- The position the entity charges to when using a kinetic weapon.SPEAR_ENGAGE_TIME- How long this entity has been engaged with its enemy when using a kinetic weapon.SPEAR_STATUS- The status of the entity when using a kinetic weapon.
net.minecraft.world.entity.player.PlayerhasEnoughFoodToDoExhaustiveManoeuvres- Returns whether the player can perform an exhaustive manuever.canInteractWithEntity->isWithinEntityInteractionRangeisWithinAttackRange- If the bounding box being targeted is within the player’s range.canInteractWithBlock->isWithinBlockInteractionRangeCREATIVE_ENTITY_INTERACTION_RANGE_MODIFIER_VALUE- A modifiers that increases the maximum range of an interaction by the given amount.
net.minecraft.world.itemItem#getDamageSource->getItemDamageSource, now deprecatedItemStackgetSwingAnimation- Returns the swing animation of the item.getDamageSource- Returns the damage source the item provides when hit.causeUseVibration- Sends the game event if the item on use can cause vibrations.
SwingAnimationType- The type of animation played when swinging the item.
net.minecraft.world.item.componentAttackRange- The hitbox range of this item.KineticWeapon- A weapon that requires some amount of forward momentum.PiercingWeapon- A weapon that lunges towards the entity.SwingAnimation- The animation applied when swinging an item.UseEffects- The effects to apply to the entity when using the item.
The Timeline of Environment Attributes
Environment attributes, as the name implies, defines a set of properties or modifications (‘attributes’) for a given dimension and/or biome (‘environment’). They are stored directly within the biome or dimension type under the attributes field, or as part of a mutable timeline under the tracks field. Each attribute can represent anything from the visual settings to gameplay behavior, interpolating between different values as defined. Vanilla provides their available attributes within EnvironmentAttributes while the stored attributes are obtained from Level#environmentAttributes.
// For some DimensionType json
// In `data/examplemod/dimension_type/example_dimension.json`
{
// Defines the attributes to apply within the dimension
"attributes": {
// Sets the cloud height
// More technically, modifies the value by overriding it
"minecraft:visual/cloud_height": 90
},
// ...
}
// For some Biome json
// In `data/examplemod/worldgen/biome/example_biome.json`
{
// Defines the attributes to apply within the biome
// Defaults or modifies those in the dimension
// These attributes must be positional
"attributes": {
"minecraft:visual/cloud_height": {
// Instead of setting the value, apply a modifier
"modifier": "add",
// Adds 60 to 90, making this biome have a cloud height of 150
"argument": 60
}
}
// ...
}
// For some Timeline json
// In `data/examplemod/timeline/example_timeline.json
{
// The number of ticks this track takes before repeating
"period_ticks": 24000,
// Defines the attributes to interpolate between
// based on the defined keyframes.
// Defaults or modifies those in the biome, or dimension
"tracks": {
"minecraft:visual/cloud_height": {
// The keyframes that define certain values of the attribute
"keyframes": [
{
// The tick representing the keyframe
"tick": 12000,
// The argument that modifies the value
// In this case, adds 1 to 60 + 90, making this have a cloud height of 151
"value": 1
},
{
// The tick representing the keyframe
"tick": 23999,
// The argument that modifies the value
// In this case, adds 0 to 60 + 90, making this have a cloud height of 150
"value": 0
}
],
// Instead of setting the value, applies a modifier to the argument
"modifier": "add",
// The sampler function to apply when interpolating between ticks
"ease": "linear"
}
}
}
When calling EnvironmentAttributeSystem#getValue, the attribute value is obtained through the layers defined by the Level:
- Read the default value from the registered attribute (via
EnvironmentAttribute#defaultValue). - Apply the modifier from the dimension, or do nothing if one does not exist for this attribute.
- Apply the modifier from the biome, or do nothing if one does not exist.
- Apply the modifiers from all active timelines defined in the
DimensionType, or do nothing if none exist. Timeline order is not guaranteed. - If the dimension can have weather (skylight, no ceiling, and not the end), apply the modifiers from the
WeatherAttributes. - If on the client (i.e.
ClientLevel), apply the sky flashes modifier. - Sanitize the final value to be in the range defined by the
EnvironmentAttribute.
This is highly oversimplified and introduces many new concepts, so let’s break it down further by creating our own environment attribute and timeline.
Custom Environment Attributes
Environment attributes are created through the $Builder, via EnvironmentAttribute#builder, taking the type value it represents (e.g., float, integer, object). The builder only requires one value to be set: the defaultValue. This is used if the attribute is not overridden by a dimension or biome. If the attribute value should have a valid set of states, then an AttributeRange can be set via valueRange. The AttributeRange is basically a unary operator that transforms the input into its ‘valid’ state via sanitize. It also verifies that the value passed in through the JSON is in a ‘valid’ state via validate.
From there, there are three more methods responsible for determining the logic used to compute the value. $Builder#syncable syncs the attribute to the client, which is required for any attribute that causes some sort of change that is not specific to the server (e.g., visuals, audio, or common code). notPositional means that the attribute cannot be applied on a biome (still settable in a dimension or timeline), else an exception is thrown. Finally spatiallyInterpolated will attempt to interpolate using the attribute type between different biomes to apply a more seamless transition. Vanilla only handles client side attributes for spatial interpolation. Anything on the server must handle their own SpatialAttributeInterpolator.
Finally the actual attribute can be obtained via $Builder#build. This value must be registered to BuiltInRegistries#ENVIRONMENT_ATTRIBUTE:
public static final EnvironmentAttribute<Boolean> EXAMPLE_ATTRIBUTE = Registry.register(
BuiltInRegistries.ENVIRONMENT_ATTRIBUTE,
Identifier.withNamespaceAndPath("examplemod", "example_attribute"),
EnvironmentAttribute.builder(
// The attribute type
// Must match the generic for the attribute value
AttributeTypes.BOOLEAN
)
// The value this attribute should have by default
.defaultValue(false)
// Syncs this value to the client
.syncable()
.build()
);
// For some DimensionType json
// In `data/examplemod/dimension_type/example_dimension.json`
{
"attributes": {
"examplemod:example_attribute": true
},
// ...
}
// For some Biome json
// In `data/examplemod/worldgen/biome/example_biome.json`
{
"attributes": {
"examplemod:example_attribute": {
"modifier": "xor",
"argument": true
}
}
// ...
}
// For some Timeline json
// In `data/examplemod/timeline/example_timeline.json
{
"period_ticks": 24000,
"tracks": {
"examplemod:example_attribute": {
"keyframes": [
{
"tick": 12000,
"value": false
},
{
"tick": 23999,
"value": true
}
],
"modifier": "and",
"ease": "linear"
}
}
}
Custom Attribute Types
Every environment attribute has an associated attribute type that is statically registered to BuiltInRegistries#ATTRIBUTE_TYPE. Not only does this define how to serialize the object value, but it also contains the modifications that can be applied to the value along with how to interpolate between spaces and frames. In fact, all of the builder settings, including syncable and spatiallyInterpolated, rely on the attribute type to determine what does it mean to perform that action. Without it, the attribute couldn’t even be read from the dimension or biome JSON, much less the actual logic behind getting the value of the attribute.
As such, the attribute type can be broken into three parts: the serialization codec, the modifier library, and the interpolation functions.
// We will use this example object for explaining the attribute type
public record ExampleObject(int value1, boolean value2) {
// The default value
public static final ExampleObject DEFAULT = new ExampleObject(0, false);
}
Type Serialization
Serialization of the attribute type is handled through a codec of that type, both to disk (biome and dimension JSON) and network ($Builder#syncable):
// The codec to serialize the attribute type value
public static final Codec<ExampleObject> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
Codec.INT.fieldOf("value1").forGetter(ExampleObject::value1),
Codec.BOOL.fieldOf("value2").forGetter(ExampleObject::value2)
).apply(instance, ExampleObject::new)
);
Modifier Library
The modifier library is a map of AttributeModifier$OperationId to AttributeModifiers that determine what operations can be performed on the default value. If the map contains no operations, the the default value cannot be mutated. All of the static constructors for AttributeType add the OVERRIDE modifier, allowing for the dimension and/or biome to set the value. This map should be thought of as a pseudo-registry (basically keys to unique values), as the default codec used to serialize is for a BiMap via an id resolver.
An AttributeModifier defines two generics: the first being the environment attribute value type, and the second being an arbitrary object to apply the operation with. The modifier has two methods: apply, which takes in the value and the argument to return a new value; and argumentCodec to properly serialize the argument. For any operation, all possible mutations must be implemented within a single AttributeModifier:
// Modifiers only handling a part of the object
public static final AttributeModifier<ExampleObject, Integer> ADD = new AttributeModifier<>() {
@Override
public ExampleObject apply(ExampleObject subject, Integer argument) {
// Apply the operation to the subject
return new ExampleObject(subject.value1() + argument, subject.value2());
}
@Override
public Codec<Integer> argumentCodec(EnvironmentAttribute<ExampleObject> attribute) {
// Construct the codec to deserialize the argument
return Codec.INT;
}
};
public static final AttributeModifier<ExampleObject, Boolean> OR = new AttributeModifier<>() {
@Override
public ExampleObject apply(ExampleObject subject, Boolean argument) {
// Apply the operation to the subject
return new ExampleObject(subject.value1(), subject.value2() || argument);
}
@Override
public Codec<Boolean> argumentCodec(EnvironmentAttribute<ExampleObject> attribute) {
// Construct the codec to deserialize the argument
return Codec.BOOL;
}
};
// A modifier handling all possible object combinations
public static final AttributeModifier<ExampleObject, Either<ExampleObject, Either<Integer, Boolean>>> AND = new AttributeModifier<>() {
@Override
public ExampleObject apply(ExampleObject subject, Either<ExampleObject, Either<Integer, Boolean>> argument) {
return argument.map(
arg -> new ExampleObject(subject.value1() & arg.value1(), subject.value2() && arg.value2()),
either -> either.map(
arg -> new ExampleObject(subject.value1() & arg, subject.value2()),
arg -> new ExampleObject(subject.value1(), subject.value2() && arg)
)
);
}
@Override
public Codec<Either<ExampleObject, Either<Integer, Boolean>>> argumentCodec(EnvironmentAttribute<ExampleObject> attribute) {
// Construct the codec to deserialize the argument
// We can use the attribute codec for the value type
return Codec.either(attribute.valueCodec(), Codec.either(Codec.INT, Codec.BOOL));
}
};
// Constructing the library
// The argument can be any value as long as it can be serialized and handled
// If using one of the static constructors for the attribute type, the override
// handler is added automatically along with the associated modifier codec for
// the map
public static final Map<AttributeModifier.OperationId, AttributeModifier<ExampleObject, ?>> EXAMPLE_LIBRARY = Map.of(
AttributeModifier.OperationId.ADD, ADD,
AttributeModifier.OperationId.OR, OR,
AttributeModifier.OperationId.AND, AND
);
Type Interpolation
To support interpolation, whether for client frames (because of $Builder#syncable), spatial ($Builder#spatiallyInterpolated), states (weather), or keyframes (timelines), there needs to be some function that, given some step between 0 and 1 (either time or position), how are the two values merged. This is handled through a LerpFunction, of which the generic is the environment attribute value type. For non-interpolated values, this normally uses LerpFunction#ofStep, which acts like a simple threshold between the two values. More specifically, spatial will set the threshold as 0.5 while the partial tick, keyframe, and state change will only consider full steps (meaning always the next value). However, this function can be however you choose to define it:
// Step represents the value between 0 and 1 to interpolation
// Original represents the step at 0
// Next represents the step at 1
public static final LerpFunction<ExampleObject> EXAMPLE_SPATIAL_LERP = (step, original, next) -> {
return new ExampleObject(
Mth.lerp(step, original.value1(), next.value1()),
step >= 0.5f ? next.value2() : original.value2()
);
}
public static final LerpFunction<ExampleObject> EXAMPLE_PARTIAL_LERP = (step, original, next) -> {
return new ExampleObject(
Mth.lerp(step, original.value1(), next.value1()),
next.value2()
);
}
// Will always return the first value
public static final LerpFunction<ExampleObject> EXAMPLE_KEYFRAME_LERP = LerpFunction.ofConstant();
// Will change to the next state after 0.1 of the step has past
public static final LerpFunction<ExampleObject> EXAMPLE_STATE_CHANGE_LERP = LerpFunction.ofStep(0.1f);
Putting it all Together
With each of these parts, an AttributeType can now be constructed. This is typically done using one of the static constructors: ofInterpolated for values that define their interpolation function, or ofNotInterpolated, for values that are okay just snapping between two values. For common use cases, unless your value transitions between something that is inherently obvious to the player (e.g., visuals like fog or sky color), then interpolation is generally unnecessary.
If you decide to use the AttributeType instance constructor instead, you will also have to create a codec to serialize the modifier map. See AttributeType#createModifierCodec on how to do so.
// The attribute type must be statically registered to be handled correctly
public static final AttributeType<ExampleObject> EXAMPLE_ATTRIBUTE_TYPE = Registry.register(
BuiltInRegistries.ATTRIBUTE_TYPE,
Identifier.withNamespaceAndPath("examplemod", "example_attribute_type"),
new AttributeType<>(
// The codec for the value
ExampleObject.CODEC,
// The map of operations that can be modified
// `OVERRIDE` is automatically added for serialization
EXAMPLE_LIBRARY,
// The codec used to serialize the modifier library
Util.make(() -> {
ImmutableBiMap<AttributeModifier.OperationId, AttributeModifier<Value, ?>> map = ImmutableBiMap.builder()
.put(AttributeModifier.OperationId.OVERRIDE, AttributeModifier.override())
.putAll(EXAMPLE_LIBRARY)
.buildOrThrow();
return ExtraCodecs.idResolverCodec(AttributeModifier.OperationId.CODEC, map::get, map.inverse()::get);
}),
// The function interpolating between two keyframes in a timeline
EXAMPLE_KEYFRAME_LERP,
// The function interpolating between two states (only used for attributes in the weather maps)
EXAMPLE_STATE_CHANGE_LERP,
// The function interpolating between two spatial coordinates
EXAMPLE_SPATIAL_LERP,
// The function interpolating between client frames
EXAMPLE_PARTIAL_LERP
)
);
From there, we can create an EnvironmentAttribute that uses said type:
public static final EnvironmentAttribute<ExampleObject> EXAMPLE_OBJECT_ATTRIBUTE = Registry.register(
BuiltInRegistries.ENVIRONMENT_ATTRIBUTE,
Identifier.withNamespaceAndPath("examplemod", "example_object_attribute"),
EnvironmentAttribute.builder(
EXAMPLE_ATTRIBUTE_TYPE
)
.defaultValue(ExampleObject.DEFAULT)
// Possible because of the codec and partial tick lerp
.syncable()
// Possible because of the spatial lerp
.spatiallyInterpolated()
.build()
);
// For some DimensionType json
// In `data/examplemod/dimension_type/example_dimension.json`
{
"attributes": {
"examplemod:example_object_attribute": {
"value1": 10,
"value2": true
}
},
// ...
}
// For some Biome json
// In `data/examplemod/worldgen/biome/example_biome.json`
{
"attributes": {
"examplemod:example_object_attribute": {
// Must use one of the arguments defined in the library
// In this case either 'add', 'or', or 'and'
"modifier": "and",
// This can be either a boolean, integer, or object
// because of how the serializer was defined
"argument": false
}
}
// ...
}
// For some Timeline json
// In `data/examplemod/timeline/example_timeline.json
{
"period_ticks": 24000,
"tracks": {
"examplemod:example_object_attribute": {
"keyframes": [
{
"tick": 12000,
// This can be either a boolean, integer, or object
// because of how the serializer was defined
"value": 1
},
{
"tick": 23999,
// This can be either a boolean, integer, or object
// because of how the serializer was defined
"value": {
"value1": 0,
"value2": false
}
}
],
// Must use one of the arguments defined in the library
// In this case either 'add', 'or', or 'and'
"modifier": "and",
"ease": "linear"
}
}
}
Timelines
Timelines are method of modifying attributes based on the current game time. More specifically, they define some keyframes that the values are interpolated between, first determining the step using the EasingType function, and second using AttributeType#keyframeLerp to get the value. This is not only a replacement of Schedules in brains, but also attributes relating to the day/night cycle (e.g., sky color, slime spawn chance, etc.). These function as a layer after the biome modifiers are applied for both positional and non-positional attributes.
Timelines are activated based on the DimensionType#timelines tag, which are prefixed with in_ (e.g. minecraft:in_overworld is the timeline tag for the overworld). All dimension tags include the minecraft:universal tag, meaning all timelines tagged within will run within all dimensions (provided they add the universal tag).
The vanilla timelines are like so:
minecraft:day: The day/night cycleminecraft:moon: The moon phase and spawn chanceminecraft:villager_schedule: WhatActivitya villager performsminecraft:early_game: Stops pillager patrol spawns for the first few days
The associated tags are the following;
minecraft:universalminecraft:villager_schedule
minecraft:in_overworld- Overworld dimension#minecraft:universalminecraft:dayminecraft:moonminecraft:early_game
minecraft:in_nether- Nether dimension#minecraft:universal
minecraft:in_end- End dimension#minecraft:universal
Keyframes
Each Timeline is made up of keyframes responsible for determining what the argument to the modifier should be at a given tick. These keyframes are then compiled into a list called a KeyframeTrack, baked into a KeyframeTrackSampler when constructing the attribute layers. Every two adjacent keyframes (including the first and last) is considered a KeyframeTrackSampler$Segment. This is what’s used to sample an attribute at a given tick.
Let’s say we have the following (keyframe, value) segment (100, 0) -> (200, 1) and we are currently at tick 150. How do we choose what argument to use? Well, this is performed in two operations. First, we calculate the step: a value between 0 and 1 that determines how much to interpolate the value with. The step is calculated first linearly: (current_tick - start_segment_tick) / (end_segment_tick - start_segment_tick). Then, the step is passed into the desired EasingType, which is a function that takes in a 0-1 value and returns a 0-1 value, such as in_out_bounce or out_back. You can also create your own EasingType like so:
// `EasingType#registerSimple` must be made public
EasyingType.registerSimple(
// The name of the function
"examplemod:ease",
// The function to apply to the value
// For smooth transitions, the function should map 0 -> 0 and 1 -> 1
original -> 0.5f * (float) Mth.sin(Math.PI * (3 * original - 0.5)) + 0.5f
);
Then, it passes the step to the AttributeType#keyframeLerp function along with the two arguments to get the lerped argument to apply.
Attribute Tracks
With the keyframes determining the arguments, we apply the arguments to the attribute through an AttributeTrack, baked into an AttributeTrackSampler when constructing the attribute layers. An AttributeTrack contains the KeyframeTrack to get the arguments, and an ArgumentModifier to apply the argument to the value. Note that there can only be one modifier for a given track.
These AttributeTracks are then stored in a map of attributes to tracks, which define our Timeline. The timeline also contains an optional integer indicating the period of the tracks. The ‘period’, in this case, acts as one full run of all tracks in the timeline. Values outside of the period are modulo’d. Most timelines use 24000 for the period as that represents one Minecraft day in ticks.
Custom Timelines
Custom Timelines are added to the timeline datapack registry:
// For some Timeline json
// In `data/examplemod/timeline/example_timeline.json
{
// Runs for every 3000 ticks (1/8 of a day)
"period_ticks": 3000,
"tracks": {
// The attribute(s) to modify
"examplemod:example_object_attribute": {
// The easing function to determine the step between arguments
"ease": "examplemod:ease",
// The list of keyframes defining the arguments at set ticks
// The arguments are then interpolated using the easing function
// and keyframe lerp
"keyframes": [
{
// The tick for which this argument is the given value
"tick": 1500,
// Adds 10 to the attribute
"value": 10
},
// In-between, uses the easing function to step down between
// 10 and 0
{
"tick": 2999,
// Adds 0 to the attribute
"value": 0
}
// In-between, uses the easing function to step up between
// 0 and 10
],
// The modifier to use when applying the argument
// to the value
"modifier": "add"
}
}
}
net.minecraft.clientCamera#attributeProbe- Gets the client environment attribute probe for values and interpolation.MinecraftgetSituationalMusicnow returnsMusicinstead ofMusicInfogetMusicVolume- Gets the volume of the background music, or normal volume if the open screen has background music.
net.minecraft.client.multiplayer.ClientLeveleffectsis removedgetSkyDarken->EnvironmentAttributes#SKY_LIGHT_COLOR,SKY_LIGHT_FACTOR; not one-to-onegetSkyColor->EnvironmentAttributes#SKY_COLOR, not one-to-onegetCloudColor->EnvironmentAttributes#CLOUD_COLOR, not one-to-onegetStarBrightness->EnvironmentAttributes#STAR_BRIGHTNESS, not one-to-onegetSkyFlashTimeis now private
net.minecraft.client.rendererDimensionSpecialEffectsclass is removed, replaced entirely byEnvironmentAttributesSkyRendererrenderSkyDiscnow takes in a single ARGBintinstead of three RGBfloatsrenderSunMoonAndStarsnow take in two additionalfloats for the moon and star rotation
net.minecraft.client.renderer.state.SkyRenderStateskyType->skybox, not one-to-oneisSunriseOrSunset,timeOfDayare removedmoonAngle,starAngle- The angle of the moon and stars.
net.minecraft.client.resources.sounds.BiomeAmbientSoundsHandlerno longer takes in theBiomeManagernet.minecraft.client.soundsMusicInfo->Minecraft#getSituationalMusic,getMusicVolume; not one-to-oneMusicManager#startPlayingnow takes in theMusicinstead of theMusicInfo
net.minecraft.core.registriesBuiltInRegistries,Registries#ENVIRONMENT_ATTRIBUTE- The registry for the environment attributes.BuiltInRegistries,Registries#ATTRIBUTE_TYPE- The registry for the attribute types.BuiltInRegistires,Registries#SCHEDULEare removedRegistries#TIMELINE- The registry key for the timeline.
net.minecraft.data.tags.TimelineTagsProvider- The tags provider for the timeline.net.minecraft.server.level.ServerLevel#getMoonBrightness- Returns the brightness of the moon.net.minecraft.sounds.Music#event->soundnet.minecraft.tags.TimelineTags- The tags for the timeline.net.minecraft.utilBinaryAnimator$EasingFunction->EasingTypeCubicSampler->GaussianSampler,SpatialAttributeInterpolator; not one-to-oneKeyframeTrack- A track of keyframes and the easing performed between them.KeyframeTrackSampler- A keyframe track that replays based on the period, lerping between values using the provided function.
net.minecraft.world.attributeAmbientSounds- The sounds that ambiently play within an environment.AttributeRange- An interface meant to validate inputs and sanitize the corresponding value into an appropriate bound.AttributeType- A type definition of the operations and modifications that can be performed by an attribute.AttributeTypes- A registry of all vanilla attribute types.BackgroundMusic- The background music that plays within an environment.BedRule- The rules of how beds function within an environment.EnvironmentAttribute- A definition of some attribute within an environment.EnvironmentAttributeLayer- A layer that modifies a value.EnvironmentAttributeMap- A map of attribute definitions to their argument and modifier.EnvironmentAttributeProbe- The attribute handler for getting and interpolating between values. Used only by the camera.EnvironmentAttributeReader- A reader that can lookup the environment attributes either by dimension or position.EnvironmentAttributes- A registry of all vanilla environment attributes.EnvironmentAttributeSystem- A reader implementation that gets and spatially interpolates environment attributes.LerpFunction- A functional interface that takes in some value between 0-1 along with the start and end values to interpolate between.WeatherAttributes- Attributes maps for applying weather layers.
net.minecraft.world.attribute.holderAttributeModifier- A modifier that takes in the attribute value along with some argument (typically a value of the same type) to produce a modified value.BooleanModifier- Modifier for a boolean with a boolean argument.ColorModifier- Modifier for an ARGB integer with some argument, typically integers.FloatModifier- Modifier for a float with some argument, typical floats or a float with an alpha interpolator.FloatWithAlpha- A record containing some value and an alpha typically used for blending.
net.minecraft.world.entity.ai.BraingetScheduleis removedsetSchedulenow takes in anEnvrionmentAttribute<Activity>instead of aScheduleupdateActivityFromSchedulenow takes in theEnvironmentAttributeSystemand position instead of the day time
net.minecraft.world.entity.animal.bee.Bee#isNightOrRainingreplaced withEnvironmentAttributes#BEES_STAY_IN_HIVEnet.minecraft.world.entity.player.Player$BedSleepingProblemis now a recordNOT_POSSIBLE_HERE->BedRule#EXPLODESNOT_POSSIBLE_NOW->BedRule#CAN_SLEEP_WHEN_DARK
net.minecraft.world.entity.scheduleKeyframe->.minecraft.util.Keyframe, not one-to-oneScheduleis removed, its logic replaced byTimeline,TimelinesScheduleBuilderis remvoed, its logic replaced byTimeline$BuilderTimeline->.world.timeline.Timeline, not one-to-one
net.minecraft.world.entity.variant.SpawnContextnow takes in theEnvironmentAttributeReadernet.minecraft.world.levelLevelisMoonVisiblereplaced byEnvironmentAttributes#MOON_ANGLEgetSunAnglereplaced byEnvironmentAttributes#SUN_ANGLEcanHaveWeatheris nowpublic
LevelAccessornow implementsLevelReaderinstead ofLevelTimeAccessLevelReader#environmentAttributes- Returns the manager for get the environment attribute within a dimension and its associated biomes.LevelTimeAccessinterface is removedMoonPhaseCODEC- The codec for the moon phase.PHASE_LENGTH- The number of ticks that a moon phase is present for.startTick- The start tick for a particular phase.
net.minecraft.world.level.biomeAmbientAdditionsSettings->.world.attribute.AmbientAdditionsSettingsAmbientMoodSettings->.world.attribute.AmbientMoodSettingsAmbientParticleSettings->.world.attribute.AmbientParticleBiomenow takes in theEnvironmentAttributeMapgetSkyColor->EnvironmentAttributes#SKY_COLORgetFogColor->EnvironmentAttributes#FOG_COLORgetAttributes- Gets the attributes for this biome.getWaterFogColor->EnvironmentAttributes#WATER_FOG_COLORgetAmbientParticle->EnvironmentAttributes#AMBIENT_PARTICLESgetAmbientLoop->AmbientSounds#loopenvironment attributegetAmbientMood->AmbientSounds#moodenvironment attributegetAmbientAdditions->AmbientSounds#additionsenvironment attributegetBackgroundMusic->EnvironmentAttributes#BACKGROUND_MUSICgetBackgroundMusicVolume->EnvironmentAttributes#MUSIC_VOLUME$BuilderputAttributes- Puts all attributes from another map.setAttribute- Sets an environment attribute.modifyAttribute- Modifies an attribute source for the biome.
BiomeSpecialEffectsis now a recordgetFogColor->EnvironmentAttributes#FOG_COLORgetWaterFogColor->EnvironmentAttributes#WATER_FOG_COLORgetSkyColor->EnvironmentAttributes#SKY_COLORgetAmbientParticleSettings->EnvironmentAttributes#AMBIENT_PARTICLESgetAmbientLoopSoundEvent->AmbientSounds#loopenvironment attributegetAmbientMoodSettings->AmbientSounds#moodenvironment attributegetAmbientAdditionsSettings->AmbientSounds#additionsenvironment attributegetBackgroundMusic->EnvironmentAttributes#BACKGROUND_MUSICgetBackgroundMusicVolume->EnvironmentAttributes#MUSIC_VOLUME
net.minecraft.world.level.blockBedBlock#canSetSpawn->BedRule#canSetSpawnenvironment attributeCreakingHeartBlock#isNaturalNightreplaced byEnvironmentAttributes#CREAKING_ACTIVERespawnAnchorBlock#canSetSpawnnow takes in theServerLevelandBlockPos
net.minecraft.world.level.dimensionBuiltinDimensionTypes#*_EFFECTSare removedDimensionDefaults#OVERWORLD_CLOUD_HEIGHTis now afloatDimensionTypefixedTime->hasFixedTime, now abooleaninstead of aOptionalLongnatural,effectsLocationare removedskybox- The skybox to display within the dimension.cardinalLightType- The type of light permeating through a dimension.timelines- A set of timelines that modify the environment attributes of this dimension.ultraWarm->EnvironmentAttributes#WATER_EVAPORATES,FAST_LAVA,DEFAULT_DRIPSTONE_PARTICLEbedWorks->EnvironmentAttributes#BED_RULErespawnAnchorWorks->EnvironmentAttributes#RESPAWN_ANCHOR_WORKScloudHeight->EnvironmentAttributes#CLOUD_HEIGHTattribute- Gets the attributes for this dimension.piglinSafe,$MonsterSettings#piglinSafe->EnvironmentAttributes#PIGLINS_ZOMBIFYhasRaids,$MonsterSettings#hasRaids->EnvironmentAttributes#CAN_START_RAIDtimeOfDayis removedmoonPhasereplaced byEnvironmentAttributes#MOON_PHASEhasEndFlashes- Returns whether the skybox is the end.$CardinalLightType- The light permeating through a dimension.$Skybox- The skybox of a dimension.
net.minecraft.world.level.material.FogType#DIMENSION_OR_BOSSis removednet.minecraft.world.timelineAttributeTrack- A track that applies the attribute modifier with the argument sampled from the given keyframe track.AttributeTrackSampler- A baked attribute track.Timeline- A map of attributes to tracks that are applied based on the given time in ticks modulo the period.Timelines- All vanilla timelines.
The Game Rule Shuffle
The gamerule system has been overhauled to a degree, allowing its keys to be stored as proper registry objects while still having its values limited to either integers or booleans. Most of the classes are basically just combinations of others.
Existing Game Rules
Existing game rules are still in a GameRules class, just moved to a different location. Their fields have been renamed and seem to follow some basic rules:
- Rules no longer have the
RULE_prefix - Rules now have underscores separating words
- The
DOprefix is removed from rule names (e.g.RULE_DOENTITYDROPS->ENTITY_DROPS) - The
SPAWNINGsuffix has been replaced with theSPAWN_prefix (e.g.RULE_DOMOBSPAWNING->SPAWN_MOBS) - The
DISABLEprefix is removed, meaning that their values are inverted (e.g.,RULE_DISABLERAIDS->RAIDS)
While there are some edge cases, searching for a specific word in the previous game rule name will most likely lead you to the new name (e.g., searching for ADVANCEMENT in RULE_ANNOUNCEADVANCEMENTS leads to SHOW_ADVANCEMENT_MESSAGES).
To actually get a value from the game rules, you would use GameRules#get instead of the previous getBoolean and getInteger. The type is obtained from the generic on the registered GameRule.
// With ServerLevel level
boolean fallDamage = level.getGameRules().get(GameRules.FALL_DAMAGE);
Additionally, setting the game rule is now simplified to calling GameRules#set – taking in the GameRule, value, and the current server if the changes are propogated through MinecraftServer#onGameRuleChanged, which it should generally be.
// With ServerLevel level
level.getGameRules().set(GameRules.FALL_DAMAGE, false, level.getServer());
Creating a Game Rule
Game rules are created through the GameRule class, which is basically a type definition of how the game rule functions depending on its caller. Its generic represents the type of the value being held. The only hardcoded concepts that separate this from being a general type is that the actual arguments can be limited to a specific range, and that they store the default value. Otherwise, the fields are mostly the same from its previous counterparts in GameRules$Type and GameRules$Key.
Then, once created, the GameRule must be statically registered to BuiltInRegistries#GAME_RULE
public static final GameRule<Integer> EXAMPLE_RULE = Registry.register(
BuiltInRegistries.GAME_RULE
Identifier.withNamespaceAndPath("examplemod", "example_rule"),
new GameRule(
// The category that best represents the game rule.
// This is only used by the edit game rule screen
// when first constructing the world.
// A custom category can be created by calling
// `GameRuleCategory#register` or just its constructor
// as the sort order goes unused
GameRuleCategory.register(
Identifier.withNamespaceAndPath("examplemod", "example_category")
),
// The type of the game rule, represenative of the
// JSON schema version of the generic.
// This is only used by the management system for
// checking an untyped rule.
GameRuleType.INT,
// The argument type used for serializing the value
// in commands.
// This can be range-limited based on the constructor.
IntegerArgumentType.integer(0, 5),
// A caller that runs typically during the visiting process
// for each game rule.
// This caller is only used by the edit game rules screen
// for adding the correct component that modifies the value.
// `GameRuleTypeVisitor#visit` should not be used here
// as the visitor already calls that function.
GameRuleTypeVisitor::visitInteger,
// The codec used to serialize the game rules to disk
// or for the managment service.
// This can be range-limited based on the constructor.
Codec.intRange(0, 5),
// A function that maps the set value to an integer
// result used when setting or querying the game rule
// via a command.
// This is the only case when a result of `0` does not
// mean the command has failed.
gameRuleValue -> gameRuleValue,
// The default value to set for this rule.
3,
// A feature flag set that are required for this game rule
// to be enabled in game.
// An empty flag set means it should be enabled at all times.
FeatureFlagSet.of()
)
);
net.minecraft.client.gui.screens.worldselection
- EditGameRulesScreen
- $BooleanRuleEntry now takes in a GameRule<Boolean> instead of a GameRules$BooleanValue
- $EntryFactory no longer bounds its generic
- $IntegerRuleEntry now takes in a GameRule<Integer> instead of a GameRules$IntegerValue
- InitialWorldCreationOptions#disabledGameRules is now a GameRuleMap
net.minecraft.core.registries.BuiltInRegistries#GAME_RULE,Registries#GAME_RULE- Game rule registry.net.minecraft.gametest.framework.TestEnvironmentDefinition$SetGameRulesnow takes in aGameRulesMapinstead of$Entrysentry,$Entryare removed
net.minecraft.server.MinecraftServer#onGameRuleChangednow takes in theGameRuleand value instead of the string key and$Valuewrappernet.minecraft.server.jsonrpc.api.SchemaRULE_TYPE_SCHEMAis now aGameRuleTypeinstead of aGameRulesService$RuleTypeTYPED_GAME_RULE_SCHEMAis now aGameRulesService$GameRuleUpdateinstead of aGameRulesService$TypedRuleUNTYPED_GAME_RULE_SCHEMAis now aGameRulesService$GameRuleUpdateinstead of aGameRulesService$UntypedRule
net.minecraft.server.jsonrpc.internalapiGameRulesinterface is removedMinecraftGameRuleService#getRule->getRuleValue
net.minecraft.server.jsonrpc.methods.GameRulesService$RuleTypeis removed$TypedRule,$UntypedRule->$GameRuleUpdate, not one-to-one
net.minecraft.server.notifications.NotificationService#onGameRuleChangednow takes in theGameRuleand value instead of the string key and$Valuewrappernet.minecraft.world.level.GameRules- The static rule keys are now located in
.gamerules.GameRuleswithout theRULE_prefix and underscores in-between wordsDOis removed from the name (e.g.RULE_DOENTITYDROPS->ENTITY_DROPS)SPAWNINGnames now start withSPAWN_(e.g.RULE_DOMOBSPAWNING->SPAWN_MOBS)
- The map behavior linking the key to its associated value is now handled by
GameRuleMapgetBoolean,getInteger->get
$Key,$Type->GameRule, not one-to-oneGameRuleimplementsFeatureElement
$Category->GameRuleCategory, not one-to-one$Value,$BooleanValue,$IntegerValueare removed, replaced with the direct object being wrapped$GameRuleTypeVisitor->GameRuleTypeVisitor
- The static rule keys are now located in
Minor Migrations
The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.
Usage Annotations
Mojang has recently given some integer values and flags an annotation, marking its intended usage. This does not affect modders in any way, as it likely seems to be a way to perform static analysis on the values passed around, probably for some kind of validation.
com.mojang.blaze3d.buffers.GpuBuffer$Usage- An annotation that marks whether a given integer defines the usage flags of the particular buffer.com.mojang.blaze3d.platform.InputConstants$Value- An annotation that marks whether a given integer defines the input of a device.com.mojang.blaze3d.buffers.GpuTexture$Usage- An annotation that marks whether a given integer defines the usage flags of the particular texture.net.minecraft.client.inputInputWithModifiers$Modifiers- An annotation that marks whether a given integer defines the modifiers of an input.KeyEvent$Action- An annotation that marks whether a given integer defines the action being performed by the input (i.e., press, release, repeat).MouseButtonInfo$Action- An annotation that marks whether a given integer defines the action being performed by the mouse (i.e., press, release, repeat).$MouseButton- An annotation that marks whether a given integer defines the input of a mouse.
net.minecraft.server.level.TicketType$Flags- An annotation that marks whether a given integer defines the flags of a ticket type.net.minecraft.world.level.block.Block$UpdateFlags- An annotation that marks whether a given integer defines the flags for a block update.
Text Collectors
ActiveTextCollector is a method of submitting strings and components to render, meant to provide common utilities for alignment, especially with text that goes off the screen. While this does not necessarily replace GuiGraphics#drawString, a few widgets require the use of the ActiveTextCollector, such as AbstractStringWidget#renderLines.
An ActiveTextCollector can be created by calling one of the GuiRenderer#textRenderer* methods. They take in a $HoveredTextEffects, which handles how to render the component hover and click event, and a Style consumer callback for any additional handling. It also stores a set of default parameters, which basically represent the current pose opacity and screen rectangle.
There are two methods two submit a piece of text for rendering: accept for standard strings, and acceptScrolling* for screens that go out of the rectangle, scrolling back and forth on the screen at a rate of roughly one unit per second (see the accessibility settings for an example). accept takes in, at most, five parameters: the alignment of the X position (TextAlignment#LEFT is like normal, CENTER the center of the text, RIGHT the end of the text), the X position for the alignment, Y position, parameters to override, and the text. acceptScrolling takes in, at most, seven parameters: the text, the starting X position center aligned, the leftmost X position, the rightmost X position, the topmost Y position, the bottommost Y position, and the parameters to override.
// In some method with GuiGraphics graphics
ActiveTextCollector collector = graphics.textRenderer(
// Render hover and click events
HoveredTextEffects.TOOLTIP_AND_CURSOR;
);
collector.accept(
// Align the text to the center
TextAlignment.CENTER,
// Start X (in this case the center position)
20,
// Start Y
0,
// The parameters to use
collector.defaultParameters(),
// The text to display
Component.literal("Hello world!")
);
net.minecraft.client.guiActiveTextCollector- A helper for rendering text with certain parameters and alignments.GuiGraphicsnow takes in the mouse XYtextRenderer*- Methods for constructing the helper for submit text in their appropriate location.$HoveredTextEffects- An enum that defines the text effects to apply when using the text collector.
net.minecraft.client.gui.componentsAbstractButtonnow extendsAbstractWidget$WithInactiveMessageinstead ofAbstractWidgetrenderWidgetis now final- Use
renderContentsinstead to submit elements renderDefaultSpriteshould be called inrenderContentsto blit the default sprite
- Use
renderString->renderDefaultLabel, not one-to-one
AbstractSliderButtonnow extendsAbstractWidget$WithInactiveMessageinstead ofAbstractWidgetAbstractStringWidgetvisitLines- Handles submitting text elements to the screen.setColor,getColorare removed- Use the
ActiveTextCollectorinvisitLinesinstead
- Use the
setComponentClickHandler- Set the handler for when a component with the provided style is clicked.
AbstractWidgetrenderScrollingString->renderScrollingStringOverContents, not one-to-onegetAlpha- Gets the alpha of the widget.$WithInactiveMessage- A widget that can change the message to display when inactive.
Buttonis now abstract$Plainreplicates the previous behavior
ChatComponentMESSAGE_BOTTOM_TO_MESSAGE_TOP- The height of a chat component.rendernow takes in aFontand abooleanfor whether to change the curse on insertionscaptureClickableText- Captures the clickable text to submit.handleChatQueueClickedreplaced byQUEUE_EXPAND_ID, not one-to-onegetClickedComponentStyleAt->$ChatGraphicsAccess#handleMessage, not one-to-onegetMessageTagAt->$ChatGraphicsAccess#handleTag,handleTagIcon; not one-to-onegetWidth,getHeight,getScaleare now private$AlphaCalculator- Calculates the alpha for a given chat line.$ChatGraphicsAccess- An interface for handling the submission of the chat input.$LineConsumerno longer takes in the first threeints
FittingMultilineTextWidget#setColoris removed- Use the
ActiveTextCollectorinvisitLinesinstead
- Use the
MultiLineLabelrender,getStyle->visitLines, not one-to-one$Align->TextAlignment
MultiLineTextWidget#setColor,configureStyleHandlingare removed- Use the
ActiveTextCollectorinvisitLinesinstead
- Use the
SplashRenderernow takes in aComponentinstead of aStringSpriteIconButton#renderSprite- Submits the sprite icon.StringWidget#setColoris removed- Use the
ActiveTextCollectorinvisitLinesinstead
- Use the
TabButtonnow extendsAbstractWidget$WithInactiveMessageinstead ofAbstractWidgetrenderString->renderLabel, now private, not one-to-one
net.minecraft.client.gui.screens.inventory.BookViewScreen#getClickedComponentStyleAt->visitText, now private, not one-to-one
Shared Text Areas Debugger
A new debug has been added that draws the bounding box each glyph, including the empty glyph. The color shifts slightly between each glyph for ease of differentiation, and changes entirely depending on if there is some combination of a click or hover event.
net.minecraft.SharedConstants#DEBUG_ACTIVE_TEXT_AREAS- A flag for the debugger drawing the bounds and effects of each glyph.net.minecraft.client.gui.FontprepareTextnow has an overload of whether to render something in the empty areas$GlyphVisitoracceptGlyphnow takes in aTextRenderable$Styledinstead of aTextRenderableacceptEmptyArea- Accepts an empty area to draw to the screen.
$PreparedTextBuildernow takes in whether to include the empty areas for rendering
net.minecraft.client.gui.fontActiveArea- Defines the bounds and style of the area to draw.EmptyArea- An area with nothing within it.PlainTextRenderablenow implementsTextRenderable$Styledinstead ofTextRenderablewidth,height,ascent- The bounds of the object.
TextRenderable$Styled- A text renderable that defines some active area for its bounds.
net.minecraft.client.gui.font.glyphs.BakedGlyph#createGlyphnow returns aTextRenderable$Styled
JSpecify Annotations
Mojang has moved from using a mix of their own annotations to those available in JSpecify when required. As such, instead of all fields, methods, and parameters being marked as nonnull by default, it is replaced by NullMarked, which considers a type usage non-null unless explictly annotated as Nullable, barring some special cases.
com.mojang.blaze3d.FieldsAreNonnullByDefault,MethodsReturnNonnullByDefaultare removedcom.mojang.math.FieldsAreNonnullByDefault,MethodsReturnNonnullByDefaultare removednet.minecraft.FieldsAreNonnullByDefault,MethodsReturnNonnullByDefaultare removed
Slot Sources
Slot sources are an expansion upon the previous contents drop system in shulker boxes allowing any loot table to pulls its entries from some container slots. This can be used in any location where a LootContext is enabled, though it is currently only implemented as a loot pool entry.
In vanilla, a slot source works by having some LootContextArg, which points to some loot context param value, return an object that implements SlotProvider. Currently, this refers to any Container or Entity implementation. The SlotProvider is then used by SlotSource#provide to construct a SlotCollection: a stream of deep copied ItemStacks. The stacks stored in the collection are then passed to the output of the pool. As this is all done in one of the SlotSource#provide implementations, it can reference anything (not just SlotProvider) as long as it can transform that data into the SlotCollection.
// A slot source whose 'slots' are the elements
// within an item tag.
public record TagSlotSource(TagKey<Item> tag) implements SlotSource {
public static final MapCodec<TagSlotSource> MAP_CODEC = TagKey.codec(Registries.ITEM)
.fieldOf("tag").xmap(TagSlotSource::new, TagSlotSource::tag);
@Override
public SlotCollection provide(LootContext ctx) {
// Get the holder set for the tag
Optional<HolderSet.Named<Item>> holderSetOpt = ctx.getResolver()
.lookup(Registries.ITEM).flatMap(getter -> getter.get(this.tag));
// Stream the elements and map to a SlotCollection
return holderSetOpt.map(holderSet ->
// `Item#getDefaultInstance` returns a new copy, so it can be used.
// If the ItemStack already exists, then `ItemStack#copy` should be
// called on each.
(SlotCollection) () -> holderSet.stream().map(holder -> holder.value().getDefaultInstance())
).orElse(SlotCollection.EMPTY);
}
@Override
public MapCodec<? extends SlotSource> codec() {
// The codec used to serialize the slot source
return MAP_CODEC;
}
}
// The map codec needs to be registered to the slot source type registry
Registry.register(
BuiltInRegistries.SLOT_SOURCE_TYPE
Identifier.withNamespaceAndPath("examplemod", "tag"),
TagSlotSource.MAP_CODEC
);
// An example loot table
{
// ...
"pools": [
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
// Use the slot source loot pool
"type": "minecraft:slots",
"slot_source": {
// Our slot source
"type": "examplemod:tag",
"tag": "minecraft:planks"
}
}
]
}
// ...
]
}
net.minecraft.advancements.criterion.SlotsPredicate#matchesnow takes in aSlotProviderinstead of anEntitynet.minecraft.core.registries.BuiltInRegistries#SLOT_SOURCE_TYPE,Registries#SLOT_SOURCE_TYPE- Slot source type registry.net.minecraft.world.Containernow extendsSlotProvidergetSlot- Gets an access for a single item.
net.minecraft.world.entityEntitynow implementsSlotProviderSlotAccessNULLis removedforContainer->forListElement, not one-to-one
SlotProvider- An object that provides some access to its internal storage via slots.
net.minecraft.world.item.slotCompositeSlotSource- A composite of multiple slot sources.ContentsSlotSource- Gets the slot contents.EmptySlotSource- An empty slot source.FilteredSlotSource- Filters the provided slot source pased on the item predicate.GroupSlotSource- Groups multiple slot sources together into one concatenated collection.LimitSlotSource- Limits the provided slot source to a maximum size.RangeSlotSource- Gets the desired range of slots.SlotCollection- A collection of slots to grab the item copies from.SlotSource- Given a loot context, returns a collection of slots to provide.SlotSources- The slot sources provided by vanilla.TransformedSlotSource- Transforms the provided slot source.
net.minecraft.world.level.storage.loot.ContainerComponentManipulator#getSlots- Gets the slots of a data component on the stack.net.minecraft.world.level.storage.loot.entriesLootPoolEntries#SLOTS- A pool that uses slots from a source.SlotLoot- A pool that gets its items from some slot source.
Zombie Nautilus Variant
Zombie nautilus are the newest addition to the variant datapack registry objects, taking in the familiar model and texture override along with the spawn conditions:
// A file located at:
// - `data/examplemod/zombie_nautilus_variant/example_zombie_nautilus.json`
{
// Points to a texture at `assets/examplemod/textures/entity/nautilus/example_zombie_nautilus.png`
"asset_id": "examplemod:entity/nautilus/example_zombie_nautilus",
// Defines the `ZombieNautilusVariant$ModelType` that's used to select what entity model to render the zombie nautilus variant with
"model": "warm",
"spawn_conditions": [
// The conditions for this variant to spawn
{
"priority": 0
}
]
}
net.minecraft.core.component.DataComponents#ZOMBIE_NAUTILUS_VARIANT- The variant of the zombie nautilus.net.minecraft.core.registries.Registries#ZOMBIE_NAUTILUS_VARIANT- The registry key for the zombie nautilus variant.net.minecraft.network.syncher.EntityDataSerializers#ZOMBIE_NAUTILUS_VARIANT- The variant of the zombie nautilus.net.minecraft.world.entity.animal.nautilusZombieNautilusVariant- A variant of a zombie nautilus.ZombieNautilusVariants- All vanilla zombie nautilus variants.
OptionEnum Removal
OptionEnum has been removed in favor of simply calling the OptionInstance$Enum constructor with the desired values and codec. As such, most byId methods have been replaced with some codec and the translatable entry is now stored as a Component than the translation key string.
net.minecraft.clientAttackIndicatorStatusno longer implementsOptionEnumbyId->LEGACY_CODEC, not one-to-onegetKey->caption, not one-to-one
CloudStatusno longer implementsOptionEnumgetKey->caption, not one-to-one
InactivityFpsLimitno longer implementsOptionEnumgetKey->caption, not one-to-one
OptionInstance#forOptionEnumis removedPrioritizeChunkUpdateno longer implementsOptionEnumgetKey->caption, not one-to-onebyId->LEGACY_CODEC, not one-to-one
net.minecraft.client.sounds.MusicManager$MusicFrequencyno longer implementsOptionEnumgetKey->caption, not one-to-one
net.minecraft.server.level.ParticleStatusno longer implementsOptionEnumgetKey->caption, not one-to-onebyId->LEGACY_CODEC, not one-to-one
net.minecraft.util.OptionEnumis removednet.minecraft.world.entity.HumanoidArmno longer implementsOptionEnumBY_IDis now privategetKey->caption, not one-to-one
net.minecraft.world.entity.player.ChatVisbilityno longer implementsOptionEnumbyId->LEGACY_CODEC, not one-to-onegetKey->caption, not one-to-one
Specific Logic Changes
net.minecraft.client.renderer.entity.EntityRenderState#lightCoordsnow defaults to 0xF000F0.net.minecraft.client.gui.screens.inventory.AbstractContainerScreen#keyPressedno longer returnstrueif the key is not handled by the screen, instead returningfalse.net.minecraft.util.Mth#clampedLerpparameters have been reordered for both overloads. The methods now take in the step, the original value, and the next value; instead of the original value, next value, and the step value.
Tag Changes
minecraft:biomeplays_underwater_musicis removed- Replaced by
BackgroundMusic#underwaterMusicenvironment attribute
- Replaced by
has_closer_water_fogis removed- Replaced by
EnvironmentAttributes#WATER_FOG_END_DISTANCE
- Replaced by
increased_fire_burnoutis removed- Replaced by
EnvironmentAttributes#INCREASED_FIRE_BURNOUT
- Replaced by
snow_golem_meltsis removed- Replaced by
EnvironmentAttributes#SNOW_GOLEM_MELTS
- Replaced by
without_patrol_spawnsis removed- Replaced by
EnvironmentAttributes#CAN_PILLAGER_PATROL_SPAWN
- Replaced by
spawns_coral_variant_zombie_nautilus
minecraft:blockcan_glide_through
minecraft:entity_typeburn_in_daylightcan_float_while_riddencan_wear_nautilus_armornautilus_hostiles
minecraft:itemcamel_husk_foodzombie_horse_foodnautilus_bucket_foodnautilus_foodnautilus_taming_itemsspearsenchantable/lungeenchantable/sword->enchantable/melee_weapon,enchantable/sweeping
minecraft:timelineuniversalin_overworldin_netherin_end
List of Additions
com.mojang.blaze3d.GraphicsWorkarounds#isAmd- Whether the GPU’s vendor is AMD.com.mojang.blaze3d.openglGlConst#GL_POINTS- Defines the points primitive as the type to render.GlTimerQuery- The OpenGL implementation of querying an object, typically the time elapsed.
com.mojang.blaze3d.platform.InputConstants#MOUSE_BUTTON_*- The inputs of a mouse click, represented by numbers as they may have different intended purposes.com.mojang.blaze3d.systemsCommandEncoder#timerQueryBegin,timerQueryEnd- Handlers for keeping track of the time elapsed.GpuQuery- A query for an arbitrary object, such as the time elapsed.
com.mojang.blaze3d.vertexDefaultVertexFormatPOSITION_COLOR_LINE_WIDTH- A vertex format that specifies the position, color, and line width.POSITION_COLOR_NORMAL_LINE_WIDTH- A vertex format that specifies the position, color, normal, and line width.
VertexFormat$Mode#POINTS- A vertex mode that draws points.VertexFormatElement#LINE_WIDTH- A vertex element that takes in one float representing the width.
com.mojang.mathOctahedralGroupBLOCK_ROT_*- Constants representing the block rotations.permutation- Returns the symmetric group.
Quadrant#fromXYZAngles- Gets the octahedral group that represents the three quadrant rotations.SymmetricGroup3#inverse- Returns the inverse group.
net.minecraftSharedConstantsMAX_CLOUD_DISTANCE- The maximum cloud range to be rendered by the player.DEFAULT_RANDOM_TICK_SPEED- The default random tick speed.
Util#localizedDateFormatter- Returns the localizedDateTimeFormatterfor the given style.
net.minecraft.advancements.criterionDataComponentMatchers$Builder#any- Matches whether there exists some data for the component.SpearMobsTrigger- A trigger that checks the number of entities the player has speared with a kinetic weapon.
net.minecraft.clientGuiMessagesplitLines- Splits the component into lines with the desired width.getTagIconLeft- Gets the width of the content with an additional four pixel padding.
KeyMapping$Category#DEBUG- The debug keyboard category.MusicToastDisplayState- An enum representing how the toast for music should be displayed.NarratorStatus#LEGACY_CODEC- A codec to deserialize the enum narrator status.OptionInstance$IntRangeBasenext- Gets the next value.previous- Gets the previous value.
$SliderableEnum- A slider that selects between enum options.$SliderableValueSetnext- Gets the next value.previous- Gets the previous value.
OptionskeyToggleGui- A key mapping that toggles the in-game gui.keyToggleSpectatorShaderEffects- A key mapping that toggles the shader effects tied to a camera entity.keyDebug*,debugKeys- Key mappings for the debug renderers.weatherRadius- Returns the radius of the weather particles to render in an area.cutoutLeaves- Whether leaves should render in cutout or solid.vignette- Whether a vignette should be applied to the screen.improvedTransparency- Whether to use the transparency post processor.chunkSectionFadeInTime- The amount of second that should be taken for a chunk to fade in when first rendered.maxAnisotropyBit- The bit value of the anisotrophic filtering level.maxAnisotropyValue- The ansiotrophic filtering level.
net.minecraft.client.animation.definitions.NautilusAnimation- The animation definitions for the nautilus.net.minecraft.client.data.models.ItemModelGeneratorsgenerateSpear- Generates the spear item model.generateItemWithTintedBaseLayer- Generates a two layered item model whose base layer is tinted.
net.minecraft.client.data.models.model.ModelTemplates#SPEAR_IN_HAND- A template for the spear in hand model.net.minecraft.client.gui.componentsAbstractButton#setOverrideRenderHighlightedSprite- Overrides whether to use the focused enabled/disabled sprite.Checkbox#adjustWidth- Sets the width of the widget using the message, font, and its initial X position.CycleButton$Builder#withSprite- Sets the supplier used to get the sprite based on the current button state.$DisplayState- How the button shoud be displayed.$SpriteSupplier- Gets the sprite location given the current button state.
EditBox#setInvertHighlightedTextColor- Sets whether to invert the highlighted text color.FocusableTextWidgetgetPadding- Returns the text padding.updateWidth- Updates the width the text can take up.updateHeight- Update the height the text can take up.$Builder- Builds the component.
MultiLineTextWidget#getTextX,getTextY- Gets the text position.OptionsListaddHeader- Adds a header entry.resetOption- Resets the option value.$AbstractEntry- Defines the element within the selection list.$HeaderEntry- An entry that represents the header of a section.$OptionInstanceWidget- A record containing the widget and optionally the option instance.
ResettableOptionWidget- A widget that can reset its value to a default.SelectableEntry- A utility for checking whether the mouse is in a specific region.
net.minecraft.client.gui.layouts.HeaderAndFooterLayout#MAGIC_PADDING- A common padding between the elements.net.minecraft.client.gui.screens.advancementsAdvancementTab#canScrollHorizontally,canScrollVertically- Checks whether the tab data can be scrolled in a given direction.AdvancementTabType#getWidth,getHeight- Gets the width / height of the tab.
net.minecraft.client.gui.screens.debug.DebugOptionsScreen#getOptionList- Returns the list of options for the debug screen.net.minecraft.client.gui.screens.inventoryAbstractMountInventoryScreen- A screen representing a mount’s inventory.EffectsInInventorySPACING- The spacing between effects.SPRITE_SQUARE_SIZE- The size of the effect icon.
NautilusInventoryScreen- The screen for the nautilus inventory.
net.minecraft.client.gui.screens.optionsOptionsSubScreen#resetOption- Resets the option value to its default.VideoSettingsScreen#updateTransparencyButton- Sets the transparency button to the current option value.
net.minecraft.client.gui.screens.packs.TransferableSelectionList$PackEntry#ICON_SIZE- The size of the pack icon.net.minecraft.client.gui.screens.recipebook.RecipeBookTabButton#select,unselect- Handles tab display selection.net.minecraft.client.input.InputQuirks#EDIT_SHORTCUT_KEY_LEFT,EDIT_SHORTCUT_KEY_RIGHT->InputWithModifiers#hasControlDownWithQuirk, not one-to-onenet.minecraft.client.model.HumanoidModel$ArmPoseSPEAR- The spear third person arm pose.animateUseItem- Modifies thePoseStackgiven the entity state, use time, arm, and stack.affectsOffhandPose- Whether the arm animation will affect the offhand pose.
net.minecraft.client.model.animal.nautilusNautilusArmorModel- The armor model for a nautilus.NautilusModel- The model for a nautilus.NautilusSaddleModel- The saddle model for a nautilus.
net.minecraft.client.model.effects.SpearAnimations- The animations performed when using a spear.net.minecraft.client.model.geomModelLayers*NAUTILUS*- The model layers for the nautilus.UNDEAD_HORSE*_ARMOR- The armor model layers for the undead horse.
PartNameINNER_MOUTH,LOWER_MOUTH- Part names for a mouth.SHELL- Part name for a shell.*_CORAL*- Part names for the corals on a zombie nautilus.
net.minecraft.client.model.geom.builders.UVPair#pack,unpack*- Handles packing/unpacking of a UV into along.net.minecraft.client.model.monster.nautilus.ZombieNautilusCoralModel- The model for the warm variant of a zombie nautilus.net.minecraft.client.model.monster.skeleton.SkeletonModel#createSingleModelDualBodyLayer- Creates a parched layer definition.net.minecraft.client.multiplayerClientPacketListener#hasClientLoaded- Whether the client is loaded.MultiPlayerGameMode#piercingAttack- Initiates a lunging attack.
net.minecraft.client.player.LocalPlayer#raycastHitResult- Gets the hit result for the camera entity for the given partial tick.net.minecraft.client.rendererDynamicUniformsCHUNK_SECTION_UBO_SIZE- The uniform buffer object size for the chunk section.writeChunkSections- Writes a varargs of chunk sections to the uniform storage.$ChunkSectionInfo- The dynamic uniform for the chunk section.
GameRendererupdateCamera- Calls the setup function for the camera.getPanoramicScreenshotParameters- Get the screenshot parameters for panoramic mode.
PanoramicScreenshotParameters- The screenshot parameters for panoramic mode.Sheets#CELESTIAL_SHEET- The atlas for the celestial textures.
net.minecraft.client.renderer.blockentity.BlockEntityWithBoundingBoxRenderer#STRUCTURE_VOIDS_COLOR- The void color for a structure.net.minecraft.client.renderer.chunk.SectionRenderDispatcher$RenderSectiongetVisibility- Returns the current alpha of the chunk.setFadeDuration- Sets the amount of time it should take for a chunk to fade in.setWasPreviouslyEmpty,wasPreviouslyEmpty- Handles whether the section did not previously exist.
net.minecraft.client.renderer.entityCamelHuskRenderer- The entity renderer for a camel husk.CamelRenderer#createCamelSaddleLayer- Creates the saddle layer for the camel.NautilusRenderer- The entity renderer for a nautilus.ParchedRenderer- The entity renderer for a parched.ZombieNautilusRenderer- The entity renderer for a zombie nautilus.
net.minecraft.client.renderer.entity.stateArmedEntityRenderStateswingAnimationType- The animation to play when swinging their hand.ticksUsingItem- How many ticks the item has been used for.getUseItemStackForArm- Returns the held item stack based on the arm.
LivingEntityRenderState#ticksSinceKineticHitFeedback- The amount of ticks since this entity was hit with a kinetic weapon.NautilusRenderState- The entity render state of a nautilus.UndeadRenderState- The entity render state for an undead humanoid.
net.minecraft.client.renderer.item.ItemModelResolver#swapAnimationScale- Gets the scale of the swap animation for the stack.net.minecraft.client.renderer.state.LevelRenderState#gameTime- The current game time.net.minecraft.client.resources.SplashManagercomponent fields - The components for the special messages.net.minecraft.client.resources.modelBlockModelRotation#IDENTITY- The identity rotation.EquipmentClientInfo#NAUTILUS_*- The layers for the nautilus.
net.minecraft.core.Vec3imultiply- Multiplies each component with a provided scalar.toMutable- Returns a mutableVector3i.
net.minecraft.data.AtlasIds#CELESTIAL_SHEET- The atlas for the celestial textures.net.minecraft.data.recipes.RecipeProvider#waxedChiseled- The recipe for a waxed chiseled block.net.minecraft.gametest.framework.GameTestHelper#getAbsoluteDirection- Returns the absolute direction from the test relative direction.net.minecraft.nbt.NbtAccounterdefaultQuota- An accounter with a maximum of 2 MiB allocated.uncompressedQuota- An accounter with a maximum of 100 MiB allocated.
net.minecraft.network.chat.MutableComponent#withoutShadow,Style#withoutShadow- Removes the drop shadow from the text.net.minecraft.network.protocol.game.ServerboundPlayerActionPacket$Action#STAB- The player performed the stab action.net.minecraft.network.syncher.EntityDataSerializers#HUMANOID_ARM- The main hand of the humanoid.net.minecraft.resources.Identifier#toShortString- Returns the string of the location. Namespace is omitted ifminecraft.net.minecraft.serverMinecraftServergetServerActivityMonitor- Returns the monitor that sends the server activity notification.getStopwatches- Returns a map of ids to timers.
ServerScoreboard#storeToSaveDataIfDirty- Writes the data if dirty.
net.minecraft.server.commands.StopwatchCommand- A command that starts or stops a stopwatch.net.minecraft.server.dedicated.DedicatedServerProperties#managementServerAllowedOrigins- The origins a request from the management server can come from.net.minecraft.server.jsonrpc.OutgoingRpcMethods#SERVER_ACTIVITY_OCCURRED- A request made from the minecraft server about server activity occurring.net.minecraft.server.jsonrpc.api.SchemaBOOL_OR_INT_SCHEMA- A schema for a field that can be either a boolean or integer.typedCodec- Returns the codec for the schema.info- Returns a copy of the schema.
net.minecraft.server.levelChunkMap#getChunkDataFixContextTag- Returns the datafix tag for the chunk data.ServerLevelgetDayCount- Gets the number of days that has passed.canSpreadFireAround- Whether fire can spread at the given block position.
net.minecraft.server.networkEventLoopGroupHolder- A holder for managing the event loop and channels for communicating with some end, whether local or socket-based.ServerGamePacketListenerImpl#resetFlyingTicks- Resets how long the player has been flying.
net.minecraft.server.notificationsNotificationService#serverActivityOccurred- Notifies the management server that activity has occurred.ServerActivityMonitor- The monitor that sends the server activity notification
net.minecraft.utilARGBsrgbToLinearChannel- Converts the sRGB value into a linear color space.linearToSrgbChannel- Converts the linear value into a sRGB color space.meanLinear- Computes the mean using the linear color space for four values, then converting it back into sRGB.addRgb- Adds the RGB channels, using the alpha from the first value.subtractRgb- Subtracts the RGB channels, using the alpha from the first value.multiplyAlpha- Multiplies the alpha value into the provided ARGB value.linearLerp- Linearly interpolates the color by converting into the linear color space.white,black- Colors with the provided alpha.alphaBlend- Blends two colors along with their alpha value.vector4fFromARGB32- Converts an ARGB value to four floats.
Ease- A utility full of easing functions.ExtraCodecsNON_NEGATIVE_LONG,POSITIVE_LONG- Longs with the listed constraints.longRange- A long codec that validates whether it is between the provided range.STRING_RGB_COLOR,STRING_ARGB_COLOR- A codec allowing for an (A)RGB value expressed in hex form as a string.MAX_PROPERTY_NAME_LENGTH,MAX_PROPERTY_VALUE_LENGTH,MAX_PROPERTY_SIGNATURE_LENGTH,MAX_PROPERTIES- Constants related to serializing the property map.
Mthcube- Cubes a number.chessboardDistance- Computes the absolute maximum difference between two pairs of coordinates; the larger axis difference is returned.
SpecialDates- A utility containing the dates that Mojang changes some behavior or rendering for.TriStateCODEC- The codec for the tristate.from- Turns a boolean into a tristate.
net.minecraft.util.profiling.jfr.JvmProfiler#onClientTick- Runs on client tick, taking in the current FPS.net.minecraft.util.profiling.jfr.event.ClientFpsEvent- An event that keeps track of the client FPS.net.minecraft.util.profiling.jfr.stats.FpsStat- A record containing the client FPS.net.minecraft.worldLockCode#canUnlock- Whether the given player can unlock this code.Stopwatch- A record that holds the creation time and amount of time that has elapsed.Stopwatches- A tracker for starting, managing, and stopping stopwatches.
net.minecraft.world.effectMobEffects#BREATH_OF_THE_NAUTILUS- Prevents the user from losing air underwater.MobEffectUtil#shouldEffectsRefillAirsupply- Whether the entity has an effect that refills the air supply while under a liquid.
net.minecraft.world.entityEntitygetHeadLookAngle- Calculates the view vector of the head rotation.updateDataBeforeSync- Updates the data stored in the entity before syncing to the client.computeSpeed- Computes last known speed and position of the entity.getKnownSpeed- Gets the last known speed of the entity.hasMovedHorizontallyRecently- If the last known speed’s horizontal distance is larger than 0, more specifically the margin of error.
EntityProcessor- A post processor for an entity when loading.EntityEvent#KINETIC_HIT- An event fired when an entity is hit with a kinetic weapon.HumanoidArm#STREAM_CODEC- The network codec for the arm enum.LivingEntityDEFAULT_KNOCKBACK- The default knockback applied to an entity on hit.itemSwapTicker- The amount of time taken when swapping items.recentKineticEnemies- The attackers that have recently attacked with a kinetic weapon.lungeForwardMaybe- Apply the lunge effects.causeExtraKnockback- Applies an multiplicative force to the knockback.wasRecentlyStabbed,rememberStabbedEntity- Handles enemies that were stabbed with a kinetic weapon.stabAttack- Handles when a mob is stabbed by this entity.onAttack- Handles when this entity has attacked another entity.getTicksUsingItem- Returns the number of ticks this item has been used for.getTicksSinceLastKineticHitFeedback- The number of ticks that has passed since this entity was last hit with a kinetic weapon.shouldTravelInFluid- If this entity should travel in the given fluid.travelInWater- Moves an entity as if they were in water.
Mob#sunProtectionSlot- The equipment slot that protects the entity from the sun.NeutralMob#level- Returns the level the entity is in.PlayerRideableJumping#getPlayerJumpPendingScale- Returns the scalar to apply to the entity on player jump.
net.minecraft.world.entity.ai.attributes.Attributes#DEFAULT_ATTACK_SPEED- The default attack speed.net.minecraft.world.entity.ai.memory.MemoryModuleTypeCHARGE_COOLDOWN_TICKS- The number of cooldown ticks after a charge attack.ATTACK_TARGET_COOLDOWN- The number of cooldown ticks before attacking a target.
net.minecraft.world.entity.ai.sensing.TemptingSensor#forAnimal- A sensor that special cases animal entities for check if the desired item is food.net.minecraft.world.entity.animal.camelCamelgetDashingSound,getDashReadySound- Camel dashing sounds.getStandUpSound,getSitDownSound- Camel sit/stand sounds.getSaddleSound- Camel saddle sound.
CamelHusk- The camel husk entity.
net.minecraft.world.entity.animal.equine.AbstractHorse#isMobControlled- Whether a mob can control this horse.net.minecraft.world.entity.animal.nautilusAbstractNautilus- The core of the nautilus entity.Nautilus- The nautilus entity.NautilusAi- The brain of a nautilus.ZombieNautilus- The zombie nautilus entity.ZombieNautilusAi- The brain of a zombie nautilus.
net.minecraft.world.entity.decoration.HangingEntity#hasLevelCollision- Whether this entity is colliding with a block or the border in a given bounds.net.minecraft.world.entity.monster.skeleton.Parched- The parched entity.net.minecraft.world.entity.monster.zombie.Husk$HuskGroupData- The group data for the husk.net.minecraft.world.entity.player.PlayercannotAttackWithItem- Checks whether the player cannot attack with the item.getItemSwapScale- Returns the scalar to use for the item swap animation.resetOnlyAttackStrengthTicker- Resets the attack strength ticker.openNautilusInventory- Opens the inventory of the interacted nautilus.applyPostImpulseGraceTime,isInPostImpulseGraceTime- Handles the grace time between impulses.
net.minecraft.world.food.FoodData#hasEnoughFood- Whether the current food level is greater than 6 hunger (or three full hunger bars).net.minecraft.world.inventoryAbstractMountInventoryMenu- The inventory menu for a mount.NautilusInventoryMenu- The inventory menu of a nautilus.
net.minecraft.world.itemHoneycombItem#WAXED_RECIPES- A map of waxed block to their recipe categories and name.Item$Propertiesspear- Adds the spear components.nautilusArmor- Adds the nautilus armor components.
ItemStack#matchesIgnoringComponents- Whether the stack matches ignoring all components that match the predicate.ItemUseAnimationTRIDENT- The trident use animation.hasCustomArmTransform- Whether the animation provides a custom transform to the arm.
net.minecraft.world.item.enchantmentEnchantment#doLunge- Applies the post piercing attack effect.EnchantmentEffectComponents#POST_PIERCING_ATTACK- The effect to apply after a piercing attack.EnchantmentHelper#doLungeEffects- Applies the effect on lunge.LevelBasedValue$Exponent- Applies an exponent given the base and power.
net.minecraft.world.item.enchantment.effectsApplyEntityImpulse- An entity effect that adds an impulse in the direction of the look angle.ApplyExhaustion- An entity effect that applies food exhaustion to the player if they are using the enchanted item.ScaleExponentially- A value effect that multiplies the value by a number raised to some exponent.
net.minecraft.world.levelChunk#isValid- Whether the chunk pos is within the maximum allowed coordinate world (within the 30 million block radius).CollisionGetternoEntityCollision- Whether the entity is not colliding with another entity in the given bounds.noBorderCollision- Whether the entity is not colliding with the world border in the given bounds.
Level#isInValidBounds- Whether the block position is not outside the maximum allowed coordinate world (build height for Y axis, 30 million block radius for XZ axis).MoonPhase- An enum representing the phases of the moon.
net.minecraft.world.level.border.WorldBorder$MovingBorderExtent#getPreviousSize- Gets the previous size of the border.net.minecraft.world.level.chunk.storageIOWorker#STORE_EMPTY- A suppliednulltag.LegacyTagFixer- An interface that handles how to upgrade a tag, like for the chunk.SimpleRegionStorageisOldChunkAround- Whether the chunk from a previous version still exists in this version.injectDatafixingContext- When the context is notnull, adds it to the given tag.markChunkDone- Marks a chunk as finished for upgrading to the current version.chunkScanner- Gets the access used to scan chunks.
net.minecraft.world.level.levelgen.structure.LegacyStructureDataHandler#LAST_MONOLYTH_STRUCTURE_DATA_VERSION- Returns the last data version containing glitched monolyths.net.minecraft.world.level.storage.loot.LootContextArg- An argument for a loot context to query.net.minecraft.world.level.storage.loot.functions.DiscardItem- A loot function that discards the loot, returning an empty stack.net.minecraft.world.phys.Vec3offsetRandomXZ- Offsets the point by a random amount in the XZ direction.rotation- Computes the rotation of the vector.applyLocalCoordinatesToRotation- Adds the components relative to the current rotation of the vector.isFinite- Returns whether all components of the vector are finite (not NaN or infinity) values.
net.minecraft.world.scoresScoreboardpackPlayerTeams- Packs the player teams into a serializable format.packObjectives- Packs the objectives into a serializable format.packDisplaySlots- Packs the display slots into a serializable format.
ScoreboardSaveDatagetData,setData- Handles the packed scoreboard.Packed$EMPTY- Represents an empty scoreboard.
net.minecraft.world.waypoints.Waypoint$Icon#copyFrom- Copies the icon color and style from another icon.
List of Changes
com.mojang.blaze3d.platform.Lighting#updateLevelnow takes in aDimensionType$CardinalLightTypeinstead of a boolean for whether the level is the nether or notcom.mojang.blaze3d.systems.GpuDevice#createTexturenow has an overload that takes in a supplied label instead of the raw stringcom.mojang.blaze3d.vertex.VertexConsumeraddVertex,addVertexWith2DPosenow take in the interface, ‘read only’ variants of its arguments (e.g.,Vector3f->Vector3fc)putBulkDatano longer takes the finalbooleanto read the buffer data to determine the initial color
com.mojang.mathOctahedralGroupfromXYAngles->Quadrant#fromXYAnglespermute->SymmetricGroup3#permuteAxis
SymmetricGroup3permutation->permutepermuteVector->OctahedralGroup#rotate
Transformationnow takes in the interface, ‘read only’ variants of its arguments (e.g.,Vector3f->Vector3fc)- This also applies to the argument getter methods
net.minecraftFileUtil#isValidStrictPathSegment->containsAllowedCharactersOnly, now private- Replaced by
isValidPathSegment
- Replaced by
MinecraftdisconnectWithProgressScreennow takes in abooleanof whether to stop the sound enginedisconnectnow takes in abooleanof whether to stop the sound engine
SharedConstantsDEBUG_WATER->DebugScreenEntries#VISUALIZE_WATER_LEVELS, not one-to-oneDEBUG_HEIGHTMAP->DebugScreenEntries#VISUALIZE_HEIGHTMAP, not one-to-oneDEBUG_COLLISION->DebugScreenEntries#VISUALIZE_COLLISION_BOXES, not one-to-oneDEBUG_SUPPORT_BLOCKS->DebugScreenEntries#VISUALIZE_ENTITY_SUPPORTING_BLOCKS, not one-to-oneDEBUG_LIGHT->DebugScreenEntries#VISUALIZE_BLOCK_LIGHT_LEVELS,VISUALIZE_SKY_LIGHT_LEVELS; not one-to-oneDEBUG_SKY_LIGHT_SECTIONS->DebugScreenEntries#VISUALIZE_SKY_LIGHT_SECTIONS, not one-to-oneDEBUG_SOLID_FACE->DebugScreenEntries#VISUALIZE_SOLID_FACES, not one-to-oneDEBUG_CHUNKS->DebugScreenEntries#VISUALIZE_CHUNKS_ON_SERVER, not one-to-one
net.minecraft.advancements.criterion.EntityFlagsPredicatenow takes in optional booleans for if the entity is in water or fall flying- The associated
$Buildermethods have also been added
- The associated
net.minecraft.clientCamerasetupnow takes in aLevelinstead of aBlockGetterget*has been replaced by their record alternatives (e.g.getEntity->entity)Vector3freturn values are replaced withVector3fc
GraphicsStatus->GraphicsPreset, not one-to-oneKeyMappingnow has an overload that takes in the sort orderMouseHandler#lastClickTime->lastClick, now private, not one-to-oneOptionInstance$OptionInstanceSliderButtonnow implementsResettableOptionWidgetOptionsgraphicsMode->graphicsPreset,applyGraphicsPresetshowNowPlayingToast->musicToast, not one-to-one
net.minecraft.client.data.modelsEquipmentAssetProvider#humanoidAndHorse->humanoidAndMountArmorItemModelGeneratorsgetSpans->getSideFaces, not one-to-one$SpanFacing->$SideDirection, not one-to-one$Span->$SideFace, not one-to-one
ItemModelOutput#acceptnow has an overload that takes in theClientItem$Properties
net.minecraft.client.guiFont#NO_SHADOW->Style#NO_SHADOWGuiGraphicstextHighlightnow takes in abooleanof whether to render the background rectanglesubmitOutline->renderOutline
net.minecraft.client.gui.componentsAbstractButton#handleCursor->handleCursor, now protectedAbstractSliderButtonHANDLE_WIDTHis now protectedcanChangeValue,setValueare now protected
AbstractWidget#messageis now protectedCycleButtonnow implementsResettableOptionWidgetbuildernow has an overload to take in a supplied default valuebooleanBuildernow takes in a boolean to choose which component to default to$Buildernow takes in a supplied default valuedisplayOnlyValue(boolean)->displayState, not one-to-one
FocusableTextWidgetconstructor is now package private, usebuilderinsteadOptionsListnow passes in an$AbstractEntryto the generic rather than an$EntryaddSmallnow has an overload that takes in anOptionInstance$Entrynow extends$AbstractEntry$OptionEntryclass is removedbig->$Entry#bigsmall->$Entry#small
StringWidget#clipTextis now public static, taking in theFont
net.minecraft.client.gui.components.debugDebugScreenEntryListtoggleF3Visible->toggleDebugOverlaysetF3Visible->setOverlayVisibleisF3Visible->isOverlayVisible
DebugScreenEntryStatus#IN_F3->IN_OVERLAY
net.minecraft.client.gui.components.debugchart.AbstractDebugChart#COLOR_GREY->CommonColors#TEXT_GRAYnet.minecraft.client.gui.components.toasts.ToastManagercreateNowPlayingToast->initializeMusicToast, now private, not one-to-oneremoveNowPlayingToast->setMusicToastDisplayState, not one-to-one
net.minecraft.client.gui.navigation.ScreenRectangle#transform*methods now take in the interface, ‘read only’ variants of its arguments (e.g.,Vector3f->Vector3fc)net.minecraft.client.gui.render.state.*now take in the interface, ‘read only’ variants for itspose(e.g.,Vector3f->Vector3fc)GuiTextRenderStatenow takes in whether to draw the empty space around each glyph
net.minecraft.client.gui.screensDeathScreennow takes in theLocalPlayerScreennow has an overload that takes in theMinecraftinstance andFontto useminecraftis now finalfontis now finalinit(Minecraft, int, int)->init(int, int)resize(Minecraft, int, int)->init(int, int)handleComponentClicked->ChatScreen#handleComponentClicked, now privatehandleClickEventhas been moved to their associated classes instead of one super interface (e.g.,BookViewScreen#handleClickEvent)
net.minecraft.client.gui.screens.advancementsAdvancementsScreen#renderWindownow takes in the mouse XYintsAdvancementTab#drawTabnow takes in the mouse XYints
net.minecraft.client.gui.screens.debug.DebugOptionsScreen$OptionListis now publicnet.minecraft.client.gui.screens.inventoryAbstractCommandBlockEditScreen#populateAndSendPacketno longer takes in theBaseCommandBlockAbstractContainerScreen#renderSlots,renderSlotnow take in the mouse XYintsCreativeModeInventoryScreen#renderTabButtonnow takes in the mouse XYintsEffectsInInventory#renderEffects->renderHorseInventoryScreennow extendsAbstractMountInventoryScreenMinecartCommandBlockEditScreennow takes in aMinecartCommandBlockinstead of aBaseCommandBlock
net.minecraft.client.gui.screens.multiplayer.ServerSelectionList$OnlineServerEntrynow implementsSelectableEntrynet.minecraft.client.gui.screens.packs.TransferableSelectionList$PackEntrynow implementsSelectableEntrynet.minecraft.client.gui.screens.recipebookRecipeBookComponent#initFilterButtonTextures->getFilterButtonTextures, not one-to-oneRecipeBookTabButtonnow implementsImageButtoninstead ofStateSwitchingButton- The constructor now takes in the XY position along with the
Button$OnPressconsumer
- The constructor now takes in the XY position along with the
net.minecraft.client.gui.screens.worldselection.WorldSelectionList$WorldListEntryis no longer static, now implementsSelectableEntrynet.minecraft.client.modelAnimationUtilsanimateCrossbowChargenow takes in afloatinstead of anintanimateZombieArmsnow takes in anUndeadRenderStateinstead of twofloats
HumanoidModelsetupAttackAnimationno longer takes in afloatgetArmis now public from protected
net.minecraft.client.model.geom.ModelPart#getExtentsForGuinow takes in aConsumer<Vector3fc>instead of a setnet.minecraft.client.model.geom.builders.UVPairis now a recordnet.minecraft.client.multiplayerMultiPlayerGameMode#isAlwaysFlying->isSpectatorServerStatusPinger#pingServernow takes in anEventLoopGroupHolder
net.minecraft.client.rendererCloudRenderer#rendernow takes in the game timelongDynamicUniforms#writeTransform,$Transformno longer take in the line widthfloatGameRenderer#setPanoramicMode->setPanoramicScreenshotParameters, not one-to-oneGlobalSettingsUniform#updatenow takes in theCameraand whether to use Rotated Grid Super Sampling (RGSS)ItemBlockRenderTypes#setFancy->setCutoutLeavesItemInHandRendererno longer takes in theItemRendererLevelRenderer#isSectionCompiled->isSectionCompiledAndVisibleRenderPipelinesLINE_STRIP->LINESorLINES_TRANSLUCENT, not one-to-oneDEBUG_LINE_STRIP->DEBUG_POINTS, not one-to-one
RenderTypeLINE_STRIP,lineStrip->RenderTypes#LINES,LINES_TRANSLUCENT,linesTranslucent; not one-to-onedebugLineStrip->debugPoint, not one-to-one
SkyRenderernow takes in theTextureManagerandAtlasManagerextractRenderStatenow takes in aCamerainstead of the camera positionrenderSunMoonAndStarsnow takes in aMoonPhaseinstead of anint
UniformValue$IVec3Uniformnow takes in aVector3icinstead of aVector3i$Vec2Uniformnow takes in aVector2fcinstead of aVector2f$Vec3Uniformnow takes in aVector3fcinstead of aVector3f$Vec4Uniformnow takes in aVector4fcinstead of aVector4f
WeatherEffectRenderer#tickRainParticlesnow takes in anintfor the weather radiusWorldBorderRenderer#extractnow takes in afloatfor the partial tick
net.minecraft.client.renderer.blockentityBannerRenderer#getExtentsnow takes in aConsumer<Vector3fc>instead of a setBedRenderer#getExtentsnow takes in aConsumer<Vector3fc>instead of a setBellRenderer#BELL_RESOURCE_LOCATION->BELL_TEXTUREDecoratedPotRenderer#getExtentsnow takes in aConsumer<Vector3fc>instead of a setEnchantTableRenderer#BOOK_LOCATION->BOOK_TEXTUREShulkerBoxRenderer#getExtentsnow takes in aConsumer<Vector3fc>instead of a setTestInstanceRendererno longer takes in theBlockEntityRendererProvider$Context
net.minecraft.client.renderer.blockentity.state.BlockEntityWithBoundingBoxRenderState$InvisibleBlockType$STRUCUTRE_VOID->STRUCTURE_VOIDnet.minecraft.client.renderer.chunk.ChunkSectionLayer#textureView->texture, not one-to-onenet.minecraft.client.renderer.entity.EntityRenderDispatcherno longer takes in theItemRenderernet.minecraft.client.renderer.entity.layersCarriedBLockLayerno longer takes in theBlockRenderDispatcherIronGolemFlowerLayerno longer takes in theBlockRenderDispatcherItemInHandLayer#submitArmWithItemnow takes in the heldItemStack
net.minecraft.client.renderer.entity.stateArmedEntityRenderState*HandItem->*HandItemState,*HandItemStack; not one-to-oneextractArmedRenderStatenow takes in the partial tickfloat
HorseRenderState#bodyArmorItem->EquineRenderState#bodyArmorItemHumanoidRenderStateattackTime->ArmedEntityRenderState#attackTimeticksUsingItemis now a float
IllagerRenderStatenow extendsUndeadRenderStateticksUsingItemis now a float
ZombieRenderStatenow extendsUndeadRenderStateZombifiedPiglinRenderStatenow extendsUndeadRenderState
net.minecraft.client.renderer.fog.FogRenderer#setupFogno longer takes in thebooleannet.minecraft.client.renderer.fog.environmentAtmosphericFogEnvironmentnow extendsFogEnvironmentinstead ofAirBasedFogEnvironmentFogEnvironment#setupFogno longer takes in theEntityandBlockPos, instead theCamera
net.minecraft.client.renderer.item.ClientItem$Propertiesnow takes in a float for changing the scale of the swap animationnet.minecraft.client.renderer.special.SpecialModelRenderer#getExtentsnow takes in aConsumer<Vector3fc>instead of a setnet.minecraft.client.renderer.state.SkyRenderState#moonPhaseis now aMoonPhaseinstead of anintnet.minecraft.client.resources.SplashManagerpreparenow returns a list ofComponents instead of stringsapplynow takes in a list ofComponents instead of strings
net.minecraft.client.resources.model.BlockModelRotationis now a classby->get, not one-to-one
net.minecraft.client.resources.soundsRidingHappyGhastSoundInstance->RidingEntitySoundInstance, not one-to-oneRidingMinecartSoundInstancenow extendsRidingEntitySoundInstanceinstead ofAbstractTickableSoundInstance- The constructor now takes in the
SoundEvent, volume min and max, and amplifier
- The constructor now takes in the
SimpleSoundInstance#forMusicno longer takes in the volume
net.minecraft.client.soundsSoundEngineno longer takes in theMusicManagerupdateCategoryVolume->refreshCategoryVolumesetVolume->updateCategoryVolume, not one-to-one
SoundManagerno longer takes in theMusicManagerupdateSourceVolume->refreshCategoryVolumesetVolume->updateCategoryVolume, not one-to-one
net.minecraft.gametest.framework.GameTestHelperspawnnow has an overload that takes in theEntitySpawnReasonor threeints for the positionassetTrue,assetFalse,assertValueEqualnow has an overload that takes in aStringinstead of aComponentassertEntityDatanow has an overload that takes in theAABBbounding boxgetRelativeBoundsis now publicassertEntityPosition->assertEntityPresent, not one-to-one
net.minecraft.nbtCompoundTag#removenow returns the removed tagNbtUtils#getDataVersionnow has an overload that only takes in theCompoundTag
net.minecraft.networkConnectionNETWORK_WORKER_GROUP->EventLoopGroupHolder#NIO, not one-to-oneNETWORK_EPOLL_WORKER_GROUP->EventLoopGroupHolder#EPOLL, not one-to-oneLOCAL_WORKER_GROUP->EventLoopGroupHolder#LOCAL, not one-to-oneconnectToServer,connectnow take in anEventLoopGroupHolderinstead of aboolean
FriendlyByteBufwriteVector3fnow takes in aVector3fcinstead of aVector3fwriteQuaternionnow takes in aQuaternionfcinstead of aQuaternionfDEFAULT_NBT_QUOTA->NbtAccounter#DEFAULT_NBT_QUOTA
net.minecraft.network.codecByteBufCodecsVECTOR3Fnow uses aVector3fcinstead of aVector3fQUATERNIONFnow uses aQuaternionfcinstead of aQuaternionf
StreamCodec#compositenow has ten and twelve parameter variants
net.minecraft.network.chatComponentUtils#mergeStylesnow has an overload that takes in and returns aComponentMutableComponentis now final
net.minecraft.network.protocol.gameClientboundHorseScreenOpenPacket->ClientboundMountScreenOpenPacketClientGamePacketListener#handleHorseScreenOpen->handleMountScreenOpenGamePacketTypes#CLIENTBOUND_HORSE_SCREEN_OPEN->CLIENTBOUND_MOUNT_SCREEN_OPEN
net.minecraft.network.numbersFixedFormatis now a recordStyledFormatis now a record
net.minecraft.network.syncher.EntityDataSerializersVECTOR3now uses aVector3fcinstead of aVector3fQUATERNIONnow uses aQuaternionfcinstead of aQuaternionf
net.minecraft.serverMinecraftServerisAllowedToEnterPortal->ServerLevel#isAllowedToEnterPortalisSpawningMonsters->ServerLevel#isSpawningMonstersisPvpAllowed->ServerLevel#isPvpAllowedisCommandBlockEnabled->ServerLevel#isCommandBlockEnabledisSpawnerBlockEnabled->ServerLevel#isSpawnerBlockEnabledgetGameRules->ServerLevel#getGameRulesisEpollEnabled->useNativeTransport
ServerScoreboardno longer implements its own saved data type, instead using the packedScoreboardSaveDataTYPE->ScoreboardSavedData#TYPE
net.minecraft.server.jsonrpcIncomingRpcMethodnow takes in two generics for the parameters to the request and the result response$Buildernow has constructors for parameterless and parameter functions, replacing$Factoryresponse,paramnow take in theirSchemas
OutgoingRpcMethod$Factorynow takes in the generic params and result
net.minecraft.server.jsonrpc.apiMethodInfo,$Namednow takes in two generics for the parameters to the request and the result responsePARAMS_CODEC->paramsTypedCodec, now private, not one-to-oneMAP_CODEC->typedCodec, now package-private, not one-to-one
ParamInfonow takes in a generic for the parameterCODEC->typedCodec, not one-to-one
ResultInfonow takes in a generic for the result responseCODEC->typedCodec, not one-to-one
Schemanow takes in a generic for the type it represents- The constructor now takes in a list of types instead of an optional, an non-optional property map, non-oprional enuma values, and the codec to serialize the type
ofTypesnow has an overload that takes in a list of types
SchemaComponentnow takes in a generic for the type it represents
net.minecraft.server.jsonrpc.security.AuthenticationHandlernow implementsChannelDuplexHandlerinstead ofChannelInboundHandlerAdapter- The constructor now takes in a string set of allowed origins
$SecurityCheckResult#allowednow has an overload that specifies whether the token was sent through the websocket protocol
net.minecraft.server.levelChunkMapnow extendsSimpleRegionStorageinstead ofChunkStorageServerLevel#dropno longer returns aboolean
net.minecraft.server.network.ServerConnectionListenerSERVER_EVENT_GROUP->EventLoopGroupHolder#NIO, not one-to-oneSERVER_EPOLL_EVENT_GROUP->EventLoopGroupHolder#EPOLL, not one-to-one
net.minecraft.stats.ServerStatsCounternow takes in aPathinstead of aFileparseLocal->parse, not one-to-onetoJsonnow returns aJsonElementinstead of aString
net.minecraft.utilARGB#lerp->srgbLerpExtraCodecsnow use the interface, ‘read only’ variants for its generic (e.g.,Vector3f->Vector3fc)MtheaseInOutSine->Ease#inOutSinesin,cosnow takes in adoubleinstead of afloatabsMaxnow has overloads that usesints orfloats
TriStatenow implementsStringRepresentable
net.minecraft.util.profiling.jfr.Percentiles#evaluatenow has an overload that takes in anint[]net.minecraft.util.profiling.jfr.parse.JfrStatsResultnow takes in an FPS stattickTimes->serverTickTimes
net.minecraft.util.profiling.jfr.stats.TimedStatSummary#summarynow returns an optional of theTimeStatSummarynet.minecraft.util.worldupdate.WorldUpgrader$AbstractUpgraderno longer takes in a genericcreateStoragenow returns aSimpleRegionStorageinstead of the generictryProcessOnePositionnow takes in aSimpleRegionStorageinstead of the generic
$DimensionToUpgradeno longer takes in a generic, instead usingSimpleRegionStorage
net.minecraft.world.RandomSequencesno longer takes in the world seedcodec->CODECget,resetnow takes in the world seed
net.minecraft.world.entityAvatar#DATA_PLAYER_MAIN_HANDnow uses aHumanoidArmgeneric instead of a byteEntity#hasImpulse->needsSyncEntityType#loadEntityRecursivenow takes in anEntityProcessorinstead of aFunctionLivingEntity#invulnerableDuration->INVULNERABLE_DURATIONMob#playAttackSound->LivingEntity#playAttackSoundNeutralMobTAG_ANGER_TIME->TAG_ANGER_END_TIME, not one-to-onegetRemainingPersistentAngerTime->getPersistentAngerEndTime, not one-to-onesetRemainingPersistentAngerTime->setTimeToRemainAngry,setPersistentAngerEndTime; second is not one-to-onegetPersistentAngerTarget,setPersistentAngerTargetnow deal withEntityReferences
net.minecraft.world.entity.ai.sensing.SensorType#*_TEMPTATIONS->FOOD_TEMPTATIONS, not one-to-onenet.minecraft.world.entity.ai.utilGoalUtilsmobRestrictednow takes in adoubleinstead of anintisRestrictednow has an overload that takes in aVec3
LandRandomPosgetPosAwaynow has an overload that takes in an additionaldoublefor the start/end radiansgenerateRandomPosTowardDirectionnow takes in adoubleinstead of anint
RandomPosgenerateRandomDirectionWithinRadiansnow takes indoubles for the start/end radiansgenerateRandomPosTowardDirectionnow takes in adoubleinstead of anint
net.minecraft.world.entity.animal.equine.AbstractHorse#getInventorySize->AbstractMountInventoryMenu#getInventorySizenet.minecraft.world.entity.monster.Monster#checkMonsterSpawnRulesnow expanded its type generic to extendsMobinstead ofMonsternet.minecraft.world.entity.monster.skeleton.Bogged#*_ATTACK_INTERVAL->AbstractSkeleton#INCREASED_*_ATTACK_INTERVALnet.minecraft.world.entity.monster.zombieHusk#checkHuskSpawnRules->Monster#checkSurfaceMonsterSpawnRules, not one-to-oneZombiedoUnderWaterConversionnow takes in theServerLevelconvertToZombieTypenow takes in theServerLevel
net.minecraft.world.entity.npc.villagerAbstractVillagerupdateTradesnow takes in theServerLeveladdOffersFromItemListingsnow takes in theServerLevel
Villager#shouldRestocknow takes in theServerLevelVillagerTrades$ItemListing#getOffernow takes in theServerLevel
net.minecraft.world.entity.player.PlayeropenMinecartCommandBlocknow takes in aMinecartCommandBlockinstead of aBaseCommandBlocksweepAttack->doSweepAttack, now private, not one-to-onerespawn->LocalPlayer#respawnCLIENT_LOADED_TIMEOUT_TIME->ServerGamePacketListenerImpl#CLIENT_LOADED_TIMEOUT_TIMEclientLoadedTimeoutTimer,tickClientLoadTimeout->ServerGamePacketListenerImpl#tickClientLoadTimeouthasClientLoaded->ServerGamePacketListenerImpl#hasClientLoadedsetClientLoaded->ServerGamePacketListenerImpl#markClientLoaded,markClientUnloadedAfterDeath,restartClientLoadTimerAfterRespawn; not one-to-one
net.minecraft.world.entity.projectile.Projectileconstructor is nowprotectedinstead of package privatenet.minecraft.world.entity.vehicle.VehicleEntity#shouldSourceDestroyis nowprotectedinstead of package privatenet.minecraft.world.entity.vehicle.minecartAbstractMinecartnow takes in theServerLevelMinecartCommandBlock$MinecartCommandBaseis now package-private
net.minecraft.world.inventory.HorseInventoryMenunow extendsAbstractMountInventoryMenunet.minecraft.world.item.component.ItemAttributeModifiers#computenow takes in theAttributeholdernet.minecraft.world.item.enchantment.effects.PlaySoundEffectnow takes in a list of sound events instead of a singlenet.minecraft.world.levelBaseCommandBlockperformCommandnow takes in aServerLevelinstead of aLevelonUpdatednow takes in aServerLevelcreateCommandSourceStacknow takes in aServerLevel$CloseableCommandBlockSourcenow takes in aServerLevel, with its constructor protected
CollisionGetter#noBlockCollisionnow has an overload that takes in an additionalbooleanof whether to check liquid collisions.Level#getGameTime->LevelAccessor#getGameTimeLevelAccessor#getCurrentDifficultyAt->ServerLevelAccessor#getCurrentDifficultyAtLevelTimeAccess#getMoonPhasenow returns aMoonPhaseinstead of anint
net.minecraft.world.level.biomeAmbientAdditionsSettingsis now a recordAmbientMoodSettingsis now a recordAmbientParticleSettingsis now a record
net.minecraft.world.level.block.entity.BaseContainerBlockEntity#canUnlock->sendChestLockedNotifications, not one-to-onenet.minecraft.world.level.borderBorderChangeListener#onLerpSizenow takes in an additionallongfor the game timeWorldBordercan now take in theWorldBorder$SettingsgetMin*,getMax*now have an overload that takes in the partial tickfloatlerpSizeBetweennow takes in an additionallongfor the game timeapplySettings->applyInitialSettings, not one-to-one- The original behavior can be replicated by passing the settings into the constructor
$BorderExtent#getMin*,getMax*now takes in the partial tickfloat
net.minecraft.world.level.chunk.storageRecreatingSimpleRegionStoragenow takes in a suppliedLegacyTagFixerSimpleRegionStoragenow takes in a suppliedLegacyTagFixerwritenow has an overload that takes in a suppliedCompoundTagupgradeChunkTagnow has an overload that takes in a a nullable tag comntext
net.minecraft.world.level.dimension.DimensionTypeMOON_PHASESis now an array ofMoonPhases and privatemoonPhasenow returns aMoonPhaseinstead of anint
net.minecraft.world.level.levelgen.structure.LegacyStructureDataHandlernow implementsLegacyTagFixer- The constructor now takes in the
DataFixer removeIndex->LegacyTagFixer#markChunkDoneupdateFromLegacynow privategetLegacyStructureHandlernow takes in theDataFixer, a suppliedDimensionDataStorage, and returns a suppliedLegacyTagFixer
- The constructor now takes in the
net.minecraft.world.level.levelgen.structure.structures.NetherFortressPieces$StartPiecefields are now package-privatenet.minecraft.world.level.saveddata.SavedDataTypeno longer takes in aSavedData$Context, removing the function argument constructornet.minecraft.world.level.storageDimensionDataStorageno longer takes in aSavedData$ContextFileNameDateFormatter#create->FORMATTERLevelStorageSourceUNCOMPRESSED_NBT_QUOTA->NbtAccounter#UNCOMPRESSED_NBT_QUOTA, nowpublic$LevelDirectory#corruptedDataFile,rawDataFilenow take in aZonedDateTimeinstead of aLocalDateTime
net.minecraft.world.level.storage.loot.LootContext$BlockEntityTargetnow implementsLootContextArg$SimpleGettergetParam->contextParam
$EntityTargetnow implementsLootContextArg$SimpleGettergetParam->contextParam
$ItemStackTargetnow implementsLootContextArg$SimpleGettergetParam->contextParam
net.minecraft.world.level.storage.loot.functionsCopyComponentsFunction$*Source->$DirectSource, not one-to-one$Source->LootContextArg$Getter, not one-to-one
CopyNameFunction#copyNamenow takes in aLootContextArginstead of a$Source$Source->LootContextArg, not one-to-one
FilteredFunctionnow takes in anOptionalpass and failLootItemFunctioninstead of just a modifier- The function can now be builder through a
$Builderviafiltered
- The function can now be builder through a
net.minecraft.world.phys.Vec3now takes in aVector3fcinstead of aVector3fnet.minecraft.world.phys.shapes.Shapes#rotateHorizontal,rotateAll,rotateAttachFacenow have overloads to take in theOctahedralGroupnet.minecraft.world.scoresScorenow has a public constructor for the$PackedvalueMAP_CODEC->Score$Packedands its$Packed#MAP_CODEC
Scoreboard$PackedScore#scorenow takes in aScore$Packedinstead of aScoreScoreboardSavedDatanow takes in aScoreboardSaveData$Packedinstead of aScoreboardFILE_IDmerged into typeloadFrom->ServerScoreboard#loadpack->ServerScoreboard#store, now private, not one-to-one
List of Removals
com.mojang.blaze3d.vertex.VertexFormat$Mode#LINE_STRIPnet.minecraft.Util#lastOfnet.minecraft.clientMinecraft#useFancyGraphicsGuiMessage#iconStringSplitterformattedIndexByWidth,componentStyleAtWidthsplitLines(FormattedText, int, Style, FormattedText)
net.minecraft.client.gui.Font#wordWrapHeight(String, int)net.minecraft.client.gui.componentsCycleButtononOffBuilder()$Builder#withInitialValue
StateSwitchingButton
net.minecraft.client.gui.screens.inventoryEffectsInInventory#renderTooltipInventoryScreen#renderEntityInInventory
net.minecraft.client.gui.screens.packs.PackSelectionScreen#clearSelectednet.minecraft.client.player.LocalPlayer#USING_ITEM_SPEED_FACTORnet.minecraft.client.rendererItemModelGenerator#createOrExpandSpanGpuWarnlistManager#dismissWarningAndSkipFabulous,isSkippingFabulousRenderPipelinesDEBUG_STRUCTURE_QUADS,DEBUG_SECTION_QUADS
SkyRenderer#initTextures
net.minecraft.client.renderer.fog.environmentAirBasedFogEnvironmentDimensionOrBossFogEnvironmentFogEnvironment#onNotApplicable
net.minecraft.client.resources.model.BlockModelRotation#actualRotationnet.minecraft.gametest.framework.GameTestHelper#setNight,setDayTimenet.minecraft.network.FriendlyByteBuf#readDate,writeDatenet.minecraft.serverMinecraftServer#hasGuiServerScoreboard#createData,addDirtyListener
net.minecraft.server.jsonrpc.IncomingRpcMethod$Factorynet.minecraft.server.jsonrpc.methods.IllegalMethodDefinitionExceptionnet.minecraft.server.jsonrpc.security.AuthenticationHandler#AUTH_HEADERnet.minecraft.utilDebugBufferLazyLoadedValue
net.minecraft.util.thread.NamedThreadFactorynet.minecraft.world.entity.Mob#isSunBurnTicknet.minecraft.world.entity.animal.armadillo.ArmadilloAi#getTemptationsnet.minecraft.world.entity.animal.axolotl.AxolotlAi#getTemptationsnet.minecraft.world.entity.animal.camel.CamelAi#getTemptationsnet.minecraft.world.entity.animal.equine.ZombieHorse#checkZombieHorseSpawnRules- Use
Monster#checkMonsterSpawnRulesinstead
- Use
net.minecraft.world.entity.animal.goat.GoatAi#getTemptationsnet.minecraft.world.entity.animal.sniffer.SnifferAi#getTemptationsnet.minecraft.world.entity.player.Player#playNotifySoundnet.minecraft.world.entity.raid.Raid#TICKS_PER_DAYnet.minecraft.world.levelBaseCommandBlockgetLevelgetUsedBy,getPosition
Level#TICKS_PER_DAY
net.minecraft.world.level.border.WorldBorder$Settings#toWorldBorder- Use the
WorldBorderconstructor instead
- Use the
net.minecraft.world.level.chunk.storageChunkStorageRecreatingChunkStorage
net.minecraft.world.level.saveddata.SavedData$Contextnet.minecraft.world.phys.Vec3#fromRGB24
Minecraft 1.21.11 -> 26.1 Mod Migration Primer
This is a high level, non-exhaustive overview on how to migrate your mod from 1.21.11 to 26.1. This does not look at any specific mod loader, just the changes to the vanilla classes.
This primer is licensed under the Creative Commons Attribution 4.0 International, so feel free to use it as a reference and leave a link so that other readers can consume the primer.
If there’s any incorrect or missing information, please file an issue on this repository or ping @ChampionAsh5357 in the Neoforged Discord server.
Thank you to:
- @Shnupbups for some grammatical fixes
- @cassiancc for information about Java 25 IDE support
- @boq for information regarding IME support
- @lolothepro for a typo
Pack Changes
There are a number of user-facing changes that are part of vanilla which are not discussed below that may be relevant to modders. You can find a list of them on Misode’s version changelog.
Java 25 and Deobfuscation
26.1 introduces two new changes into the general pipeline.
First, the Java Development Kit has been upgraded from 21 to 25. Vanilla makes use of these new features, such as JEP 447, which allows statements before super within constructors. For users within the modding scene, please make sure to update accordingly, or take advantage of your IDE or build tool features. Microsoft’s OpenJDK can be found here.
You may need to update your IDE to support Java 25. If using Eclipse, you will need at least either 2025-12, or 2025-09 with the Java 25 Support marketplace plugin. If using IntelliJ IDEA, you will need at least 2025.2.
Vanilla has also returned to being deobfuscated, meaning that all value types now have the official names provided by Mojang. There are still some things that are not captured due to the Java compilation process, such as inlining primitive and string constants, but the majority are now provided. This will only have a change for users or mod loaders who used a different value type mapping set from the official mappings.
Loot Type Unrolling
Loot pool entries, item functions, item conditions, nbt providers, number providers, score providers, int providers, and float providers no longer use a wrapping object type to act as the registered instance. Now, the registries directly take in the MapCodec used for the serialization and deserialization process. As such, the *Type classes or records that held the codec have been removed. Additionally, getType is now renamed to codec, taking in the registered MapCodec.
// The following is an example with LootItemFunctions, but can roughly apply to the other instances as well
public record NoopItemFunction() implements LootItemFunction {
public static final NoopItemFunction INSTANCE = new NoopItemFunction();
// The map codec used as the registry object
public static final MapCodec<NoopItemFunction> MAP_CODEC = MapCodec.unit(INSTANCE);
// Replaces getType
@Override
public MapCodec<NoopItemFunction> codec() {
// Return the registry object
return MAP_CODEC;
}
}
// Register the map codec to the appropriate registry
Registry.register(BuiltInRegistries.LOOT_FUNCTION_TYPE, Identifier.fromNamespaceAndPath("examplemod", "noop"), NoopItemFunction.MAP_CODEC);
net.minecraft.core.registries.BuiltInRegistries,RegistriesLOOT_POOL_ENTRY_TYPEnow holds aLootPoolEntryContainermap codec instead of aLootPoolEntryTypeLOOT_FUNCTION_TYPEnow holds aLootItemFunctionmap codec instead of aLootItemFunctionTypeLOOT_CONDITION_TYPEnow holds aLootItemConditionmap codec instead of aLootItemConditionTypeLOOT_NUMBER_PROVIDER_TYPEnow holds aNumberProvidermap codec instead of aLootNumberProviderTypeLOOT_NBT_PROVIDER_TYPEnow holds aNbtProvidermap codec instead of aLootNbtProviderTypeLOOT_SCORE_PROVIDER_TYPEnow holds aScoreboardNameProvidermap codec instead of aLootScoreProviderTypeFLOAT_PROVIDER_TYPEnow holds aFloatProvidermap codec instead of aFloatProviderTypeINT_PROVIDER_TYPEnow holds aIntProvidermap codec instead of aIntProviderType
net.minecraft.util.valueprovidersnow renamesCODECfields toMAP_CODECFloatProvidersubtypes are now all recordsIntProvidersubtypes, except forWeightedListInt, are now all recordsFloatProvideris now aninterfacefrom aclassCODEC->FloatProviders#CODECcodec->FloatProviders#codecgetType->codec, not one-to-onegetMinValue->mingetMaxValue->max
FloatProviders- All vanilla float providers to register.FloatProviderTypeinterface is removed- Singleton fields have all been removed, use map codecs in each class instead
codec->FloatProvider#codec
IntProvideris now aninterfacefrom aclassCODEC->IntProviders#CODECNON_NEGATIVE_CODEC->IntProviders#NON_NEGATIVE_CODECPOSITIVE_CODEC->IntProviders#POSITIVE_CODECcodec->IntProviders#codecvalidateCodec->IntProviders#validateCodecgetMinValue->minInclusivegetMaxValue->maxInclusivegetType->codec, not one-to-one
IntProviders- All vanilla int providers to register.IntProviderTypeinterface is removed- Singleton fields have all been removed, use map codecs in each class instead
codec->IntProvider#codec
net.minecraft.world.level.storage.loot.entriesnow renamesCODECfields toMAP_CODECLootPoolEntriessingleton fields have all been removed- The map codecs in each class should be used instead
bootstrap- Registers the loot pool entries.
LootPoolEntryContainer#getType->codec, not one-to-oneLootPoolEntryTyperecord is removed
net.minecraft.world.level.storage.loot.functionsnow renamesCODECfields toMAP_CODECLootItemFunction#getType->codec, not one-to-oneLootItemFunctionssingleton fields have all been removed- The map codecs in each class should be used instead
bootstrap- Registers the loot item functions.
LootItemFunctionTyperecord is removed
net.minecraft.world.level.storage.loot.predicatesnow renamesCODECfields toMAP_CODECLootItemCondition#getType->codec, not one-to-oneLootItemConditionssingleton fields have all been removed- The map codecs in each class should be used instead
bootstrap- Registers the loot item conditions.
LootItemConditionTyperecord is removed
net.minecraft.world.level.storage.loot.providers.nbtnow renamesCODECfields toMAP_CODECLootNbtProviderTyperecord is removedNbtProvidernow implementsLootContextUsergetType->codec, not one-to-one
NbtProviderssingleton fields have all been removed- The map codecs in each class should be used instead
bootstrap- Registers the nbt providers.
LootItemConditionTyperecord is removed
net.minecraft.world.level.storage.loot.providers.numbernow renamesCODECfields toMAP_CODECLootNumberProviderTyperecord is removedNumberProvider#getType->codec, not one-to-oneNumberProviderssingleton fields have all been removed- The map codecs in each class should be used instead
bootstrap- Registers the number providers.
net.minecraft.world.level.storage.loot.providers.scorenow renamesCODECfields toMAP_CODECLootScoreProviderTyperecord is removedScoreProvidernow implementsLootContextUsergetType->codec, not one-to-one
ScoreProviderssingleton fields have all been removed- The map codecs in each class should be used instead
bootstrap- Registers the score providers.
Validation Overhaul
The validation handler used to collect and then report problems with data-generated content has been overhauled. This is not, and has never been a replacement for field validation. The validation handler is specifically for more easily handling validation between multiple pieces of information that may not be exposed to a single field, such as whether a loot provider can be used for the given context params.
All validated objects implement either Validatable, or CriterionTriggerInstance specifically for advancement criteria. Both of these methods provide one method: validate, which is used to check the validity of an object. validate takes in a ValidationContext, which essentially holds the ProblemReporter used to collect issues, the current context params, and a reference resolver. CriterionTriggerInstance provides a ValidationContextSource, but this can be transformed to a ValidationContext using one of the context methods, providing the context params to check against. If the specific object cannot be validated, then ValidationContext#reportProblem is called, detailing the specific issue.
// For some object that implements Validatable
@Override
public void validate(ValidationContext ctx) {
// Check if a specific condition is validated.
if (this.foo() != this.bar()) {
// If not, report that there is an issue.
ctx.reportProblem(() -> "'Foo' does not equal 'bar'.");
}
}
If the object itself does not have any issues, but rather the specific fields, then the reporter can follow the stack trace while checking the individual elements using one of the ValidationContext#for* methods, performing something similar.
// For some object that implements Validatable
// Let's assume it has a list of children objects.
@Override
public void validate(ValidationContext ctx) {
for (int i = 0; i < this.children.size(); i++) {
// Get specific context for child in list
var childCtx = ctx.forIndexedField("children", i);
// Check if a specific condition is validated.
if (this.foo() != this.bar()) {
// If not, report that there is an issue.
childCtx.reportProblem(() -> "'Foo' does not equal 'bar'.");
}
}
}
Validatable also provides some static utilities for checking other Validatable fields.
// For some object that implements Validatable
// Assume some child object also implements Validatable
@Override
public void validate(ValidationContext ctx) {
Validatable.validate(ctx, "child", this.child);
}
After Validatable is implemented on all required objects, the validation can then be called depending on where it is used (typically after deserialization or before serialization). The call stack for these is typically the following:
// For some Validatable validatable
// Let's assume we have access to the HolderGetter.Provider provider.
// The parameter itself is optional if not available.
// Create the problem collector and validation context.
// The context params should only include the ones that are being provided.
ProblemReporter reporter = new ProblemCollector.Collector();
ValidationContext ctx = new ValidationContext(reporter, LootContextParamSets.ALL_PARAMS, provider);
// Call the validator
validatable.validate(ctx);
This can also be appended to the end of codecs via Codec#validate:
public record ExampleObject() implements Validatable {
public static final Codec<ExampleObject> CODEC = MapCodec.unitCodec(
ExampleObject::new
).validate(
// Supply the validator along with the context params to check against.
// This method does not have access to the registry provider.
Validatable.validatorForContext(LootContextParamSets.ALL_PARAMS)
);
@Override
public void validate(ValidationContext ctx) {
// ...
}
}
net.minecraft.advancements.CriterionTriggerInstance#validatenow takes in aValidationContextSourceinstead of aCriterionValidatornet.minecraft.advancements.criterionContextAwarePredicatenow implementsValidatableCriterionValidator->ValidationContextSourceandValidatableValidatablecontains thevalidate*methodsValidationContextSourceholds the context and reporters
net.minecraft.world.item.enchantmentConditionalEffectnow implementsValidatableconditionCodecis replaced by callingvalidateafter load
TargetedConditionalEffectnow implementsValidatable
net.minecraft.world.level.storage.lootIntRangenow implementsLootContextUsergetReferencedContextParamsreplaced byvalidate
LootContext$VisitedEntrygeneric must now extendValidatableLootContextUsernow implementsValidatableLootDataTypegeneric must now extendValidatable- The constructor now takes in a
$ContextGetterinstead of a$Validator runValidationnow takes in theValidationContextSourceinstead of aValidationContext- Also has an overload taking in a
HolderLookupinstead of a key-value pair
- Also has an overload taking in a
createSimpleValidator,createLootTableValidator,$Validatorreplaced byValidatable$ContextGetter- Gets theContextKeySetfor some value.
- The constructor now takes in a
LootPoolnow implementsValidatableLootTablenow implementsValidatableValidatable- An interface which handles the validation of its instance within the given context.ValidationContextforField- Creates a context for a given field.forIndexedField- Creates a context for a given entry in a list.forMapField- Creates a context for a given key in a map.setContextKeySetis removed
ValidationContextSource- The source for the defined context where the validation is taking place.
net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainernow implementsValidatablenet.minecraft.world.level.storage.loot.functionsSetAttributesFunction$Modifiernow implementsLootContextUserSetStewEffectFunction$EffectEntrynow implementsLootContextUser
Datapack Villager Trades
Villager trades has now become a data-generated registry from its original map-based setup. While basic impressions make it seem like that system is more limited, it is actually just as extensible, though in a rather convoluted way because the trades are functionally a loot table itself to determine what MerchantOffers a trader can provide. For the purposes of understanding, this section will go over the basics of the trade rewrite, along with how each previous item listing can be converted to a VillagerTrade.
Understanding the Trade Format
All trades are expressed as VillagerTrades, which at its core determines what a trader wants and what it gives in return. Each trade can also provide modifiers to the item itself or its cost, or whether the specific trade can be made at all with the given condition. Each trade also specifies the number of trades that can be made, how much xp to give, or the price multiple that is multiplied with the user’s reputation. A VillagerTrade is then turned into a MerchantOffer via getOffer, taking in the LootContext, typically with a context param of LootContextParamSets#VILLAGER_TRADE, providing the trader itself (THIS_ENTITY) and its position (ORIGIN).
The trades themselves are within data/<namespace>/villager_trade/<path>. Typically the path contains the profession and level the trade is for, such as examplemod:example_profession/1/example_trade
// For some villager trade 'examplemod:example_profession/1/example_trade'
// JSON at 'data/examplemod/villager_trade/example_profession/1/example_trade.json'
{
// The stack the trader wants.
"wants": {
// The item of the stack.
"id": "minecraft:apple",
// A number provider used to determine how much
// of the item that it wants. Once the count is
// determined, any additional cost on the `gives`
// stack (via `ADDITIONAL_TRADE_COST` component)
// is added to the count before being clamped to
// the max stack size.
// If not specified, defaults to 1.
"count": {
"type": "minecraft:uniform",
"min": 1,
"max": 5
},
// Any components that stack should have. The stack
// must have the exact components specified.
// If not specified, then no components will be
// checked, meaning that this is ignored.
"components": {
// Map of registry key to component value.
"minecraft:custom_name": "Apple...?"
}
},
// An additional stack the trader wants.
// If not specified, the trader only checks `wants`.
"additional_wants": {
"id": "minecraft:emerald"
},
// The stack template the trader gives in return.
"gives": {
// The item of the stack.
"id": "minecraft:golden_apple",
// A number [1, 99].
// If not specified, defaults to 1.
"count": 1,
// The components to apply to the stack.
// If not specified, just applies the default
// item components.
"components": {
"minecraft:custom_name": "Not an Apple"
}
},
// A number provider to determine how many times
// the trade can be performed by the player before
// the trader restocks. The value will always be at
// least 1.
// If not specified, defaults to 4.
"max_uses": {
"type": "minecraft:uniform",
"min": 1,
"max": 20
},
// A number provider to determine the price multiplier
// to apply to the cost of the item based on the player's
// reputation with the trader and the item demand,
// calculated from how many times the player has performed
// the trade. This should generally be a small number as
// the maximum reputation a user can have per trader is 150,
// though it's more likely to have a reputation of 25 at most.
// However, the trade must always have a minimum of one item,
// even if the reputation discount multiplied with the reputation
// indicates 100% or more off.
// If not specified, defaults to 0.
"reputation_discount": {
"type": "minecraft:uniform",
"min": 0,
"max": 0.05
},
// A number provider to determine the amount of experience
// the player obtains from performing the trade with the trader.
// This is typically around 5-30 xp for vanilla trades.
// If not specified, defaults to 1.
"xp": {
"type": "minecraft:uniform",
"min": 10,
"max": 20
},
// A loot item condition that determines whether the
// trader can provide the trade to the player.
// If not specified, defaults to always true.
"merchant_predicate": {
// This trade can only be performed by villagers
// from a desert or snow village.
"condition": "minecraft:entity_properties",
"entity": "this",
"predicate": {
"predicates": {
"minecraft:villager/variant": [
"minecraft:desert",
"minecraft:snow"
]
}
}
},
// A list of loot item functions that modify the item
// offered from `gives` to the player.
// If not specified, `gives` is not modified.
"given_item_modifiers": [
{
// Chooses a random enchantment from the provided tag
"function": "minecraft:enchant_randomly",
// If this is true, the trade cost increases the
// number of `wants` items required.
"include_additional_cost_component": true,
"only_compatible": false,
"options": "#minecraft:trades/desert_common"
}
],
// Can either be an enchantment id, such as "minecraft:protection",
// or a list of enchantment ids, such as ["minecraft:protection", "minecraft:smite", ...],
// or an enchantment tag, such as "#minecraft:trades/desert_common".
// When provided, if the `gives` item after modifiers contains an
// enchantment in this list, then the number of `wants` items required
// is multiplied by 2.
// If not specified, does nothing.
"double_trade_price_enchantments": "#minecraft:trades/desert_common"
}
The Trades of a Trader
Every trader can make many trades, typically choosing from a specified pool known as a TradeSet. Trade sets themselves are a separate datapack registry that consumes VillagerTrades. Each set of trades determines how many trades can be offered and if the same trade can be chosen more than once. The trades that are offered are computed within AbstractVillager#addOffersFromTradeSet, first calling TradeSet#calculateNumberOfTrades to get the number of offers, and then using either AbstractVillager#addOffersFromItemListings or AbstractVillager#addOffersFromItemListingsWithoutDuplicates to choose the offers to use.
Note that if duplicate trades are allowed, there is a potential race condition where if all trades’ merchant_predicates fail, then the offers will loop forever. This is because the method always assumes that there will be one trade that can be made.
The trade sets are within data/<namespace>/trade_set/<path>. Typically the path contains the profession and level the trade is for, such as examplemod:example_profession/level_1.json
// For some trade set 'examplemod:example_profession/level_1'
// JSON at 'data/examplemod/villager_trade/trade_set/level_1.json'
{
// Can either be a villager trade id, such as "examplemod:example_profession/1/example_trade",
// or a list of trade ids, such as ["examplemod:example_profession/1/example_trade", "minecraft:farmer/1/wheat_emerald", ...],
// or an trade tag, such as "#examplemod:example_profession/level_1".
// This is the set of trades that can be offered by the trader.
// This should always be a villager trade tag so allow other users
// to easily add their own trades to a trader.
"trades": "#examplemod:example_profession/level_1",
// A number provider that determines the number of offers that can be
// made by the trader.
"amount": {
"type": "minecraft:uniform",
"min": 1,
"max": 5
},
// Whether the same trade can be used to make multiple offers.
// If not specified, defaults to false.
"allow_duplicates": true,
// An identifier that determines the unique random instance to
// user when determining the offers.
// If not specified, uses the level random.
"random_sequence": "examplemod:example_profession/level_1"
}
Where the villager trade tag could be:
// For some tag 'examplemod:example_profession/level_1'
// JSON at 'data/examplemod/tags/villager_trade/example_profession/level_1.json'
{
"values": [
"examplemod:example_profession/1/example_trade"
]
}
This also means trades can be easily added to existing trade sets by adding to the associated tag:
// For some tag 'minecraft:farmer/level_1'
// JSON at 'data/minecraft/tags/villager_trade/farmer/level_1.json'
{
"values": [
"examplemod:example_profession/1/example_trade"
]
}
Meanwhile, adding to a new VillagerProfession is done by mapping the level int to the trade set key in tradeSetsByLevel:
public static final VillagerProfession EXAMPLE = Registry.register(
BuiltInRegistries.VILLAGER_PROFESSION,
Identifier.fromNamespaceAndPath("examplemod", "example_profession"),
new VillagerProfession(
Component.literal(""),
p -> true,
p -> true,
ImmutableSet.of(),
ImmutableSet.of(),
null,
// A map of profession level to trade set keys
Int2ObjectMap.ofEntries(
Int2ObjectMap.entry(
// The profession level
1,
// The trade set id
ResourceKey.create(Registries.TRADE_SET, Identifier.fromNamespaceAndPath("examplemod", "example_profession/level_1"))
)
)
)
);
Item Listing Conversions
With all this in mind, we can now convert item listings to their new data-generated villager trades.
Emeralds <-> Items
For the following trades:
public static final VillagerTrades.ItemListing ITEM_TO_EMERALD = new VillagerTrades.EmeraldForItems(
// The item the trader wants.
Items.WHEAT,
// The number of items the trader wants.
20,
// The maximum number of times the trade can be made
// before restock.
16,
// The amount of experience given for the trade.
2,
// The number of emeralds given in return.
1
);
public static final VillagerTrades.ItemListing EMERALD_TO_ITEM = new VillagerTrades.ItemsForEmeralds(
// The item the trader will give in return.
Items.BREAD,
// The number of emeralds the trader wants.
1,
// The number of items the trader will give.
6,
// The maximum number of times the trade can be made
// before restock.
16,
// The amount of experience given for the trade.
1,
// The price multiplier to apply to the offer, given
// reputation and demand.
0.05f
);
Their equivalent would be:
// For some villager trade 'examplemod:item_to_emerald'
// JSON at 'data/examplemod/villager_trade/item_to_emerald.json'
{
"gives": {
// The number of emeralds given in return.
"count": 1,
"id": "minecraft:emerald"
},
// The maximum number of times the trade can be made
// before restock.
"max_uses": 16,
// The price multiplier to apply to the offer, given
// reputation and demand.
// `EmeraldForItems` hardcoded this to 0.05
"reputation_discount": 0.05,
"wants": {
// The number of items the trader wants.
"count": 20,
// The item the trader wants.
"id": "minecraft:wheat"
},
// The amount of experience given for the trade.
"xp": 2
}
// For some villager trade 'examplemod:emerald_to_item'
// JSON at 'data/examplemod/villager_trade/emerald_to_item.json'
{
"gives": {
// The number of items the trader will give.
"count": 6,
// The item the trader will give in return.
"id": "minecraft:bread"
},
// The maximum number of times the trade can be made
// before restock.
"max_uses": 16,
// The price multiplier to apply to the offer, given
// reputation and demand.
"reputation_discount": 0.05,
"wants": {
"id": "minecraft:emerald",
// The number of emeralds the trader wants.
"count": 1
},
// The amount of experience given for the trade.
"xp": 1
}
Items and Emeralds -> Items
For the following trade:
public static final VillagerTrades.ItemListing ITEM_EMERALD_TO_ITEM = new VillagerTrades.ItemsAndEmeraldsToItems(
// The item the trader wants.
Items.COD,
// The number of items the trader wants.
6,
// The number of emeralds the trader additionally wants.
1,
// The item the trader will give in return.
Items.COOKED_COD,
// The number of items the trader will give.
6,
// The maximum number of times the trade can be made
// before restock.
16,
// The amount of experience given for the trade.
1,
// The price multiplier to apply to the offer, given
// reputation and demand.
0.05f
);
The equivalent would be:
// For some villager trade 'examplemod:item_emerald_to_item'
// JSON at 'data/examplemod/villager_trade/item_emerald_to_item.json'
{
// The emeralds the trader additionally wants.
"additional_wants": {
"id": "minecraft:emerald",
},
"gives": {
// The number of items the trader will give.
"count": 6,
// The item the trader will give in return.
"id": "minecraft:cooked_cod"
},
// The maximum number of times the trade can be made
// before restock.
"max_uses": 16,
// The price multiplier to apply to the offer, given
// reputation and demand.
"reputation_discount": 0.05,
"wants": {
// The number of items the trader wants.
"count": 6,
// The item the trader wants.
"id": "minecraft:cod"
},
// The amount of experience given for the trade.
"xp": 1
}
Emeralds -> Dyed Armor
For the following trade:
public static final VillagerTrades.ItemListing EMERALD_TO_DYED_ARMOR = new VillagerTrades.DyedArmorForEmeralds(
// The item the trader will give in return and dye.
Items.LEATHER_HELMET,
// The number of emeralds the trader wants.
5,
// The maximum number of times the trade can be made
// before restock.
12,
// The amount of experience given for the trade.
5
);
The equivalent would be:
// For some villager trade 'examplemod:emerald_to_dyed_armor'
// JSON at 'data/examplemod/villager_trade/emerald_to_dyed_armor.json'
{
"given_item_modifiers": [
{
// Sets the random dye(s) on the armor.
"function": "minecraft:set_random_dyes",
"number_of_dyes": {
"type": "minecraft:sum",
"summands": [
1.0,
{
"type": "minecraft:binomial",
"n": 2.0,
"p": 0.75
}
]
}
},
{
// Checks that the dye was successfully applied
// to the item.
"function": "minecraft:filtered",
"item_filter": {
"items": "minecraft:leather_helmet",
"predicates": {
"minecraft:dyed_color": {}
}
},
// If it fails, discards the offer.
"on_fail": {
"function": "minecraft:discard"
}
}
],
"gives": {
"count": 1,
// The item the trader will give in return and dye.
"id": "minecraft:leather_helmet"
},
// The maximum number of times the trade can be made
// before restock.
"max_uses": 12,
// The price multiplier to apply to the offer, given
// reputation and demand.
"reputation_discount": 0.05,
"wants": {
// The number of emeralds the trader wants.
"count": 5,
"id": "minecraft:emerald"
},
// The amount of experience given for the trade.
"xp": 5
}
Emeralds -> Enchanted Item
For the following trade:
public static final VillagerTrades.ItemListing EMERALD_TO_ENCHANTED_BOOK = new VillagerTrades.EnchantBookForEmeralds(
// The amount of experience given for the trade.
30,
// The minimum level used when selecting the stored enchantments on the book.
3,
// The maximum level used when selecting the stored enchantments on the book.
3,
// A tag containing the list of available enchantments to select from for the book.
EnchantmentTags.TRADES_DESERT_SPECIAL
);
public static final VillagerTrades.ItemListing EMERALD_TO_ENCHANTED_ITEM = new VillagerTrades.EnchantedItemForEmeralds(
// The item the trader will give in return and try to enchant.
Items.FISHING_ROD,
// The base number of emeralds the trader wants.
3,
// The maximum number of times the trade can be made
// before restock.
3,
// The amount of experience given for the trade.
10,
// The price multiplier to apply to the offer, given
// reputation and demand.
0.2f
);
The equivalent would be:
// For some villager trade 'examplemod:emerald_to_enchanted_book'
// JSON at 'data/examplemod/villager_trade/emerald_to_enchanted_book.json'
{
// The trader expects a book to write the enchantment to.
"additional_wants": {
"id": "minecraft:book"
},
// Trade cost for emeralds increased when in the double trade price
// tag.
"double_trade_price_enchantments": "#minecraft:double_trade_price",
"given_item_modifiers": [
{
"function": "minecraft:enchant_with_levels",
"include_additional_cost_component": true,
"levels": {
"type": "minecraft:uniform",
// The minimum level used when selecting the stored enchantments on the book.
"min": 3,
// The maximum level used when selecting the stored enchantments on the book.
"max": 3
},
// The list of available enchantments to select from for the book.
"options": [
"minecraft:efficiency"
]
},
{
// Make sure the enchantment was added successfully with the given level.
"function": "minecraft:filtered",
"item_filter": {
"items": "minecraft:enchanted_book",
"predicates": {
"minecraft:stored_enchantments": [
{
"levels": {
// The minimum level used when selecting the stored enchantments on the book.
"min": 3,
// The maximum level used when selecting the stored enchantments on the book.
"max": 3
}
}
]
}
},
// Discard on failure
"on_fail": {
"function": "minecraft:discard"
}
}
],
// The trader gives the enchanted book.
"gives": {
"count": 1,
"id": "minecraft:enchanted_book"
},
// The maximum number of times the trade can be made
// before restock was hardcoded to 12.
"max_uses": 12,
// The price multiplier to apply to the offer, given
// reputation and demand, hardcoded to 0.2.
"reputation_discount": 0.2,
"wants": {
"count": {
"type": "minecraft:sum",
"summands": [
// A hardcoded computation based on the min and max
// level of the enchantment.
11.0,
{
"type": "minecraft:uniform",
"max": 35.0,
"min": 0.0
}
]
},
"id": "minecraft:emerald"
},
// The amount of experience given for the trade.
"xp": 30
}
// For some villager trade 'examplemod:emerald_to_enchanted_item'
// JSON at 'data/examplemod/villager_trade/emerald_to_enchanted_item.json'
{
"given_item_modifiers": [
{
// Applies the enchantment to the given equipment.
"function": "minecraft:enchant_with_levels",
"include_additional_cost_component": true,
"levels": {
"type": "minecraft:uniform",
"max": 20,
"min": 5
},
"options": "#minecraft:on_traded_equipment"
},
{
// Checks to make sure the enchantment was applied.
"function": "minecraft:filtered",
"item_filter": {
"items": "minecraft:fishing_rod",
"predicates": {
"minecraft:enchantments": [
{}
]
}
},
// On fail, give nothing.
"on_fail": {
"function": "minecraft:discard"
}
}
],
"gives": {
"count": 1,
// The item the trader will give in return and try to enchant.
"id": "minecraft:fishing_rod"
},
// The maximum number of times the trade can be made
// before restock.
"max_uses": 3,
// The price multiplier to apply to the offer, given
// reputation and demand.
"reputation_discount": 0.2,
"wants": {
"count": {
"type": "minecraft:sum",
"summands": [
// The base number of emeralds the trader wants.
3,
{
// The variation based on the enchantment level.
// Originally, this would be the value used in the
// item function, but since they are now isolated,
// these values could differ.
"type": "minecraft:uniform",
"max": 20,
"min": 5
}
]
},
"id": "minecraft:emerald"
},
// The amount of experience given for the trade.
"xp": 10
}
Items and Emeralds -> Potion Effect Item
For the following trade:
public static final VillagerTrades.ItemListing EMERALD_TO_SUSPICIOUS_STEW = new VillagerTrades.SuspiciousStewForEmerald(
// The effect applied by the suspicious stew.
MobEffects.NIGHT_VISION,
// The number of ticks the effect should be active for.
100,
// The amount of experience given for the trade.
15
);
public static final VillagerTrades.ItemListing ITEM_EMERALD_TO_TIPPED_ARROW = new VillagerTrades.TippedArrowForItemsAndEmeralds(
// The item the trader additionally wants.
Items.ARROW,
// The number of items the trader additionally wants.
5,
// The item the trader will give in return.
Items.TIPPED_ARROW,
// The number of items the trader will give.
5,
// The number of emeralds the trader wants.
2,
// The maximum number of times the trade can be made
// before restock.
12,
// The amount of experience given for the trade.
30
);
The equivalent would be:
// For some villager trade 'examplemod:emerald_to_suspicious_stew'
// JSON at 'data/examplemod/villager_trade/emerald_to_suspicious_stew.json'
{
"given_item_modifiers": [
{
"effects": [
{
// The effect applied by the suspicious stew.
"type": "minecraft:night_vision",
// The number of ticks the effect should be active for.
"duration": 100
}
// Vanilla merges all suspicious stew offers
// into one since this function picks one
// stew effect at random.
],
"function": "minecraft:set_stew_effect"
}
],
"gives": {
"count": 1,
"id": "minecraft:suspicious_stew"
},
// The maximum number of times the trade can be made
// before restock, hardcoded to 12.
"max_uses": 12,
// The price multiplier to apply to the offer, given
// reputation and demand, hardcoded to 0.05.
"reputation_discount": 0.05,
"wants": {
"id": "minecraft:emerald"
},
// The amount of experience given for the trade.
"xp": 15
}
// For some villager trade 'examplemod:item_emerald_to_tipped_arrow'
// JSON at 'data/examplemod/villager_trade/item_emerald_to_tipped_arrow.json'
{
"additional_wants": {
// The number of items the trader additionally wants.
"count": 5,
// The item the trader additionally wants.
"id": "minecraft:arrow"
},
"given_item_modifiers": [
{
// Applies a random potion effect from the tradable potions.
// Original implementation just picked any potion at random.
"function": "minecraft:set_random_potion",
"options": "#minecraft:tradeable"
}
],
"gives": {
// The number of items the trader will give.
"count": 5,
// The item the trader will give in return.
"id": "minecraft:tipped_arrow"
},
// The maximum number of times the trade can be made
// before restock.
"max_uses": 12,
// The price multiplier to apply to the offer, given
// reputation and demand, hardcoded to 0.05.
"reputation_discount": 0.05,
"wants": {
// The number of emeralds the trader wants.
"count": 2,
"id": "minecraft:emerald"
},
// The amount of experience given for the trade.
"xp": 30
}
Emeralds -> Treasure Map
For the following trade:
public static final VillagerTrades.ItemListing EMERALD_TO_TREASURE_MAP = new VillagerTrades.TreasureMapForEmeralds(
// The number of emeralds the trader wants.
8,
// A tag containing a list of treasure structures to find the nearest of.
StructureTags.ON_TAIGA_VILLAGE_MAPS,
// The translation key of the map name.
"filled_map.village_taiga",
// The icon used to decorate the treasure location found on the map.
MapDecorationTypes.TAIGA_VILLAGE,
// The maximum number of times the trade can be made
// before restock.
12,
// The amount of experience given for the trade.
5
);
The equivalent would be:
// For some villager trade 'examplemod:emerald_to_treasure_map'
// JSON at 'data/examplemod/villager_trade/emerald_to_treasure_map.json'
{
"additional_wants": {
// An item the trader additionally wants, hardcoded to compass.
"id": "minecraft:compass"
},
"given_item_modifiers": [
{
// Finds a treasure structure to display on the map.
// The icon used to decorate the treasure location found on the map.
"decoration": "minecraft:village_taiga",
// A tag containing a list of treasure structures to find the nearest of.
"destination": "minecraft:on_taiga_village_maps",
"function": "minecraft:exploration_map",
"search_radius": 100
},
{
// Sets the name of the map.
"function": "minecraft:set_name",
"name": {
// The translation key of the map name.
"translate": "filled_map.village_taiga"
},
"target": "item_name"
},
{
// Check to make sure a structure was found.
"function": "minecraft:filtered",
"item_filter": {
"items": "minecraft:filled_map",
"predicates": {
"minecraft:map_id": {}
}
},
"on_fail": {
"function": "minecraft:discard"
}
}
],
"gives": {
"count": 1,
// Returns a map filled with the treasure location.
"id": "minecraft:map"
},
// The maximum number of times the trade can be made
// before restock.
"max_uses": 12,
// The price multiplier to apply to the offer, given
// reputation and demand, hardcoded to 0.05.
"reputation_discount": 0.05,
"wants": {
// The number of emeralds the trader wants.
"count": 8,
"id": "minecraft:emerald"
},
// The amount of experience given for the trade.
"xp": 5
}
Villager Variants
Some traders would provide different options depending on the villager type it was as one giant map of item listings. Now, each type has its own individual villager trade, using a merchant_predicate to check whether the offer can be made to the specific villager type:
// For some villager trade 'examplemod:villager_type_item'
// JSON at 'data/examplemod/villager_trade/villager_type_item.json'
{
// ...
"merchant_predicate": {
// Check the entity.
"condition": "minecraft:entity_properties",
"entity": "this",
"predicate": {
"predicates": {
// Villager type must be desert for this trade to be chosen.
"minecraft:villager/variant": "minecraft:desert"
}
}
},
// ...
}
net.minecraft.core.registries.RegistriesTRADE_SET- A key to the registry holding a list of trades.VILLAGER_TRADE- A key to the registry holding a single trade.
net.minecraft.tags.VillagerTradeTags- Tags for villager trades.net.minecraft.world.entity.npc.villagerAbstractVillager#addOffersFromItemListings->addOffersFromTradeSet, taking in a key for the trade set rather than the$ItemListings and number of offers; not one-to-oneVillagerProfessionnow takes in a map of trader level toTradeSetgetTrades- Returns the trades set key for the given level.
VillagerTradeshas been split into many different classes and implementationsTRADES,EXPERIMENTAL_TRADES,WANDERING_TRADER_TRADESis now represented by theVillagerProfession#tradeSetsByLevel- As they are now datapack entries, they are stored in their respective datapacks
TRADES,EXPERIMENTAL_TRADESare represented bydata/minecraft/trade_set/<profession>/*WANDERING_TRADER_TRADESare represented bydata/minecraft/trade_set/wandering_trader/*
$DyedArmorForEmeralds->VillagerTrades#dyedItem,addRandomDye; not one-to-one$EmeraldForItems->VillagerTrade, not one-to-one$EmeraldsForVillagerTypeItem->VillagerTrades#registerBoatTrades, see usage, not one-to-one$EnchantBookForEmeralds->VillagerTrades#enchantedBook, not one-to-one$EnchantedItemForEmeralds->VillagerTrades#enchantedItem, not one-to-one$ItemListing->VillagerTrade$ItemsAndEmeraldsToItems->VillagerTradewithadditionalWants$ItemsForEmeralds->VillagerTrade, not one-to-one$SuspiciousStewForEmerald->VillagerTradewithSetStewEffectFunction$TippedArrowForItemsAndEmeralds->VillagerTradewithSetRandomPotionFunction$TreasureMapForEmeralds->VillagerTrades$VillagerExplorerMapEntry, see usage, not one-to-one$TypeSpecificTrade->VillagerTrades#villagerTypeRestriction,villagerTypeHolderSet; not one-to-one
net.minecraft.world.item.enchantment.providers.TradeRebalanceEnchantmentProvidersinterface is removed- Replaced by
TradeRebalanceVillagerTrades,TradeRebalanceRegistries
- Replaced by
net.minecraft.world.item.tradingTradeCost- AnItemStackthat is being traded to some trader.TradeRebalanceVillagerTrades- All trades part of the trade rebalance datapack.TradeSet- A set of trades that can be performed by a trader at some level.TradeSets- All vanilla trades sets for some trader at some level.VillagerTrade- A trade between the trader and the player.VillagerTrades- All vanilla trades.
net.minecraft.world.level.storage.loot.parameters.LootContextParamSets#VILLAGER_TRADE- A loot context when a villager trade is taking place, containing the trade origin and the trading entity.
Level#random field now protected
The Level#random field is now protected instead of public. As such, uses should transition to using the public getRandom method.
// For some Level level
RandomSource random = level.getRandom();
net.minecraft.world.level.Level#randomfield is nowprotectedinstead ofpublic- Use
getRandommethod instead
- Use
Data Component Initializers
Data components have begun their transition from being moved off the raw object and onto the Holder itself. This is to properly handle objects that are not available during construction, such as datapack registry objects for items. Currently, this is only implemented for Items, but the system allows for any registry object, given its wrapped-holder, to store some defined data components.
Data components are attached to their holders through the DataComponentInitializers. During object construction, DataComponentInitializers#add is called, providing the ResourceKey identifier of the registry object, along with a DataComponentInitializers$Initializer. The initializer takes in three parameters: the builder for the component map, the full registries HolderLookup$Provider, and the key passed to DataComponentInitializers#add. The initializer functions like a consumer, also allowing for additional initializers to be chained via $Initializer#andThen or to easily add a component via $Initializer#add.
// For some custom registry object
public ExampleObject(ResourceKey<ExampleObject> id) {
// Register the data component initializer
BuiltInRegistries.DATA_COMPONENT_INITIALIZERS.add(
// The identifier for the registry object
id,
// The initializer function, taking in a component builder,
// the registries context, and the id
(components, context, key) -> components
.set(DataComponents.MAX_DAMAGE, 1)
.set(DataComponents.DAMAGE_TYPE, context.getOrThrow(DamageTypes.SPEAR))
);
}
From there, the data components are initialized or reinitialized whenever ReloadableServerResources#loadResources is called (on datapack reload). The datapack objects are loaded first, then the components are set on the Holder$References. From there, the components can be gathered via Holder#components.
// For some Holder<ExampleObject> EXAMPLE_HOLDER
DataComponentMap components = EXAMPLE_HOLDER.components();
Items
Since components are now initialized during resource reload, Item$Properties provides two methods to properly delay component initialization until such data components are loaded: delayedComponent and delayedHolderComponent. delayedComponent takes in the component type and a function that takes in the HolderLookup$Provider and returns the component value. delayedHolderCOmponent delegates to delayedComponent, taking in a ResourceKey and setting the registry object as the component value.
public static final Item EXAMPLE_ITEM = new Item(
new Item.Properties()
.delayedComponent(
// The component type whose construction
// should be lazily initialized.
DataComponents.JUKEBOX_PLAYABLE,
// A function that takes in the registries
// and returns the component value.
context -> new JukeboxPlayable(context.getOrThrow(
JukeboxSongs.THIRTEEN
))
)
.delayedHolderComponent(
// The component type which has a
// holder value type.
DataComponents.DAMAGE_TYPE
// The resource key for a registry
// object of the associated holder
// generic type.
DamageTypes.SPEAR
)
// ...
);
Recipes
Since data components now hold the true values from being lazily initialized after resource reload, Recipe#assemble no longer takes in the HolderLookup$Provider. Instead, it assumes that the recipe has all the required data stored passed into the recipe, either on a stack or directly.
net.minecraft.coreHolderareComponentsBound- Whether the components have been bound to the holder.components- The components of the object stored on the holder.direct,$Directnow can take in theDataComponentMap$Reference#bindComponents- Stores the components on the holder reference.
Registry#componentLookup- Gets the lookup of component to holders.WritableRegistry#bindTag->bindTags, now taking in a map of keys to holder lists instead of one mapping
net.minecraft.core.componentDataComponentInitializers- A class that handles initializing the data components for component-attached objects.DataComponentLookup- A lookup that maps the component type to the holders that use it.DataComponentMap$Builder#addValidator- Adds a validator for the components on the object.DataComponentPatchgetnow takes in aDataComponentGetterand returns the raw component value$Builder#setnow has an overload that takes in an iterable ofTypedDataComponents
DataComponentsDAMAGE_TYPEnow is a holder-wrappedDamageTypeinstead ofEitherHolder-wrappedPROVIDES_TRIM_MATERIALnow is a holder-wrappedTrimMaterialinstead ofProvidesTrimMaterialCHICKEN_VARIANTnow is a holder-wrappedChickenVariantinstead ofEitherHolder-wrappedZOMBIE_NAUTILUS_VARIANTnow is a holder-wrappedZombieNautilusVariantinstead ofEitherHolder-wrappedPROVIDES_BANNER_PATTERNSis now aHolderSetinstead of aTagKey
net.minecraft.core.registriesBuiltInRegistries#DATA_COMPONENT_INITIALIZERS- A list of data components attached to registry entries.Registries#componentsDirPath- The path directory for the components in a registry.
net.minecraft.data.PackOutput#createRegistryComponentPathProvider- The path provider for the components registry report.net.minecraft.data.info.ItemListReport->RegistryComponentsReport, not one-to-onenet.minecraft.resourcesNetworkRegistryLoadTask- A load task that handles registering registry objects and tags from the network, or else from a resource.RegistryDataLoader$PendingRegistration->RegistryLoadTask$PendingRegistration$RegistryDatanow takes in aRegistryValidatorinstead of aboolean$RegistryLoadTask->RegistryLoadTask, not one-to-one
RegistryValidator- An interface that validates the entries in a registry, storing all errors in a map.ResourceManagerRegistryLoadTask- A load task that handles registering registry objects and tags from the local resource manager.
net.minecraft.server.ReloadableServerResources#updateStaticRegistryTags->updateComponentsAndStaticRegistryTags, not one-to-onenet.minecraft.world.itemEitherHolderclass is removedItemCODEC_WITH_BOUND_COMPONENTS- An item codec that validates that the components are bound.$PropertiesdelayedComponent- Sets the component lazily, providing theHolderLookup$Providerto get any dynamic elements.delayedHolderComponent- Sets the component lazily for some holder-wrapped registry object.
ItemStack#validateComponentsis nowprivatefrompublicJukeboxPlayablenow holds a holder-wrappedJukeboxSonginstead of anEitherHolder-wrapped variantJukeboxSong#fromStackno longer takes in theHolderLookup$ProviderSpawnEggItemspawnEntityis nowstaticbyIdnow returns an optional holder-wrappedIteminstead of aSpawnEggItemeggsis removedgetTypeis nowstaticspawnOffspringFromSpawnEggis nowstatic
net.minecraft.world.item.componentBlocksAttacksnow holds an optional holder set-wrappedDamageTypeinstead of aTagKeyDamageResistantnow holds a holder setDamageTypeinstead of aTagKeyInstrumentComponentnow holds a holder-wrappedInstrumentinstead of anEitherHolder-wrapped variantunwrapis removed
ProvidesTrimMaterialnow holds a holder-wrappedTrimMaterialinstead of anEitherHolder-wrapped variant
net.minecraft.world.item.craftingRecipe#assembleno longer takes in theHolderLookup$ProviderSmithingTrimRecipe#applyTrimno longer takes in theHolderLookup$Provider
net.minecraft.world.item.equipment.trim.TrimMaterials#getFromIngredientis removednet.minecraft.world.level.storage.loot.functions.SetInstrumentFunction,#setInstrumentOptionsnow takes in a holder set-wrappedInstrumentinstead of aTagKeynet.minecraft.world.timeline.Timeline#validateRegistry- Validates that each time marker was only defined once.
Item Instances and Stack Templates
ItemStacks now have an immutable instance known as an ItemStackTemplate. Similar to the ItemStack, it contains the holder-wrapped Item, the number of items it represents, and a DataComponentPatch of the components to apply to the stack. The template can be transformed to a stack via create, or apply if adding additional data components. An ItemStack can likewise be turned into a template via ItemStackTemplate#fromNonEmptyStack. Templates are now used in place of ItemStacks were immutability is required (e.g., advancements, recipes, etc.). They provide a regular CODEC, a MAP_CODEC, and a STREAM_CODEC for network communication.
ItemStackTemplate apple = new ItemStackTemplate(
// The item of the stack
Items.APPLE.builtInRegistryHolder(),
// The number of items held
5,
// The components applied to the stack
DataComponentPatch.builder()
.set(DataComponents.ITEM_NAME, Component.literal("Apple?"))
.build()
);
// Turn the template into a stack
ItemStack stack = apple.create();
// Creating a template from a non-empty stack
ItemStackTemplate fromStack = ItemStackTemplate.fromNonEmptyStack(stack);
To help standardize accessing the general components between the two, both the template and the stack implement ItemInstance, which provides access to the standard holder method checks, the count, and the DataComponentGetter. The common interface also means that if it doesn’t matter whether the stack is mutable or not, then the ItemInstance can be used as the type.
// Both are item instances
ItemInstance stack = new ItemStack(Items.APPLE);
ItemInstance template = new ItemStackTemplate(Items.APPLE);
// Get the holder or check something
Holder<Item> item = stack.typeHolder();
template.is(Items.APPLE);
// Get the number of items in the stack or template
int stackCount = stack.count();
int templateCount = template.count();
// Get the component values
Identifier stackModel = stack.get(DataComponents.ITEM_MODEL);
Identifier templateModel = template.get(DataComponents.ITEM_MODEL);
Recipe Builders
Due to the addition of ItemStackTemplates, RecipeBuilders have changed slightly in their implementation. First, the builder no longer stores an Item for the result, instead defining the defaultId as the resource key recipe. As such, this allows for a more clear method of defining custom recipes that do not export an Item.
Of course, the change to this new format just has defaultId return RecipeBuilder#getDefaultRecipeId with the ItemInstance (either a stack or template), like so:
public class ExampleRecipeBuilder implements RecipeBuilder {
// The result of the recipe
private final ItemStackTemplate result;
public ExampleRecipeBuilder(ItemStackTemplate result) {
this.result = result;
}
@Override
public ResourceKey<Recipe<?>> defaultId() {
// Get the default recipe id from the result
return RecipeBuilder.getDefaultRecipeId(this.result);
}
// Implement everything else below
// ...
}
net.minecraft.advancementsAdvancement$Builder#displaynow takes in anItemStackTemplateinstead of anItemStackDisplayInfonow takes in anItemStackTemplateinstead of anItemStackgetIconnow returns anItemStackTemplateinstead of anItemStack
net.minecraft.advancements.criterionAnyBlockInteractionTrigger#triggernow takes in anItemInstanceinstead of anItemStackItemPredicatenow implements a predicate ofItemInstanceinstead ofItemStackItemUsedOnLocationTrigger#triggernow takes in anItemInstanceinstead of anItemStack
net.minecraft.client.particle.BreakingItemParticle$ItemParticleProvider#getSpritenow takes in anItemStackTemplateinstead of anItemStacknet.minecraft.commands.arguments.itemItemInputis now a recordserializeis removedcreateItemStackno longer takes in thebooleanto check the size
ItemParser#parsenow returns anItemResultinstead of anItemParser$ItemResult$ItemResultmerged intoItemInput
net.minecraft.core.component.predicatesBundlePredicatenow deals with an iterable ofItemInstances rather thanItemStacksContainerPredicatenow deals with an iterable ofItemInstances rather thanItemStacks
net.minecraft.core.particles.ItemParticleOptionnow takes in anItemStackTemplateinstead of anItemStack- There is also an overload for a regular
Item getItemnow returns anItemStackTemplateinstead of anItemStack
- There is also an overload for a regular
net.minecraft.data.recipesRecipeBuildergetResultis removeddefaultId- The default identifiers for the recipe made with this builder.getDefaultRecipeIdnow takes in anItemInstanceinstead of anItemLike
RecipeProvideroreSmelting,oreBlastingnow take in aCookingBookCategoryoreCookingno longer takes in theRecipeSerializerand now takes in aCookingBookCategorycookRecipes,simpleCookingRecipeno longer take in theRecipeSerializershapelessnow takes in anItemStackTemplateinstead of anItemStack
ShapedRecipeBuildernow takes in anItemStackTemplatefor the result, with theItemLikemoved to an overload- Both constructors are
private
- Both constructors are
ShapelessRecipeBuildernow takes in anItemStackTemplatefor the result instead of anItemStackSimpleCookingRecipeBuildernow takes in anItemStackTemplatefor the result, with theItemLikemoved to an overloadgenericno longer takes in theRecipeSerializerand now takes in aCookingBookCategoryblasting,smeltingnow take in aCookingBookCategory
SingleItemRecipeBuildernow takes in anItemStackTemplatefor the result, with theItemLikemoved to an overload- The
ItemStackTemplateconstructor is madeprivate
- The
SmithingTransformRecipeBuildernow takes in anItemStackTemplatefor the result instead of anItemTransmuteRecipeBuildernow takes in anItemStackTemplatefor the result instead of aHolder<Item>- The constructor is
private transmutenow has an overload that takes in theItemStackTemplatefor the resultaddMaterialCountToOutput,setMaterialCount- Handles the size of the result stack based on the number of materials used.
- The constructor is
net.minecraft.network.chat.HoverEvent$ShowItemnow takes in anItemStackTemplateinstead of anItemStacknet.minecraft.server.dialog.body.ItemBodynow takes in anItemStackTemplateinstead of anItemStacknet.minecraft.world.entity.LivingEntitydropFromEntityInteractLootTablenow takes in anItemInstanceinstead of anItemStackfor the tooldropFromShearingLootTablenow takes in anItemInstanceinstead of anItemStackfor the tool
net.minecraft.world.itemBundleItem#getSelectedItemStack->getSelectedItem, now returning anItemStackTemplateinstead of anItemStackItemgetCraftingRemaindernow returns anItemStackTemplateinstead of anItemStack$Properties#craftRemaindernow has an overload that takes in theItemStackTemplate
ItemInstance- A typed item instance that can query the item, the size, and its components.ItemStacknow implementsItemInstanceSINGLE_ITEM_CODEC,STRICT_CODEC,STRING_SINGLE_ITEM_CODEC,SIMPLE_ITEM_CODECare removedgetMaxStackSize->ItemInstance#getMaxStackSize
ItemStackTemplate- A record containing the immutable components of a stack: the item, count, and components.
net.minecraft.world.item.componentBundleContentsnow takes in a list ofItemStackTemplates instead ofItemStacksitemsnow returns a list ofItemStackTemplates instead of an iterable ofItemStacksitemsCopyis removedgetSelectedItem- Returns the stack template of the selected item, ornullif no item is selected.
ChargedProjectileis now a record- The constructor takes in a list of
ItemStackTemplates instead ofItemStacks of->ofNonEmptygetItems->itemCopies
- The constructor takes in a list of
ItemContainerContentsstream->allItemsCopyStreamnonEmptyStream->nonEmptyItemCopyStreamnonEmptyItems,nonEmptyItemsCopy->nonEmptyItems, now returning an iterable ofItemStackTemplates instead ofItemStacks
UseRemaindernow takes in anItemStackTemplateinstead of anItemStack
net.minecraft.world.item.craftingAbstractCookingRecipenow takes in anItemStackTemplateinstead of anItemStackfor the result$Factory#createnow takes in anItemStackTemplateinstead of anItemStackfor the result
BlastingRecipenow takes in anItemStackTemplateinstead of anItemStackfor the resultCampfireCookingRecipenow takes in anItemStackTemplateinstead of anItemStackfor the resultShapedRecipenow takes in anItemStackTemplateinstead of anItemStackfor the resultShapelessRecipenow takes in anItemStackTemplateinstead of anItemStackfor the resultSingleItemRecipenow takes in anItemStackTemplateinstead of anItemStackfor the resultresultnow returns anItemStackTemplateinstead of anItemStack$Factory#createnow takes in anItemStackTemplateinstead of anItemStackfor the result
SmeltingRecipenow takes in anItemStackTemplateinstead of anItemStackfor the resultSmithingTransformRecipenow takes in anItemStackTemplateinstead of anItemStackfor the resultSmokingRecipenow takes in anItemStackTemplateinstead of anItemStackfor the resultStonecutterRecipenow takes in anItemStackTemplateinstead of anItemStackfor the resultTransmuteRecipenow takes in anItemStackTemplateinstead of anItemStackfor the resultTransmuteResult->ItemStackTemplate, not one-to-oneisResultUnchangedis removedapply->TransmuteRecipe#createWithOriginalComponents, not one-to-one
net.minecraft.world.item.crafting.display.SlotDisplay$ItemStackSlotDisplaynow takes in anItemStackTemplateinstead of anItemStacknet.minecraft.world.item.enchantment.EnchantmentHelper#getItemEnchantmentLevelnow takes in anItemInstanceinstead of anItemStacknet.minecraft.world.level.block.BlockdropFromBlockInteractLootTablenow takes in anItemInstanceinstead of anItemStackgetDropsnow takes in anItemInstanceinstead of anItemStack
net.minecraft.world.level.block.entity.DecoratedPotBlockEntity#createdDecoratedPotItem->createdDecoratedPotInstancecreateDecoratedPotTemplatecreates theItemStackTemplateinstead of theItemStack
net.minecraft.world.level.storage.lootLootContext$ItemStackTargetnow implements anItemInstancegeneric for the argument getter instead of theItemStackLootContextArg$ArgCodecBuilder#anyItemStacknow requires a function taking in anItemInstancecontext key instead of anItemStackcontext key
net.minecraft.world.level.storage.loot.parameters.LootContextParams#TOOLis now anItemInstancecontext key instead of anItemStackcontext key
Serializer Records and Recipe Info
Recipes have been slightly reworked in their implementation. First, RecipeSerializer is now a record taking in the MapCodec and StreamCodec used to serialize and deserialize the recipe. As such, Serializer classes have been removed in their entirety, replaced with providing the codecs to the record during registration:
// Assume some ExampleRecipe implements Recipe
// We'll say there's also only one INSTANCE
public static final RecipeSerializer<ExampleRecipe> EXAMPLE_RECIPE = new RecipeSerializer<>(
// The map codec for reading the recipe to/from disk.
MapCodec.unit(INSTANCE),
// The stream codec for reading the recipe to/from the network.
StreamCodec.unit(INSTANCE)
);
Second, some common data regarding the recipe settings and book information have been sectioned into separate objects. These objects are passed into the recipe as part of the constructor and used to more cleanly handle similar implementations across all recipes.
Vanilla provides four of these common object classes, split into two separate categories. Recipe$CommonInfo is used for general recipe settings. Meanwhile, Recipe$BookInfo is used for recipe book information, with CraftingRecipe$CraftingBookInfo for crafting recipes, and AbstractCookingRecipe$CookingBookInfo for cooking recipes (e.g., smelting, blasting, etc.). The common object classes provide methods for constructing the codecs as required, which can then be passed into the relevant recipe codec.
These classes are typically passed through the Recipe subclasses, used as boilerplate to implement abstract methods. None of the data in these objects are directly available outside the implementation itself, only through the methods defined in the Recipe interface. Because of this, classes like NormalCraftingRecipe, CustomRecipe, SimpleSmithingRecipe, and SingleItemRecipe, and AbstractCookingRecipe can be used to create a new recipe implementation by implementing a few methods.
Note that these common info classes are a design philosophy, which you can choose to implement if desired. It’s only when building off existing recipe subtypes that you are required to make use of them.
net.minecraft.data.recipesCustomCraftingRecipeBuilder- A recipe builder that creates an arbitrary crafting recipe from some common and crafting book information.RecipeBuilderdetermineBookCategory->determineCraftingBookCategorycreateCraftingCommonInfo- Creates the common recipe info.createCraftingBookInfo- Creates the crafting book info.
RecipeUnlockAdvancementBuilder- An advancement builder for unlocking a recipe.SpecialRecipeBuilder,specialnow takes in a suppliedRecipeinstead of a function ofCraftingBookCategorytoRecipeunlockedBy- The criteria required to unlock the recipe advancement.
net.minecraft.world.item.craftingAbstractCookingRecipenow takes in theRecipe$CommonInfoand$CookingBookInfoinstead of the group andCookingBookCategory$Factory#createnow takes in theRecipe$CommonInfoand$CookingBookInfoinstead of the group andCookingBookCategory$Serializerreplaced bycookingMapCodec,cookingStreamCodec$CookingBookInfo- A record containing the common cooking information for the recipe book.
BannerDuplicateRecipenow takes in the bannerIngredientand theItemStackTemplateresult instead of theCraftingBookCategoryMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
BlastingRecipenow takes in theRecipe$CommonInfoand$AbstractCookingRecipeCookingBookInfoinstead of the group andCookingBookCategoryMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
BookCloningRecipenow takes in theIngredientsource and material, theMinMaxBounds$Ints defining the generations that can be copied, and theItemStackTemplateresult instead of theCraftingBookCategoryALLOWED_BOOK_GENERATION_RANGES,DEFAULT_BOOK_GENERATION_RANGES- Ranges for the book generation cloning.MAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
CampfireCookingRecipenow takes in theRecipe$CommonInfoandAbstractCookingRecipe$CookingBookInfoinstead of the group andCookingBookCategoryMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
CraftingRecipe$CraftingBookInfo- A record containing the common crafting information for the recipe book.CustomRecipeno longer takes in anything to its constructor$Serializeris removed, replaced by its implementation’s codecs
DecoratedPotRecipenow takes in theIngredientpatterns for each side along with theItemStackTemplateresult instead of theCraftingBookCategoryMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
DyeRecipenow takes in theRecipe$CommonInfoandCraftingRecipe$CraftingBookInfoalong with theIngredienttarget and dye and theItemStackTemplateresult instead of theCraftingBookCategoryMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
FireworkRocketRecipenow takes in theIngredientshell, fuel, and star along with theItemStackTemplateresult instead of theCraftingBookCategoryMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
FireworkStarFadeRecipenow takes in theIngredienttarget and dye along with theItemStackTemplateresult instead of theCraftingBookCategoryMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
FireworkStarRecipenow takes in the$ShapetoIngredientmap; theIngredienttrail, twinkle, fuel, and dye; along with theItemStackTemplateresult instead of theCraftingBookCategoryMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
MapCloningRecipereplaced withTransmuteRecipeMapExtendingRecipenow extendsCustomRecipeinstead ofShapedRecipe- The constructor now takes in the
Ingredientmap and material along with theItemStackTemplateresult instead of theCraftingBookCategory MAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
- The constructor now takes in the
NormalCraftingRecipe- A class that defines the standard implementation for a crafting recipe.RecipeshowNotification,groupare no longer default$BookInfo- The information for the recipe book.$CommonInfo- The common information across all recipes.
RecipeSerializeris now a record containing theMapCodecandStreamCodec- The registered entries have been moved to
RecipeSerializers registeris removed
- The registered entries have been moved to
RecipeSerializers- All vanilla serializers for recipes.RepairItemRecipeno longer takes in anythingINSTANCE- The recipe serializer singleton.MAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
ShapedRecipenow extendsNormalCraftingRecipeinstead of implementingCraftingRecipe- The constructor now takes in the
Recipe$CommonInfoandCraftingRecipe$CraftingBookInfoinstead of the group andCraftingBookCategory $Serializer->MAP_CODEC,STREAM_CODEC,SERIALIZER; not one-to-one
- The constructor now takes in the
ShapelessRecipenow extendsNormalCraftingRecipeinstead of implementingCraftingRecipe- The constructor now takes in the
Recipe$CommonInfoandCraftingRecipe$CraftingBookInfoinstead of the group andCraftingBookCategory $Serializer->MAP_CODEC,STREAM_CODEC,SERIALIZER; not one-to-one
- The constructor now takes in the
ShieldDecorationRecipenow takes in theIngredientbanner and target along with theItemStackTemplateresult instead of theCraftingBookCategoryMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
SimpleSmithingRecipe- A class that defines the standard implementation of a smithing recipe.SingleItemRecipenow takes in theRecipe$CommonInfoinstead of the groupcommonInfo- The common information for the recipe.$Factory#createnow takes in theRecipe$CommonInfoinstead of the group$Serializer->simpleMapCodec,simpleStreamCodec; not one-to-one
SmeltingRecipenow takes in theRecipe$CommonInfoandAbstractCookingRecipe$CookingBookInfoinstead of the group andCookingBookCategoryMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
SmithingTransformRecipenow extendsSimpleSmithingRecipeinstead of implementingSmithingRecipe- The constructor now takes in the
Recipe$CommonInfo $Serializer->MAP_CODEC,STREAM_CODEC,SERIALIZER; not one-to-one
- The constructor now takes in the
SmithingTrimRecipenow extendsSimpleSmithingRecipeinstead of implementingSmithingRecipe- The constructor now takes in the
Recipe$CommonInfo $Serializer->MAP_CODEC,STREAM_CODEC,SERIALIZER; not one-to-one
- The constructor now takes in the
SmokingRecipenow takes in theRecipe$CommonInfoandAbstractCookingRecipe$CookingBookInfoinstead of the group andCookingBookCategoryMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
StonecutterRecipenow takes in theRecipe$CommonInfoinstead of the groupMAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
TippedArrowRecipe->ImbueRecipe, not one-to-one- The constructor now takes in the
Recipe$CommonInfoandCraftingRecipe$CraftingBookInfoalong with theIngredientsource and material and theItemStackTemplateresult instead of theCraftingBookCategory MAP_CODEC,STREAM_CODEC,SERIALIZER- Serializers for the recipe.
- The constructor now takes in the
TransmuteRecipenow extendsNormalCraftingRecipeinstead of implementingCraftingRecipe- The constructor now takes in the
Recipe$CommonInfoandCraftingRecipe$CraftingBookInfoalong with theMinMaxBounds$Intsandbooleanhandling the material count and adding it to the result instead of the group andCraftingBookCategory $Serializer->MAP_CODEC,STREAM_CODEC,SERIALIZER; not one-to-one
- The constructor now takes in the
net.minecraft.world.item.crafting.display.SlotDisplay$OnlyWithComponent- A display only with the contents having the desired components.$WithAnyPotion- A display with the contents having any potion contents component.
net.minecraft.world.level.storage.loot.functions.SmeltItemFunction#smeltednow can take in whether to use the input material count
Dye Component
Specifying whether an item can be used as a dye material is now handled through the DYE data component. The component specifies a DyeColor, which can be set via Item$Properties#component:
public static final Item EXAMPLE_DYE = new Item(new Item.Properties().component(
DataComponents.DYE, DyeColor.WHITE
));
However, a dye material’s behavior is not fully encompassed by the component alone. In most cases, the component is used in conjunction with some other tag or subclass to get the desired behavior.
Entities and Signs
Dying sheeps and signs are handled purely through the DyeItem subclass, checking if the item has the DYE component.
Dying the collars of wolfs and cats, on the other hand, can be any item, assuming it has the DYE component. Additionally, the item must be in the ItemTags#WOLF_COLLAR_DYES or ItemTags#CAT_COLLAR_DYES tag, respectively.
Dye Recipes
The DyeRecipe, formerly named ArmorDyeRecipe, can take any target ingredient and apply the colors of the dye ingredients to obtain the desired result with the associated DYED_COLOR component. Any item can be considered a dye; however, those without the DYE component will default to DyeColor#WHITE. Armor makes used of RecipeProvider#dyedItem to allow any item in the ItemTags#DYES tag to dye armor. However, bundles and shulker boxes have their color components as different items, meaning instead the default recipes are tied directly to the vanilla DyeItem, meaning a separate recipe will need to be generated for applying dyes to those items.
The loom, firework star, and firework star face recipes on the other hand expect any dye material to have the DYE component. The loom has an additional requirement of the item being in the ItemTags#LOOM_DYES tag.
net.minecraft.core.component.DataComponents#DYE- Represents that an item can act as a dye for the specific color.net.minecraft.data.recipes.RecipeProviderdyedItem- Creates a dyed item recipe.dyedShulkerBoxRecipe- Creates a dyed shulker box recipe.dyedBundleRecipe- Creates a dyed bundle recipe.
net.minecraft.world.itemBundleItemgetAllBundleItemColors,getByColorare removed
DyeColor#VALUES- A list of all dye colors.DyeItemno longer takes in theDyeColorgetDyeColor,byColorare removed
net.minecraft.world.item.component.DyedItemColor#applyDyesnow takes in a list ofDyeColors instead ofDyeItems- An overload can also take in a
DyedItemColorcomponent instead of theItemStack
- An overload can also take in a
net.minecraft.world.item.crafting.ArmorDyeRecipe->DyeRecipe, not one-to-onenet.minecraft.world.item.crafting.display.SlotDisplay$DyedSlotDemo- A display for demoing dying an item.net.minecraft.world.level.blockBannerBlock#byColoris removedShulkerBoxBlock#getBlockByColor,getColoredItemStackare removed
World Clocks and Time Markers
World clocks are objects that represent some time that increases every tick from when the world first loads. These clocks are used as timers to properly handle timing-based events (e.g., the current day, sleeping). Vanilla provides two world clocks: one for minecraft:overworld and one for minecraft:the_end.
Creating a clock is rather simple: just an empty, datapack registry object in world_clock.
// For some world clock 'examplemod:EXAMPLE_CLOCK'
// JSON at 'data/examplemod/world_clock/EXAMPLE_CLOCK.json'
{}
From there, you can query the clock state through the ClockManager via Level#clockManager or MinecraftServer#clockManager:
// For some Level level
// Assume we have some ResourceKey<WorldClock> EXAMPLE_CLOCK
// Get the clock reference
Holder.Reference<WorldClock> clock = level.registryAccess().getOrThrow(EXAMPLE_CLOCK);
// Query the clock time
long ticksPassed = level.clockManager().getTotalTicks(clock);
If accessing the clock from the server, you can also modify the state of the clock:
// For some ServerLevel level
// Assume we have some ResourceKey<WorldClock> EXAMPLE_CLOCK
// Get the clock reference
Holder.Reference<WorldClock> clock = level.registryAccess().getOrThrow(EXAMPLE_CLOCK);
// Get the server clock manager
ServerClockManager clockManager = level.clockManager();
// Set the total number of ticks that have passed
clockManager.setTotalTicks(clock, 0L);
// Add the a certain value to the number of ticks
clockManager.addTicks(clock, 10L);
// Pause the clock
clockManager.setPaused(
clock,
// `true` to pause.
// `false` to unpause.
true
);
Marking Timelines
On its own, world clocks are rather limited in scope as you have to keep track of the number of ticks that have passed. However, when used with timelines, specific recurring times can be marked to handle timing-based events.
As a refresher, Timelines are a method of modifying attributes based on some WorldClock. Currently, all vanilla timelines use the minecraft:overworld world clock to keep track of their timing, via the clock field. All timelines must define a clock it uses; however, be aware that clocks to not support any synchronization by default, meaning that updating the time on one clock will not affect the other.
// For some timeline 'examplemod:example_timeline'
// In `data/examplemod/timeline/example_timeline.json
{
// Uses the custom clock.
// Any changes to the clock time will only affect
// timelines using this clock.
// e.g., `minecraft:overworld` will not be changed.
"clock": "examplemod:example_clock",
// Perform actions on a 24,000 tick interval.
"period_ticks": "24000",
// ...
}
// For some timeline 'examplemod:example_timeline_2'
// In `data/examplemod/timeline/example_timeline_2.json
{
// Uses the same clock as the one above.
// Changes to the clock time will affect both
// timelines.
"clock": "examplemod:example_clock",
// Perform actions on a 1,000 tick interval.
"period_ticks": "1000",
// ...
}
// For some timeline 'examplemod:example_overworld'
// In `data/examplemod/timeline/example_overworld.json
{
// Uses the vanilla overworld clock.
// Changes to the clock time will not affect
// the above timelines as they use a different
// clock.
"clock": "minecraft:overworld",
// Perform actions on a 6,000 tick interval.
"period_ticks": "6000",
// ...
}
Timelines can also define time markers, which is just some identifier for a time within the timeline period for a world clock. These are commonly used within commands (e.g. /time set), to check if a certain time has passed (e.g. village sieges), or to skip to the given time (e.g. waking up from sleep). Time markers are defined in time_markers, specifying the ticks within the period and whether it can be show_in_commands. As time markers are identified by their world clock, timelines using the same world clock cannot define the same time markers.
// For some timeline 'examplemod:example_timeline'
// In `data/examplemod/timeline/example_timeline.json
{
// The identifier of the clock.
"clock": "examplemod:example_clock",
// Perform actions on a 24,000 tick interval.
"period_ticks": "24000",
// The markers within the period specified by the timeline
"time_markers": {
// A marker
"examplemod:example_marker": {
// The number of ticks within the period
// that this marker represents.
// e.g., 5000, 29000, 53000, etc.
"ticks": 5000,
// When true, allows the time marker to be
// suggested in the command. If false,
// the time marker can still be used in the
// command, it just won't be suggested.
"show_in_commands": true
}
}
// ...
}
Once the time markers are defined, they are registered for a world clock in the ServerClockManager, allowing them to be used given the ResourceKey.
// For some ServerLevel level
// Assume we have some ResourceKey<WorldClock> EXAMPLE_CLOCK
// Assume we have some ResourceKey<ClockTimerMarker> EXAMPLE_MARKER
// Get the clock reference
Holder.Reference<WorldClock> clock = level.registryAccess().getOrThrow(EXAMPLE_CLOCK);
// Get the server clock manager
ServerClockManager clockManager = level.clockManager();
// Check if the time is at the specified marker
// This should be used when checking for a specific time event every tick
boolean atMarker = clockManager.isAtTimeMarker(clock, EXAMPLE_MARKER);
// Skip to the time specified by the marker
// If the world clock is at 3000, sets the clock time to 5000
// If the world clock is at 6000, sets the clock time to 29000
// Returns whether the time was set, which is always true if the marker
// exists for the clock.
boolean timeSet = clockManager.skipToTimeMarker(clock, EXAMPLE_MARKER);
net.minecraft.client.ClientClockManager- Manages the ticking of the world clocks on the client side.net.minecraft.client.gui.components.debug.DebugEntryDayCount- Displays the current day of the Minecraft world.net.minecraft.client.multiplayerClientLevelsetTimeFromServerno longer takes in thelongday time nor thebooleanof whether to tick the day time$ClientLevelData#setDayTimeis removed
ClientPacketListener#clockManager- Gets the client clock manager.
net.minecraft.client.renderer.EndFlashState#ticknow takes in the end clock time instead of the game timenet.minecraft.commands.arguments.ResourceArgumentgetClock- Gets a reference to the world clock given the string resource identifier.getTimeline- Gets a reference to the timeline given the string resource identifier.
net.minecraft.core.registries.Registries#WORLD_CLOCK- The registry identifier for the world clock.net.minecraft.gametest.framework.TestEnvironmentDefinition$TimeOfDay->$ClockTime, not one-to-one$Timelines- A test environment that uses a list of timelines.
net.minecraft.network.protocol.game.ClientboundSetTimePacketnow takes in a map of clocks to their network states instead of the day timelongandbooleannet.minecraft.serverMinecraftServerforceTimeSynchronization->forceGameTimeSynchronization, not one-to-oneclockManager- The server clock manager.
net.minecraft.server.level.ServerLevelsetDayTime,getDayCountare removedsetEnvironmentAttributes- Sets the environment attribute system to use.
net.minecraft.world.attribute.EnvironmentAttributeSystem$Builder#addTimelineLayernow takes in theClockManagerinstead of aLongSuppliernet.minecraft.world.clockClockManager- A manager that gets the total number of ticks that have passed for a world clock.ClockNetworkState- The current state of the clock to sync over the network.ClockState- The current state of the clock, including the total number of ticks and whether the clock is paused.ClockTimeMarker- A marker that keeps track of a certain period of time for a world clock.ClockTimeMarkers- All vanilla time markers.PackedClockStates- A map of clocks to their states, compressed for storage or other use.ServerClockManager- Manages the ticking of the world clocks on the server side.WorldClock- An empty record that represents a key for timing some location.WorldClocks- All vanilla world clocks.
net.minecraft.world.levelLevelgetDayTime->getOverworldClockTime, not one-to-oneclockManager- The clock manager.getDefaultClockTime- Gets the clock time for the current dimension.
LevelReader#getEffectiveSkyBrightness- Gets the sky brightness with the current darkening factor.
net.minecraft.world.level.dimension.DimensionTypenow takes in a default, holder-wrappedWorldClocknet.minecraft.world.level.storageLevelData#getDayTimeis removedServerLevelDatasetDayTimeis removedsetClockStates,clockStates- Handles the current states of the world clocks.
net.minecraft.world.level.storage.loot.predicates.TimeChecknow takes in a holder-wrappedWorldClocktimenow takes in a holder-wrappedWorldClock$Buildernow takes in a holder-wrappedWorldClock
net.minecraft.world.timelineAttributeTrack#bakeSamplernow takes in a holder-wrappedWorldClockAttributeTrackSamplernow takes in a holder-wrappedWorldClock, and aClockManagerinstead of aLongSupplierfor the day time getterTimelinenow takes in a holder-wrappedWorldClockalong with a map of time markers to their infos#buildernow takes in a holder-wrappedWorldClockgetPeriodCount- Gets the number of times a period has occurred within the given timeframe.getCurrentTicksnow takes in theClockManagerinstead of theLevelgetTotalTicksnow takes in theClockManagerinstead of theLevelclock- Returns the holder-wrappedWorldClock.registerTimeMarkers- Registers allClockTimeMarkerdefined in this timeline.createTrackSamplernow takes in aClockManagerinstead of aLongSupplierfor the day time getter$Builder#addTimeMarker- Adds a time markers at the given tick, along with whether the marker can be suggested in commands.
Timelines#DAY->OVERWORLD_DAY
Splitting the Primary Level Data into Saved Data
Some of the WorldData settings have been moved into SavedData, allowing for levels / dimensions to have more customizability. This addition also brings along some changes to how SavedData is referenced and queried.
Saved Data Changes
SavedDataType now identifies some SavedData using an Identifier, which is resolved against the data folder. This change allows subdirectories within the data folder, as the data storage will first create all missing parent directories before attempting to write the file.
public class ExampleData extends SavedData {
public static final SavedDataType<ExampleData> TYPE = new SavedDataType<>(
// The identifier for the saved data to resolve against
// Data can be found in:
// `<world_folder>/dimensions/<dimension_namespace>/<dimension_path>/data/examplemod/example/data.dat`
Identifier.fromNamespaceAndPath("examplemod", "example/data"),
// The constructor to create a new saved data
ExampleData::new,
// The codec to serialize the new saved data
MapCodec.unitCodec(ExampleData::new),
// The data fixer type
// Either some patched enum value or null depending on mod loader implementation.
null
);
}
The SavedData can then be queried through the SavedDataStorage, renamed from DimensionDataStorage. This was renamed because the MinecraftServer instance now has its own data storage for global instances in addition to the levels. This means that any global saved data should be stored on the server instance rather than the overworld.
// Given a MinecraftServer server
ExampleData data = server.getDataStorage().computeIfAbsent(ExampleData.TYPE);
// Given a ServerLevel level
ExampleData data = level.getDataStorage().computeIfAbsent(ExampleData.TYPE);
Additional Saved Data
The following information is now stored as saved data:
- Custom boss events
- Ender dragon fight
- Game rules
- Wandering trader spawning
- Weather
- World generation settings
Of these, only the ender dragon fight is on a per-level / dimension basis. The rest are still stored and accessed through the server data storage. Custom boss events, on the other hand, remain unique as it is up to the implementer to determine what players are part of the event.
net.minecraft.client.Minecraft#doWorldLoadnow takes in the optionalGameRulesnet.minecraft.client.gui.screens.worldselectionCreateWorldCallbacknow takes in theLevelDataAndDimensions$WorldDataAndGenSettingsand the optionalGameRulesinstead of thePrimaryLevelDataEditGameRulesScreen->AbstractGameRulesScreen- Implementations in
.screens.options.InWorldGameRulesScreenandWorldCreationGameRulesScreen
- Implementations in
WorldOpenFlowscreateLevelFromExistingSettingsnow takes in theLevelDataAndDimensions$WorldDataAndGenSettingsand the optionalGameRulesinstead of theWorldDataloadWorldStemnow takes in theLevelStorageSource$LevelStorageAccess
net.minecraft.client.server.IntegratedServernow takes in the optionalGameRulesnet.minecraft.serverMinecraftServernow takes in the optionalGameRulesgetGlobalGameRules- Gets the game rules for the overworld dimension.getWorldGenSettings- Gets the generation settings for the world.getWeatherData- Gets the weather data for the server.getDataStorage- Gets the saved data storage for the server.getGameRules- Gets the game rules for the server.
WorldStemnow takes in theLevelDataAndDimensions$WorldDataAndGenSettingsinstead of theWorldData
net.minecraft.server.bosseventsCustomBossEventnow takes in aUUIDfor the identifier along with aRunnablefor the callbackgetTextId->customIdaddOfflinePlayeris removedgetValue->valuegetMax->maxloadnow takes in theUUIDidentifier along with aRunnablefor the callback
CustomBossEventsnow extendsSavedDatacreatenow takes in aRandomSourcesave,load->TYPE, not one-to-one
net.minecraft.server.dedicated.DedicatedServernow takes in the optionalGameRulesnet.minecraft.server.levelChunkMap#getChunkDataFixContextTagnow takes in an optionalIdentifierinstead of aResourceKeyServerBossEventnow takes in anUUIDfor the idsetDirty- Marks the boss event as dirty for saving.
ServerLevelno longer takes in theRandomSequencessetWeatherParameters->MinecraftServer#setWeatherParametersgetWeatherData- Gets the weather data for the server.getRandomSequence->MinecraftServer#getRandomSequencegetRandomSequences->MinecraftServer#getRandomSequences
net.minecraft.world.entity.npc.wanderingtrader.WanderingTraderSpawnernow takes in theSavedDataStorageinstead of theServerLevelDataMIN_SPAWN_CHANCEis nowpublicfromprivate
net.minecraft.world.entity.raid.Raids#TYPE_END,getTypeare removednet.minecraft.world.levelLevel#prepareWeatheris removedLevelSettingsis now a record- The constructor now takes in the
$DifficultySettingsinstead of just theDifficulty withDifficultyLock- The settings with whether the difficulty is locked.copy- Copies the settings.$DifficultySettings- The settings for the difficulty.
- The constructor now takes in the
net.minecraft.world.level.dimension.DimensionTypenow takes in abooleanfor whether the dimension can have an ender dragon fightnet.minecraft.world.level.dimension.endDragonRespawnAnimation->DragonRespawnStage, not one-to-oneEndDragonFight->EnderDragonFight, not one-to-one
net.minecraft.world.level.gamerules.GameRuleMapnow extendsSavedDataTYPE- The saved data type.reset- Resets the rule to its default value.
net.minecraft.world.level.levelgen.WorldGenSettingsis now a final class instead of a record, extendingSavedDataencode,decodereplaced withTYPEof- Constructs the generation settings.
net.minecraft.world.level.saveddataSavedDataTypenow takes in anIdentifierinstead of a string for the idWanderingTraderData- The saved data for the wandering trader.WeatherData- The saved data for the weather.
net.minecraft.world.level.storageDimensionDataStorage->SavedDataStorage, not one-to-oneLevelData#isThundering,isRaining,setRainingnow inWeatherDataLevelDataAndDimensionsnow takes in a$WorldDataAndGenSettingsinstead of theWorldData$WorldDataAndGenSettings- Holds the world data and generation settings.
LevelResourceis now a recordPrimaryLevelDatafields have been moved to their respective saved data classesPLAYER->OLD_PLAYERSINGLEPLAYER_UUID- A string that represents the UUID of the player in a singleplayer world.WORLD_GEN_SETTINGS->OLD_WORLD_GEN_SETTINGSwriteLastPlayed- Writes the last played player.writeVersionTag- Writes the data version tag.
ServerLevelDatasetThundering,getRainTime,setRainTime,setThunderTime,getThunderTime,getClearWeatherTime,setClearWeatherTimemoved toWeatherDatagetWanderingTraderSpawnDelay,setWanderingTraderSpawnDelay,getWanderingTraderSpawnChance,setWanderingTraderSpawnChance,getWanderingTraderId,setWanderingTraderIdmoved toWanderingTraderDatagetLegacyWorldBorderSettings,setLegacyWorldBorderSettingsreplaced byWorldBordergetScheduledEvents->MinecraftServer#getScheduledEventsgetGameRulesreplaced byGameRuleMap
WorldDatagetCustomBossEvents,setCustomBossEventsreplaced byCustomBossEventscreateTagno longer takes in theRegistryAccessgetGameRulesreplaced byGameRuleMapgetLoadedPlayerTag->getSinglePlayerUUID, not one-to-oneendDragonFightData,setEndDragonFightDatareplaced byEnderDragonFightworldGenOptionsreplaced byWorldGenSettingssaved data
net.minecraft.world.level.timers.TimerQueuenow extendsSavedData- The constructor now takes in the
$Packedevents instead of theTimerCallbacksandStreamof event data storereplaced byCODEC,TYPE,codecloadEvent,storeEventreplaced by$Event$Packed#codec$Eventis now a record$Packed- The packed event data.
$Packed- The packed time queue.
- The constructor now takes in the
Even More Rendering Changes
Materials and Dynamic Layer Selection
Block and item models now no longer specify what RenderType or ChunkSectionLayer they belong to. Instead, this is computed when loading the model, determing the associated layer for each quad. This means that ItemBlockRenderTypes is removed, with setting the RenderType for an item removed altogether.
To determine what layer a quad or face gets set to, the Transparency of the texture is computed. Specifically, it checks that, for the UV area mapped to the quad, if there are any pixels that are transparent (have an alpha of 0), or translucent (have an alpha that is not 0 or 255). For the ChunkSectionLayer, ChunkSectionLayer#TRANSLUCENT is used if there is a translucent pixel, else CUTOUT is used if there is a transparent pixel, else SOLID. For the item RenderType, Sheets#translucentItemSheet and translucentBlockItemSheet for block items are used if there is a translucent pixel, or cutoutItemSheet and cutoutBlockItemSheet for block items. The Transparency also affects using MipmapStrategy#AUTO, using CUTOUT instead of MEAN as the default if there is a transparent pixel.
One can influence a quad’s Transparency through the Material texture defined by the model JSON. A Material specifies the texture’s sprite, which represents the relative path to the texture, and optionally force_translucent, which forces any quad using this texture to use Transparency#TRANSLUCENT (transparent is false while translucent is true):
// For some model `examplemod:example_model`
// In: `assets/examplemod/models/example_model.json`
{
"parent": "minecraft:block/template_glass_pane_post",
"textures": {
// A Material can be a simple texture reference
// Points to `assets/minecraft/textures/block/glass_pane_top.png`
"edge": "minecraft:block/glass_pane_top",
// Or it can be an object
"pane": {
// The relative texture reference for faces using this key
// Points to `assets/minecraft/textures/block/glass.png`
"sprite": "minecraft:block/glass",
// When true, sets all faces using this texture key to
// always have a transparent pixel.
"force_translucent": true
}
}
// ...
}
This change also defines the rendering order, where all solid quads are rendered first, followed by cutout quads, and finally translucent quads, sorted by distance from the camera.
Materials and Sprites
As you may have noticed, Materials were originally used to define some texture in an atlas. The addition of materials in texture JSONs have changed the naming of these classes. Materials now explicitly refer to texture references within model JSONs. This means that all references to the raw texture location have been replaced with Material, if unbaked, and Material$Baked, if baked. Additionally, the SpriteGetter is now MaterialBaker.
As for the original Material, these are now known as sprites, where Material is renamed to SpriteId, and MaterialSet is renamed to SpriteGetter.
Quad Particle Layers
The SingleQuadParticle$Layers have been split into OPAQUE_* and TRANSLUCENT_* layers, depending on if the particle texture used by the atlas contains a translucent pixel. Note that ‘opaque’ in this instance means cutout, where pixels with an alpha of less than 0.1 are discarded. If not creating a new layer, $Layer#bySprite can be used to determine what layer the particle texture should use.
public class ExampleParticle extends SingleQuadParticle {
private final SingleQuadParticle.Layer layer;
public SingleQuadParticle(ClientLevel level, double x, double y, double z, TextureAtlasSprite sprite) {
super(level, x, y, z, sprite);
this.layer = SingleQuadParticle.Layer.bySprite(sprite);
}
@Override
protected SingleQuadParticle.Layer getLayer() {
return this.layer;
}
}
Block Models
The pipeline for rendering individual block models outside of the general world context has been rewritten similarly to ItemModels, where a ‘block model’ updates some render state, which then submits its elements for rendering. As such, most of the block model classes have been either rewritten or reorganized to a degree.
Due to the block model name being synonymous with the model JSONs in general, many classes were moved and rename to separate the model JSONs, from the block state JSONs, from the now block models. As such, geometry for models that originally had ‘block’ in the name were changed to ‘cuboid’: (e.g., BlockModel -> CuboidModel, BlockModelWrapper -> CuboidItemModelWrapper). Additionally, parts of the rendering process referring to the definitions within a block state JSON were changed from ‘block’ to ‘block state’ (e.g., BlockModelPart -> BlockStateModelPart, BlockModelDefinition -> BlockStateModelDispatcher). You can consider most of the ‘block model’ classes to be new, with those renamed replacing the SpecialBlockModelRenderer system.
The block model system starts from the ModelManager after all models and definitions are loaded and resolved, ready to be baked. Block models are loaded through BuiltInBlockModels#crateBlockModels, which links some BlockState to a BlockModel$Unbaked. Similarly to item models, the unbaked instance defines the properties of how the block model should be constructed. These are stored within LoadedBlockModels, to which they are then subsequently baked after all JSONs into BlockModels via bake. This BlockState to BlockModel map is then stored within the BlockModelSet, ready to be queried through get, or more commonly through BlockModelResolver#update, which calls in the model set. Any models not defined lazily resolve to a wrapper around the BlockStateModel.
Vanilla provides six BlockModel implementations for common usage. There is EmptyBlockModel, which submit no elements, and as such renders nothing; and BlockStateModelWrapper, which wraps around and displays the associated BlockStateModel. Then, there are equivalents for changing the model based on some property switch (SelectBlockModel), a conditional boolean (ConditionalBlockModel), and composing multiple models together (CompositeBlockModel). Finally, there is the SpecialBlockModelWrapper, which submits its elements through the stored SpecialModelRenderer, the unified submitter between item and block models.
// As the block model system is hardcoded through its in-code bootstrap,
// this example will assume there exists some method to get access to the
// `BuiltInBlockModels$Builder` builder.
// We will also assume we have some Block EXAMPLE_BLOCK_* to attach the models to.
// Regular block model
builder.put(
// A factory that takes in the `BlockColors` and `BlockState` to return
// a `BlockModel$Unbaked`.
(colors, state) -> new BlockStateModelWrapper.Unbaked(
// The state to get the `BlockStateModel` of.
state,
// The tint layers for the model.
colors.getTintSources(state),
// An optional transformation to apply to the `PoseStack` before
// submitting the model.
Optional.empty(new Transformation(new Matrix4f().translation(0.5f, 0.5f, 0.5f)))
),
// The block to use this model for. Will loop through a construct one
// per state.
EXAMPLE_BLOCK_1
);
// Block model switched on some property
builder.put(
(colors, state) -> new SelectBlockModel.Unbaked(
// An optional transformation to apply to the `PoseStack` before
// submitting the model.
Optional.empty(),
// A record containing the property to switch on, along with the
// values when a specific block model should be selected.
new SelectBlockModel.UnbakedSwitch<>(
// The `SelectBlockModelProperty` to switch on. The property
// value is determined from the `BlockState` and its `BlockDisplayContext`.
(state, displayContext) -> state.getRenderShape(),
// The list of cases to determine what `BlockModel` to use.
List.of(
new SelectBlockModel.SwitchCase<>(
// The list of values this model applies to.
List.of(RenderShape.INVISIBLE),
// The model to use when this property is met.
new EmptyBlockModel.Unbaked()
)
),
// An optional fallback if no switch case matches the state's
// property.
Optional.of(new EmptyBlockModel.Unbaked())
)
),
EXAMPLE_BLOCK_2
);
// Block model based on some conditional
builder.put(
(colors, state) -> new ConditionalBlockModel.Unbaked(
// An optional transformation to apply to the `PoseStack` before
// submitting the model.
Optional.empty(),
// The `ConditionalBlockModelProperty` that determines the
// `boolean` from the `BlockState`.
BlockState::isSignalSource,
// The model to display when the property returns `true`.
new EmptyBlockModel.Unbaked(),
// The model to display when the property returns `false`.
new EmptyBlockModel.Unbaked()
),
EXAMPLE_BLOCK_3
);
// A composite block model
builder.put(
(colors, state) -> new CompositeBlockModel.Unbaked(
// The first model to display.
new EmptyBlockModel.Unbaked(),
// The second model to display.
new EmptyBlockModel.Unbaked(),
// An optional transformation to apply to the `PoseStack` before
// submitting the model.
Optional.empty()
),
EXAMPLE_BLOCK_4
);
// Special block model
builder.put(
(colors, state) -> new SpecialBlockModelWrapper.Unbaked(
// The unbaked `SpecialModelRenderer` used to submit elements for the
// model.
new BellSpecialRenderer.Unbaked(),
// An optional transformation to apply to the `PoseStack` before
// submitting the model.
Optional.empty()
),
EXAMPLE_BLOCK_5
);
During the feature submission process, block models are handled through the BlockModelResolver and BlockModelRenderState. This is similar to how other render states work. First, BlockModelResolver#update sets up the BlockModelRenderState. Setup is handled through either the basic path – BlockModelRenderState#setupModel, add the model parts to the returned list, then setupTints, or through setupSpecialModel for the special renderers. Then, the render state submits its elements for rendering through BlockModelRenderState#submit. The render state also provides submitOnlyOutline which uses the outline render type, and submitWithZOffset which uses the sold entity forward Z-offset render type.
// BlockEntity example
public class ExampleRenderState extends BlockEntityRenderState {
// Hold the render state.
public final BlockModelRenderState exampleBlock = new BlockModelRenderState();
}
public class ExampleRenderer implements BlockEntityRenderer<ExampleBlockEntity, ExampleRenderState> {
// The display context for use in the block entity renderer.
public static final BlockDisplayContext BLOCK_DISPLAY_CONTEXT = BlockDisplayContext.create();
private final BlockModelResolver blockResolver;
public ExampleRenderer(BlockEntityRendererProvider.Context ctx) {
super(ctx);
// Get the model resolver.
this.blockResolver = ctx.blockModelResolver();
}
@Override
public void extractRenderState(ExampleBlockEntity blockEntity, ExampleRenderState state, float partialTick, Vec3 cameraPosition, ModelFeatureRenderer.CrumblingOverlay breakProgress) {
super.extractRenderState(blockEntity, state, partialTick, cameraPosition, breakProgress);
// Update the model state.
this.blockResolver.update(state.exampleBlock, Blocks.DIRT.defaultBlockState(), BLOCK_DISPLAY_CONTEXT);
}
@Override
public void submit(ExampleRenderState state, PoseStack pose, SubmitNodeCollector collector, CameraRenderState camera) {
super.submit(state, pose, collector, camera);
// Submit the model state for rendering.
state.exampleBlock.submit(
// The current pose stack,
pose,
// The node collector.
collector,
// The light coordinates.
state.lightCoords,
// The overlay coordinates.
OverlayTexture.NO_OVERLAY,
// The outline color.
0
);
}
}
// Entity example
public class ExampleRenderState extends EntityRenderState {
// Hold the render state.
public final BlockModelRenderState exampleBlock = new BlockModelRenderState();
}
public class ExampleRenderer extends EntityRenderer<ExampleEntity, ExampleRenderState> {
// The display context for use in the entity renderer.
public static final BlockDisplayContext BLOCK_DISPLAY_CONTEXT = BlockDisplayContext.create();
private final BlockModelResolver blockResolver;
public ExampleRenderer(EntityRendererProvider.Context ctx) {
super(ctx);
// Get the model resolver.
this.blockResolver = ctx.getBlockModelResolver();
}
@Override
public void extractRenderState(ExampleEntity entity, ExampleRenderState state, float partialTick) {
super.extractRenderState(entity, state, partialTick);
// Update the model state.
this.blockResolver.update(state.exampleBlock, Blocks.DIRT.defaultBlockState(), BLOCK_DISPLAY_CONTEXT);
}
@Override
public void submit(ExampleRenderState state, PoseStack pose, SubmitNodeCollector collector, CameraRenderState camera) {
super.submit(state, pose, collector, camera);
// Submit the model state for rendering.
state.exampleBlock.submit(
// The current pose stack.
pose,
// The node collector.
collector,
// The light coordinates.
state.lightCoords,
// The overlay coordinates.
OverlayTexture.NO_OVERLAY,
// The outline color.
state.outlineColor
);
}
}
Block Tint Sources
BlockColor has been completely replaced by BlockTintSource, which sets the ARGB tint of a particular index based on the desired context. There are three contexts a tint source can provide:
colorfor the general context, used byBlockModelscolorInWorldfor the world context, used byModelBlockRenderer#tesselateBlockcolorAsTerrainParticlefor the particle context, used by the falling dust and terrain particle
In addition, BlockTintSource provides a relevantProperties if the Propertys of a BlockState are used to determine what color to tint. This is used by the LevelRenderer to determine whether a change in state requires a model to be re-rendered.
BlockTintSources are still registered to BlockColors via register, taking in a list of sources followed by the vararg of blocks. The tintindex specfied in the model JSON is used to index into the tint source list.
// Assume access to BlockColors colors
colors.register(
// The list of tints to apply to some block model.
List.of(
// "tintindex": 0
(state) -> 0xFFFF0000,
// "tintindex": 1
new BlockTintSource() {
@Override
public int color(BlockState state) {
return 0xFF00FF00;
}
@Override
public int colorInWorld(BlockState state, BlockAndTintGetter level, BlockPos pos) {
return 0xFF0000FF;
}
}
),
// The blocks these tint sources will apply to.
EXAMPLE_BLOCK_1
);
Removing the Old Block and Item Renderers
Since ItemModels and BlockModel are now fully handled through their own feature submission pipeline, BlockRenderDispatcher and ItemRenderer have been completely removed, replaced by the corresponding systems.
Object Definition Transformations
ItemModels and BlockModels can now take in an optional Transformation, which transforms how the model should be displayed. As such, the $Unbaked#bake methods now take in the parent Matrix4fc transformation, to which the transformation is multiplied to via Transformation#compose. For item models, this is known as a local transform separate from the model JSON item transform. The local transforms are always applied after the item transform.
Note that adding support for transformations should always be done through Transformation#compose as the matrices passed around are mutable by nature. Assume any custom methods not performed through a vanilla interface should copy before performing any modifications.
Quad Instance
The brightness / tint color, lightmap, and overlay coordinates have been consolidated into a single object: QuadInstance. The mutable class sets its values through its associated set* methods, and can pull the information for each quad vertex via the get* methods. Brightness and tinting are stored together as the color, rather them being two separate values.
QuadInstance does not replace all usecases, such as when adding a single vertex. It only updates methods for the VertexConsumer, splitting putBulkData into putBlockBakedQuad for quads in block models, and putBakedQuad for all other uses.
In addition, mmany methods used to upload BakedQuads to a buffer now take in a BlockQuadOutput. This has the same parameters as VertexConsumer#putBlockBakedQuad, and was added due to the section renderer uploading to a newly allocated BufferBuilder for use with the uber buffer.
Gui Extractor
GUI classes methods have gone through a massive renaming scheme, indicating that the submitted elements are ‘extracted’ into a general tree to be submitted and then rendered. As such, methods that began with draw* or render* are now prefixed with extract*, and potentially suffixed with *RenderState (e.g., Renderable#render -> extractRenderState, AbstractContainerScreen#renderLabels -> extractLabels, AbstractWidget#renderWidget -> extractWidgetRenderState). Some shorthands were also expanded, either by renamining or replacing the method with another (e.g., AbstractContainerScreen#renderBg replaced by Screen#extractBackground).
GuiGraphics was also renamed to GuiGraphicsExtractor in the same fashion. The methods follow similar patterns to the rest of the GUI changes (e.g. hline -> horizontalLine), except that draw*, render*, and submit* prefixes along with *RenderState suffixes are removed (e.g. renderOutline -> outline, submitEntityRenderState -> entity). The only rename is that *String* method names are replaced with *Text*.
Fluid Models
Defining a fluid’s textures and tint has now been moved out of the FluidRenderer (previously LiquidBlockRenderer) and into its own separate FluidModel record. Initially, given the small number of fluids, the unbaked variants (FluidModel$Unbaked) are stored as constants. Then, after BlockModel have been baked, the fluid models are baked via FluidStateModelSet#bake, linking a Fluid to its FluidModel. This map is then stored within the FluidStateModelSet, ready to be queried through get.
A FluidModel$Unbaked has four arguments: three Materials for the still, flowing, and optional overlay textures; and one for the BlockTintSource. The tint is obtained via BlockTintSource#colorInWorld. During the baking process, it will determine the ChunkSectionLayer based on the transparency of the provided materials.
// As the fluid model system is hardcoded within its baking, this example
// will assume there exists some method to get modifiable access to the
// `Map<Fluid, FluidModel>` fluidModels returned by `FluidStateModelSet#bake`.
// We will also assume we have some Fluid EXAMPLE_FLUID* to attach the models to.
FluidModel.Unbaked exampleFluidModel = new FluidModel.Unbaked(
// The texture for the still fluid.
new Material(
// The relative identifier for the texture.
// Points to `assets/examplemod/textures/block/example_fluid_still.png`
Identifier.fromNamespaceAndPath("examplemod", "block/example_fluid_still"),
// When true, sets all faces using this texture key to
// always have a transparent pixel.
true
),
// The texture for the flowing fluid.
new Material(Identifier.fromNamespaceAndPath("examplemod", "block/example_fluid_flowing")),
// If not null, the texture for the overlay when the side of the fluid is
// occluded by a `HalfTransparentBlock` or `LeavesBlock`.
null,
// If not null, the tint source to apply to the fluid's texture when in
// the world.
null
);
// Assume we have access to the `MaterialBaker` materials.
FluidModel exampleBakedFluidModel = exampleFluidModel.bake(
// The baker to grab the atlas sprites for the materials.
materials,
// A supplied debug name to properly report which models have
// missing textures.
() -> "examplemod:example_fluid_model"
);
fluidModels.put(
// The fluid the model should be used by.
EXAMPLE_FLUID,
// The baked fluid model.
exampleBakedFluidModel
);
fluidModels.put(EXAMPLE_FLUID_FLOWING, exampleBakedFluidModel);
Name Tag Offsets
EntityRenderer#submitNameTag has been renamed to submitNameDisplay, now optionally taking in the y offset from the name tag attachment.
Tint Getter
BlockAndTintGetter is now a client only interface attached to the ClientLevel. It previous uses were replaced with BlockAndLightGetter – which BlockAndTintGetter now extends – with the tint and lighting directions stripped.
Pipeline Depth and Color
Depth and color methods defined in the RenderPipeline have been consolidated into two state objects.
The DepthTestFunction, write boolean, and the bias floats are now stored in DepthStencilState. DepthTestFunction has been replaced with a more generic CompareOp, which defines how to compare two numbers. Each function has an simple equivalent, with NO_DEPTH_TEST replaced by CompareOp#ALWAYS_PASS. The depth information can be added to the pipeline via RenderPipeline$Builder#withDepthStencilState.
The optional BlendFunction and color / alpha booleans are now stored in ColorTargetState. The booleans are consolidated into an int using the lower four bits as flags: 1 is red, 2 is green, 4 is blue, and 8 is alpha. The color boolean uses 7 for red, green, and blue; the alpha boolean uses 8; while both combined use 15. The LopicOp is removed entirely. The color information can be added to the pipeline via RenderPipeline$Builder#withColorTargetState.
public static final RenderPipeline EXAMPLE_PIPELINE = RenderPipeline.builder()
.withLocation(ResourceLocation.fromNamespaceAndPath("examplemod", "pipeline/example"))
.withVertexShader(ResourceLocation.fromNamespaceAndPath("examplemod", "example"))
.withFragmentShader(ResourceLocation.fromNamespaceAndPath("examplemod", "example"))
.withVertexFormat(DefaultVertexFormat.POSITION_TEX_COLOR, VertexFormat.Mode.QUADS)
.withShaderDefine("ALPHA_CUTOUT", 0.5)
.withSampler("Sampler0")
.withUniform("ModelOffset", UniformType.VEC3)
.withUniform("CustomUniform", UniformType.INT)
.withPolygonMode(PolygonMode.FILL)
.withCull(false)
// Sets the color target when writing the buffer data.
.withColorTargetState(new ColorTargetState(
// Specifies the functions to use when blending two colors with alphas together.
// Made up of the `SourceFactor` and `DestFactor`.
// First two are for RGB, the last two are for alphas.
// If the optional is empty, then blending is disabled.
Optional.of(BlendFunction.TRANSLUCENT),
// The mask determining what colors to write to the buffer.
// Represented as a four bit value
// 0001 - Write the red channel..
// 0010 - Write the green channel.
// 0100 - Write the blue channel.
// 1000 - Write the alpha channel.
ColorTargetState.WRITE_RED | ColorTargetState.WRITE_GREEN | ColorTargetState.WRITE_BLUE | ColorTargetState.WRITE_ALPHA
))
// Sets the depth stencil when writing the buffer data.
.withDepthStencilState(new DepthStencilState(
// Sets the depth test function to use when rendering objects at varying
// distances from the camera.
// Values:
// - ALWAYS_PASS (GL_ALWAYS)
// - LESS_THAN (GL_LESS)
// - LESS_THAN_OR_EQUAL (GL_LEQUAL)
// - EQUAL (GL_EQUAL)
// - NOT_EQUAL (GL_NOTEQUAL)
// - GREATER_THAN_OR_EQUAL (GL_GEQUAL)
// - GREATER_THAN (GL_GREATER)
// - NEVER_PASS (GL_NEVER)
CompareOp.LESS_THAN_OR_EQUAL,
// Whether to mask writing values to the depth buffer
false,
// The scale factor used to calculate the depth values for the polygon.
0f,
// The unit offset used to calculate the depth values for the polygon.
0f
))
.build()
;
Blaze3d Backends
CommandEncoder, GpuDevice, and RenderPassBackend has been split into the *Backend interface, which functions similarly to the previous interface, and the wrapper class, which holds the backend and provides delegate calls, performing any validation necessary. The *Backend interfaces now explicitly perform the operation without checking whether the operation is valid.
Solid and Translucent Features
Feature rendering has been further split into two passes: one for solid render types, and one for translucent render types. As such, most render methods now have a renderSolid and renderTranslucent method, respectively. Those which only render solid or translucent data only have one of the methods.
Camera State
The Camera has been updated similarly to other render state implementations where the camera is extracted to the CameraRenderState during GameRenderer#renderLevel, and that is passed around with the data required to either submit and render elements.
Due to this change, FogRenderer#setupFog now returns the FogData, containing all the information needed to render the fog, instead of just its color, and storing that in CameraRenderState#fogData.
- Some shaders within
assets/minecraft/shaders/corenow usetextureovertexelFetchentity.vshitem.vshrendertype_leash.vshrendertype_text.vshrendertype_text_background.vshrendertype_text_intensity.vsh
assets/minecraft/shaders/coreblock.vsh#minecraft_sample_lightmap->sample_lightmap.glsl#sample_lightmaprendertype_crumblingno longer takes intexCoord2(lightmap)rendertype_entity_alpha,rendertype_entity_decalmerged intoentity.fshusing aDissolveMaskSamplerrendertype_item_entity_translucent_cull->item, not one-to-onerendertype_translucent_moving_blockis removed- This now uses the the shaders provided by the
ChunkSectionLayer
- This now uses the the shaders provided by the
com.mojang.blaze3dGLFWErrorCapture- Captures errors during a GL process.GLFWErrorScope- A closable that defines the scope of the GL errors to capture.
com.mojang.blaze3d.openglGlProgram#BUILT_IN_UNIFORMS,INVALID_PROGRAMare now finalGlBackend- A GPU backend for OpenGL.GlCommandEncodernow implementsCommandEncoderBackendinstead ofCommandEncoder, the class now package-privategetDeviceis removed
GlConst#toGlnow takes in aCompareOpinstead of theDepthTestFunctionGlDevicenow implementsGpuDeviceBackendinstead ofGpuDevice, the class now package-private- The constructor now takes in a
GpuDebugOptionscontaining the log level, whether to use synchronous logs, and whether to use debug labels instead of those parameters being passed in directly
- The constructor now takes in a
GlRenderPassnow implementsRenderPassBackendinstead ofRenderPass, the class now package-private- The constructor now takes in the
GlDevice
- The constructor now takes in the
GlStateManager#_colorMasknow takes anintfor the color mask instead of fourbooleans
com.mojang.blaze3d.platformClientShutdownWatchdognow takes in theMinecraftinstanceDebugMemoryUntracker#untrackis removedGLX#make(T, Consumer)is removedNativeImagecomputeTransparency- Returns whether there is at least one transparent or translucent pixel in the image.- This crashes if the image’s area is greater than 512MiB, or 2GiB with color data.
isClosed- Whether the image is closed or deallocated.
Transparency- An object of whether some image has a translucent and/or transparent pixel.Windownow takes theGpuBackendinstead of theScreenManagercreateGlfwWindow- Directly creates the GLFW window with the provided settings.updateDisplay->updateFullscreenIfChanged, not one-to-oneisResized,resetIsResized- Handles whether the window has been resized.backend- Returns theGpuBackend.$WindowInitFailedconstructor is nowpublicfromprivate
WindowEventHandler#resizeDisplay->resizeGui
com.mojang.blaze3d.pipelineColorTargetState- A record containing the blend function and mask for the color.DepthStencilState- A record containing the data for the depth stencil.RenderPipelinenow takes in theColorTargetStateinstead of the optionalBlendFunction, color and alphabooleans, andLogicOp; and theDepthStencilStateinstead of theDepthTestFunction, depthboolean, and biasfloatsgetDepthTestFunction,isWriteDepth,getDepthBiasScaleFactor,getDepthBiasConstant->getDepthStencilState, not one-to-onegetColorLogic,getBlendFunction,isWriteColor,isWriteAlpha->getColorTargetState, not one-to-one$BuilderwithDepthTestFunction,withDepthWrite,withDepthBias->withDepthStencilState, not one-to-onewithBlend,withColorWrite,withColorLogic->withColorTargetState, not one-to-one
$Snippetnow takes in theColorTargetStateinstead of the optionalBlendFunction, color and alphabooleans, andLogicOp; and theDepthStencilStateinstead of theDepthTestFunctionand depthboolean
com.mojang.blaze3d.platformBackendOptions- A configuration for initializing the backend with.DepthTestFunction->CompareOp, not one-to-oneNO_DEPTH_TEST->CompareOp#ALWAYS_PASSEQUAL_DEPTH_TEST->CompareOp#EQUALLEQUAL_DEPTH_TEST->CompareOp#LESS_THAN_OR_EQUALLESS_DEPTH_TEST->CompareOp#LESS_THANGREATER_DEPTH_TEST->CompareOp#GREATER_THAN
GLX_initGlfwnow takes in theBackendOptionsglfwBool-1iftrue,0iffalse.
LogicOpenum is removed
com.mojang.blaze3d.shaders.GpuDebugOptions- The debug options for the GPU pipeline.com.mojang.blaze3d.systemsBackendCreationException- An exception thrown when the GPU backend couldn’t be created.CommandEncoder->CommandEncoderBackend- The original interface is now a class wrapper around the interface, delegating to the backend after performing validation checks
GpuBackend- An interface responsible for creating the used GPU device and window to display to.GpuDevice->GpuDeviceBackend- The original interface is now a class wrapper around the interface, delegating to the backend after performing validation checks
setVsync- Sets whether VSync is enabled.presentFrame- Swaps the front and back buffers of the window to display the present frame.isZZeroToOne- Whether the 0 to 1 Z range is used instead of -1 to 1.
RenderPass->RenderPassBackend- The original interface is now a class wrapper around the interface, delegating to the backend after performing validation checks
RenderSystempollEventsis now publicflipFrameno longer takes in theWindowinitRenderernow only takes in theGpuDevicelimitDisplayFPS->FramerateLimiter#limitDisplayFPSinitBackendSystemnow takes in theBackendOptions
com.mojang.blaze3d.vertexDefaultVertexFormat#BLOCKno longer takes in the normal vectorPoseStack#mulPose,$Pose#mulPosenow has an overload that takes in theTransformationQuadInstance- A class containing the color, light coordinates, and overlay of a quad.TlsfAllocator- A two-level segregate fit allocator for dynamic memory allocation.UberGpuBuffer- A buffer for uploading dynamically sized data to the GPU, used for chunk section layers.VertexConsumerputBulkData->putBlockBakedQuad,putBakedQuad; not one-to-one- Brightness
floatarray, colorfloats, lightmapintarray, and overlayintare replaced withQuadInstance putBlockBakedQuadreplaces thePoseStack$Posewith the XYZfloatblock position
- Brightness
addVertex(PoseStack$Pose, Vector3f)->addVertex(PoseStack$Pose, Vector3fc)setNormal(PoseStack$Pose, Vector3f)->setNormal(PoseStack$Pose, Vector3fc)
com.mojang.mathMatrixUtilcheckPropertyRawis nowpublicfromprivateisOrthonormalis removed
TransformationIDENTITYis nowpublicfromprivate- Replaces
identitymethod
- Replaces
getTranslation->translationgetLeftRotation->leftRotationgetScale->scalegetRightRotation->rightRotationcompose- Applies the transformation to the given matrix, if present.
net.minecraft.SharedConstantsDEBUG_DUMP_INTERPOLATED_TEXTURE_FRAMESis removedDEBUG_PREFER_WAYLAND- When true, prevents the platform initialization hint from being set to X11 if both Wayland and X11 are supported.
net.minecraft.clientCameraBASE_HUD_FOV- The base hud field-of-view.setup->update, not one-to-oneextractRenderState- Extract the state of the camera.getFov- Gets the field-of-view.getViewRotationMatrix- Gets the matrix for a projection view.setEntity- Sets the entity the camera is attached to.getNearPlanenow takes in thefloatfield-of-viewpanoramicForwards- The forward vector when in panorama mode.getPartialTickTimeis removedsetLevel- Sets the level the camera is in.getCameraEntityPartialTicks- Gets the partial tick based on the state of the entity.
DeltaTracker#advanceTimereplaced byadvanceGameTimewhen thebooleanwastrue, andadvanceRealTimeadvanceGameTime,advanceRealTimewere previouslyprivate, nowpublic
FramerateLimiter- A utility for limiting the framerate of the client.MinecraftnoRenderis removeduseAmbientOcclusionis removedgetBlockRendereris removedgetItemRendereris removed
OptionsgetCloudsType->getCloudStatusexclusiveFullscreen- Whentrue, fullscreen mode takes full control of the monitor.
net.minecraft.client.color.blockBlockColorreplaced byBlockTintSource, not one-to-onegetColor->colorInWorld,colorAsTerrainParticle; not one-to-one
BlockColorsgetColorreplaced bygetTintSources,getTintSource; not one-to-oneregisternow takes in a list ofBlockTintSources instead of aBlockColor
BlockTintSource- A source for how to tint aBlockStatein isolation or with context.BlockTintSources- Utilites for common block tint sources.
net.minecraft.client.data.modelsBlockModelGeneratorscreateSuffixedVariantnow takes in a function ofMaterialtoTextureMappingfor the textures instead of just anIdentifiercreateAirLikeBlocknow takes in aMaterialinstead of anIdentifierfor the particle texturegenerateSimpleSpecialItemModelnow takes in an optionalTransformationcreateChestnow has an overload that takes in theMutiblockChestResourcestextures
ItemModelGenerators#generateLayeredItemnow takes inMaterials instead ofIdentifiers for the textures
net.minecraft.client.data.models.modelItemModelUtilsspecialModelnow has overloads that take in theTransformationconditionalnow has overloads that take in theTransformationselectnow has an overload that takes in theTransformationselectBlockItemPropertynow has an overload that takes in theTransformation
TexturedModel#createAllSamenow takes in aMaterialinstead of anIdentifierfor the textureTextureMappingput,putForcednow take in aMaterialinstead of anIdentifierfor the texturegetnow returns aMaterialinstead of anIdentifierfor the texturecopyAndUpdatenow takes in aMaterialinstead of anIdentifierfor the textureupdateSlots- Replaces all slots using the provided mapper function.forceAllTranslucent- Sets the force translucency flag for all material textures.defaultTexture,cube,cross,plant,rail,wool,crop,singleSlot,particle,torch,cauldron,layer0now take in aMaterialinstead of anIdentifierfor the texturecolumn,door,layerednow take inMaterials instead ofIdentifiers for the texturesgetBlockTeture,getItemTexturenow return aMaterialinstead of anIdentifierfor the texture
net.minecraft.client.entity.ClientAvatarEntity#belowNameDisplay->Entity#belowNameDisplaynet.minecraft.client.guiFontdrawInBatch,drawInBatch8xOutlinenow take in aMatrix4fcinstead of aMatrix4ffor the pose$GlyphVisitor#forMultiBufferSourcenow takes in aMatrix4fcinstead of aMatrix4ffor the pose
Guirender*methods have been renamed toextract*render->extractRenderState$RenderFunctioninterface is removed
GuiGraphics->GuiGraphicsExtractorhLine->horizontalLinevLine->verticalLinerenderOutline->outlinedrawCenteredString->centeredTextdrawString->textdrawStringWithBackdrop->textWithBackdroprenderItem->itemrenderFakeItem->fakeItemrenderItemDecorations->itemDecorationssubmitMapRenderState->mapsubmitEntityRenderState->entitysubmitSkinRenderState->skinsubmitBookModelRenderState->booksubmitBannerPatternRenderState->bannerPatternsubmitSignRenderState->signsubmitProfilerChartRenderState->profilerChartrenderTooltip->tooltiprenderComponentHoverEffect->componentHoverEffect, nowprivateinstead ofpublic
net.minecraft.client.gui.components- Most methods that begin with
render*ordraw*have been renamed to eitherextract*orextract*RenderStatedepending on usage. AbstractWidget#renderWidget->extractWidgetRenderStateDebugScreenOverlay#render3dCrosshairnow takes in theCameraRenderStateinstead of theCamera, and the gui scaleintLogoRenderer#renderLogo->extractRenderStatePlayerFaceRenderer->PlayerFaceExtractordraw->extractRenderState
Renderable#render->extractRenderStateStringWidget#clipText->ComponentRenderUtils#clipTextTextCursorUtils#draw*->extract*
- Most methods that begin with
net.minecraft.client.gui.components.debugchartAbstractDebugChartdrawChart->extractRenderStatedrawDimensions->extractSampleBarsdrawMainDimension->extractMainSampleBardrawAdditionalDimensions->extractAdditionalSampleBarsrenderAdditionalLinesAndLabels->extractAdditionalLinesAndLabelsdrawStringWithShade->extractStringWithShade
ProfilerPieChart#render->extractRenderState
net.minecraft.client.gui.components.spectator.SpectatorGui#render*->extract*net.minecraft.client.gui.components.toastsNowPlayingToast#renderToast->extractToastToast#render->extractRenderStateToastManager,$ToastInstance#render->extractRenderStateTutorialToast$Icons#render->extractRenderState
net.minecraft.client.gui.contextualbar.ContextualBarRendererrenderBackground->extractBackgroundrender->extractRenderStaterenderExperienceLevel->extractExperienceLevel
net.minecraft.client.gui.fontPlainTextRenderable#renderSpritenow takes in aMatrix4fcinstead of aMatrix4ffor the poseTextRenderable#rendernow takes in aMatrix4fcinstead of aMatrix4ffor the pose
net.minecraft.client.gui.renderDynamicAtlasAllocator- An allocator for handling a dynamically sized texture atlas.GuiItemAtlas- An atlas for all items displayed in a user interface.GuiRenderer#incrementFrameNumber->endFrame, not one-to-one
net.minecraft.client.gui.render.state.*->.client.rendererer.state.gui.*GuiItemRenderStateno longer takes in theStringnamenameis removed
net.minecraft.client.gui.render.state.pip.*->.client.rendererer.state.gui.pip.*net.minecraft.client.gui.screensLevelLoadingScreen#renderChunks->extractChunksForRenderingScreenrenderWithTooltipAndSubtitles->extractRenderStateWithTooltipAndSubtitlesrenderBackground->extractBackgroundrenderBlurredBackground->extractBlurredBackgroundrenderPanorama->extractPanoramarenderMenuBackground->extractMenuBackgroundrenderMenuBackgroundTexture->extractMenuBackgroundTexturerenderTransparentBackground->extractTransparentBackground
net.minecraft.client.gui.screens.advancementsAdvancementTab#draw*->extract*AdvancementTabTypedraw->extractRenderStatedrawIcon->extractIcon
AdvancementWidgetdraw->extractRenderStatedraw*->extract*
net.minecraft.client.gui.screens.inventory- Most methods that begin with
render*ordraw*have been renamed to eitherextract*orextract*RenderStatedepending on usage. AbstractContainerScreenrenderContents->extractContentsrenderCarriedItem->extractCarriedItemrenderSnapbackItem->extractSnapbackItemrenderSlots->extractSlotsrenderTooltip->extractTooltiprenderLabels->extractLabelsrenderBgreplaced byScreen#extractBackgroundrenderSlot->extractSlot
AbstractMountInventoryScreen#drawSlot->extractSlotAbstractSignEditScreen#renderSignBackground->extractSignBackgroundCyclingSlotBackground#render->extractRenderStateEffectsInInventory#render->extractRenderStateInventoryScreen#renderEntityInInventoryFollowsMouse->extractEntityInInventoryFollowsMouseItemCombinerScreen#renderErrorIcon->extractErrorIcon
- Most methods that begin with
net.minecraft.client.gui.screens.inventory.tooltipClientTooltipComponentrenderText->extractTextrenderImage->extractImage
TooltipRenderUtil#renderTooltipBackground->extractTooltipBackground
net.minecraft.client.gui.screens.optionsDifficultyButtonsis now a record that takes in theLayoutElement,CycleButtonfor the difficulty, theLockIconButton, and the currentLevelcreatenow takes in theLeveland returns theDifficultyButtonsinstead of aLayoutElementrefresh- Sets the data of the held button components.
HasDifficultyReaction- An interface that responds to when the difficulty has changed.OptionsScreennow implementsHasDifficultyReactionWorldOptionsScreennow implementsHasDifficultyReaction- The constructor now takes in the
Level
- The constructor now takes in the
net.minecraft.client.gui.screens.recipebookGhostSlotsrender->extractRenderStaterenderTooltip->extractTooltip
RecipeBookComponent#render*->extract*RecipeBookPagerender->extractRenderStaterenderTooltip->extractTooltip
net.minecraft.cilent.gui.screens.reporting.ChatSelectionScreen$ChatSelectionList#renderItem->extractItemnet.minecraft.client.gui.screens.worldselection.AbstractGameRulesScreen$GameRuleEntry#renderLabel->extractLabelnet.minecraft.client.gui.spectator.SpectatorMenuItem#renderIcon->extractIconnet.minecraft.client.model.Model#renderTypenow has an overload that returns the passed in functionnet.minecraft.client.model.object.book.BookModel$Stateno longer takes in the animation pos, and moves the openfloatto the first parameterforAnimation- Gets the current state of the animation for the book based on the progress.
net.minecraft.client.model.object.statue.CopperGolemStatueModelnow usesUnitfor the generic instead ofDirectionnet.minecraft.client.multiplayer.ClientLevelnow implementsBlockAndTintGetterupdate- Updates the lighting of the level.
net.minecraft.client.multiplayer.chat.GuiMessageTag$Icon#draw->extractRenderStatenet.minecraft.client.particleParticle#getLightColor->getLightCoordsSimpleVerticalParticle- A particle that moves vertically.SingleQuadParticle$LayerTERRAIN->OPAQUE_TERRAIN,TRANSLUCENT_TERRAINITEMS->OPAQUE_ITEMS,TRANSLUCENT_ITEMSbySprite- Gets the layer from the atlas sprite.
net.minecraft.client.rendererCachedOrthoProjectionMatrixBuffer,CachedPerspectiveProjectionMatrixBuffer,PerspectiveProjectionMatrixBuffer->ProjectionMatrixBufferwith sometimesProjection, not one-to-oneCloudRenderernow takes in the cloud rangeintCubeMapno longer takes in theMinecraftinstanceGameRenderernow takes in theModelManagerinstead of theBlockRenderDispatcherPROJECTION_Z_NEAR->Camera#PROJECTION_Z_NEARsetPanoramicScreenshotParameters,getPanoramicScreenshotParameters->Camera#enablePanoramicMode,disablePanoramicMode; not one-to-oneisPanoramicMode->Camera#isPanoramicModegetProjectionMatrix->Camera#getViewRotationProjectionMatrix, not one-to-oneupdateCamera->Camera#update, not one-to-onegetRenderDistanceis removedcubeMap->GuiRenderer#cubeMap, nowprivatefromprotectedgetDarkenWorldAmount->getBossOverlayWorldDarkeninglightTexture->lightmap,levelLightmap; not one-to-onegetLevelRenderStatereplaced bygetGameRenderState, returning theGameRenderStateinstead of theLevelRenderStatepick->Minecraft#pick, nowprivatefrompublicrendersplit betweenupdate,extract, andrender; with thebooleannow taking in whether to advance the game time rather than render the level
GlobalSettingsUniformnow takes in theVec3camera position instead of the mainCameraitselfItemBlockRenderTypesis removedgetChunkRenderType,getMovingBlockRenderTypenow stored withinBakedQuad$SpriteInfogetRenderLayer(FluidState)->FluidModel#layer, not one-to-onesetCutoutLeavesis removed- This should be obtained directly from the options
MultiblockChestResources- A record containing some data based on theChestType.LevelRenderernow takes in theGameRenderStateinstaed of theLevelRenderStateupdate- Updates the level.renderLevelnow takes in theCameraRenderStateinstead of theCamera, aMatrix4fcinstead of aMatrix4ffrom the model view, and theChunkSectionsToRender; it no longer takes in theMatrix3ffor the projection matricesextractLevel- Extracts the level state.prepareChunkRendersis nowpublicinstead ofprivatecaptureFrustum,killFrustum,getCapturedFrustumare removedgetLightColor->getLightCoords, now taking in theBlockAndLightGetterinstead of theBlockAndTintGetter$BrightnessGetter#packedBrightnessnow takes in theBlockAndLightGetterinstead of theBlockAndTintGetter
LightTexture->Lightmaptick->LightmapRenderStateExtractor#tickupdateLightTexture->renderpack->LightCoordsUtil#packblock->LightCoordsUtil#blocksky->LightCoordsUtil#skylightCoordsWithEmission->LightCoordsUtil#lightCoordsWithEmission
MaterialMapper->SpriteMapperOrderedSubmitNodeCollectorsubmitBlockis removedsubmitBlockModelnow takes in a list ofBlockStateModelParts instead of theBlockStateModel, and an array ofints (array of tint colors) instead of threefloats for a single colorsubmitItemno longer takes in theRenderTypesubmitModelnow has overloads that takes in theIdentifierfor the texture, or aSpriteIdwith theSpriteGetteralong with aninttint colorsubmitBreakingBlockModel- Submits the block breaking overlay.
PanoramaRendererreplaced byPanoramaregisterTextures->GuiRenderer#registerPanoramaTexturesrender->extractRenderState
PanoramicScreenshotParametersrecord is removedPostChainnow takes in aProjectionandProjectionMatrixBufferinstead of anCachedOrthoProjectionMatrixBufferloadnow takes in aProjectionandProjectionMatrixBufferinstead of anCachedOrthoProjectionMatrixBuffer
RenderPipelinesENTITY_CUTOUT_NO_CULL->ENTITY_CUTOUT- The original cutout with cull is replaced by
ENTITY_CUTOUT_CULL
- The original cutout with cull is replaced by
ENTITY_CUTOUT_NO_CULL_Z_OFFSET->ENTITY_CUTOUT_Z_OFFSETENTITY_SMOOTH_CUTOUT->END_CRYSTAL_BEAMENTITY_NO_OUTLINEreplaced byENTITY_TRANSLUCENT, render type constructed with affects outline being falseENTITY_DECAL,DRAGON_EXPLOSION_ALPHA->ENTITY_CUTOUT_DISSOLVE, not one-to-oneITEM_ENTITY_TRANSLUCENT_CULL->ENTITY_TRANSLUCENT_CULL,ITEM_CUTOUT,ITEM_TRANSLUCENT; not one-to-oneTRANSLUCENT_MOVING_BLOCKreplaced byTRANSLUCENT_BLOCKBANNER_PATTERN- A pipeline for rendering the patterns on a banner.
ScreenEffectRenderer#renderScreenEffectnow takes inbooleans for whether the player is in first person and whether to hide the GUISheets*CHEST_*LOCATION*have been combined into one of theCHEST_*fields based on what the resource was fortranslucentBlockSheet- A cullable entity item translucent render type using the block atlas.cutoutBlockItemSheet- An item cutout render type using the block atlas.bannerSheet->RenderTypes#entityTranslucent, not one-to-onecutoutItemSheet- An item cutout render type using the item atlas.get*Material->get*SpritechooseMaterial->chooseSprite
SpecialBlockModelRendererreplaced byBuiltInBlockModels, not one-to-onerenderByBlock->BlockModelRenderState#submit*, not one-to-one
SubmitNodeCollectiongetBlockSubmitsis removedgetBreakingBlockModelSubmits- Gets the submitted breaking block overlay.
SubmitNodeCollector$ParticleGroupRendererisEmpty- Whether there are no particles to render in this group.preparenow takes whether the particles are being prepared for the translucent layerrenderno longer takes in the translucentboolean
SubmitNodeStorage$BlockModelSubmitnow takes in a list ofBlockStateModelParts instead of theBlockStateModel, and an array ofints (array of tint colors) instead of threefloats for a single color$BlockSubmitis removed$BreakingBlockModelSubmit- A record containing the information to render the block breaking overlay.$ItemSubmitno longer takes in theRenderType$MovingBlockSubmit,$NameTagSubmit,$ShadowSubmit,$TextSubmitnow take in aMatrix4fcinstead of aMatrix4ffor the pose
VirtualScreenreplaced byGpuBackend
net.minecraft.client.renderer.blockBlockAndTintGetter- A getter for positional block tinting (e.g., biomes).BlockModelRenderState- The render state for a block model.BlockModelResolver- A helper for setting up the render state for aBlockState.BlockModelSet- Holds theBlockModelassociated with eachBlockState.BlockModelShaper->BlockStateModelSet, not one-to-onegetParticleIcon->getParticleMaterial, now returning aMaterial$Bakedinstead of aTextureAtlasSpritegetBlockModel->getgetModelManager,replaceCacheare removed
BlockQuadOutput- A functional interface for writing the baked quad information to some output, like a buffer.BlockRenderDispatcherclass is removedgetBlockModelShaper->getModelSet, not one-to-onerenderBreakingTexturereplaced withSubmitNodeCollector#submitBreakingBlockModelrenderBatchedreplaced with direct call toModelBlockRenderer#tesselateBlockrenderLiquidreplaced with direct call toFluidRenderer#tesselaterenderSingleBlockis now inlined withinBlockFeatureRenderer#renderBlockModelSubmits, aprivatemethod- Use
ModelBlockRenderer#tesselateBlockas an alternative
- Use
FluidModel- The base fluid model that holds the data for the renderer.FluidStateModelSet- Holds theFluidModelassociated with eachFluid.LoadedBlockModels- A task for baking theBlockModelfor eachBlockState.LiquidBlockRenderer->FluidRenderer, not one-to-one- The constructor now takes in the
FluidStateModelSetinstead of theSpriteGetter tesselatenow takes in aFluidRenderer$Outputinstead of aVertexConsumer$Output- Gets theVertexConsumerto use for theChunkSectionLayer.
- The constructor now takes in the
ModelBlockRenderernow takes inbooleans for ambient occlusion and cullingtesselateBlocknow takes in aBlockQuadOutputinstead of aVertexConsumer, the XYZfloats instead of aPoseStack, theBlockStateModelinstead of the list ofBlockModelParts, no longer takes in the cullbooleanandintoverlay, and takes in the seedlongtesselateWithAO->tesselateAmbientOcclusion, nowprivateinstead ofpublictesselateWithoutAO->tesselateFlat, nowprivateinstead ofpublicrenderModelis now inlined withinBlockFeatureRenderer#renderBlockModelSubmits, aprivatemethodforceOpaque- Whether the block textures should be opaque instead of translucent.enableCaching->BlockModelLighter$Cache#enableclearCache->BlockModelLighter$Cache#disable$AdjacencyInfo->BlockModelLighter$AdjacencyInfo, nowprivateinstead ofprotected$AmbientOcclusionRenderStorageis replaced byBlockModelLighter, not one-to-one$AmbientVertexRemap->BlockModelLighter$AmbientVertexRemap$Cache->BlockModelLighter$Cache$CommonRenderStorageis replaced byBlockModelLighter, not one-to-one$SizeInfo->BlockModelLighter$SizeInfo
MovingBlockRenderState#level->cardinalLighting,lightEngine; not one-to-oneSelectBlockModel- A block model that determined or selected by its resolved property.
net.minecraft.client.renderer.block.modelBakedQuad->.client.resources.model.geometry.BakedQuad- The constructor now takes in a
$MaterialInfoinstead of theTextureAtlasSprite,inttint index,intlight emission, andbooleanshade FLAG_TRANSLUCENT- A flag that marks the baked quad has having translucency.FLAG_ANIMATED- A flag that marks the baked quad has having an animated texture.isTinted->$MaterialInfo#isTinted$MaterialFlags- An annotation that marks whether a given integer defines the flags for a material.$MaterialInfo- A record holding the information on how to render the quad.
- The constructor now takes in a
BlockDisplayContext- An object that represents the display context of a block.BlockElement->.client.resources.model.cuboid.CuboidModelElementBlockElementFace->.client.resources.model.cuboid.CuboidFaceBlockElementRotation->.client.resources.model.cuboid.CuboidRotationBlockModel- The base block model that updates the render state for use outside the world context.- The original implementation has been moved to
.client.resources.model.cuboid.CuboidModel
- The original implementation has been moved to
BlockModelDefinition->.block.dispatch.BlockStateModelDispatcherBlockModelPart->.block.dispatch.BlockStateModelPartparticleIcon->particleMaterial, now returning aMaterial$Bakedinstead of aTextureAtlasSpritematerialFlags- Handles the flags for the material(s) used by the model.
BlockStateModel->.block.dispatch.BlockStateModelparticleIcon->particleMaterial, now returning aMaterial$Bakedinstead of aTextureAtlasSpritematerialFlags,hasMaterialFlag- Handles the flags for the material(s) used by the model.
BlockStateModelWrapper- The basic block model that contains the model, tints, and transformation.CompositeBlockModel- Overlays multiple block models together.ConditionalBlockModel- A block model that shows a different model based on a boolean obtained from some property.EmptyBlockModel- A block model that shows nothing.FaceBakery->.client.resources.model.cuboid.FaceBakerybakeQuadoverload now takes in aModelBakerinstead of theModelBaker$PartCache, and aMaterial$Bakedinstead of aTextureAtlasSprite- It also has an overload taking in the fields of the
BlockElementFaceinstead of the object itself
- It also has an overload taking in the fields of the
- Another
bakedQuadovrload now takes in theBakedQuad$MaterialInfoinstead of theinttint index and light emission, and the shadeboolean
ItemModelGenerator->.client.resources.model.cuboid.ItemModelGeneratorItemTransform->.client.resources.model.cuboid.ItemTransformItemTransforms->.client.resources.model.cuboid.ItemTransformsSimpleModelWrapper->.client.resources.model.SimpleModelWrapper- The constructor now takes in a
Material$Bakedinstead of aTextureAtlasSpritefor the particle
- The constructor now takes in a
SimpleUnbakedGeometry->.client.resources.model.cuboid.UnbakedCuboidGeometrySingleVariant->.block.dispatch.SingleVariantSpecialBlockModelWrapper- A block model for models that submit their elements throughSpecialModelRenderers.TextureSlots->.client.resources.model.sprite.TextureSlotsVariant->.block.dispatch.VariantVariantMutator->.block.dispatch.VariantMutatorVariantSelector->.block.dispatch.VariantSelector
net.minecraft.client.renderer.block.model.multipart.*->.block.dispatch.multipart.*net.minecraft.client.renderer.block.model.properties.conditionalConditionalBlockModelProperty- A property that computes somebooleanfrom theBlockState.IsXmas- Returns whether the current time is between December 24th - 26th.
net.minecraft.client.renderer.block.model.properties.selectDisplayContext- A case based on the currentBlockDisplayContext.SelectBlockModelProperty- A property that computes some switch state from theBlockState.
net.minecraft.client.renderer.blockentityAbstractEndPortalRendererrenderCube->submitCube, nowprotectedandstaticfromprivatesubmitSpecial- Submits the end portal cube, used by the special renderer.getExtents- Gets the vertices of each face.getOffsetUp,getOffsetDownare removedrenderTypeis removed
AbstractSignRenderernow takes in a generic for theSignRenderStategetSignModelnow takes in theSignRenderStategeneric instead of theBlockStateandWoodTypegetSignModelRenderScale,getSignTextRenderScale,getTextOffset,translateSignreplaced bySignRenderState#transformations,SignRenderState$SignTransformationsgetSignMaterial->getSignSprite
BannerRendererTRANSFORMATIONS- The transformations to apply when on the wall or ground.submitPatternsno longer takes in the baseSpriteId, whether the pattern has foil, and the outline colorsubmitSpecialnow takes in theBannerBlock$AttachmentType
BedRenderersubmitSpecialis removed- This is replaced by calling
submitPiecetwice, or making a composite for each bed part via theBedSpecialRenderer
- This is replaced by calling
submitPieceis nowpublicfromprivate, taking in theBedPartinstead of theModel$Simple,Direction, or thebooleanof whether to translate in the Z directiongetExtentsnow takes in theBedPartmodelTransform- Gets the transformation for the givenDirection.
BlockEntityRenderDispatchernow takes in theBlockModelResolverinstead of theBlockRenderDispatcher, and no longer takes in theItemRendererpreparenow takes in aVec3camera position instead of theCameraitself
BlockEntityRendererProvider$Contextnow takes in theBlockModelResolverinstead of theBlockRenderDispatcher, and no longer takes in theItemRenderermaterials->sprites
ChestRendererLAYERS- Holds the model layers of the chest.modelTransformation- Gets the transformation for the givenDirection.
ConduitRenderer#DEFAULT_TRANSFORMATION- The default transformation to apply.CopperGolemStatueBlockRenderer#modelTransformation- Gets the transformation for the givenDirection.DecoratedPotRenderer#modelTransformation- Gets the transformation for the givenDirection.HangingSignRenderernow uses aHangingSignRenderStateMODEL_RENDER_SCALEis nowprivatefrompublicTRANSFORMATIONS- The transformations to apply when on the wall or ground.translateBase->baseTransformation, nowprivatefrompublic$AttachmentType->HangingSignBlock$AttachmentbyBlockState->$Models#get
$ModelKeyrecord is removed
ShulkerBoxRenderermodelTransform- Gets the transformation for the givenDirection.getExtentsno longer takes in theDirection
SignRenderer->StandingSignRendererTRANSFORMATIONS- The transformations to apply when on the wall or ground.createSignModelnow takes in aPlainSignBlock$Attachmentinstead of abooleanfor whether the block is standing
SkullBlockRendererTRANSFORMATIONS- The transformations to apply when on the wall or ground.submitSkullno longer takes in theDirectionorfloatrotation
WallAndGroundTransformations- A class that holds a map ofDirections to transforms to apply for the wall, and anintfunction to compute the ground transformations, with theintsegments generally acting as the number of rotation states.
net.minecraft.client.renderer.blockentity.stateBannerRenderStateangle->transformation, not one-to-onestanding->attachmentType, not one-to-one
BedRenderState#isHead->part, not one-to-oneBlockEntityRenderState#blockStateis nowprivatefrompublicChestRenderState#angle->facing, not one-to-oneCondiutRenderState->ConduitRenderStateCopperGolemStatueRenderState#oxidationState- The current oxidation state.HangingSignRenderState- The render state for the hanging sign.ShelfRenderState#facing- The direction the shelf is facing.SignRenderState#woodType- The type of wood the sign is made of.SkullblockRenderState#direction,rotationDegrees->transformation, not one-to-oneStandingSignRenderState- The render state for the standing sign.
net.minecraft.client.renderer.chunkChunkSectionLayernow takes in abooleanfor whether the layer is translucent rather than just sorting on uploadbyTransparency- Gets the layer by its transparency setting.sortOnUpload->translucent, not one-to-onevertexFormat- The vertex format of the pipeline used by the layer.
ChunkSectionsToRender#drawsPerLayer->drawGroupsPerLayer, with its value being aintto list of draws mapCompiledSectionMeshuploadMeshLayerreplaced byisVertexBufferUploaded,setVertexBufferUploadeduploadLayerIndexBufferreplaced byisIndexBufferUploaded,setIndexBufferUploaded
RenderRegionCache#createRegionnow takes in theClientLevelinstead of theLevelSectionBuffers->SectionRenderDispatcher$RenderSectionBufferSlice, not one-to-oneSectionCompilernow takes in thebooleans for ambient occlusion and cutout leaves, theBlockStateModelSet, theFluidStateModelSet, and theBlockColorsinstead of theBlockRenderDispatcherSectionMeshgetBuffers->getSectionDraw, not one-to-one$SectionDraw- The draw information for the section.
SectionRenderDispatchernow takes in theSectionCompilerinstead of theBlockRenderDispatcherandBlockEntityRenderDispatchergetRenderSectionSlice- Gets the buffer slice of the section mesh to render for the chunk layer.uploadAllPendingUploads->uploadGlobalGeomBuffersToGPU, not one-to-onelock,unlock- Handles locking the dispatcher when copying data from location to another, usually for GPU allocation.getToUploadis removedsetLevelnow takes in theSectionCompiler$RenderSectionupload,uploadSectionIndexBuffer->addSectionBuffersToUberBuffer, now private$CompileTaskdoTasknow returns a$SectionTaskResultinstead of aCompletableFuture
$SectionTaskResult->$RenderSection$CompileTask$SectionTaskResult
net.minecraft.client.renderer.culling.Frustumnow takes in aMatrix4fcinstead of aMatrix4ffor the model viewset- Copies the information from another frustum.
net.minecraft.client.renderer.entityAbstractBoatRenderernow takes in theIdentifiertexturerenderTypeis removed
AbstractMinecartRendererBLOCK_DISPLAY_CONTEXT- The context of how to display the block inside the minecart.submitMinecartContentsnow takes in aBlockModelRenderStateinstead of theBlockState
CopperGolemRenderer#BLOCK_DISPLAY_CONTEXT- The context of how to display the antenna block.DisplayRendererBLOCK_DISPLAY_CONTEXT- The context of how to display the displayed block.blockModelResolver- The block model resolver.
EndermanRenderer#BLOCK_DISPLAY_CONTEXT- The context of how to display the held block.EntityRenderDispatchernow takes in theBlockModelResolverinstead of theBlockRenderDispatcherEntityRenderer#submitNameTag->submitNameDisplay, now optionally taking in the y positionintas an offset from the name tag attachmentEntityRendererProvider$Contextnow takes in theBlockModelResolverinstead of theBlockRenderDispatchergetMaterials->getSpritesgetBlockRenderDispatcherreplaced bygetBlockModelResolver
IronGolemRenderer#BLOCK_DISPLAY_CONTEXT- The context of how to display the held block.ItemFrameRenderer#BLOCK_DISPLAY_CONTEXT- The context of how to display the displayed block.ItemRendererclass is removed- Use the
ItemStackRenderStateto submit elements to the feature dispatcher instead ENCHANTED_GLINT_ARMOR->ItemFeatureRenderer#ENCHANTED_GLINT_ARMORENCHANTED_GLINT_ITEM->ItemFeatureRenderer#ENCHANTED_GLINT_ITEMNO_TINT->ItemFeatureRenderer#NO_TINTgetFoilBuffer->ItemFeatureRenderer#getFoilBuffergetFoilRenderType->ItemFeatureRenderer#getFoilRenderType, nowpublicfromprivate
- Use the
MushroomCowRenderer#BLOCK_DISPLAY_CONTEXT- The context of how to display the attached blocks.SnowGolemRenderer#BLOCK_DISPLAY_CONTEXT- The context of how to display the head block.TntRenderer#BLOCK_DISPLAY_CONTEXT- The context of how to display the TNT block.TntMinecartRenderer#submitWhiteSolidBlocknow takes in aBlockModelRenderStateinstead of theBlockState
net.minecraft.client.renderer.entity.layersBlockDecorationLayernow takes in a function that returns aBlockModelRenderStateinstead of an optionalBlockStateMushroomCowMushroomLayerno longer takes in theBlockRenderDispatcherSnowGolemHeadLayerno longer takes in theBlockRenderDispatcher
net.minecraft.client.renderer.entity.stateAvatarRenderState#scoreText->EntityRenderState#scoreTextBlockDisplayEntityRenderState#blockRenderState->blockModel, now aBlockModelRenderStateinstead of aBlockRenderStateCopperGolemRenderState#blockOnAntennanow aBlockModelRenderStateinstead of an optionalBlockStateEndermanRenderState#carriedBlocknow aBlockModelRenderStateinstead of a nullableBlockStateIronGolemRenderState#flowerBlock- The flower held by the iron golem.ItemFrameRenderState#frameModel- The model of the item frame block.MinecartRenderState#displayBlockState->displayBlockModel, now aBlockModelRenderStateinstead of aBlockStateMushroomCowRenderState#mushroomModel- The model of mushrooms attached to the cow.SnowGolemRenderState#hasPumpkin->headBlock, now aBlockModelRenderStateinstead of abooleanTntRenderState#blockStatenow aBlockModelRenderStateinstead of a nullableBlockState
net.minecraft.client.renderer.features- Feature
rendermethods have been split intorenderSolidfor solid render types, andrenderTranslucentfor see-through render types - Some
render*methods now take in theOptionsRenderState BlockFeatureRendererrenderSolidnow takes in theBlockStateModelSetinstead of theBlockRenderDispatcherrenderTranslucentnow takes in theBlockStateModelSetand the crumblingMultiBufferSource$BufferSourceinstead of theBlockRenderDispatcher
FeatureRenderDispatchernow takes in theGameRenderStateandModelManagerrenderAllFeatureshas been split intorenderSolidFeaturesandrenderTranslucentFeatures- The original method now calls both of these methods, first solid then translucent
clearSubmitNodes- Clears the submit node storage.renderTranslucentParticles- Renders collected translucent particles.
FlameFeatureRenderer#render->renderSolidLeashFeatureRenderer#render->renderSolidNameTagFeatureRenderer#render->renderTranslucentShadowFeatureRenderer#render->renderTranslucentTextFeatureRenderer#render->renderTranslucent
- Feature
net.minecraft.client.renderer.fogFogData#color- The color of the fog.FogRenderersetupFognow returns aFogDatainstead of theVector4ffog colorupdateBuffer- Updates the buffer with the fog data.
net.minecraft.client.renderer.gizmos.DrawableGizmoPrimitives#rendernow takes in aMatrix4fcinstead of aMatrix4ffor the model viewnet.minecraft.client.renderer.itemBlockModelWrapper->CuboidItemModelWrapper- The constructor no longer takes in the
RenderTypefunction, and now takes in theMatrix4fctransformation $Unbakednow takes in an optionalTransformation
- The constructor no longer takes in the
CompositeModel$Unbakednow takes in an optionalTransformationConiditionalItemModel$Unbakednow takes in an optionalTransformationItemModel$BakingContextmaterials->spritesmissingItem- Gets the missing item model with the givenMatrix4fctransformation.
$Unbaked#bakenow takes in theMatrix4fctransformation from any parent client items
ItemStackRenderStatepickParticleIcon->pickParticleMaterial, now returning aMaterial$Bakedinstead of aTextureAtlasSprite$LayerRenderStateEMPTY_TINTS- Anintarray representing no tints to apply.setRenderTypeis removedsetParticleIcon->setParticleMaterial, now taking aMaterial$Bakedinstead of aTextureAtlasSpritesetTransform->setItemTransformsetLocalTransform- Sets the client item transform that’s applied after item display transforms.prepareTintLayers->tintLayers, not one-to-one
MissingItemModel#withTransform- Gets a missing item model with the given transform.ModelRenderProperties#particleIcon->particleMaterial, now taking aMaterial$Bakedinstead of aTextureAtlasSpriteRangeSelectItemModel$Unbakednow takes in an optionalTransformationSelectItemModel$ModelSelector#getno longer supports nullableItemModels.$Unbakednow takes in an optionalTransformation$UnbakedSwitch#bakenow takes in theMatrix4fctransformation
SpecialModelWrappernow takes in theMatrix4fctransformation$Unbakednow takes in an optionalTransformation
net.minecraft.client.renderer.rendertypeRenderType#outputTarget- Gets the output target.RenderTypesMOVING_BLOCK_SAMPLERreplaced bycreateMovingBlockSetup, nowprivateentityCutoutNoCull->entityCutout- The original cutout with cull is replaced by
entityCutoutCull
- The original cutout with cull is replaced by
entityCutoutNoCullZOffset->entityCutoutZOffsetentitySmoothCutout->endCrystalBeamentityNoOutline->entityTranslucentwithaffectsOutlineasfalseentityDecal,dragonExplosionAlpha->entityCutoutDissolve, not one-to-oneitemEntityTranslucentCull->entityTranslucentCullItemTarget,itemCutout,itemTranslucent; not one-to-onebannerPattern- The render type for rendering the patterns of banners.
net.minecraft.client.renderer.specialBannerSpecialRenderer,$Unbakednow take in theBannerBlock$AttachmentType$Unbakednow usesBannerPatternLayersfor the generic
BedSpecialRenderer,$Unbakednow take in theBedPart$Unbakednow implementsNoDataSpecialModelRenderer$Unbaked
BellSpecialRenderer- A special renderer for the bell.BookSpecialRenderer- A special renderer for the book on the enchantment table.ChestSpecialRenderer$Unbakednow implementsNoDataSpecialModelRenderer$Unbaked- The constructor now takes in the
ChestType *_CHEST_TEXTUREis removed from the field name, now aMultiBlockChestResourcesENDER_CHEST_TEXTURE->ENDER_CHEST
- The constructor now takes in the
ConduitSpecialRenderer$Unbakednow implementsNoDataSpecialModelRenderer$UnbakedCopperGolemStatueSpecialRenderer$Unbakednow implementsNoDataSpecialModelRenderer$UnbakedDecoratedPotSpecialRenderer$Unbakednow usesPotDecorationsfor the genericEndCubeSpecialRenderer- A special renderer for the end portal cube.HangingSignSpecialRenderer$Unbakednow implementsNoDataSpecialModelRenderer$Unbaked- The constructor now takes in the
HangingSignBlock$Attachment
- The constructor now takes in the
NoDataSpecialModelRenderersubmitno longer takes in theItemDisplayContext$Unbaked- The unbaked renderer for a special model renderer not needing extracted data.
PlayerHeadSpecialRenderer$Unbakednow usesPlayerSkinRenderCache$RenderInfofor the genericShieldSpecialRendererDEFAULT_TRANSFORMATION- The default transformation to apply.$Unbakednow usesDataComponentMapfor the generic
ShulkerBoxSpecialRenderer,$Unbakedno longer takes in theDirectionorientation$Unbakednow implementsNoDataSpecialModelRenderer$Unbaked
SkullSpecialRenderer$Unbakednow implementsNoDataSpecialModelRenderer$UnbakedSpecialModelRenderersubmitno longer takes in theItemDisplayContext$BakingContextmaterials->sprites$Simplereplaced byBlockModel$BakingContext,ItemModel$BakingContextmaterials->sprites
$Unbakednow has the generic of the argument to extract from the representing object
SpecialModelRenderers#createBlockRenderers->BuiltInBlockModels#createBlockModels, not one-to-oneStandingSignSpecialRenderer$Unbakednow implementsNoDataSpecialModelRenderer$Unbaked- The constructor now takes in the
PlainSignBlock$Attachment
- The constructor now takes in the
TridentSpecialRendererDEFAULT_TRANSFORMATION- The default transformation to apply.$Unbakednow implementsNoDataSpecialModelRenderer$Unbaked
net.minecraft.client.renderer.state.*->.state.level.*net.minecraft.client.renderer.stateGameRenderState- The render state of the game.OptionsRenderState- The render state of the client user options.WindowRenderState- The render state of the game window.
net.minecraft.client.renderer.state.gui.GuiRenderState#submit*methods have been renamed toadd*net.minecraft.client.renderer.state.levelBlockBreakingRenderStateis now a record, and no longer extendsMovingBlockRenderState- The constructor takes in the
BlockPos,BlockState, and the currentintprogress
- The constructor takes in the
CameraEntityRenderState- The render state for the camera entity.CameraRenderStatexRot,yRot- The rotation of the camera.entityPosis removedisPanoramicMode- Whether the camera is in panorama mode.cullFrustum- The cull frustum.fogType,fogData- Fog metadata.hudFov- The hud field-of-view.depthFar- The depth Z far plane.projectionMatrix,viewRotationMatrix- The matrices for moving from world space to screen space.entityRenderState- The entity the camera is attached to.
LevelRenderStatelastEntityRenderStateCount- The number of entities being rendered to the screen.cloudColor,cloudHeight- Cloud metadata.
LightmapRenderState- The render state for the lightmap.
net.minecraft.client.renderer.textureMipmapGenerator#generateMipLevelsnow takes in the computedTransparencyof the imageSpriteContentstransparency- Gets the transparency of the sprite.getUniqueFramesnow returns anIntListinstaed of anIntStreamcomputeTransparency- Computes the transparency of the selected UV bounds.$AnimatedTexture#getUniqueFramesnow returns anIntListinstaed of anIntStream
TextureAtlasSprite#transparency- Gets the transparency of the sprite.
net.minecraft.client.resources.modelAtlasManager->.model.sprite.AtlasManagerBlockModelRotation->.client.renderer.block.dispatch.BlockModelRotationMaterial->.model.sprite.SpriteId, not one-to-oneMaterialSet->.model.sprite.SpriteGetterMissingBlockModel->.model.cuboid.MissingCuboidModelModelBakersprites->materialsparts->interner$PartCache->$Internervector(float, float, float)is removedmaterialInfo- Gets the interned material info object.
ModelBakeryBANNER_BASE->Sheets#BANNER_BASESHIELD_BASE->Sheets#SHIELD_BASENO_PATTERN_SHIELD->Sheets#SHIELD_BASE_NO_PATTERNLAVA_*->FluidStateModelSet#LAVA_MODEL, nowprivatefrompublicWATER_*->FluidStateModelSet#WATER_MODEL, nowprivatefrompublic$BakingResult#getBlockStateModel- Gets theBlockStateModelfrom theBlockState.$MissingModelsnow takes in aMissingItemModelinstead of anItemModelfor theItem, and aFluidModel
ModelManagerBLOCK_OR_ITEMis removedgetMissingBlockStateModel->BlockStateModelSet#missingModelgetBlockModelShaper->getBlockStateModelSet, not one-to-onegetBlockModelSet- Gets the map ofBlockStateto block model.specialBlockModelRendereris removedgetFluidStateModelSet- Gets the map ofFluidto fluid model.
ModelState->.client.renderer.block.dispatch.ModelStateQuadCollection->.model.geometry.QuadCollectionaddAll- Adds all elements from another quad collection.materialFlags,hasMaterialFlag- Handles the flags for the material(s) used by the model.
ResolvedModel#resolveParticleSprite->resolveParticleMaterial, now returning aMaterial$Bakedinstead of aTextureAtlasSpriteSpriteGetter->.model.sprite.MaterialBakerUnbakedGeometry->.model.geometry.UnbakedGeometryWeightedVariants->.client.renderer.block.dispatch.WeightedVariants
net.minecraft.client.resources.model.sprite.Material- A reference to a texture sprite, along with whether to force translucency on the texture.net.minecraft.world.entity.animal.Animal#isBrightEnoughToSpawnnow takes in aBlockAndLightGetterinstead of theBlockAndTintGetternet.minecraft.world.levelBlockAndTintGetter->BlockAndLightGetterBlockAndTintGetteris now client only, implementingBlockAndLightGettergetShade->cardinalLighting; not one-to-onegetBlockTint->BlockAndTintGetter#getBlockTint
CardinalLighting- Holds the lighting applied in each direction.EmptyBlockAndTintGetter->BlockAndTintGetter#EMPTYLevelReadernow implementsBlockAndLightGetterinstead ofBlockAndTintGetter
net.minecraft.world.level.blockBannerBlock$AttachmentType- Where the banner attaches to another block.CeilingHangingSignBlocknow implementsHangingSignBlockgetAttachmentPoint- Gets where the sign attaches to another block.
HangingSignBlock- An interface that defines a hanging sign attached to another block.PlainSignBlock- An inteface that defines a plain sign attached to another block.StandingSignBlocknow implementsPlainSignBlockWallingHangingSignBlocknow implementsHangingSignBlockWallSignBlocknow implementsPlainSignBlock
net.minecraft.world.level.block.state.BlockBehaviour#getLightBlock,$BlockStateBase#getLightBlock->getLightDampeningnet.minecraft.world.level.block.state.propertiesBedPart#CODEC- The codec for the bed part.ChestType#CODEC- The codec for the chest type.
net.minecraft.world.level.dimension.DimensionType$CardinalLightType->CardinalLighting$Type
Minor Migrations
The following is a list of useful or interesting additions, changes, and removals that do not deserve their own section in the primer.
Plantable Tags
The blocks to determine whether a plantable can survive or be placed on has been moved to block and fluid tags. Each of these tags starts with support_* along with the block (e.g., bamboo, cactus) or group (e.g., crops, dry_vegetation). This is handled by the relevant block subclasses overriding either Block#canSurvive, or for vegetation VegetationBlock#mayPlaceOn.
net.minecraft.world.level.blockAttachedStemBlocknow takes in aTagKeyfor the blocks it can be placed onFarmBlock->FarmlandBlockFungusBlock->NetherFungusBlock, not one-to-oneRootsBlock->NetherRootsBlock, not one-to-oneWaterlilyBlock->LilyPadBlock, not one-to-oneStemBlocknow takes in aTagKeyfor the blocks it can be placed on, and aTagKeyfor the blocks its fruit can be placed on
Container Screen Changes
The usage of AbstractContainerScreens has changed slightly, requiring some minor changes. First imageWidth and imageHeight are now final, settable as parameters within the constructor. If these two are not specified, they default to the original 176 x 166 background image.
// Assume some AbstractContainerMenu subclass exists
public class ExampleContainerScreen extends AbstractContainerScreen<ExampleContainerMenu> {
// Constructor
public ExampleContainerScreen(ExampleContainerMenu menu, Inventory playerInventory, Component title) {
// Specify image width and height as the last two parameters in the constructor
super(menu, playerInventory, title, 256, 256);
}
}
Additionally, the AbstractContainerScreen#render override now calls renderTooltip at the end of the call stack. This means that, in most cases, you should not override render in subtypes of the AbstractContainerScreen. Everything can be done in one of the other methods provided by the class.
net.minecraft.client.gui.screens.inventory.AbstractContainerScreennow optionally takes in the background image width and heightimageWidth,imageHeightare now finalDEFAULT_IMAGE_WIDTH,DEFAULT_IMAGE_HEIGHT- The default width and height of the container background image.slotClickednow takes is aContainerInputinstead of aClickTyperenderoverride now callsrenderTooltipby default
net.minecraft.world.inventoryAbstractContainerMenu#clickednow takes in aContainerInputinstead of aClickTypeClickType->ContainerInput
New Tag Providers
A new TagsProvider has been added that provides a utility for working with Holder$References, known as HolderTagProvider. This is only used by the PotionTagsProvider.
Additionally, the TagBuilder now provides a method of setting the replace field on a tag, which removes all previous read entries during deserialization.
net.minecraft.data.tagsFeatureTagsProvider- A tag provider forConfiguredFeatures.HolderTagProvider- A tag provider with a utility for appending tags by their reference holder.KeyTagProvider#tagnow has an overload of whether to replace the entries in the tag.PotionTagsProvider- A provider for potion tags.TradeRebalanceTradeTagsProvider- A provider for villager trade tags for the trade rebalance.VillagerTradesTagsProvider- A provider for villager trade tags.
net.minecraft.tagsFeatureTags- Tags forConfiguredFeatures.TagBuilder#shouldReplace,setReplace- Handles thereplacefield that removes all previously read entries during deserialization.
Test Environment State Tracking
TestEnvironmentDefinitions can now keep track of the original state of the world when being created, such that it can be properly restored on run. This is done through a generic known as the ‘SavedDataType’. On setup, each environment will return the generic data representing the original state of what was modified. Then, on teardown, the original state will be restored to the level for the next test case.
// The generic should represent the original data stored on the level
public record RespawnEnvironment(LevelData.RespawnData respawn) implements TestEnvironmentDefinition<LevelData.RespawnData> {
@Override
public LevelData.RespawnData setup(ServerLevel level) {
// Modify the level while logging the original state.
var original = level.getRespawnData();
level.setRespawnData(this.respawn);
// Return the original state.
return original;
}
@Override
public void teardown(ServerLevel level, LevelData.RespawnData original) {
// Reset the state of the level to the original values.
level.setRespawnData(original);
}
@Override
public MapCodec<RespawnEnvironment> codec() {
// Return the registered MapCodec here.
// ...
}
}
net.minecraft.gametest.framework.TestEnvironmentDefinitionnow has a generic representing the original state of the given modification performed by the test environmentsetupnow returns the generic representing the original stateteardownis no longer default, taking in the original state to restoreactivate,$Activation- Handles an active test environment.
Typed Instance
TypedInstance is an interface that is attached to certain objects that represent an instance of some other ‘type’ object. For example, and Entity is a typed instance of EntityType, or a BlockState is a typed instance of Block. This interface is meant as a standard method to provide access to the type Holder and check whether the backing type, and therefore the instance, is equivalent to some identifier, tag, or raw object via is.
// For some Entity entity, check the EntityType
entity.is(EntityType.PLAYER);
// For some ItemStack itemStack, check the Item
itemStack.is(ItemTags.BUTTONS);
// For some BlockEntity blockEntity, check the BlockEntityType
blockEntity.is(BlockEntityType.CHEST);
// For some BlockState blockState, check the Block
blockState.is(Blocks.DIRT);
// For some FluidState fluidState, check the Fluid
fluidState.is(FluidTags.WATER);
net.minecraft.core.TypedInstance- An interface that represents that this object is an instance for some other ‘type’ object.net.minecraft.world.entityEntitynow implementsTypedInstance<EntityType<?>>EntityType#is->TypedInstance#is- Now on the
Entityinstance
- Now on the
net.minecraft.world.item.ItemStacknow implementsTypedInstance<Item>getItemHolder->typeHoldergetTags->tags
net.minecraft.world.level.block.entityBlockEntitynow implementsTypedInstance<BlockEntityType>BlockEntityType#getKeyis removed
net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBasenow implementsTypedInstance<Block>getBlockHolder->typeHoldergetTags->tags
net.minecraft.world.level.material.FluidStatenow implementsTypedInstance<Fluid>holder->typeHoldergetTags->tags
Entity Textures and Adult/Baby Models
Entity textures within assets/minecraft/textures/entity/* have now been sorted into subdirectories (e.g., entity/panda for panda textures, or entity/pig for pig textures). Most textures have been named with the entity type starting followed by an underscore along with its variant (e.g., arrow_tipped for tipped arrow, pig_cold for the cold pig variant, or panda_brown for the brown panda variant).
Additionally, some animal models have been split into separate classes for the baby and adult variants. These models either directly extend an abstract model implementation (e.g., AbstractFelineModel) or the original model class (e.g., PigModel).
net.minecraft.client.animation.definitionsBabyArmadilloAnimation- Animations for the baby armadillo.BabyAxolotlAnimation- Animations for the baby axolotl.BabyRabbitAnimation- Animations for the baby rabbit.CamelBabyAnimation- Animations for the baby camel.FoxBabyAnimation- Animations for the baby fox.RabbitAnimation- Animations for the rabbit.
net.minecraft.client.modelHumanoidModelADULT_ARMOR_PARTS_PER_SLOT,BABY_ARMOR_PARTS_PER_SLOT- A map of equipment slot to model part keys.createBabyArmorMeshSet- Creates the armor model set for a baby humanoid.createArmorMeshSetcan now take in a map of equipment slot to model part keys for what to retainsetAllVisibleis removed
QuadrupedModelnow has a constructor that takes in a function for theRenderType
net.minecraft.client.model.animal.armadilloAdultArmadilloModel- Entity model for the adult armadillo.ArmadilloModelis now abstract- The constructor now takes in the definitions for the walk, roll out/up, and peek animations
BABY_TRANSFORMERhas been directly merged into the layer definition for theBabyArmadilloModelHEAD_CUBE,RIGHT_EAR_CUBE,LEFT_EAR_CUBEare nowprotectedinstead ofprivatecreateBodyLayer->AdultArmadilloModel#createBodyLayer,BabyArmadilloModel#createBodyLayer
BabyArmadilloModel- Entity model for the baby armadillo.
net.minecraft.client.model.animal.axolotl.AxolotlModel->AdultAxolotlModel,BabyAxolotlModelnet.minecraft.client.model.animal.beeAdultBeeModel- Entity model for the adult bee.BabyBeeModel- Entity model for the baby bee.BeeModelis now abstractBABY_TRANSFORMERhas been directly merged into the layer definition for theBabyBeeModelBONE,STINGER,FRONT_LEGS,MIDDLE_LEGS,BACK_LEGSare nowprotectedinstead ofprivateboneis nowprotectedinstead ofprivatecreateBodyLayer->AdultBeeModel#createBodyLayer,BabyBeeModel#createBodyLayerbobUpAndDown- Bobs the bee up and down at the desired speed, depending on its current age.
net.minecraft.client.model.animal.camelAdultCamelModel- Entity model for the adult camel.BabyCamelModel- Entity model for the baby camel.CamelModelis now abstract- The constructor now takes in the definitions for the walk, sit with/without pose, standup, idle, and dash animations
BABY_TRANSFORMERhas been directly merged into the layer definition for theBabyCamelModelcreateBodyLayer->AdultCamelModel#createBodyLayer,BabyCamelModel#createBodyLayer
CameSaddleModelnow extendsAdultCamelModelinstead ofCamelModel
net.minecraft.client.model.animal.chickenAdultChickenModel- Entity model for the adult chicken.BabyChickenModel- Entity model for the baby chicken.ChickenModelis now abstractRED_THING->AdultChickenModel#RED_THINGBABY_TRANSFORMERhas been directly merged into the layer definition for theBabyChickenModelcreateBodyLayer->AdultChickenModel#createBodyLayercreateBaseChickenModel->AdultChickenModel#createBaseChickenModel
ColdChickenModelnow extendsAdultChickenModel
net.minecraft.client.model.animal.cow.BabyCowModel- Entity model for the baby cow.net.minecraft.client.model.animal.dolphin.BabyDolphinModel- Entity model for the baby dolphin.net.minecraft.client.model.animal.equineAbstractEquineModelnow has an overload that directly specifies theModelParts to useBABY_TRANSFORMERhas been directly merged into the layer definition for theBabyDonkeyModelrightHindLeg,leftHindLeg,rightFrontLeg,leftFrontLegare nowprotectedfromprivatecreateBabyMesh->BabyHorseModel#createBabyMesh, not one-to-oneoffsetLegPositionWhenStanding- Offsets the position of the legs when the entity is standing.getLegStandAngle,getLegStandingYOffset,getLegStandingZOffset,getLegStandingXRotOffset,getTailXRotOffset- Offsets and angles for parts of the equine model.animateHeadPartsPlacement- Animates the head based on its eating and standing states.
BabyDonkeyModel- Entity model for the baby donkey.BabyHorseModel- Entity model for the baby horse.DonkeyModelnow has an overload that directly specifies theModelParts to usecreateBabyLayer->BabyDonkeyModel#createBabyLayer
EquineSaddleModel#createFullScaleSaddleLayeris removed Merged intocreateSaddleLayer, with the baby variant removed
net.minecraft.client.model.animal.felineCatModel->AdultCatModel,BabyCatModel; not one-to-oneFelineModel->AbstractFelineModel, not one-to-one- Implementations in
AdultFelineModelandBabyFelineModel
- Implementations in
OcelotModel->AdultOcelotModel,BabyOcelotModel; not one-to-one
net.minecraft.client.model.animal.foxAdultFoxModel- Entity model for the adult fox.BabyFoxModel- Entity model for the baby fox.FoxModelis now abstractBABY_TRANSFORMERhas been directly merged into the layer definition for theBabyFoxModelbody,rightHindLeg,leftHindLeg,rightFontLeg,leftFrontLeg,tailare nowprotectedinstead ofprivatecreateBodyLayer->AdultFoxModel#createBodyLayer,BabyFoxModel#createBodyLayerset*Pose- Methods for setting the current pose of the fox.
net.minecraft.client.model.animal.goatBabyGoatModel- Entity model for the baby goat.GoatModel#BABY_TRANSFORMERhas been directly merged into the layer definition for theBabyGoatModel
net.minecraft.client.model.animal.llamaBabyLlamaModel- Entity model for the baby llama.LlamaModel#createBodyLayerno longer takes in thebooleanfor if the entity is a baby
net.minecraft.client.model.animal.pandaBabyPandaModel- Entity model for the baby panda.PandaModelBABY_TRANSFORMERhas been directly merged into the layer definition for theBabyPandaModelanimateSitting- Animates the panda sitting.
net.minecraft.client.model.animal.pig.BabyPigModel- Entity model for the baby pig.net.minecraft.client.model.animal.polarbearBabyPolarBearModel- Entity model for the baby polar bear.PolarBearModel#BABY_TRANSFORMERhas been directly merged into the layer definition for theBabyPolarBearModel
net.minecraft.client.model.animal.rabbitAdultRabbitModel- Entity model for the adult rabbit.BabyRabbitModel- Entity model for the baby rabbit.RabbitModelis now abstract- The constructor now takes in two animation definitions for the hop and idle head tilt
FRONT_LEGS,BACK_LEGS- The child name for the entity legs.LEFT_HAUNCH,RIGHT_HAUNCHare nowprotectedcreateBodyLayer->AdultRabbitModel#createBodyLayer,BabyRabbitModel#createBodyLayer; not one-to-one
net.minecraft.client.model.animal.sheepBabySheepModel- Entity model for the baby sheep.SheepModel#BABY_TRANSFORMERhas been directly merged into the layer definition for theBabySheepModel
net.minecraft.client.model.animal.snifferSnifferModel#BABY_TRANSFORMERhas been directly merged into the layer definition for theSniffletModelSniffletModel- Entity model for the baby sniffer.
net.minecraft.client.model.animal.squidBabySquidModel- Entity model for the baby squid.SquidModel#createTentacleNameis now protected from private
net.minecraft.client.model.animal.turtleAdultTurtleModel- Entity model for the adult turtle.BabyTurtleModel- Entity model for the baby turtle.TurtleModelis now abstract- The constructor can how take in the render type function
BABY_TRANSFORMERhas been directly merged into the layer definition for theBabyTurtleModelcreateBodyLayer->AdultTurtleModel#createBodyLayer,BabyTurtleModel#createBodyLayer
net.minecraft.client.model.animal.wolfAdultWolfModel- Entity model for the adult wolf.BabyWolfModel- Entity model for the baby wolf.WolfModelis now abstractModelPartfields are now all protectedcreateMeshDefinition->AdultWolfModel#createBodyLayer,BabyWolfModel#createBodyLayer; not one-to-oneshakeOffWater- Sets the body rotation when shaking off water.setSittingPose- Sets the sitting pose of the wolf.
net.minecraft.client.model.geomModelLayersCOLD_CHICKEN_BABYis removedCOLD_PIG_BABYis removedPIG_BABY_SADDLEis removedSHEEP_BABY_WOOL_UNDERCOATis removedWOLF_BABY_ARMORis removedDONKEY_BABY_SADDLEis removedHORSE_BABY_ARMORis removedHORSE_BABY_SADDLEis removedMULE_BABY_SADDLEis removedSKELETON_HORSE_BABY_SADDLEis removedUNDEAD_HORSE_BABY_ARMORis removedZOMBIE_HORSE_BABY_SADDLEis removedSTRIDER_BABY_SADDLEis removed
PartNames#WAIST- The waist part.
net.minecraft.client.model.monster.hoglinBabyHoglinModel- Entity model for the baby hoglin.HoglinModelBABY_TRANSFORMERhas been directly merged into the layer definition for theBabyHoglinModelheadis nowprotectedfromprivatecreateBabyLayer->BabyHoglinModel#createBodyLayer
net.minecraft.client.model.monster.piglinAbstractPiglinModelis now abstractleftSleeve,rightSleeve,leftPants,rightPants,jacketare removedADULT_EAR_ANGLE_IN_DEGREES,BABY_EAR_ANGLE_IN_DEGREES- The angle of the piglin ears.createMeshreplaced byAdultPiglinModel#createBodyLayer,AdultZombifiedPiglinModel#createBodyLayer,BabyPiglinModel#createBodyLayer,BabyZombifiedPiglinModel#createBodyLayercreateBabyArmorMeshSet- Create the armor meshes for the baby piglin model.getDefaultEarAngleInDegrees- Gets the default ear angle.
AdultPiglinModel- Entity model for the adult piglin.AdultZombifiedPiglinModel- Entity model for the adult zombified piglin.BabyPiglinModel- Entity model for the baby piglin.BabyZombifiedPiglinModel- Entity model for the baby zombified piglin.PiglinModelis now abstractZombifiedPiglinModelis now abstract
net.minecraft.client.model.monster.striderAdultStriderModel- Entity model for the adult strider.BabyStriderModel- Entity model for the baby strider.StriderModelis now abstractBABY_TRANSFORMERhas been directly merged into the layer definition for theBabyStriderModelrightLeg,leftLeg,bodyare nowprotectedfromprivateSPEED- The speed scalar of the movement animation.customAnimations- Additional animation setup.animateBristle- Animates the bristles of the strider.
net.minecraft.client.model.monster.zombieBabyDrownedModel- Entity model for the baby drowned.BabyZombieModel- Entity model for the baby zombie.BabyZombieVillagerModel- Entity model for the baby zombie villager.
net.minecraft.client.model.npcBabyVillagerModel- Entity model for the baby villager.VillagerModel#BABY_TRANSFORMERhas been directly merged into the layer definition for theBabyVillagerModel
net.minecraft.client.renderer.entityAxolotlRenderernow takes in anEntityModel<AxolotlRenderState>for its genericCamelHuskRenderernow extendsMobRendererinstead ofCamelRendererCamelRenderer#createCamelSaddleLayeris nowstaticCatRenderernow takes in anAbstractFelineModelfor its genericDonkeyRenderernow takes in anEquipmentClientInfo$LayerTypeandModelLayerLocationfor the saddle layer and model, and splits theDonkeyRenderer$Typeinto the adult type and baby type$TypeDONKEY_BABY- A baby variant of the donkey.MULE_BABY- A baby variant of the mule.
OcelotRenderernow takes in anAbstractFelineModelfor its genericUndeadHorseRenderernow takes in anEquipmentClientInfo$LayerTypeandModelLayerLocationfor the saddle layer and model, and splits theUndeadHorseRenderer$Typeinto the adult type and baby type$TypeSKELETON_BABY- A baby variant of the skeleton horse.ZOMBIE_BABY- A baby variant of the zombie horse.
net.minecraft.client.renderer.entity.layers.CatCollarLayernow takes in anAbstractFelineModelfor its genericnet.minecraft.client.renderer.entity.stateAxolotlRenderStateswimAnimation- The state of swimming.walkAnimationState- The state of walking on the ground, not underwater.walkUnderWaterAnimationState- The state of walking underwater.idleUnderWaterAnimationState- The state of idling underwater but not on the ground.idleUnderWaterOnGroundAnimationState- The state of idling underwater while touching the seafloor.idleOnGroundAnimationState- The state of idling on the ground, not underwater.playDeadAnimationState- The state of playing dead.
RabbitRenderStatehopAnimationState- The state of the hop the entity is performing.idleHeadTiltAnimationState- The state of the head tilt when performing the idle animation.
net.minecraft.client.resources.model.EquipmentClientInfo$LayerType#HUMANOID_BABY- The baby humanoid equipment layer.net.minecraft.sounds.SoundEvents#PIG_EAT_BABY- Ths sound played when a baby big is eating.net.minecraft.world.entity.AgeableMobcanUseGoldenDandelion- Whether a golden dandelion can be used to agelock an entity.setAgeLocked- Sets the entity as agelocked.makeAgeLockedParticle- Creates the particles when agelocking an entity.AGE_LOCK_DOWNWARDS_MOVING_PARTICLE_Y_OFFSET- The Y offset for the particle’s starting position.
net.minecraft.world.entity.animal.axolotl.AxolotlswimAnimation- The state of swimming.walkAnimationState- The state of walking on the ground, not underwater.walkUnderWaterAnimationState- The state of walking underwater.idleUnderWaterAnimationState- The state of idling underwater but not on the ground.idleUnderWaterOnGroundAnimationState- The state of idling underwater while touching the seafloor.idleOnGroundAnimationState- The state of idling on the ground, not underwater.playDeadAnimationState- The state of playing dead.$AnimationState->$AxolotlAnimationState
net.minecraft.world.entity.animal.chicken.ChickenVariantnow takes in a resource for the baby texturenet.minecraft.world.entity.animal.cow.CowVariantnow takes in a resource for the baby texturenet.minecraft.world.entity.animal.cat.CatVariantnow takes in a resource for the baby textureCatVariant#assetInfo- Gets the entity texture based on whether the entity is a baby.
net.minecraft.world.entity.animal.equine.AbstractHorse#BABY_SCALE- The scale of the baby size compared to an adult.net.minecraft.world.entity.animal.frog.TadpoleageLockParticleTimer- A timer for how long the particles for the agelocked entity should spawn.setAgeLocked,isAgeLocked- Handles agelocking for the tadpole.
net.minecraft.world.entity.animal.goat.GoatBABY_DEFAULT_X_HEAD_ROT- The default head X rotation for the baby variant.MAX_ADDED_RAMMING_X_HEAD_ROT- The maximum head X rotation.addHorns,removeHornsare removed
net.minecraft.world.entity.animal.pig.PigVariantnow takes in a resource for the baby texturenet.minecraft.world.entity.animal.rabbit.RabbithopAnimationState- The state of the hop the entity is performing.idleHeadTiltAnimationState- The state of the head tilt when performing the idle animation.
net.minecraft.world.entity.animal.wolfWolfSoundVariant->WolfSoundVariant$WolfSoundSet- The class itself now holds two sound sets for the adult wolf and baby wolf.
WolfSoundVariants$SoundSet#getSoundEventSuffix->getSoundEventIdentifier
net.minecraft.world.entity.animal.wolf.WolfVariantnow takes in an asset info for the baby variantnet.minecraft.world.item.equipment.EquipmentAssets#TRADER_LLAMA_BABY- Equipment asset for baby trader llamas.
The Removal of interactAt
Entity#interactAt has been removed, with all further invocation merged with Entity#interact. Originally, Entity#interactAt was called if the hit result was within the entity’s interaction range. If interactAt did not consume the action (i.e., InteractionResult#consumesAction returns false), then Entity#interact is called. Now, Entity#interact is called if within the entity’s interaction range, taking in the Vec3 location of interaction.
// In some Entity subclass
@Override
public InteractionResult interact(Player player, InteractionHand hand, Vec3 location) {
// Handle the interaction
super.interact(player, hand, location);
}
interactAt checks if result does not consume the interaction, and if not calls interact
Now, interact is called with the entity hit
net.minecraft.client.multiplayer.MultiPlayerGameModeinteractnow takes in theEntityHitResultinteractAtis removed
net.minecraft.world.entity.Entityinteractnow takes in aVec3for the location of the interactioninteractAtis removed
net.minecraft.world.entity.player.Player#interactOnnow takes in aVec3for the location of the interaction
ChunkPos, now a record
ChunkPos is now a record. The BlockPos constructor has been replaced by ChunkPos#containing while the packed long constructor has been replaced by ChunkPose#unpack.
net.minecraft.world.level.ChunkPosis now a recordChunkPos(BlockPos)->containingChunkPos(long)->unpacktoLong,asLong->pack
No More Tripwire Pipelines
The tripwire render pipeline has been completely removed. Now, tripwires make use of cutout with an alpha_cutoff_bias of 0.1 for the texture.
net.minecraft.client.renderer.RenderPipelines#TRIPWIRE_BLOCK,TRIPWIRE_TERRAINare removednet.minecraft.client.renderer.chunkChunkSectionLayer#TRIPWIREis removedChunkSectionLayerGroup#TRIPWIREis removed
net.minecraft.client.renderer.rendertype.RenderTypes#tripwireMovingBlockis removed
Activities and Brains
Activities, which define how a living entity behaves during a certain phase, now are stored and passed around through ActivityData. This contains the activity type, the behaviors to perform along with their priorities, the conditions on when this activity activates, and the memories to erase when the activity has stopped. Brain#provider now takes in an $ActivitySupplier to construct a list of ActivityData the entity performs.
Brains have also changed slightly. First, the Brain itself is not directly serializable. Instead, the brain is $Packed into the record, holding a map of its current memories. To get the memory types used, they are typically extracted from those that the Sensor#requires. Additionally, LivingEntity#brainProvider no longer exists, instead opting to store the provider in a static constant on the entity itself. This means that brains are now completely constructed through the makeBrain method, taking in the previous $Packed data:
// For some ExampleEntity extends LivingEntity
// Assume extends Mob subclass
private static final Brain.Provider<ExampleEntity> BRAIN_PROVIDER = Brain.provider(
// The list of sensors the entity uses.
ImmutableList.of(),
// A function that takes in the entity and returns a list of activities.
entity -> List.of(
new ActivityData(
// The activity type
Activity.CORE,
// A list of priority and behavior pairs
ImmutableList.of(Pair.of(0, new MoveToTargetSink())),
// A set of memory conditions for the activity to run
// For example, this memory value must be present
ImmutableSet.of(Pair.of(MemoryModuleType.ATTACK_TARGET, MemoryStatus.VALUE_PRESENT)),
// The set of memories to erase when the activity has stopped
ImmutableSet.of(MemoryModuleType.ATTACK_TARGET)
)
)
);
@Override
protected Brain.Provider<ExampleEntity> makeBrain(Brain.Packed packedBrain) {
// Make the brain, populating any previous memories
return BRAIN_PROVIDER.makeBrain(this, packedBrain);
}
net.minecraft.world.entity.LivingEntitybrainProvideris removedmakeBrainnow takes in aBrain$Packedinstead of aDynamic
net.minecraft.world.entity.aiActivityData- A record containing the activity being performed, the behaviors to perform during that activity, any memory conditions, and what memories to erase once stopped.Brainis now protected, taking in a list ofActivityData, aMemoryMapinstead of an immutable list of memories, aRandomSource, and not the suppliedCodec- The public constructor no longer takes in anything
providernow has an overload that only takes in the sensor types, defaulting the memory types to an empty list- Some
providermethods also take in theBrain$ActivitySupplierto perform
- Some
codec,serializeStartare replaced bypack,Brain$PackedaddActivityAndRemoveMemoryWhenStopped,addActivityWithConditionsmerged intoaddActivity- Alternatively use
ActivityData#create
- Alternatively use
copyWithoutBehaviorsis removedgetMemoriesreplaced byforEach$ActivitySupplier- Creates a list of activities for the entity.$MemoryValueis removed$Packed- A record containing the data to serialize the brain to disk.$Provider#makeBrainnow takes in the entity and theBrain$Packedto deserialize the memories$Visitor- Visits the memories within a brain, whether defined but empty, present, or present with some timer.
net.minecraft.world.entity.ai.behavior.VillagerGoalPackages#get*Packageno longer take in theVillagerProfessionnet.minecraft.world.entity.ai.memoryExpirableValue->MemorySlot, not one-to-one- The original
ExpirableValueis now a record that defines when a memory should expire, rather than be updated itself
- The original
MemoryMap- A map linking the memory type to its stored value.MemoryModuleType- Whether a memory can be serialized.
net.minecraf.tworld.entity.ai.sensing.Sensor#randomlyDelayStart- How long to delay a sensor.net.minecraft.world.entity.animal.allay.AllayAiSENSOR_TYPES,MEMORY_TYPES->BRAIN_PROVIDER, now private; not one-to-onemakeBrain->getActivities, not one-to-one
net.minecraft.world.entity.animal.armadillo.ArmadilloAi#makeBrain,brainProvider->getActivities, nowprotected, not one-to-onenet.minecraft.world.entity.animal.axolotlAxolotlSENSOR_TYPES->BRAIN_PROVIDER, now private; not one-to-oneAxolotlAimakeBrain->getActivities, not one-to-oneinitPlayDeadActivity, nowprotected, no longer taking in anythinginitFightActivity, nowprotected, no longer taking in anythinginitCoreActivity, nowprotected, no longer taking in anythinginitIdleActivity, nowprotected, no longer taking in anything
net.minecraft.world.entity.animal.camel.CamelAi#makeBrain,brainProvider->getActivities, nowprotected, not one-to-onenet.minecraft.world.entity.animal.frogFrog#SENSOR_TYPES->BRAIN_PROVIDER, now private; not one-to-oneFrogAi#makeBrain->getActivities, not one-to-oneTadpole#SENSOR_TYPES->BRAIN_PROVIDER, now private; not one-to-one
net.minecraft.world.entity.animal.frog.TadpoleAi#makeBrain->getActivities, nowpublic, not one-to-onenet.minecraft.world.entity.animal.goatGoat#SENSOR_TYPES->BRAIN_PROVIDER, now private; not one-to-oneGoatAi#makeBrain->getActivities, not one-to-one
net.minecraft.world.entity.animal.golem.CopperGolemAi#makeBrain,brainProvider->getActivities, nowprotected, not one-to-onenet.minecraft.world.entity.animal.happyghast.HappyGhastAi#makeBrain,brainProvider->getActivities, nowprotected, not one-to-onenet.minecraft.world.entity.animal.nautilusNautilusAiSENSOR_TYPES,MEMORY_TYPES->Nautilus#BRAIN_PROVIDER, now private, not one-to-onemakeBrain,brainProvider->getActivities, nowpublic, not one-to-one
ZombieNautilusAiSENSOR_TYPES,MEMORY_TYPES->ZombieNautilus#BRAIN_PROVIDER, now private, not one-to-onemakeBrain,brainProvider->getActivities, nowpublic, not one-to-one
net.minecraft.world.entity.animal.sniffer.SnifferAi#makeBrain->getActivities, nowpublic, not one-to-onenet.minecraft.world.entity.monster.ZoglinSENSOR_TYPES->BRAIN_PROVIDER, now private, not one-to-onegetActivities- The activities the zoglin performs.
net.minecraft.world.entity.monster.breeze.BreezeAi#makeBrain->getActivities, not one-to-onenet.minecraft.world.entity.monster.creaking.CreakingAi#makeBrain,brainProvider->getActivities, nowprotected, not one-to-onenet.minecraft.world.entity.monster.hoglinHoglin#SENSOR_TYPES->BRAIN_PROVIDER, now private; not one-to-oneHoglinAi#makeBrain->getActivities, not one-to-one
net.minecraft.world.entity.monster.piglinPiglin#SENSOR_TYPES,MEMORY_TYPES->BRAIN_PROVIDER, now private, not one-to-onePiglinAi#makeBrain->getActivities, nowpublic, not one-to-onePiglinBrute#SENSOR_TYPES,MEMORY_TYPES->BRAIN_PROVIDER, now private, not one-to-onePiglinBruteAi#makeBrain->getActivities, nowpublic, not one-to-one
net.minecraft.world.entity.monster.warden.WardenAi#makeBrain->getActivities, not one-to-one
File Fixer Upper
The file fixer upper is a new system to help with upgrading game files between versions, in conjunction with the data fixer upper. Similar to how the data within files can be modified or ‘upgraded’ between Minecraft versions via data fixers, file fixers can modify anything within a world directory, from moving files and directories to deleting them outright. As such, file fixers are always applied before data fixers.
Unlike when upgrading when data fixers, file fixers change the structure of the world folder. Because of this, downgrading is rarely possible, as the file names and locations will have likely changed location.
File fixers are applied through a FileFix, which defines some operation(s) to perform on a file using makeFixer. This is done typically through the addFileContentFix, providing access to the desired files through the FileAccess, and then modifying the data like any other Dynamic instance. Operations are commonly defined as FileFixOperations, which can move the file structure around.
The file fixes are then applied through the FileFixerUpper, which uses a copy-on-write file system to operate on the files. The fixer is constructed using the $Builder, using addSchema and addFixer to apply the fixers for the desired version. During the upgrade process, the files are created in a temporary folder, then moved to the world folder. The original world folder is moved to another folder before being deleted.
net.minecraft.client.gui.screens.FileFixerAbortedScreen- A screen that’s shown when the file fixing has been aborted.net.minecraft.client.gui.screens.worldselection.FileFixerProgressScreen- A screen that’s displayed when attempting to show the progress of upgrading and fixing the world files.net.minecraft.server.packs.linkfsDummyFileAttributes->.minecraft.util.DummyFileAttributesLinkFSPathDIRECTORY_ATTRIBUTES->DummyFileAttributes#DIRECTORYFILE_ATTRIBUTES->DummyFileAttributes#FILE
net.minecraft.utilExtraCodecspathCodec- A codec for a path, converting from a string and storing with Unix separators.relaiveNormalizedSubPathCodec- A codec for a path, normalized and validated to make sure it is relative.guardedPathCodec- A codec for a path, resolved and relativatized from some base path.
FileUtilisPathNormalized,createPathToResourceare removedisEmptyPath- Returns whether the path is empty.
Util#safeMoveFile- Safely moves a file from some source to a destination with the given options.
net.minecraft.util.filefixAbortedFileFixException- An exception thrown when the file fix has been aborted and was unable to revert moves.AtmoicMoveNotSupportedFileFixException- An exception thrown when the user file system does not support atomic moves.CanceledFileFixException- An exception thrown when the file fix upgrade proccess is canceled.FailedCleanupFileFixException- An exception thrown when the file fix was not able to move or delete folders for cleanup.FileFix- A fixer that performs some operation on a file.FileFixerUpper- The file fixers to perform operations with.FileFixException- An exception thrown when attempting to upgrade a world through the file fixer.FileFixUtil- A utility for performing some file operations.FileSystemCapabilities- The capabilities of the file system from a directory.
net.minecraft.util.filefix.accessChunkNbt- Handles upgrading a chunk nbt.CompressedNbt- Handles upgrading a compressed nbt file.FileAccess- Provides an reference to some file resource(s), given its relation.FileAccessProvider- A provider of file accesses, given some relation to the origin.FileRelation- A definition of how a file relates to some origin bpath.FileResourceType- Defines the type of resource to access.FileResourceTypes- All defined file resource types.LevelDat- Handles upgrading a level dat.PlayerData- Handles upgrading the player data.SavedDataNbt- Handles upgrading the saved data.
net.minecraft.util.filefix.fixes.*- The vanilla fixes to apply to the file(s).net.minecraft.util.filefix.operationsApplyInFolders- Applies the given operations within the related folders.DeleteFileOrEmptyDirectory- Deletes the target file or empty directory.FileFixOperation- An operation performed within some base directory.FileFixOperations- All vanilla file fix operations.GroupMove- Moves some directory, applying any move operation on its contents.ModifyContent- Modifies the content of a file.Move- Moves a file from some source to some destination.RegexMove- Moves all files that match the given source pattern to the destination, replacing the matched sections.
net.minecraft.util.filefix.virtualfilesystemCopyOnWriteFileStore- A file store using the copy-on-write principle.CopyOnWriteFileSystem- A file system using the copy-on-write principle.CopyOnWriteFSPath- A path using the copy-on-write principle.CopyOnWriteFSProvider- A file system provider using the copy-on-write principle.DirectoryNode- A directory node for some copy-on-write file system path.FileMove- A record containing the path a file has been moved from to.FileNode- A file node for some copy-on-write file system path.Node- A node for some copy-on-write file system path.
net.minecraft.util.filefix.virtualfilesystem.exceptionCowFSCreationException- ACowFSFileSystemExceptionwhen the file system cannot be created.CowFSDirectoryNotEmptyException- ADirectoryNotEmptyExceptionspecifically for a copy-on-write system.CowFSFileAlreadyExistsException- AFileAlreadyExistsExceptionspecifically for a copy-on-write system.CowFSFileSystemException- AFileSystemExceptionspecifically for a copy-on-write system.CowFSIllegalArgumentException- AnIllegalArgumentExceptionwhen attempting to operate upon a copy-on-write system.CowFSNoSuchFileException- ANoSuchFileExceptionspecifically for a copy-on-write system.CowFSNotDirectoryException- ANotDirectoryExceptionspecifically for a copy-on-write system.CowFSSymlinkException- ACowFSCreationExceptionwhen attempting to use the copy-on-write system with a symlink.
net.minecraft.util.worldupdateUpgradeProgressgetTotalFiles->getTotalFileFixState, not one-to-oneaddTotalFiles->addTotalFileFixOperations, not one-to-onegetTypeFileFixStats,getRunningFileFixerStats- Gets the fixer stats for the specific file group.incrementFinishedOperations,incrementFinishedOperationsBy- Increments the number of operations that have finished.setType,getType- Gets the type of the upgrade progress.setApplicableFixerAmount- Sets the total number of finished operations for the running file fixers.incrementRunningFileFixer- Increments the number of finished operations.logProgress- Logs the progress of the upgrade every second.$FileFixStats- A counter for the operations performed / finished.$Type- The type of upgrade being performed on the world data.
WorldUpgraderno longer takes in theWorldDataSTATUS_*messages have been combined inUpgradeStatusTranslator- This also contains the specific datafix type
running,finished,progress,totalChunks,totalFiles,converted,skipped,progressMap,statushave all been moved intoUpgradeProgress, stored inupgradeProgressgetProgress->getTotalProgress, not one-to-one$AbstractUpgrader,$SimpleRegionStorageUpgrader->RegionStorageUpgrader, no longer taking in the suppliedLegacyTagFixer, not one-to-one$ChunkUpgrader,$EntityUpgrader,$PoiUpgraderare now just constructed withinWorldUpgrader#work$Builder#setLegacyFixeris removed
$ChunkUpgrader#tryProcessOnePositionhas been partially abstracted intogetDataFixContentTag,verifyChunkPosAndEraseCache,verifyChunkPos$FileToUpgrade->FileToUpgrade
net.minecraft.world.level.ChunkPos#getRegionX,getRegionZ- Gets the region the chunk is in.net.minecraft.world.level.chunk.ChunkGenerator#getTypeNameForDataFixernow returns an optionalIdentifierinstead of aResourceKeynet.minecraft.world.level.chunk.storageLegacyTagFixerinterface is removedRecreatingSimpleRegionStorageno longer takes in the suppliedLegacyTagFixerSimpleRegionStorageno longer takes in the suppliedLegacyTagFixermarkChunkDoneis removed
net.minecraft.world.level.levelgen.structureLegacyStructureDataHandlerclass is removedStructureFeatureIndexSavedDataclass is removed
net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManagerSTRUCTURE_RESOURCE_DIRECTORY_NAME->STRUCTURE_DIRECTORY_NAME, not one-to-oneWORLD_STRUCTURE_LISTER,RESOURCE_TEXT_STRUCTURE_LISTER- Id converters for the structure nbts.savenow has an overload that takes in the path,StructureTemplate, andbooleanfor whether to write the data as textcreateAndValidatePathToGeneratedStructure->TemplatePathFactory#createAndValidatePathToStructure, not one-to-oneworldTemplates,testTemplates- The template path factories.
net.minecraft.world.level.levelgen.structure.templatesystem.loaderDirectoryTemplateSource- A template source for some directory.ResourceManagerTemplateSource- A template source for the resource manager.TemplatePathFactory- A factory that gets the path to some structure.TemplateSource- A loader for structure templates.
net.minecraft.world.level.storageLevelStorageSourcegetLevelDataAndDimensionsnow takes in the$LevelStorageAccessreadExistingSavedData- Reads any existing saved data.writeGameRules- Writes the game rules to the saved data.$LevelStorageAccess#releaseTemporarilyAndRun- Releases the access and runs before recreating the lock.collectIssues- Collects any issues when attempting to upgrade the data.getSummary->fixAndGetSummary,fixAndGetSummaryFromTag; not one-to-onegetDataTag->getUnfixedDataTag, not one-to-onegetDataTagFallback->getUnfixedDataTagWithFallback, not one-to-onesaveDataTagno longer takes in theRegistryAccesssaveLevelData- Saves the level dat.
LevelSummarynow takes in whether it requires file fixingUPGRADE_AND_PLAY_WORLD- A component telling the user to upgrade their world and play.requiresFileFixing- Whether the level requires file fixing.$BackupStatus#FILE_FIXING_REQUIRED- Whether file fixing is require to play this level on this version.
Chat Permissions
The chat system now has an associated set of permissions indicating what messages the player can send or receive. Permissions#CHAT_SEND_MESSAGES and CHAT_SEND_COMMANDS determine if the player can send messages or commands, respectively. Likewise, CHAT_RECEIVE_PLAYER_MESSAGES and CHAT_RECEIVE_SYSTEM_MESSAGES if the player can receive messages from other players or the system, respectively. Note that all of these permissions are only handled clientside and are not validated serverside.
net.minecraft.SharedConstants#DEBUG_CHAT_DISABLED- A flag that disables the chat box.net.minecraft.clientGuiMessage->.multiplayer.chat.GuiMessageGuiMessageTag->.multiplayer.chat.GuiMessageTagMinecraftgetChatStatus->computeChatAbilities, not one-to-one$ChatStatus->ChatRestriction, not one-to-one
net.minecraft.client.gui.Gui#setChatDisabledByPlayerShown,isShowingChatDisabledByPlayer- Handles whether the chat is disabled by the shown player.net.minecraft.client.gui.componentsChatComponentGO_TO_RESTRICTIONS_SCREEN- An identifier for redirecting to the restrictions screen.setVisibleMessageFilter- Sets the message filter function.render,captureClickableTextnow take in the$DisplayModeinstead of abooleanfor if the player is chattingaddMessageis now private- Split for use into
addClientSystemMessage,addServerSystemMessage,addPlayerMessage
- Split for use into
$DisplayMode- How the chat should be displayed.
CommandSuggestionsUSAGE_FORMAT,USAGE_OFFSET_FROM_BOTTOM,LINE_HEIGHT- Constants for showing the command suggestions.setRestrictions- Sets the restrictions of the messages that can be typed.hasAllowedInput- Whether the chat box can allow input.
net.minecraft.client.gui.screens.ChatScreen#USAGE_BACKGROUND_COLOR- The background color of the command suggestions box.net.minecraft.client.gui.screens.multiplayer.RestrictionsScreen- A screen for settings the restrictions of the player’s chat box.net.minecraft.client.gui.screens.reporting.ReportPlayerScreennow takes in abooleanfor if the chat is disabled or blockednet.minecraft.client.multiplayer.chatChatAbilities- The set of restrictions the player has on chatting with the chat box.ChatListenerhandleSystemMessagebooleanis now used for if the system is remote instead of overlay- The overlay is now handled through
handleOverlay
- The overlay is now handled through
GuiMessageSource- The source the message came from.
net.minecraft.client.player.LocalPlayernow takes in theChatAbilitieschatAbilities,refreshChatAbilities- Handles the chat abilities.
net.minecraft.server.permissions.PermissionsCHAT_SEND_MESSAGES- If the player can send chat messages.CHAT_SEND_COMMANDS- If the player can send commands.CHAT_RECEIVE_PLAYER_MESSAGES- If the player can receive other player messages.CHAT_RECEIVE_SYSTEM_MESSAGES- If the player can receive system messages.CHAT_PERMISSIONS- A set of available chat permissions.
net.minecraft.world.entity.player.Player#displayClientMessagesplit intosendSystemMessagewhen overlay message wasfalse, andsendOverlayMessagewhen the overlay message wastrue
More Entity Sound Variant Registries
Cats, chickens, cows, and pigs now have sound variants: a databack registry object that specifies the sounds an entity plays. This does not need to be directly tied to an actual entity variant, as it only defines the sounds an entity plays, typically during Mob#finalizeSpawn.
For cows:
// A file located at:
// - `data/examplemod/cow_sound_variant/example_cow_sound.json`
{
// The registry name of the sound event to play randomly on idle.
"ambient_sound": "minecraft:entity.cow.ambient",
// The registry name of the sound event to play when killed.
"death_sound": "minecraft:entity.cow.death",
// The registry name of the sound event to play when hurt.
"hurt_sound": "minecraft:entity.cow.hurt",
// The registry name of the sound event to play when stepping.
"step_sound": "minecraft:entity.cow.step"
}
For chickens and pigs:
// A file located at:
// - `data/examplemod/chicken_sound_variant/example_chicken_sound.json`
{
// The sounds played when an entity's age is greater than or equal to 0 (an adult).
"adult_sounds": {
// The registry name of the sound event to play randomly on idle.
"ambient_sound": "minecraft:entity.chicken.ambient",
// The registry name of the sound event to play when killed.
"death_sound": "minecraft:entity.chicken.death",
// The registry name of the sound event to play when hurt.
"hurt_sound": "minecraft:entity.chicken.hurt",
// The registry name of the sound event to play when stepping.
"step_sound": "minecraft:entity.chicken.step"
},
// The sounds played when an entity's age is less than 0 (a baby).
"baby_sounds": {
"ambient_sound": "minecraft:entity.baby_chicken.ambient",
"death_sound": "minecraft:entity.baby_chicken.death",
"hurt_sound": "minecraft:entity.baby_chicken.hurt",
"step_sound": "minecraft:entity.baby_chicken.step"
}
}
For pigs:
// A file located at:
// - `data/examplemod/pig_sound_variant/example_pig_sound.json`
{
// The sounds played when an entity's age is greater than or equal to 0 (an adult).
"adult_sounds": {
// The registry name of the sound event to play randomly on idle.
"ambient_sound": "minecraft:entity.pig.ambient",
// The registry name of the sound event to play when killed.
"death_sound": "minecraft:entity.pig.death",
// The registry name of the sound event to play when eating.
"eat_sound": "minecraft:entity.pig.eat",
// The registry name of the sound event to play when hurt.
"hurt_sound": "minecraft:entity.pig.hurt",
// The registry name of the sound event to play when stepping.
"step_sound": "minecraft:entity.pig.step"
},
// The sounds played when an entity's age is less than 0 (a baby).
"baby_sounds": {
"ambient_sound": "minecraft:entity.baby_pig.ambient",
"death_sound": "minecraft:entity.baby_pig.death",
"eat_sound": "minecraft:entity.baby_pig.eat",
"hurt_sound": "minecraft:entity.baby_pig.hurt",
"step_sound": "minecraft:entity.baby_pig.step"
}
}
For cats:
// A file located at:
// - `data/examplemod/cat_sound_variant/example_cat_sound.json`
{
// The sounds played when an entity's age is greater than or equal to 0 (an adult).
"adult_sounds": {
// The registry name of the sound event to play randomly on idle when tamed.
"ambient_sound": "minecraft:entity.cat.ambient",
// The registry name of the sound event to play when non-tamed and tempted by food.
"beg_for_food_sound": "minecraft:entity.cat.beg_for_food",
// The registry name of the sound event to play when killed.
"death_sound": "minecraft:entity.cat.death",
// The registry name of the sound event to play when fed.
"eat_sound": "minecraft:entity.cat.eat",
// The registry name of the sound event to play when hissing, typically at a pursuing phantom.
"hiss_sound": "minecraft:entity.cat.hiss",
// The registry name of the sound event to play when hurt.
"hurt_sound": "minecraft:entity.cat.hurt",
// The registry name of the sound event to play when purring, typically when in love or lying down.
"purr_sound": "minecraft:entity.cat.purr",
// The registry name of the sound event to play randomly on idle when tamed 25% of the time.
"purreow_sound": "minecraft:entity.cat.purreow",
// The registry name of the sound event to play randomly on idle when not tamed.
"stray_ambient_sound": "minecraft:entity.cat.stray_ambient"
},
// The sounds played when an entity's age is less than 0 (a baby).
"baby_sounds": {
"ambient_sound": "minecraft:entity.baby_cat.ambient",
"beg_for_food_sound": "minecraft:entity.baby_cat.beg_for_food",
"death_sound": "minecraft:entity.baby_cat.death",
"eat_sound": "minecraft:entity.baby_cat.eat",
"hiss_sound": "minecraft:entity.baby_cat.hiss",
"hurt_sound": "minecraft:entity.baby_cat.hurt",
"purr_sound": "minecraft:entity.baby_cat.purr",
"purreow_sound": "minecraft:entity.baby_cat.purreow",
"stray_ambient_sound": "minecraft:entity.baby_cat.stray_ambient"
}
}
net.minecraft.core.registries.RegistriesCAT_SOUND_VARIANT- The registry key for the sounds a cat should make.CHICKEN_SOUND_VARIANT- The registry key for the sounds a chicken should make.COW_SOUND_VARIANT- The registry key for the sounds a cow should make.PIG_SOUND_VARIANT- The registry key for the sounds a pig should make.
net.minecraft.network.synched.EntityDataSerializersCAT_SOUND_VARIANT- The entity serializer for the sounds a cat should make.CHICKEN_SOUND_VARIANT- The entity serializer for the sounds a chicken should make.COW_SOUND_VARIANT- The entity serializer for the sounds a cow should make.PIG_SOUND_VARIANT- The entity serializer for the sounds a pig should make.
net.minecraft.sounds.SoundEventsCAT_*sounds are now eitherHolder$References or stored in the map ofCAT_SOUNDSCHICKEN_*sounds are now eitherHolder$References or stored in the map ofCHICKEN_SOUNDSCOW_*sounds are stored in the map ofCOW_SOUNDSPIG_*sounds are now eitherHolder$References or stored in the map ofPIG_SOUNDS
net.minecraft.world.entity.animal.chickenChickenSoundVariant- The sounds that are played for a chicken variant.ChickenSoundVariants- All vanilla chicken variants.
net.minecraft.world.entity.animal.cowAbstractCow#getSoundSet- Gets the sounds a cow makes.CowSoundVariant- The sounds that are played for a cow variant.CowSoundVariants- All vanilla cow variants.
net.minecraft.world.entity.animal.felineCatSoundVariant- The sounds that are played for a cat variant.CatSoundVariants- All vanilla cat variants.
net.minecraft.world.entity.animal.chickenChickenSoundVariant- The sounds that are played for a chicken variant.ChickenSoundVariants- All vanilla chicken variants.
net.minecraft.world.entity.animal.pigPigSoundVariant- The sounds that are played for a pig variant.PigSoundVariants- All vanilla pig variants.
Audio Changes
Audio devices are now handled through the DeviceTracker which, depending on the backing machine, allows for either the machine to send system events when audio devices change, or using a standard polling interval to requery the list of available devices.
com.mojang.blaze3d.audioAbstractDeviceTracker- An abstract tracker for managing the changes of audio devices.CallbackDeviceTracker- A device tracker that uses the SOFT system events callback to determine changes.DeviceList- A list of all audio devices, including the default device, if available.DeviceTracker- An interface for managing the changes of audio devices.LibraryNO_DEVICEis nowpublicfromprivateinitnow takes in theDeviceListgetDefaultDeviceNamemoved toDeviceList#defaultDevicegetCurrentDeviceName->currentDeviceNamehasDefaultDeviceChangedmoved toAbstractDeviceTracker, not one-to-onegetAvailableSoundDevicesmoved toDeviceList, not one-to-onecreateDeviceTracker- Creates the tracker for managing audio device changes.getDebugString->getChannelDebugString
PollingDeviceTracker- A device tracker that uses polling intervals to determine changes.SoundBufferformat- The format of the sound stream.size- The number of bytes in the sound stream.isValid- If the sound stream is in a valid state.
net.minecraft.client.OptionsDEFAULT_SOUND_DEVICEis nowprivatefrompublicisSoundDeviceDefault- Checks if the device is the default audio device.
net.minecraft.client.gui.components.debugDebugEntrySoundCache- A debug entry displaying the current cache for loaded sound streams.DebugScreenEntries#SOUND_CACHE- The identifier for the sound stream cache debug information.
net.minecraft.client.soundsSoundBufferLibraryenumerate- Loops through all cached sounds, outputting its id, size, and format.$DebugOutput- An interface that accepts some sound metadata.$Counter- An output implementation that keepts track of the number of sound streams and the total size.
SoundEnginegetDebugString->getChannelDebugString,getSoundCacheDebugStats; not one-to-one$DeviceCheckStateis removed
SoundManager#getDebugString->getChannelDebugString,getSoundCacheDebugStats; not one-to-one
Input Message Editor Support
Minecraft now has support for Input Message Editors (IME), which allow complex characters from languages like Chinese or Hindi to be inputted instead of the temporary preedit text. The preedit text is displayed as an overlay within the game, while any other IME features provided by the host OS. With this addition, support can be added within screens through GuiEventListener#preeditUpdated, or by using an existing vanilla widget which implements the method.
com.mojang.blaze3d.platformInputConstants#setupKeyboardCallbacksnow takes in theGLFWCharCallbackIinstead ofGLFWCharModsCallbackIfor the character typed callback,GLFWPreeditCallbackIto handle inputting complex characters via an input method editor, andGLFWIMEStatusCallbackIfor notifying about the status of the editorMessageBox- A utility for creating OS native messages boxes.TextInputManager- A manager for handling when text is inputted in the game window.setTextInputArea- Sets the area where the predicted text cursor should appear.startTextInput,stopTextInput- Handles toggling the input message editor.
net.minecraft.clientKeyboardHandlerresubmitLastPreeditEvent- Repeats the last preedit event that was sent.submitPreeditEvent- Tells the listener that the preedit text has been updated.
MinecrafttextInputManager- Returns the input manager.onTextInputFocusChange- Changes the editor input status based on if the text input is focused.
net.minecraft.client.gui.GuiGraphicssetPreeditOverlay- Sets the overlay drawing the preedit text.renderDeferredElementsnow takes in theints for the mouse position and the game time delta ticksfloat
net.minecraft.client.gui.componentsIMEPreeditOverlay- The overlay for displaying the preedit text for an input message editor.TextCursorUtils- A utility for drawing the text cursor.
net.minecraft.client.gui.components.events.GuiEventListener#preeditUpdated- Listens for when the preedit text changes.net.minecraft.client.inputCharacterEventno longer takes in the modifierintsetPreeditEvent- An event containing the preedit text along with the cursor location.
Cauldron Interaction Dispatchers
Cauldron interactions have been reorganized somewhat, with all registration being moved to CauldronInteractions from CauldronInteraction. In addition, the backing $InteractionMap for a cauldron type has been replaced with a $Dispatcher that can register interactions for both tags and items. Tags are checked before items.
CauldronInteractions.EMPTY.put(
// The Item or TagKey to use
ItemTags.WOOL,
// The cauldron interaction to apply
(state, level, pos, player, hand, itemInHand) -> InteractionResult.TRY_WITH_EMPTY_HAND
);
net.minecraft.core.cauldronCauldronInteraction- All fields regarding to registering interactions to a map have been moved to
CauldronInteractionsINTERACTIONS->CauldronInteractions#ID_MAPPER, nowprivate
DEFAULT- The default interaction with a cauldron$InteractionMap->$Dispatcher, not one-to-one
- All fields regarding to registering interactions to a map have been moved to
CauldronInteractions- All vanilla cauldron interactions.
Rule-Based Block State Providers
RuleBasedStateProvider now extends BlockStateProvider, allowing it to be used wherever a state provider is required. It’s implementation hasn’t changed, now only requiring rule_based_state_provider to be specified as the type. As such, all configurations that used RuleBasedBlockStateProvider have been broadened to allow any BlockStateProvider.
net.minecraft.world.level.levelgen.feature.configurationsDiskConfigurationnow takes in aBlockStateProviderinstead of aRuleBasedBlockStateProviderTreeConfigurationnow takes in aBlockStateProviderinstead of aRuleBasedBlockStateProviderbelowTrunkProvideris now aBlockStateProviderinstead of aRuleBasedBlockStateProvider$TreeConfigurationBuildernow takes in aBlockStateProviderinstead of aRuleBasedBlockStateProvider
net.minecraft.world.level.levelgen.feature.stateprovidersBlockStateProvider#getOptionalState- Gets the state of the block, or otherwisenull.BlockStateProviderType#RULE_BASED_STATE_PROVIDER- The type for the rule based state provider.RuleBasedBlockStateProvider->RuleBasedStateProvider, now a class, implementingBlockStateProvider- The constructor can now take in a nullable fallback
BlockStateProvider ifTrueThenProvide- If the predicate is true, provide the given block.simple->always$Builder- A builder for constructing the rules for the block to place.
- The constructor can now take in a nullable fallback
Fluid Logic Reorganization
Generic entity fluid movement has been moved into a separate EntityFluidInteraction class, where all tracked fluids are updated and then potentially pushed by the current at a layer time.
net.minecraft.world.entityEntityupdateInWaterStateAndDoFluidPushing->updateFluidInteraction, not one-to-oneupdateFluidHeightAndDoFluidPushing->EntityFluidInteraction#updategetFluidInteractionBox- Gets the bounding box of the entity during fluid interactions.modifyPassengerFluidInteractionBox- Returns the modified bounding box of the entity when riding in some vehicle.
EntityFluidInteraction- A handler for managing the fluid interactions and basic movement with an entity.
net.minecraft.world.level.chunk.LevelChunkSection#hasFluid- Whether the chunk section has a fluid block.
Removal of Random Patch Feature
The random patch feature has been completely removed in favor of using placements like most other features. To convert, the ConfiguredFeature defined as part of the configuration should be its own file. Then, the placements should specify the CountPlacement, followed by the RandomOffsetPlacement using a TrapezoidInt, and finished with a BlockPredicateFilter:
// In `data/examplemod/worldgen/configured_feature/example_configured_feature.json`
{
// Previously config.feature.feature
"type": "minecraft:simple_block",
"config": {
"to_place": {
"type": "minecraft:simple_state_provider",
"state": {
"Name": "minecraft:sweet_berry_bush",
"Properties": {
"age": "3"
}
}
}
}
}
// In `data/examplemod/worldgen/placed_feature/example_placed_feature.json`
{
"feature": "examplemod:example_configured_feature",
"placement": [
{
// Previously config.tries
"type": "minecraft:count",
"count": 96
},
{
"type": "minecraft:random_offset",
"xz_spread": {
// Previously config.xz_spread
// The min and max are additive inverses
"type": "minecraft:trapezoid",
"max": 7,
"min": -7,
"plateau": 0
},
"y_spread": {
// Previously config.y_spread
"type": "minecraft:trapezoid",
"max": 3,
"min": -3,
"plateau": 0
}
},
{
// Previously config.feature.placement
// This contains the placements of the original placed feature
"type": "minecraft:block_predicate_filter",
"predicate": {
"type": "minecraft:all_of",
"predicates": [
{
"type": "minecraft:matching_block_tag",
"tag": "minecraft:air"
},
{
"type": "minecraft:matching_blocks",
"blocks": "minecraft:grass_block",
"offset": [ 0, -1, 0 ]
}
]
}
}
]
}
net.minecraft.data.worldgen.featuresFeatureUtils#simpleRandomPatchConfiguration,simplePatchConfigurationare removed- Typically replaced by
Feature#SIMPLE_BLOCKwith placements for random offset and filters
- Typically replaced by
NetherFeatures#PATCH_*fields no longer has thePATCH_*prefixVegetationFeaturesPATCH_*fields no longer has thePATCH_*prefixWILDFLOWERS_BIRCH_FOREST,WILDFLOWERS_MEADOW->WILDFLOWER, not one-to-onePALE_FOREST_FLOWERS->PALE_FOREST_FLOWER
net.minecraft.world.level.biome.BiomeGenerationSettings#getFlowerFeatures->getBoneMealFeaturesnet.minecraft.world.level.levelgen.featureConfiguredFeature#getFeatures->getSubFeatures, now returning a stream of holders-wrappedConfiguredFeatures without this featureFeatureFLOWER,NO_BONEMEAL_FLOWERare removedRANDOM_PATCHis removed
RandomPatchFeatureclass is removed
net.minecraft.world.level.levelgen.feature.configurationsFeatureConfiguration#getFeatures->getSubFeatures, now returning a stream of holders-wrappedConfiguredFeaturesRandomPatchConfigurationrecord is removed
net.minecraft.world.level.levelgen.placement.PlacedFeature#getFeaturesnow returns a stream of holders-wrappedConfiguredFeatures with this feature concatenated
Specific Logic Changes
- Picture-In-Picture submission calls are now taking in
0xF000F0instead of0x000000for the light coordinates. net.minecraft.client.multiplayer.RegistryDataCollector#collectGameRegistriesbooleanparameter now handles only updating components from synchronized registries along with tags.net.minecraft.client.renderer.RenderPipelines#VIGNETTEnow blends the alpha with a source of zero and a destination of one.net.minecraft.server.packs.PathPackResources#getResource,listPath,listResourcesresolves the path using the identifier’s namespace first.net.minecraft.world.entity.EntitySelector#CAN_BE_PICKEDcan now find entities in spectator mode, assumingEntity#isPickableis true.net.minecraft.world.entity.ai.sensing.NearestVisibleLivingEntitySensor#requiresis no longer implemented by default.net.minecraft.world.level.levelgen.WorldOptions#generate_featuresfield in JSON has been renamed togenerate_structuresto match its java field name.net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate#ONLY_IN_AIR_PREDICATEnow matches the air tag instead of just the air block.net.minecraft.world.level.timersFunctionCallback,FunctionTagCallbacknow useidinstead ofNamewhen serializingTimerCallbacksnow usestypeinstead ofTypewhen serializing
Data Component Additions
dye- Sets the item as a dye material, used in specific circumstances.additional_trade_cost- A modifier that offsets the trade cost by the specified amount.pig/sound_variant- The sounds a pig should make.cow/sound_variant- The sounds a cow should make.chicken/sound_variant- The sounds a chicken should make.cat/sound_variant- The sounds a cat should make.
Environment Attribute Additions
visual/block_light_tint- Tints the color of the light emitted by a block.visual/night_vision_color- The color when night vision is active.visual/ambient_light_color- The color of the ambient light in an environment.
Tag Changes
minecraft:blockbamboo_plantable_on->supports_bamboomushroom_grow_block->overrides_mushroom_light_requirementsmall_dripleaf_placeable->supports_small_dripleafbig_dripleaf_placeable->supports_big_dripleafdry_vegetation_may_place_on->supports_dry_vegetationsnow_layer_cannot_survive_on->cannot_support_snow_layersnow_layer_can_survive_on->support_override_snow_layerenables_bubble_column_drag_downenables_bubble_column_push_upsupports_vegetationsupports_cropssupports_stem_cropssupports_stem_fruitsupports_pumpkin_stemsupports_melon_stemsupports_pumpkin_stem_fruitsupports_melon_stem_fruitsupports_sugar_canesupports_sugar_cane_adjacentlysupports_cactussupports_chorus_plantsupports_chorus_flowersupports_nether_sproutssupports_azaleasupports_warped_fungussupports_crimson_fungussupports_mangrove_propagulesupports_hanging_mangrove_propagulesupports_nether_wartsupports_crimson_rootssupports_warped_rootssupports_wither_rosesupports_cocoasupports_lily_padsupports_frogspawnsupport_override_cactus_flowercannot_support_seagrasscannot_support_kelpgrows_cropsmudmoss_blocksgrass_blockssubstrate_overworldbeneath_tree_podzol_replaceablebeneath_bamboo_podzol_replaceablecannot_replace_below_tree_trunkice_spike_replaceableforest_rock_can_place_onhuge_brown_mushroom_can_place_onhuge_red_mushroom_can_place_onprevents_nearby_leaf_decay
minecraft:enchantmenttrades/desert_specialis removedtrades/jungle_specialis removedtrades/plains_specialis removedtrades/savanna_specialis removedtrades/snow_specialis removedtrades/swamp_specialis removedtrades/taiga_specialis removed
minecraft:entity_typecannot_be_age_locked
minecraft:fluidsupports_sugar_cane_adjacentlysupports_lily_padsupports_frogspawnbubble_column_can_occupy
minecraft:itemmetal_nuggetsdyeableis removed, split between:dyesloom_dyesloom_patternscauldron_can_remove_duecat_collar_dyeswolf_collar_dyes
mudmoss_blocksgrass_blocks
minecraft:potiontradable
minecraft:worldgen/configured_featurecan_spawn_from_bone_meal
List of Additions
net.minecraft.advancements.criterionFoodPredicate- A criterion predicate that can check the food level and saturation.MinMaxBoundsvalidateContainedInRange- Returns a function which validates the target range and returns as a data result.$Bounds#asRange- Converts the bounds into aRange.
net.minecraft.clientMinecraft#sendLowDiskSpaceWarning- Sends a system toast for low disk space.Options#keyDebugLightmapTexture- A key mapping to show the lightmap texture.
net.minecraft.client.gui.componentsAbstractScrollAreascrollbarWidth- The width of the scrollbar.defaultSettings- Constructs the default scrollbar settings given the scroll rate.$ScrollbarSettings- A record containing the metadata for the scrollbar.
DebugScreenOverlayshowLightmapTexture- Whether to render the lightmap texture on the overlay.toggleLightmapTexture- Toggles whether the lightmap texture should be rendered.
ScrollableLayoutsetMinHeight- Sets the minimum height of the container layout.$ReserveStrategy- What to use when reserving the width of the scrollbar within the layout.
Tooltipcomponent- The component of a tooltip to display.style- The identifier used to compute the tooltip background and frame.
net.minecraft.client.gui.components.debugDebugEntryDetailedMemory- A debug entry displaying the detailed memory usage.DebugEntryLookingAt#getHitResult- Gets the hit result of the camera entity.DebugEntryLookingAtEntityTags- A debug entry for displaying an entity’s tags.DebugScreenEntriesDETAILED_MEMORY- The identifier for the detailed memory usage debug entry.LOOKING_AT_ENTITY_TAGS- The identifier for the entity tags debug entry.
net.minecraft.client.gui.navigation.FocusNavigationEvent$ArrowNavigation#with- Sets the previous focus of the navigation.net.minecraft.client.gui.screens.GenericWaitingScreene#createWaitingWithoutButton- Creates a waiting screen without showing the button to cancel.net.minecraft.client.gui.screens.optionsDifficultyButtons- A class containing the layout element to create the difficulty buttons.HasGamemasterPermissionReaction- An interface marking an option screen as able to respond to changing gamemaster permissions.OptionsScreen#getLastScreen- Returns the previous screen that navigated to this one.WorldOptionsScreen- A screen containing the options for the current world the player is in.
net.minecraft.client.gui.screens.worldselection.EditWorldScreen#conditionallyMakeBackupAndShowToast- Only makes the backup and shows a toast if the passed inbooleanis true; otherwise, returns afalsefuture.net.minecraft.client.multiplayer.MultiPlayerGameMode#spectate- Sends a packet to the server that the player will spectate the given entity.net.minecraft.client.multiplayer.prediction.BlockStatePredictionHandler#onTeleport- Runs when a player is moved on the server, typically from some kind of teleportation (e.g. commands, riding an entity).net.minecraft.client.rendererLightmapRenderStateExtractor- Extracts the render state for the lightmap.UiLightmap- The lightmap when in a user interface.RenderPipelinesLINES_DEPTH_BIAS- A render pipeline that sets the polygon depth offset factor to -1 and the units to -1.ENTITY_CUTOUT_DISSOLVE- A render pipeline that dissolves an entity model into the background using a mask sampler.
net.minecraft.client.renderer.rendertype.RenderType#hasBlending- Whether the pipeline has a defined blend function.net.minecraft.commands.ArgumentVisitor- A helper for visiting the arguments for a command.net.minecraft.commands.arguments.selector.EntitySelector#COMPILABLE_CODEC- ACompilableStringcodec wrapped around anEntitySelectorParser.net.minecraft.core.component.predicatesDataComponentPredicates#VILLAGER_VARIANT- A predicate that checks a villager type.VillagerTypePredicate- A predicate that checks a villager’s type.
net.minecraft.core.dispenser.SpawnEggItemBehavior- The dispenser behavior for spawn eggs.net.minecraft.core.registries.ConcurrentHolderGetter- A getter that reads references from a local cache, synchronizing to the original when necessary.net.minecraft.dataBlockFamiliesEND_STONE- A family for end stone variants.getFamily- Gets the family for the base block, when present.
BlockFamily$Builder#tiles,$Variant#TILES- The block that acts as the tiles variant for some base block.$Builder#bricks,$Variant#BRICKS- The block that acts as the bricks variant for some base block.$Builder#cobbled,$Variant#COBBLED- The block that acts as the cobbled variant from some base block.
DataGenerator$Uncached- A data generator which does not cache any information about the files generated.
net.minecraft.data.recipes.RecipeProviderbricksBuilder,tilesBuilder- Builders for the bricks and tiles block variants.generateCraftingRecipe,generateStonecutterRecipe- Generates the appropriate recipes for the given block family.getBaseBlock->getBaseBlockForCraftingbredAnimal- Unlocks the recipe if the player has bred two animals together.
net.minecraft.gametest.frameworkGameTestEvent#createWithMinimumDelay- Creates a test event with some minimum delay.GameTestHelpergetBoundsWithPadding- Gets the bounding box of the test area with the specified padding.runBeforeTestEnd- Runs the runnable at one tick before the test ends.despawnItem- Despawns all item entities within the distance of the position.discard- Discards the entity.setTime- Sets the time of the dimension’s default clock.placeBlock- Places the given block at the relative position and direction.
GameTestInstance#padding- The number of blocks spaced around each game test.GameTestSequence#thenWaitAtLeast- Waits for at least the specified number of ticks before running the runnable.
net.minecraft.nbt.TextComponentTagVisitor$PlainStyling- A styling that stores the nbt in a component literal map.$RichStyling- A styling that stores the nbt with syntax highlighting and formatting.$Styling- An interface defining how the read tag should be styled.$Token- The tokens used to more richly represent the tag datas.
net.minecraft.network.chat.ResolutionContext- The context that the component is being resolved to a string within.net.minecraft.network.chat.contents.NbtContents#NBT_PATH_CODEC- ACompilableStringcodec wrapped around aNbtPathArgument$NbtPath.net.minecraft.network.chat.contents.data.BlockDataSource#BLOCK_POS_CDEC- ACompilableStringcodec wrapped aroundCoordinates.net.minecraft.network.protocol.gameClientboundGameRuleValuesPacket- A packet that sends the game rule values in string form to the client.ClientboundGamePacketListener#handleGameRuleValues- Handles the game rule values sent from the server.ClientboundLowDiskSpaceWarningPacket- A packet sent to the client warning about low disk space on the machine.ClientGamePacketListener#handleLowDiskSpaceWarning- Handles the warning packet about low disk space.ServerboundAttackPacket- A packet sent to the server about what entity the player attacked.ServerboundClientCommandPacket$Action#REQUEST_GAMERULE_VALUES- Requests the game rule values from the server.ServerboundSetGameRulePacket- A packet that sends the game rules entries to set from the client.ServerboundSpectateEntityPacket- A packet sent to the server about what entity the player wants to spectate.ServerGamePacketListenerhandleAttack- Handles the player’s attack on an entity.handleSpectateEntity- Handles the player wanting to spectate an entity.handleSetGameRule- Handles setting the game rules from the client.
net.minecraft.resourcesFileToIdConverter#extensionMatches- Checks if the identifier ends with the specified extension.IdentifierALLOWED_NAMESPACE_CHARACTERS- The characters allowed in an identifier’s namespace.resolveAgainst- Resolves the path from the given root by checking/<namespace>/<path>.
net.minecraft.serverBootstrap#shutdownStdout- Closes the stdout stream.MinecraftServerDEFAULT_GAME_RULES- The supplied default game rules for a server.warnOnLowDiskSpace- Sends a warning if the disk space is below 64 MiB.sendLowDiskSpaceWarning- Sends a warning for low disk space.
net.minecraft.server.commands.SwingCommand- A command that callsLivingEntity#swingfor all targets.net.minecraft.server.level.ServerPlayersendBuildLimitMessage- Sends an overlay message if the player cannot build anymore in the cooresponding Y direction.sendSpawnProtectionMessage- Sends an overlay message if the player cannot modify the terrain due to spawn protection.
net.minecraft.server.packs.AbstractPackResources#loadMetadata- Loads the rootpack.mcmeta.net.minecraft.server.packs.resources.ResourceMetadata$MapBased- A resource metadata that stores the sections in a map.net.minecraft.tags.TagLoader$ElementLookup#fromGetters- Constructs an element lookup from the givenHolderGetters depending on whether the element is required or not.net.minecraft.utilARGB#gray- Gets a grayscale color based on the given brightness.CompilableString- A utility for taking some string pattern and compiling it to an object through some parser.LightCoordsUtil- A utility for determining the light coordinates from light values.ProblemReporter$MapEntryPathElement- A path element for some entry key in a map.Util#allOfEnumExcept- Gets the set of all enums except the provided value.
net.minecraft.util.thread.BlockableEventLoop#hasDelayedCrash- Whether there is a crash report queued.net.minecraft.util.valueproviders.TrapezoidInt- Samples a random value with a trapezoidal distribution.net.minecraft.world.InteractionHand#STREAM_CODEC- The network codec for the interaction hand.net.minecraft.world.attributeAttributeType#toFloat- Gets the attribute value as afloat, or throws an exception if not defined.AttributeTypes#INTEGER- An integer attribute type.LerpFunction#ofInteger- A lerp function for an integer value.
net.minecraft.world.attribute.modifierAttributeModifier#INTEGER_LIBRARY- A library of operators to apply for integers.IntegerModifier- A modifier that applies some argument to the integer value.
net.minecraft.world.entityAgeableMobAGE_LOCK_COOLDOWN_TICKS- The number of ticks to wait before the entity can be age locked/unlocked.ageLockParticleTimer- The time for displaying particles while age locking/unlocking.
EntityapplyEffectsFromBlocksForLastMovements- Applies any block effects to this entity for the last movement, used by items.$Flags- An annotation that marks a particular value as a bitset of flags for an entity.
LivingEntity#getLiquidCollisionShape- Return’s the bounds of the entity when attempting to collide with a liquid.MobasValidTarget- Checks whether an entity is a valid target (can attack) for this entity.getTargetUnchecked- Gets the raw target without checking if its valid.canAgeUp- If the entity can grow up into a more mature variant.setAgeLocked,isAgeLocked- Whether the entity cannot grow up.
NeutralMob#getTargetUnchecked- Gets the raw target without checking if its valid.TamableAnimal#feed- The player gives the stack as food, healing them either based on the stored component or some default value.
net.minecraft.world.entity.ai.behaviorBehaviorControl#getRequiredMemories- The list of memories required by the behavior.GoAndGiveItemsToTarget$ItemThrower- An interface that handles what should occur if an item is thrown because of this entity’s behavior.
net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder$TriggerWithResult#memories- The list of memories required by the behavior.net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities#nearbyEntities- The list of entities within the follow range of this one.net.minecraft.world.entity.decoration.LeashFenceKnotEntitygetKnot- Finds the knot at the given position, else returns an empty optional.createKnot- Creates a new knot and adds it to the level.
net.minecraft.world.entity.monster.piglinPiglinAiMAX_TIME_BETWEEN_HUNTS- The maximum number of seconds before a piglin begins to hunt again.findNearbyAdultPiglins- Returns a list of all adult piglins in this piglin’s memory.
net.minecraft.world.entity.raid.RaidgetBannerComponentPatch- Gets the components of the banner pattern.getOminousBannerTemplate- Gets the stack template for the omnious banner.
net.minecraft.world.inventory.SlotRangesMOB_INVENTORY_SLOT_OFFSET- The start index of a mob’s inventory.MOB_INVENTORY_SIZE- The size of a mob’s inventory.
net.minecraft.world.item.component.BundleContents#BEEHIVE_WEIGHT- The weight of a beehive.net.minecraft.world.item.enchantment.EnchantmentTarget#NON_DAMAGE_CODEC- A codec that only allows the attacker and victim enchantment targets.net.minecraft.world.level.block.BigDripleafBlock#canGrowInto- Whether the dripleaf can grow into the specified position.net.minecraft.world.level.block.grower.TreeGrower#getMinimumHeight- If present, gets the base height of the trunk placer.net.minecraft.world.level.block.stateBlockBehaviour$PostProcess- An interface that gets the position to mark for post-processing.StateDefinitionpropertiesCodec- The map codec for the state properties.isSingletonState- If the definition only contains one state.
StateHolder#isSingletonState- If the holder only contains one state.
net.minecraft.world.level.block.state.propertiesNoteBlockInstrumentTRUMPET- The sound a copper block makes when placed under a note block.TRUMPET_EXPOSED- The sound an exposed copper block makes when placed under a note block.TRUMPET_OXIDIZED- The sound an oxidized copper block makes when placed under a note block.TRUMPET_WEATHERED- The sound a weathered copper block makes when placed under a note block.
Property$Value#valueName- Gets the name of the value.
net.minecraft.world.level.dimension.DimensionDefaultsBLOCK_LIGHT_TINT- The default tint for the block light.NIGHT_VISION_COLOR- The default color when in night vision.TURTLE_EGG_HATCH_CHANCE- The chance of a turtle egg hatching on a random tick.
net.minecraft.world.level.gamerules.GameRule#getIdentifierWithFallback- Gets the identifier of the game rule, or else the unregistered identifier.net.minecraft.world.level.levelgenNoiseBasedChunkGenerator#getInterpolatedNoiseValue- Gets the interpolated density at the given position, or the not-a-number value if the Y is outside the range of the noise settings.NoiseChunk#getInterpolatedDensity- Computes the full noise density.
net.minecraft.world.level.levelgen.feature.AbstractHugeMushroomFeature#MIN_MUSHROOM_HEIGHT- The minimum mushroom height.net.minecraft.world.level.levelgen.feature.configurations.BlockBlobConfiguration- The configuration for the block blob feature.net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacer#getBaseHeight- Returns the minimum height of the trunk.net.minecraft.world.level.levelgen.placement.RandomOffsetPlacement#ofTriangle- Creates a trapezoidal distribution to select from for the XZ and Y range.net.minecraft.world.level.materialFluidState#isFull- If the fluid amount is eight.LavaFluid#LIGHT_EMISSION- The amount of light the lava fluid emits.
net.minecraft.world.level.pathfinder.PathType#BIG_MOBS_CLOSE_TO_DANGER- A path malus for mobs with an entity width greater than a block.net.minecraft.world.level.storage.LevelStorageSource#writeWorldGenSettings- Wriets the world generation settings to its saved data location.net.minecraft.world.level.storage.loot.functionsEnchantRandomlyFunction$Builder#withOptions- Specifies the enchantments that can be used to randomly enchant this item.SetRandomDyesFunction- An item function that applies a random dye (if the item is in thedyeabletag) to theDYED_COLORcomponent from the provided list.SetRandomPotionFunction- An item function that applies a random potion to thePOTION_CONTENTScomponent from the provided list.
net.minecraft.world.level.storage.loot.parameters.LootContextParams#ADDITIONAL_COST_COMPONENT_ALLOWED- Enables a trade to incur an additional cost if desired by the wanted stack or modifiers.net.minecraft.world.level.storage.loot.predicates.EnvironmentAttributeCheck- A loot condition that checks whether that given attribute matches the provided value.net.minecraft.world.level.storage.loot.providers.numberEnvironmentAttributeValue- A provider that gets the attribute value as a float.Sum- A provider that sums the value of all provided number providers.
net.minecraft.world.phys.AABB$Builder#isDefined- Checks if there is at least one point making up the bounding box.
List of Changes
net.minecraft.advancements.criterionEntityTypePredicate#matchesnow takes in a holder-wrappedEntityTypeinstead of the raw type itselfKilledTrigger$TriggerInstance#entityPredicate->entityPlayerPredicatenow takes in aFoodPredicate- Can be set using
PlayerPredicate$Builder#setFood
- Can be set using
net.minecraft.client.guiGuiGraphicsblitnow has an overload that takes in theGpuTextureViewand theGpuSamplersetTooltipForNextFramenow has an overload that takes in a list ofFormattedCharSequences for the tooltip and whether to replace any existing tooltip
ItemSlotMouseAction#onSlotClickednow takes in aContainerInputinstead of aClickType
net.minecraft.client.gui.componentsAbstractContainerWidgetnow takes in anAbstractScrollArea$ScrollbarSettingsAbstractScrollAreanow takes in anAbstractScrollArea$ScrollbarSettingsscrollbarVisible->scrollablescrollBarYis now publicscrollRateis now longer abstract
AbstractTextAreaWidgetnow takes in anAbstractScrollArea$ScrollbarSettingsPopupScreen$Builder#setMessage->addMessage, not one-to-oneScrollableLayout$Containernow takes in anAbstractScrollArea$ScrollbarSettingsTooltip#createnow has an overload that takes in an optionalTooltipComponentand styleIdentifier
net.minecraft.client.gui.components.debugDebugEntryLookingAtBlock,DebugEntryLookingAtFluid->DebugEntryLookingAt- More specifically,
$BlockStateInfo,$BlockTagInfo,$FluidStateInfo,$FluidTagInfo
- More specifically,
DebugEntryLookingAtEntity#GROUPis now publicDebugScreenEntriesLOOKING_AT_BLOCK->LOOKING_AT_BLOCK_STATE,LOOKING_AT_BLOCK_TAGSLOOKING_AT_FLUID->LOOKING_AT_FLUID_STATE,LOOKING_AT_FLUID_TAGS
DebugScreenEntryListnow takes in aDataFixer
net.minecraft.client.gui.components.tabs.TabNavigationBar#setWidth->updateWidth, not one-to-onenet.minecraft.client.gui.navigation.FocusNavigationEvent$ArrowNavigationnow takes in a nullableScreenRectanglefor the previous focusnet.minecraft.client.gui.screensConfirmScreen#layoutis now finalDemoIntroScreenreplaced byClientPacketListener#openDemoIntroScreen, now privateGenericWaitingScreennow takes in threebooleans for showing the loading dots, the cancel button, and whether the screen should close on escape
net.minecraft.client.gui.screens.inventory.AbstractMountInventoryScreen#mountis now finalnet.minecraft.client.gui.screens.optionsOptionsScreennow implementsHasGamemasterPermissionReaction- The constructor now takes in a
booleanfor if the player is currently in a world createDifficultyButtonnow handles withinWorldOptionsScreen#createDifficultyButtons, not one-to-one
- The constructor now takes in a
WorldOptionsScreennow implementsHasGamemasterPermissionReactioncreateDifficultyButtons->DifficultyButtons#create, now public
net.minecraft.client.multiplayerClientLevel#syncBlockStatecan now take in a nullable player positionMultiPlayerGameMode#handleInventoryMouseClicknow takes in aContainerInputinstead of aClickTypeWeatherEffectRenderer#renderno longer takes in theMultiBufferSource
net.minecraft.client.renderer.block.ModelBlockRenderer$Cache#getLightColor->getLightCoordsnet.minecraft.client.renderer.blockentity.stateBrushableBlockRenderState#itemStateis now finalEndPortalRenderStateis now a final set ofDirections rather than anEnumSetShelfRenderState#itemsis now final
net.minecraft.client.renderer.entity.stateFallingBlockRenderState#movingBlockRenderStateis now finalHumanoidRenderState#attackArm->ArmedEntityRenderState#attackArmWitherRenderState#xHeadRots,yHeadRotsare now final
net.minecraft.client.resources.sounds.AbstractSoundInstance#randomis now finalnet.minecraft.commands.SharedSuggestionProvider#getCustomTabSugggestions->getCustomTabSuggestionsnet.minecraft.commands.arguments.ComponentArgument#getResolvedComponentnow takes in a non-nullableEntitynet.minecraft.commands.arguments.selector.SelectorPatternreplaced byCompilableStringnet.minecraft.core.HolderGetter$Provider#get,getOrThrownow has overloads that take in theTagKeynet.minecraft.dataBlockFamilyshouldGenerateRecipe->shouldGenerateCraftingRecipe,shouldGenerateStonecutterRecipe$Builder#dontGenerateRecipe->dontGenerateCraftingRecipe,generateStonecutterRecipe
DataGeneratoris now abstract- The constructor now only takes in the
Pathoutput, not theWorldVersionor whether to always generate- The original implementation can be founded in
DataGenerator$Cached
- The original implementation can be founded in
runis now abstract
- The constructor now only takes in the
Main#addServerProviders->addServerDefinitionProviders, no longer taking in the devboolean, not one-to-one- The remaining logic has been put into
addServerConverters, taking in the devbooleanbut not the reportboolean
net.minecraft.data.loot.BlockLootSubProviderexplosionResistantis now privateenabledFeaturesis now privatemapis now private
net.minecraft.data.recipesRecipeProvider$FamilyRecipeProvider->$FamilyCraftingRecipeProvider,$FamilyStonecutterRecipeProviderSingleItemRecipeBuilder#stonecuttingmoved to a parameter on theBlockFamily
net.minecraft.data.structures.SnbtToNbtnow has an overload that takes in a single input folder pathnet.minecraft.gametest.frameworkGameTestHelperassertBlockPresentnow has an overload that only takes in the block to check formoveTonow has overloads for taking in theBlockPosandVec3for the positionassertEntityInstancePresentnow has an overload that inflates (via adouble) the bounding box to check entities within
GameTestServer#createnow takes in anintfor the number of times to run all matching testsStructureUtils#testStructuresDirsplit intotestStructuresTargetDir,testStructuresSourceDirTestDatanow takes in anintfor the number of blocks padding around the test
net.minecraft.nbtNbtUtilsaddDataVersionnow uses a generic for theDynamicinstead of the explicit nbt taggetDataVersionnow has an overload that defaults to -1 if the version is not specified
TextComponentTagVisitorcan now take in a$Stylingand abooleanof whether to sort the keyshandleEscapePrettyis now aprivateinstance method fromprotectedstatic
net.minecraft.network.FriendlyByteBufreadVec3,writeVec3replaced withVec3#STREAM_CODECreadLpVec3,writeLpVec3replaced withVec3#LP_STREAM_CODEC
net.minecraft.network.chatComponentnbtnow takes in aCompilableStringinstead of aStringobjectnow has an overload that takes in aComponentfallback
ComponentContents#resolvenow takes in aResolutionContextinstead of theCommandSourceStackandEntityComponentUtils#updateForEnttiy->resolve, taking in theResolutionContextinstead of theCommandSourceStackandEntityLastSeenMessages#EMPTYis now final
net.minecraft.network.chat.contentsNbtContentsis now a record, the constructor taking in aCompilableStringinstead of aStringObjectContentsnow takes in an optionalComponentfor the fallback if its contents cannot be validated
net.minecraft.network.chat.contents.dataBlockDataSourcenow takes in aCompilableStringfor theCoordinatesinstead of the pattern and compiled positionEntityDataSourcenow takes in aCompilableStringfor theEntitySelectorinstead of the pattern and compiled selector
net.minecraft.network.chat.contents.objects.ObjectInfo#description->defaultFallbacknet.minecraft.network.protocol.gameClientboundSetEntityMotionPacketis now a recordServerboundContainerClickPacketnow takes in aContainerInputinstead of aClickTypeServerboundInteractPacketis now a record, now taking in theVec3interaction location
net.minecraft.referencesBlocks->BlockIdsItems->ItemIds
net.minecraft.resourcesFileToIdConverteris now a recordRegistryDataLoader#loadnow returns aCompletableFutureof the frozen registry access
net.minecraft.server.MinecraftServernow takes in abooleanof whether to propogate crashes, usually to throw a delayed crashthrowIfFatalException->BlockableEventLoop#throwDelayedException, now private, not one-to-onesetFatalException->BlockableEventLoop#delayCrash,relayDelayCrash; not one-to-one
net.minecraft.server.commands.ChaseCommand#DIMENSION_NAMESis now finalnet.minecraft.server.dedicated.DedicatedServerProperties#acceptsTransfersis now finalnet.minecraft.server.packsBuiltInMetadatahas been merged inResourceMetadataget->ResourceMetadata#getSectionof->ResourceMetadata#of
PathPackResources#getNamespacesnow has a static overload that takes in the root directoryPathVanillaPackResourcesBuilder#setMetadatanow takes in aResourceMetadatainstead of aBuiltInMetadata
net.minecraft.server.players.OldUsersConverter#serverReadyAfterUserconversionreplaced byareOldUserListsRemoves, nowpublicnet.minecraft.tags.TagLoaderloadTagsFromNetworknow takes in aRegistryinstead of aWritableRegistry, returning a map of tag keys to a list of holder entriesloadTagsForRegistrynow has an overload which takes in registry key along with an element lookup, returning a map of tag keys to a list of holder entries
net.minecraft.utilBrightnesspack->LightCoordsUtil#packblock->LightCoordsUtil#blocksky->LightCoordsUtil#sky
RandomSource#createNewThreadLocalInstance->createThreadLocalInstance- Now has an overload to specify the seed
Util#copyAndAddnow has an overload that takes in a varargs of elements
net.minecraft.util.threadBlockableEventLoopnow takes in abooleanof whether to propogate crashes, usually to throw a delayed crashReentrantBlockableEventLoopnow takes in abooleanof whether to propogate crashes, usually to throw a delayed crash
net.minecraft.world.InteractionResult$ItemContext#NONE,DEFAULTare now finalnet.minecraft.world.attributeAttributeTypenow takes in aToFloatFunctionfor use in a number providerofInterpolatednow takes in aToFloatFunction
EnvironmentAttributeReader#getValuenow has an overload that takes in theLootContext
net.minecraft.world.entityAvataris now abstractEntityfluidHeightis now finalgetTags->entityTagsgetRandomYnow has an overload that specifies the spreaddouble
Leashable$Wrench#ZEROis now finalLivingEntityinterpolationis now finalswingingArmis now nullablecanAttackType->canAttack, not one-to-one, taking in theLivingEntityinstead of theEntityTypelungeForwardMaybe->postPiercingAttackentityAttackRange->getAttackRangeWith, now taking in theItemStackused to attack
net.minecraft.world.entity.ai.behaviorGoAndGiveItemsToTargetnow takes in the$ItemThrowerthrowItem->BehaviorUtils#throwItem, not one-to-one
SpearAttackno longer takes in the approach distancefloatTryLaySpawnOnWaterNearLand->TryLaySpawnOnFluidNearLand, not one-to-one
net.minecraft.world.entity.ai.behavior.declarative.BehaviorBuilder#sequencenow takes in aOneshotfor the second entry instead of aTriggernet.minecraft.world.entity.ai.goalBoatGoals->FollowPlayerRiddenEntityGoal$FollowEntityGoalBOATis replaced byENTITY
FollowBoatGoal->FollowPlayerRiddenEntityGoal, not one-to-one
net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal#targetConditionsis now finalnet.minecraft.world.entity.ai.sensing.NearestVisibleLivingEntitySensor#getMemory->getMemoryToSetnet.minecraft.world.entity.decoration.Mannequin#getProfile->Avatar#getProfile, nowpublicandabstract- Still implemented in
Mannequin
- Still implemented in
net.minecraft.world.entity.item.ItemEntity#DEFAULT_HEALTHis nowpublicfromprivatenet.minecraft.world.entity.monster.breeze.Breeze#idle,slide,slideBack,longJump,shoot,inhaleare now finalnet.minecraft.world.entity.monster.piglin.PiglinAi#isZombifiednow takes in theEntityinstead of theEntityTypenet.minecraft.world.entity.monster.warden.Warden#roarAnimationState,sniffAnimationState,emergeAnimationState,diggingAnimationState,attackAnimationState,sonicBoomAnimationStateare now finalnet.minecraft.world.entity.monster.zombie.Zombie#handleAttributesnow takes in theEntitySpawnReasonnet.minecraft.world.entity.playerInput#EMPTYis now finalPlayercurrentImpulseImpactPos->LivingEntity#currentImpulseImpactPoscurrentExplosionCause->LivingEntity#currentExplosionCausesetIgnoreFallDamageFromCurrentImpulse->LivingEntity#setIgnoreFallDamageFromCurrentImpulseapplyPostImpulseGraceTime->LivingEntity#applyPostImpulseGraceTimeisIgnoringFallDamageFromCurrentImpulse->LivingEntity#isIgnoringFallDamageFromCurrentImpulsetryResetCurrentImpulseContext->LivingEntity#tryResetCurrentImpulseContextresetCurrentImpulseContext->LivingEntity#resetCurrentImpulseContextisInPostImpulseGraceTime->LivingEntity#isInPostImpulseGraceTimeisWithinAttackRangenow takes in theItemStackattacked with
net.minecraft.world.entity.vehicle.minecart.NewMinecartBehavior$MinecartStep#EMPTYis now finalnet.minecraft.world.inventory.AbstractContainerMenu#getQuickCraftPlaceCountnow takes in the number of quick craft slots instead of the set of slots itselfnet.minecraft.world.itemBundleItem#getSelectedItem->getSelectedItemIndexCreativeModeTab$Outputis nowprotectedfrompublicEnderpearlItem#PROJECTILE_SHOOT_POWERis now finalItem$Properties#requiredFeaturesnow has an overload that takes in aFeatureFlagSetItems#register*methods are nowprivatefrompublicItemUtils#onContainerDestroyednow takes in aStreamofItemStacks instead of anIterableSignApplicator#tryApplyToSign,canApplyToSignnow take in theItemStackbeing usedSnowballItem#PROJECTILE_SHOOT_POWERis now finalThrowablePotionItem#PROJECTILE_SHOOT_POWERis now finalWindChargeItem#PROJECTILE_SHOOT_POWERis now final
net.minecraft.world.item.alchemy.Potionsnow deal withHolder$References instead of the superHoldernet.minecraft.world.item.componentAttackRangeminRange->minReachmaxRange->maxReachminCreativeRange->minCreativeReachmaxCreativeRange->maxCreativeReach
BundleContentsweightnow returns aDataResult-wrappedFractioninstead of the raw objectgetSelectedItem->getSelectedItemIndex
WrittenBookContenttryCraftCopy->craftCopyresolveForItem,resolvenow take in theResolutionContextandHolderLookup$Providerinstead of theCommandSourceStackandPlayer
net.minecraft.world.item.enchantmentConditionalEffect#codecno longer takes in theContextKeySetEnchantment#doLunge->doPostPiercingAttackEnchantmentHelper#doLungeEffects->doPostPiercingAttackEffectsTargetedConditionalEffect#codec,equipmentDropsCodecno longer take in theContextKeySet
net.minecraft.world.item.enchantment.effects.EnchantmentAttributeEffect#CODEC->MAP_CODECnet.minecraft.world.item.equipment.Equippable#canBeEquippedBynow takes in a holder-wrappedEntityTypeinstead of the raw type itselfnet.minecraft.world.item.trading.VillagerTrades#LIBRARIAN_5_EMERALD_NAME_TAGwas replaced withLIBRARIAN_5_EMERALD_YELLOW_CANDLE,LIBRARIAN_5_EMERALD_RED_CANDLE, not one-to-one- The original trade was moved to
WANDERING_TRADER_EMERALD_NAME_TAG
- The original trade was moved to
net.minecraft.world.levelLevelAccessorno longer implementsLevelReaderLevelHeightAccessor#isInsideBuildHeightnow has an overload that takes in theBlockPos
net.minecraft.world.level.blockBigDripleafBlock#canPlaceAtnow takes in theLevelReaderinstead of theLevelHeightAccessor, and no longer takes in the old stateBubbleColumnBlock#updateColumnnow takes in the bubble columnBlockFireBlock#setFlammableis nowprivatefrompublicMultifaceSpreader$DefaultSpreaderConfig#blockis now finalSnowyDirtBlock->SnowyBlockSpreadingSnowyDirtBlock->SpreadingSnowyBlock- The constructor now takes in the
ResourceKeyfor the ‘base’ block, or the block when the snow or any other decoration (e.g. grass) is removed
- The constructor now takes in the
net.minecraft.world.level.block.entity.TestInstanceBlockEntitygetTestBoundingBox- The bounding box of the test inflated by its padding.getTestBounds- The axis aligned bounding box of the test inflated by its padding.
net.minecraft.world.level.block.entity.vaultVaultConfig#DEFAULT,CODECare now finalVaultServerData#CODECis now finalVaultSharedData#CODECis now final
net.minecraft.world.level.block.stateBlockBehaviour$BlockStateBasenow takes in an array ofPropertys andComparablevalues instead of one value map, and no longer takes in theMapCodechasPostProcess->getPostProcessPos, not one-to-one$Properties#hasPostProcess->getPostProcessPos, not one-to-one
BlockStatenow takes in an array ofPropertys andComparablevalues instead of one value map, and no longer takes in theMapCodecStateHoldernow takes in an array ofPropertys andComparablevalues instead of one value map, and no longer takes in theMapCodecpopulateNeighbours->initializeNeighbors, now package-private instead ofpublic; not one-to-onegetValuesnow returns a stream ofProperty$Valuescodecnow takes in the function that gets the state definition from some object
net.minecraft.world.level.chunk.ChunkAccess#blendingDatais now finalnet.minecraft.world.level.chunk.storage.SimpleRegionStorage#upgradeChunkTagnow takes in anintfor the target versionnet.minecraft.world.level.gameevent.vibrations.VibrationSystem$Data#CODECis now finalnet.minecraft.world.level.gamerules.GameRulesnow has an overload that takes in a list ofGameRulesnet.minecraft.world.level.levelgenNoiseRouterData#cavesno longer takes in theHolderGetterfor theNormalNoise$NoiseParametersWorldDimensions#keysInOrdernow takes in a set ofLevelStemkeys instead of a stream
net.minecraft.world.level.levelgen.blockpredicatesTrueBlockPredicate#INSTANCEis now finalUnobstructedPredicate#INSTANCEis now final
net.minecraft.world.level.levelgen.featureAbstractHugeMushrromFeatureisValidPositionnow takes in aWorldGenLevelinstead of theLevelAccessorplaceTrunknow takes in theWorldGenLevelinstead of theLevelAccessormakeCapnow takes in theWorldGenLevelinstead of theLevelAccessor
BlockBlobFeaturenow uses aBlockBlobConfigurationgenericFeatureFOREST_ROCKreplaced byBLOCK_BLOBICE_SPIKEreplaced bySPIKE
IceSpikeFeature->SpikeFeature, not one-to-oneSpikeFeatureis nowEndSpikeFeature, not one-to-oneNUMBER_OF_SPIKES->EndSpikeFeature#NUMBER_OF_SPIKESgetSpikesForLevel->EndSpikeFeature#getSpikesForLevel
net.minecraft.world.level.levelgen.feature.configurationsHugeMushroomFeatureConfigurationis now a record, taking in a can place onBlockPredicateSpikeConfiguration->EndSpikeConfigurationis now a record- The original
SpikeConfigurationis now for the ice spike, taking in the blocks to use, along with predicates of where to place and whether it can replace a block present
- The original
TreeConfigurationdirtProvider,forceDirthave been replaced bybelowTrunkProviderdirtProvidercommonly usesCAN_PLACE_BELOW_OVERWORLD_TRUNKSforceDirtcommonly usesPLACE_BELOW_OVERWORLD_TRUNKS
$TreeConfigurationBuilderdirtProvider,dirt,forceDirthave been replaced bybelowTrunkProvider
net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacercreateFoliagenow takes in aWorldGenLevelisntead of aLevelSimulatedReaderplaceLeavesRow,placeLeavesRowWithHangingLeavesBelownow take in aWorldGenLevelisntead of aLevelSimulatedReadertryPlaceExtension,tryPlaceLeafnow take in aWorldGenLevelisntead of aLevelSimulatedReader
net.minecraft.world.level.levelgen.feature.rootplacers.RootPlacer#placeRoots,placeRootnow take in aWorldGenLevelinstead of aLevelSimulatedReadernet.minecraft.world.level.levelgen.feature.stateprovidersBlockStateProvider#getStatenow takes in theWorldGenLevel
net.minecraft.world.level.levelgen.feature.treedecoratorsTreeDecorator$Contextnow takes in aWorldGenLevelinstead of theLevelSimulatedReaderlevelnow returns aWorldGenLevelinstead of theLevelSimulatedReader
net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacerplaceTrunknow takes in aWorldGenLevelinstead of theLevelSimulatedReadersetDirtAt->placeBelowTrunkBlock, now taking in aWorldGenLevelinstead of theLevelSimulatedReaderplaceLognow takes in aWorldGenLevelinstead of theLevelSimulatedReaderplaceLogIfFreenow takes in aWorldGenLevelinstead of theLevelSimulatedReadervalidTreePosnow takes in aWorldGenLevelinstead of theLevelSimulatedReaderisFreenow takes in aWorldGenLevelinstead of theLevelSimulatedReader
net.minecraft.world.level.levelgen.placement.BiomeFilter#CODECis now finalnet.minecraft.world.level.levelgen.structure.TemplateStructurePiece#template,placeSettingsare now finalnet.minecraft.world.level.levelgen.structure.pools.aliasDirectPoolAlias#CODECis now finalRandomGroupPoolAlias#CODECis now finalRandomPoolAlias#CODECis now final
net.minecraft.world.level.levelgen.structure.templatesystem.LiquidSettings#CODECis now finalnet.minecraft.world.level.levelgen.synth.PerlinNoise#getValueno longer takes in thebooleanfor whether to flat the Y value instead of applying the frequency factornet.minecraft.world.level.material.FluidStatenow takes in an array ofPropertys andComparablevalues instead of one value map, and no longer takes in theMapCodecnet.minecraft.world.level.pathfinder.PathTypeDANGER_POWDER_SNOW->ON_TOP_OF_POWDER_SNOWDANGER_FIRE->FIRE_IN_NEIGHBORDAMAGE_FIRE->FIREDANGER_OTHER->DAMAGING_IN_NEIGHBORDAMAGE_OTHER->DAMAGING,DANGER_TRAPDOOR->ON_TOP_OF_TRAPDOOR
net.minecraft.world.level.saveddata.maps.MapItemSavedData#tickCarriedBynow takes in a nullableItemFramenet.minecraft.world.level.storage.loot.functionsEnchantRandomlyFunctionnow takes in abooleanof whether to include the additional trade cost component from the stack being enchanted- Set via
$Builder#includeAdditionalCostComponent
- Set via
EnchantWithLevelsFunctionnow takes in abooleanof whether to include the additional trade cost component from the stack being enchanted- Set via
$Builder#includeAdditionalCostComponent $Builder#fromOptions->withOptions, now with overload to take in an optionalHolderSet
- Set via
List of Removals
net.minecraft.SharedConstants#USE_WORKFLOWS_HOOKSnet.minecraft.client.data.models.BlockModelGenerators#createGenericCubenet.minecraft.client.Minecraft#delayCrashRawnet.minecraft.client.gui.components.EditBox#setFilternet.minecraft.client.multiplayer.ClientPacketListener#getIdnet.minecraft.client.renderer.SheetsshieldSheetbedSheetshulkerBoxSheetsignSheethangingSignSheetchestSheet
net.minecraft.client.renderer.rendertype.RenderTypes#weathernet.minecraft.data.loot.BlockLootSubProvider(Set, FeatureFlagSet, Map, HolderLookup$Provider)net.minecraft.gametest.framework.StructureUtils#DEFAULT_TEST_STRUCTURES_DIRnet.minecraft.nbt.NbtUtilsaddCurrentDataVersionprettyPrint(Tag)
net.minecraft.server.packs.AbstractPackResources#getMetadataFromStreamnet.minecraft.server.players.PlayerList#getSingleplayerDatanet.minecraft.utilMth#createInsecureUUIDLightCoordsUtil#UI_FULL_BRIGHT
net.minecraft.worldContainerListenerDifficulty#getKeySimpleContainer#addListener,removeListener
net.minecraft.world.entity.ai.memory.MemoryModuleType#INTERACTABLE_DOORSnet.minecraft.world.entity.monster.Zoglin#MEMORY_TYPESnet.minecraft.world.entity.monster.creaking.Creaking#MEMORY_TYPESnet.minecraft.world.entity.monster.hogling.Hoglin#MEMORY_TYPESnet.minecraft.world.itemBundleItem#hasSelectedItemItem#getName()ItemStackisFramed,getFramesetEntityRepresentation,getEntityRepresentation
net.minecraft.world.item.componentBundleContentsgetItemUnsafehasSelectedItem
WrittenBookContent#MAX_CRAFTABLE_GENERATION
net.minecraft.world.level.block.LiquidBlock#SHAPE_STABLEnet.minecraft.world.level.levelgen.featureFeature#isStone,isDirt,isGrassOrDirt
net.minecraft.world.level.levelgen.material.WorldGenMaterialRulenet.minecraft.world.level.storage.loot.functions.SetOminousBottleAmplifierFunction#amplifier
Source And Attribution
This docs tree was assembled from the upstream primers in:
- Repository:
https://github.com/ChampionAsh5357/neoforged-github - Branch:
update/26.1 - Primer root:
primers/
Coverage used for this compilation
The compiled direct-port guide includes these upstream primer steps:
1.21.1 -> 1.21.2/31.21.2/3 -> 1.21.41.21.4 -> 1.21.51.21.5 -> 1.21.61.21.6 -> 1.21.71.21.7 -> 1.21.81.21.8 -> 1.21.91.21.9 -> 1.21.101.21.10 -> 1.21.111.21.11 -> 26.1
Attribution
Per the upstream primers/README.md:
- Primers for versions
1.12 - 1.15were written by@williewillus. - Primers for versions
1.16 - 1.17were written by@50ap5ud5. - All newer primers, including the ones used here, were written by
@ChampionAsh5357.
Licensing note
The detailed primers copied into this docs tree remain under their upstream licenses and attribution requirements.
For the exact license text and upstream breakdown, refer to:
repo/primers/README.mdrepo/primers/LICENSE-CHAMPIONASH5357repo/primers/LICENSE-50AP5UD5repo/primers/LICENSE-WILLIEWILLUS